diff --git a/configure b/configure index 956e5824ca..437c26cdb3 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 9.5.3. +# Generated by GNU Autoconf 2.69 for PostgreSQL 9.5.4. # # Report bugs to . # @@ -583,8 +583,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='PostgreSQL' PACKAGE_TARNAME='postgresql' -PACKAGE_VERSION='9.5.3' -PACKAGE_STRING='PostgreSQL 9.5.3' +PACKAGE_VERSION='9.5.4' +PACKAGE_STRING='PostgreSQL 9.5.4' PACKAGE_BUGREPORT='pgsql-bugs@postgresql.org' PACKAGE_URL='' @@ -1401,7 +1401,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 9.5.3 to adapt to many kinds of systems. +\`configure' configures PostgreSQL 9.5.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1466,7 +1466,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of PostgreSQL 9.5.3:";; + short | recursive ) echo "Configuration of PostgreSQL 9.5.4:";; esac cat <<\_ACEOF @@ -1617,7 +1617,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -PostgreSQL configure 9.5.3 +PostgreSQL configure 9.5.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2329,7 +2329,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 9.5.3, which was +It was created by PostgreSQL $as_me 9.5.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2746,7 +2746,7 @@ fi -PGPRO_VERSION="$PACKAGE_VERSION.3" +PGPRO_VERSION="$PACKAGE_VERSION.1" PGPRO_PACKAGE_NAME="PostgresPro" @@ -8763,9 +8763,9 @@ else as_fn_error $? "library 'crypto' is required for OpenSSL" "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_library_init in -lssl" >&5 -$as_echo_n "checking for SSL_library_init in -lssl... " >&6; } -if ${ac_cv_lib_ssl_SSL_library_init+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_new in -lssl" >&5 +$as_echo_n "checking for SSL_new in -lssl... " >&6; } +if ${ac_cv_lib_ssl_SSL_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS @@ -8779,27 +8779,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char SSL_library_init (); +char SSL_new (); int main () { -return SSL_library_init (); +return SSL_new (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_ssl_SSL_library_init=yes + ac_cv_lib_ssl_SSL_new=yes else - ac_cv_lib_ssl_SSL_library_init=no + ac_cv_lib_ssl_SSL_new=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_library_init" >&5 -$as_echo "$ac_cv_lib_ssl_SSL_library_init" >&6; } -if test "x$ac_cv_lib_ssl_SSL_library_init" = xyes; then : +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_new" >&5 +$as_echo "$ac_cv_lib_ssl_SSL_new" >&6; } +if test "x$ac_cv_lib_ssl_SSL_new" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSSL 1 _ACEOF @@ -8869,9 +8869,9 @@ else as_fn_error $? "library 'eay32' or 'crypto' is required for OpenSSL" "$LINENO" 5 fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_library_init" >&5 -$as_echo_n "checking for library containing SSL_library_init... " >&6; } -if ${ac_cv_search_SSL_library_init+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing SSL_new" >&5 +$as_echo_n "checking for library containing SSL_new... " >&6; } +if ${ac_cv_search_SSL_new+:} false; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS @@ -8884,11 +8884,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext #ifdef __cplusplus extern "C" #endif -char SSL_library_init (); +char SSL_new (); int main () { -return SSL_library_init (); +return SSL_new (); ; return 0; } @@ -8901,25 +8901,25 @@ for ac_lib in '' ssleay32 ssl; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : - ac_cv_search_SSL_library_init=$ac_res + ac_cv_search_SSL_new=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext - if ${ac_cv_search_SSL_library_init+:} false; then : + if ${ac_cv_search_SSL_new+:} false; then : break fi done -if ${ac_cv_search_SSL_library_init+:} false; then : +if ${ac_cv_search_SSL_new+:} false; then : else - ac_cv_search_SSL_library_init=no + ac_cv_search_SSL_new=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SSL_library_init" >&5 -$as_echo "$ac_cv_search_SSL_library_init" >&6; } -ac_res=$ac_cv_search_SSL_library_init +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_SSL_new" >&5 +$as_echo "$ac_cv_search_SSL_new" >&6; } +ac_res=$ac_cv_search_SSL_new if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" @@ -8936,6 +8936,37 @@ if test "x$ac_cv_func_SSL_get_current_compression" = xyes; then : #define HAVE_SSL_GET_CURRENT_COMPRESSION 1 _ACEOF +fi +done + + # Functions introduced in OpenSSL 1.1.0. We used to check for + # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL + # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it + # doesn't have these OpenSSL 1.1.0 functions. So check for individual + # functions. + for ac_func in OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data RAND_OpenSSL +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + # OpenSSL versions before 1.1.0 required setting callback functions, for + # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock() + # function was removed. + for ac_func in CRYPTO_lock +do : + ac_fn_c_check_func "$LINENO" "CRYPTO_lock" "ac_cv_func_CRYPTO_lock" +if test "x$ac_cv_func_CRYPTO_lock" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_CRYPTO_LOCK 1 +_ACEOF + fi done @@ -18131,7 +18162,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 9.5.3, which was +This file was extended by PostgreSQL $as_me 9.5.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18201,7 +18232,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 9.5.3 +PostgreSQL config.status 9.5.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.in b/configure.in index b4919b8bf4..2eb3ac0d1a 100644 --- a/configure.in +++ b/configure.in @@ -17,7 +17,7 @@ dnl Read the Autoconf manual for details. dnl m4_pattern_forbid(^PGAC_)dnl to catch undefined macros -AC_INIT([PostgreSQL], [9.5.3], [pgsql-bugs@postgresql.org]) +AC_INIT([PostgreSQL], [9.5.4], [pgsql-bugs@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 @@ -38,7 +38,7 @@ PGAC_ARG_REQ(with, extra-version, [STRING], [append STRING to version], [PG_VERSION="$PACKAGE_VERSION$withval"], [PG_VERSION="$PACKAGE_VERSION"]) -PGPRO_VERSION="$PACKAGE_VERSION.3" +PGPRO_VERSION="$PACKAGE_VERSION.1" PGPRO_PACKAGE_NAME="PostgresPro" AC_SUBST(PGPRO_PACKAGE_NAME) @@ -1046,12 +1046,22 @@ if test "$with_openssl" = yes ; then dnl Order matters! if test "$PORTNAME" != "win32"; then AC_CHECK_LIB(crypto, CRYPTO_new_ex_data, [], [AC_MSG_ERROR([library 'crypto' is required for OpenSSL])]) - AC_CHECK_LIB(ssl, SSL_library_init, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) + AC_CHECK_LIB(ssl, SSL_new, [], [AC_MSG_ERROR([library 'ssl' is required for OpenSSL])]) else AC_SEARCH_LIBS(CRYPTO_new_ex_data, eay32 crypto, [], [AC_MSG_ERROR([library 'eay32' or 'crypto' is required for OpenSSL])]) - AC_SEARCH_LIBS(SSL_library_init, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])]) + AC_SEARCH_LIBS(SSL_new, ssleay32 ssl, [], [AC_MSG_ERROR([library 'ssleay32' or 'ssl' is required for OpenSSL])]) fi AC_CHECK_FUNCS([SSL_get_current_compression]) + # Functions introduced in OpenSSL 1.1.0. We used to check for + # OPENSSL_VERSION_NUMBER, but that didn't work with 1.1.0, because LibreSSL + # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it + # doesn't have these OpenSSL 1.1.0 functions. So check for individual + # functions. + AC_CHECK_FUNCS([OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data RAND_OpenSSL]) + # OpenSSL versions before 1.1.0 required setting callback functions, for + # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock() + # function was removed. + AC_CHECK_FUNCS([CRYPTO_lock]) fi if test "$with_icu" = yes ; then diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c index f74e912ed7..030b61097f 100644 --- a/contrib/btree_gin/btree_gin.c +++ b/contrib/btree_gin/btree_gin.c @@ -223,10 +223,7 @@ GIN_SUPPORT(int4, false, leftmostvalue_int4, btint4cmp) static Datum leftmostvalue_int8(void) { - /* - * Use sequence's definition to keep compatibility. - */ - return Int64GetDatum(SEQ_MINVALUE); + return Int64GetDatum(PG_INT64_MIN); } GIN_SUPPORT(int8, false, leftmostvalue_int8, btint8cmp) @@ -250,10 +247,7 @@ GIN_SUPPORT(float8, false, leftmostvalue_float8, btfloat8cmp) static Datum leftmostvalue_money(void) { - /* - * Use sequence's definition to keep compatibility. - */ - return Int64GetDatum(SEQ_MINVALUE); + return Int64GetDatum(PG_INT64_MIN); } GIN_SUPPORT(money, false, leftmostvalue_money, cash_cmp) diff --git a/contrib/btree_gin/expected/bytea.out b/contrib/btree_gin/expected/bytea.out index 8b5a0c615d..b0ed7a5345 100644 --- a/contrib/btree_gin/expected/bytea.out +++ b/contrib/btree_gin/expected/bytea.out @@ -4,13 +4,13 @@ SET bytea_output TO escape; CREATE TABLE test_bytea ( i bytea ); -INSERT INTO test_bytea VALUES ('aaa'),('a'),('abc'),('abb'),('axy'),('xyz'); +INSERT INTO test_bytea VALUES ('a'),('ab'),('abc'),('abb'),('axy'),('xyz'); CREATE INDEX idx_bytea ON test_bytea USING gin (i); SELECT * FROM test_bytea WHERE i<'abc'::bytea ORDER BY i; i ----- a - aaa + ab abb (3 rows) @@ -18,7 +18,7 @@ SELECT * FROM test_bytea WHERE i<='abc'::bytea ORDER BY i; i ----- a - aaa + ab abb abc (4 rows) diff --git a/contrib/btree_gin/expected/text.out b/contrib/btree_gin/expected/text.out index 1ed206eec7..3e31ad744d 100644 --- a/contrib/btree_gin/expected/text.out +++ b/contrib/btree_gin/expected/text.out @@ -2,13 +2,13 @@ set enable_seqscan=off; CREATE TABLE test_text ( i text ); -INSERT INTO test_text VALUES ('aaa'),('a'),('abc'),('abb'),('axy'),('xyz'); +INSERT INTO test_text VALUES ('a'),('ab'),('abc'),('abb'),('axy'),('xyz'); CREATE INDEX idx_text ON test_text USING gin (i); SELECT * FROM test_text WHERE i<'abc' ORDER BY i; i ----- a - aaa + ab abb (3 rows) @@ -16,7 +16,7 @@ SELECT * FROM test_text WHERE i<='abc' ORDER BY i; i ----- a - aaa + ab abb abc (4 rows) diff --git a/contrib/btree_gin/expected/varchar.out b/contrib/btree_gin/expected/varchar.out index b893dd976d..086afbc356 100644 --- a/contrib/btree_gin/expected/varchar.out +++ b/contrib/btree_gin/expected/varchar.out @@ -2,13 +2,13 @@ set enable_seqscan=off; CREATE TABLE test_varchar ( i varchar ); -INSERT INTO test_varchar VALUES ('aaa'),('a'),('abc'),('abb'),('axy'),('xyz'); +INSERT INTO test_varchar VALUES ('a'),('ab'),('abc'),('abb'),('axy'),('xyz'); CREATE INDEX idx_varchar ON test_varchar USING gin (i); SELECT * FROM test_varchar WHERE i<'abc'::varchar ORDER BY i; i ----- a - aaa + ab abb (3 rows) @@ -16,7 +16,7 @@ SELECT * FROM test_varchar WHERE i<='abc'::varchar ORDER BY i; i ----- a - aaa + ab abb abc (4 rows) diff --git a/contrib/btree_gin/sql/bytea.sql b/contrib/btree_gin/sql/bytea.sql index 0ef6247e10..5f3eb11b16 100644 --- a/contrib/btree_gin/sql/bytea.sql +++ b/contrib/btree_gin/sql/bytea.sql @@ -6,7 +6,7 @@ CREATE TABLE test_bytea ( i bytea ); -INSERT INTO test_bytea VALUES ('aaa'),('a'),('abc'),('abb'),('axy'),('xyz'); +INSERT INTO test_bytea VALUES ('a'),('ab'),('abc'),('abb'),('axy'),('xyz'); CREATE INDEX idx_bytea ON test_bytea USING gin (i); diff --git a/contrib/btree_gin/sql/text.sql b/contrib/btree_gin/sql/text.sql index 5288206af3..d5b3b39898 100644 --- a/contrib/btree_gin/sql/text.sql +++ b/contrib/btree_gin/sql/text.sql @@ -4,7 +4,7 @@ CREATE TABLE test_text ( i text ); -INSERT INTO test_text VALUES ('aaa'),('a'),('abc'),('abb'),('axy'),('xyz'); +INSERT INTO test_text VALUES ('a'),('ab'),('abc'),('abb'),('axy'),('xyz'); CREATE INDEX idx_text ON test_text USING gin (i); diff --git a/contrib/btree_gin/sql/varchar.sql b/contrib/btree_gin/sql/varchar.sql index 16255df426..dbdacab7e9 100644 --- a/contrib/btree_gin/sql/varchar.sql +++ b/contrib/btree_gin/sql/varchar.sql @@ -4,7 +4,7 @@ CREATE TABLE test_varchar ( i varchar ); -INSERT INTO test_varchar VALUES ('aaa'),('a'),('abc'),('abb'),('axy'),('xyz'); +INSERT INTO test_varchar VALUES ('a'),('ab'),('abc'),('abb'),('axy'),('xyz'); CREATE INDEX idx_varchar ON test_varchar USING gin (i); diff --git a/contrib/citext/expected/citext.out b/contrib/citext/expected/citext.out index 373fe6da54..6541b24b5f 100644 --- a/contrib/citext/expected/citext.out +++ b/contrib/citext/expected/citext.out @@ -175,7 +175,7 @@ SELECT 'a'::citext >= 'B'::varchar AS t; -- varchar wins. t (1 row) --- A couple of longer examlpes to ensure that we don't get any issues with bad +-- A couple of longer examples to ensure that we don't get any issues with bad -- conversions to char[] in the c code. Yes, I did do this. SELECT 'aardvark'::citext = 'aardvark'::citext AS t; t @@ -272,14 +272,14 @@ DETAIL: Key (name)=(A) already exists. INSERT INTO try (name) VALUES ('aB'); ERROR: duplicate key value violates unique constraint "try_pkey" DETAIL: Key (name)=(aB) already exists. --- Make sure that citext_smaller() and citext_lager() work properly. -SELECT citext_smaller( 'aa'::citext, 'ab'::citext ) = 'aa' AS t; +-- Make sure that citext_smaller() and citext_larger() work properly. +SELECT citext_smaller( 'ab'::citext, 'ac'::citext ) = 'ab' AS t; t --- t (1 row) -SELECT citext_smaller( 'AAAA'::citext, 'bbbb'::citext ) = 'AAAA' AS t; +SELECT citext_smaller( 'ABC'::citext, 'bbbb'::citext ) = 'ABC' AS t; t --- t @@ -297,13 +297,13 @@ SELECT citext_smaller( 'aardvark'::citext, 'AARDVARK'::citext ) = 'AARDVARK' AS t (1 row) -SELECT citext_larger( 'aa'::citext, 'ab'::citext ) = 'ab' AS t; +SELECT citext_larger( 'ab'::citext, 'ac'::citext ) = 'ac' AS t; t --- t (1 row) -SELECT citext_larger( 'AAAA'::citext, 'bbbb'::citext ) = 'bbbb' AS t; +SELECT citext_larger( 'ABC'::citext, 'bbbb'::citext ) = 'bbbb' AS t; t --- t @@ -320,18 +320,17 @@ CREATE TEMP TABLE srt ( name CITEXT ); INSERT INTO srt (name) -VALUES ('aardvark'), - ('AAA'), - ('aba'), +VALUES ('abb'), + ('ABA'), ('ABC'), ('abd'); CREATE INDEX srt_name ON srt (name); -- Check the min() and max() aggregates, with and without index. set enable_seqscan = off; -SELECT MIN(name) AS "AAA" FROM srt; - AAA +SELECT MIN(name) AS "ABA" FROM srt; + ABA ----- - AAA + ABA (1 row) SELECT MAX(name) AS abd FROM srt; @@ -342,10 +341,10 @@ SELECT MAX(name) AS abd FROM srt; reset enable_seqscan; set enable_indexscan = off; -SELECT MIN(name) AS "AAA" FROM srt; - AAA +SELECT MIN(name) AS "ABA" FROM srt; + ABA ----- - AAA + ABA (1 row) SELECT MAX(name) AS abd FROM srt; @@ -358,162 +357,146 @@ reset enable_indexscan; -- Check sorting likewise set enable_seqscan = off; SELECT name FROM srt ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) reset enable_seqscan; set enable_indexscan = off; SELECT name FROM srt ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) reset enable_indexscan; -- Test assignment casts. -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::text; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::text; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::varchar; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::varchar; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::bpchar; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::bpchar; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::citext; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::citext; + aba ----- - aaa + aba (1 row) -- LIKE should be case-insensitive SELECT name FROM srt WHERE name LIKE '%a%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name NOT LIKE '%b%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) SELECT name FROM srt WHERE name LIKE '%A%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name NOT LIKE '%B%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) -- ~~ should be case-insensitive SELECT name FROM srt WHERE name ~~ '%a%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~~ '%b%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) SELECT name FROM srt WHERE name ~~ '%A%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~~ '%B%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) -- ~ should be case-insensitive SELECT name FROM srt WHERE name ~ '^a' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~ 'a$' ORDER BY name; - name ----------- - aardvark + name +------ + abb ABC abd (3 rows) SELECT name FROM srt WHERE name ~ '^A' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~ 'A$' ORDER BY name; - name ----------- - aardvark + name +------ + abb ABC abd (3 rows) @@ -522,16 +505,14 @@ SELECT name FROM srt WHERE name !~ 'A$' ORDER BY name; SELECT name FROM srt WHERE name SIMILAR TO '%a.*'; name ------ - AAA - aba -(2 rows) + ABA +(1 row) SELECT name FROM srt WHERE name SIMILAR TO '%A.*'; name ------ - AAA - aba -(2 rows) + ABA +(1 row) -- Explicit casts. SELECT true::citext = 'true' AS t; @@ -1503,8 +1484,7 @@ SELECT bit_length( name ) = bit_length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT textlen( name ) = textlen( name::text ) AS t FROM srt; t @@ -1513,8 +1493,7 @@ SELECT textlen( name ) = textlen( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT char_length( name ) = char_length( name::text ) AS t FROM srt; t @@ -1523,8 +1502,7 @@ SELECT char_length( name ) = char_length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT lower( name ) = lower( name::text ) AS t FROM srt; t @@ -1533,8 +1511,7 @@ SELECT lower( name ) = lower( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT octet_length( name ) = octet_length( name::text ) AS t FROM srt; t @@ -1543,8 +1520,7 @@ SELECT octet_length( name ) = octet_length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT overlay( name placing 'hom' from 2 for 4) = overlay( name::text placing 'hom' from 2 for 4) AS t FROM srt; t @@ -1553,8 +1529,7 @@ SELECT overlay( name placing 'hom' from 2 for 4) = overlay( name::text placing ' t t t - t -(5 rows) +(4 rows) SELECT position( 'a' IN name ) = position( 'a' IN name::text ) AS t FROM srt; t @@ -1563,8 +1538,7 @@ SELECT position( 'a' IN name ) = position( 'a' IN name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT substr('alphabet'::citext, 3) = 'phabet' AS t; t @@ -1645,8 +1619,7 @@ SELECT upper( name ) = upper( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) -- Table 9-6. Other String Functions. SELECT ascii( name ) = ascii( name::text ) AS t FROM srt; @@ -1656,8 +1629,7 @@ SELECT ascii( name ) = ascii( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT btrim(' trim'::citext ) = 'trim' AS t; t @@ -1698,8 +1670,7 @@ SELECT convert_from( name::bytea, 'SQL_ASCII' ) = convert_from( name::text::byte t t t - t -(5 rows) +(4 rows) SELECT decode('MTIzAAE='::citext, 'base64') = decode('MTIzAAE='::text, 'base64') AS t; t @@ -1721,8 +1692,7 @@ SELECT length( name ) = length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT lpad('hi'::citext, 5 ) = ' hi' AS t; t @@ -1779,8 +1749,7 @@ SELECT md5( name ) = md5( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) -- pg_client_encoding() takes no args and returns name. SELECT quote_ident( name ) = quote_ident( name::text ) AS t FROM srt; @@ -1790,8 +1759,7 @@ SELECT quote_ident( name ) = quote_ident( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t @@ -1800,8 +1768,7 @@ SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; t @@ -2106,37 +2073,37 @@ SELECT split_part('abcTdefTghi', 't'::citext, 2) = 'def' AS t; t (1 row) -SELECT strpos('high'::citext, 'ig' ) = 2 AS t; +SELECT strpos('high'::citext, 'gh' ) = 3 AS t; t --- t (1 row) -SELECT strpos('high', 'ig'::citext) = 2 AS t; +SELECT strpos('high', 'gh'::citext) = 3 AS t; t --- t (1 row) -SELECT strpos('high'::citext, 'ig'::citext) = 2 AS t; +SELECT strpos('high'::citext, 'gh'::citext) = 3 AS t; t --- t (1 row) -SELECT strpos('high'::citext, 'IG' ) = 2 AS t; +SELECT strpos('high'::citext, 'GH' ) = 3 AS t; t --- t (1 row) -SELECT strpos('high', 'IG'::citext) = 2 AS t; +SELECT strpos('high', 'GH'::citext) = 3 AS t; t --- t (1 row) -SELECT strpos('high'::citext, 'IG'::citext) = 2 AS t; +SELECT strpos('high'::citext, 'GH'::citext) = 3 AS t; t --- t @@ -2270,8 +2237,7 @@ SELECT like_escape( name, '' ) = like_escape( name::text, '' ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT like_escape( name::text, ''::citext ) = like_escape( name::text, '' ) AS t FROM srt; t @@ -2280,8 +2246,7 @@ SELECT like_escape( name::text, ''::citext ) = like_escape( name::text, '' ) AS t t t - t -(5 rows) +(4 rows) -- Ensure correct behavior for citext with materialized views. CREATE TABLE citext_table ( diff --git a/contrib/citext/expected/citext_1.out b/contrib/citext/expected/citext_1.out index fcadd8d392..462d42a3bd 100644 --- a/contrib/citext/expected/citext_1.out +++ b/contrib/citext/expected/citext_1.out @@ -175,7 +175,7 @@ SELECT 'a'::citext >= 'B'::varchar AS t; -- varchar wins. f (1 row) --- A couple of longer examlpes to ensure that we don't get any issues with bad +-- A couple of longer examples to ensure that we don't get any issues with bad -- conversions to char[] in the c code. Yes, I did do this. SELECT 'aardvark'::citext = 'aardvark'::citext AS t; t @@ -272,14 +272,14 @@ DETAIL: Key (name)=(A) already exists. INSERT INTO try (name) VALUES ('aB'); ERROR: duplicate key value violates unique constraint "try_pkey" DETAIL: Key (name)=(aB) already exists. --- Make sure that citext_smaller() and citext_lager() work properly. -SELECT citext_smaller( 'aa'::citext, 'ab'::citext ) = 'aa' AS t; +-- Make sure that citext_smaller() and citext_larger() work properly. +SELECT citext_smaller( 'ab'::citext, 'ac'::citext ) = 'ab' AS t; t --- t (1 row) -SELECT citext_smaller( 'AAAA'::citext, 'bbbb'::citext ) = 'AAAA' AS t; +SELECT citext_smaller( 'ABC'::citext, 'bbbb'::citext ) = 'ABC' AS t; t --- t @@ -297,13 +297,13 @@ SELECT citext_smaller( 'aardvark'::citext, 'AARDVARK'::citext ) = 'AARDVARK' AS t (1 row) -SELECT citext_larger( 'aa'::citext, 'ab'::citext ) = 'ab' AS t; +SELECT citext_larger( 'ab'::citext, 'ac'::citext ) = 'ac' AS t; t --- t (1 row) -SELECT citext_larger( 'AAAA'::citext, 'bbbb'::citext ) = 'bbbb' AS t; +SELECT citext_larger( 'ABC'::citext, 'bbbb'::citext ) = 'bbbb' AS t; t --- t @@ -320,18 +320,17 @@ CREATE TEMP TABLE srt ( name CITEXT ); INSERT INTO srt (name) -VALUES ('aardvark'), - ('AAA'), - ('aba'), +VALUES ('abb'), + ('ABA'), ('ABC'), ('abd'); CREATE INDEX srt_name ON srt (name); -- Check the min() and max() aggregates, with and without index. set enable_seqscan = off; -SELECT MIN(name) AS "AAA" FROM srt; - AAA +SELECT MIN(name) AS "ABA" FROM srt; + ABA ----- - AAA + ABA (1 row) SELECT MAX(name) AS abd FROM srt; @@ -342,10 +341,10 @@ SELECT MAX(name) AS abd FROM srt; reset enable_seqscan; set enable_indexscan = off; -SELECT MIN(name) AS "AAA" FROM srt; - AAA +SELECT MIN(name) AS "ABA" FROM srt; + ABA ----- - AAA + ABA (1 row) SELECT MAX(name) AS abd FROM srt; @@ -358,162 +357,146 @@ reset enable_indexscan; -- Check sorting likewise set enable_seqscan = off; SELECT name FROM srt ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) reset enable_seqscan; set enable_indexscan = off; SELECT name FROM srt ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) reset enable_indexscan; -- Test assignment casts. -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::text; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::text; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::varchar; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::varchar; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::bpchar; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::bpchar; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'; + aba ----- - aaa + aba (1 row) -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::citext; - aaa +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::citext; + aba ----- - aaa + aba (1 row) -- LIKE should be case-insensitive SELECT name FROM srt WHERE name LIKE '%a%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name NOT LIKE '%b%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) SELECT name FROM srt WHERE name LIKE '%A%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name NOT LIKE '%B%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) -- ~~ should be case-insensitive SELECT name FROM srt WHERE name ~~ '%a%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~~ '%b%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) SELECT name FROM srt WHERE name ~~ '%A%' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~~ '%B%' ORDER BY name; - name ----------- - AAA - aardvark -(2 rows) + name +------ +(0 rows) -- ~ should be case-insensitive SELECT name FROM srt WHERE name ~ '^a' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~ 'a$' ORDER BY name; - name ----------- - aardvark + name +------ + abb ABC abd (3 rows) SELECT name FROM srt WHERE name ~ '^A' ORDER BY name; - name ----------- - AAA - aardvark - aba + name +------ + ABA + abb ABC abd -(5 rows) +(4 rows) SELECT name FROM srt WHERE name !~ 'A$' ORDER BY name; - name ----------- - aardvark + name +------ + abb ABC abd (3 rows) @@ -522,16 +505,14 @@ SELECT name FROM srt WHERE name !~ 'A$' ORDER BY name; SELECT name FROM srt WHERE name SIMILAR TO '%a.*'; name ------ - AAA - aba -(2 rows) + ABA +(1 row) SELECT name FROM srt WHERE name SIMILAR TO '%A.*'; name ------ - AAA - aba -(2 rows) + ABA +(1 row) -- Explicit casts. SELECT true::citext = 'true' AS t; @@ -1503,8 +1484,7 @@ SELECT bit_length( name ) = bit_length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT textlen( name ) = textlen( name::text ) AS t FROM srt; t @@ -1513,8 +1493,7 @@ SELECT textlen( name ) = textlen( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT char_length( name ) = char_length( name::text ) AS t FROM srt; t @@ -1523,8 +1502,7 @@ SELECT char_length( name ) = char_length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT lower( name ) = lower( name::text ) AS t FROM srt; t @@ -1533,8 +1511,7 @@ SELECT lower( name ) = lower( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT octet_length( name ) = octet_length( name::text ) AS t FROM srt; t @@ -1543,8 +1520,7 @@ SELECT octet_length( name ) = octet_length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT overlay( name placing 'hom' from 2 for 4) = overlay( name::text placing 'hom' from 2 for 4) AS t FROM srt; t @@ -1553,8 +1529,7 @@ SELECT overlay( name placing 'hom' from 2 for 4) = overlay( name::text placing ' t t t - t -(5 rows) +(4 rows) SELECT position( 'a' IN name ) = position( 'a' IN name::text ) AS t FROM srt; t @@ -1563,8 +1538,7 @@ SELECT position( 'a' IN name ) = position( 'a' IN name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT substr('alphabet'::citext, 3) = 'phabet' AS t; t @@ -1645,8 +1619,7 @@ SELECT upper( name ) = upper( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) -- Table 9-6. Other String Functions. SELECT ascii( name ) = ascii( name::text ) AS t FROM srt; @@ -1656,8 +1629,7 @@ SELECT ascii( name ) = ascii( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT btrim(' trim'::citext ) = 'trim' AS t; t @@ -1698,8 +1670,7 @@ SELECT convert_from( name::bytea, 'SQL_ASCII' ) = convert_from( name::text::byte t t t - t -(5 rows) +(4 rows) SELECT decode('MTIzAAE='::citext, 'base64') = decode('MTIzAAE='::text, 'base64') AS t; t @@ -1721,8 +1692,7 @@ SELECT length( name ) = length( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT lpad('hi'::citext, 5 ) = ' hi' AS t; t @@ -1779,8 +1749,7 @@ SELECT md5( name ) = md5( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) -- pg_client_encoding() takes no args and returns name. SELECT quote_ident( name ) = quote_ident( name::text ) AS t FROM srt; @@ -1790,8 +1759,7 @@ SELECT quote_ident( name ) = quote_ident( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t @@ -1800,8 +1768,7 @@ SELECT quote_literal( name ) = quote_literal( name::text ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT regexp_matches('foobarbequebaz'::citext, '(bar)(beque)') = ARRAY[ 'bar', 'beque' ] AS t; t @@ -2106,37 +2073,37 @@ SELECT split_part('abcTdefTghi', 't'::citext, 2) = 'def' AS t; t (1 row) -SELECT strpos('high'::citext, 'ig' ) = 2 AS t; +SELECT strpos('high'::citext, 'gh' ) = 3 AS t; t --- t (1 row) -SELECT strpos('high', 'ig'::citext) = 2 AS t; +SELECT strpos('high', 'gh'::citext) = 3 AS t; t --- t (1 row) -SELECT strpos('high'::citext, 'ig'::citext) = 2 AS t; +SELECT strpos('high'::citext, 'gh'::citext) = 3 AS t; t --- t (1 row) -SELECT strpos('high'::citext, 'IG' ) = 2 AS t; +SELECT strpos('high'::citext, 'GH' ) = 3 AS t; t --- t (1 row) -SELECT strpos('high', 'IG'::citext) = 2 AS t; +SELECT strpos('high', 'GH'::citext) = 3 AS t; t --- t (1 row) -SELECT strpos('high'::citext, 'IG'::citext) = 2 AS t; +SELECT strpos('high'::citext, 'GH'::citext) = 3 AS t; t --- t @@ -2270,8 +2237,7 @@ SELECT like_escape( name, '' ) = like_escape( name::text, '' ) AS t FROM srt; t t t - t -(5 rows) +(4 rows) SELECT like_escape( name::text, ''::citext ) = like_escape( name::text, '' ) AS t FROM srt; t @@ -2280,8 +2246,7 @@ SELECT like_escape( name::text, ''::citext ) = like_escape( name::text, '' ) AS t t t - t -(5 rows) +(4 rows) -- Ensure correct behavior for citext with materialized views. CREATE TABLE citext_table ( diff --git a/contrib/citext/sql/citext.sql b/contrib/citext/sql/citext.sql index 950895baea..2df1b4aaf0 100644 --- a/contrib/citext/sql/citext.sql +++ b/contrib/citext/sql/citext.sql @@ -72,7 +72,7 @@ SELECT 'B'::citext <= 'a'::varchar AS t; -- varchar wins. SELECT 'a'::citext > 'B'::varchar AS t; -- varchar wins. SELECT 'a'::citext >= 'B'::varchar AS t; -- varchar wins. --- A couple of longer examlpes to ensure that we don't get any issues with bad +-- A couple of longer examples to ensure that we don't get any issues with bad -- conversions to char[] in the c code. Yes, I did do this. SELECT 'aardvark'::citext = 'aardvark'::citext AS t; @@ -104,14 +104,14 @@ INSERT INTO try (name) VALUES ('a'); INSERT INTO try (name) VALUES ('A'); INSERT INTO try (name) VALUES ('aB'); --- Make sure that citext_smaller() and citext_lager() work properly. -SELECT citext_smaller( 'aa'::citext, 'ab'::citext ) = 'aa' AS t; -SELECT citext_smaller( 'AAAA'::citext, 'bbbb'::citext ) = 'AAAA' AS t; +-- Make sure that citext_smaller() and citext_larger() work properly. +SELECT citext_smaller( 'ab'::citext, 'ac'::citext ) = 'ab' AS t; +SELECT citext_smaller( 'ABC'::citext, 'bbbb'::citext ) = 'ABC' AS t; SELECT citext_smaller( 'aardvark'::citext, 'Aaba'::citext ) = 'Aaba' AS t; SELECT citext_smaller( 'aardvark'::citext, 'AARDVARK'::citext ) = 'AARDVARK' AS t; -SELECT citext_larger( 'aa'::citext, 'ab'::citext ) = 'ab' AS t; -SELECT citext_larger( 'AAAA'::citext, 'bbbb'::citext ) = 'bbbb' AS t; +SELECT citext_larger( 'ab'::citext, 'ac'::citext ) = 'ac' AS t; +SELECT citext_larger( 'ABC'::citext, 'bbbb'::citext ) = 'bbbb' AS t; SELECT citext_larger( 'aardvark'::citext, 'Aaba'::citext ) = 'aardvark' AS t; -- Test aggregate functions and sort ordering @@ -121,9 +121,8 @@ CREATE TEMP TABLE srt ( ); INSERT INTO srt (name) -VALUES ('aardvark'), - ('AAA'), - ('aba'), +VALUES ('abb'), + ('ABA'), ('ABC'), ('abd'); @@ -131,11 +130,11 @@ CREATE INDEX srt_name ON srt (name); -- Check the min() and max() aggregates, with and without index. set enable_seqscan = off; -SELECT MIN(name) AS "AAA" FROM srt; +SELECT MIN(name) AS "ABA" FROM srt; SELECT MAX(name) AS abd FROM srt; reset enable_seqscan; set enable_indexscan = off; -SELECT MIN(name) AS "AAA" FROM srt; +SELECT MIN(name) AS "ABA" FROM srt; SELECT MAX(name) AS abd FROM srt; reset enable_indexscan; @@ -148,11 +147,11 @@ SELECT name FROM srt ORDER BY name; reset enable_indexscan; -- Test assignment casts. -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::text; -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::varchar; -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::bpchar; -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'; -SELECT LOWER(name) as aaa FROM srt WHERE name = 'AAA'::citext; +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::text; +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::varchar; +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::bpchar; +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'; +SELECT LOWER(name) as aba FROM srt WHERE name = 'ABA'::citext; -- LIKE should be case-insensitive SELECT name FROM srt WHERE name LIKE '%a%' ORDER BY name; @@ -657,12 +656,12 @@ SELECT split_part('abcTdefTghi'::citext, 't', 2) = 'def' AS t; SELECT split_part('abcTdefTghi'::citext, 't'::citext, 2) = 'def' AS t; SELECT split_part('abcTdefTghi', 't'::citext, 2) = 'def' AS t; -SELECT strpos('high'::citext, 'ig' ) = 2 AS t; -SELECT strpos('high', 'ig'::citext) = 2 AS t; -SELECT strpos('high'::citext, 'ig'::citext) = 2 AS t; -SELECT strpos('high'::citext, 'IG' ) = 2 AS t; -SELECT strpos('high', 'IG'::citext) = 2 AS t; -SELECT strpos('high'::citext, 'IG'::citext) = 2 AS t; +SELECT strpos('high'::citext, 'gh' ) = 3 AS t; +SELECT strpos('high', 'gh'::citext) = 3 AS t; +SELECT strpos('high'::citext, 'gh'::citext) = 3 AS t; +SELECT strpos('high'::citext, 'GH' ) = 3 AS t; +SELECT strpos('high', 'GH'::citext) = 3 AS t; +SELECT strpos('high'::citext, 'GH'::citext) = 3 AS t; -- to_ascii() does not support UTF-8. -- to_hex() takes a numeric argument. diff --git a/contrib/intarray/bench/bench.pl b/contrib/intarray/bench/bench.pl index 8746291114..395d61655f 100755 --- a/contrib/intarray/bench/bench.pl +++ b/contrib/intarray/bench/bench.pl @@ -92,7 +92,8 @@ if ($opt{e}) { - $dbi->do("explain $sql"); + my @plan = map { "$_->[0]\n" } @{$dbi->selectall_arrayref("explain $sql")}; + print @plan; } my $t0 = [gettimeofday]; diff --git a/contrib/pg_arman/Makefile b/contrib/pg_arman/Makefile index a7addd1771..184acb18a7 100644 --- a/contrib/pg_arman/Makefile +++ b/contrib/pg_arman/Makefile @@ -21,12 +21,15 @@ OBJS = backup.o \ pgut/pgut.o \ pgut/pgut-port.o -EXTRA_CLEAN = datapagemap.c datapagemap.h xlogreader.c +EXTRA_CLEAN = datapagemap.c datapagemap.h xlogreader.c receivelog.c receivelog.h streamutil.c streamutil.h logging.h REGRESS = init option show delete backup restore -all: datapagemap.h receivelog.h streamutil.h pg_arman -ifdef $(USE_PGXS) +all: checksrcdir datapagemap.h logging.h receivelog.h streamutil.h pg_arman + +MAKE_GLOBAL="../../src/Makefile.global" +TEST_GLOBAL:=$(shell test -e ../../src/Makefile.global) +ifeq ($(.SHELLSTATUS),1) PG_CONFIG = pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) @@ -40,6 +43,8 @@ ifndef top_srcdir @exit 1 endif else +#TODO: fix me +REGRESS = subdir=contrib/pg_arman top_builddir=../.. include $(top_builddir)/src/Makefile.global @@ -52,8 +57,17 @@ PG_LIBS = $(libpq_pgport) ${PTHREAD_CFLAGS} envtest: : top_srcdir=$(top_srcdir) : libpq_srcdir = $(libpq_srcdir) + # This rule's only purpose is to give the user instructions on how to pass # the path to PostgreSQL source tree to the makefile. +.PHONY: checksrcdir +checksrcdir: +ifndef top_srcdir + @echo "You must have PostgreSQL source tree available to compile." + @echo "Pass the path to the PostgreSQL source tree to make, in the top_srcdir" + @echo "variable: \"make top_srcdir=\"" + @exit 1 +endif # Those files are symlinked from the PostgreSQL sources. xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/% @@ -62,6 +76,10 @@ datapagemap.c: % : $(top_srcdir)/src/bin/pg_rewind/% rm -f $@ && $(LN_S) $< . datapagemap.h: % : $(top_srcdir)/src/bin/pg_rewind/% rm -f && $(LN_S) $< . +#logging.c: % : $(top_srcdir)/src/bin/pg_rewind/% +# rm -f && $(LN_S) $< . +logging.h: % : $(top_srcdir)/src/bin/pg_rewind/% + rm -f && $(LN_S) $< . receivelog.c: % : $(top_srcdir)/src/bin/pg_basebackup/% rm -f && $(LN_S) $< . receivelog.h: % : $(top_srcdir)/src/bin/pg_basebackup/% @@ -70,7 +88,3 @@ streamutil.c: % : $(top_srcdir)/src/bin/pg_basebackup/% rm -f && $(LN_S) $< . streamutil.h: % : $(top_srcdir)/src/bin/pg_basebackup/% rm -f && $(LN_S) $< . - -# Disable make check -check: - true diff --git a/contrib/pg_arman/README.md b/contrib/pg_arman/README.md index 839832500a..6ccaa900fc 100644 --- a/contrib/pg_arman/README.md +++ b/contrib/pg_arman/README.md @@ -1,5 +1,8 @@ -pg_arman -======== +pg_arman fork from Postgres Professional +======================================== + +This repository contains fork of pg_arman by Postgres Professional with +block level incremental backup support. pg_arman is a backup and recovery manager for PostgreSQL servers able to do differential and full backup as well as restore a cluster to a @@ -14,7 +17,8 @@ Download -------- The latest version of this software can be found on the project website at -https://github.com/michaelpq/pg_arman. +https://github.com/postgrespro/pg_arman. Original fork of pg_arman can be +found at https://github.com/michaelpq/pg_arman. Installation ------------ @@ -48,6 +52,112 @@ launched in a way similar to common PostgreSQL extensions and modules: make installcheck +Block level incremental backup +------------------------------ + +Idea of block level incremental backup is that you may backup only blocks +changed since last full backup. It gives two major benefits: taking backups +faster and making backups smaller. + +The major question here is how to get the list of changed blocks. Since +each block contains LSN number, changed blocks could be retrieved by full scan +of all the blocks. But this approach consumes as much server IO as full +backup. + +This is why we implemented alternative approaches to retrieve +list of changed blocks. + +1. Scan WAL archive and extract changed blocks from it. However, shortcoming +of these approach is requirement to have WAL archive. + +2. Track bitmap of changes blocks inside PostgreSQL (ptrack). It introduces +some overhead to PostgreSQL performance. On our experiments it appears to be +less than 3%. + +These two approaches were implemented in this fork of pg_arman. The second +approach requires [patch for PostgreSQL 9.5](https://gist.github.com/stalkerg/44703dbcbac1da08f448b7e6966646c0). + +Testing block level incremental backup +-------------------------------------- + +You need build and install [PGPRO9_5 branch of PostgreSQL](https://github.com/postgrespro/postgrespro) or [apply this patch to PostgreSQL 9.5](https://gist.github.com/stalkerg/44703dbcbac1da08f448b7e6966646c0). + +### Retrieving changed blocks from WAL archive + +You need to enable WAL archive by adding following lines to postgresql.conf: + +``` +wal_level = archive +archive_command = 'test ! -f /home/postgres/backup/arman/wal/%f && cp %p /home/postgres/backup/arman/wal/%f' +wal_log_hints = on +``` + +Example backup (assuming PostgreSQL is running): +```bash +# Init pg_aramn backup folder +pg_arman init -B /home/postgres/backup/pgarman +cat << __EOF__ >> /home/postgres/backup/pgarman/pg_arman.ini +ARCLOG_PATH = '/home/postgres/backup/arman/wal' +__EOF__ +# Make full backup with 2 thread and verbose mode. +pg_arman backup -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman -b full -v -j 2 +# Validate backup +pg_arman validate -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman +# Show backups information +pg_arman show -B /home/postgres/backup/pgarman + +# Now you can insert or update some data in your database + +# Then start the incremental backup. +pg_arman backup -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman -b page -v -j 2 +pg_arman validate -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman +# You should see that increment is really small +pg_arman show -B /home/postgres/backup/pgarman +``` + +For restore after remove your pgdata you can use: +``` +pg_arman restore -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman -j 4 --verbose +``` + +### Retrieving changed blocks from ptrack + +The advantage of this approach is that you don't have to save WAL archive. You will need to enable ptrack in postgresql.conf (restart required). + +``` +ptrack_enable = on +``` + +Also, some WALs still need to be fetched in order to get consistent backup. pg_arman can fetch them trough the streaming replication protocol. Thus, you also need to [enable streaming replication connection](https://wiki.postgresql.org/wiki/Streaming_Replication). + +Example backup (assuming PostgreSQL is running): +```bash +# Init pg_aramn backup folder +pg_arman init -B /home/postgres/backup/pgarman +cat << __EOF__ >> /home/postgres/backup/pgarman/pg_arman.ini +ARCLOG_PATH = '/home/postgres/backup/arman/wal' +__EOF__ +# Make full backup with 2 thread and verbose mode. +pg_arman backup -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman -b full -v -j 2 --stream +# Validate backup +pg_arman validate -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman +# Show backups information +pg_arman show -B /home/postgres/backup/pgarman + +# Now you can insert or update some data in your database + +# Then start the incremental backup. +pg_arman backup -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman -b ptrack -v -j 2 --stream +pg_arman validate -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman +# You should see that increment is really small +pg_arman show -B /home/postgres/backup/pgarman +``` + +For restore after remove your pgdata you can use: +``` +pg_arman restore -B /home/postgres/backup/pgarman -D /home/postgres/pgdata/arman -j 4 --verbose --stream +``` + License ------- diff --git a/contrib/pg_arman/backup.c b/contrib/pg_arman/backup.c index 323d62d667..a1c85fef82 100644 --- a/contrib/pg_arman/backup.c +++ b/contrib/pg_arman/backup.c @@ -38,7 +38,9 @@ static XLogRecPtr stop_backup_lsn = InvalidXLogRecPtr; const char *progname = "pg_arman"; /* list of files contained in backup */ -parray *backup_files_list; +parray *backup_files_list; +static volatile uint32 total_copy_files_increment; +static uint32 total_files_num; typedef struct { @@ -47,8 +49,6 @@ typedef struct parray *files; parray *prev_files; const XLogRecPtr *lsn; - unsigned int start_file_idx; - unsigned int end_file_idx; } backup_files_args; /* @@ -106,6 +106,7 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt) pthread_t stream_thread; backup_files_args *backup_threads_args[num_threads]; + /* repack the options */ bool smooth_checkpoint = bkupopt.smooth_checkpoint; pgBackup *prev_backup = NULL; @@ -146,7 +147,7 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt) } /* clear ptrack files for FULL and DIFF backup */ - if (current.backup_mode != BACKUP_MODE_DIFF_PTRACK) + if (current.backup_mode != BACKUP_MODE_DIFF_PTRACK && !disable_ptrack_clear) pg_ptrack_clear(); /* start stream replication */ @@ -310,11 +311,21 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt) if (!check) dir_create_dir(dirpath, DIR_PERMISSION); } + else + { + total_files_num++; + } + + __sync_lock_release(&file->lock); } if (num_threads < 1) num_threads = 1; + /* sort by size for load balancing */ + parray_qsort(backup_files_list, pgFileCompareSize); + + /* init thread args with own file lists */ for (i = 0; i < num_threads; i++) { backup_files_args *arg = pg_malloc(sizeof(backup_files_args)); @@ -323,19 +334,17 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt) arg->files = backup_files_list; arg->prev_files = prev_files; arg->lsn = lsn; - arg->start_file_idx = i * (parray_num(backup_files_list)/num_threads); - if (i == num_threads - 1) - arg->end_file_idx = parray_num(backup_files_list); - else - arg->end_file_idx = (i + 1) * (parray_num(backup_files_list)/num_threads); + backup_threads_args[i] = arg; + } + + total_copy_files_increment = 0; + /* Run threads */ + for (i = 0; i < num_threads; i++) + { if (verbose) - elog(WARNING, "Start thread for start_file_idx:%i end_file_idx:%i num:%li", - arg->start_file_idx, - arg->end_file_idx, - parray_num(backup_files_list)); - backup_threads_args[i] = arg; - pthread_create(&backup_threads[i], NULL, (void *(*)(void *)) backup_files, arg); + elog(WARNING, "Start thread num:%li", parray_num(backup_threads_args[i]->files)); + pthread_create(&backup_threads[i], NULL, (void *(*)(void *)) backup_files, backup_threads_args[i]); } /* Wait theads */ @@ -345,6 +354,9 @@ do_backup_database(parray *backup_list, pgBackupOption bkupopt) pg_free(backup_threads_args[i]); } + if (progress) + fprintf(stderr, "\n"); + /* Notify end of backup */ pg_stop_backup(¤t); @@ -461,6 +473,7 @@ do_backup(pgBackupOption bkupopt) current.wal_block_size = XLOG_BLCKSZ; current.recovery_xid = 0; current.recovery_time = (time_t) 0; + current.checksum_version = get_data_checksum_version(true); /* create backup directory and backup.ini */ if (!check) @@ -910,12 +923,14 @@ backup_files(void *arg) gettimeofday(&tv, NULL); /* backup a file or create a directory */ - for (i = arguments->start_file_idx; i < arguments->end_file_idx; i++) + for (i = 0; i < parray_num(arguments->files); i++) { int ret; struct stat buf; pgFile *file = (pgFile *) parray_get(arguments->files, i); + if (__sync_lock_test_and_set(&file->lock, 1) != 0) + continue; /* If current time is rewinded, abort this backup. */ if (tv.tv_sec < file->mtime) @@ -1006,6 +1021,9 @@ backup_files(void *arg) } else elog(LOG, "unexpected file type %d", buf.st_mode); + if (progress) + fprintf(stderr, "\rProgress %i/%u", total_copy_files_increment, total_files_num-1); + __sync_fetch_and_add(&total_copy_files_increment, 1); } } @@ -1088,6 +1106,27 @@ add_files(parray *files, const char *root, bool add_root, bool is_pgdata) continue; file->is_datafile = true; + { + int find_dot; + int check_digit; + char *text_segno; + for(find_dot = path_len-1; file->path[find_dot] != '.' && find_dot >= 0; find_dot--); + if (find_dot <= 0) + continue; + + text_segno = file->path + find_dot + 1; + for(check_digit=0; text_segno[check_digit] != '\0'; check_digit++) + if (!isdigit(text_segno[check_digit])) + { + check_digit = -1; + break; + } + + if (check_digit == -1) + continue; + + file->segno = (int) strtol(text_segno, NULL, 10); + } } parray_concat(files, list_file); } @@ -1325,9 +1364,23 @@ StreamLog(void *arg) progname, (uint32) (startpos >> 32), (uint32) startpos, starttli); +#if PG_VERSION_NUM >= 90600 + StreamCtl ctl; + ctl.startpos = startpos; + ctl.timeline = starttli; + ctl.sysidentifier = NULL; + ctl.basedir = basedir; + ctl.stream_stop = stop_streaming; + ctl.standby_message_timeout = standby_message_timeout; + ctl.partial_suffix = NULL; + ctl.synchronous = false; + ctl.mark_done = false; + ReceiveXlogStream(conn, &ctl); +#else ReceiveXlogStream(conn, startpos, starttli, NULL, basedir, - stop_streaming, standby_message_timeout, ".partial", + stop_streaming, standby_message_timeout, NULL, false, false); +#endif PQfinish(conn); conn = NULL; diff --git a/contrib/pg_arman/catalog.c b/contrib/pg_arman/catalog.c index de577943fa..d7a5370f08 100644 --- a/contrib/pg_arman/catalog.c +++ b/contrib/pg_arman/catalog.c @@ -329,6 +329,7 @@ pgBackupWriteResultSection(FILE *out, pgBackup *backup) backup->data_bytes); fprintf(out, "BLOCK_SIZE=%u\n", backup->block_size); fprintf(out, "XLOG_BLOCK_SIZE=%u\n", backup->wal_block_size); + fprintf(out, "CHECKSUM_VERSION=%u\n", backup->checksum_version); fprintf(out, "STATUS=%s\n", status2str(backup->status)); } @@ -383,6 +384,7 @@ catalog_read_ini(const char *path) { 'I', 0, "data-bytes" , NULL, SOURCE_ENV }, { 'u', 0, "block-size" , NULL, SOURCE_ENV }, { 'u', 0, "xlog-block-size" , NULL, SOURCE_ENV }, + { 'u', 0, "checksum_version" , NULL, SOURCE_ENV }, { 's', 0, "status" , NULL, SOURCE_ENV }, { 0 } }; @@ -405,6 +407,7 @@ catalog_read_ini(const char *path) options[i++].var = &backup->data_bytes; options[i++].var = &backup->block_size; options[i++].var = &backup->wal_block_size; + options[i++].var = &backup->checksum_version; options[i++].var = &status; Assert(i == lengthof(options) - 1); diff --git a/contrib/pg_arman/data.c b/contrib/pg_arman/data.c index 75ad3de527..eb57d8aefa 100644 --- a/contrib/pg_arman/data.c +++ b/contrib/pg_arman/data.c @@ -17,6 +17,7 @@ #include "libpq/pqsignal.h" #include "storage/block.h" #include "storage/bufpage.h" +#include "storage/checksum_impl.h" typedef struct BackupPageHeader { @@ -41,8 +42,7 @@ parse_page(const DataPage *page, page_data->pd_lower <= page_data->pd_upper && page_data->pd_upper <= page_data->pd_special && page_data->pd_special <= BLCKSZ && - page_data->pd_special == MAXALIGN(page_data->pd_special) && - !XLogRecPtrIsInvalid(*lsn)) + page_data->pd_special == MAXALIGN(page_data->pd_special)) { *offset = page_data->pd_lower; *length = page_data->pd_upper - page_data->pd_lower; @@ -64,14 +64,16 @@ backup_data_file(const char *from_root, const char *to_root, pgFile *file, const XLogRecPtr *lsn) { char to_path[MAXPGPATH]; - FILE *in; - FILE *out; + FILE *in; + FILE *out; BackupPageHeader header; - DataPage page; /* used as read buffer */ + DataPage page; /* used as read buffer */ BlockNumber blknum = 0; size_t read_len = 0; pg_crc32 crc; off_t offset; + char write_buffer[sizeof(header)+BLCKSZ]; + size_t write_buffer_real_size; INIT_CRC32C(crc); @@ -111,6 +113,7 @@ backup_data_file(const char *from_root, const char *to_root, /* confirm server version */ check_server_version(); + /* * Read each page and write the page excluding hole. If it has been * determined that the page can be copied safely, but no page map @@ -128,36 +131,99 @@ backup_data_file(const char *from_root, const char *to_root, XLogRecPtr page_lsn; int upper_offset; int upper_length; + int try_checksum = 100; + bool stop_backup = false; header.block = blknum; - /* - * If an invalid data page was found, fallback to simple copy to ensure - * all pages in the file don't have BackupPageHeader. - */ - if (!parse_page(&page, &page_lsn, - &header.hole_offset, &header.hole_length)) + while(try_checksum) { - elog(LOG, "%s fall back to simple copy", file->path); - fclose(in); - fclose(out); - file->is_datafile = false; - return copy_file(from_root, to_root, file); + try_checksum--; + /* + * If an invalid data page was found, fallback to simple copy to ensure + * all pages in the file don't have BackupPageHeader. + */ + if (!parse_page(&page, &page_lsn, + &header.hole_offset, &header.hole_length)) + { + struct stat st; + int i; + + for(i=0; ipath, blknum); + goto end_checks; + } + + stat(file->path, &st); + elog(WARNING, "SIZE: %lu %lu pages:%lu pages:%lu i:%i", file->size, st.st_size, file->size/BLCKSZ, st.st_size/BLCKSZ, i); + if (st.st_size != file->size && blknum >= file->size/BLCKSZ-1) + { + stop_backup = true; + elog(WARNING, "File: %s blknum %u, file size has changed before backup start", file->path, blknum); + break; + } + if (blknum >= file->size/BLCKSZ-1) + { + stop_backup = true; + elog(WARNING, "File: %s blknum %u, the last page is empty, skip", file->path, blknum); + break; + } + if (st.st_size != file->size && blknum < file->size/BLCKSZ-1) + { + elog(WARNING, "File: %s blknum %u, file size has changed before backup start, it seems bad", file->path, blknum); + if (!try_checksum) + break; + } + if (try_checksum) + { + elog(WARNING, "File: %s blknum %u have wrong page header, try again", file->path, blknum); + fseek(in, -sizeof(page), SEEK_CUR); + fread(&page, 1, sizeof(page), in); + continue; + } + else + elog(ERROR, "File: %s blknum %u have wrong page header.", file->path, blknum); + } + + + if(current.checksum_version && + pg_checksum_page(page.data, file->segno * RELSEG_SIZE + blknum) != ((PageHeader) page.data)->pd_checksum) + { + if (try_checksum) + { + elog(WARNING, "File: %s blknum %u have wrong checksum, try again", file->path, blknum); + usleep(100); + fseek(in, -sizeof(page), SEEK_CUR); + fread(&page, 1, sizeof(page), in); + } + else + elog(ERROR, "File: %s blknum %u have wrong checksum.", file->path, blknum); + } else { + try_checksum = 0; + } } + end_checks: + file->read_size += read_len; - /* if the page has not been modified since last backup, skip it */ - if (lsn && !XLogRecPtrIsInvalid(page_lsn) && page_lsn < *lsn) - continue; + if(stop_backup) + break; upper_offset = header.hole_offset + header.hole_length; upper_length = BLCKSZ - upper_offset; + write_buffer_real_size = sizeof(header)+header.hole_offset+upper_length; + memcpy(write_buffer, &header, sizeof(header)); + if (header.hole_offset) + memcpy(write_buffer+sizeof(header), page.data, header.hole_offset); + if (upper_length) + memcpy(write_buffer+sizeof(header)+header.hole_offset, page.data + upper_offset, upper_length); + /* write data page excluding hole */ - if (fwrite(&header, 1, sizeof(header), out) != sizeof(header) || - fwrite(page.data, 1, header.hole_offset, out) != header.hole_offset || - fwrite(page.data + upper_offset, 1, upper_length, out) != upper_length) + if(fwrite(write_buffer, 1, write_buffer_real_size, out) != write_buffer_real_size) { int errno_tmp = errno; /* oops */ @@ -185,47 +251,102 @@ backup_data_file(const char *from_root, const char *to_root, int upper_offset; int upper_length; int ret; + int try_checksum = 100; + bool stop_backup = false; offset = blknum * BLCKSZ; - if (offset > 0) + while(try_checksum) { - ret = fseek(in, offset, SEEK_SET); - if (ret != 0) - elog(ERROR, - "Can't seek in file offset: %llu ret:%i\n", - (long long unsigned int) offset, ret); + if (offset > 0) + { + ret = fseek(in, offset, SEEK_SET); + if (ret != 0) + elog(ERROR, + "Can't seek in file offset: %llu ret:%i\n", + (long long unsigned int) offset, ret); + } + read_len = fread(&page, 1, sizeof(page), in); + + header.block = blknum; + + try_checksum--; + + /* + * If an invalid data page was found, fallback to simple copy to ensure + * all pages in the file don't have BackupPageHeader. + */ + if (!parse_page(&page, &page_lsn, + &header.hole_offset, &header.hole_length)) + { + struct stat st; + int i; + + for(i=0; ipath, blknum); + goto end_checks2; + } + + stat(file->path, &st); + elog(WARNING, "PTRACK SIZE: %lu %lu pages:%lu pages:%lu i:%i", file->size, st.st_size, file->size/BLCKSZ, st.st_size/BLCKSZ, i); + if (st.st_size != file->size && blknum >= file->size/BLCKSZ-1) + { + stop_backup = true; + elog(WARNING, "File: %s blknum %u, file size has changed before backup start", file->path, blknum); + break; + } + if (st.st_size != file->size && blknum < file->size/BLCKSZ-1) + { + elog(WARNING, "File: %s blknum %u, file size has changed before backup start, it seems bad", file->path, blknum); + if (!try_checksum) + break; + } + if (try_checksum) + { + elog(WARNING, "File: %s blknum %u have wrong page header, try again", file->path, blknum); + usleep(100); + fseek(in, -sizeof(page), SEEK_CUR); + fread(&page, 1, sizeof(page), in); + continue; + } + else + elog(ERROR, "File: %s blknum %u have wrong page header.", file->path, blknum); + } + + if(current.checksum_version && + pg_checksum_page(page.data, file->segno * RELSEG_SIZE + blknum) != ((PageHeader) page.data)->pd_checksum) + { + if (try_checksum) + elog(WARNING, "File: %s blknum %u have wrong checksum, try again", file->path, blknum); + else + elog(ERROR, "File: %s blknum %u have wrong checksum.", file->path, blknum); + } + else + { + try_checksum = 0; + } } - read_len = fread(&page, 1, sizeof(page), in); - - header.block = blknum; - /* - * If an invalid data page was found, fallback to simple copy to ensure - * all pages in the file don't have BackupPageHeader. - */ - if (!parse_page(&page, &page_lsn, - &header.hole_offset, &header.hole_length)) - { - elog(LOG, "%s fall back to simple copy", file->path); - fclose(in); - fclose(out); - file->is_datafile = false; - return copy_file(from_root, to_root, file); - } + file->read_size += read_len; - /* if the page has not been modified since last backup, skip it */ - if (lsn && !XLogRecPtrIsInvalid(page_lsn) && page_lsn < *lsn) - continue; + if(stop_backup) + break; - file->read_size += read_len; + end_checks2: upper_offset = header.hole_offset + header.hole_length; upper_length = BLCKSZ - upper_offset; + write_buffer_real_size = sizeof(header)+header.hole_offset+upper_length; + memcpy(write_buffer, &header, sizeof(header)); + if (header.hole_offset) + memcpy(write_buffer+sizeof(header), page.data, header.hole_offset); + if (upper_length) + memcpy(write_buffer+sizeof(header)+header.hole_offset, page.data + upper_offset, upper_length); + /* write data page excluding hole */ - if (fwrite(&header, 1, sizeof(header), out) != sizeof(header) || - fwrite(page.data, 1, header.hole_offset, out) != header.hole_offset || - fwrite(page.data + upper_offset, 1, upper_length, out) != upper_length) + if(fwrite(write_buffer, 1, write_buffer_real_size, out) != write_buffer_real_size) { int errno_tmp = errno; /* oops */ @@ -299,7 +420,8 @@ backup_data_file(const char *from_root, const char *to_root, void restore_data_file(const char *from_root, const char *to_root, - pgFile *file) + pgFile *file, + pgBackup *backup) { char to_path[MAXPGPATH]; FILE *in; @@ -386,6 +508,22 @@ restore_data_file(const char *from_root, blknum, file->path, strerror(errno)); } + /* update checksum because we are not save whole */ + if(backup->checksum_version) + { + /* skip calc checksum if zero page */ + if(page.page_data.pd_upper == 0) + { + int i; + for(i=0; ipd_checksum = pg_checksum_page(page.data, file->segno * RELSEG_SIZE + header.block); + } + + skip_checksum: + /* * Seek and write the restored page. Backup might have holes in * differential backups. diff --git a/contrib/pg_arman/dir.c b/contrib/pg_arman/dir.c index dd89dedf60..195a5e7fe1 100644 --- a/contrib/pg_arman/dir.c +++ b/contrib/pg_arman/dir.c @@ -28,6 +28,7 @@ const char *pgdata_exclude[] = NULL, /* arclog_path will be set later */ NULL, /* 'pg_tblspc' will be set later */ NULL, /* sentinel */ + NULL }; static pgFile *pgFileNew(const char *path, bool omit_symlink); @@ -192,6 +193,21 @@ pgFileComparePathDesc(const void *f1, const void *f2) return -pgFileComparePath(f1, f2); } +/* Compare two pgFile with their size */ +int +pgFileCompareSize(const void *f1, const void *f2) +{ + pgFile *f1p = *(pgFile **)f1; + pgFile *f2p = *(pgFile **)f2; + + if (f1p->size > f2p->size) + return 1; + else if (f1p->size < f2p->size) + return -1; + else + return 0; +} + /* Compare two pgFile with their modify timestamp. */ int pgFileCompareMtime(const void *f1, const void *f2) @@ -260,9 +276,13 @@ dir_list_file(parray *files, const char *root, const char *exclude[], bool omit_ fclose(black_list_file); parray_qsort(black_list, BlackListCompare); dir_list_file_internal(files, root, exclude, omit_symlink, add_root, black_list); + parray_qsort(files, pgFileComparePath); } else + { dir_list_file_internal(files, root, exclude, omit_symlink, add_root, NULL); + parray_qsort(files, pgFileComparePath); + } } void @@ -406,8 +426,6 @@ dir_list_file_internal(parray *files, const char *root, const char *exclude[], break; /* pseudo loop */ } - - parray_qsort(files, pgFileComparePath); } /* print mkdirs.sh */ @@ -529,7 +547,7 @@ dir_read_file_list(const char *root, const char *file_txt) pg_crc32 crc; unsigned int mode; /* bit length of mode_t depends on platforms */ struct tm tm; - pgFile *file; + pgFile *file; memset(&tm, 0, sizeof(tm)); if (sscanf(buf, "%s %c %lu %u %o %d-%d-%d %d:%d:%d", @@ -572,6 +590,30 @@ dir_read_file_list(const char *root, const char *file_txt) strcpy(file->path, path); parray_append(files, file); + + if(file->is_datafile) + { + int find_dot; + int check_digit; + char *text_segno; + size_t path_len = strlen(file->path); + for(find_dot = path_len-1; file->path[find_dot] != '.' && find_dot >= 0; find_dot--); + if (find_dot <= 0) + continue; + + text_segno = file->path + find_dot + 1; + for(check_digit=0; text_segno[check_digit] != '\0'; check_digit++) + if (!isdigit(text_segno[check_digit])) + { + check_digit = -1; + break; + } + + if (check_digit == -1) + continue; + + file->segno = (int) strtol(text_segno, NULL, 10); + } } fclose(fp); diff --git a/contrib/pg_arman/doc/pg_arman.md b/contrib/pg_arman/doc/pg_arman.md index 138033b69a..079c099b39 100644 --- a/contrib/pg_arman/doc/pg_arman.md +++ b/contrib/pg_arman/doc/pg_arman.md @@ -1,12 +1,10 @@ -% PG_ARMAN(1) -% Michael Paquier, Yury Zhuravlev -% June 2016 +# pg_arman(1) -# NAME +## NAME pg_arman - Backup and recovery manager for PostgreSQL -# SYNOPSIS +## SYNOPSIS ``` pg_arman [ OPTIONS ] { init | @@ -21,7 +19,7 @@ DATE is the start time of the target backup in ISO-format: (YYYY-MM-DD HH:MI:SS). Prefix match is used to compare DATE and backup files. -# DESCRIPTION +## DESCRIPTION pg_arman is a utility program to backup and restore PostgreSQL database. @@ -34,7 +32,7 @@ It proposes the following features: - Support for full and differential backup + ptrack differential backup - Management of backups with integrated catalog -# COMMANDS +## COMMANDS pg_arman supports the following commands. See also **OPTIONS** for more details. @@ -57,7 +55,7 @@ details. * **delete**: Delete backup files. -## INITIALIZATION +### INITIALIZATION First, you need to create "a backup catalog" to store backup files and their metadata. It is recommended to setup archive_mode and archive_command @@ -70,7 +68,7 @@ specify it in PGDATA environmental variable or -D/--pgdata option. $ pg_arman init -B /path/to/backup/ ``` -## BACKUP +### BACKUP Backup target can be one of the following types: @@ -87,7 +85,7 @@ For use it you need set ptrack_enable option to "on". It is recommended to verify backup files as soon as possible after backup. Unverified backup cannot be used in restore and in differential backups. -## RESTORE +### RESTORE PostgreSQL server should be stopped before performing a restore. If database cluster still exists, restore command will save unarchived transaction log @@ -105,7 +103,7 @@ target. If pg_control is not present, TimeLineID in the full backup used by the restore will be a restore target. -## EXAMPLES +### EXAMPLES To reduce the number of command line arguments, you can set BACKUP_PATH, an environment variable, to the absolute path of the backup catalog and @@ -119,7 +117,7 @@ KEEP_DATA_GENERATIONS = 3 KEEP_DATA_DAYS = 120 ``` -## TAKE A BACKUP +### TAKE A BACKUP This example takes a full backup of the whole database. Then, it validates all unvalidated backups. @@ -128,7 +126,7 @@ $ pg_arman backup --backup-mode=full $ pg_arman validate ``` -## RESTORE FROM A BACKUP +### RESTORE FROM A BACKUP Here are some commands to restore from a backup: @@ -138,7 +136,7 @@ $ pg_arman restore $ pg_ctl start ``` -## SHOW A BACKUP +### SHOW A BACKUP ``` $ pg_arman show =================================================================================== @@ -195,13 +193,13 @@ the specified date. This command also cleans up in the WAL archive the WAL segments that are no longer needed to restore from the remaining backups. -## OPTIONS +### OPTIONS pg_arman accepts the following command line parameters. Some of them can be also specified as environment variables. See also *PARAMETERS* for the details. -## COMMON OPTIONS +### COMMON OPTIONS As a general rule, paths for data location need to be specified as absolute paths; relative paths are not allowed. @@ -221,11 +219,11 @@ absolute paths; relative paths are not allowed. parameters and required resources. The option is typically used with --verbose option to verify the operation. -## BACKUP OPTIONS +### BACKUP OPTIONS **-b** BACKUPMODE / **--backup-mode**=BACKUPMODE: Specify backup target files. Available options are: "full", - "page". + "page", "ptrack". **-C** / **--smooth-checkpoint**: Checkpoint is performed on every backups. If the option is specified, @@ -246,9 +244,12 @@ absolute paths; relative paths are not allowed. Number of threads for backup. **--stream**: - Enable stream replication for save WAL during backup process. + Enable stream replication for save WAL during backup process. -## RESTORE OPTIONS +**--disable-ptrack-clear**: + Disable clear ptrack files for postgres without ptrack patch. + +### RESTORE OPTIONS The parameters whose name start are started with --recovery refer to the same parameters as the ones in recovery.confin recovery.conf. @@ -274,15 +275,14 @@ the same parameters as the ones in recovery.confin recovery.conf. **--stream**: Restore without recovery.conf and use pg_xlog WALs. Before you need backup with **--stream** option. This option will disable all **--recovery-** - options. + options. -## CATALOG OPTIONS +### CATALOG OPTIONS **-a** / **--show-all**: Show all existing backups, including the deleted ones. -## CONNECTION OPTIONS - +### CONNECTION OPTIONS Parameters to connect PostgreSQL server. **-d** DBNAME / **--dbname**=DBNAME: @@ -315,7 +315,7 @@ Parameters to connect PostgreSQL server. if the server wants a password. In some cases it is worth typing -W to avoid the extra connection attempt. -## GLOBAL OPTIONS +### GLOBAL OPTIONS **--help**: Print help, then exit. @@ -326,7 +326,7 @@ Parameters to connect PostgreSQL server. **-v** / **--verbose**: If specified, pg_arman works in verbose mode. -# PARAMETERS +## PARAMETERS Some of parameters can be specified as command line arguments, environment variables or in configuration file as follows: @@ -360,7 +360,7 @@ line and configuration file for security reason. This utility, like most other PostgreSQL utilities, also uses the environment variables supported by libpq (see Environment Variables). -# RESTRICTIONS +## RESTRICTIONS pg_arman has the following restrictions. @@ -373,21 +373,21 @@ pg_arman has the following restrictions. WAL directory or archived WAL directory, the backup or restore will fail depending on the backup mode selected. -# DETAILS +## DETAILS -## RECOVERY TO POINT-IN-TIME +### RECOVERY TO POINT-IN-TIME pg_arman can recover to point-in-time if timeline, transaction ID, or timestamp is specified in recovery.conf. xlogdump is a contrib module of PostgreSQL core that allows checking in the content of WAL files and determine when to recover. This might help. -## CONFIGURATION FILE +### CONFIGURATION FILE Setting parameters in configuration file is done as "name=value". Quotes are required if the value contains whitespaces. Comments should start with "#" and are automatically ignored. Whitespaces and tabs are ignored excluding values. -## RESTRICTIONS +### RESTRICTIONS * In order to work, the PostgreSQL instance on which backups are taken need to have data checksums enabled or to enable wal_log_hints. * pg_arman is aimed at working with PostgreSQL 9.5 and newer versions. @@ -395,7 +395,7 @@ to have data checksums enabled or to enable wal_log_hints. archive or hot_standby and ptrack_enable. * For stream feature you need configure streaming replication in your postgres. -## EXIT CODE +### EXIT CODE pg_arman returns exit codes for each error status. ``` @@ -406,7 +406,7 @@ Code Name Description 3 PANIC Unknown critical condition ``` -# AUTHORS +## AUTHOR ## pg_arman is a fork of pg_arman that was originally written by NTT, now developed and maintained by Michael Paquier. Threads, WAL diff, ptrack diff, stream WAL and some other features developed by diff --git a/contrib/pg_arman/expected/option.out b/contrib/pg_arman/expected/option.out index 4a01617d0f..7467cf0582 100644 --- a/contrib/pg_arman/expected/option.out +++ b/contrib/pg_arman/expected/option.out @@ -18,6 +18,7 @@ Common Options: -c, --check show what would have been done -j, --threads=NUM num threads for backup and restore --stream use stream for save/restore WAL during backup + --progress show progress copy files Backup options: -b, --backup-mode=MODE full,page,ptrack @@ -25,6 +26,8 @@ Backup options: --validate validate backup after taking it --keep-data-generations=N keep GENERATION of full data backup --keep-data-days=DAY keep enough data backup to recover to DAY days age + --disable-ptrack-clear disable clear ptrack for postgres without ptrack + --backup-pg-log start backup pg_log directory Restore options: --recovery-target-time time stamp up to which recovery will proceed diff --git a/contrib/pg_arman/pg_arman.c b/contrib/pg_arman/pg_arman.c index 9a575503bf..a91af247cd 100644 --- a/contrib/pg_arman/pg_arman.c +++ b/contrib/pg_arman/pg_arman.c @@ -36,7 +36,10 @@ static int keep_data_generations = KEEP_INFINITE; static int keep_data_days = KEEP_INFINITE; int num_threads = 1; bool stream_wal = false; +bool disable_ptrack_clear = false; +static bool backup_logs = false; static bool backup_validate = false; +bool progress = false; /* restore configuration */ static char *target_time; @@ -59,8 +62,11 @@ static pgut_option options[] = /* common options */ { 'b', 'c', "check", &check }, { 'i', 'j', "threads", &num_threads }, - { 'b', 8, "stream", &stream_wal }, + { 'b', 8, "stream", &stream_wal }, + { 'b', 11, "progress", &progress }, /* backup options */ + { 'b', 9, "disable-ptrack-clear", &disable_ptrack_clear }, + { 'b', 10, "backup-pg-log", &backup_logs }, { 'f', 'b', "backup-mode", opt_backup_mode, SOURCE_ENV }, { 'b', 'C', "smooth-checkpoint", &smooth_checkpoint, SOURCE_ENV }, /* options with only long name (keep-xxx) */ @@ -168,11 +174,14 @@ main(int argc, char *argv[]) elog(ERROR, "delete command needs ARCLOG_PATH (-A, --arclog-path) to be set"); /* setup exclusion list for file search */ - for (i = 0; pgdata_exclude[i]; i++) /* find first empty slot */ - ; + for (i = 0; pgdata_exclude[i]; i++); /* find first empty slot */ + if (arclog_path) pgdata_exclude[i++] = arclog_path; + if(!backup_logs) + pgdata_exclude[i++] = "pg_log"; + /* do actual operation */ if (pg_strcasecmp(cmd, "init") == 0) return do_init(); @@ -232,12 +241,15 @@ pgut_help(bool details) printf(_(" -c, --check show what would have been done\n")); printf(_(" -j, --threads=NUM num threads for backup and restore\n")); printf(_(" --stream use stream for save/restore WAL during backup\n")); + printf(_(" --progress show progress copy files\n")); printf(_("\nBackup options:\n")); printf(_(" -b, --backup-mode=MODE full,page,ptrack\n")); printf(_(" -C, --smooth-checkpoint do smooth checkpoint before backup\n")); printf(_(" --validate validate backup after taking it\n")); printf(_(" --keep-data-generations=N keep GENERATION of full data backup\n")); printf(_(" --keep-data-days=DAY keep enough data backup to recover to DAY days age\n")); + printf(_(" --disable-ptrack-clear disable clear ptrack for postgres without ptrack\n")); + printf(_(" --backup-pg-log start backup pg_log directory\n")); printf(_("\nRestore options:\n")); printf(_(" --recovery-target-time time stamp up to which recovery will proceed\n")); printf(_(" --recovery-target-xid transaction ID up to which recovery will proceed\n")); diff --git a/contrib/pg_arman/pg_arman.h b/contrib/pg_arman/pg_arman.h index 13588c45fe..fb11bce717 100644 --- a/contrib/pg_arman/pg_arman.h +++ b/contrib/pg_arman/pg_arman.h @@ -12,8 +12,6 @@ #include "postgres_fe.h" #include -#include - #include "libpq-fe.h" #include "pgut/pgut.h" @@ -25,6 +23,7 @@ #include "datapagemap.h" #include "storage/bufpage.h" #include "storage/block.h" +#include "storage/checksum.h" /* Query to fetch current transaction ID */ #define TXID_CURRENT_SQL "SELECT txid_current();" @@ -57,11 +56,12 @@ typedef struct pgFile that the file existed but was not backed up because not modified since last backup. */ pg_crc32 crc; /* CRC value of the file, regular file only */ - char *linked; /* path of the linked file */ + char *linked; /* path of the linked file */ bool is_datafile; /* true if the file is PostgreSQL data file */ char *path; /* path of the file */ char *ptrack_path; int segno; /* Segment number for ptrack */ + volatile uint32 lock; datapagemap_t pagemap; } pgFile; @@ -142,6 +142,7 @@ typedef struct pgBackup /* data/wal block size for compatibility check */ uint32 block_size; uint32 wal_block_size; + uint32 checksum_version; } pgBackup; typedef struct pgBackupOption @@ -210,6 +211,8 @@ extern parray *backup_files_list; extern int num_threads; extern bool stream_wal; +extern bool disable_ptrack_clear; +extern bool progress; /* in backup.c */ extern int do_backup(pgBackupOption bkupopt); @@ -283,6 +286,7 @@ extern void pgFileFree(void *file); extern pg_crc32 pgFileGetCRC(pgFile *file); extern int pgFileComparePath(const void *f1, const void *f2); extern int pgFileComparePathDesc(const void *f1, const void *f2); +extern int pgFileCompareSize(const void *f1, const void *f2); extern int pgFileCompareMtime(const void *f1, const void *f2); extern int pgFileCompareMtimeDesc(const void *f1, const void *f2); @@ -290,7 +294,7 @@ extern int pgFileCompareMtimeDesc(const void *f1, const void *f2); extern bool backup_data_file(const char *from_root, const char *to_root, pgFile *file, const XLogRecPtr *lsn); extern void restore_data_file(const char *from_root, const char *to_root, - pgFile *file); + pgFile *file, pgBackup *backup); extern bool copy_file(const char *from_root, const char *to_root, pgFile *file); @@ -308,6 +312,7 @@ extern const char *status2str(BackupStatus status); extern void remove_trailing_space(char *buf, int comment_mark); extern void remove_not_digit(char *buf, size_t len, const char *str); extern XLogRecPtr get_last_ptrack_lsn(void); +extern uint32 get_data_checksum_version(bool safe); /* in status.c */ extern bool is_pg_running(void); diff --git a/contrib/pg_arman/pgut/pgut.c b/contrib/pg_arman/pgut/pgut.c index ff71d9e1d1..e4775aeab4 100644 --- a/contrib/pg_arman/pgut/pgut.c +++ b/contrib/pg_arman/pgut/pgut.c @@ -50,6 +50,16 @@ static bool in_cleanup = false; static bool parse_pair(const char buffer[], char key[], char value[]); +typedef enum +{ + PG_DEBUG, + PG_PROGRESS, + PG_WARNING, + PG_FATAL +} eLogType; + +void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3); + /* Connection routines */ static void init_cancel_handler(void); static void on_before_exec(PGconn *conn); @@ -1202,6 +1212,45 @@ elog(int elevel, const char *fmt, ...) exit_or_abort(elevel); } +void pg_log(eLogType type, const char *fmt, ...) +{ + va_list args; + + if (!verbose && type <= PG_PROGRESS) + return; + if (quiet && type < PG_WARNING) + return; + + switch (type) + { + case PG_DEBUG: + fputs("DEBUG: ", stderr); + break; + case PG_PROGRESS: + fputs("PROGRESS: ", stderr); + break; + case PG_WARNING: + fputs("WARNING: ", stderr); + break; + case PG_FATAL: + fputs("FATAL: ", stderr); + break; + default: + if (type >= PG_FATAL) + fputs("ERROR: ", stderr); + break; + } + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + fflush(stderr); + va_end(args); + + if (type > 0) + exit_or_abort(type); +} + #ifdef WIN32 static CRITICAL_SECTION cancelConnLock; #endif diff --git a/contrib/pg_arman/restore.c b/contrib/pg_arman/restore.c index e46d5cd924..89022a705b 100644 --- a/contrib/pg_arman/restore.c +++ b/contrib/pg_arman/restore.c @@ -21,8 +21,6 @@ typedef struct { parray *files; pgBackup *backup; - unsigned int start_file_idx; - unsigned int end_file_idx; } restore_files_args; static void backup_online_files(bool re_recovery); @@ -317,23 +315,22 @@ restore_database(pgBackup *backup) if (num_threads < 1) num_threads = 1; + for (i = 0; i < parray_num(files); i++) + { + pgFile *file = (pgFile *) parray_get(files, i); + + __sync_lock_release(&file->lock); + } + /* restore files into $PGDATA */ for (i = 0; i < num_threads; i++) { restore_files_args *arg = pg_malloc(sizeof(restore_files_args)); arg->files = files; arg->backup = backup; - arg->start_file_idx = i * (parray_num(files)/num_threads); - if (i == num_threads - 1) - arg->end_file_idx = parray_num(files); - else - arg->end_file_idx = (i + 1) * (parray_num(files)/num_threads); if (verbose) - elog(WARNING, "Start thread for start_file_idx:%i end_file_idx:%i num:%li", - arg->start_file_idx, - arg->end_file_idx, - parray_num(files)); + elog(WARNING, "Start thread for num:%li", parray_num(files)); restore_threads_args[i] = arg; pthread_create(&restore_threads[i], NULL, (void *(*)(void *)) restore_files, arg); @@ -403,10 +400,12 @@ restore_files(void *arg) restore_files_args *arguments = (restore_files_args *)arg; /* restore files into $PGDATA */ - for (i = arguments->start_file_idx; i < arguments->end_file_idx; i++) + for (i = 0; i < parray_num(arguments->files); i++) { char from_root[MAXPGPATH]; pgFile *file = (pgFile *) parray_get(arguments->files, i); + if (__sync_lock_test_and_set(&file->lock, 1) != 0) + continue; pgBackupGetPath(arguments->backup, from_root, lengthof(from_root), DATABASE_DIR); @@ -437,7 +436,7 @@ restore_files(void *arg) /* restore file */ if (!check) - restore_data_file(from_root, pgdata, file); + restore_data_file(from_root, pgdata, file, arguments->backup); /* print size of restored file */ if (!check) diff --git a/contrib/pg_arman/sql/restore.sh b/contrib/pg_arman/sql/restore.sh index ea2b65745d..bdbca96b69 100644 --- a/contrib/pg_arman/sql/restore.sh +++ b/contrib/pg_arman/sql/restore.sh @@ -183,6 +183,7 @@ psql --no-psqlrc -p ${TEST_PGPORT} -d pgbench -c "SELECT * FROM pgbench_branches pg_ctl stop -m immediate > /dev/null 2>&1 pg_arman restore -B ${BACKUP_PATH} --stream --verbose >> ${TEST_BASE}/TEST-0011-run.out 2>&1;echo $? pg_ctl start -w -t 600 > /dev/null 2>&1 +sleep 5 psql --no-psqlrc -p ${TEST_PGPORT} -d pgbench -c "SELECT * FROM pgbench_branches;" > ${TEST_BASE}/TEST-0011-after.out diff ${TEST_BASE}/TEST-0011-before.out ${TEST_BASE}/TEST-0011-after.out echo '' diff --git a/contrib/pg_arman/util.c b/contrib/pg_arman/util.c index b6a8f2a7c7..f053ac3424 100644 --- a/contrib/pg_arman/util.c +++ b/contrib/pg_arman/util.c @@ -111,6 +111,24 @@ get_current_timeline(bool safe) return ControlFile.checkPointCopy.ThisTimeLineID; } +uint32 +get_data_checksum_version(bool safe) +{ + ControlFileData ControlFile; + char *buffer; + size_t size; + + /* First fetch file... */ + buffer = slurpFile(pgdata, "global/pg_control", &size, safe); + if (buffer == NULL) + return 0; + digestControlFile(&ControlFile, buffer, size); + pg_free(buffer); + + return ControlFile.data_checksum_version; +} + + /* * Convert time_t value to ISO-8601 format string */ diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 17b4b6fa6f..da13bde359 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -124,7 +124,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS) fctx->tupdesc = BlessTupleDesc(tupledesc); /* Allocate NBuffers worth of BufferCachePagesRec records. */ - fctx->record = (BufferCachePagesRec *) palloc(sizeof(BufferCachePagesRec) * NBuffers); + fctx->record = (BufferCachePagesRec *) + MemoryContextAllocHuge(CurrentMemoryContext, + sizeof(BufferCachePagesRec) * NBuffers); /* Set max calls and remember the user function context. */ funcctx->max_calls = NBuffers; diff --git a/contrib/pg_pathman/.gitignore b/contrib/pg_pathman/.gitignore index 64cd1a7e7a..50fb51a52f 100644 --- a/contrib/pg_pathman/.gitignore +++ b/contrib/pg_pathman/.gitignore @@ -1,3 +1,9 @@ +.deps +isolation_output +results/* +regression.diffs +regression.out *.o *.so -pg_pathman--*.sql \ No newline at end of file +*.pyc +pg_pathman--*.sql diff --git a/contrib/pg_pathman/.travis.yml b/contrib/pg_pathman/.travis.yml new file mode 100644 index 0000000000..36b5bc04ab --- /dev/null +++ b/contrib/pg_pathman/.travis.yml @@ -0,0 +1,22 @@ +os: + - linux + +sudo: required +dist: trusty + +language: c + +compiler: + - clang + - gcc + +before_install: + - sudo sh ./travis/apt.postgresql.org.sh + +env: + - PGVERSION=9.6 CHECK_CODE=true + - PGVERSION=9.6 CHECK_CODE=false + - PGVERSION=9.5 CHECK_CODE=true + - PGVERSION=9.5 CHECK_CODE=false + +script: bash ./travis/pg-travis-test.sh diff --git a/contrib/pg_pathman/Makefile b/contrib/pg_pathman/Makefile index 45558fe6b8..a451089773 100644 --- a/contrib/pg_pathman/Makefile +++ b/contrib/pg_pathman/Makefile @@ -1,14 +1,23 @@ # contrib/pg_pathman/Makefile MODULE_big = pg_pathman -OBJS = init.o pg_pathman.o dsm_array.o rangeset.o pl_funcs.o worker.o $(WIN32RES) +OBJS = src/init.o src/relation_info.o src/utils.o src/partition_filter.o \ + src/runtimeappend.o src/runtime_merge_append.o src/pg_pathman.o src/rangeset.o \ + src/pl_funcs.o src/pl_range_funcs.o src/pl_hash_funcs.o src/pathman_workers.o \ + src/hooks.o src/nodes_common.o src/xact_handling.o src/copy_stmt_hooking.o \ + src/pg_compat.o $(WIN32RES) EXTENSION = pg_pathman -EXTVERSION = 0.1 +EXTVERSION = 1.0 DATA_built = $(EXTENSION)--$(EXTVERSION).sql PGFILEDESC = "pg_pathman - partitioning tool" -REGRESS = pg_pathman +REGRESS = pathman_basic \ + pathman_runtime_nodes \ + pathman_callbacks \ + pathman_domains \ + pathman_foreign_keys \ + pathman_rowmarks EXTRA_REGRESS_OPTS=--temp-config=$(top_srcdir)/$(subdir)/conf.add EXTRA_CLEAN = $(EXTENSION)--$(EXTVERSION).sql ./isolation_output @@ -26,7 +35,7 @@ endif $(EXTENSION)--$(EXTVERSION).sql: init.sql hash.sql range.sql cat $^ > $@ -ISOLATIONCHECKS=insert_trigger +ISOLATIONCHECKS=insert_nodes for_update rollback_on_create_partitions submake-isolation: $(MAKE) -C $(top_builddir)/src/test/isolation all @@ -34,6 +43,6 @@ submake-isolation: isolationcheck: | submake-isolation $(MKDIR_P) isolation_output $(pg_isolation_regress_check) \ - --temp-config=$(top_srcdir)/$(subdir)/conf.add \ - --outputdir=./isolation_output \ - $(ISOLATIONCHECKS) \ No newline at end of file + --temp-config=$(top_srcdir)/$(subdir)/conf.add \ + --outputdir=./isolation_output \ + $(ISOLATIONCHECKS) diff --git a/contrib/pg_pathman/README.md b/contrib/pg_pathman/README.md index 2a1ee532e6..ec176bb822 100644 --- a/contrib/pg_pathman/README.md +++ b/contrib/pg_pathman/README.md @@ -1,10 +1,14 @@ +[![Build Status](https://travis-ci.org/postgrespro/pg_pathman.svg?branch=master)](https://travis-ci.org/postgrespro/pg_pathman) +[![PGXN version](https://badge.fury.io/pg/pg_pathman.svg)](https://badge.fury.io/pg/pg_pathman) + # pg_pathman The `pg_pathman` module provides optimized partitioning mechanism and functions to manage partitions. -## pg_pathman Concepts +The extension is compatible with PostgreSQL 9.5 (9.6 support is coming soon). -Partitioning refers to splitting one large table into smaller pieces. Each row in such table assigns to a single partition based on partitioning key. PostgreSQL supports partitioning via table inheritance. Each partition must be created as child table with CHECK CONSTRAINT. For example: +## Overview +**Partitioning** means splitting one large table into smaller pieces. Each row in such table is moved to a single partition according to the partitioning key. PostgreSQL supports partitioning via table inheritance: each partition must be created as a child table with CHECK CONSTRAINT. For example: ``` CREATE TABLE test (id SERIAL PRIMARY KEY, title TEXT); @@ -12,154 +16,455 @@ CREATE TABLE test_1 (CHECK ( id >= 100 AND id < 200 )) INHERITS (test); CREATE TABLE test_2 (CHECK ( id >= 200 AND id < 300 )) INHERITS (test); ``` -Despite the flexibility this approach forces the planner to perform an exhaustive search and check constraints for each partition to determine which one should present in the plan. If the number of partitions is large the overhead may be significant. +Despite the flexibility, this approach forces the planner to perform an exhaustive search and to check constraints on each partition to determine whether it should be present in the plan or not. Large amount of partitions may result in significant planning overhead. -The `pg_pathman` module provides functions to manage partitions and partitioning mechanism optimized based on knowledge of the partitions structure. It stores partitioning configuration in the `pathman_config` table, each row of which contains single entry for partitioned table (relation name, partitioning key and type). During initialization the `pg_pathman` module caches information about child partitions in shared memory in form convenient to perform rapid search. When SELECT query executes `pg_pathman` analyzes conditions tree looking for conditions like: +The `pg_pathman` module features partition managing functions and optimized planning mechanism which utilizes knowledge of the partitions' structure. It stores partitioning configuration in the `pathman_config` table; each row contains a single entry for a partitioned table (relation name, partitioning column and its type). During the initialization stage the `pg_pathman` module caches some information about child partitions in the shared memory, which is used later for plan construction. Before a SELECT query is executed, `pg_pathman` traverses the condition tree in search of expressions like: ``` VARIABLE OP CONST ``` -where `VARIABLE` is partitioning key, `OP` is comparison operator (supported operators are =, <, <=, >, >=), `CONST` is scalar value. For example: +where `VARIABLE` is a partitioning key, `OP` is a comparison operator (supported operators are =, <, <=, >, >=), `CONST` is a scalar value. For example: ``` WHERE id = 150 ``` -Based on partitioning type and operator the `pg_pathman` searches corresponding partitions and builds the plan. Current version of `pg_pathman` supports two partitioning types: +Based on the partitioning type and condition's operator, `pg_pathman` searches for the corresponding partitions and builds the plan. Currently `pg_pathman` supports two partitioning schemes: -* RANGE - maps data to partitions based on ranges of partitioning key. Optimization is achieved by using binary search algorithm. -* HASH - maps rows to partitions based on hash function values (only INTEGER attributes at the moment); +* **RANGE** - maps rows to partitions using partitioning key ranges assigned to each partition. Optimization is achieved by using the binary search algorithm; +* **HASH** - maps rows to partitions using a generic hash function. -## Roadmap +More interesting features are yet to come. Stay tuned! - * Execute time sections selections (useful for nested loops and prepared statements); - * Optimization of ordering output from patitioned tables (useful for merge join and order by); - * Optimization of hash join when both tables are patitioned by join key; - * LIST-patitioning; - * HASH-patitioning by non integer attribtes. +## Roadmap -## Installation + * Implement LIST partitioning scheme; + * Optimize hash join (both tables are partitioned by join key). -To install pg_pathman run in psql: -``` -CREATE EXTENSION pg_pathman; +## Installation guide +To install `pg_pathman`, execute this in the module's directory: +```shell +make install USE_PGXS=1 ``` -Then modify shared_preload_libraries parameter in postgres.conf as following: +Modify the **`shared_preload_libraries`** parameter in `postgresql.conf` as following: ``` shared_preload_libraries = 'pg_pathman' ``` -It will require to restart the PostgreSQL instance. +It is essential to restart the PostgreSQL instance. After that, execute the following query in psql: +```plpgsql +CREATE EXTENSION pg_pathman; +``` -## pg_pathman Functions +Done! Now it's time to setup your partitioning schemes. -### Partitions Creation -``` -create_hash_partitions( - relation TEXT, - attribute TEXT, - partitions_count INTEGER) +> **Important:** Don't forget to set the `PG_CONFIG` variable in case you want to test `pg_pathman` on a custom build of PostgreSQL. Read more [here](https://wiki.postgresql.org/wiki/Building_and_Installing_PostgreSQL_Extension_Modules). + +## Available functions + +### Partition creation +```plpgsql +create_hash_partitions(relation REGCLASS, + attribute TEXT, + partitions_count INTEGER, + partition_name TEXT DEFAULT NULL, + partition_data BOOLEAN DEFAULT TRUE) ``` -Performs HASH partitioning for `relation` by integer key `attribute`. Creates `partitions_count` partitions and trigger on INSERT. All the data will be automatically copied from the parent to partitions. +Performs HASH partitioning for `relation` by integer key `attribute`. The `partitions_count` parameter specifies the number of partitions to create; it cannot be changed afterwards. If `partition_data` is `true` then all the data will be automatically copied from the parent table to partitions. Note that data migration may took a while to finish and the table will be locked until transaction commits. See `partition_table_concurrently()` for a lock-free way to migrate data. Partition creation callback is invoked for each partition if set beforehand (see `set_part_init_callback()`). +```plpgsql +create_range_partitions(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + interval ANYELEMENT, + count INTEGER DEFAULT NULL + partition_data BOOLEAN DEFAULT TRUE) + +create_range_partitions(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + interval INTERVAL, + count INTEGER DEFAULT NULL, + partition_data BOOLEAN DEFAULT TRUE) ``` -create_range_partitions( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - interval ANYELEMENT, - premake INTEGER DEFAULT NULL) +Performs RANGE partitioning for `relation` by partitioning key `attribute`. `start_value` argument specifies initial value, `interval` sets the range of values in a single partition, `count` is the number of premade partitions (if not set then pathman tries to determine it based on attribute values). Partition creation callback is invoked for each partition if set beforehand. + +```plpgsql +create_partitions_from_range(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + end_value ANYELEMENT, + interval ANYELEMENT, + partition_data BOOLEAN DEFAULT TRUE) -create_range_partitions( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - interval INTERVAL, - premake INTEGER DEFAULT NULL) +create_partitions_from_range(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + end_value ANYELEMENT, + interval INTERVAL, + partition_data BOOLEAN DEFAULT TRUE) ``` -Performs RANGE partitioning for `relation` by partitioning key `attribute`. `start_value` argument specifies initial value, `interval` sets the range of values in a single partition, `premake` is the number of premade partitions (if not set then pathman tries to determine it based on attribute values). All the data will be automatically copied from the parent to partitions. +Performs RANGE-partitioning from specified range for `relation` by partitioning key `attribute`. Partition creation callback is invoked for each partition if set beforehand. +### Data migration + +```plpgsql +partition_table_concurrently(relation REGCLASS) ``` -create_partitions_from_range( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT, - interval ANYELEMENT) +Starts a background worker to move data from parent table to partitions. The worker utilizes short transactions to copy small batches of data (up to 10K rows per transaction) and thus doesn't significantly interfere with user's activity. -create_partitions_from_range( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT, - interval INTERVAL) +```plpgsql +stop_concurrent_part_task(relation REGCLASS) ``` -Performs RANGE-partitioning from specified range for `relation` by partitioning key `attribute`. Data will be copied to partitions as well. +Stops a background worker performing a concurrent partitioning task. Note: worker will exit after it finishes relocating a current batch. ### Triggers +```plpgsql +create_hash_update_trigger(parent REGCLASS) ``` -create_hash_update_trigger(parent TEXT) +Creates the trigger on UPDATE for HASH partitions. The UPDATE trigger isn't created by default because of the overhead. It's useful in cases when the key attribute might change. +```plpgsql +create_range_update_trigger(parent REGCLASS) ``` -Creates the trigger on UPDATE for HASH partitions. The UPDATE trigger isn't created by default because of overhead. It is useful in cases when key attribute could be changed. +Same as above, but for a RANGE-partitioned table. + +### Post-creation partition management +```plpgsql +split_range_partition(partition REGCLASS, + value ANYELEMENT, + partition_name TEXT DEFAULT NULL) ``` -create_range_update_trigger(parent TEXT) +Split RANGE `partition` in two by `value`. Partition creation callback is invoked for a new partition if available. + +```plpgsql +merge_range_partitions(partition1 REGCLASS, partition2 REGCLASS) ``` -Same as above for RANGE partitioned table. +Merge two adjacent RANGE partitions. First, data from `partition2` is copied to `partition1`, then `partition2` is removed. -### Partitions management +```plpgsql +append_range_partition(p_relation REGCLASS, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) ``` -split_range_partition(partition TEXT, value ANYELEMENT) +Append new RANGE partition with `pathman_config.range_interval` as interval. + +```plpgsql +prepend_range_partition(p_relation REGCLASS, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) ``` -Splits RANGE `partition` in two by `value`. +Prepend new RANGE partition with `pathman_config.range_interval` as interval. + +```plpgsql +add_range_partition(relation REGCLASS, + start_value ANYELEMENT, + end_value ANYELEMENT, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) ``` -merge_range_partitions(partition1 TEXT, partition2 TEXT) +Create new RANGE partition for `relation` with specified range bounds. + +```plpgsql +drop_range_partition(partition TEXT, delete_data BOOLEAN DEFAULT TRUE) ``` -Merge two adjacent RANGE partitions. Data from `partition2` is copied to `partition1`. Then the `partition2` is removed. +Drop RANGE partition and all of its data if `delete_data` is true. + +```plpgsql +attach_range_partition(relation REGCLASS, + partition REGCLASS, + start_value ANYELEMENT, + end_value ANYELEMENT) ``` -append_range_partition(p_relation TEXT) +Attach partition to the existing RANGE-partitioned relation. The attached table must have exactly the same structure as the parent table, including the dropped columns. Partition creation callback is invoked if set (see `pathman_config_params`). + +```plpgsql +detach_range_partition(partition REGCLASS) ``` -Appends new RANGE partition and returns +Detach partition from the existing RANGE-partitioned relation. + +```plpgsql +disable_pathman_for(relation TEXT) ``` -prepend_range_partition(p_relation TEXT) +Permanently disable `pg_pathman` partitioning mechanism for the specified parent table and remove the insert trigger if it exists. All partitions and data remain unchanged. + +```plpgsql +drop_partitions(parent REGCLASS, + delete_data BOOLEAN DEFAULT FALSE) ``` -Prepends new RANGE partition. +Drop partitions of the `parent` table (both foreign and local relations). If `delete_data` is `false`, the data is copied to the parent table first. Default is `false`. + + +### Additional parameters +```plpgsql +set_enable_parent(relation REGCLASS, value BOOLEAN) ``` -add_range_partition( - relation TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT) +Include/exclude parent table into/from query plan. In original PostgreSQL planner parent table is always included into query plan even if it's empty which can lead to additional overhead. You can use `disable_parent()` if you are never going to use parent table as a storage. Default value depends on the `partition_data` parameter that was specified during initial partitioning in `create_range_partitions()` or `create_partitions_from_range()` functions. If the `partition_data` parameter was `true` then all data have already been migrated to partitions and parent table disabled. Otherwise it is enabled. + +```plpgsql +set_auto(relation REGCLASS, value BOOLEAN) ``` -Creates new RANGE partition for `relation` with specified values range. +Enable/disable auto partition propagation (only for RANGE partitioning). It is enabled by default. +```plpgsql +set_init_callback(relation REGCLASS, callback REGPROC DEFAULT 0) ``` -drop_range_partition(partition TEXT) +Set partition creation callback to be invoked for each attached or created partition (both HASH and RANGE). The callback must have the following signature: `part_init_callback(args JSONB) RETURNS VOID`. Parameter `arg` consists of several fields whose presence depends on partitioning type: +```json +/* RANGE-partitioned table abc (child abc_4) */ +{ + "parent": "abc", + "parttype": "2", + "partition": "abc_4", + "range_max": "401", + "range_min": "301" +} + +/* HASH-partitioned table abc (child abc_0) */ +{ + "parent": "abc", + "parttype": "1", + "partition": "abc_0" +} ``` -Drops RANGE partition and all its data. +## Views and tables + +#### `pathman_config` --- main config storage +```plpgsql +CREATE TABLE IF NOT EXISTS pathman_config ( + partrel REGCLASS NOT NULL PRIMARY KEY, + attname TEXT NOT NULL, + parttype INTEGER NOT NULL, + range_interval TEXT, + + CHECK (parttype IN (1, 2)) /* check for allowed part types */ ); ``` -attach_range_partition( - relation TEXT, - partition TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT) +This table stores a list of partitioned tables. + +#### `pathman_config_params` --- optional parameters +```plpgsql +CREATE TABLE IF NOT EXISTS pathman_config_params ( + partrel REGCLASS NOT NULL PRIMARY KEY, + enable_parent BOOLEAN NOT NULL DEFAULT TRUE, + auto BOOLEAN NOT NULL DEFAULT TRUE, + init_callback REGPROCEDURE NOT NULL DEFAULT 0); ``` -Attaches partition to existing RANGE partitioned relation. The table being attached must have exact same structure as the parent one. +This table stores optional parameters which override standard behavior. + +#### `pathman_concurrent_part_tasks` --- currently running partitioning workers +```plpgsql +-- helper SRF function +CREATE OR REPLACE FUNCTION show_concurrent_part_tasks() +RETURNS TABLE ( + userid REGROLE, + pid INT, + dbid OID, + relid REGCLASS, + processed INT, + status TEXT) +AS 'pg_pathman', 'show_concurrent_part_tasks_internal' +LANGUAGE C STRICT; +CREATE OR REPLACE VIEW pathman_concurrent_part_tasks +AS SELECT * FROM show_concurrent_part_tasks(); ``` -detach_range_partition(partition TEXT) +This view lists all currently running concurrent partitioning tasks. + +#### `pathman_partition_list` --- list of all existing partitions +```plpgsql +-- helper SRF function +CREATE OR REPLACE FUNCTION show_partition_list() +RETURNS TABLE ( + parent REGCLASS, + partition REGCLASS, + parttype INT4, + partattr TEXT, + range_min TEXT, + range_max TEXT) +AS 'pg_pathman', 'show_partition_list_internal' +LANGUAGE C STRICT; + +CREATE OR REPLACE VIEW pathman_partition_list +AS SELECT * FROM show_partition_list(); +``` +This view lists all existing partitions, as well as their parents and range boundaries (NULL for HASH partitions). + + +## Custom plan nodes +`pg_pathman` provides a couple of [custom plan nodes](https://wiki.postgresql.org/wiki/CustomScanAPI) which aim to reduce execution time, namely: + +- `RuntimeAppend` (overrides `Append` plan node) +- `RuntimeMergeAppend` (overrides `MergeAppend` plan node) +- `PartitionFilter` (drop-in replacement for INSERT triggers) + +`PartitionFilter` acts as a *proxy node* for INSERT's child scan, which means it can redirect output tuples to the corresponding partition: + +```plpgsql +EXPLAIN (COSTS OFF) +INSERT INTO partitioned_table +SELECT generate_series(1, 10), random(); + QUERY PLAN +----------------------------------------- + Insert on partitioned_table + -> Custom Scan (PartitionFilter) + -> Subquery Scan on "*SELECT*" + -> Result +(4 rows) +``` + +`RuntimeAppend` and `RuntimeMergeAppend` have much in common: they come in handy in a case when WHERE condition takes form of: +``` +VARIABLE OP PARAM +``` +This kind of expressions can no longer be optimized at planning time since the parameter's value is not known until the execution stage takes place. The problem can be solved by embedding the *WHERE condition analysis routine* into the original `Append`'s code, thus making it pick only required scans out of a whole bunch of planned partition scans. This effectively boils down to creation of a custom node capable of performing such a check. + +---------- + +There are at least several cases that demonstrate usefulness of these nodes: + +```plpgsql +/* create table we're going to partition */ +CREATE TABLE partitioned_table(id INT NOT NULL, payload REAL); + +/* insert some data */ +INSERT INTO partitioned_table +SELECT generate_series(1, 1000), random(); + +/* perform partitioning */ +SELECT create_hash_partitions('partitioned_table', 'id', 100); + +/* create ordinary table */ +CREATE TABLE some_table AS SELECT generate_series(1, 100) AS VAL; +``` + + + - **`id = (select ... limit 1)`** +```plpgsql +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = (SELECT * FROM some_table LIMIT 1); + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Custom Scan (RuntimeAppend) (actual time=0.030..0.033 rows=1 loops=1) + InitPlan 1 (returns $0) + -> Limit (actual time=0.011..0.011 rows=1 loops=1) + -> Seq Scan on some_table (actual time=0.010..0.010 rows=1 loops=1) + -> Seq Scan on partitioned_table_70 partitioned_table (actual time=0.004..0.006 rows=1 loops=1) + Filter: (id = $0) + Rows Removed by Filter: 9 + Planning time: 1.131 ms + Execution time: 0.075 ms +(9 rows) + +/* disable RuntimeAppend node */ +SET pg_pathman.enable_runtimeappend = f; + +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = (SELECT * FROM some_table LIMIT 1); + QUERY PLAN +---------------------------------------------------------------------------------- + Append (actual time=0.196..0.274 rows=1 loops=1) + InitPlan 1 (returns $0) + -> Limit (actual time=0.005..0.005 rows=1 loops=1) + -> Seq Scan on some_table (actual time=0.003..0.003 rows=1 loops=1) + -> Seq Scan on partitioned_table_0 (actual time=0.014..0.014 rows=0 loops=1) + Filter: (id = $0) + Rows Removed by Filter: 6 + -> Seq Scan on partitioned_table_1 (actual time=0.003..0.003 rows=0 loops=1) + Filter: (id = $0) + Rows Removed by Filter: 5 + ... /* more plans follow */ + Planning time: 1.140 ms + Execution time: 0.855 ms +(306 rows) +``` + + - **`id = ANY (select ...)`** +```plpgsql +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = any (SELECT * FROM some_table limit 4); + QUERY PLAN +----------------------------------------------------------------------------------------------------------- + Nested Loop (actual time=0.025..0.060 rows=4 loops=1) + -> Limit (actual time=0.009..0.011 rows=4 loops=1) + -> Seq Scan on some_table (actual time=0.008..0.010 rows=4 loops=1) + -> Custom Scan (RuntimeAppend) (actual time=0.002..0.004 rows=1 loops=4) + -> Seq Scan on partitioned_table_70 partitioned_table (actual time=0.001..0.001 rows=10 loops=1) + -> Seq Scan on partitioned_table_26 partitioned_table (actual time=0.002..0.003 rows=9 loops=1) + -> Seq Scan on partitioned_table_27 partitioned_table (actual time=0.001..0.002 rows=20 loops=1) + -> Seq Scan on partitioned_table_63 partitioned_table (actual time=0.001..0.002 rows=9 loops=1) + Planning time: 0.771 ms + Execution time: 0.101 ms +(10 rows) + +/* disable RuntimeAppend node */ +SET pg_pathman.enable_runtimeappend = f; + +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = any (SELECT * FROM some_table limit 4); + QUERY PLAN +----------------------------------------------------------------------------------------- + Nested Loop Semi Join (actual time=0.531..1.526 rows=4 loops=1) + Join Filter: (partitioned_table.id = some_table.val) + Rows Removed by Join Filter: 3990 + -> Append (actual time=0.190..0.470 rows=1000 loops=1) + -> Seq Scan on partitioned_table (actual time=0.187..0.187 rows=0 loops=1) + -> Seq Scan on partitioned_table_0 (actual time=0.002..0.004 rows=6 loops=1) + -> Seq Scan on partitioned_table_1 (actual time=0.001..0.001 rows=5 loops=1) + -> Seq Scan on partitioned_table_2 (actual time=0.002..0.004 rows=14 loops=1) +... /* 96 scans follow */ + -> Materialize (actual time=0.000..0.000 rows=4 loops=1000) + -> Limit (actual time=0.005..0.006 rows=4 loops=1) + -> Seq Scan on some_table (actual time=0.003..0.004 rows=4 loops=1) + Planning time: 2.169 ms + Execution time: 2.059 ms +(110 rows) +``` + + - **`NestLoop` involving a partitioned table**, which is omitted since it's occasionally shown above. + +---------- + +In case you're interested, you can read more about custom nodes at Alexander Korotkov's [blog](http://akorotkov.github.io/blog/2016/06/15/pg_pathman-runtime-append/). + + +## Examples + +### Common tips +- You can easily add **_partition_** column containing the names of the underlying partitions using the system attribute called **_tableoid_**: +```plpgsql +SELECT tableoid::regclass AS partition, * FROM partitioned_table; ``` -Detaches partition from existing RANGE partitioned relation. +- Though indices on a parent table aren't particularly useful (since it's supposed to be empty), they act as prototypes for indices on partitions. For each index on the parent table, `pg_pathman` will create a similar index on every partition. +- All running concurrent partitioning tasks can be listed using the `pathman_concurrent_part_tasks` view: +```plpgsql +SELECT * FROM pathman_concurrent_part_tasks; + userid | pid | dbid | relid | processed | status +--------+------+-------+-------+-----------+--------- + dmitry | 7367 | 16384 | test | 472000 | working +(1 row) ``` -disable_partitioning(relation TEXT) + +- `pathman_partition_list` in conjunction with `drop_range_partition()` can be used to drop RANGE partitions in a more flexible way compared to good old `DROP TABLE`: +```plpgsql +SELECT drop_range_partition(partition, false) /* move data to parent */ +FROM pathman_partition_list +WHERE parent = 'part_test'::regclass AND range_min::int < 500; +NOTICE: 1 rows copied from part_test_11 +NOTICE: 100 rows copied from part_test_1 +NOTICE: 100 rows copied from part_test_2 + drop_range_partition +---------------------- + dummy_test_11 + dummy_test_1 + dummy_test_2 +(3 rows) ``` -Disables `pg_pathman` partitioning mechanism for the specified parent table and removes an insert trigger. Partitions itself remain unchanged. -## Examples -### HASH +### HASH partitioning Consider an example of HASH partitioning. First create a table with some integer column: -``` +```plpgsql CREATE TABLE items ( id SERIAL PRIMARY KEY, name TEXT, @@ -169,88 +474,98 @@ INSERT INTO items (id, name, code) SELECT g, md5(g::text), random() * 100000 FROM generate_series(1, 100000) as g; ``` -If partitions are supposed to have indexes, then they should be created for parent table before partitioning. In this case pg_pathman will automaticaly create indexes for partitions. Then run create_hash_partitions() function with appropriate arguments: -``` +Now run the `create_hash_partitions()` function with appropriate arguments: +```plpgsql SELECT create_hash_partitions('items', 'id', 100); ``` This will create new partitions and move the data from parent to partitions. -Here is an example of the query with filtering by partitioning key and its plan: -``` + +Here's an example of the query performing filtering by partitioning key: +```plpgsql SELECT * FROM items WHERE id = 1234; - id | name | code + id | name | code ------+----------------------------------+------ 1234 | 81dc9bdb52d04dc20036dbd8313ed055 | 1855 (1 row) EXPLAIN SELECT * FROM items WHERE id = 1234; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------------------ Append (cost=0.28..8.29 rows=0 width=0) -> Index Scan using items_34_pkey on items_34 (cost=0.28..8.29 rows=0 width=0) Index Cond: (id = 1234) ``` -Note that pg_pathman exludes parent table from the query plan. To access parent table use ONLY modifier: -``` + +Notice that the `Append` node contains only one child scan which corresponds to the WHERE clause. + +> **Important:** pay attention to the fact that `pg_pathman` excludes the parent table from the query plan. + +To access parent table use ONLY modifier: +```plpgsql EXPLAIN SELECT * FROM ONLY items; - QUERY PLAN + QUERY PLAN ------------------------------------------------------ Seq Scan on items (cost=0.00..0.00 rows=1 width=45) ``` -### RANGE -Consider an example of RANGE partitioning. Let's create a table to store log data: -``` +### RANGE partitioning +Consider an example of RANGE partitioning. Let's create a table containing some dummy logs: +```plpgsql CREATE TABLE journal ( id SERIAL, dt TIMESTAMP NOT NULL, level INTEGER, - msg TEXT -); + msg TEXT); + +-- similar index will also be created for each partition CREATE INDEX ON journal(dt); +-- generate some data INSERT INTO journal (dt, level, msg) -SELECT g, random()*6, md5(g::text) +SELECT g, random() * 6, md5(g::text) FROM generate_series('2015-01-01'::date, '2015-12-31'::date, '1 minute') as g; ``` -Run create_range_partitions() function to create partitions so that each partition would contain data for one day: -``` +Run the `create_range_partitions()` function to create partitions so that each partition would contain the data for one day: +```plpgsql SELECT create_range_partitions('journal', 'dt', '2015-01-01'::date, '1 day'::interval); ``` It will create 365 partitions and move the data from parent to partitions. -New partitions are appended automaticaly by insert trigger. But it can be done manually with the following functions: -``` +New partitions are appended automaticaly by insert trigger, but it can be done manually with the following functions: +```plpgsql +-- add new partition with specified range SELECT add_range_partition('journal', '2016-01-01'::date, '2016-01-07'::date); -SELECT append_range_partition('journal'); -``` -The first one creates partition with specified range. The second one creates partition with default interval and appends it to the partition list. It is also possible to attach an existing table as partition. For example we may want to attach an archive table (or even foreign table from another server) for outdated data: +-- append new partition with default range +SELECT append_range_partition('journal'); ``` +The first one creates a partition with specified range. The second one creates a partition with default interval and appends it to the partition list. It is also possible to attach an existing table as partition. For example, we may want to attach an archive table (or even foreign table from another server) for some outdated data: +```plpgsql CREATE FOREIGN TABLE journal_archive ( id INTEGER NOT NULL, dt TIMESTAMP NOT NULL, level INTEGER, - msg TEXT -) SERVER archive_server; + msg TEXT) +SERVER archive_server; SELECT attach_range_partition('journal', 'journal_archive', '2014-01-01'::date, '2015-01-01'::date); ``` -> Important: the structure of the table being attched must exactly match the parent. +> **Important:** the definition of the attached table must match the one of the existing partitioned table, including the dropped columns. -To merge to adjacent partitions use function: -``` +To merge to adjacent partitions, use the `merge_range_partitions()` function: +```plpgsql SELECT merge_range_partitions('journal_archive', 'journal_1'); ``` -To split partition by value use function: -``` +To split partition by value, use the `split_range_partition()` function: +```plpgsql SELECT split_range_partition('journal_366', '2016-01-03'::date); ``` -To detach partition use: -``` +To detach partition, use the `detach_range_partition()` function: +```plpgsql SELECT detach_range_partition('journal_archive'); ``` -Here is an example of the query with filtering by partitioning key and its plan: -``` +Here's an example of the query performing filtering by partitioning key: +```plpgsql SELECT * FROM journal WHERE dt >= '2015-06-01' AND dt < '2015-06-03'; id | dt | level | msg --------+---------------------+-------+---------------------------------- @@ -269,9 +584,27 @@ EXPLAIN SELECT * FROM journal WHERE dt >= '2015-06-01' AND dt < '2015-06-03'; (3 rows) ``` -### Disable pg_pathman -To disable pg_pathman for some previously partitioned table use disable_partitioning() function: +### Disabling `pg_pathman` +There are several user-accessible [GUC](https://www.postgresql.org/docs/9.5/static/config-setting.html) variables designed to toggle the whole module or specific custom nodes on and off: + + - `pg_pathman.enable` --- disable (or enable) `pg_pathman` completely + - `pg_pathman.enable_runtimeappend` --- toggle `RuntimeAppend` custom node on\off + - `pg_pathman.enable_runtimemergeappend` --- toggle `RuntimeMergeAppend` custom node on\off + - `pg_pathman.enable_partitionfilter` --- toggle `PartitionFilter` custom node on\off + - `pg_pathman.enable_auto_partition` --- toggle automatic partition creation on\off (per session) + - `pg_pathman.insert_into_fdw` --- allow INSERTs into various FDWs `(disabled | postgres | any_fdw)` + - `pg_pathman.override_copy` --- toggle COPY statement hooking on\off + +To **permanently** disable `pg_pathman` for some previously partitioned table, use the `disable_pathman_for()` function: ``` -SELECT disable_partitioning('range_rel'); +SELECT disable_pathman_for('range_rel'); ``` -All sections and data will stay available and will be handled by standard PostgreSQL partitioning mechanism. +All sections and data will remain unchanged and will be handled by the standard PostgreSQL inheritance mechanism. + +##Feedback +Do not hesitate to post your issues, questions and new ideas at the [issues](https://github.com/postgrespro/pg_pathman/issues) page. + +## Authors +Ildar Musin Postgres Professional Ltd., Russia +Alexander Korotkov Postgres Professional Ltd., Russia +Dmitry Ivanov Postgres Professional Ltd., Russia diff --git a/contrib/pg_pathman/README.rus.md b/contrib/pg_pathman/README.rus.md index 3fe04c21c1..6acea3c5d1 100644 --- a/contrib/pg_pathman/README.rus.md +++ b/contrib/pg_pathman/README.rus.md @@ -1,10 +1,15 @@ +[![Build Status](https://travis-ci.org/postgrespro/pg_pathman.svg?branch=master)](https://travis-ci.org/postgrespro/pg_pathman) +[![PGXN version](https://badge.fury.io/pg/pg_pathman.svg)](https://badge.fury.io/pg/pg_pathman) + # pg_pathman Модуль `pg_pathman` предоÑтавлÑет оптимизированный механизм ÑекционированиÑ, а также функции Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸ ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÑекциÑми. +РаÑширение ÑовмеÑтимо Ñ PostgreSQL 9.5 (поддержка 9.6 будет добавлена в одном из ближайших обновлений). + ## ÐšÐ¾Ð½Ñ†ÐµÐ¿Ñ†Ð¸Ñ pg_pathman -Секционирование -- Ñто ÑпоÑоб Ñ€Ð°Ð·Ð±Ð¸ÐµÐ½Ð¸Ñ Ð¾Ð´Ð½Ð¾Ð¹ большой таблицы на множеÑтво меньших по размеру. Ð”Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ запиÑи можно однозначно определить Ñекцию, в которой она должна хранитьÑÑ Ð¿Ð¾ÑредÑтвом вычиÑÐ»ÐµÐ½Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð°. +**Секционирование** -- Ñто ÑпоÑоб Ñ€Ð°Ð·Ð±Ð¸ÐµÐ½Ð¸Ñ Ð¾Ð´Ð½Ð¾Ð¹ большой таблицы на множеÑтво меньших по размеру. Ð”Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ запиÑи можно однозначно определить Ñекцию, в которой она должна хранитьÑÑ Ð¿Ð¾ÑредÑтвом вычиÑÐ»ÐµÐ½Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð°. Секционирование в postgres оÑновано на механизме наÑледованиÑ. Каждому наÑледнику задаетÑÑ ÑƒÑловие CHECK CONSTRAINT. Ðапример: ``` @@ -29,137 +34,332 @@ WHERE id = 150 Ð’ текущей верÑии `pg_pathman` поддерживает Ñледующие типы ÑекционированиÑ: -* RANGE - разбивает таблицу на Ñекции по диапазонам ключевого аттрибута; Ð´Ð»Ñ Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ð¸ поÑÑ‚Ñ€Ð¾ÐµÐ½Ð¸Ñ Ð¿Ð»Ð°Ð½Ð° иÑпользуетÑÑ Ð¼ÐµÑ‚Ð¾Ð´ бинарного поиÑка. -* HASH - данные равномерно раÑпределÑÑŽÑ‚ÑÑ Ð¿Ð¾ ÑекциÑм в ÑоответÑтвии Ñо значениÑми hash-функции, вычиÑленными по заданному целочиÑленному атрибуту. +* **RANGE** - разбивает таблицу на Ñекции по диапазонам ключевого аттрибута; Ð´Ð»Ñ Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ð¸ поÑÑ‚Ñ€Ð¾ÐµÐ½Ð¸Ñ Ð¿Ð»Ð°Ð½Ð° иÑпользуетÑÑ Ð¼ÐµÑ‚Ð¾Ð´ бинарного поиÑка. +* **HASH** - данные равномерно раÑпределÑÑŽÑ‚ÑÑ Ð¿Ð¾ ÑекциÑм в ÑоответÑтвии Ñо значениÑми hash-функции, вычиÑленными по заданному целочиÑленному атрибуту. + +More interesting features are yet to come. Stay tuned! ## Roadmap - * Выбор Ñекций на Ñтапе Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñа (полезно Ð´Ð»Ñ nested loop join, prepared statements); - * ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð²Ñ‹Ð´Ð°Ñ‡Ð¸ упорÑдоченных результатов из Ñекционированных таблиц (полезно Ð´Ð»Ñ merge join, order by); - * ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ hash join Ð´Ð»Ñ ÑлучаÑ, когда обе таблицы Ñекционированы по ключу join’а; + * ПредоÑтавить возможноÑть уÑтановки пользовательÑких колбеков на Ñоздание\уничтожение партиции (issue [#22](https://github.com/postgrespro/pg_pathman/issues/22)) * LIST-Ñекционирование; - * HASH-Ñекционирование по ключевому атрибуту Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼, отличным от INTEGER. + * ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ hash join Ð´Ð»Ñ ÑлучаÑ, когда обе таблицы Ñекционированы по ключу join’а. ## УÑтановка -Ð”Ð»Ñ ÑƒÑтановки pg_pathman выполните в командной Ñтроке: +Ð”Ð»Ñ ÑƒÑтановки pg_pathman выполните в директории Ð¼Ð¾Ð´ÑƒÐ»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñƒ: ``` -CREATE EXTENSION pg_pathman; - +make install USE_PGXS=1 ``` -Затем модифицируйте параметр shared_preload_libraries в конфигурационном файле postgres.conf: +Модифицируйте параметр shared_preload_libraries в конфигурационном файле postgres.conf: ``` shared_preload_libraries = 'pg_pathman' ``` -Ð”Ð»Ñ Ð²ÑÑ‚ÑƒÐ¿Ð»ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ в Ñилу потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° Ñервера PostgreSQL. +Ð”Ð»Ñ Ð²ÑÑ‚ÑƒÐ¿Ð»ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ в Ñилу потребуетÑÑ Ð¿ÐµÑ€ÐµÐ·Ð°Ð³Ñ€ÑƒÐ·ÐºÐ° Ñервера PostgreSQL. Затем выполните в psql: +``` +CREATE EXTENSION pg_pathman; +``` + +> **Важно:** ЕÑли вы хотите Ñобрать `pg_pathman` Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ ÐºÐ°Ñтомной Ñборкой PostgreSQL, не забудьте уÑтановить переменную Ð¾ÐºÑ€ÑƒÐ¶ÐµÐ½Ð¸Ñ `PG_CONFIG` равной пути к иÑполнÑемому файлу pg_config. Узнать больше о Ñборке раÑширений Ð´Ð»Ñ PostgreSQL можно по ÑÑылке: [here](https://wiki.postgresql.org/wiki/Building_and_Installing_PostgreSQL_Extension_Modules). -## Функции pg_pathman +## Функции `pg_pathman` ### Создание Ñекций +```plpgsql +create_hash_partitions(relation REGCLASS, + attribute TEXT, + partitions_count INTEGER, + partition_name TEXT DEFAULT NULL) ``` -create_hash_partitions( - relation TEXT, - attribute TEXT, - partitions_count INTEGER) -``` -ВыполнÑет HASH-Ñекционирование таблицы `relation` по целочиÑленному полю `attribute`. Создает `partitions_count` дочерних Ñекций, а также триггер на вÑтавку. Данные из родительÑкой таблицы будут автоматичеÑки Ñкопированы в дочерние. +ВыполнÑет HASH-Ñекционирование таблицы `relation` по целочиÑленному полю `attribute`. Параметр `partitions_count` определÑет, Ñколько Ñекций будет Ñоздано. ЕÑли `partition_data` уÑтановлен в значение `true`, то данные из родительÑкой таблицы будут автоматичеÑки раÑпределены по ÑекциÑм. Стоит иметь в виду, что Ð¼Ð¸Ð³Ñ€Ð°Ñ†Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… может занÑть некоторое времÑ, а данные заблокированы. Ð”Ð»Ñ ÐºÐ¾Ð½ÐºÑƒÑ€ÐµÐ½Ñ‚Ð½Ð¾Ð¹ миграции данных Ñм. функцию `partition_table_concurrently()`. + +```plpgsql +create_range_partitions(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + interval ANYELEMENT, + count INTEGER DEFAULT NULL + partition_data BOOLEAN DEFAULT true) +create_range_partitions(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + interval INTERVAL, + count INTEGER DEFAULT NULL, + partition_data BOOLEAN DEFAULT true) ``` -create_range_partitions( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - interval ANYELEMENT, - premake INTEGER DEFAULT NULL) +ВыполнÑет RANGE-Ñекционирование таблицы `relation` по полю `attribute`. Ðргумент `start_value` задает начальное значение, `interval` -- диапазон значений внутри одной Ñекции, `count` -- количеÑтво Ñоздаваемых Ñекций (еÑли не задано, то pathman попытаетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ð¸Ñ‚ÑŒ количеÑтво Ñекций на оÑнове значений аттрибута). -create_range_partitions( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - interval INTERVAL, - premake INTEGER DEFAULT NULL) +```plpgsql +create_partitions_from_range(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + end_value ANYELEMENT, + interval ANYELEMENT, + partition_data BOOLEAN DEFAULT true) + +create_partitions_from_range(relation REGCLASS, + attribute TEXT, + start_value ANYELEMENT, + end_value ANYELEMENT, + interval INTERVAL, + partition_data BOOLEAN DEFAULT true) ``` -ВыполнÑет RANGE-Ñекционирование таблицы `relation` по полю `attribute`. Ðргумент `start_value` задает начальное значение, `interval` -- диапазон значений внутри одной Ñекции, `premake` -- количеÑтво заранее Ñоздаваемых Ñекций (еÑли не задано, то pathman попытаетÑÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ð¸Ñ‚ÑŒ количеÑтво Ñекций на оÑнове значений аттрибута). Данные из родительÑкой таблицы будут автоматичеÑки Ñкопированы в дочерние. +ВыполнÑет RANGE-Ñекционирование Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ диапазона таблицы `relation` по полю `attribute`. + +### ÐœÐ¸Ð³Ñ€Ð°Ñ†Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… +```plpgsql +partition_table_concurrently(relation REGCLASS) ``` -create_partitions_from_range( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT, - interval ANYELEMENT) +ЗапуÑкает новый процеÑÑ (background worker) Ð´Ð»Ñ ÐºÐ¾Ð½ÐºÑƒÑ€ÐµÐ½Ñ‚Ð½Ð¾Ð³Ð¾ Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… из родительÑкой таблицы в дочерние Ñекции. Рабочий процеÑÑ Ð¸Ñпользует короткие транзакции Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð½ÐµÐ±Ð¾Ð»ÑŒÑˆÐ¸Ñ… объемов данных (порÑдка 10 тыÑÑч запиÑей) и, таким образом, не оказывает ÑущеÑтвенного влиÑÐ½Ð¸Ñ Ð½Ð° работу пользователей. -create_partitions_from_range( - relation TEXT, - attribute TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT, - interval INTERVAL) +```plpgsql +stop_concurrent_part_task(relation REGCLASS) ``` -ВыполнÑет RANGE-Ñекционирование Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ диапазона таблицы `relation` по полю `attribute`. Данные также будут Ñкопированы в дочерние Ñекции. +ОÑтанавливает процеÑÑ ÐºÐ¾Ð½ÐºÑƒÑ€ÐµÐ½Ñ‚Ð½Ð¾Ð³Ð¾ партиционированиÑ. Обратите внимание, что процеÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ°ÐµÑ‚ÑÑ Ð½Ðµ мгновенно, а только по завершении текущей транзакции. ### Утилиты -``` -create_hash_update_trigger(parent TEXT) +```plpgsql +create_hash_update_trigger(parent REGCLASS) ``` Создает триггер на UPDATE Ð´Ð»Ñ HASH Ñекций. По-умолчанию триггер на обновление данных не ÑоздаетÑÑ, Ñ‚.к. Ñто Ñоздает дополнительные накладные раÑходы. Триггер полезен только в том Ñлучае, когда менÑетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ ключевого аттрибута. -``` -create_range_update_trigger(parent TEXT) +```plpgsql +create_range_update_trigger(parent REGCLASS) ``` Ðналогично предыдущей, но Ð´Ð»Ñ RANGE Ñекций. ### Управление ÑекциÑми -``` -split_range_partition(partition TEXT, value ANYELEMENT) +```plpgsql +split_range_partition(partition REGCLASS, + value ANYELEMENT, + partition_name TEXT DEFAULT NULL,) ``` Разбивает RANGE Ñекцию `partition` на две Ñекции по значению `value`. -``` -merge_range_partitions(partition1 TEXT, partition2 TEXT) + +```plpgsql +merge_range_partitions(partition1 REGCLASS, partition2 REGCLASS) ``` ОбъединÑет две Ñмежные RANGE Ñекции. Данные из `partition2` копируютÑÑ Ð² `partition1`, поÑле чего ÑÐµÐºÑ†Ð¸Ñ `partition2` удалÑетÑÑ. + +```plpgsql +append_range_partition(p_relation REGCLASS, + partition_name TEXT DEFAULT NULL) ``` -append_range_partition(p_relation TEXT) +ДобавлÑет новую RANGE Ñекцию Ñ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð¾Ð¼ `pathman_config.range_interval` в конец ÑпиÑка Ñекций. + +```plpgsql +prepend_range_partition(p_relation REGCLASS, + partition_name TEXT DEFAULT NULL) ``` -ДобавлÑет новую RANGE Ñекцию в конец ÑпиÑка Ñекций. +ДобавлÑет новую RANGE Ñекцию Ñ Ð´Ð¸Ð°Ð¿Ð°Ð·Ð¾Ð½Ð¾Ð¼ `pathman_config.range_interval` в начало ÑпиÑка Ñекций. + +```plpgsql +add_range_partition(relation REGCLASS, + start_value ANYELEMENT, + end_value ANYELEMENT, + partition_name TEXT DEFAULT NULL) ``` -prepend_range_partition(p_relation TEXT) +ДобавлÑет новую RANGE Ñекцию Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ диапазоном к Ñекционированной таблице `relation`. + +```plpgsql +drop_range_partition(partition TEXT) ``` -ДобавлÑет новую RANGE Ñекцию в начало ÑпиÑка Ñекций. +УдалÑет RANGE Ñекцию вмеÑте Ñ ÑодержащимиÑÑ Ð² ней данными. +```plpgsql +attach_range_partition(relation REGCLASS, + partition REGCLASS, + start_value ANYELEMENT, + end_value ANYELEMENT) ``` -add_range_partition( - relation TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT) +ПриÑоединÑет ÑущеÑтвующую таблицу `partition` в качеÑтве Ñекции к ранее Ñекционированной таблице `relation`. Структура приÑоединÑемой таблицы должна в точноÑти повторÑть Ñтруктуру родительÑкой. + +```plpgsql +detach_range_partition(partition REGCLASS) ``` -ДобавлÑет новую RANGE Ñекцию Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ диапазоном к Ñекционированной таблице `relation`. +ОтÑоединÑет Ñекцию `partition`, поÑле чего она ÑтановитÑÑ Ð½ÐµÐ·Ð°Ð²Ð¸Ñимой таблицей. +```plpgsql +disable_pathman_for(relation REGCLASS) ``` -drop_range_partition(partition TEXT) +Отключает механизм ÑÐµÐºÑ†Ð¸Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ `pg_pathman` Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¹ таблицы. При Ñтом Ñозданные ранее Ñекции оÑтаютÑÑ Ð±ÐµÐ· изменений. + +```plpgsql +drop_partitions(parent REGCLASS, + delete_data BOOLEAN DEFAULT FALSE) ``` -УдалÑет RANGE Ñекцию вмеÑте Ñ ÑодержащимиÑÑ Ð² ней данными. +УдалÑет вÑе Ñекции таблицы `parent`. ЕÑли параметр `delete_data` задан как `false` (по-умолчанию `false`), то данные из Ñекций копируютÑÑ Ð² родительÑкую таблицу. + +### Дополнительные параметры +```plpgsql +enable_parent(relation REGCLASS) +disable_parent(relation REGCLASS) ``` -attach_range_partition( - relation TEXT, - partition TEXT, - start_value ANYELEMENT, - end_value ANYELEMENT) +Включает/иÑключает родительÑкую таблицу в план запроÑа. Ð’ оригинальном планировщике PostgreSQL родительÑÐºÐ°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° вÑегда включаетÑÑ Ð² план запроÑа, даже еÑли она пуÑта. Это Ñоздает дополнительные накладные раÑходы. Выполните `disable_parent()`, еÑли вы не ÑобираетеÑÑŒ хранить какие-либо данные в родительÑкой таблице. Значение по-умолчанию завиÑит от того, был ли уÑтановлен параметр `partition_data` при первоначальном разбиении таблицы (Ñм. функции `create_range_partitions()` и `create_partitions_from_range()`). ЕÑли он был уÑтановлен в значение `true`, то вÑе данные были перемещены в Ñекции, а родительÑÐºÐ°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° отключена. Ð’ противном Ñлучае родительÑÐºÐ°Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° по-умолчанию влючена. + +```plpgsql +enable_auto(relation REGCLASS) +disable_auto(relation REGCLASS) ``` -ПриÑоединÑет ÑущеÑтвующую таблицу `partition` в качеÑтве Ñекции к ранее Ñекционированной таблице `relation`. Структура приÑоединÑемой таблицы должна в точноÑти повторÑть Ñтруктуру родительÑкой. +Включает/выключает автоматичеÑкое Ñоздание Ñекций (только Ð´Ð»Ñ RANGE ÑекционированиÑ). По-умолчанию включено. + +## Custom plan nodes +`pg_pathman` вводит три новых узла плана (Ñм. [custom plan nodes](https://wiki.postgresql.org/wiki/CustomScanAPI)), предназначенных Ð´Ð»Ñ Ð¾Ð¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ð¸ времени выполнениÑ: + +- `RuntimeAppend` (замещает узел типа `Append`) +- `RuntimeMergeAppend` (замещает узел типа `MergeAppend`) +- `PartitionFilter` (выполнÑет работу INSERT-триггера) + +`PartitionFilter` работает как прокÑи-узел Ð´Ð»Ñ INSERT-запроÑов, раÑпределÑÑ Ð½Ð¾Ð²Ñ‹Ðµ запиÑи по ÑоответÑтвующим ÑекциÑм: ``` -detach_range_partition(partition TEXT) +EXPLAIN (COSTS OFF) +INSERT INTO partitioned_table +SELECT generate_series(1, 10), random(); + QUERY PLAN +----------------------------------------- + Insert on partitioned_table + -> Custom Scan (PartitionFilter) + -> Subquery Scan on "*SELECT*" + -> Result +(4 rows) ``` -ОтÑоединÑет Ñекцию `partition`, поÑле чего она ÑтановитÑÑ Ð½ÐµÐ·Ð°Ð²Ð¸Ñимой таблицей. +Узлы `RuntimeAppend` и `RuntimeMergeAppend` имеют между Ñобой много общего: они нужны в Ñлучает, когда уÑловие WHERE принимает форму: +``` +ПЕРЕМЕÐÐÐЯ ОПЕРÐТОР ПÐРÐМЕТР +``` +Подобные Ð²Ñ‹Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð½Ðµ могут быть оптимизированы во Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð»Ð°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ, Ñ‚.к. значение параметра неизвеÑтно до Ñтадии выполнениÑ. Проблема может быть решена путем вÑÑ‚Ñ€Ð°Ð¸Ð²Ð°Ð½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ процедуры анализа в код `Append` узла, таким образом позволÑÑ ÐµÐ¼Ñƒ выбирать лишь необходимые Ñубпланы из вÑего ÑпиÑка дочерних планов. + +---------- + +ЕÑть по меньшей мере неÑколько Ñитуаций, которые демонÑтрируют полезноÑть таких узлов: + +``` +/* Ñоздаем таблицу, которую хотим Ñекционировать */ +CREATE TABLE partitioned_table(id INT NOT NULL, payload REAL); + +/* заполнÑем данными */ +INSERT INTO partitioned_table +SELECT generate_series(1, 1000), random(); + +/* выполнÑем Ñекционирование */ +SELECT create_hash_partitions('partitioned_table', 'id', 100); + +/* Ñоздаем обычную таблицу */ +CREATE TABLE some_table AS SELECT generate_series(1, 100) AS VAL; ``` -disable_partitioning(relation TEXT) + + + - **`id = (select ... limit 1)`** ``` -Отключает механизм ÑÐµÐºÑ†Ð¸Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ `pg_pathman` Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ð¾Ð¹ таблицы и удалÑет триггер на вÑтавку. При Ñтом Ñозданные ранее Ñекции оÑтаютÑÑ Ð±ÐµÐ· изменений. +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = (SELECT * FROM some_table LIMIT 1); + QUERY PLAN +---------------------------------------------------------------------------------------------------- + Custom Scan (RuntimeAppend) (actual time=0.030..0.033 rows=1 loops=1) + InitPlan 1 (returns $0) + -> Limit (actual time=0.011..0.011 rows=1 loops=1) + -> Seq Scan on some_table (actual time=0.010..0.010 rows=1 loops=1) + -> Seq Scan on partitioned_table_70 partitioned_table (actual time=0.004..0.006 rows=1 loops=1) + Filter: (id = $0) + Rows Removed by Filter: 9 + Planning time: 1.131 ms + Execution time: 0.075 ms +(9 rows) + +/* выключаем узел RuntimeAppend */ +SET pg_pathman.enable_runtimeappend = f; -## Примеры иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ -### HASH +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = (SELECT * FROM some_table LIMIT 1); + QUERY PLAN +---------------------------------------------------------------------------------- + Append (actual time=0.196..0.274 rows=1 loops=1) + InitPlan 1 (returns $0) + -> Limit (actual time=0.005..0.005 rows=1 loops=1) + -> Seq Scan on some_table (actual time=0.003..0.003 rows=1 loops=1) + -> Seq Scan on partitioned_table_0 (actual time=0.014..0.014 rows=0 loops=1) + Filter: (id = $0) + Rows Removed by Filter: 6 + -> Seq Scan on partitioned_table_1 (actual time=0.003..0.003 rows=0 loops=1) + Filter: (id = $0) + Rows Removed by Filter: 5 + ... /* more plans follow */ + Planning time: 1.140 ms + Execution time: 0.855 ms +(306 rows) +``` + + - **`id = ANY (select ...)`** +``` +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = any (SELECT * FROM some_table limit 4); + QUERY PLAN +----------------------------------------------------------------------------------------------------------- + Nested Loop (actual time=0.025..0.060 rows=4 loops=1) + -> Limit (actual time=0.009..0.011 rows=4 loops=1) + -> Seq Scan on some_table (actual time=0.008..0.010 rows=4 loops=1) + -> Custom Scan (RuntimeAppend) (actual time=0.002..0.004 rows=1 loops=4) + -> Seq Scan on partitioned_table_70 partitioned_table (actual time=0.001..0.001 rows=10 loops=1) + -> Seq Scan on partitioned_table_26 partitioned_table (actual time=0.002..0.003 rows=9 loops=1) + -> Seq Scan on partitioned_table_27 partitioned_table (actual time=0.001..0.002 rows=20 loops=1) + -> Seq Scan on partitioned_table_63 partitioned_table (actual time=0.001..0.002 rows=9 loops=1) + Planning time: 0.771 ms + Execution time: 0.101 ms +(10 rows) + +/* выключаем узел RuntimeAppend */ +SET pg_pathman.enable_runtimeappend = f; + +EXPLAIN (COSTS OFF, ANALYZE) SELECT * FROM partitioned_table +WHERE id = any (SELECT * FROM some_table limit 4); + QUERY PLAN +----------------------------------------------------------------------------------------- + Nested Loop Semi Join (actual time=0.531..1.526 rows=4 loops=1) + Join Filter: (partitioned_table.id = some_table.val) + Rows Removed by Join Filter: 3990 + -> Append (actual time=0.190..0.470 rows=1000 loops=1) + -> Seq Scan on partitioned_table (actual time=0.187..0.187 rows=0 loops=1) + -> Seq Scan on partitioned_table_0 (actual time=0.002..0.004 rows=6 loops=1) + -> Seq Scan on partitioned_table_1 (actual time=0.001..0.001 rows=5 loops=1) + -> Seq Scan on partitioned_table_2 (actual time=0.002..0.004 rows=14 loops=1) +... /* 96 scans follow */ + -> Materialize (actual time=0.000..0.000 rows=4 loops=1000) + -> Limit (actual time=0.005..0.006 rows=4 loops=1) + -> Seq Scan on some_table (actual time=0.003..0.004 rows=4 loops=1) + Planning time: 2.169 ms + Execution time: 2.059 ms +(110 rows) +``` + + - **`NestLoop` involving a partitioned table**, which is omitted since it's occasionally shown above. + +---------- + +Узнать больше о работе RuntimeAppend можно в [блоге](http://akorotkov.github.io/blog/2016/06/15/pg_pathman-runtime-append/) ÐлекÑандра Короткова. + +## Примеры + +### Common tips +- You can easily add **_partition_** column containing the names of the underlying partitions using the system attribute called **_tableoid_**: +``` +SELECT tableoid::regclass AS partition, * FROM partitioned_table; +``` +- ÐеÑÐ¼Ð¾Ñ‚Ñ€Ñ Ð½Ð° то, что индекÑÑ‹ на родительÑкой таблице не очень полезны (Ñ‚.к. таблица пуÑта), они тем не менее выполнÑÑŽÑ‚ роль прототипов Ð´Ð»Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¸Ð½Ð´ÐµÐºÑов в дочерних таблицах: `pg_pathman` автоматичеÑки Ñоздает аналогичные индекÑÑ‹ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ новой Ñекции. + +- Получить вÑе текущие процеÑÑÑ‹ конкурентного ÑÐµÐºÑ†Ð¸Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ из предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ `pathman_concurrent_part_tasks`: +```plpgsql +SELECT * FROM pathman_concurrent_part_tasks; + userid | pid | dbid | relid | processed | status +--------+------+-------+-------+-----------+--------- + dmitry | 7367 | 16384 | test | 472000 | working +(1 row) +``` + +### HASH Ñекционирование РаÑÑмотрим пример ÑÐµÐºÑ†Ð¸Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ HASH-Ñтратегию на примере таблицы товаров. ``` CREATE TABLE items ( @@ -198,7 +398,7 @@ EXPLAIN SELECT * FROM ONLY items; Seq Scan on items (cost=0.00..0.00 rows=1 width=45) ``` -### RANGE +### RANGE Ñекционирование РаÑÑмотрим пример Ñ€Ð°Ð·Ð±Ð¸ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ по диапазону дат. ПуÑть у Ð½Ð°Ñ Ð¸Ð¼ÐµÐµÑ‚ÑÑ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° логов: ``` CREATE TABLE journal ( @@ -272,8 +472,22 @@ EXPLAIN SELECT * FROM journal WHERE dt >= '2015-06-01' AND dt < '2015-06-03'; ``` ### Ð”ÐµÐ°ÐºÑ†Ð¸Ð²Ð°Ñ†Ð¸Ñ pg_pathman -Деактивировать механизм pg_pathman Ð´Ð»Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ð¾Ð¹ ранее разделенной таблицы можно Ñледующей командой disable_partitioning(): +Ð”Ð»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¸ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ `pg_pathman` и отдельных его копонентов ÑущеÑтвует Ñ€Ñд [GUC](https://www.postgresql.org/docs/9.5/static/config-setting.html) переменных: + + - `pg_pathman.enable` --- Ð¿Ð¾Ð»Ð½Ð°Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ðµ (или включение) Ð¼Ð¾Ð´ÑƒÐ»Ñ `pg_pathman` + - `pg_pathman.enable_runtimeappend` --- включение/отключение функционала `RuntimeAppend` + - `pg_pathman.enable_runtimemergeappend` --- включение/отключение функционала `RuntimeMergeAppend` + - `pg_pathman.enable_partitionfilter` --- включение/отключение функционала `PartitionFilter` + +Чтобы **безвозвратно** отключить механизм `pg_pathman` Ð´Ð»Ñ Ð¾Ñ‚Ð´ÐµÐ»ÑŒÐ½Ð¾Ð¹ таблицы, иÑпользуйте фунцию `disable_pathman_for()`. Ð’ результате Ñтой операции Ñтруктура таблиц оÑтанетÑÑ Ð¿Ñ€ÐµÐ¶Ð½ÐµÐ¹, но Ð´Ð»Ñ Ð¿Ð»Ð°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾Ñов будет иÑпользоватьÑÑ Ñтандартный механизм PostgreSQL. ``` -SELECT disable_partitioning('journal'); +SELECT disable_pathman_for('range_rel'); ``` -Ð’Ñе Ñозданные Ñекции и данные оÑтанутÑÑ Ð¿Ð¾ прежнему доÑтупны и будут обрабатыватьÑÑ Ñтандартным планировщиком PostgreSQL. + +## ÐžÐ±Ñ€Ð°Ñ‚Ð½Ð°Ñ ÑвÑзь +ЕÑли у Ð²Ð°Ñ ÐµÑть вопроÑÑ‹ или предложениÑ, а также еÑли вы обнаружили ошибки, напишите нам в разделе [issues](https://github.com/postgrespro/pg_pathman/issues). + +## Ðвторы +Ильдар МуÑин Postgres Professional, РоÑÑÐ¸Ñ +ÐлекÑандр Коротков Postgres Professional, РоÑÑÐ¸Ñ +Дмитрий Иванов Postgres Professional, РоÑÑÐ¸Ñ diff --git a/contrib/pg_pathman/dsm_array.c b/contrib/pg_pathman/dsm_array.c deleted file mode 100644 index c66d868467..0000000000 --- a/contrib/pg_pathman/dsm_array.c +++ /dev/null @@ -1,302 +0,0 @@ -/* ------------------------------------------------------------------------ - * - * init.c - * This module allocates large DSM segment to store arrays, - * initializes it with block structure and provides functions to - * allocate and free arrays - * - * Copyright (c) 2015-2016, Postgres Professional - * - * ------------------------------------------------------------------------ - */ -#include "pathman.h" -#include "storage/shmem.h" -#include "storage/dsm.h" -#include "storage/lwlock.h" -#include - - -static dsm_segment *segment = NULL; - -typedef struct DsmConfig -{ - dsm_handle segment_handle; - size_t block_size; - size_t blocks_count; - size_t first_free; -} DsmConfig; - -static DsmConfig *dsm_cfg = NULL; - -/* - * Block header - * - * Its size must be 4 bytes for 32bit and 8 bytes for 64bit. Otherwise it could - * screw up an alignment (for example on Sparc9) - */ -typedef uintptr_t BlockHeader; -typedef BlockHeader* BlockHeaderPtr; - -#define FREE_BIT 0x80000000 -#define is_free(header) \ - ((*header) & FREE_BIT) -#define set_free(header) \ - ((*header) | FREE_BIT) -#define set_used(header) \ - ((*header) & ~FREE_BIT) -#define get_length(header) \ - ((*header) & ~FREE_BIT) -#define set_length(header, length) \ - ((length) | ((*header) & FREE_BIT)) - -/* - * Amount of memory that need to be requested in shared memory to store dsm - * config - */ -Size -get_dsm_shared_size() -{ - return (Size) MAXALIGN(sizeof(DsmConfig)); -} - -/* - * Initialize dsm config for arrays - */ -void -init_dsm_config() -{ - bool found; - dsm_cfg = ShmemInitStruct("pathman dsm_array config", sizeof(DsmConfig), &found); - if (!found) - { - dsm_cfg->segment_handle = 0; - dsm_cfg->block_size = 0; - dsm_cfg->blocks_count = INITIAL_BLOCKS_COUNT; - dsm_cfg->first_free = 0; - } -} - -/* - * Attach process to dsm_array segment. This function is used for - * background workers only. Use init_dsm_segment() in backend processes. - */ -void -attach_dsm_array_segment() -{ - segment = dsm_attach(dsm_cfg->segment_handle); -} - -/* - * Initialize dsm segment. Returns true if new segment was created and - * false if attached to existing segment - */ -bool -init_dsm_segment(size_t blocks_count, size_t block_size) -{ - bool ret; - - /* if there is already an existing segment then attach to it */ - if (dsm_cfg->segment_handle != 0) - { - ret = false; - segment = dsm_attach(dsm_cfg->segment_handle); - } - - /* - * If segment hasn't been created yet or has already been destroyed - * (it happens when last session detaches segment) then create new one - */ - if (dsm_cfg->segment_handle == 0 || segment == NULL) - { - /* create segment */ - segment = dsm_create(block_size * blocks_count, 0); - dsm_cfg->segment_handle = dsm_segment_handle(segment); - dsm_cfg->first_free = 0; - dsm_cfg->block_size = block_size; - dsm_cfg->blocks_count = blocks_count; - init_dsm_table(block_size, 0, dsm_cfg->blocks_count); - ret = true; - } - - /* - * Keep mapping till the end of the session. Otherwise it would be - * destroyed by the end of transaction - */ - dsm_pin_mapping(segment); - - return ret; -} - -/* - * Initialize allocated segment with block structure - */ -void -init_dsm_table(size_t block_size, size_t start, size_t end) -{ - int i; - BlockHeaderPtr header; - char *ptr = dsm_segment_address(segment); - - /* create blocks */ - for (i=start; ifirst_free; iblocks_count; ) - { - header = (BlockHeaderPtr) &ptr[i * dsm_cfg->block_size]; - if (is_free(header)) - { - if (!collecting_blocks) - { - offset = i * dsm_cfg->block_size; - total_length = dsm_cfg->block_size - sizeof(BlockHeader); - min_pos = i; - collecting_blocks = true; - } - else - { - total_length += dsm_cfg->block_size; - } - i++; - } - else - { - collecting_blocks = false; - offset = 0; - total_length = 0; - i += get_length(header); - } - - if (total_length >= size_requested) - { - max_pos = i-1; - found = true; - break; - } - } - - /* - * If dsm segment size is not enough then resize it (or allocate bigger - * for segment SysV and Windows, not implemented yet) - */ - if (!found) - { - size_t new_blocks_count = dsm_cfg->blocks_count * 2; - - dsm_resize(segment, new_blocks_count * dsm_cfg->block_size); - init_dsm_table(dsm_cfg->block_size, dsm_cfg->blocks_count, new_blocks_count); - dsm_cfg->blocks_count = new_blocks_count; - - /* try again */ - return alloc_dsm_array(arr, entry_size, length); - } - - /* look up for first free block */ - if (dsm_cfg->first_free == min_pos) - { - for (; iblocks_count; ) - { - header = (BlockHeaderPtr) &ptr[i * dsm_cfg->block_size]; - if (is_free(header)) - { - dsm_cfg->first_free = i; - break; - } - else - { - i += get_length(header); - } - } - } - - /* if we found enough of space */ - if (total_length >= size_requested) - { - header = (BlockHeaderPtr) &ptr[min_pos * dsm_cfg->block_size]; - *header = set_used(header); - *header = set_length(header, max_pos - min_pos + 1); - - arr->offset = offset; - arr->length = length; - } -} - -void -free_dsm_array(DsmArray *arr) -{ - int start = arr->offset / dsm_cfg->block_size; - int i = 0; - char *ptr = dsm_segment_address(segment); - BlockHeaderPtr header = (BlockHeaderPtr) &ptr[start * dsm_cfg->block_size]; - size_t blocks_count = get_length(header); - - /* set blocks free */ - for(; i < blocks_count; i++) - { - header = (BlockHeaderPtr) &ptr[(start + i) * dsm_cfg->block_size]; - *header = set_free(header); - *header = set_length(header, 1); - } - - if (start < dsm_cfg->first_free) - dsm_cfg->first_free = start; - - arr->offset = 0; - arr->length = 0; -} - -void -resize_dsm_array(DsmArray *arr, size_t entry_size, size_t length) -{ - void *array_data; - size_t array_data_size; - void *buffer; - - /* Copy data from array to temporary buffer */ - array_data = dsm_array_get_pointer(arr); - array_data_size = arr->length * entry_size; - buffer = palloc(array_data_size); - memcpy(buffer, array_data, array_data_size); - - /* Free array */ - free_dsm_array(arr); - - /* Allocate new array */ - alloc_dsm_array(arr, entry_size, length); - - /* Copy data to new array */ - array_data = dsm_array_get_pointer(arr); - memcpy(array_data, buffer, array_data_size); - - pfree(buffer); -} - -void * -dsm_array_get_pointer(const DsmArray* arr) -{ - return (char *) dsm_segment_address(segment) + arr->offset + sizeof(BlockHeader); -} diff --git a/contrib/pg_pathman/expected/for_update.out b/contrib/pg_pathman/expected/for_update.out new file mode 100644 index 0000000000..3e41031ee3 --- /dev/null +++ b/contrib/pg_pathman/expected/for_update.out @@ -0,0 +1,38 @@ +Parsed test spec with 2 sessions + +starting permutation: s1_b s1_update s2_select s1_r +create_range_partitions + +10 +step s1_b: begin; +step s1_update: update test_tbl set id = 2 where id = 1; +step s2_select: select * from test_tbl where id = 1; +id val + +1 1 +step s1_r: rollback; + +starting permutation: s1_b s1_update s2_select_locked s1_r +create_range_partitions + +10 +step s1_b: begin; +step s1_update: update test_tbl set id = 2 where id = 1; +step s2_select_locked: select * from test_tbl where id = 1 for share; +step s1_r: rollback; +step s2_select_locked: <... completed> +id val + +1 1 + +starting permutation: s1_b s1_update s2_select_locked s1_c +create_range_partitions + +10 +step s1_b: begin; +step s1_update: update test_tbl set id = 2 where id = 1; +step s2_select_locked: select * from test_tbl where id = 1 for share; +step s1_c: commit; +step s2_select_locked: <... completed> +id val + diff --git a/contrib/pg_pathman/expected/insert_trigger.out b/contrib/pg_pathman/expected/insert_nodes.out similarity index 97% rename from contrib/pg_pathman/expected/insert_trigger.out rename to contrib/pg_pathman/expected/insert_nodes.out index b82ae8379a..a6791621e9 100644 --- a/contrib/pg_pathman/expected/insert_trigger.out +++ b/contrib/pg_pathman/expected/insert_nodes.out @@ -7,7 +7,7 @@ create_range_partitions step s1b: BEGIN; step s1_insert_150: INSERT INTO range_rel SELECT generate_series(1, 150); step s1r: ROLLBACK; -step s1_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s1_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) @@ -15,7 +15,7 @@ consrc step s2b: BEGIN; step s2_insert_150: INSERT INTO range_rel SELECT generate_series(1, 150); step s2c: COMMIT; -step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) @@ -28,7 +28,7 @@ create_range_partitions step s1b: BEGIN; step s1_insert_150: INSERT INTO range_rel SELECT generate_series(1, 150); step s1r: ROLLBACK; -step s1_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s1_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) @@ -36,7 +36,7 @@ consrc step s2b: BEGIN; step s2_insert_300: INSERT INTO range_rel SELECT generate_series(151, 300); step s2c: COMMIT; -step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) @@ -50,7 +50,7 @@ create_range_partitions step s1b: BEGIN; step s1_insert_300: INSERT INTO range_rel SELECT generate_series(151, 300); step s1r: ROLLBACK; -step s1_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s1_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) @@ -59,7 +59,7 @@ consrc step s2b: BEGIN; step s2_insert_150: INSERT INTO range_rel SELECT generate_series(1, 150); step s2c: COMMIT; -step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) @@ -76,7 +76,7 @@ step s2b: BEGIN; step s2_insert_300: INSERT INTO range_rel SELECT generate_series(151, 300); step s1r: ROLLBACK; step s2r: ROLLBACK; -step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; +step s2_show_partitions: SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; consrc ((id >= 1) AND (id < 101)) diff --git a/contrib/pg_pathman/expected/pg_pathman.out b/contrib/pg_pathman/expected/pathman_basic.out similarity index 85% rename from contrib/pg_pathman/expected/pg_pathman.out rename to contrib/pg_pathman/expected/pathman_basic.out index 78b5eaebe9..b905b02a0b 100644 --- a/contrib/pg_pathman/expected/pg_pathman.out +++ b/contrib/pg_pathman/expected/pathman_basic.out @@ -9,12 +9,87 @@ INSERT INTO test.hash_rel VALUES (1, 1); INSERT INTO test.hash_rel VALUES (2, 2); INSERT INTO test.hash_rel VALUES (3, 3); SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3); -ERROR: Partitioning key 'value' must be NOT NULL +ERROR: partitioning key 'value' must be NOT NULL ALTER TABLE test.hash_rel ALTER COLUMN value SET NOT NULL; +SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3, partition_data:=false); + create_hash_partitions +------------------------ + 3 +(1 row) + +EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; + QUERY PLAN +------------------------------ + Append + -> Seq Scan on hash_rel + -> Seq Scan on hash_rel_0 + -> Seq Scan on hash_rel_1 + -> Seq Scan on hash_rel_2 +(5 rows) + +SELECT * FROM test.hash_rel; + id | value +----+------- + 1 | 1 + 2 | 2 + 3 | 3 +(3 rows) + +SELECT pathman.set_enable_parent('test.hash_rel', false); + set_enable_parent +------------------- + +(1 row) + +EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; + QUERY PLAN +------------------------------ + Append + -> Seq Scan on hash_rel_0 + -> Seq Scan on hash_rel_1 + -> Seq Scan on hash_rel_2 +(4 rows) + +SELECT * FROM test.hash_rel; + id | value +----+------- +(0 rows) + +SELECT pathman.set_enable_parent('test.hash_rel', true); + set_enable_parent +------------------- + +(1 row) + +EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; + QUERY PLAN +------------------------------ + Append + -> Seq Scan on hash_rel + -> Seq Scan on hash_rel_0 + -> Seq Scan on hash_rel_1 + -> Seq Scan on hash_rel_2 +(5 rows) + +SELECT * FROM test.hash_rel; + id | value +----+------- + 1 | 1 + 2 | 2 + 3 | 3 +(3 rows) + +SELECT pathman.drop_partitions('test.hash_rel'); +NOTICE: function test.hash_rel_upd_trig_func() does not exist, skipping +NOTICE: 0 rows copied from test.hash_rel_0 +NOTICE: 0 rows copied from test.hash_rel_1 +NOTICE: 0 rows copied from test.hash_rel_2 + drop_partitions +----------------- + 3 +(1 row) + SELECT pathman.create_hash_partitions('test.hash_rel', 'Value', 3); -NOTICE: function test.hash_rel_insert_trigger_func() does not exist, skipping -NOTICE: function test.hash_rel_update_trigger_func() does not exist, skipping -NOTICE: Copying data to partitions... create_hash_partitions ------------------------ 3 @@ -55,13 +130,12 @@ CREATE INDEX ON test.range_rel (dt); INSERT INTO test.range_rel (dt, txt) SELECT g, md5(g::TEXT) FROM generate_series('2015-01-01', '2015-04-30', '1 day'::interval) as g; SELECT pathman.create_range_partitions('test.range_rel', 'dt', '2015-01-01'::DATE, '1 month'::INTERVAL, 2); -ERROR: Partitioning key 'dt' must be NOT NULL P0001 +ERROR: partitioning key 'dt' must be NOT NULL ALTER TABLE test.range_rel ALTER COLUMN dt SET NOT NULL; SELECT pathman.create_range_partitions('test.range_rel', 'dt', '2015-01-01'::DATE, '1 month'::INTERVAL, 2); -ERROR: Not enough partitions to fit all the values of 'dt' P0001 +ERROR: not enough partitions to fit all values of 'dt' SELECT pathman.create_range_partitions('test.range_rel', 'DT', '2015-01-01'::DATE, '1 month'::INTERVAL); NOTICE: sequence "range_rel_seq" does not exist, skipping -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 4 @@ -84,7 +158,6 @@ CREATE TABLE test.num_range_rel ( txt TEXT); SELECT pathman.create_range_partitions('test.num_range_rel', 'id', 0, 1000, 4); NOTICE: sequence "num_range_rel_seq" does not exist, skipping -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 4 @@ -116,12 +189,16 @@ SELECT COUNT(*) FROM ONLY test.num_range_rel; 0 (1 row) +SELECT * FROM ONLY test.range_rel UNION SELECT * FROM test.range_rel; +ERROR: It is prohibited to query partitioned tables both with and without ONLY modifier +SET pg_pathman.enable_runtimeappend = OFF; +SET pg_pathman.enable_runtimemergeappend = OFF; VACUUM; /* update triggers test */ SELECT pathman.create_hash_update_trigger('test.hash_rel'); - create_hash_update_trigger ----------------------------- - + create_hash_update_trigger +----------------------------- + test.hash_rel_upd_trig_func (1 row) UPDATE test.hash_rel SET value = 7 WHERE value = 6; @@ -140,9 +217,9 @@ SELECT * FROM test.hash_rel WHERE value = 7; (1 row) SELECT pathman.create_range_update_trigger('test.num_range_rel'); - create_range_update_trigger ------------------------------------------- - test.num_range_rel_update_trigger_func() + create_range_update_trigger +---------------------------------- + test.num_range_rel_upd_trig_func (1 row) UPDATE test.num_range_rel SET id = 3001 WHERE id = 1; @@ -176,7 +253,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value = 2; QUERY PLAN ------------------------------ Append - -> Seq Scan on hash_rel_2 + -> Seq Scan on hash_rel_1 Filter: (value = 2) (3 rows) @@ -185,11 +262,21 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value = 2 OR value = 1; ------------------------------ Append -> Seq Scan on hash_rel_1 - Filter: (value = 1) - -> Seq Scan on hash_rel_2 Filter: (value = 2) + -> Seq Scan on hash_rel_2 + Filter: (value = 1) (5 rows) +-- Temporarily commented out +-- EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value BETWEEN 1 AND 2; +-- QUERY PLAN +-- ------------------------------------------------- +-- Append +-- -> Seq Scan on hash_rel_1 +-- Filter: ((value >= 1) AND (value <= 2)) +-- -> Seq Scan on hash_rel_2 +-- Filter: ((value >= 1) AND (value <= 2)) +-- (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id > 2500; QUERY PLAN ----------------------------------- @@ -286,7 +373,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value = 2; QUERY PLAN ------------------------------ Append - -> Seq Scan on hash_rel_2 + -> Seq Scan on hash_rel_1 Filter: (value = 2) (3 rows) @@ -295,9 +382,9 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value = 2 OR value = 1; ------------------------------ Append -> Seq Scan on hash_rel_1 - Filter: (value = 1) - -> Seq Scan on hash_rel_2 Filter: (value = 2) + -> Seq Scan on hash_rel_2 + Filter: (value = 1) (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id > 2500; @@ -469,6 +556,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel_1 UNION ALL SELECT * FROM test. * Join */ SET enable_hashjoin = OFF; +set enable_nestloop = OFF; SET enable_mergejoin = ON; EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel j1 @@ -536,7 +624,7 @@ WHERE j1.dt < '2015-03-01' AND j2.dt >= '2015-02-01' ORDER BY j2.dt; * Test CTE query */ EXPLAIN (COSTS OFF) - WITH ttt AS (SELECT * FROM test.range_rel WHERE dt >= '2015-02-01' AND dt < '2015-03-15') + WITH ttt AS (SELECT * FROM test.range_rel WHERE dt >= '2015-02-01' AND dt < '2015-03-15') SELECT * FROM ttt; QUERY PLAN -------------------------------------------------------------------------------------------- @@ -549,14 +637,14 @@ SELECT * FROM ttt; (6 rows) EXPLAIN (COSTS OFF) - WITH ttt AS (SELECT * FROM test.hash_rel WHERE value = 2) + WITH ttt AS (SELECT * FROM test.hash_rel WHERE value = 2) SELECT * FROM ttt; QUERY PLAN -------------------------------------- CTE Scan on ttt CTE ttt -> Append - -> Seq Scan on hash_rel_2 + -> Seq Scan on hash_rel_1 Filter: (value = 2) (5 rows) @@ -565,10 +653,6 @@ SELECT * FROM ttt; */ /* Split first partition in half */ SELECT pathman.split_range_partition('test.num_range_rel_1', 500); -NOTICE: Creating new partition... -NOTICE: Copying data to new partition... -NOTICE: Altering original partition... -NOTICE: Done! split_range_partition ----------------------- {0,1000} @@ -585,10 +669,6 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id BETWEEN 100 AND 70 (5 rows) SELECT pathman.split_range_partition('test.range_rel_1', '2015-01-15'::DATE); -NOTICE: Creating new partition... -NOTICE: Copying data to new partition... -NOTICE: Altering original partition... -NOTICE: Done! split_range_partition ------------------------- {01-01-2015,02-01-2015} @@ -596,10 +676,6 @@ NOTICE: Done! /* Merge two partitions into one */ SELECT pathman.merge_range_partitions('test.num_range_rel_1', 'test.num_range_rel_' || currval('test.num_range_rel_seq')); -NOTICE: Altering first partition... -NOTICE: Copying data... -NOTICE: Dropping second partition... -NOTICE: Done! merge_range_partitions ------------------------ @@ -614,10 +690,6 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id BETWEEN 100 AND 70 (3 rows) SELECT pathman.merge_range_partitions('test.range_rel_1', 'test.range_rel_' || currval('test.range_rel_seq')); -NOTICE: Altering first partition... -NOTICE: Copying data... -NOTICE: Dropping second partition... -NOTICE: Done! merge_range_partitions ------------------------ @@ -625,8 +697,6 @@ NOTICE: Done! /* Append and prepend partitions */ SELECT pathman.append_range_partition('test.num_range_rel'); -NOTICE: Appending new partition... -NOTICE: Done! append_range_partition ------------------------ test.num_range_rel_6 @@ -640,8 +710,6 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id >= 4000; (2 rows) SELECT pathman.prepend_range_partition('test.num_range_rel'); -NOTICE: Prepending new partition... -NOTICE: Done! prepend_range_partition ------------------------- test.num_range_rel_7 @@ -661,16 +729,12 @@ SELECT pathman.drop_range_partition('test.num_range_rel_7'); (1 row) SELECT pathman.append_range_partition('test.range_rel'); -NOTICE: Appending new partition... -NOTICE: Done! append_range_partition ------------------------ test.range_rel_6 (1 row) SELECT pathman.prepend_range_partition('test.range_rel'); -NOTICE: Prepending new partition... -NOTICE: Done! prepend_range_partition ------------------------- test.range_rel_7 @@ -701,9 +765,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel WHERE dt BETWEEN '2014-12-15' A (3 rows) SELECT pathman.add_range_partition('test.range_rel', '2014-12-01'::DATE, '2015-01-02'::DATE); -ERROR: Specified range overlaps with existing partitions P0001 +ERROR: specified range overlaps with existing partitions SELECT pathman.add_range_partition('test.range_rel', '2014-12-01'::DATE, '2015-01-01'::DATE); -NOTICE: Done! add_range_partition --------------------- test.range_rel_8 @@ -721,7 +784,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel WHERE dt BETWEEN '2014-12-15' A CREATE TABLE test.range_rel_archive (LIKE test.range_rel INCLUDING ALL); SELECT pathman.attach_range_partition('test.range_rel', 'test.range_rel_archive', '2014-01-01'::DATE, '2015-01-01'::DATE); -ERROR: Specified range overlaps with existing partitions P0001 +ERROR: specified range overlaps with existing partitions SELECT pathman.attach_range_partition('test.range_rel', 'test.range_rel_archive', '2014-01-01'::DATE, '2014-12-01'::DATE); attach_range_partition ------------------------ @@ -755,17 +818,61 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel WHERE dt BETWEEN '2014-11-15' A (4 rows) CREATE TABLE test.range_rel_test1 ( - id SERIAL PRIMARY KEY, - dt TIMESTAMP, - txt TEXT, - abc INTEGER); + id SERIAL PRIMARY KEY, + dt TIMESTAMP, + txt TEXT, + abc INTEGER); SELECT pathman.attach_range_partition('test.range_rel', 'test.range_rel_test1', '2013-01-01'::DATE, '2014-01-01'::DATE); -ERROR: Partition must have the exact same structure as parent P0001 +ERROR: partition must have the exact same structure as parent CREATE TABLE test.range_rel_test2 ( - id SERIAL PRIMARY KEY, - dt TIMESTAMP); + id SERIAL PRIMARY KEY, + dt TIMESTAMP); SELECT pathman.attach_range_partition('test.range_rel', 'test.range_rel_test2', '2013-01-01'::DATE, '2014-01-01'::DATE); -ERROR: Partition must have the exact same structure as parent P0001 +ERROR: partition must have the exact same structure as parent +/* + * Zero partitions count and adding partitions with specified name + */ +CREATE TABLE test.zero( + id SERIAL PRIMARY KEY, + value INT NOT NULL); +INSERT INTO test.zero SELECT g, g FROM generate_series(1, 100) as g; +SELECT pathman.create_range_partitions('test.zero', 'value', 50, 10, 0); +NOTICE: sequence "zero_seq" does not exist, skipping + create_range_partitions +------------------------- + 0 +(1 row) + +SELECT pathman.append_range_partition('test.zero', 'test.zero_0'); +ERROR: cannot append to empty partitions set +SELECT pathman.prepend_range_partition('test.zero', 'test.zero_1'); +ERROR: cannot prepend to empty partitions set +SELECT pathman.add_range_partition('test.zero', 50, 70, 'test.zero_50'); + add_range_partition +--------------------- + test.zero_50 +(1 row) + +SELECT pathman.append_range_partition('test.zero', 'test.zero_appended'); + append_range_partition +------------------------ + test.zero_appended +(1 row) + +SELECT pathman.prepend_range_partition('test.zero', 'test.zero_prepended'); + prepend_range_partition +------------------------- + test.zero_prepended +(1 row) + +SELECT pathman.split_range_partition('test.zero_50', 60, 'test.zero_60'); + split_range_partition +----------------------- + {50,70} +(1 row) + +DROP TABLE test.zero CASCADE; +NOTICE: drop cascades to 4 other objects /* * Check that altering table columns doesn't break trigger */ @@ -780,15 +887,14 @@ SELECT * FROM test.hash_rel WHERE id = 123; /* * Clean up */ -SELECT pathman.drop_hash_partitions('test.hash_rel'); -NOTICE: drop cascades to trigger test_hash_rel_insert_trigger on table test.hash_rel +SELECT pathman.drop_partitions('test.hash_rel'); NOTICE: drop cascades to 3 other objects -NOTICE: 2 rows copied from test.hash_rel_2 -NOTICE: 3 rows copied from test.hash_rel_1 NOTICE: 2 rows copied from test.hash_rel_0 - drop_hash_partitions ----------------------- - 3 +NOTICE: 3 rows copied from test.hash_rel_1 +NOTICE: 2 rows copied from test.hash_rel_2 + drop_partitions +----------------- + 3 (1 row) SELECT COUNT(*) FROM ONLY test.hash_rel; @@ -798,20 +904,16 @@ SELECT COUNT(*) FROM ONLY test.hash_rel; (1 row) SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3); -NOTICE: function test.hash_rel_insert_trigger_func() does not exist, skipping -NOTICE: function test.hash_rel_update_trigger_func() does not exist, skipping -NOTICE: Copying data to partitions... create_hash_partitions ------------------------ 3 (1 row) -SELECT pathman.drop_hash_partitions('test.hash_rel', TRUE); -NOTICE: drop cascades to trigger test_hash_rel_insert_trigger on table test.hash_rel -NOTICE: function test.hash_rel_update_trigger_func() does not exist, skipping - drop_hash_partitions ----------------------- - 3 +SELECT pathman.drop_partitions('test.hash_rel', TRUE); +NOTICE: function test.hash_rel_upd_trig_func() does not exist, skipping + drop_partitions +----------------- + 3 (1 row) SELECT COUNT(*) FROM ONLY test.hash_rel; @@ -821,15 +923,16 @@ SELECT COUNT(*) FROM ONLY test.hash_rel; (1 row) DROP TABLE test.hash_rel CASCADE; -SELECT pathman.drop_range_partitions('test.num_range_rel'); -NOTICE: 0 rows copied from test.num_range_rel_6 -NOTICE: 2 rows copied from test.num_range_rel_4 -NOTICE: 1000 rows copied from test.num_range_rel_3 -NOTICE: 1000 rows copied from test.num_range_rel_2 +SELECT pathman.drop_partitions('test.num_range_rel'); +NOTICE: drop cascades to 4 other objects NOTICE: 998 rows copied from test.num_range_rel_1 - drop_range_partitions ------------------------ - 5 +NOTICE: 1000 rows copied from test.num_range_rel_2 +NOTICE: 1000 rows copied from test.num_range_rel_3 +NOTICE: 2 rows copied from test.num_range_rel_4 +NOTICE: 0 rows copied from test.num_range_rel_6 + drop_partitions +----------------- + 5 (1 row) DROP TABLE test.num_range_rel CASCADE; @@ -840,7 +943,6 @@ CREATE TABLE test.range_rel ( id SERIAL PRIMARY KEY, dt TIMESTAMP NOT NULL); SELECT pathman.create_range_partitions('test.range_rel', 'dt', '2015-01-01'::DATE, '10 days'::INTERVAL, 1); -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 1 @@ -878,11 +980,26 @@ SELECT * FROM test.range_rel WHERE dt = '2015-03-15'; 74 | Sun Mar 15 00:00:00 2015 (1 row) +SELECT pathman.set_auto('test.range_rel', false); + set_auto +---------- + +(1 row) + +INSERT INTO test.range_rel (dt) VALUES ('2015-06-01'); +ERROR: no suitable partition for key 'Mon Jun 01 00:00:00 2015' +SELECT pathman.set_auto('test.range_rel', true); + set_auto +---------- + +(1 row) + +INSERT INTO test.range_rel (dt) VALUES ('2015-06-01'); DROP TABLE test.range_rel CASCADE; -NOTICE: drop cascades to 16 other objects +NOTICE: drop cascades to 20 other objects SELECT * FROM pathman.pathman_config; - id | relname | attname | parttype | range_interval -----+---------+---------+----------+---------------- + partrel | attname | parttype | range_interval +---------+---------+----------+---------------- (0 rows) /* Check overlaps */ @@ -890,7 +1007,6 @@ CREATE TABLE test.num_range_rel ( id SERIAL PRIMARY KEY, txt TEXT); SELECT pathman.create_range_partitions('test.num_range_rel', 'id', 1000, 1000, 4); -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 4 @@ -943,9 +1059,6 @@ CREATE TABLE test."TeSt" (a INT NOT NULL, b INT); SELECT pathman.create_hash_partitions('test.TeSt', 'a', 3); ERROR: relation "test.test" does not exist at character 39 SELECT pathman.create_hash_partitions('test."TeSt"', 'a', 3); -NOTICE: function test.TeSt_insert_trigger_func() does not exist, skipping -NOTICE: function test.TeSt_update_trigger_func() does not exist, skipping -NOTICE: Copying data to partitions... create_hash_partitions ------------------------ 3 @@ -958,14 +1071,14 @@ SELECT * FROM test."TeSt"; a | b ---+--- 3 | 3 - 1 | 1 2 | 2 + 1 | 1 (3 rows) SELECT pathman.create_hash_update_trigger('test."TeSt"'); create_hash_update_trigger ---------------------------- - + test."TeSt_upd_trig_func" (1 row) UPDATE test."TeSt" SET a = 1; @@ -973,43 +1086,42 @@ SELECT * FROM test."TeSt"; a | b ---+--- 1 | 3 - 1 | 1 1 | 2 + 1 | 1 (3 rows) SELECT * FROM test."TeSt" WHERE a = 1; a | b ---+--- 1 | 3 - 1 | 1 1 | 2 + 1 | 1 (3 rows) EXPLAIN (COSTS OFF) SELECT * FROM test."TeSt" WHERE a = 1; QUERY PLAN ---------------------------- Append - -> Seq Scan on "TeSt_1" + -> Seq Scan on "TeSt_2" Filter: (a = 1) (3 rows) -SELECT pathman.drop_hash_partitions('test."TeSt"'); -NOTICE: drop cascades to trigger test_TeSt_insert_trigger on table test."TeSt" +SELECT pathman.drop_partitions('test."TeSt"'); NOTICE: drop cascades to 3 other objects -NOTICE: 0 rows copied from test."TeSt_2" -NOTICE: 3 rows copied from test."TeSt_1" NOTICE: 0 rows copied from test."TeSt_0" - drop_hash_partitions ----------------------- - 3 +NOTICE: 0 rows copied from test."TeSt_1" +NOTICE: 3 rows copied from test."TeSt_2" + drop_partitions +----------------- + 3 (1 row) SELECT * FROM test."TeSt"; a | b ---+--- 1 | 3 - 1 | 1 1 | 2 + 1 | 1 (3 rows) CREATE TABLE test."RangeRel" ( @@ -1020,61 +1132,48 @@ INSERT INTO test."RangeRel" (dt, txt) SELECT g, md5(g::TEXT) FROM generate_series('2015-01-01', '2015-01-03', '1 day'::interval) as g; SELECT pathman.create_range_partitions('test."RangeRel"', 'dt', '2015-01-01'::DATE, '1 day'::INTERVAL); NOTICE: sequence "RangeRel_seq" does not exist, skipping -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 3 (1 row) SELECT pathman.append_range_partition('test."RangeRel"'); -NOTICE: Appending new partition... -NOTICE: Done! append_range_partition ------------------------ test."RangeRel_4" (1 row) SELECT pathman.prepend_range_partition('test."RangeRel"'); -NOTICE: Prepending new partition... -NOTICE: Done! prepend_range_partition ------------------------- test."RangeRel_5" (1 row) SELECT pathman.merge_range_partitions('test."RangeRel_1"', 'test."RangeRel_' || currval('test."RangeRel_seq"') || '"'); -NOTICE: Altering first partition... -NOTICE: Copying data... -NOTICE: Dropping second partition... -NOTICE: Done! merge_range_partitions ------------------------ (1 row) SELECT pathman.split_range_partition('test."RangeRel_1"', '2015-01-01'::DATE); -NOTICE: Creating new partition... -NOTICE: Copying data to new partition... -NOTICE: Altering original partition... -NOTICE: Done! split_range_partition ------------------------- {12-31-2014,01-02-2015} (1 row) -SELECT pathman.drop_range_partitions('test."RangeRel"'); -NOTICE: 1 rows copied from test."RangeRel_6" -NOTICE: 0 rows copied from test."RangeRel_4" -NOTICE: 1 rows copied from test."RangeRel_3" -NOTICE: 1 rows copied from test."RangeRel_2" +SELECT pathman.drop_partitions('test."RangeRel"'); +NOTICE: function test.RangeRel_upd_trig_func() does not exist, skipping NOTICE: 0 rows copied from test."RangeRel_1" - drop_range_partitions ------------------------ - 5 +NOTICE: 1 rows copied from test."RangeRel_2" +NOTICE: 1 rows copied from test."RangeRel_3" +NOTICE: 0 rows copied from test."RangeRel_4" +NOTICE: 1 rows copied from test."RangeRel_6" + drop_partitions +----------------- + 5 (1 row) SELECT pathman.create_partitions_from_range('test."RangeRel"', 'dt', '2015-01-01'::DATE, '2015-01-05'::DATE, '1 day'::INTERVAL); -NOTICE: Copying data to partitions... create_partitions_from_range ------------------------------ 5 @@ -1083,9 +1182,9 @@ NOTICE: Copying data to partitions... DROP TABLE test."RangeRel" CASCADE; NOTICE: drop cascades to 5 other objects SELECT * FROM pathman.pathman_config; - id | relname | attname | parttype | range_interval -----+--------------------+---------+----------+---------------- - 6 | test.num_range_rel | id | 2 | 1000 + partrel | attname | parttype | range_interval +--------------------+---------+----------+---------------- + test.num_range_rel | id | 2 | 1000 (1 row) CREATE TABLE test."RangeRel" ( @@ -1093,23 +1192,22 @@ CREATE TABLE test."RangeRel" ( dt TIMESTAMP NOT NULL, txt TEXT); SELECT pathman.create_range_partitions('test."RangeRel"', 'id', 1, 100, 3); -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 3 (1 row) -SELECT pathman.drop_range_partitions('test."RangeRel"'); -NOTICE: 0 rows copied from test."RangeRel_3" -NOTICE: 0 rows copied from test."RangeRel_2" +SELECT pathman.drop_partitions('test."RangeRel"'); +NOTICE: function test.RangeRel_upd_trig_func() does not exist, skipping NOTICE: 0 rows copied from test."RangeRel_1" - drop_range_partitions ------------------------ - 3 +NOTICE: 0 rows copied from test."RangeRel_2" +NOTICE: 0 rows copied from test."RangeRel_3" + drop_partitions +----------------- + 3 (1 row) SELECT pathman.create_partitions_from_range('test."RangeRel"', 'id', 1, 300, 100); -NOTICE: Copying data to partitions... create_partitions_from_range ------------------------------ 3 @@ -1126,9 +1224,6 @@ CREATE TABLE hash_rel ( value INTEGER NOT NULL); INSERT INTO hash_rel (value) SELECT g FROM generate_series(1, 10000) as g; SELECT create_hash_partitions('hash_rel', 'value', 3); -NOTICE: function public.hash_rel_insert_trigger_func() does not exist, skipping -NOTICE: function public.hash_rel_update_trigger_func() does not exist, skipping -NOTICE: Copying data to partitions... create_hash_partitions ------------------------ 3 @@ -1154,43 +1249,30 @@ CREATE TABLE range_rel ( INSERT INTO range_rel (dt, value) SELECT g, extract(day from g) FROM generate_series('2010-01-01'::date, '2010-12-31'::date, '1 day') as g; SELECT create_range_partitions('range_rel', 'dt', '2010-01-01'::date, '1 month'::interval, 12); NOTICE: sequence "range_rel_seq" does not exist, skipping -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 12 (1 row) SELECT merge_range_partitions('range_rel_1', 'range_rel_2'); -NOTICE: Altering first partition... -NOTICE: Copying data... -NOTICE: Dropping second partition... -NOTICE: Done! merge_range_partitions ------------------------ (1 row) SELECT split_range_partition('range_rel_1', '2010-02-15'::date); -NOTICE: Creating new partition... -NOTICE: Copying data to new partition... -NOTICE: Altering original partition... -NOTICE: Done! split_range_partition ------------------------- {01-01-2010,03-01-2010} (1 row) SELECT append_range_partition('range_rel'); -NOTICE: Appending new partition... -NOTICE: Done! append_range_partition ------------------------ public.range_rel_14 (1 row) SELECT prepend_range_partition('range_rel'); -NOTICE: Prepending new partition... -NOTICE: Done! prepend_range_partition ------------------------- public.range_rel_15 @@ -1274,41 +1356,41 @@ EXPLAIN (COSTS OFF) DELETE FROM range_rel r USING tmp t WHERE r.dt = '2010-01-02 DELETE FROM range_rel r USING tmp t WHERE r.dt = '2010-01-02' AND r.id = t.id; /* Create range partitions from whole range */ -SELECT drop_range_partitions('range_rel'); -NOTICE: 0 rows copied from range_rel_15 -NOTICE: 0 rows copied from range_rel_14 -NOTICE: 14 rows copied from range_rel_13 -NOTICE: 31 rows copied from range_rel_12 -NOTICE: 30 rows copied from range_rel_11 -NOTICE: 31 rows copied from range_rel_10 -NOTICE: 30 rows copied from range_rel_9 -NOTICE: 31 rows copied from range_rel_8 -NOTICE: 31 rows copied from range_rel_7 -NOTICE: 29 rows copied from range_rel_6 -NOTICE: 31 rows copied from range_rel_5 -NOTICE: 30 rows copied from range_rel_4 -NOTICE: 31 rows copied from range_rel_3 +SELECT drop_partitions('range_rel'); +NOTICE: function public.range_rel_upd_trig_func() does not exist, skipping NOTICE: 44 rows copied from range_rel_1 - drop_range_partitions ------------------------ - 14 +NOTICE: 31 rows copied from range_rel_3 +NOTICE: 30 rows copied from range_rel_4 +NOTICE: 31 rows copied from range_rel_5 +NOTICE: 29 rows copied from range_rel_6 +NOTICE: 31 rows copied from range_rel_7 +NOTICE: 31 rows copied from range_rel_8 +NOTICE: 30 rows copied from range_rel_9 +NOTICE: 31 rows copied from range_rel_10 +NOTICE: 30 rows copied from range_rel_11 +NOTICE: 31 rows copied from range_rel_12 +NOTICE: 14 rows copied from range_rel_13 +NOTICE: 0 rows copied from range_rel_14 +NOTICE: 0 rows copied from range_rel_15 + drop_partitions +----------------- + 14 (1 row) SELECT create_partitions_from_range('range_rel', 'id', 1, 1000, 100); -NOTICE: Copying data to partitions... create_partitions_from_range ------------------------------ 10 (1 row) -SELECT drop_range_partitions('range_rel', TRUE); - drop_range_partitions ------------------------ - 10 +SELECT drop_partitions('range_rel', TRUE); +NOTICE: function public.range_rel_upd_trig_func() does not exist, skipping + drop_partitions +----------------- + 10 (1 row) SELECT create_partitions_from_range('range_rel', 'dt', '2015-01-01'::date, '2015-12-01'::date, '1 month'::interval); -NOTICE: Copying data to partitions... create_partitions_from_range ------------------------------ 12 @@ -1327,12 +1409,11 @@ CREATE TABLE replies(id SERIAL PRIMARY KEY, message_id INTEGER REFERENCES messag INSERT INTO messages SELECT g, md5(g::text) FROM generate_series(1, 10) as g; INSERT INTO replies SELECT g, g, md5(g::text) FROM generate_series(1, 10) as g; SELECT create_range_partitions('messages', 'id', 1, 100, 2); -WARNING: Foreign key 'replies_message_id_fkey' references to the relation 'messages' -ERROR: Relation 'messages' is referenced from other relations P0001 +WARNING: foreign key 'replies_message_id_fkey' references relation 'messages' +ERROR: relation "messages" is referenced from other relations ALTER TABLE replies DROP CONSTRAINT replies_message_id_fkey; SELECT create_range_partitions('messages', 'id', 1, 100, 2); NOTICE: sequence "messages_seq" does not exist, skipping -NOTICE: Copying data to partitions... create_range_partitions ------------------------- 2 @@ -1346,4 +1427,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM messages; -> Seq Scan on messages_2 (3 rows) -DROP EXTENSION pg_pathman; +DROP SCHEMA test CASCADE; +NOTICE: drop cascades to 13 other objects +DROP EXTENSION pg_pathman CASCADE; +NOTICE: drop cascades to 3 other objects +DROP SCHEMA pathman CASCADE; diff --git a/contrib/pg_pathman/expected/pathman_callbacks.out b/contrib/pg_pathman/expected/pathman_callbacks.out new file mode 100644 index 0000000000..6a997e9ee6 --- /dev/null +++ b/contrib/pg_pathman/expected/pathman_callbacks.out @@ -0,0 +1,85 @@ +\set VERBOSITY terse +CREATE EXTENSION pg_pathman; +CREATE SCHEMA callbacks; +/* Check callbacks */ +CREATE OR REPLACE FUNCTION callbacks.abc_on_part_created_callback( + args JSONB) +RETURNS VOID AS $$ +BEGIN + RAISE WARNING 'callback arg: %', args::TEXT; +END +$$ language plpgsql; +/* set callback to be called on RANGE partitions */ +CREATE TABLE callbacks.abc(a serial, b int); +SELECT create_range_partitions('callbacks.abc', 'a', 1, 100, 2); +NOTICE: sequence "abc_seq" does not exist, skipping + create_range_partitions +------------------------- + 2 +(1 row) + +SELECT set_init_callback('callbacks.abc', + 'callbacks.abc_on_part_created_callback'); + set_init_callback +------------------- + +(1 row) + +INSERT INTO callbacks.abc VALUES (123, 1); +INSERT INTO callbacks.abc VALUES (223, 1); +SELECT append_range_partition('callbacks.abc'); +WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_4", "range_max": "401", "range_min": "301"} + append_range_partition +------------------------ + callbacks.abc_4 +(1 row) + +SELECT prepend_range_partition('callbacks.abc'); +WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_5", "range_max": "1", "range_min": "-99"} + prepend_range_partition +------------------------- + callbacks.abc_5 +(1 row) + +SELECT add_range_partition('callbacks.abc', 401, 502); +WARNING: callback arg: {"parent": "abc", "parttype": "2", "partition": "abc_6", "range_max": "502", "range_min": "401"} + add_range_partition +--------------------- + callbacks.abc_6 +(1 row) + +SELECT drop_partitions('callbacks.abc'); +NOTICE: function callbacks.abc_upd_trig_func() does not exist, skipping +NOTICE: 0 rows copied from callbacks.abc_1 +NOTICE: 1 rows copied from callbacks.abc_2 +NOTICE: 1 rows copied from callbacks.abc_3 +NOTICE: 0 rows copied from callbacks.abc_4 +NOTICE: 0 rows copied from callbacks.abc_5 +NOTICE: 0 rows copied from callbacks.abc_6 + drop_partitions +----------------- + 6 +(1 row) + +/* set callback to be called on HASH partitions */ +SELECT set_init_callback('callbacks.abc', + 'callbacks.abc_on_part_created_callback'); + set_init_callback +------------------- + +(1 row) + +SELECT create_hash_partitions('callbacks.abc', 'a', 5); +WARNING: callback arg: {"parent": "abc", "parttype": "1", "partition": "abc_0"} +WARNING: callback arg: {"parent": "abc", "parttype": "1", "partition": "abc_1"} +WARNING: callback arg: {"parent": "abc", "parttype": "1", "partition": "abc_2"} +WARNING: callback arg: {"parent": "abc", "parttype": "1", "partition": "abc_3"} +WARNING: callback arg: {"parent": "abc", "parttype": "1", "partition": "abc_4"} + create_hash_partitions +------------------------ + 5 +(1 row) + +DROP SCHEMA callbacks CASCADE; +NOTICE: drop cascades to 8 other objects +DROP EXTENSION pg_pathman CASCADE; diff --git a/contrib/pg_pathman/expected/pathman_domains.out b/contrib/pg_pathman/expected/pathman_domains.out new file mode 100644 index 0000000000..283a6d5b83 --- /dev/null +++ b/contrib/pg_pathman/expected/pathman_domains.out @@ -0,0 +1,92 @@ +\set VERBOSITY terse +CREATE EXTENSION pg_pathman; +CREATE SCHEMA domains; +CREATE DOMAIN domains.dom_test AS numeric CHECK (value < 1200); +CREATE TABLE domains.dom_table(val domains.dom_test NOT NULL); +INSERT INTO domains.dom_table SELECT generate_series(1, 999); +SELECT create_range_partitions('domains.dom_table', 'val', 1, 100); +NOTICE: sequence "dom_table_seq" does not exist, skipping + create_range_partitions +------------------------- + 10 +(1 row) + +EXPLAIN (COSTS OFF) +SELECT * FROM domains.dom_table +WHERE val < 250; + QUERY PLAN +--------------------------------------------------- + Append + -> Seq Scan on dom_table_1 + -> Seq Scan on dom_table_2 + -> Seq Scan on dom_table_3 + Filter: ((val)::numeric < '250'::numeric) +(5 rows) + +INSERT INTO domains.dom_table VALUES(1500); +ERROR: value for domain domains.dom_test violates check constraint "dom_test_check" +INSERT INTO domains.dom_table VALUES(-10); +SELECT append_range_partition('domains.dom_table'); + append_range_partition +------------------------ + domains.dom_table_12 +(1 row) + +SELECT prepend_range_partition('domains.dom_table'); + prepend_range_partition +------------------------- + domains.dom_table_13 +(1 row) + +SELECT merge_range_partitions('domains.dom_table_1', 'domains.dom_table_2'); + merge_range_partitions +------------------------ + +(1 row) + +SELECT split_range_partition('domains.dom_table_1', 50); + split_range_partition +----------------------- + {1,201} +(1 row) + +INSERT INTO domains.dom_table VALUES(1101); +EXPLAIN (COSTS OFF) +SELECT * FROM domains.dom_table +WHERE val < 450; + QUERY PLAN +--------------------------------------------------- + Append + -> Seq Scan on dom_table_13 + -> Seq Scan on dom_table_11 + -> Seq Scan on dom_table_1 + -> Seq Scan on dom_table_14 + -> Seq Scan on dom_table_3 + -> Seq Scan on dom_table_4 + -> Seq Scan on dom_table_5 + Filter: ((val)::numeric < '450'::numeric) +(9 rows) + +SELECT * FROM pathman_partition_list +ORDER BY range_min::INT, range_max::INT; + parent | partition | parttype | partattr | range_min | range_max +-------------------+----------------------+----------+----------+-----------+----------- + domains.dom_table | domains.dom_table_13 | 2 | val | -199 | -99 + domains.dom_table | domains.dom_table_11 | 2 | val | -99 | 1 + domains.dom_table | domains.dom_table_1 | 2 | val | 1 | 50 + domains.dom_table | domains.dom_table_14 | 2 | val | 50 | 201 + domains.dom_table | domains.dom_table_3 | 2 | val | 201 | 301 + domains.dom_table | domains.dom_table_4 | 2 | val | 301 | 401 + domains.dom_table | domains.dom_table_5 | 2 | val | 401 | 501 + domains.dom_table | domains.dom_table_6 | 2 | val | 501 | 601 + domains.dom_table | domains.dom_table_7 | 2 | val | 601 | 701 + domains.dom_table | domains.dom_table_8 | 2 | val | 701 | 801 + domains.dom_table | domains.dom_table_9 | 2 | val | 801 | 901 + domains.dom_table | domains.dom_table_10 | 2 | val | 901 | 1001 + domains.dom_table | domains.dom_table_12 | 2 | val | 1001 | 1101 + domains.dom_table | domains.dom_table_15 | 2 | val | 1101 | 1201 +(14 rows) + +DROP SCHEMA domains CASCADE; +NOTICE: drop cascades to 17 other objects +DROP EXTENSION pg_pathman CASCADE; diff --git a/contrib/pg_pathman/expected/pathman_foreign_keys.out b/contrib/pg_pathman/expected/pathman_foreign_keys.out new file mode 100644 index 0000000000..20a4da60d4 --- /dev/null +++ b/contrib/pg_pathman/expected/pathman_foreign_keys.out @@ -0,0 +1,67 @@ +\set VERBOSITY terse +CREATE EXTENSION pg_pathman; +CREATE SCHEMA fkeys; +/* Check primary keys generation */ +CREATE TABLE fkeys.test_ref(comment TEXT UNIQUE); +INSERT INTO fkeys.test_ref VALUES('test'); +CREATE TABLE fkeys.test_fkey( + id INT NOT NULL, + comment TEXT, + FOREIGN KEY (comment) REFERENCES fkeys.test_ref(comment)); +INSERT INTO fkeys.test_fkey SELECT generate_series(1, 1000), 'test'; +SELECT create_range_partitions('fkeys.test_fkey', 'id', 1, 100); +NOTICE: sequence "test_fkey_seq" does not exist, skipping + create_range_partitions +------------------------- + 10 +(1 row) + +INSERT INTO fkeys.test_fkey VALUES(1, 'wrong'); +ERROR: insert or update on table "test_fkey_1" violates foreign key constraint "test_fkey_1_comment_fkey" +INSERT INTO fkeys.test_fkey VALUES(1, 'test'); +SELECT drop_partitions('fkeys.test_fkey'); +NOTICE: function fkeys.test_fkey_upd_trig_func() does not exist, skipping +NOTICE: 101 rows copied from fkeys.test_fkey_1 +NOTICE: 100 rows copied from fkeys.test_fkey_2 +NOTICE: 100 rows copied from fkeys.test_fkey_3 +NOTICE: 100 rows copied from fkeys.test_fkey_4 +NOTICE: 100 rows copied from fkeys.test_fkey_5 +NOTICE: 100 rows copied from fkeys.test_fkey_6 +NOTICE: 100 rows copied from fkeys.test_fkey_7 +NOTICE: 100 rows copied from fkeys.test_fkey_8 +NOTICE: 100 rows copied from fkeys.test_fkey_9 +NOTICE: 100 rows copied from fkeys.test_fkey_10 + drop_partitions +----------------- + 10 +(1 row) + +SELECT create_hash_partitions('fkeys.test_fkey', 'id', 10); + create_hash_partitions +------------------------ + 10 +(1 row) + +INSERT INTO fkeys.test_fkey VALUES(1, 'wrong'); +ERROR: insert or update on table "test_fkey_0" violates foreign key constraint "test_fkey_0_comment_fkey" +INSERT INTO fkeys.test_fkey VALUES(1, 'test'); +SELECT drop_partitions('fkeys.test_fkey'); +NOTICE: function fkeys.test_fkey_upd_trig_func() does not exist, skipping +NOTICE: 100 rows copied from fkeys.test_fkey_0 +NOTICE: 90 rows copied from fkeys.test_fkey_1 +NOTICE: 90 rows copied from fkeys.test_fkey_2 +NOTICE: 116 rows copied from fkeys.test_fkey_3 +NOTICE: 101 rows copied from fkeys.test_fkey_4 +NOTICE: 90 rows copied from fkeys.test_fkey_5 +NOTICE: 95 rows copied from fkeys.test_fkey_6 +NOTICE: 118 rows copied from fkeys.test_fkey_7 +NOTICE: 108 rows copied from fkeys.test_fkey_8 +NOTICE: 94 rows copied from fkeys.test_fkey_9 + drop_partitions +----------------- + 10 +(1 row) + +DROP SCHEMA fkeys CASCADE; +NOTICE: drop cascades to 3 other objects +DROP EXTENSION pg_pathman CASCADE; diff --git a/contrib/pg_pathman/expected/pathman_rowmarks.out b/contrib/pg_pathman/expected/pathman_rowmarks.out new file mode 100644 index 0000000000..40bd14e62b --- /dev/null +++ b/contrib/pg_pathman/expected/pathman_rowmarks.out @@ -0,0 +1,178 @@ +CREATE EXTENSION pg_pathman; +CREATE SCHEMA rowmarks; +CREATE TABLE rowmarks.first(id int NOT NULL); +CREATE TABLE rowmarks.second(id int NOT NULL); +INSERT INTO rowmarks.first SELECT generate_series(1, 10); +INSERT INTO rowmarks.second SELECT generate_series(1, 10); +SELECT create_hash_partitions('rowmarks.first', 'id', 5); + create_hash_partitions +------------------------ + 5 +(1 row) + +/* Not partitioned */ +SELECT * FROM rowmarks.second ORDER BY id FOR UPDATE; + id +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +/* Simple case (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first ORDER BY id FOR UPDATE; + QUERY PLAN +--------------------------------------- + LockRows + -> Sort + Sort Key: first_0.id + -> Append + -> Seq Scan on first_0 + -> Seq Scan on first_1 + -> Seq Scan on first_2 + -> Seq Scan on first_3 + -> Seq Scan on first_4 +(9 rows) + +/* Simple case (execution) */ +SELECT * FROM rowmarks.first ORDER BY id FOR UPDATE; + id +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +SELECT FROM rowmarks.first ORDER BY id FOR UPDATE; +-- +(10 rows) + +SELECT tableoid > 0 FROM rowmarks.first ORDER BY id FOR UPDATE; + ?column? +---------- + t + t + t + t + t + t + t + t + t + t +(10 rows) + +/* A little harder (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.first + ORDER BY id + OFFSET 10 LIMIT 1 + FOR UPDATE) +FOR SHARE; + QUERY PLAN +----------------------------------------------------- + LockRows + InitPlan 1 (returns $1) + -> Limit + -> LockRows + -> Sort + Sort Key: first_0.id + -> Append + -> Seq Scan on first_0 + -> Seq Scan on first_1 + -> Seq Scan on first_2 + -> Seq Scan on first_3 + -> Seq Scan on first_4 + -> Custom Scan (RuntimeAppend) + -> Seq Scan on first_0 first + Filter: (id = $1) + -> Seq Scan on first_1 first + Filter: (id = $1) + -> Seq Scan on first_2 first + Filter: (id = $1) + -> Seq Scan on first_3 first + Filter: (id = $1) + -> Seq Scan on first_4 first + Filter: (id = $1) +(23 rows) + +/* A little harder (execution) */ +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.first + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + id +---- + 6 +(1 row) + +/* Two tables (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.second + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + QUERY PLAN +---------------------------------------------- + LockRows + InitPlan 1 (returns $1) + -> Limit + -> LockRows + -> Sort + Sort Key: second.id + -> Seq Scan on second + -> Custom Scan (RuntimeAppend) + -> Seq Scan on first_0 first + Filter: (id = $1) + -> Seq Scan on first_1 first + Filter: (id = $1) + -> Seq Scan on first_2 first + Filter: (id = $1) + -> Seq Scan on first_3 first + Filter: (id = $1) + -> Seq Scan on first_4 first + Filter: (id = $1) +(18 rows) + +/* Two tables (execution) */ +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.second + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + id +---- + 6 +(1 row) + +DROP SCHEMA rowmarks CASCADE; +NOTICE: drop cascades to 7 other objects +DETAIL: drop cascades to table rowmarks.first +drop cascades to table rowmarks.second +drop cascades to table rowmarks.first_0 +drop cascades to table rowmarks.first_1 +drop cascades to table rowmarks.first_2 +drop cascades to table rowmarks.first_3 +drop cascades to table rowmarks.first_4 +DROP EXTENSION pg_pathman; diff --git a/contrib/pg_pathman/expected/pathman_runtime_nodes.out b/contrib/pg_pathman/expected/pathman_runtime_nodes.out new file mode 100644 index 0000000000..98b08710e0 --- /dev/null +++ b/contrib/pg_pathman/expected/pathman_runtime_nodes.out @@ -0,0 +1,291 @@ +\set VERBOSITY terse +CREATE SCHEMA pathman; +CREATE EXTENSION pg_pathman SCHEMA pathman; +CREATE SCHEMA test; +/* + * Test RuntimeAppend + */ +create or replace function test.pathman_assert(smt bool, error_msg text) returns text as $$ +begin + if not smt then + raise exception '%', error_msg; + end if; + + return 'ok'; +end; +$$ language plpgsql; +create or replace function test.pathman_equal(a text, b text, error_msg text) returns text as $$ +begin + if a != b then + raise exception '''%'' is not equal to ''%'', %', a, b, error_msg; + end if; + + return 'equal'; +end; +$$ language plpgsql; +create or replace function test.pathman_test(query text) returns jsonb as $$ +declare + plan jsonb; +begin + execute 'explain (analyze, format json)' || query into plan; + + return plan; +end; +$$ language plpgsql; +create or replace function test.pathman_test_1() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.runtime_test_1 where id = (select * from test.run_values limit 1)'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Custom Plan Provider')::text, + '"RuntimeAppend"', + 'wrong plan provider'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Relation Name')::text, + format('"runtime_test_1_%s"', pathman.get_hash_part_idx(hashint4(1), 6)), + 'wrong partition'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans') into num; + perform test.pathman_equal(num::text, '2', 'expected 2 child plans for custom scan'); + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; +create or replace function test.pathman_test_2() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.runtime_test_1 where id = any (select * from test.run_values limit 4)'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Nested Loop"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Custom Plan Provider')::text, + '"RuntimeAppend"', + 'wrong plan provider'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans'->1->'Plans') into num; + perform test.pathman_equal(num::text, '4', 'expected 4 child plans for custom scan'); + + for i in 0..3 loop + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Plans'->i->'Relation Name')::text, + format('"runtime_test_1_%s"', pathman.get_hash_part_idx(hashint4(i + 1), 6)), + 'wrong partition'); + + num = plan->0->'Plan'->'Plans'->1->'Plans'->i->'Actual Loops'; + perform test.pathman_equal(num::text, '1', 'expected 1 loop'); + end loop; + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; +create or replace function test.pathman_test_3() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.runtime_test_1 a join test.run_values b on a.id = b.val'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Nested Loop"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Custom Plan Provider')::text, + '"RuntimeAppend"', + 'wrong plan provider'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans'->1->'Plans') into num; + perform test.pathman_equal(num::text, '6', 'expected 6 child plans for custom scan'); + + for i in 0..5 loop + num = plan->0->'Plan'->'Plans'->1->'Plans'->i->'Actual Loops'; + perform test.pathman_assert(num > 0 and num <= 1718, 'expected no more than 1718 loops'); + end loop; + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; +create or replace function test.pathman_test_4() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.category c, lateral' || + '(select * from test.runtime_test_2 g where g.category_id = c.id order by rating limit 4) as tg'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Nested Loop"', + 'wrong plan type'); + + /* Limit -> Custom Scan */ + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->0->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->0->'Custom Plan Provider')::text, + '"RuntimeMergeAppend"', + 'wrong plan provider'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans'->1->'Plans'->0->'Plans') into num; + perform test.pathman_equal(num::text, '4', 'expected 4 child plans for custom scan'); + + for i in 0..3 loop + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Plans'->0->'Plans'->i->'Relation Name')::text, + format('"runtime_test_2_%s"', pathman.get_hash_part_idx(hashint4(i + 1), 6)), + 'wrong partition'); + + num = plan->0->'Plan'->'Plans'->1->'Plans'->0->'Plans'->i->'Actual Loops'; + perform test.pathman_assert(num = 1, 'expected no more than 1 loops'); + end loop; + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; +create or replace function test.pathman_test_5() returns text as $$ +declare + res record; +begin + select + from test.runtime_test_3 + where id = (select * from test.vals order by val limit 1) + limit 1 + into res; /* test empty tlist */ + + + select id, generate_series(1, 2) gen, val + from test.runtime_test_3 + where id = any (select * from test.vals order by val limit 5) + order by id, gen, val + offset 1 limit 1 + into res; /* without IndexOnlyScan */ + + perform test.pathman_equal(res.id::text, '1', 'id is incorrect (t2)'); + perform test.pathman_equal(res.gen::text, '2', 'gen is incorrect (t2)'); + perform test.pathman_equal(res.val::text, 'k = 1', 'val is incorrect (t2)'); + + + select id + from test.runtime_test_3 + where id = any (select * from test.vals order by val limit 5) + order by id + offset 3 limit 1 + into res; /* with IndexOnlyScan */ + + perform test.pathman_equal(res.id::text, '4', 'id is incorrect (t3)'); + + + select v.val v1, generate_series(2, 2) gen, t.val v2 + from test.runtime_test_3 t join test.vals v on id = v.val + order by v1, gen, v2 + limit 1 + into res; + + perform test.pathman_equal(res.v1::text, '1', 'v1 is incorrect (t4)'); + perform test.pathman_equal(res.gen::text, '2', 'gen is incorrect (t4)'); + perform test.pathman_equal(res.v2::text, 'k = 1', 'v2 is incorrect (t4)'); + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_hashjoin = off +set enable_mergejoin = off; +create table test.run_values as select generate_series(1, 10000) val; +create table test.runtime_test_1(id serial primary key, val real); +insert into test.runtime_test_1 select generate_series(1, 10000), random(); +select pathman.create_hash_partitions('test.runtime_test_1', 'id', 6); + create_hash_partitions +------------------------ + 6 +(1 row) + +create table test.category as (select id, 'cat' || id::text as name from generate_series(1, 4) id); +create table test.runtime_test_2 (id serial, category_id int not null, name text, rating real); +insert into test.runtime_test_2 (select id, (id % 6) + 1 as category_id, 'good' || id::text as name, random() as rating from generate_series(1, 100000) id); +create index on test.runtime_test_2 (category_id, rating); +select pathman.create_hash_partitions('test.runtime_test_2', 'category_id', 6); + create_hash_partitions +------------------------ + 6 +(1 row) + +create table test.vals as (select generate_series(1, 10000) as val); +create table test.runtime_test_3(val text, id serial not null); +insert into test.runtime_test_3(id, val) select * from generate_series(1, 10000) k, format('k = %s', k); +select pathman.create_hash_partitions('test.runtime_test_3', 'id', 4); + create_hash_partitions +------------------------ + 4 +(1 row) + +create index on test.runtime_test_3 (id); +create index on test.runtime_test_3_0 (id); +analyze test.run_values; +analyze test.runtime_test_1; +analyze test.runtime_test_2; +analyze test.runtime_test_3; +analyze test.runtime_test_3_0; +set pg_pathman.enable_runtimeappend = on; +set pg_pathman.enable_runtimemergeappend = on; +select test.pathman_test_1(); /* RuntimeAppend (select ... where id = (subquery)) */ + pathman_test_1 +---------------- + ok +(1 row) + +select test.pathman_test_2(); /* RuntimeAppend (select ... where id = any(subquery)) */ + pathman_test_2 +---------------- + ok +(1 row) + +select test.pathman_test_3(); /* RuntimeAppend (a join b on a.id = b.val) */ + pathman_test_3 +---------------- + ok +(1 row) + +select test.pathman_test_4(); /* RuntimeMergeAppend (lateral) */ + pathman_test_4 +---------------- + ok +(1 row) + +select test.pathman_test_5(); /* projection tests for RuntimeXXX nodes */ + pathman_test_5 +---------------- + ok +(1 row) + +DROP SCHEMA test CASCADE; +NOTICE: drop cascades to 30 other objects +DROP EXTENSION pg_pathman CASCADE; +DROP SCHEMA pathman CASCADE; diff --git a/contrib/pg_pathman/expected/rollback_on_create_partitions.out b/contrib/pg_pathman/expected/rollback_on_create_partitions.out new file mode 100644 index 0000000000..3531107db8 --- /dev/null +++ b/contrib/pg_pathman/expected/rollback_on_create_partitions.out @@ -0,0 +1,403 @@ +Parsed test spec with 1 sessions + +starting permutation: begin insert_data create_partitions show_rel rollback show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 +step rollback: ROLLBACK; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data create_partitions show_rel commit show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 +step commit: COMMIT; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions show_rel savepoint_c rollback show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step savepoint_c: SAVEPOINT c; +step rollback: ROLLBACK; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions show_rel savepoint_c commit show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step savepoint_c: SAVEPOINT c; +step commit: COMMIT; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions savepoint_c rollback_b show_rel rollback show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step savepoint_c: SAVEPOINT c; +step rollback_b: ROLLBACK TO SAVEPOINT b; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 +step rollback: ROLLBACK; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions savepoint_c rollback_b show_rel commit show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step savepoint_c: SAVEPOINT c; +step rollback_b: ROLLBACK TO SAVEPOINT b; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 +step commit: COMMIT; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions show_rel savepoint_c rollback_a show_rel rollback show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step savepoint_c: SAVEPOINT c; +step rollback_a: ROLLBACK TO SAVEPOINT a; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step rollback: ROLLBACK; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions show_rel savepoint_c rollback_a show_rel commit show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step savepoint_c: SAVEPOINT c; +step rollback_a: ROLLBACK TO SAVEPOINT a; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step commit: COMMIT; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions show_rel savepoint_c rollback_b drop_partitions show_rel rollback show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step savepoint_c: SAVEPOINT c; +step rollback_b: ROLLBACK TO SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step rollback: ROLLBACK; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions show_rel savepoint_c rollback_b drop_partitions show_rel commit show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step savepoint_c: SAVEPOINT c; +step rollback_b: ROLLBACK TO SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel +step commit: COMMIT; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions rollback_a create_partitions show_rel rollback show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step rollback_a: ROLLBACK TO SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 +step rollback: ROLLBACK; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Seq Scan on range_rel + +starting permutation: begin insert_data savepoint_a create_partitions savepoint_b drop_partitions rollback_a create_partitions show_rel commit show_rel +step begin: BEGIN; +step insert_data: INSERT INTO range_rel SELECT generate_series(1, 10000); +step savepoint_a: SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step savepoint_b: SAVEPOINT b; +step drop_partitions: SELECT drop_partitions('range_rel'); +drop_partitions + +10 +step rollback_a: ROLLBACK TO SAVEPOINT a; +step create_partitions: SELECT create_range_partitions('range_rel', 'id', 1, 1000); +create_range_partitions + +10 +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 +step commit: COMMIT; +step show_rel: EXPLAIN (COSTS OFF) SELECT * FROM range_rel; +QUERY PLAN + +Append + -> Seq Scan on range_rel_1 + -> Seq Scan on range_rel_2 + -> Seq Scan on range_rel_3 + -> Seq Scan on range_rel_4 + -> Seq Scan on range_rel_5 + -> Seq Scan on range_rel_6 + -> Seq Scan on range_rel_7 + -> Seq Scan on range_rel_8 + -> Seq Scan on range_rel_9 + -> Seq Scan on range_rel_10 diff --git a/contrib/pg_pathman/hash.sql b/contrib/pg_pathman/hash.sql index 111c3c9f9f..e4001bdceb 100644 --- a/contrib/pg_pathman/hash.sql +++ b/contrib/pg_pathman/hash.sql @@ -12,258 +12,218 @@ * Creates hash partitions for specified relation */ CREATE OR REPLACE FUNCTION @extschema@.create_hash_partitions( - relation REGCLASS - , attribute TEXT - , partitions_count INTEGER -) RETURNS INTEGER AS + parent_relid REGCLASS, + attribute TEXT, + partitions_count INTEGER, + partition_data BOOLEAN DEFAULT TRUE) +RETURNS INTEGER AS $$ DECLARE - v_relname TEXT; - v_child_relname TEXT; - v_type TEXT; + v_child_relname TEXT; + v_plain_schema TEXT; + v_plain_relname TEXT; + v_atttype REGTYPE; + v_hashfunc REGPROC; + v_init_callback REGPROCEDURE; + BEGIN - v_relname := @extschema@.validate_relname(relation); + IF partition_data = true THEN + /* Acquire data modification lock */ + PERFORM @extschema@.prevent_relation_modification(parent_relid); + ELSE + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + END IF; + + PERFORM @extschema@.validate_relname(parent_relid); attribute := lower(attribute); - PERFORM @extschema@.common_relation_checks(relation, attribute); + PERFORM @extschema@.common_relation_checks(parent_relid, attribute); - v_type := @extschema@.get_attribute_type_name(v_relname, attribute); - IF v_type::regtype != 'integer'::regtype THEN - RAISE EXCEPTION 'Attribute type must be INTEGER'; - END IF; + /* Fetch atttype and its hash function */ + v_atttype := @extschema@.get_attribute_type(parent_relid, attribute); + v_hashfunc := @extschema@.get_type_hash_func(v_atttype); + + SELECT * INTO v_plain_schema, v_plain_relname + FROM @extschema@.get_plain_schema_and_relname(parent_relid); + + /* Insert new entry to pathman config */ + INSERT INTO @extschema@.pathman_config (partrel, attname, parttype) + VALUES (parent_relid, attribute, 1); /* Create partitions and update pg_pathman configuration */ FOR partnum IN 0..partitions_count-1 LOOP - v_child_relname := @extschema@.get_schema_qualified_name(relation, '.', suffix := '_' || partnum); - EXECUTE format('CREATE TABLE %s (LIKE %s INCLUDING ALL)' - , v_child_relname - , v_relname); - - EXECUTE format('ALTER TABLE %s INHERIT %s' - , v_child_relname - , v_relname); - - EXECUTE format('ALTER TABLE %s ADD CHECK (%s %% %s = %s)' - , v_child_relname - , attribute - , partitions_count - , partnum); + v_child_relname := format('%s.%s', + quote_ident(v_plain_schema), + quote_ident(v_plain_relname || '_' || partnum)); + + EXECUTE format( + 'CREATE TABLE %1$s (LIKE %2$s INCLUDING ALL) INHERITS (%2$s) TABLESPACE %s', + v_child_relname, + parent_relid::TEXT, + @extschema@.get_rel_tablespace_name(parent_relid)); + + EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s + CHECK (@extschema@.get_hash_part_idx(%s(%s), %s) = %s)', + v_child_relname, + @extschema@.build_check_constraint_name(v_child_relname::REGCLASS, + attribute), + v_hashfunc::TEXT, + attribute, + partitions_count, + partnum); + + PERFORM @extschema@.copy_foreign_keys(parent_relid, v_child_relname::REGCLASS); + + /* Fetch init_callback from 'params' table */ + WITH stub_callback(stub) as (values (0)) + SELECT coalesce(init_callback, 0::REGPROCEDURE) + FROM stub_callback + LEFT JOIN @extschema@.pathman_config_params AS params + ON params.partrel = parent_relid + INTO v_init_callback; + + PERFORM @extschema@.invoke_on_partition_created_callback(parent_relid, + v_child_relname::REGCLASS, + v_init_callback); END LOOP; - INSERT INTO @extschema@.pathman_config (relname, attname, parttype) - VALUES (v_relname, attribute, 1); - - /* Create triggers */ - PERFORM @extschema@.create_hash_insert_trigger(v_relname, attribute, partitions_count); - /* Do not create update trigger by default */ - -- PERFORM @extschema@.create_hash_update_trigger(relation, attribute, partitions_count); /* Notify backend about changes */ - PERFORM @extschema@.on_create_partitions(relation::oid); + PERFORM @extschema@.on_create_partitions(parent_relid); /* Copy data */ - PERFORM @extschema@.partition_data(relation); + IF partition_data = true THEN + PERFORM @extschema@.set_enable_parent(parent_relid, false); + PERFORM @extschema@.partition_data(parent_relid); + ELSE + PERFORM @extschema@.set_enable_parent(parent_relid, true); + END IF; RETURN partitions_count; END -$$ LANGUAGE plpgsql; - -/* - * Creates hash trigger for specified relation - */ -CREATE OR REPLACE FUNCTION @extschema@.create_hash_insert_trigger( - IN relation REGCLASS - , IN attr TEXT - , IN partitions_count INTEGER) -RETURNS VOID AS -$$ -DECLARE - func TEXT := ' - CREATE OR REPLACE FUNCTION %s() - RETURNS TRIGGER AS $body$ - DECLARE - hash INTEGER; - BEGIN - hash := NEW.%s %% %s; - %s - RETURN NULL; - END $body$ LANGUAGE plpgsql;'; - funcname TEXT; - trigger TEXT := ' - CREATE TRIGGER %s - BEFORE INSERT ON %s - FOR EACH ROW EXECUTE PROCEDURE %s();'; - triggername TEXT; - -- fields TEXT; - -- fields_format TEXT; - insert_stmt TEXT; - relname TEXT; - schema TEXT; -BEGIN - /* drop trigger and corresponding function */ - PERFORM @extschema@.drop_hash_triggers(relation); - - SELECT * INTO schema, relname - FROM @extschema@.get_plain_schema_and_relname(relation); - - /* generate INSERT statement for trigger */ - insert_stmt = format('EXECUTE format(''INSERT INTO %s.%s SELECT $1.*'', hash) USING NEW;' - , schema, quote_ident(relname || '_%s')); - - /* format and create new trigger for relation */ - funcname := schema || '.' || quote_ident(format('%s_insert_trigger_func', relname)); - triggername := quote_ident(format('%s_%s_insert_trigger', schema, relname)); - - func := format(func, funcname, attr, partitions_count, insert_stmt); - trigger := format(trigger, triggername, relation, funcname); - EXECUTE func; - EXECUTE trigger; -END -$$ LANGUAGE plpgsql; - -/* - * Drops all partitions for specified relation - */ -CREATE OR REPLACE FUNCTION @extschema@.drop_hash_partitions( - IN relation REGCLASS - , delete_data BOOLEAN DEFAULT FALSE) -RETURNS INTEGER AS -$$ -DECLARE - v_relname TEXT; - v_rec RECORD; - v_rows INTEGER; - v_part_count INTEGER := 0; -BEGIN - v_relname := @extschema@.validate_relname(relation); - - /* Drop trigger first */ - PERFORM @extschema@.drop_hash_triggers(relation); - DELETE FROM @extschema@.pathman_config WHERE relname::regclass = relation; - - FOR v_rec in (SELECT inhrelid::regclass::text AS tbl - FROM pg_inherits WHERE inhparent = relation::oid) - LOOP - IF NOT delete_data THEN - EXECUTE format('WITH part_data AS (DELETE FROM %s RETURNING *) - INSERT INTO %s SELECT * FROM part_data' - , v_rec.tbl - , relation::text); - GET DIAGNOSTICS v_rows = ROW_COUNT; - RAISE NOTICE '% rows copied from %', v_rows, v_rec.tbl; - END IF; - EXECUTE format('DROP TABLE %s', v_rec.tbl); - v_part_count := v_part_count + 1; - END LOOP; - - /* Notify backend about changes */ - PERFORM @extschema@.on_remove_partitions(relation::oid); - - RETURN v_part_count; -END -$$ LANGUAGE plpgsql; - -/* - * Drops hash trigger - */ -CREATE OR REPLACE FUNCTION @extschema@.drop_hash_triggers(IN relation REGCLASS) -RETURNS VOID AS -$$ -DECLARE - relname TEXT; - schema TEXT; - funcname TEXT; -BEGIN - SELECT * INTO schema, relname - FROM @extschema@.get_plain_schema_and_relname(relation); - - funcname := schema || '.' || quote_ident(format('%s_insert_trigger_func', relname)); - EXECUTE format('DROP FUNCTION IF EXISTS %s() CASCADE', funcname); - funcname := schema || '.' || quote_ident(format('%s_update_trigger_func', relname)); - EXECUTE format('DROP FUNCTION IF EXISTS %s() CASCADE', funcname); -END -$$ LANGUAGE plpgsql; +$$ LANGUAGE plpgsql +SET client_min_messages = WARNING; /* * Creates an update trigger */ CREATE OR REPLACE FUNCTION @extschema@.create_hash_update_trigger( - IN relation REGCLASS) -RETURNS VOID AS + parent_relid REGCLASS) +RETURNS TEXT AS $$ DECLARE - func TEXT := ' - CREATE OR REPLACE FUNCTION %s() - RETURNS TRIGGER AS - $body$ - DECLARE old_hash INTEGER; new_hash INTEGER; q TEXT; - BEGIN - old_hash := OLD.%2$s %% %3$s; - new_hash := NEW.%2$s %% %3$s; - IF old_hash = new_hash THEN RETURN NEW; END IF; - q := format(''DELETE FROM %8$s WHERE %4$s'', old_hash); - EXECUTE q USING %5$s; - q := format(''INSERT INTO %8$s VALUES (%6$s)'', new_hash); - EXECUTE q USING %7$s; - RETURN NULL; - END $body$ LANGUAGE plpgsql'; - trigger TEXT := ' - CREATE TRIGGER %s - BEFORE UPDATE ON %s - FOR EACH ROW EXECUTE PROCEDURE %s()'; - att_names TEXT; - old_fields TEXT; - new_fields TEXT; - att_val_fmt TEXT; - att_fmt TEXT; - relid INTEGER; - partitions_count INTEGER; - attr TEXT; - plain_schema TEXT; - plain_relname TEXT; - funcname TEXT; - triggername TEXT; - child_relname_format TEXT; + func TEXT := 'CREATE OR REPLACE FUNCTION %1$s() + RETURNS TRIGGER AS + $body$ + DECLARE + old_idx INTEGER; /* partition indices */ + new_idx INTEGER; + + BEGIN + old_idx := @extschema@.get_hash_part_idx(%9$s(OLD.%2$s), %3$s); + new_idx := @extschema@.get_hash_part_idx(%9$s(NEW.%2$s), %3$s); + + IF old_idx = new_idx THEN + RETURN NEW; + END IF; + + EXECUTE format(''DELETE FROM %8$s WHERE %4$s'', old_idx) + USING %5$s; + + EXECUTE format(''INSERT INTO %8$s VALUES (%6$s)'', new_idx) + USING %7$s; + + RETURN NULL; + END $body$ + LANGUAGE plpgsql'; + + trigger TEXT := 'CREATE TRIGGER %s + BEFORE UPDATE ON %s + FOR EACH ROW EXECUTE PROCEDURE %s()'; + + att_names TEXT; + old_fields TEXT; + new_fields TEXT; + att_val_fmt TEXT; + att_fmt TEXT; + attr TEXT; + plain_schema TEXT; + plain_relname TEXT; + child_relname_format TEXT; + funcname TEXT; + triggername TEXT; + atttype REGTYPE; + partitions_count INTEGER; + BEGIN - relation := @extschema@.validate_relname(relation); + attr := attname FROM @extschema@.pathman_config WHERE partrel = parent_relid; - SELECT * INTO plain_schema, plain_relname - FROM @extschema@.get_plain_schema_and_relname(relation); + IF attr IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; - relid := relation::regclass::oid; SELECT string_agg(attname, ', '), string_agg('OLD.' || attname, ', '), string_agg('NEW.' || attname, ', '), - string_agg('CASE WHEN NOT $' || attnum || ' IS NULL THEN ' || attname || ' = $' || attnum || - ' ELSE ' || attname || ' IS NULL END', ' AND '), + string_agg('CASE WHEN NOT $' || attnum || ' IS NULL THEN ' || + attname || ' = $' || attnum || ' ' || + 'ELSE ' || + attname || ' IS NULL END', + ' AND '), string_agg('$' || attnum, ', ') - FROM pg_attribute - WHERE attrelid=relid AND attnum>0 + FROM pg_catalog.pg_attribute + WHERE attrelid = parent_relid AND attnum > 0 INTO att_names, old_fields, new_fields, att_val_fmt, att_fmt; - attr := attname FROM @extschema@.pathman_config WHERE relname::regclass = relation; - partitions_count := COUNT(*) FROM pg_inherits WHERE inhparent = relation::oid; + partitions_count := COUNT(*) FROM pg_catalog.pg_inherits + WHERE inhparent = parent_relid::oid; + + /* Build trigger & trigger function's names */ + funcname := @extschema@.build_update_trigger_func_name(parent_relid); + triggername := @extschema@.build_update_trigger_name(parent_relid); + + /* Build partition name template */ + SELECT * INTO plain_schema, plain_relname + FROM @extschema@.get_plain_schema_and_relname(parent_relid); + + child_relname_format := quote_ident(plain_schema) || '.' || + quote_ident(plain_relname || '_%s'); - /* Function name, trigger name and child relname template */ - funcname := plain_schema || '.' || quote_ident(format('%s_update_trigger_func', plain_relname)); - child_relname_format := plain_schema || '.' || quote_ident(plain_relname || '_%s'); - triggername := quote_ident(format('%s_%s_update_trigger', plain_schema, plain_relname)); + /* Fetch base hash function for atttype */ + atttype := @extschema@.get_attribute_type(parent_relid, attr); /* Format function definition and execute it */ - func := format(func, funcname, attr, partitions_count, att_val_fmt, - old_fields, att_fmt, new_fields, child_relname_format); - EXECUTE func; + EXECUTE format(func, funcname, attr, partitions_count, att_val_fmt, + old_fields, att_fmt, new_fields, child_relname_format, + @extschema@.get_type_hash_func(atttype)::TEXT); - /* Create triggers on child relations */ + /* Create trigger on every partition */ FOR num IN 0..partitions_count-1 LOOP - EXECUTE format(trigger - , triggername - , format(child_relname_format, num) - , funcname); + EXECUTE format(trigger, + triggername, + format(child_relname_format, num), + funcname); END LOOP; + + return funcname; END $$ LANGUAGE plpgsql; + +/* + * Returns hash function OID for specified type + */ +CREATE OR REPLACE FUNCTION @extschema@.get_type_hash_func(REGTYPE) +RETURNS REGPROC AS 'pg_pathman', 'get_type_hash_func' +LANGUAGE C STRICT; + +/* + * Calculates hash for integer value + */ +CREATE OR REPLACE FUNCTION @extschema@.get_hash_part_idx(INTEGER, INTEGER) +RETURNS INTEGER AS 'pg_pathman', 'get_hash_part_idx' +LANGUAGE C STRICT; diff --git a/contrib/pg_pathman/init.c b/contrib/pg_pathman/init.c deleted file mode 100644 index 264acf4fc1..0000000000 --- a/contrib/pg_pathman/init.c +++ /dev/null @@ -1,595 +0,0 @@ -/* ------------------------------------------------------------------------ - * - * init.c - * Initialization functions - * - * Copyright (c) 2015-2016, Postgres Professional - * - * ------------------------------------------------------------------------ - */ -#include "pathman.h" -#include "miscadmin.h" -#include "executor/spi.h" -#include "catalog/pg_type.h" -#include "catalog/pg_class.h" -#include "catalog/pg_constraint.h" -#include "catalog/pg_operator.h" -#include "access/htup_details.h" -#include "utils/syscache.h" -#include "utils/builtins.h" -#include "utils/typcache.h" -#include "utils/lsyscache.h" -#include "utils/bytea.h" -#include "utils/snapmgr.h" -#include "optimizer/clauses.h" - - -HTAB *relations = NULL; -HTAB *range_restrictions = NULL; -bool initialization_needed = true; - -static FmgrInfo *qsort_type_cmp_func; -static bool globalByVal; - -static bool validate_range_constraint(Expr *, PartRelationInfo *, Datum *, Datum *); -static bool validate_hash_constraint(Expr *expr, PartRelationInfo *prel, int *hash); -static bool read_opexpr_const(OpExpr *opexpr, int varattno, Datum *val); -static int cmp_range_entries(const void *p1, const void *p2); - -Size -pathman_memsize() -{ - Size size; - - size = get_dsm_shared_size() + MAXALIGN(sizeof(PathmanState)); - return size; -} - -void -init_shmem_config() -{ - bool found; - - /* Check if module was initialized in postmaster */ - pmstate = ShmemInitStruct("pathman state", sizeof(PathmanState), &found); - if (!found) - { - /* - * Initialize locks in postmaster - */ - if (!IsUnderPostmaster) - { - /* Initialize locks */ - pmstate->load_config_lock = LWLockAssign(); - pmstate->dsm_init_lock = LWLockAssign(); - pmstate->edit_partitions_lock = LWLockAssign(); - } - } - - create_relations_hashtable(); - create_range_restrictions_hashtable(); -} - -/* - * Initialize hashtables - */ -void -load_config(void) -{ - bool new_segment_created; - Oid *databases; - - initialization_needed = false; - - LWLockAcquire(pmstate->dsm_init_lock, LW_EXCLUSIVE); - new_segment_created = init_dsm_segment(INITIAL_BLOCKS_COUNT, 32); - - /* If dsm segment just created */ - if (new_segment_created) - { - /* - * Allocate databases array and put current database - * oid into it. This array contains databases oids - * that have already been cached (to prevent repeat caching) - */ - if (&pmstate->databases.length > 0) - free_dsm_array(&pmstate->databases); - alloc_dsm_array(&pmstate->databases, sizeof(Oid), 1); - databases = (Oid *) dsm_array_get_pointer(&pmstate->databases); - databases[0] = MyDatabaseId; - } - else - { - int databases_count = pmstate->databases.length; - int i; - - /* Check if we already cached config for current database */ - databases = (Oid *) dsm_array_get_pointer(&pmstate->databases); - for(i=0; idsm_init_lock); - return; - } - - /* Put current database oid to databases list */ - resize_dsm_array(&pmstate->databases, sizeof(Oid), databases_count + 1); - databases = (Oid *) dsm_array_get_pointer(&pmstate->databases); - databases[databases_count] = MyDatabaseId; - } - - /* Load cache */ - LWLockAcquire(pmstate->load_config_lock, LW_EXCLUSIVE); - load_relations_hashtable(new_segment_created); - LWLockRelease(pmstate->load_config_lock); - LWLockRelease(pmstate->dsm_init_lock); -} - -/* - * Returns extension schema name or NULL. Caller is responsible for freeing - * the memory. - */ -char * -get_extension_schema() -{ - int ret; - bool isnull; - - ret = SPI_exec("SELECT extnamespace::regnamespace::text FROM pg_extension WHERE extname = 'pg_pathman'", 0); - if (ret > 0 && SPI_tuptable != NULL && SPI_processed > 0) - { - TupleDesc tupdesc = SPI_tuptable->tupdesc; - SPITupleTable *tuptable = SPI_tuptable; - HeapTuple tuple = tuptable->vals[0]; - Datum datum = SPI_getbinval(tuple, tupdesc, 1, &isnull); - - if (isnull) - return NULL; - - return TextDatumGetCString(datum); - } - return NULL; -} - -/* - * Loads partitioned tables structure to hashtable - */ -void -load_relations_hashtable(bool reinitialize) -{ - int ret, - i, - proc; - bool isnull; - List *part_oids = NIL; - ListCell *lc; - char *schema; - PartRelationInfo *prel; - char sql[] = "SELECT pg_class.oid, pg_attribute.attnum, cfg.parttype, pg_attribute.atttypid " - "FROM %s.pathman_config as cfg " - "JOIN pg_class ON pg_class.oid = cfg.relname::regclass::oid " - "JOIN pg_attribute ON pg_attribute.attname = lower(cfg.attname) " - "AND attrelid = pg_class.oid"; - char *query; - - SPI_connect(); - schema = get_extension_schema(); - - /* If extension isn't exist then just quit */ - if (!schema) - { - SPI_finish(); - return; - } - - /* Put schema name to the query */ - query = psprintf(sql, schema); - ret = SPI_exec(query, 0); - proc = SPI_processed; - - if (ret > 0 && SPI_tuptable != NULL) - { - TupleDesc tupdesc = SPI_tuptable->tupdesc; - SPITupleTable *tuptable = SPI_tuptable; - - for (i=0; ivals[i]; - int oid = DatumGetObjectId(SPI_getbinval(tuple, tupdesc, 1, &isnull)); - - key.dbid = MyDatabaseId; - key.relid = oid; - prel = (PartRelationInfo*) - hash_search(relations, (const void *) &key, HASH_ENTER, NULL); - - prel->attnum = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 2, &isnull)); - prel->parttype = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 3, &isnull)); - prel->atttype = DatumGetObjectId(SPI_getbinval(tuple, tupdesc, 4, &isnull)); - - part_oids = lappend_int(part_oids, oid); - } - } - pfree(query); - - /* Load children information */ - foreach(lc, part_oids) - { - Oid oid = (int) lfirst_int(lc); - - prel = get_pathman_relation_info(oid, NULL); - switch(prel->parttype) - { - case PT_RANGE: - if (reinitialize && prel->children.length > 0) - { - RangeRelation *rangerel = get_pathman_range_relation(oid, NULL); - free_dsm_array(&prel->children); - free_dsm_array(&rangerel->ranges); - prel->children_count = 0; - } - load_check_constraints(oid, GetCatalogSnapshot(oid)); - break; - case PT_HASH: - if (reinitialize && prel->children.length > 0) - { - free_dsm_array(&prel->children); - prel->children_count = 0; - } - load_check_constraints(oid, GetCatalogSnapshot(oid)); - break; - } - } - SPI_finish(); -} - -void -create_relations_hashtable() -{ - HASHCTL ctl; - - memset(&ctl, 0, sizeof(ctl)); - ctl.keysize = sizeof(RelationKey); - ctl.entrysize = sizeof(PartRelationInfo); - - /* Already exists, recreate */ - if (relations != NULL) - hash_destroy(relations); - - relations = ShmemInitHash("Partitioning relation info", 1024, 1024, &ctl, HASH_ELEM | HASH_BLOBS); -} - -/* - * Load and validate CHECK constraints - */ -void -load_check_constraints(Oid parent_oid, Snapshot snapshot) -{ - PartRelationInfo *prel = NULL; - RangeRelation *rangerel = NULL; - SPIPlanPtr plan; - bool found; - int ret, - i, - proc; - Datum vals[1]; - Oid oids[1] = {INT4OID}; - bool nulls[1] = {false}; - - vals[0] = Int32GetDatum(parent_oid); - prel = get_pathman_relation_info(parent_oid, NULL); - - /* Skip if already loaded */ - if (prel->children.length > 0) - return; - - plan = SPI_prepare("select pg_constraint.* " - "from pg_constraint " - "join pg_inherits on inhrelid = conrelid " - "where inhparent = $1 and contype='c';", - 1, oids); - ret = SPI_execute_snapshot(plan, vals, nulls, - snapshot, InvalidSnapshot, true, false, 0); - - proc = SPI_processed; - - if (ret > 0 && SPI_tuptable != NULL) - { - SPITupleTable *tuptable = SPI_tuptable; - Oid *children; - RangeEntry *ranges = NULL; - Datum min; - Datum max; - int hash; - - alloc_dsm_array(&prel->children, sizeof(Oid), proc); - children = (Oid *) dsm_array_get_pointer(&prel->children); - - if (prel->parttype == PT_RANGE) - { - TypeCacheEntry *tce; - RelationKey key; - key.dbid = MyDatabaseId; - key.relid = parent_oid; - - rangerel = (RangeRelation *) - hash_search(range_restrictions, (void *) &key, HASH_ENTER, &found); - - alloc_dsm_array(&rangerel->ranges, sizeof(RangeEntry), proc); - ranges = (RangeEntry *) dsm_array_get_pointer(&rangerel->ranges); - - tce = lookup_type_cache(prel->atttype, 0); - rangerel->by_val = tce->typbyval; - } - - for (i=0; ivals[i]; - bool isnull; - Datum val; - char *conbin; - Expr *expr; - - Form_pg_constraint con; - - con = (Form_pg_constraint) GETSTRUCT(tuple); - - val = SysCacheGetAttr(CONSTROID, tuple, Anum_pg_constraint_conbin, - &isnull); - if (isnull) - elog(ERROR, "null conbin for constraint %u", - HeapTupleGetOid(tuple)); - conbin = TextDatumGetCString(val); - expr = (Expr *) stringToNode(conbin); - - switch(prel->parttype) - { - case PT_RANGE: - if (!validate_range_constraint(expr, prel, &min, &max)) - { - elog(WARNING, "Range constraint for relation %u MUST have exact format: " - "VARIABLE >= CONST AND VARIABLE < CONST. Skipping...", - (Oid) con->conrelid); - continue; - } - - /* If datum is referenced by val then just assign */ - if (rangerel->by_val) - { - re.min = min; - re.max = max; - } - /* else copy the memory by pointer */ - else - { - memcpy(&re.min, DatumGetPointer(min), sizeof(re.min)); - memcpy(&re.max, DatumGetPointer(max), sizeof(re.max)); - } - re.child_oid = con->conrelid; - ranges[i] = re; - break; - - case PT_HASH: - if (!validate_hash_constraint(expr, prel, &hash)) - { - elog(WARNING, "Hash constraint for relation %u MUST have exact format: " - "VARIABLE %% CONST = CONST. Skipping...", - (Oid) con->conrelid); - continue; - } - children[hash] = con->conrelid; - } - } - prel->children_count = proc; - - if (prel->parttype == PT_RANGE) - { - TypeCacheEntry *tce; - bool byVal = rangerel->by_val; - - /* Sort ascending */ - tce = lookup_type_cache(prel->atttype, TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO); - qsort_type_cmp_func = &tce->cmp_proc_finfo; - globalByVal = byVal; - qsort(ranges, proc, sizeof(RangeEntry), cmp_range_entries); - - /* Copy oids to prel */ - for(i=0; i < proc; i++) - children[i] = ranges[i].child_oid; - - /* Check if some ranges overlap */ - for(i=0; i < proc-1; i++) - { - Datum cur_upper = PATHMAN_GET_DATUM(ranges[i].max, byVal); - Datum next_lower = PATHMAN_GET_DATUM(ranges[i+1].min, byVal); - bool overlap = DatumGetInt32(FunctionCall2(qsort_type_cmp_func, next_lower, cur_upper)) < 0; - - if (overlap) - { - RelationKey key; - key.dbid = MyDatabaseId; - key.relid = parent_oid; - - elog(WARNING, "Partitions %u and %u overlap. Disabling pathman for relation %u...", - ranges[i].child_oid, ranges[i+1].child_oid, parent_oid); - hash_search(relations, (const void *) &key, HASH_REMOVE, &found); - } - } - } - } -} - - -/* qsort comparison function for oids */ -static int -cmp_range_entries(const void *p1, const void *p2) -{ - const RangeEntry *v1 = (const RangeEntry *) p1; - const RangeEntry *v2 = (const RangeEntry *) p2; - - return FunctionCall2(qsort_type_cmp_func, - PATHMAN_GET_DATUM(v1->min, globalByVal), - PATHMAN_GET_DATUM(v2->min, globalByVal)); -} - -/* - * Validates range constraint. It MUST have the exact format: - * VARIABLE >= CONST AND VARIABLE < CONST - */ -static bool -validate_range_constraint(Expr *expr, PartRelationInfo *prel, Datum *min, Datum *max) -{ - TypeCacheEntry *tce; - BoolExpr *boolexpr = (BoolExpr *) expr; - OpExpr *opexpr; - - /* it should be an AND operator on top */ - if (!and_clause((Node *) expr)) - return false; - - tce = lookup_type_cache(prel->atttype, TYPECACHE_BTREE_OPFAMILY); - - /* check that left operand is >= operator */ - opexpr = (OpExpr *) linitial(boolexpr->args); - if (get_op_opfamily_strategy(opexpr->opno, tce->btree_opf) == BTGreaterEqualStrategyNumber) - { - if (!read_opexpr_const(opexpr, prel->attnum, min)) - return false; - } - else - return false; - - /* check that right operand is < operator */ - opexpr = (OpExpr *) lsecond(boolexpr->args); - if (get_op_opfamily_strategy(opexpr->opno, tce->btree_opf) == BTLessStrategyNumber) - { - if (!read_opexpr_const(opexpr, prel->attnum, max)) - return false; - } - else - return false; - - return true; -} - -/* - * Reads const value from expressions of kind: VAR >= CONST or VAR < CONST - */ -static bool -read_opexpr_const(OpExpr *opexpr, int varattno, Datum *val) -{ - Node *left = linitial(opexpr->args); - Node *right = lsecond(opexpr->args); - - if ( !IsA(left, Var) || !IsA(right, Const) ) - return false; - if ( ((Var*) left)->varattno != varattno ) - return false; - *val = ((Const*) right)->constvalue; - - return true; -} - -/* - * Validate hash constraint. It MUST have the exact format - * VARIABLE % CONST = CONST - */ -static bool -validate_hash_constraint(Expr *expr, PartRelationInfo *prel, int *hash) -{ - OpExpr *eqexpr; - OpExpr *modexpr; - TypeCacheEntry *tce; - - if (!IsA(expr, OpExpr)) - return false; - eqexpr = (OpExpr *) expr; - - /* Is this an equality operator? */ - tce = lookup_type_cache(prel->atttype, TYPECACHE_BTREE_OPFAMILY); - if (get_op_opfamily_strategy(eqexpr->opno, tce->btree_opf) != BTEqualStrategyNumber) - return false; - - if (!IsA(linitial(eqexpr->args), OpExpr)) - return false; - - /* Is this a modulus operator? */ - modexpr = (OpExpr *) linitial(eqexpr->args); - if (modexpr->opno != 530 && modexpr->opno != 439 && modexpr->opno && modexpr->opno != 529) - return false; - - if (list_length(modexpr->args) == 2) - { - Node *left = linitial(modexpr->args); - Node *right = lsecond(modexpr->args); - Const *mod_result; - - if ( !IsA(left, Var) || !IsA(right, Const) ) - return false; - if ( ((Var*) left)->varattno != prel->attnum ) - return false; - if (DatumGetInt32(((Const*) right)->constvalue) != prel->children.length) - return false; - - if ( !IsA(lsecond(eqexpr->args), Const) ) - return false; - - mod_result = lsecond(eqexpr->args); - *hash = DatumGetInt32(mod_result->constvalue); - return true; - } - - return false; -} - -/* - * Create range restrictions table - */ -void -create_range_restrictions_hashtable() -{ - HASHCTL ctl; - - memset(&ctl, 0, sizeof(ctl)); - ctl.keysize = sizeof(RelationKey); - ctl.entrysize = sizeof(RangeRelation); - range_restrictions = ShmemInitHash("pg_pathman range restrictions", - 1024, 1024, &ctl, HASH_ELEM | HASH_BLOBS); -} - -/* - * Remove partitions - */ -void -remove_relation_info(Oid relid) -{ - PartRelationInfo *prel; - RangeRelation *rangerel; - RelationKey key; - - key.dbid = MyDatabaseId; - key.relid = relid; - - prel = get_pathman_relation_info(relid, NULL); - - /* If there is nothing to remove then just return */ - if (!prel) - return; - - /* Remove children relations */ - switch (prel->parttype) - { - case PT_HASH: - free_dsm_array(&prel->children); - break; - case PT_RANGE: - rangerel = get_pathman_range_relation(relid, NULL); - free_dsm_array(&rangerel->ranges); - free_dsm_array(&prel->children); - hash_search(range_restrictions, (const void *) &key, HASH_REMOVE, NULL); - break; - } - prel->children_count = 0; - hash_search(relations, (const void *) &key, HASH_REMOVE, 0); -} diff --git a/contrib/pg_pathman/init.sql b/contrib/pg_pathman/init.sql index 56c591b6e0..4d56242bae 100644 --- a/contrib/pg_pathman/init.sql +++ b/contrib/pg_pathman/init.sql @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * init.sql - * Creates config table and provides common utility functions + * Creates config table and provides common utility functions * * Copyright (c) 2015-2016, Postgres Professional * @@ -10,201 +10,352 @@ /* * Pathman config - * relname - schema qualified relation name - * attname - partitioning key - * parttype - partitioning type: - * 1 - HASH - * 2 - RANGE - * range_interval - base interval for RANGE partitioning in string representation + * partrel - regclass (relation type, stored as Oid) + * attname - partitioning key + * parttype - partitioning type: + * 1 - HASH + * 2 - RANGE + * range_interval - base interval for RANGE partitioning as string */ CREATE TABLE IF NOT EXISTS @extschema@.pathman_config ( - id SERIAL PRIMARY KEY, - relname VARCHAR(127), - attname VARCHAR(127), - parttype INTEGER, - range_interval TEXT + partrel REGCLASS NOT NULL PRIMARY KEY, + attname TEXT NOT NULL, + parttype INTEGER NOT NULL, + range_interval TEXT, + + CHECK (parttype IN (1, 2)) /* check for allowed part types */ +); + +/* + * Optional parameters for partitioned tables. + * partrel - regclass (relation type, stored as Oid) + * enable_parent - add parent table to plan + * auto - enable automatic partition creation + * init_callback - cb to be executed on partition creation + */ +CREATE TABLE IF NOT EXISTS @extschema@.pathman_config_params ( + partrel REGCLASS NOT NULL PRIMARY KEY, + enable_parent BOOLEAN NOT NULL DEFAULT TRUE, + auto BOOLEAN NOT NULL DEFAULT TRUE, + init_callback REGPROCEDURE NOT NULL DEFAULT 0 ); +CREATE UNIQUE INDEX i_pathman_config_params +ON @extschema@.pathman_config_params(partrel); + +/* + * Invalidate relcache every time someone changes parameters config. + */ +CREATE OR REPLACE FUNCTION @extschema@.pathman_config_params_trigger_func() +RETURNS TRIGGER AS +$$ +BEGIN + IF TG_OP IN ('INSERT', 'UPDATE') THEN + PERFORM @extschema@.invalidate_relcache(NEW.partrel); + END IF; + + IF TG_OP IN ('UPDATE', 'DELETE') THEN + PERFORM @extschema@.invalidate_relcache(OLD.partrel); + END IF; + + IF TG_OP = 'DELETE' THEN + RETURN OLD; + ELSE + RETURN NEW; + END IF; +END +$$ +LANGUAGE plpgsql; + +CREATE TRIGGER pathman_config_params_trigger +BEFORE INSERT OR UPDATE OR DELETE ON @extschema@.pathman_config_params +FOR EACH ROW EXECUTE PROCEDURE @extschema@.pathman_config_params_trigger_func(); + +/* + * Enable dump of config tables with pg_dump. + */ SELECT pg_catalog.pg_extension_config_dump('@extschema@.pathman_config', ''); +SELECT pg_catalog.pg_extension_config_dump('@extschema@.pathman_config_params', ''); -CREATE OR REPLACE FUNCTION @extschema@.on_create_partitions(relid OID) -RETURNS VOID AS 'pg_pathman', 'on_partitions_created' LANGUAGE C STRICT; -CREATE OR REPLACE FUNCTION @extschema@.on_update_partitions(relid OID) -RETURNS VOID AS 'pg_pathman', 'on_partitions_updated' LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION @extschema@.partitions_count(relation REGCLASS) +RETURNS INT AS +$$ +BEGIN + RETURN count(*) FROM pg_inherits WHERE inhparent = relation; +END +$$ +LANGUAGE plpgsql STRICT; -CREATE OR REPLACE FUNCTION @extschema@.on_remove_partitions(relid OID) -RETURNS VOID AS 'pg_pathman', 'on_partitions_removed' LANGUAGE C STRICT; +/* + * Add a row describing the optional parameter to pathman_config_params. + */ +CREATE OR REPLACE FUNCTION @extschema@.pathman_set_param( + relation REGCLASS, + param TEXT, + value ANYELEMENT) +RETURNS VOID AS +$$ +BEGIN + EXECUTE format('INSERT INTO @extschema@.pathman_config_params + (partrel, %1$s) VALUES ($1, $2) + ON CONFLICT (partrel) DO UPDATE SET %1$s = $2', param) + USING relation, value; +END +$$ +LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION @extschema@.find_or_create_range_partition(relid OID, value ANYELEMENT) -RETURNS OID AS 'pg_pathman', 'find_or_create_range_partition' LANGUAGE C STRICT; +/* + * Include\exclude parent relation in query plan. + */ +CREATE OR REPLACE FUNCTION @extschema@.set_enable_parent( + relation REGCLASS, + value BOOLEAN) +RETURNS VOID AS +$$ +BEGIN + PERFORM @extschema@.pathman_set_param(relation, 'enable_parent', value); +END +$$ +LANGUAGE plpgsql STRICT; +/* + * Enable\disable automatic partition creation. + */ +CREATE OR REPLACE FUNCTION @extschema@.set_auto( + relation REGCLASS, + value BOOLEAN) +RETURNS VOID AS +$$ +BEGIN + PERFORM @extschema@.pathman_set_param(relation, 'auto', value); +END +$$ +LANGUAGE plpgsql STRICT; /* - * Returns min and max values for specified RANGE partition. + * Set partition creation callback */ -CREATE OR REPLACE FUNCTION @extschema@.get_partition_range( - parent_relid OID, partition_relid OID, dummy ANYELEMENT) -RETURNS ANYARRAY AS 'pg_pathman', 'get_partition_range' LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION @extschema@.set_init_callback( + relation REGCLASS, + callback REGPROC DEFAULT 0) +RETURNS VOID AS +$$ +BEGIN + PERFORM @extschema@.validate_on_partition_created_callback(callback); + PERFORM @extschema@.pathman_set_param(relation, 'init_callback', callback); +END +$$ +LANGUAGE plpgsql; +/* + * Show all existing parents and partitions. + */ +CREATE OR REPLACE FUNCTION @extschema@.show_partition_list() +RETURNS TABLE ( + parent REGCLASS, + partition REGCLASS, + parttype INT4, + partattr TEXT, + range_min TEXT, + range_max TEXT) +AS 'pg_pathman', 'show_partition_list_internal' LANGUAGE C STRICT; /* - * Returns N-th range (in form of array) + * View for show_partition_list(). */ -CREATE OR REPLACE FUNCTION @extschema@.get_range_by_idx( - parent_relid OID, idx INTEGER, dummy ANYELEMENT) -RETURNS ANYARRAY AS 'pg_pathman', 'get_range_by_idx' LANGUAGE C STRICT; +CREATE OR REPLACE VIEW @extschema@.pathman_partition_list +AS SELECT * FROM @extschema@.show_partition_list(); /* - * Returns min value of the first range for relation + * Show all existing concurrent partitioning tasks. */ -CREATE OR REPLACE FUNCTION @extschema@.get_min_range_value( - parent_relid OID, dummy ANYELEMENT) -RETURNS ANYELEMENT AS 'pg_pathman', 'get_min_range_value' LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION @extschema@.show_concurrent_part_tasks() +RETURNS TABLE ( + userid REGROLE, + pid INT, + dbid OID, + relid REGCLASS, + processed INT, + status TEXT) +AS 'pg_pathman', 'show_concurrent_part_tasks_internal' LANGUAGE C STRICT; /* - * Returns max value of the last range for relation + * View for show_concurrent_part_tasks(). */ -CREATE OR REPLACE FUNCTION @extschema@.get_max_range_value( - parent_relid OID, dummy ANYELEMENT) -RETURNS ANYELEMENT AS 'pg_pathman', 'get_max_range_value' LANGUAGE C STRICT; +CREATE OR REPLACE VIEW @extschema@.pathman_concurrent_part_tasks +AS SELECT * FROM @extschema@.show_concurrent_part_tasks(); /* - * Checks if range overlaps with existing partitions. - * Returns TRUE if overlaps and FALSE otherwise. + * Partition table using ConcurrentPartWorker. */ -CREATE OR REPLACE FUNCTION @extschema@.check_overlap( - parent_relid OID, range_min ANYELEMENT, range_max ANYELEMENT) -RETURNS BOOLEAN AS 'pg_pathman', 'check_overlap' LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION @extschema@.partition_table_concurrently(relation regclass) +RETURNS VOID AS 'pg_pathman', 'partition_table_concurrently' LANGUAGE C STRICT; /* - * Copy rows to partitions + * Stop concurrent partitioning task. */ -CREATE OR REPLACE FUNCTION @extschema@.partition_data( - p_parent regclass - , p_invalidate_cache_on_error BOOLEAN DEFAULT FALSE - , OUT p_total BIGINT) +CREATE OR REPLACE FUNCTION @extschema@.stop_concurrent_part_task(relation regclass) +RETURNS BOOL AS 'pg_pathman', 'stop_concurrent_part_task' LANGUAGE C STRICT; + + +/* + * Copy rows to partitions concurrently. + */ +CREATE OR REPLACE FUNCTION @extschema@._partition_data_concurrent( + p_relation REGCLASS, + p_min ANYELEMENT DEFAULT NULL::text, + p_max ANYELEMENT DEFAULT NULL::text, + p_limit INT DEFAULT NULL, + OUT p_total BIGINT) AS $$ DECLARE - relname TEXT; - rec RECORD; - cnt BIGINT := 0; + v_attr TEXT; + v_limit_clause TEXT := ''; + v_where_clause TEXT := ''; + ctids TID[]; + BEGIN - relname := @extschema@.validate_relname(p_parent); + SELECT attname INTO v_attr + FROM @extschema@.pathman_config WHERE partrel = p_relation; p_total := 0; - /* Create partitions and copy rest of the data */ + /* Format LIMIT clause if needed */ + IF NOT p_limit IS NULL THEN + v_limit_clause := format('LIMIT %s', p_limit); + END IF; + + /* Format WHERE clause if needed */ + IF NOT p_min IS NULL THEN + v_where_clause := format('%1$s >= $1', v_attr); + END IF; + + IF NOT p_max IS NULL THEN + IF NOT p_min IS NULL THEN + v_where_clause := v_where_clause || ' AND '; + END IF; + v_where_clause := v_where_clause || format('%1$s < $2', v_attr); + END IF; + + IF v_where_clause != '' THEN + v_where_clause := 'WHERE ' || v_where_clause; + END IF; + + /* Lock rows and copy data */ RAISE NOTICE 'Copying data to partitions...'; + EXECUTE format('SELECT array(SELECT ctid FROM ONLY %1$s %2$s %3$s FOR UPDATE NOWAIT)', + p_relation, v_where_clause, v_limit_clause) + USING p_min, p_max + INTO ctids; + EXECUTE format(' - WITH part_data AS ( - DELETE FROM ONLY %s RETURNING *) - INSERT INTO %s SELECT * FROM part_data' - , relname - , relname); + WITH data AS ( + DELETE FROM ONLY %1$s WHERE ctid = ANY($1) RETURNING *) + INSERT INTO %1$s SELECT * FROM data', + p_relation) + USING ctids; + + /* Get number of inserted rows */ GET DIAGNOSTICS p_total = ROW_COUNT; RETURN; - --- EXCEPTION WHEN others THEN --- PERFORM on_remove_partitions(p_parent::regclass::integer); --- RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; END $$ -LANGUAGE plpgsql; - +LANGUAGE plpgsql +SET pg_pathman.enable_partitionfilter = on; /* ensures that PartitionFilter is ON */ /* - * Disable pathman partitioning for specified relation + * Old school way to distribute rows to partitions. */ -CREATE OR REPLACE FUNCTION @extschema@.disable_partitioning(IN relation TEXT) -RETURNS VOID AS +CREATE OR REPLACE FUNCTION @extschema@.partition_data( + parent_relid REGCLASS, + OUT p_total BIGINT) +AS $$ DECLARE - parttype INTEGER; + relname TEXT; + rec RECORD; + cnt BIGINT := 0; + BEGIN - relation := @extschema@.validate_relname(relation); - parttype := parttype FROM pathman_config WHERE relname = relation; - - DELETE FROM @extschema@.pathman_config WHERE relname = relation; - IF parttype = 1 THEN - PERFORM @extschema@.drop_hash_triggers(relation); - ELSIF parttype = 2 THEN - PERFORM @extschema@.drop_range_triggers(relation); - END IF; + p_total := 0; - /* Notify backend about changes */ - PERFORM on_remove_partitions(relation::regclass::integer); + /* Create partitions and copy rest of the data */ + EXECUTE format('WITH part_data AS (DELETE FROM ONLY %1$s RETURNING *) + INSERT INTO %1$s SELECT * FROM part_data', + parent_relid::TEXT); + + /* Get number of inserted rows */ + GET DIAGNOSTICS p_total = ROW_COUNT; + RETURN; END $$ -LANGUAGE plpgsql; - +LANGUAGE plpgsql STRICT +SET pg_pathman.enable_partitionfilter = on; /* ensures that PartitionFilter is ON */ /* - * Returns attribute type name for relation + * Disable pathman partitioning for specified relation. */ -CREATE OR REPLACE FUNCTION @extschema@.get_attribute_type_name( - p_relation REGCLASS - , p_attname TEXT - , OUT p_atttype TEXT) -RETURNS TEXT AS +CREATE OR REPLACE FUNCTION @extschema@.disable_pathman_for( + parent_relid REGCLASS) +RETURNS VOID AS $$ BEGIN - SELECT typname::TEXT INTO p_atttype - FROM pg_type JOIN pg_attribute on atttypid = "oid" - WHERE attrelid = p_relation::oid and attname = lower(p_attname); -END -$$ -LANGUAGE plpgsql; + PERFORM @extschema@.validate_relname(parent_relid); + DELETE FROM @extschema@.pathman_config WHERE partrel = parent_relid; + PERFORM @extschema@.drop_triggers(parent_relid); -/* - * Checks if attribute is nullable - */ -CREATE OR REPLACE FUNCTION @extschema@.is_attribute_nullable( - p_relation REGCLASS - , p_attname TEXT - , OUT p_nullable BOOLEAN) -RETURNS BOOLEAN AS -$$ -BEGIN - SELECT NOT attnotnull INTO p_nullable - FROM pg_type JOIN pg_attribute on atttypid = "oid" - WHERE attrelid = p_relation::oid and attname = lower(p_attname); + /* Notify backend about changes */ + PERFORM @extschema@.on_remove_partitions(parent_relid); END $$ -LANGUAGE plpgsql; - +LANGUAGE plpgsql STRICT; /* - * Aggregates several common relation checks before partitioning. Suitable for every partitioning type. + * Aggregates several common relation checks before partitioning. + * Suitable for every partitioning type. */ CREATE OR REPLACE FUNCTION @extschema@.common_relation_checks( - p_relation REGCLASS - , p_attribute TEXT) + p_relation REGCLASS, + p_attribute TEXT) RETURNS BOOLEAN AS $$ DECLARE - v_rec RECORD; - is_referenced BOOLEAN; + v_rec RECORD; + is_referenced BOOLEAN; + rel_persistence CHAR; + BEGIN - IF EXISTS (SELECT * FROM @extschema@.pathman_config WHERE relname::regclass = p_relation) THEN - RAISE EXCEPTION 'Relation "%" has already been partitioned', p_relation; + /* Ignore temporary tables */ + SELECT relpersistence FROM pg_catalog.pg_class + WHERE oid = p_relation INTO rel_persistence; + + IF rel_persistence = 't'::CHAR THEN + RAISE EXCEPTION 'temporary table "%" cannot be partitioned', + p_relation::TEXT; + END IF; + + IF EXISTS (SELECT * FROM @extschema@.pathman_config + WHERE partrel = p_relation) THEN + RAISE EXCEPTION 'relation "%" has already been partitioned', p_relation; END IF; IF @extschema@.is_attribute_nullable(p_relation, p_attribute) THEN - RAISE EXCEPTION 'Partitioning key ''%'' must be NOT NULL', p_attribute; + RAISE EXCEPTION 'partitioning key ''%'' must be NOT NULL', p_attribute; END IF; - /* Check if there are foreign keys reference to the relation */ + /* Check if there are foreign keys that reference the relation */ FOR v_rec IN (SELECT * FROM pg_constraint WHERE confrelid = p_relation::regclass::oid) LOOP is_referenced := TRUE; - RAISE WARNING 'Foreign key ''%'' references to the relation ''%''', v_rec.conname, p_relation; + RAISE WARNING 'foreign key ''%'' references relation ''%''', + v_rec.conname, p_relation; END LOOP; IF is_referenced THEN - RAISE EXCEPTION 'Relation ''%'' is referenced from other relations', p_relation; + RAISE EXCEPTION 'relation "%" is referenced from other relations', p_relation; END IF; RETURN TRUE; @@ -213,130 +364,409 @@ $$ LANGUAGE plpgsql; /* - * Returns relname without quotes or something + * Returns relname without quotes or something. */ -CREATE OR REPLACE FUNCTION @extschema@.get_plain_schema_and_relname(cls regclass, OUT schema TEXT, OUT relname TEXT) +CREATE OR REPLACE FUNCTION @extschema@.get_plain_schema_and_relname( + cls REGCLASS, + OUT schema TEXT, + OUT relname TEXT) AS $$ BEGIN - SELECT relnamespace::regnamespace, pg_class.relname FROM pg_class WHERE oid = cls::oid + SELECT pg_catalog.pg_class.relnamespace::regnamespace, + pg_catalog.pg_class.relname + FROM pg_catalog.pg_class WHERE oid = cls::oid INTO schema, relname; END $$ -LANGUAGE plpgsql; +LANGUAGE plpgsql STRICT; - -CREATE OR REPLACE FUNCTION @extschema@.get_plain_relname(cls regclass) +/* + * Returns the schema-qualified name of table. + */ +CREATE OR REPLACE FUNCTION @extschema@.get_schema_qualified_name( + cls REGCLASS, + delimiter TEXT DEFAULT '.', + suffix TEXT DEFAULT '') RETURNS TEXT AS $$ BEGIN - RETURN relname FROM pg_class WHERE oid = cls::oid; + RETURN (SELECT quote_ident(relnamespace::regnamespace::text) || + delimiter || + quote_ident(relname || suffix) + FROM pg_catalog.pg_class + WHERE oid = cls::oid); END $$ -LANGUAGE plpgsql; - +LANGUAGE plpgsql STRICT; /* - * Validates relation name. It must be schema qualified + * Validates relation name. It must be schema qualified. */ -CREATE OR REPLACE FUNCTION @extschema@.validate_relname(cls regclass) +CREATE OR REPLACE FUNCTION @extschema@.validate_relname( + cls REGCLASS) RETURNS TEXT AS $$ +DECLARE + relname TEXT; + BEGIN - RETURN @extschema@.get_schema_qualified_name(cls, '.'); + relname = @extschema@.get_schema_qualified_name(cls); + + IF relname IS NULL THEN + RAISE EXCEPTION 'relation %s does not exist', cls; + END IF; + + RETURN relname; END $$ LANGUAGE plpgsql; - /* - * Returns schema-qualified name for table + * Check if two relations have equal structures. */ -CREATE OR REPLACE FUNCTION @extschema@.get_schema_qualified_name( - cls REGCLASS - , delimiter TEXT DEFAULT '_' - , suffix TEXT DEFAULT '') -RETURNS TEXT AS +CREATE OR REPLACE FUNCTION @extschema@.validate_relations_equality( + relation1 OID, relation2 OID) +RETURNS BOOLEAN AS $$ +DECLARE + rec RECORD; + BEGIN - RETURN relnamespace::regnamespace || delimiter || quote_ident(relname || suffix) FROM pg_class WHERE oid = cls::oid; + FOR rec IN ( + WITH + a1 AS (select * from pg_catalog.pg_attribute + where attrelid = relation1 and attnum > 0), + a2 AS (select * from pg_catalog.pg_attribute + where attrelid = relation2 and attnum > 0) + SELECT a1.attname name1, a2.attname name2, a1.atttypid type1, a2.atttypid type2 + FROM a1 + FULL JOIN a2 ON a1.attnum = a2.attnum + ) + LOOP + IF rec.name1 IS NULL OR rec.name2 IS NULL OR rec.name1 != rec.name2 THEN + RETURN false; + END IF; + END LOOP; + + RETURN true; END $$ LANGUAGE plpgsql; /* - * Check if two relations have equal structures + * DDL trigger that deletes entry from pathman_config table. */ -CREATE OR REPLACE FUNCTION @extschema@.validate_relations_equality(relation1 OID, relation2 OID) -RETURNS BOOLEAN AS +CREATE OR REPLACE FUNCTION @extschema@.pathman_ddl_trigger_func() +RETURNS event_trigger AS $$ DECLARE - rec RECORD; + obj record; + pg_class_oid oid; BEGIN - FOR rec IN ( - WITH - a1 AS (select * from pg_attribute where attrelid = relation1 and attnum > 0), - a2 AS (select * from pg_attribute where attrelid = relation2 and attnum > 0) - SELECT a1.attname name1, a2.attname name2, a1.atttypid type1, a2.atttypid type2 - FROM a1 - FULL JOIN a2 ON a1.attnum = a2.attnum - ) - LOOP - IF rec.name1 IS NULL OR rec.name2 IS NULL OR rec.name1 != rec.name2 THEN - RETURN False; - END IF; - END LOOP; - - RETURN True; + pg_class_oid = 'pg_catalog.pg_class'::regclass; + + /* Handle 'DROP TABLE' events */ + WITH to_be_deleted AS ( + SELECT cfg.partrel AS rel FROM pg_event_trigger_dropped_objects() AS events + JOIN @extschema@.pathman_config AS cfg ON cfg.partrel::oid = events.objid + WHERE events.classid = pg_class_oid + ) + DELETE FROM @extschema@.pathman_config + WHERE partrel IN (SELECT rel FROM to_be_deleted); + + /* Cleanup params table too */ + WITH to_be_deleted AS ( + SELECT cfg.partrel AS rel FROM pg_event_trigger_dropped_objects() AS events + JOIN @extschema@.pathman_config_params AS cfg ON cfg.partrel::oid = events.objid + WHERE events.classid = pg_class_oid + ) + DELETE FROM @extschema@.pathman_config_params + WHERE partrel IN (SELECT rel FROM to_be_deleted); END $$ LANGUAGE plpgsql; /* - * Check if regclass if date or timestamp + * Drop triggers. */ -CREATE OR REPLACE FUNCTION @extschema@.is_date(cls REGTYPE) -RETURNS BOOLEAN AS +CREATE OR REPLACE FUNCTION @extschema@.drop_triggers( + parent_relid REGCLASS) +RETURNS VOID AS $$ BEGIN - RETURN cls IN ('timestamp'::regtype, 'timestamptz'::regtype, 'date'::regtype); + EXECUTE format('DROP FUNCTION IF EXISTS %s() CASCADE', + @extschema@.build_update_trigger_func_name(parent_relid)); END -$$ -LANGUAGE plpgsql; +$$ LANGUAGE plpgsql STRICT; /* - * DDL trigger that deletes entry from pathman_config + * Drop partitions. If delete_data set to TRUE, partitions + * will be dropped with all the data. */ -CREATE OR REPLACE FUNCTION @extschema@.pathman_ddl_trigger_func() -RETURNS event_trigger AS +CREATE OR REPLACE FUNCTION @extschema@.drop_partitions( + parent_relid REGCLASS, + delete_data BOOLEAN DEFAULT FALSE) +RETURNS INTEGER AS $$ DECLARE - obj record; + v_rec RECORD; + v_rows BIGINT; + v_part_count INTEGER := 0; + conf_num_del INTEGER; + v_relkind CHAR; + BEGIN - FOR obj IN SELECT * FROM pg_event_trigger_dropped_objects() as events - JOIN @extschema@.pathman_config as cfg ON cfg.relname = events.object_identity + PERFORM @extschema@.validate_relname(parent_relid); + + /* Drop trigger first */ + PERFORM @extschema@.drop_triggers(parent_relid); + + WITH config_num_deleted AS (DELETE FROM @extschema@.pathman_config + WHERE partrel = parent_relid + RETURNING *) + SELECT count(*) from config_num_deleted INTO conf_num_del; + + DELETE FROM @extschema@.pathman_config_params WHERE partrel = parent_relid; + + IF conf_num_del = 0 THEN + RAISE EXCEPTION 'relation "%" has no partitions', parent_relid::TEXT; + END IF; + + FOR v_rec IN (SELECT inhrelid::REGCLASS AS tbl + FROM pg_catalog.pg_inherits + WHERE inhparent::regclass = parent_relid + ORDER BY inhrelid ASC) LOOP - IF obj.object_type = 'table' THEN - EXECUTE 'DELETE FROM @extschema@.pathman_config WHERE relname = $1' - USING obj.object_identity; + IF NOT delete_data THEN + EXECUTE format('INSERT INTO %s SELECT * FROM %s', + parent_relid::TEXT, + v_rec.tbl::TEXT); + GET DIAGNOSTICS v_rows = ROW_COUNT; + + /* Show number of copied rows */ + RAISE NOTICE '% rows copied from %', v_rows, v_rec.tbl::TEXT; + END IF; + + SELECT relkind FROM pg_catalog.pg_class + WHERE oid = v_rec.tbl + INTO v_relkind; + + /* + * Determine the kind of child relation. It can be either regular + * table (r) or foreign table (f). Depending on relkind we use + * DROP TABLE or DROP FOREIGN TABLE. + */ + IF v_relkind = 'f' THEN + EXECUTE format('DROP FOREIGN TABLE %s', v_rec.tbl::TEXT); + ELSE + EXECUTE format('DROP TABLE %s', v_rec.tbl::TEXT); END IF; + + v_part_count := v_part_count + 1; END LOOP; + + /* Notify backend about changes */ + PERFORM @extschema@.on_remove_partitions(parent_relid); + + RETURN v_part_count; END +$$ LANGUAGE plpgsql +SET pg_pathman.enable_partitionfilter = off; /* ensures that PartitionFilter is OFF */ + + +/* + * Copy all of parent's foreign keys. + */ +CREATE OR REPLACE FUNCTION @extschema@.copy_foreign_keys( + parent_relid REGCLASS, + partition REGCLASS) +RETURNS VOID AS $$ -LANGUAGE plpgsql; +DECLARE + rec RECORD; + +BEGIN + PERFORM @extschema@.validate_relname(parent_relid); + PERFORM @extschema@.validate_relname(partition); + FOR rec IN (SELECT oid as conid FROM pg_catalog.pg_constraint + WHERE conrelid = parent_relid AND contype = 'f') + LOOP + EXECUTE format('ALTER TABLE %s ADD %s', + partition::TEXT, + pg_get_constraintdef(rec.conid)); + END LOOP; +END +$$ LANGUAGE plpgsql STRICT; + + +/* + * Create DDL trigger to call pathman_ddl_trigger_func(). + */ CREATE EVENT TRIGGER pathman_ddl_trigger ON sql_drop EXECUTE PROCEDURE @extschema@.pathman_ddl_trigger_func(); + + +CREATE OR REPLACE FUNCTION @extschema@.on_create_partitions( + relid REGCLASS) +RETURNS VOID AS 'pg_pathman', 'on_partitions_created' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION @extschema@.on_update_partitions( + relid REGCLASS) +RETURNS VOID AS 'pg_pathman', 'on_partitions_updated' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION @extschema@.on_remove_partitions( + relid REGCLASS) +RETURNS VOID AS 'pg_pathman', 'on_partitions_removed' +LANGUAGE C STRICT; + + +/* + * Get parent of pg_pathman's partition. + */ +CREATE OR REPLACE FUNCTION @extschema@.get_parent_of_partition(REGCLASS) +RETURNS REGCLASS AS 'pg_pathman', 'get_parent_of_partition_pl' +LANGUAGE C STRICT; + +/* + * Extract basic type of a domain. + */ +CREATE OR REPLACE FUNCTION @extschema@.get_base_type(REGTYPE) +RETURNS REGTYPE AS 'pg_pathman', 'get_base_type_pl' +LANGUAGE C STRICT; + +/* + * Returns attribute type name for relation. + */ +CREATE OR REPLACE FUNCTION @extschema@.get_attribute_type( + REGCLASS, TEXT) +RETURNS REGTYPE AS 'pg_pathman', 'get_attribute_type_pl' +LANGUAGE C STRICT; + +/* + * Return tablespace name for specified relation. + */ +CREATE OR REPLACE FUNCTION @extschema@.get_rel_tablespace_name(REGCLASS) +RETURNS TEXT AS 'pg_pathman', 'get_rel_tablespace_name' +LANGUAGE C STRICT; + + +/* + * Checks if attribute is nullable + */ +CREATE OR REPLACE FUNCTION @extschema@.is_attribute_nullable( + REGCLASS, TEXT) +RETURNS BOOLEAN AS 'pg_pathman', 'is_attribute_nullable' +LANGUAGE C STRICT; + +/* + * Check if regclass is date or timestamp. + */ +CREATE OR REPLACE FUNCTION @extschema@.is_date_type( + typid REGTYPE) +RETURNS BOOLEAN AS 'pg_pathman', 'is_date_type' +LANGUAGE C STRICT; + + +/* + * Build check constraint name for a specified relation's column. + */ +CREATE OR REPLACE FUNCTION @extschema@.build_check_constraint_name( + REGCLASS, INT2) +RETURNS TEXT AS 'pg_pathman', 'build_check_constraint_name_attnum' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION @extschema@.build_check_constraint_name( + REGCLASS, TEXT) +RETURNS TEXT AS 'pg_pathman', 'build_check_constraint_name_attname' +LANGUAGE C STRICT; + +/* + * Build update trigger and its underlying function's names. + */ +CREATE OR REPLACE FUNCTION @extschema@.build_update_trigger_name( + REGCLASS) +RETURNS TEXT AS 'pg_pathman', 'build_update_trigger_name' +LANGUAGE C STRICT; + +CREATE OR REPLACE FUNCTION @extschema@.build_update_trigger_func_name( + REGCLASS) +RETURNS TEXT AS 'pg_pathman', 'build_update_trigger_func_name' +LANGUAGE C STRICT; + + +/* + * Attach a previously partitioned table. + */ +CREATE OR REPLACE FUNCTION @extschema@.add_to_pathman_config( + parent_relid REGCLASS, + attname TEXT, + range_interval TEXT DEFAULT NULL) +RETURNS BOOLEAN AS 'pg_pathman', 'add_to_pathman_config' +LANGUAGE C; + +CREATE OR REPLACE FUNCTION @extschema@.invalidate_relcache(relid OID) +RETURNS VOID AS 'pg_pathman' LANGUAGE C STRICT; + + +/* + * Lock partitioned relation to restrict concurrent + * modification of partitioning scheme. + */ + CREATE OR REPLACE FUNCTION @extschema@.lock_partitioned_relation( + REGCLASS) + RETURNS VOID AS 'pg_pathman', 'lock_partitioned_relation' + LANGUAGE C STRICT; + +/* + * Lock relation to restrict concurrent modification of data. + */ + CREATE OR REPLACE FUNCTION @extschema@.prevent_relation_modification( + REGCLASS) + RETURNS VOID AS 'pg_pathman', 'prevent_relation_modification' + LANGUAGE C STRICT; + + +/* + * DEBUG: Place this inside some plpgsql fuction and set breakpoint. + */ +CREATE OR REPLACE FUNCTION @extschema@.debug_capture() +RETURNS VOID AS 'pg_pathman', 'debug_capture' +LANGUAGE C STRICT; + +/* + * Checks that callback function meets specific requirements. Particularly it + * must have the only JSONB argument and VOID return type. + */ +CREATE OR REPLACE FUNCTION @extschema@.validate_on_partition_created_callback( + callback REGPROC) +RETURNS VOID AS 'pg_pathman', 'validate_on_part_init_callback_pl' +LANGUAGE C STRICT; + + /* - * Acquire partitions lock to prevent concurrent partitions creation + * Invoke init_callback on RANGE partition. */ -CREATE OR REPLACE FUNCTION @extschema@.acquire_partitions_lock() -RETURNS VOID AS 'pg_pathman', 'acquire_partitions_lock' LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION @extschema@.invoke_on_partition_created_callback( + parent_relid REGCLASS, + partition REGCLASS, + init_callback REGPROCEDURE, + start_value ANYELEMENT, + end_value ANYELEMENT) +RETURNS VOID AS 'pg_pathman', 'invoke_on_partition_created_callback' +LANGUAGE C; /* - * Release partitions lock + * Invoke init_callback on HASH partition. */ -CREATE OR REPLACE FUNCTION @extschema@.release_partitions_lock() -RETURNS VOID AS 'pg_pathman', 'release_partitions_lock' LANGUAGE C STRICT; +CREATE OR REPLACE FUNCTION @extschema@.invoke_on_partition_created_callback( + parent_relid REGCLASS, + partition REGCLASS, + init_callback REGPROCEDURE) +RETURNS VOID AS 'pg_pathman', 'invoke_on_partition_created_callback' +LANGUAGE C; diff --git a/contrib/pg_pathman/pathman.h b/contrib/pg_pathman/pathman.h deleted file mode 100644 index fc6315e29f..0000000000 --- a/contrib/pg_pathman/pathman.h +++ /dev/null @@ -1,199 +0,0 @@ -/* ------------------------------------------------------------------------ - * - * pathman.h - * structures and prototypes for pathman functions - * - * Copyright (c) 2015-2016, Postgres Professional - * - * ------------------------------------------------------------------------ - */ -#ifndef PATHMAN_H -#define PATHMAN_H - -#include "postgres.h" -#include "utils/date.h" -#include "utils/hsearch.h" -#include "utils/snapshot.h" -#include "nodes/pg_list.h" -#include "storage/dsm.h" -#include "storage/lwlock.h" - -#include "nodes/bitmapset.h" - -/* Check PostgreSQL version */ -#if PG_VERSION_NUM < 90500 - #error "You are trying to build pg_pathman with PostgreSQL version lower than 9.5. Please, check you environment." -#endif - -#define ALL NIL -#define INITIAL_BLOCKS_COUNT 8192 - -/* - * Partitioning type - */ -typedef enum PartType -{ - PT_HASH = 1, - PT_RANGE -} PartType; - -/* - * Dynamic shared memory array - */ -typedef struct DsmArray -{ - dsm_handle segment; - size_t offset; - size_t length; -} DsmArray; - -/* - * Hashtable key for relations - */ -typedef struct RelationKey -{ - Oid dbid; - Oid relid; -} RelationKey; - -/* - * PartRelationInfo - * Per-relation partitioning information - * - * oid - parent table oid - * children - list of children oids - * parttype - partitioning type (HASH, LIST or RANGE) - * attnum - attribute number of parent relation - */ -typedef struct PartRelationInfo -{ - RelationKey key; - DsmArray children; - int children_count; - PartType parttype; - Index attnum; - Oid atttype; - -} PartRelationInfo; - -/* - * Child relation for HASH partitioning - */ -typedef struct HashRelationKey -{ - int hash; - Oid parent_oid; -} HashRelationKey; - -typedef struct HashRelation -{ - HashRelationKey key; - Oid child_oid; -} HashRelation; - -/* - * Child relation for RANGE partitioning - */ -typedef struct RangeEntry -{ - Oid child_oid; - #ifdef HAVE_INT64_TIMESTAMP - int64 min; - int64 max; - #else - double min; - double max; - #endif -} RangeEntry; - -typedef struct RangeRelation -{ - RelationKey key; - bool by_val; - DsmArray ranges; -} RangeRelation; - -typedef struct PathmanState -{ - LWLock *load_config_lock; - LWLock *dsm_init_lock; - LWLock *edit_partitions_lock; - DsmArray databases; -} PathmanState; - -extern bool pg_pathman_enable; -extern PathmanState *pmstate; - -#define PATHMAN_GET_DATUM(value, by_val) ( (by_val) ? (value) : PointerGetDatum(&value) ) - -typedef int IndexRange; -#define RANGE_INFINITY 0x7FFF -#define RANGE_LOSSY 0x80000000 - -#define make_irange(lower, upper, lossy) \ - (((lower) & RANGE_INFINITY) << 15 | ((upper) & RANGE_INFINITY) | ((lossy) ? RANGE_LOSSY : 0)) - -#define irange_lower(irange) \ - (((irange) >> 15) & RANGE_INFINITY) - -#define irange_upper(irange) \ - ((irange) & RANGE_INFINITY) - -#define irange_is_lossy(irange) \ - ((irange) & RANGE_LOSSY) - -#define lfirst_irange(lc) ((IndexRange)(lc)->data.int_value) -#define lappend_irange(list, irange) (lappend_int((list), (int)(irange))) -#define lcons_irange(irange, list) lcons_int((int)(irange), (list)) -#define list_make1_irange(irange) lcons_int((int)(irange), NIL) -#define llast_irange(l) (IndexRange)lfirst_int(list_tail(l)) - -/* rangeset.c */ -bool irange_intersects(IndexRange a, IndexRange b); -bool irange_conjuncted(IndexRange a, IndexRange b); -IndexRange irange_union(IndexRange a, IndexRange b); -IndexRange irange_intersect(IndexRange a, IndexRange b); -List *irange_list_union(List *a, List *b); -List *irange_list_intersect(List *a, List *b); -int irange_list_length(List *rangeset); -bool irange_list_find(List *rangeset, int index, bool *lossy); - -/* Dynamic shared memory functions */ -Size get_dsm_shared_size(void); -void init_dsm_config(void); -bool init_dsm_segment(size_t blocks_count, size_t block_size); -void init_dsm_table(size_t block_size, size_t start, size_t end); -void alloc_dsm_array(DsmArray *arr, size_t entry_size, size_t length); -void free_dsm_array(DsmArray *arr); -void resize_dsm_array(DsmArray *arr, size_t entry_size, size_t length); -void *dsm_array_get_pointer(const DsmArray* arr); -dsm_handle get_dsm_array_segment(void); -void attach_dsm_array_segment(void); - -HTAB *relations; -HTAB *range_restrictions; -bool initialization_needed; - -/* initialization functions */ -Size pathman_memsize(void); -void init_shmem_config(void); -void load_config(void); -void create_relations_hashtable(void); -void create_hash_restrictions_hashtable(void); -void create_range_restrictions_hashtable(void); -void load_relations_hashtable(bool reinitialize); -void load_check_constraints(Oid parent_oid, Snapshot snapshot); -void remove_relation_info(Oid relid); - -/* utility functions */ -PartRelationInfo *get_pathman_relation_info(Oid relid, bool *found); -RangeRelation *get_pathman_range_relation(Oid relid, bool *found); -int range_binary_search(const RangeRelation *rangerel, FmgrInfo *cmp_func, Datum value, bool *fountPtr); -char *get_extension_schema(void); -FmgrInfo *get_cmp_func(Oid type1, Oid type2); -Oid create_partitions_bg_worker(Oid relid, Datum value, Oid value_type, bool *crashed); -Oid create_partitions(Oid relid, Datum value, Oid value_type, bool *crashed); - -char *bms_print(Bitmapset *bms); - -#endif /* PATHMAN_H */ diff --git a/contrib/pg_pathman/pg_pathman.c b/contrib/pg_pathman/pg_pathman.c deleted file mode 100644 index f4bba3d188..0000000000 --- a/contrib/pg_pathman/pg_pathman.c +++ /dev/null @@ -1,1801 +0,0 @@ -/* ------------------------------------------------------------------------ - * - * pg_pathman.c - * This module sets planner hooks, handles SELECT queries and produces - * paths for partitioned tables - * - * Copyright (c) 2015-2016, Postgres Professional - * - * ------------------------------------------------------------------------ - */ -#include "pathman.h" -#include "postgres.h" -#include "fmgr.h" -#include "miscadmin.h" -#include "nodes/makefuncs.h" -#include "nodes/nodeFuncs.h" -#include "nodes/pg_list.h" -#include "nodes/relation.h" -#include "nodes/primnodes.h" -#include "optimizer/clauses.h" -#include "optimizer/paths.h" -#include "optimizer/pathnode.h" -#include "optimizer/planner.h" -#include "optimizer/restrictinfo.h" -#include "optimizer/cost.h" -#include "parser/analyze.h" -#include "parser/parsetree.h" -#include "utils/hsearch.h" -#include "utils/tqual.h" -#include "utils/rel.h" -#include "utils/elog.h" -#include "utils/array.h" -#include "utils/date.h" -#include "utils/typcache.h" -#include "utils/lsyscache.h" -#include "utils/guc.h" -#include "access/heapam.h" -#include "access/nbtree.h" -#include "storage/ipc.h" -#include "catalog/pg_operator.h" -#include "catalog/pg_type.h" -#include "foreign/fdwapi.h" - -PG_MODULE_MAGIC; - -typedef struct -{ - Oid old_varno; - Oid new_varno; -} change_varno_context; - -typedef struct -{ - const Node *orig; - List *args; - List *rangeset; -} WrapperNode; - -bool pg_pathman_enable; -PathmanState *pmstate; - -/* Original hooks */ -static set_rel_pathlist_hook_type set_rel_pathlist_hook_original = NULL; -static shmem_startup_hook_type shmem_startup_hook_original = NULL; -static post_parse_analyze_hook_type post_parse_analyze_hook_original = NULL; -static planner_hook_type planner_hook_original = NULL; - -/* pg module functions */ -void _PG_init(void); -void _PG_fini(void); - -/* Hook functions */ -static void pathman_shmem_startup(void); -static void pathman_set_rel_pathlist_hook(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte); -void pathman_post_parse_analysis_hook(ParseState *pstate, Query *query); -static PlannedStmt * pathman_planner_hook(Query *parse, int cursorOptions, ParamListInfo boundParams); - -/* Utility functions */ -static void handle_modification_query(Query *parse); -static int append_child_relation(PlannerInfo *root, RelOptInfo *rel, Index rti, - RangeTblEntry *rte, int index, Oid childOID, List *wrappers); -static Node *wrapper_make_expression(WrapperNode *wrap, int index, bool *alwaysTrue); -static void disable_inheritance(Query *parse); -static void disable_inheritance_cte(Query *parse); -static void disable_inheritance_subselect(Query *parse); -bool inheritance_disabled; - -/* Expression tree handlers */ -static WrapperNode *walk_expr_tree(Expr *expr, const PartRelationInfo *prel); -static int make_hash(const PartRelationInfo *prel, int value); -static void handle_binary_opexpr(const PartRelationInfo *prel, WrapperNode *result, const Var *v, const Const *c); -static WrapperNode *handle_opexpr(const OpExpr *expr, const PartRelationInfo *prel); -static WrapperNode *handle_boolexpr(const BoolExpr *expr, const PartRelationInfo *prel); -static WrapperNode *handle_arrexpr(const ScalarArrayOpExpr *expr, const PartRelationInfo *prel); -static void change_varnos_in_restrinct_info(RestrictInfo *rinfo, change_varno_context *context); -static void change_varnos(Node *node, Oid old_varno, Oid new_varno); -static bool change_varno_walker(Node *node, change_varno_context *context); -static RestrictInfo *rebuild_restrictinfo(Node *clause, RestrictInfo *old_rinfo); - -/* copied from allpaths.h */ -static void set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, - RangeTblEntry *rte); -static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); -static void set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte); -static void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte, PathKey *pathkeyAsc, PathKey *pathkeyDesc); -static List *accumulate_append_subpath(List *subpaths, Path *path); -static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, - List *live_childrels, - List *all_child_pathkeys, - PathKey *pathkeyAsc, - PathKey *pathkeyDesc); - - -char * -bms_print(Bitmapset *bms) -{ - StringInfoData str; - int x; - - initStringInfo(&str); - x = -1; - while ((x = bms_next_member(bms, x)) >= 0) - appendStringInfo(&str, " %d", x); - - return str.data; -} - -/* - * Compare two Datums with the given comarison function - * - * flinfo is a pointer to an instance of FmgrInfo - * arg1, arg2 are Datum instances - */ -#define check_lt(flinfo, arg1, arg2) \ - ((int) FunctionCall2(cmp_func, arg1, arg2) < 0) -#define check_le(flinfo, arg1, arg2) \ - ((int) FunctionCall2(cmp_func, arg1, arg2) <= 0) -#define check_eq(flinfo, arg1, arg2) \ - ((int) FunctionCall2(cmp_func, arg1, arg2) == 0) -#define check_ge(flinfo, arg1, arg2) \ - ((int) FunctionCall2(cmp_func, arg1, arg2) >= 0) -#define check_gt(flinfo, arg1, arg2) \ - ((int) FunctionCall2(cmp_func, arg1, arg2) > 0) - - -/* - * Entry point - */ -void -_PG_init(void) -{ - if (!process_shared_preload_libraries_in_progress) - { - elog(ERROR, "Pathman module must be initialized in postmaster. " - "Put the following line to configuration file: " - "shared_preload_libraries='pg_pathman'"); - initialization_needed = false; - } - - /* Request additional shared resources */ - RequestAddinShmemSpace(pathman_memsize()); - RequestAddinLWLocks(3); - - set_rel_pathlist_hook_original = set_rel_pathlist_hook; - set_rel_pathlist_hook = pathman_set_rel_pathlist_hook; - shmem_startup_hook_original = shmem_startup_hook; - shmem_startup_hook = pathman_shmem_startup; - post_parse_analyze_hook_original = post_parse_analyze_hook; - post_parse_analyze_hook = pathman_post_parse_analysis_hook; - planner_hook_original = planner_hook; - planner_hook = pathman_planner_hook; - - DefineCustomBoolVariable("pg_pathman.enable", - "Enables pg_pathman's optimizations during the planner stage", - NULL, - &pg_pathman_enable, - true, - PGC_USERSET, - 0, - NULL, - NULL, - NULL); -} - -void -_PG_fini(void) -{ - set_rel_pathlist_hook = set_rel_pathlist_hook_original; - shmem_startup_hook = shmem_startup_hook_original; - post_parse_analyze_hook = post_parse_analyze_hook_original; - planner_hook = planner_hook_original; -} - -PartRelationInfo * -get_pathman_relation_info(Oid relid, bool *found) -{ - RelationKey key; - - key.dbid = MyDatabaseId; - key.relid = relid; - return hash_search(relations, (const void *) &key, HASH_FIND, found); -} - -RangeRelation * -get_pathman_range_relation(Oid relid, bool *found) -{ - RelationKey key; - - key.dbid = MyDatabaseId; - key.relid = relid; - return hash_search(range_restrictions, (const void *) &key, HASH_FIND, found); -} - -FmgrInfo * -get_cmp_func(Oid type1, Oid type2) -{ - FmgrInfo *cmp_func; - Oid cmp_proc_oid; - TypeCacheEntry *tce; - - cmp_func = palloc(sizeof(FmgrInfo)); - tce = lookup_type_cache(type1, - TYPECACHE_BTREE_OPFAMILY | TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO); - cmp_proc_oid = get_opfamily_proc(tce->btree_opf, - type1, - type2, - BTORDER_PROC); - fmgr_info(cmp_proc_oid, cmp_func); - return cmp_func; -} - -/* - * Post parse analysis hook. It makes sure the config is loaded before executing - * any statement, including utility commands - */ -void -pathman_post_parse_analysis_hook(ParseState *pstate, Query *query) -{ - if (initialization_needed) - load_config(); - - if (post_parse_analyze_hook_original) - post_parse_analyze_hook_original(pstate, query); -} - -/* - * Planner hook. It disables inheritance for tables that have been partitioned - * by pathman to prevent standart PostgreSQL partitioning mechanism from - * handling that tables. - */ -PlannedStmt * -pathman_planner_hook(Query *parse, int cursorOptions, ParamListInfo boundParams) -{ - PlannedStmt *result; - - if (pg_pathman_enable) - { - inheritance_disabled = false; - switch(parse->commandType) - { - case CMD_SELECT: - disable_inheritance(parse); - break; - case CMD_UPDATE: - case CMD_DELETE: - disable_inheritance_cte(parse); - disable_inheritance_subselect(parse); - handle_modification_query(parse); - break; - default: - break; - } - } - - /* Invoke original hook */ - if (planner_hook_original) - result = planner_hook_original(parse, cursorOptions, boundParams); - else - result = standard_planner(parse, cursorOptions, boundParams); - - return result; -} - -/* - * Disables inheritance for partitioned by pathman relations. It must be done to - * prevent PostgresSQL from full search. - */ -static void -disable_inheritance(Query *parse) -{ - ListCell *lc; - RangeTblEntry *rte; - PartRelationInfo *prel; - bool found; - - /* If query contains CTE (WITH statement) then handle subqueries too */ - disable_inheritance_cte(parse); - - /* If query contains subselects */ - disable_inheritance_subselect(parse); - - foreach(lc, parse->rtable) - { - rte = (RangeTblEntry*) lfirst(lc); - switch(rte->rtekind) - { - case RTE_RELATION: - if (rte->inh) - { - /* Look up this relation in pathman relations */ - prel = get_pathman_relation_info(rte->relid, &found); - if (prel != NULL && found) - { - rte->inh = false; - /* - * Sometimes user uses the ONLY statement and in this case - * rte->inh is also false. We should differ the case - * when user uses ONLY statement from case when we - * make rte->inh false intentionally. - */ - inheritance_disabled = true; - } - } - break; - case RTE_SUBQUERY: - /* Recursively disable inheritance for subqueries */ - disable_inheritance(rte->subquery); - break; - default: - break; - } - } -} - -static void -disable_inheritance_cte(Query *parse) -{ - ListCell *lc; - - foreach(lc, parse->cteList) - { - CommonTableExpr *cte = (CommonTableExpr*) lfirst(lc); - - if (IsA(cte->ctequery, Query)) - disable_inheritance((Query *) cte->ctequery); - } -} - -static void -disable_inheritance_subselect(Query *parse) -{ - Node *quals; - - if (!parse->jointree || !parse->jointree->quals) - return; - - quals = parse->jointree->quals; - if (!IsA(quals, SubLink)) - return; - - if (!IsA(((SubLink *) quals)->subselect, Query)) - return; - - disable_inheritance((Query *) (((SubLink *) quals)->subselect)); -} - -/* - * Checks if query is affects only one partition. If true then substitute - */ -static void -handle_modification_query(Query *parse) -{ - PartRelationInfo *prel; - List *ranges; - RangeTblEntry *rte; - WrapperNode *wrap; - Expr *expr; - bool found; - - Assert(parse->commandType == CMD_UPDATE || - parse->commandType == CMD_DELETE); - Assert(parse->resultRelation > 0); - - rte = rt_fetch(parse->resultRelation, parse->rtable); - prel = get_pathman_relation_info(rte->relid, &found); - - if (!found) - return; - - /* Parse syntax tree and extract partition ranges */ - ranges = list_make1_int(make_irange(0, prel->children_count - 1, false)); - expr = (Expr *) eval_const_expressions(NULL, parse->jointree->quals); - if (!expr) - return; - - /* Parse syntax tree and extract partition ranges */ - wrap = walk_expr_tree(expr, prel); - ranges = irange_list_intersect(ranges, wrap->rangeset); - - /* If only one partition is affected then substitute parent table with partition */ - if (irange_list_length(ranges) == 1) - { - IndexRange irange = (IndexRange) linitial_oid(ranges); - if (irange_lower(irange) == irange_upper(irange)) - { - Oid *children = (Oid *) dsm_array_get_pointer(&prel->children); - rte->relid = children[irange_lower(irange)]; - rte->inh = false; - } - } - - return; -} - -/* - * Shared memory startup hook - */ -static void -pathman_shmem_startup(void) -{ - /* Allocate shared memory objects */ - LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); - init_dsm_config(); - init_shmem_config(); - LWLockRelease(AddinShmemInitLock); - - /* Invoke original hook if needed */ - if (shmem_startup_hook_original != NULL) - shmem_startup_hook_original(); -} - -/* - * Main hook. All the magic goes here - */ -void -pathman_set_rel_pathlist_hook(PlannerInfo *root, RelOptInfo *rel, Index rti, RangeTblEntry *rte) -{ - PartRelationInfo *prel = NULL; - RelOptInfo **new_rel_array; - RangeTblEntry **new_rte_array; - int len; - bool found; - - /* Invoke original hook if needed */ - if (set_rel_pathlist_hook_original != NULL) - { - set_rel_pathlist_hook_original(root, rel, rti, rte); - } - - if (!pg_pathman_enable) - return; - - /* This works only for SELECT queries */ - if (root->parse->commandType != CMD_SELECT || !inheritance_disabled) - return; - - /* Lookup partitioning information for parent relation */ - prel = get_pathman_relation_info(rte->relid, &found); - - if (prel != NULL && found) - { - ListCell *lc; - int i; - Oid *dsm_arr; - List *ranges, - *wrappers; - PathKey *pathkeyAsc = NULL, - *pathkeyDesc = NULL; - - if (prel->parttype == PT_RANGE) - { - /* - * Get pathkeys for ascending and descending sort by partition - * column - */ - List *pathkeys; - Var *var; - Oid vartypeid, - varcollid; - int32 type_mod; - TypeCacheEntry *tce; - - /* Make Var from patition column */ - get_rte_attribute_type(rte, prel->attnum, - &vartypeid, &type_mod, &varcollid); - var = makeVar(rti, prel->attnum, vartypeid, type_mod, varcollid, 0); - var->location = -1; - - /* Determine operator type */ - tce = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); - - /* Make pathkeys */ - pathkeys = build_expression_pathkey(root, (Expr *)var, NULL, - tce->lt_opr, NULL, false); - if (pathkeys) - pathkeyAsc = (PathKey *) linitial(pathkeys); - pathkeys = build_expression_pathkey(root, (Expr *)var, NULL, - tce->gt_opr, NULL, false); - if (pathkeys) - pathkeyDesc = (PathKey *) linitial(pathkeys); - } - - rte->inh = true; - dsm_arr = (Oid *) dsm_array_get_pointer(&prel->children); - ranges = list_make1_int(make_irange(0, prel->children_count - 1, false)); - - /* Make wrappers over restrictions and collect final rangeset */ - wrappers = NIL; - foreach(lc, rel->baserestrictinfo) - { - WrapperNode *wrap; - - RestrictInfo *rinfo = (RestrictInfo*) lfirst(lc); - - wrap = walk_expr_tree(rinfo->clause, prel); - wrappers = lappend(wrappers, wrap); - ranges = irange_list_intersect(ranges, wrap->rangeset); - } - - /* - * Expand simple_rte_array and simple_rel_array - */ - - if (ranges) - { - len = irange_list_length(ranges); - - /* Expand simple_rel_array and simple_rte_array */ - new_rel_array = (RelOptInfo **) - palloc0((root->simple_rel_array_size + len) * sizeof(RelOptInfo *)); - - /* simple_rte_array is an array equivalent of the rtable list */ - new_rte_array = (RangeTblEntry **) - palloc0((root->simple_rel_array_size + len) * sizeof(RangeTblEntry *)); - - /* Copy relations to the new arrays */ - for (i = 0; i < root->simple_rel_array_size; i++) - { - new_rel_array[i] = root->simple_rel_array[i]; - new_rte_array[i] = root->simple_rte_array[i]; - } - - /* Free old arrays */ - pfree(root->simple_rel_array); - pfree(root->simple_rte_array); - - root->simple_rel_array_size += len; - root->simple_rel_array = new_rel_array; - root->simple_rte_array = new_rte_array; - } - - /* - * Iterate all indexes in rangeset and append corresponding child - * relations. - */ - foreach(lc, ranges) - { - IndexRange irange = lfirst_irange(lc); - - for (i = irange_lower(irange); i <= irange_upper(irange); i++) - append_child_relation(root, rel, rti, rte, i, dsm_arr[i], wrappers); - - } - - /* Clear old path list */ - list_free(rel->pathlist); - - rel->pathlist = NIL; - set_append_rel_pathlist(root, rel, rti, rte, pathkeyAsc, pathkeyDesc); - set_append_rel_size(root, rel, rti, rte); - } -} - -static void -set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte) -{ - double parent_rows = 0; - double parent_size = 0; - ListCell *l; - - foreach(l, root->append_rel_list) - { - AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); - int childRTindex, - parentRTindex = rti; - RelOptInfo *childrel; - - /* append_rel_list contains all append rels; ignore others */ - if (appinfo->parent_relid != parentRTindex) - continue; - - childRTindex = appinfo->child_relid; - - childrel = find_base_rel(root, childRTindex); - Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL); - - /* - * Accumulate size information from each live child. - */ - Assert(childrel->rows > 0); - - parent_rows += childrel->rows; - parent_size += childrel->width * childrel->rows; - } - - rel->rows = parent_rows; - rel->width = rint(parent_size / parent_rows); - // for (i = 0; i < nattrs; i++) - // rel->attr_widths[i] = rint(parent_attrsizes[i] / parent_rows); - rel->tuples = parent_rows; -} - -/* - * Creates child relation and adds it to root. - * Returns child index in simple_rel_array - */ -static int -append_child_relation(PlannerInfo *root, RelOptInfo *rel, Index rti, - RangeTblEntry *rte, int index, Oid childOid, List *wrappers) -{ - RangeTblEntry *childrte; - RelOptInfo *childrel; - Index childRTindex; - AppendRelInfo *appinfo; - Node *node; - ListCell *lc, *lc2; - Relation newrelation; - - newrelation = heap_open(childOid, NoLock); - - /* - * Create RangeTblEntry for child relation. - * This code partially based on expand_inherited_rtentry() function. - */ - childrte = copyObject(rte); - childrte->relid = childOid; - childrte->relkind = newrelation->rd_rel->relkind; - childrte->inh = false; - childrte->requiredPerms = 0; - root->parse->rtable = lappend(root->parse->rtable, childrte); - childRTindex = list_length(root->parse->rtable); - root->simple_rte_array[childRTindex] = childrte; - - /* Create RelOptInfo */ - childrel = build_simple_rel(root, childRTindex, RELOPT_OTHER_MEMBER_REL); - - /* Copy targetlist */ - childrel->reltargetlist = NIL; - foreach(lc, rel->reltargetlist) - { - Node *new_target; - - node = (Node *) lfirst(lc); - new_target = copyObject(node); - change_varnos(new_target, rel->relid, childrel->relid); - childrel->reltargetlist = lappend(childrel->reltargetlist, new_target); - } - - /* Copy attr_needed (used in build_joinrel_tlist() function) */ - childrel->attr_needed = rel->attr_needed; - - /* Copy restrictions */ - childrel->baserestrictinfo = NIL; - forboth(lc, wrappers, lc2, rel->baserestrictinfo) - { - bool alwaysTrue; - WrapperNode *wrap = (WrapperNode *) lfirst(lc); - Node *new_clause = wrapper_make_expression(wrap, index, &alwaysTrue); - RestrictInfo *old_rinfo = (RestrictInfo *) lfirst(lc2); - - if (alwaysTrue) - { - continue; - } - Assert(new_clause); - - if (and_clause((Node *) new_clause)) - { - ListCell *alc; - - foreach(alc, ((BoolExpr *) new_clause)->args) - { - Node *arg = (Node *) lfirst(alc); - RestrictInfo *new_rinfo = rebuild_restrictinfo(arg, old_rinfo); - - change_varnos((Node *)new_rinfo, rel->relid, childrel->relid); - childrel->baserestrictinfo = lappend(childrel->baserestrictinfo, - new_rinfo); - } - } - else - { - RestrictInfo *new_rinfo = rebuild_restrictinfo(new_clause, old_rinfo); - - /* Replace old relids with new ones */ - change_varnos((Node *)new_rinfo, rel->relid, childrel->relid); - - childrel->baserestrictinfo = lappend(childrel->baserestrictinfo, - (void *) new_rinfo); - } - } - - /* Build an AppendRelInfo for this parent and child */ - appinfo = makeNode(AppendRelInfo); - appinfo->parent_relid = rti; - appinfo->child_relid = childRTindex; - appinfo->parent_reloid = rte->relid; - root->append_rel_list = lappend(root->append_rel_list, appinfo); - root->total_table_pages += (double) childrel->pages; - - /* Add equivalence members */ - foreach(lc, root->eq_classes) - { - EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc); - - /* Copy equivalence member from parent and make some modifications */ - foreach(lc2, cur_ec->ec_members) - { - EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); - EquivalenceMember *em; - - if (!bms_is_member(rti, cur_em->em_relids)) - continue; - - em = makeNode(EquivalenceMember); - em->em_expr = copyObject(cur_em->em_expr); - change_varnos((Node *) em->em_expr, rti, childRTindex); - em->em_relids = bms_add_member(NULL, childRTindex); - em->em_nullable_relids = cur_em->em_nullable_relids; - em->em_is_const = false; - em->em_is_child = true; - em->em_datatype = cur_em->em_datatype; - cur_ec->ec_members = lappend(cur_ec->ec_members, em); - } - } - childrel->has_eclass_joins = rel->has_eclass_joins; - - /* Recalc parent relation tuples count */ - rel->tuples += childrel->tuples; - - heap_close(newrelation, NoLock); - - return childRTindex; -} - -/* Create new restriction based on clause */ -static RestrictInfo * -rebuild_restrictinfo(Node *clause, RestrictInfo *old_rinfo) -{ - return make_restrictinfo((Expr *) clause, - old_rinfo->is_pushed_down, - old_rinfo->outerjoin_delayed, - old_rinfo->pseudoconstant, - old_rinfo->required_relids, - old_rinfo->outer_relids, - old_rinfo->nullable_relids); -} - -/* Convert wrapper into expression for given index */ -static Node * -wrapper_make_expression(WrapperNode *wrap, int index, bool *alwaysTrue) -{ - bool lossy, found; - - *alwaysTrue = false; - /* - * TODO: use faster algorithm using knowledge that we enumerate indexes - * sequntially. - */ - found = irange_list_find(wrap->rangeset, index, &lossy); - /* Return NULL for always true and always false. */ - if (!found) - return NULL; - if (!lossy) - { - *alwaysTrue = true; - return NULL; - } - - if (IsA(wrap->orig, BoolExpr)) - { - const BoolExpr *expr = (const BoolExpr *) wrap->orig; - BoolExpr *result; - - if (expr->boolop == OR_EXPR || expr->boolop == AND_EXPR) - { - ListCell *lc; - List *args = NIL; - - foreach (lc, wrap->args) - { - Node *arg; - bool childAlwaysTrue; - - arg = wrapper_make_expression((WrapperNode *)lfirst(lc), index, &childAlwaysTrue); -#ifdef USE_ASSERT_CHECKING - /* - * We shouldn't get there for always true clause under OR and - * always false clause under AND. - */ - if (expr->boolop == OR_EXPR) - Assert(!childAlwaysTrue); - if (expr->boolop == AND_EXPR) - Assert(arg || childAlwaysTrue); -#endif - if (arg) - args = lappend(args, arg); - } - - Assert(list_length(args) >= 1); - - /* Remove redundant OR/AND when child is single. */ - if (list_length(args) == 1) - return (Node *) linitial(args); - - result = makeNode(BoolExpr); - result->xpr.type = T_BoolExpr; - result->args = args; - result->boolop = expr->boolop; - result->location = expr->location; - return (Node *)result; - } - else - { - return copyObject(wrap->orig); - } - } - else - { - return copyObject(wrap->orig); - } -} - -/* - * Changes varno attribute in all variables nested in the node - */ -static void -change_varnos(Node *node, Oid old_varno, Oid new_varno) -{ - change_varno_context context; - context.old_varno = old_varno; - context.new_varno = new_varno; - - change_varno_walker(node, &context); -} - -static bool -change_varno_walker(Node *node, change_varno_context *context) -{ - ListCell *lc; - Var *var; - EquivalenceClass *ec; - EquivalenceMember *em; - - if (node == NULL) - return false; - - switch(node->type) - { - case T_Var: - var = (Var *) node; - if (var->varno == context->old_varno) - { - var->varno = context->new_varno; - var->varnoold = context->new_varno; - } - return false; - - case T_RestrictInfo: - change_varnos_in_restrinct_info((RestrictInfo *) node, context); - return false; - - case T_PathKey: - change_varno_walker((Node *) ((PathKey *) node)->pk_eclass, context); - return false; - - case T_EquivalenceClass: - ec = (EquivalenceClass *) node; - - foreach(lc, ec->ec_members) - change_varno_walker((Node *) lfirst(lc), context); - foreach(lc, ec->ec_derives) - change_varno_walker((Node *) lfirst(lc), context); - return false; - - case T_EquivalenceMember: - em = (EquivalenceMember *) node; - change_varno_walker((Node *) em->em_expr, context); - if (bms_is_member(context->old_varno, em->em_relids)) - { - em->em_relids = bms_del_member(em->em_relids, context->old_varno); - em->em_relids = bms_add_member(em->em_relids, context->new_varno); - } - return false; - - case T_TargetEntry: - change_varno_walker((Node *) ((TargetEntry *) node)->expr, context); - return false; - - case T_List: - foreach(lc, (List *) node) - change_varno_walker((Node *) lfirst(lc), context); - return false; - - default: - break; - } - - /* Should not find an unplanned subquery */ - Assert(!IsA(node, Query)); - - return expression_tree_walker(node, change_varno_walker, (void *) context); -} - -static void -change_varnos_in_restrinct_info(RestrictInfo *rinfo, change_varno_context *context) -{ - ListCell *lc; - - change_varno_walker((Node *) rinfo->clause, context); - if (rinfo->left_em) - change_varno_walker((Node *) rinfo->left_em->em_expr, context); - - if (rinfo->right_em) - change_varno_walker((Node *) rinfo->right_em->em_expr, context); - - if (rinfo->orclause) - foreach(lc, ((BoolExpr *) rinfo->orclause)->args) - { - Node *node = (Node *) lfirst(lc); - change_varno_walker(node, context); - } - - /* TODO: find some elegant way to do this */ - if (bms_is_member(context->old_varno, rinfo->clause_relids)) - { - rinfo->clause_relids = bms_del_member(rinfo->clause_relids, context->old_varno); - rinfo->clause_relids = bms_add_member(rinfo->clause_relids, context->new_varno); - } - if (bms_is_member(context->old_varno, rinfo->left_relids)) - { - rinfo->left_relids = bms_del_member(rinfo->left_relids, context->old_varno); - rinfo->left_relids = bms_add_member(rinfo->left_relids, context->new_varno); - } - if (bms_is_member(context->old_varno, rinfo->right_relids)) - { - rinfo->right_relids = bms_del_member(rinfo->right_relids, context->old_varno); - rinfo->right_relids = bms_add_member(rinfo->right_relids, context->new_varno); - } -} - -/* - * Recursive function to walk through conditions tree - */ -static WrapperNode * -walk_expr_tree(Expr *expr, const PartRelationInfo *prel) -{ - BoolExpr *boolexpr; - OpExpr *opexpr; - ScalarArrayOpExpr *arrexpr; - WrapperNode *result; - - switch (expr->type) - { - /* AND, OR, NOT expressions */ - case T_BoolExpr: - boolexpr = (BoolExpr *) expr; - return handle_boolexpr(boolexpr, prel); - /* =, !=, <, > etc. */ - case T_OpExpr: - opexpr = (OpExpr *) expr; - return handle_opexpr(opexpr, prel); - /* IN expression */ - case T_ScalarArrayOpExpr: - arrexpr = (ScalarArrayOpExpr *) expr; - return handle_arrexpr(arrexpr, prel); - default: - result = (WrapperNode *)palloc(sizeof(WrapperNode)); - result->orig = (const Node *)expr; - result->args = NIL; - result->rangeset = list_make1_irange(make_irange(0, prel->children_count - 1, true)); - return result; - } -} - -/* - * This function determines which partitions should appear in query plan - */ -static void -handle_binary_opexpr(const PartRelationInfo *prel, WrapperNode *result, - const Var *v, const Const *c) -{ - HashRelationKey key; - RangeRelation *rangerel; - Datum value; - int i, - int_value, - strategy; - bool is_less, - is_greater; - FmgrInfo cmp_func; - Oid cmp_proc_oid; - const OpExpr *expr = (const OpExpr *)result->orig; - TypeCacheEntry *tce; - - /* Determine operator type */ - tce = lookup_type_cache(v->vartype, - TYPECACHE_BTREE_OPFAMILY | TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO); - strategy = get_op_opfamily_strategy(expr->opno, tce->btree_opf); - cmp_proc_oid = get_opfamily_proc(tce->btree_opf, - c->consttype, - prel->atttype, - BTORDER_PROC); - fmgr_info(cmp_proc_oid, &cmp_func); - - switch (prel->parttype) - { - case PT_HASH: - if (strategy == BTEqualStrategyNumber) - { - int_value = DatumGetInt32(c->constvalue); - key.hash = make_hash(prel, int_value); - result->rangeset = list_make1_irange(make_irange(key.hash, key.hash, true)); - return; - } - case PT_RANGE: - value = c->constvalue; - rangerel = get_pathman_range_relation(prel->key.relid, NULL); - if (rangerel != NULL) - { - RangeEntry *re; - bool lossy = false; -#ifdef USE_ASSERT_CHECKING - bool found = false; - int counter = 0; -#endif - int startidx = 0, - cmp_min, - cmp_max, - endidx = rangerel->ranges.length - 1; - RangeEntry *ranges = dsm_array_get_pointer(&rangerel->ranges); - bool byVal = rangerel->by_val; - - /* Check boundaries */ - if (rangerel->ranges.length == 0) - { - result->rangeset = NIL; - return; - } - else - { - /* Corner cases */ - cmp_min = FunctionCall2(&cmp_func, value, - PATHMAN_GET_DATUM(ranges[0].min, byVal)), - cmp_max = FunctionCall2(&cmp_func, value, - PATHMAN_GET_DATUM(ranges[rangerel->ranges.length - 1].max, byVal)); - - if ((cmp_min < 0 && - (strategy == BTLessEqualStrategyNumber || - strategy == BTEqualStrategyNumber)) || - (cmp_min <= 0 && strategy == BTLessStrategyNumber)) - { - result->rangeset = NIL; - return; - } - - if (cmp_max >= 0 && (strategy == BTGreaterEqualStrategyNumber || - strategy == BTGreaterStrategyNumber || - strategy == BTEqualStrategyNumber)) - { - result->rangeset = NIL; - return; - } - - if ((cmp_min < 0 && strategy == BTGreaterStrategyNumber) || - (cmp_min <= 0 && strategy == BTGreaterEqualStrategyNumber)) - { - result->rangeset = list_make1_irange(make_irange(startidx, endidx, false)); - return; - } - - if (cmp_max >= 0 && (strategy == BTLessEqualStrategyNumber || - strategy == BTLessStrategyNumber)) - { - result->rangeset = list_make1_irange(make_irange(startidx, endidx, false)); - return; - } - } - - /* Binary search */ - while (true) - { - i = startidx + (endidx - startidx) / 2; - Assert(i >= 0 && i < rangerel->ranges.length); - re = &ranges[i]; - cmp_min = FunctionCall2(&cmp_func, value, PATHMAN_GET_DATUM(re->min, byVal)); - cmp_max = FunctionCall2(&cmp_func, value, PATHMAN_GET_DATUM(re->max, byVal)); - - is_less = (cmp_min < 0 || (cmp_min == 0 && strategy == BTLessStrategyNumber)); - is_greater = (cmp_max > 0 || (cmp_max >= 0 && strategy != BTLessStrategyNumber)); - - if (!is_less && !is_greater) - { - if (strategy == BTGreaterEqualStrategyNumber && cmp_min == 0) - lossy = false; - else if (strategy == BTLessStrategyNumber && cmp_max == 0) - lossy = false; - else - lossy = true; -#ifdef USE_ASSERT_CHECKING - found = true; -#endif - break; - } - - /* If we still didn't find partition then it doesn't exist */ - if (startidx >= endidx) - { - result->rangeset = NIL; - return; - } - - if (is_less) - endidx = i - 1; - else if (is_greater) - startidx = i + 1; - - /* For debug's sake */ - Assert(++counter < 100); - } - - Assert(found); - - /* Filter partitions */ - switch(strategy) - { - case BTLessStrategyNumber: - case BTLessEqualStrategyNumber: - if (lossy) - { - result->rangeset = list_make1_irange(make_irange(i, i, true)); - if (i > 0) - result->rangeset = lcons_irange( - make_irange(0, i - 1, false), result->rangeset); - } - else - { - result->rangeset = list_make1_irange( - make_irange(0, i, false)); - } - return; - case BTEqualStrategyNumber: - result->rangeset = list_make1_irange(make_irange(i, i, true)); - return; - case BTGreaterEqualStrategyNumber: - case BTGreaterStrategyNumber: - if (lossy) - { - result->rangeset = list_make1_irange(make_irange(i, i, true)); - if (i < prel->children_count - 1) - result->rangeset = lappend_irange(result->rangeset, - make_irange(i + 1, prel->children_count - 1, false)); - } - else - { - result->rangeset = list_make1_irange( - make_irange(i, prel->children_count - 1, false)); - } - return; - } - result->rangeset = list_make1_irange(make_irange(startidx, endidx, true)); - return; - } - } - - result->rangeset = list_make1_irange(make_irange(0, prel->children_count - 1, true)); -} - -/* - * Calculates hash value - */ -static int -make_hash(const PartRelationInfo *prel, int value) -{ - return value % prel->children_count; -} - -/* - * Search for range section. Returns position of the item in array. - * If item wasn't found then function returns closest position and sets - * foundPtr to false. If value is outside the range covered by partitions - * then returns -1. - */ -int -range_binary_search(const RangeRelation *rangerel, FmgrInfo *cmp_func, Datum value, bool *foundPtr) -{ - RangeEntry *ranges = dsm_array_get_pointer(&rangerel->ranges); - RangeEntry *re; - bool byVal = rangerel->by_val; - int cmp_min, - cmp_max, - i = 0, - startidx = 0, - endidx = rangerel->ranges.length-1; -#ifdef USE_ASSERT_CHECKING - int counter = 0; -#endif - - *foundPtr = false; - - /* Check boundaries */ - cmp_min = FunctionCall2(cmp_func, value, PATHMAN_GET_DATUM(ranges[0].min, byVal)), - cmp_max = FunctionCall2(cmp_func, value, PATHMAN_GET_DATUM(ranges[rangerel->ranges.length - 1].max, byVal)); - - if (cmp_min < 0 || cmp_max >= 0) - { - return -1; - } - - while (true) - { - i = startidx + (endidx - startidx) / 2; - Assert(i >= 0 && i < rangerel->ranges.length); - re = &ranges[i]; - cmp_min = FunctionCall2(cmp_func, value, PATHMAN_GET_DATUM(re->min, byVal)); - cmp_max = FunctionCall2(cmp_func, value, PATHMAN_GET_DATUM(re->max, byVal)); - - if (cmp_min >= 0 && cmp_max < 0) - { - *foundPtr = true; - break; - } - - if (startidx >= endidx) - return i; - - if (cmp_min < 0) - endidx = i - 1; - else if (cmp_max >= 0) - startidx = i + 1; - - /* For debug's sake */ - Assert(++counter < 100); - } - - return i; -} - -/* - * Operator expression handler - */ -static WrapperNode * -handle_opexpr(const OpExpr *expr, const PartRelationInfo *prel) -{ - WrapperNode *result = (WrapperNode *)palloc(sizeof(WrapperNode)); - Node *firstarg = NULL, - *secondarg = NULL; - - result->orig = (const Node *)expr; - result->args = NIL; - - if (list_length(expr->args) == 2) - { - firstarg = (Node *) linitial(expr->args); - secondarg = (Node *) lsecond(expr->args); - - if (IsA(firstarg, Var) && IsA(secondarg, Const) && - ((Var *)firstarg)->varattno == prel->attnum) - { - handle_binary_opexpr(prel, result, (Var *)firstarg, (Const *)secondarg); - return result; - } - else if (IsA(secondarg, Var) && IsA(firstarg, Const) && - ((Var *)secondarg)->varattno == prel->attnum) - { - handle_binary_opexpr(prel, result, (Var *)secondarg, (Const *)firstarg); - return result; - } - } - - result->rangeset = list_make1_irange(make_irange(0, prel->children_count - 1, true)); - return result; -} - -/* - * Boolean expression handler - */ -static WrapperNode * -handle_boolexpr(const BoolExpr *expr, const PartRelationInfo *prel) -{ - WrapperNode *result = (WrapperNode *)palloc(sizeof(WrapperNode)); - ListCell *lc; - - result->orig = (const Node *)expr; - result->args = NIL; - - if (expr->boolop == AND_EXPR) - result->rangeset = list_make1_irange(make_irange(0, prel->children_count - 1, false)); - else - result->rangeset = NIL; - - foreach (lc, expr->args) - { - WrapperNode *arg; - - arg = walk_expr_tree((Expr *)lfirst(lc), prel); - result->args = lappend(result->args, arg); - switch(expr->boolop) - { - case OR_EXPR: - result->rangeset = irange_list_union(result->rangeset, arg->rangeset); - break; - case AND_EXPR: - result->rangeset = irange_list_intersect(result->rangeset, arg->rangeset); - break; - default: - result->rangeset = list_make1_irange(make_irange(0, prel->children_count - 1, false)); - break; - } - } - - return result; -} - -/* - * Scalar array expression - */ -static WrapperNode * -handle_arrexpr(const ScalarArrayOpExpr *expr, const PartRelationInfo *prel) -{ - WrapperNode *result = (WrapperNode *)palloc(sizeof(WrapperNode)); - Node *varnode = (Node *) linitial(expr->args); - Node *arraynode = (Node *) lsecond(expr->args); - int hash; - - result->orig = (const Node *)expr; - result->args = NIL; - - /* If variable is not the partition key then skip it */ - if (!varnode || !IsA(varnode, Var) || ((Var *) varnode)->varattno != prel->attnum) - goto handle_arrexpr_return; - - if (arraynode && IsA(arraynode, Const) && - !((Const *) arraynode)->constisnull) - { - ArrayType *arrayval; - int16 elmlen; - bool elmbyval; - char elmalign; - int num_elems; - Datum *elem_values; - bool *elem_nulls; - int i; - - /* Extract values from array */ - arrayval = DatumGetArrayTypeP(((Const *) arraynode)->constvalue); - get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), - &elmlen, &elmbyval, &elmalign); - deconstruct_array(arrayval, - ARR_ELEMTYPE(arrayval), - elmlen, elmbyval, elmalign, - &elem_values, &elem_nulls, &num_elems); - - result->rangeset = NIL; - - /* Construct OIDs list */ - for (i = 0; i < num_elems; i++) - { - hash = make_hash(prel, elem_values[i]); - result->rangeset = irange_list_union(result->rangeset, - list_make1_irange(make_irange(hash, hash, true))); - } - - /* Free resources */ - pfree(elem_values); - pfree(elem_nulls); - - return result; - } - -handle_arrexpr_return: - result->rangeset = list_make1_irange(make_irange(0, prel->children_count - 1, true)); - return result; -} - -/* - * Theres are functions below copied from allpaths.c with (or without) some - * modifications. Couldn't use original because of 'static' modifier. - */ - -/* - * set_plain_rel_size - * Set size estimates for a plain relation (no subquery, no inheritance) - */ -static void -set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) -{ - /* - * Test any partial indexes of rel for applicability. We must do this - * first since partial unique indexes can affect size estimates. - */ - check_partial_indexes(root, rel); - - /* Mark rel with estimated output rows, width, etc */ - set_baserel_size_estimates(root, rel); -} - -/* - * set_plain_rel_pathlist - * Build access paths for a plain relation (no subquery, no inheritance) - */ -static void -set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) -{ - Relids required_outer; - Path *path; - - /* - * We don't support pushing join clauses into the quals of a seqscan, but - * it could still have required parameterization due to LATERAL refs in - * its tlist. - */ - required_outer = rel->lateral_relids; - - /* Consider sequential scan */ -#if PG_VERSION_NUM >= 90600 - path = create_seqscan_path(root, rel, required_outer, 0); -#else - path = create_seqscan_path(root, rel, required_outer); -#endif - add_path(rel, path); - // set_pathkeys(root, rel, path); - - /* Consider index scans */ - create_index_paths(root, rel); - - /* Consider TID scans */ - create_tidscan_paths(root, rel); -} - -/* - * set_foreign_size - * Set size estimates for a foreign table RTE - */ -static void -set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) -{ - /* Mark rel with estimated output rows, width, etc */ - set_foreign_size_estimates(root, rel); - - /* Let FDW adjust the size estimates, if it can */ - rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid); - - /* ... but do not let it set the rows estimate to zero */ - rel->rows = clamp_row_est(rel->rows); -} - -/* - * set_foreign_pathlist - * Build access paths for a foreign table RTE - */ -static void -set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) -{ - /* Call the FDW's GetForeignPaths function to generate path(s) */ - rel->fdwroutine->GetForeignPaths(root, rel, rte->relid); -} - -/* - * set_append_rel_pathlist - * Build access paths for an "append relation" - */ -static void -set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, - Index rti, RangeTblEntry *rte, - PathKey *pathkeyAsc, PathKey *pathkeyDesc) -{ - int parentRTindex = rti; - List *live_childrels = NIL; - List *subpaths = NIL; - bool subpaths_valid = true; - List *all_child_pathkeys = NIL; - List *all_child_outers = NIL; - ListCell *l; - - /* - * Generate access paths for each member relation, and remember the - * cheapest path for each one. Also, identify all pathkeys (orderings) - * and parameterizations (required_outer sets) available for the member - * relations. - */ - foreach(l, root->append_rel_list) - { - AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); - int childRTindex; - RangeTblEntry *childRTE; - RelOptInfo *childrel; - ListCell *lcp; - - /* append_rel_list contains all append rels; ignore others */ - if (appinfo->parent_relid != parentRTindex) - continue; - - /* Re-locate the child RTE and RelOptInfo */ - childRTindex = appinfo->child_relid; - childRTE = root->simple_rte_array[childRTindex]; - childrel = root->simple_rel_array[childRTindex]; - - /* - * Compute the child's access paths. - */ - if (childRTE->relkind == RELKIND_FOREIGN_TABLE) - { - set_foreign_size(root, childrel, childRTE); - set_foreign_pathlist(root, childrel, childRTE); - } - else - { - set_plain_rel_size(root, childrel, childRTE); - set_plain_rel_pathlist(root, childrel, childRTE); - } - set_cheapest(childrel); - - /* - * If child is dummy, ignore it. - */ - if (IS_DUMMY_REL(childrel)) - continue; - - /* - * Child is live, so add it to the live_childrels list for use below. - */ - live_childrels = lappend(live_childrels, childrel); - - /* - * If child has an unparameterized cheapest-total path, add that to - * the unparameterized Append path we are constructing for the parent. - * If not, there's no workable unparameterized path. - */ - if (childrel->cheapest_total_path->param_info == NULL) - subpaths = accumulate_append_subpath(subpaths, - childrel->cheapest_total_path); - else - subpaths_valid = false; - - /* - * Collect lists of all the available path orderings and - * parameterizations for all the children. We use these as a - * heuristic to indicate which sort orderings and parameterizations we - * should build Append and MergeAppend paths for. - */ - foreach(lcp, childrel->pathlist) - { - Path *childpath = (Path *) lfirst(lcp); - List *childkeys = childpath->pathkeys; - Relids childouter = PATH_REQ_OUTER(childpath); - - /* Unsorted paths don't contribute to pathkey list */ - if (childkeys != NIL) - { - ListCell *lpk; - bool found = false; - - /* Have we already seen this ordering? */ - foreach(lpk, all_child_pathkeys) - { - List *existing_pathkeys = (List *) lfirst(lpk); - - if (compare_pathkeys(existing_pathkeys, - childkeys) == PATHKEYS_EQUAL) - { - found = true; - break; - } - } - if (!found) - { - /* No, so add it to all_child_pathkeys */ - all_child_pathkeys = lappend(all_child_pathkeys, - childkeys); - } - } - - /* Unparameterized paths don't contribute to param-set list */ - if (childouter) - { - ListCell *lco; - bool found = false; - - /* Have we already seen this param set? */ - foreach(lco, all_child_outers) - { - Relids existing_outers = (Relids) lfirst(lco); - - if (bms_equal(existing_outers, childouter)) - { - found = true; - break; - } - } - if (!found) - { - /* No, so add it to all_child_outers */ - all_child_outers = lappend(all_child_outers, - childouter); - } - } - } - } - - /* - * If we found unparameterized paths for all children, build an unordered, - * unparameterized Append path for the rel. (Note: this is correct even - * if we have zero or one live subpath due to constraint exclusion.) - */ - if (subpaths_valid) - add_path(rel, (Path *) create_append_path(rel, subpaths, NULL)); - - /* - * Also build unparameterized MergeAppend paths based on the collected - * list of child pathkeys. - */ - if (subpaths_valid) - generate_mergeappend_paths(root, rel, live_childrels, - all_child_pathkeys, pathkeyAsc, - pathkeyDesc); -} - -static List * -accumulate_append_subpath(List *subpaths, Path *path) -{ - return lappend(subpaths, path); -} - - - - -//--------------------------------------------------------------- - -/* - * Returns the same list in reversed order. - */ -static List * -list_reverse(List *l) -{ - List *result = NIL; - ListCell *lc; - - foreach (lc, l) - { - result = lcons(lfirst(lc), result); - } - return result; -} - -/* - * generate_mergeappend_paths - * Generate MergeAppend paths for an append relation - * - * Generate a path for each ordering (pathkey list) appearing in - * all_child_pathkeys. - * - * We consider both cheapest-startup and cheapest-total cases, ie, for each - * interesting ordering, collect all the cheapest startup subpaths and all the - * cheapest total paths, and build a MergeAppend path for each case. - * - * We don't currently generate any parameterized MergeAppend paths. While - * it would not take much more code here to do so, it's very unclear that it - * is worth the planning cycles to investigate such paths: there's little - * use for an ordered path on the inside of a nestloop. In fact, it's likely - * that the current coding of add_path would reject such paths out of hand, - * because add_path gives no credit for sort ordering of parameterized paths, - * and a parameterized MergeAppend is going to be more expensive than the - * corresponding parameterized Append path. If we ever try harder to support - * parameterized mergejoin plans, it might be worth adding support for - * parameterized MergeAppends to feed such joins. (See notes in - * optimizer/README for why that might not ever happen, though.) - */ -static void -generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, - List *live_childrels, - List *all_child_pathkeys, - PathKey *pathkeyAsc, PathKey *pathkeyDesc) -{ - ListCell *lcp; - - foreach(lcp, all_child_pathkeys) - { - List *pathkeys = (List *) lfirst(lcp); - List *startup_subpaths = NIL; - List *total_subpaths = NIL; - bool startup_neq_total = false; - bool presorted = true; - ListCell *lcr; - - /* Select the child paths for this ordering... */ - foreach(lcr, live_childrels) - { - RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr); - Path *cheapest_startup, - *cheapest_total; - - /* Locate the right paths, if they are available. */ - cheapest_startup = - get_cheapest_path_for_pathkeys(childrel->pathlist, - pathkeys, - NULL, - STARTUP_COST); - cheapest_total = - get_cheapest_path_for_pathkeys(childrel->pathlist, - pathkeys, - NULL, - TOTAL_COST); - - /* - * If we can't find any paths with the right order just use the - * cheapest-total path; we'll have to sort it later. - */ - if (cheapest_startup == NULL || cheapest_total == NULL) - { - cheapest_startup = cheapest_total = - childrel->cheapest_total_path; - /* Assert we do have an unparameterized path for this child */ - Assert(cheapest_total->param_info == NULL); - presorted = false; - } - - /* - * Notice whether we actually have different paths for the - * "cheapest" and "total" cases; frequently there will be no point - * in two create_merge_append_path() calls. - */ - if (cheapest_startup != cheapest_total) - startup_neq_total = true; - - startup_subpaths = - accumulate_append_subpath(startup_subpaths, cheapest_startup); - total_subpaths = - accumulate_append_subpath(total_subpaths, cheapest_total); - } - - /* - * When first pathkey matching ascending/descending sort by partition - * column then build path with Append node, because MergeAppend is not - * required in this case. - */ - if ((PathKey *) linitial(pathkeys) == pathkeyAsc && presorted) - { - Path *path; - - path = (Path *) create_append_path(rel, startup_subpaths, NULL); - path->pathkeys = pathkeys; - add_path(rel, path); - - if (startup_neq_total) - { - path = (Path *) create_append_path(rel, total_subpaths, NULL); - path->pathkeys = pathkeys; - add_path(rel, path); - } - } - else if ((PathKey *) linitial(pathkeys) == pathkeyDesc && presorted) - { - /* - * When pathkey is descending sort by partition column then we - * need to scan partitions in reversed order. - */ - Path *path; - - path = (Path *) create_append_path(rel, - list_reverse(startup_subpaths), NULL); - path->pathkeys = pathkeys; - add_path(rel, path); - - if (startup_neq_total) - { - path = (Path *) create_append_path(rel, - list_reverse(total_subpaths), NULL); - path->pathkeys = pathkeys; - add_path(rel, path); - } - } - else - { - /* ... and build the MergeAppend paths */ - add_path(rel, (Path *) create_merge_append_path(root, - rel, - startup_subpaths, - pathkeys, - NULL)); - if (startup_neq_total) - add_path(rel, (Path *) create_merge_append_path(root, - rel, - total_subpaths, - pathkeys, - NULL)); - } - } -} diff --git a/contrib/pg_pathman/pg_pathman.control b/contrib/pg_pathman/pg_pathman.control index d42ea8c09d..ecc4ef641f 100644 --- a/contrib/pg_pathman/pg_pathman.control +++ b/contrib/pg_pathman/pg_pathman.control @@ -1,4 +1,4 @@ # pg_pathman extension -comment 'Partitioning tool' -default_version = '0.1' +comment 'Partitioning tool ver. 1.0' +default_version = '1.0' module_pathname='$libdir/pg_pathman' diff --git a/contrib/pg_pathman/pl_funcs.c b/contrib/pg_pathman/pl_funcs.c deleted file mode 100644 index 48314fd90b..0000000000 --- a/contrib/pg_pathman/pl_funcs.c +++ /dev/null @@ -1,386 +0,0 @@ -/* ------------------------------------------------------------------------ - * - * pl_funcs.c - * Utility C functions for stored procedures - * - * Copyright (c) 2015-2016, Postgres Professional - * - * ------------------------------------------------------------------------ - */ -#include "pathman.h" -#include "utils/lsyscache.h" -#include "utils/typcache.h" -#include "utils/array.h" -#include "utils/snapmgr.h" -#include "access/nbtree.h" -#include "access/xact.h" -#include "catalog/pg_type.h" -#include "executor/spi.h" -#include "storage/lmgr.h" - - -/* declarations */ -PG_FUNCTION_INFO_V1( on_partitions_created ); -PG_FUNCTION_INFO_V1( on_partitions_updated ); -PG_FUNCTION_INFO_V1( on_partitions_removed ); -PG_FUNCTION_INFO_V1( find_or_create_range_partition); -PG_FUNCTION_INFO_V1( get_range_by_idx ); -PG_FUNCTION_INFO_V1( get_partition_range ); -PG_FUNCTION_INFO_V1( acquire_partitions_lock ); -PG_FUNCTION_INFO_V1( release_partitions_lock ); -PG_FUNCTION_INFO_V1( check_overlap ); -PG_FUNCTION_INFO_V1( get_min_range_value ); -PG_FUNCTION_INFO_V1( get_max_range_value ); - -/* - * Callbacks - */ -Datum -on_partitions_created(PG_FUNCTION_ARGS) -{ - LWLockAcquire(pmstate->load_config_lock, LW_EXCLUSIVE); - - /* Reload config */ - /* TODO: reload just the specified relation */ - load_relations_hashtable(false); - - LWLockRelease(pmstate->load_config_lock); - - PG_RETURN_NULL(); -} - -Datum -on_partitions_updated(PG_FUNCTION_ARGS) -{ - Oid relid; - PartRelationInfo *prel; - - /* Parent relation oid */ - relid = DatumGetInt32(PG_GETARG_DATUM(0)); - prel = get_pathman_relation_info(relid, NULL); - if (prel != NULL) - { - LWLockAcquire(pmstate->load_config_lock, LW_EXCLUSIVE); - remove_relation_info(relid); - load_relations_hashtable(false); - LWLockRelease(pmstate->load_config_lock); - } - - PG_RETURN_NULL(); -} - -Datum -on_partitions_removed(PG_FUNCTION_ARGS) -{ - Oid relid; - - LWLockAcquire(pmstate->load_config_lock, LW_EXCLUSIVE); - - /* parent relation oid */ - relid = DatumGetInt32(PG_GETARG_DATUM(0)); - remove_relation_info(relid); - - LWLockRelease(pmstate->load_config_lock); - - PG_RETURN_NULL(); -} - -/* - * Returns partition oid for specified parent relid and value. - * In case when partition isn't exist try to create one. - */ -Datum -find_or_create_range_partition(PG_FUNCTION_ARGS) -{ - int relid = DatumGetInt32(PG_GETARG_DATUM(0)); - Datum value = PG_GETARG_DATUM(1); - Oid value_type = get_fn_expr_argtype(fcinfo->flinfo, 1); - int pos; - bool found; - RangeRelation *rangerel; - RangeEntry *ranges; - TypeCacheEntry *tce; - PartRelationInfo *prel; - Oid cmp_proc_oid; - FmgrInfo cmp_func; - - tce = lookup_type_cache(value_type, - TYPECACHE_EQ_OPR | TYPECACHE_LT_OPR | TYPECACHE_GT_OPR | - TYPECACHE_CMP_PROC | TYPECACHE_CMP_PROC_FINFO); - - prel = get_pathman_relation_info(relid, NULL); - rangerel = get_pathman_range_relation(relid, NULL); - - if (!prel || !rangerel) - PG_RETURN_NULL(); - - cmp_proc_oid = get_opfamily_proc(tce->btree_opf, - value_type, - prel->atttype, - BTORDER_PROC); - fmgr_info(cmp_proc_oid, &cmp_func); - - ranges = dsm_array_get_pointer(&rangerel->ranges); - pos = range_binary_search(rangerel, &cmp_func, value, &found); - - /* - * If found then just return oid. Else create new partitions - */ - if (found) - PG_RETURN_OID(ranges[pos].child_oid); - /* - * If not found and value is between first and last partitions - */ - if (!found && pos >= 0) - PG_RETURN_NULL(); - else - { - Oid child_oid; - bool crashed = false; - - /* Lock config before appending new partitions */ - LWLockAcquire(pmstate->load_config_lock, LW_EXCLUSIVE); - - /* Restrict concurrent partition creation */ - LWLockAcquire(pmstate->edit_partitions_lock, LW_EXCLUSIVE); - - /* - * Check if someone else has already created partition. - */ - ranges = dsm_array_get_pointer(&rangerel->ranges); - pos = range_binary_search(rangerel, &cmp_func, value, &found); - if (found) - { - LWLockRelease(pmstate->edit_partitions_lock); - LWLockRelease(pmstate->load_config_lock); - PG_RETURN_OID(ranges[pos].child_oid); - } - - /* Start background worker to create new partitions */ - child_oid = create_partitions_bg_worker(relid, value, value_type, &crashed); - - // SPI_connect(); - // child_oid = create_partitions(relid, value, value_type, &crashed); - // SPI_finish(); - // elog(WARNING, "Worker finished"); - - /* Release locks */ - if (!crashed) - { - LWLockRelease(pmstate->edit_partitions_lock); - LWLockRelease(pmstate->load_config_lock); - } - - /* Repeat binary search */ - ranges = dsm_array_get_pointer(&rangerel->ranges); - pos = range_binary_search(rangerel, &cmp_func, value, &found); - if (found) - PG_RETURN_OID(child_oid); - } - - PG_RETURN_NULL(); -} - -/* - * Returns range (min, max) as output parameters - * - * first argument is the parent relid - * second is the partition relid - * third and forth are MIN and MAX output parameters - */ -Datum -get_partition_range(PG_FUNCTION_ARGS) -{ - int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0)); - int child_oid = DatumGetInt32(PG_GETARG_DATUM(1)); - int nelems = 2; - int i; - bool found = false; - Datum *elems; - PartRelationInfo *prel; - RangeRelation *rangerel; - RangeEntry *ranges; - TypeCacheEntry *tce; - ArrayType *arr; - - prel = get_pathman_relation_info(parent_oid, NULL); - - rangerel = get_pathman_range_relation(parent_oid, NULL); - - if (!prel || !rangerel) - PG_RETURN_NULL(); - - ranges = dsm_array_get_pointer(&rangerel->ranges); - tce = lookup_type_cache(prel->atttype, 0); - - /* Looking for specified partition */ - for(i=0; iranges.length; i++) - if (ranges[i].child_oid == child_oid) - { - found = true; - break; - } - - if (found) - { - bool byVal = rangerel->by_val; - - elems = palloc(nelems * sizeof(Datum)); - elems[0] = PATHMAN_GET_DATUM(ranges[i].min, byVal); - elems[1] = PATHMAN_GET_DATUM(ranges[i].max, byVal); - - arr = construct_array(elems, nelems, prel->atttype, - tce->typlen, tce->typbyval, tce->typalign); - PG_RETURN_ARRAYTYPE_P(arr); - } - - PG_RETURN_NULL(); -} - - -/* - * Returns N-th range (in form of array) - * - * First argument is the parent relid. - * Second argument is the index of the range (if it is negative then the last - * range will be returned). - */ -Datum -get_range_by_idx(PG_FUNCTION_ARGS) -{ - int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0)); - int idx = DatumGetInt32(PG_GETARG_DATUM(1)); - PartRelationInfo *prel; - RangeRelation *rangerel; - RangeEntry *ranges; - RangeEntry *re; - Datum *elems; - TypeCacheEntry *tce; - - prel = get_pathman_relation_info(parent_oid, NULL); - - rangerel = get_pathman_range_relation(parent_oid, NULL); - - if (!prel || !rangerel || idx >= (int)rangerel->ranges.length) - PG_RETURN_NULL(); - - tce = lookup_type_cache(prel->atttype, 0); - ranges = dsm_array_get_pointer(&rangerel->ranges); - if (idx >= 0) - re = &ranges[idx]; - else - re = &ranges[rangerel->ranges.length - 1]; - - elems = palloc(2 * sizeof(Datum)); - elems[0] = PATHMAN_GET_DATUM(re->min, rangerel->by_val); - elems[1] = PATHMAN_GET_DATUM(re->max, rangerel->by_val); - - PG_RETURN_ARRAYTYPE_P( - construct_array(elems, 2, prel->atttype, - tce->typlen, tce->typbyval, tce->typalign)); -} - -/* - * Returns min value of the first range for relation - */ -Datum -get_min_range_value(PG_FUNCTION_ARGS) -{ - int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0)); - PartRelationInfo *prel; - RangeRelation *rangerel; - RangeEntry *ranges; - - prel = get_pathman_relation_info(parent_oid, NULL); - rangerel = get_pathman_range_relation(parent_oid, NULL); - - if (!prel || !rangerel || prel->parttype != PT_RANGE || rangerel->ranges.length == 0) - PG_RETURN_NULL(); - - ranges = dsm_array_get_pointer(&rangerel->ranges); - PG_RETURN_DATUM(PATHMAN_GET_DATUM(ranges[0].min, rangerel->by_val)); -} - -/* - * Returns max value of the last range for relation - */ -Datum -get_max_range_value(PG_FUNCTION_ARGS) -{ - int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0)); - PartRelationInfo *prel; - RangeRelation *rangerel; - RangeEntry *ranges; - - prel = get_pathman_relation_info(parent_oid, NULL); - rangerel = get_pathman_range_relation(parent_oid, NULL); - - if (!prel || !rangerel || prel->parttype != PT_RANGE || rangerel->ranges.length == 0) - PG_RETURN_NULL(); - - ranges = dsm_array_get_pointer(&rangerel->ranges); - PG_RETURN_DATUM(PATHMAN_GET_DATUM(ranges[rangerel->ranges.length-1].max, rangerel->by_val)); -} - -/* - * Checks if range overlaps with existing partitions. - * Returns TRUE if overlaps and FALSE otherwise. - */ -Datum -check_overlap(PG_FUNCTION_ARGS) -{ - int parent_oid = DatumGetInt32(PG_GETARG_DATUM(0)); - Datum p1 = PG_GETARG_DATUM(1); - Oid p1_type = get_fn_expr_argtype(fcinfo->flinfo, 1); - Datum p2 = PG_GETARG_DATUM(2); - Oid p2_type = get_fn_expr_argtype(fcinfo->flinfo, 2); - PartRelationInfo *prel; - RangeRelation *rangerel; - RangeEntry *ranges; - FmgrInfo cmp_func_1; - FmgrInfo cmp_func_2; - int i; - bool byVal; - - prel = get_pathman_relation_info(parent_oid, NULL); - rangerel = get_pathman_range_relation(parent_oid, NULL); - - if (!prel || !rangerel || prel->parttype != PT_RANGE) - PG_RETURN_NULL(); - - /* comparison functions */ - cmp_func_1 = *get_cmp_func(p1_type, prel->atttype); - cmp_func_2 = *get_cmp_func(p2_type, prel->atttype); - - byVal = rangerel->by_val; - ranges = (RangeEntry *) dsm_array_get_pointer(&rangerel->ranges); - for (i=0; iranges.length; i++) - { - int c1 = FunctionCall2(&cmp_func_1, p1, - PATHMAN_GET_DATUM(ranges[i].max, byVal)); - int c2 = FunctionCall2(&cmp_func_2, p2, - PATHMAN_GET_DATUM(ranges[i].min, byVal)); - - if (c1 < 0 && c2 > 0) - PG_RETURN_BOOL(true); - } - - PG_RETURN_BOOL(false); -} - -/* - * Acquire partitions lock - */ -Datum -acquire_partitions_lock(PG_FUNCTION_ARGS) -{ - LWLockAcquire(pmstate->edit_partitions_lock, LW_EXCLUSIVE); - PG_RETURN_NULL(); -} - -Datum -release_partitions_lock(PG_FUNCTION_ARGS) -{ - LWLockRelease(pmstate->edit_partitions_lock); - PG_RETURN_NULL(); -} diff --git a/contrib/pg_pathman/range.sql b/contrib/pg_pathman/range.sql index 43728938e1..dfad1fdcd8 100644 --- a/contrib/pg_pathman/range.sql +++ b/contrib/pg_pathman/range.sql @@ -8,18 +8,24 @@ * ------------------------------------------------------------------------ */ -CREATE OR REPLACE FUNCTION @extschema@.get_sequence_name(plain_schema TEXT, plain_relname TEXT) +CREATE OR REPLACE FUNCTION @extschema@.get_sequence_name( + plain_schema TEXT, + plain_relname TEXT) RETURNS TEXT AS $$ BEGIN - RETURN format('%s.%s', plain_schema, quote_ident(format('%s_seq', plain_relname))); + RETURN format('%s.%s', + quote_ident(plain_schema), + quote_ident(format('%s_seq', plain_relname))); END $$ LANGUAGE plpgsql; -CREATE OR REPLACE FUNCTION @extschema@.create_or_replace_sequence(plain_schema TEXT, plain_relname TEXT, OUT seq_name TEXT) +CREATE OR REPLACE FUNCTION @extschema@.create_or_replace_sequence( + plain_schema TEXT, + plain_relname TEXT, + OUT seq_name TEXT) AS $$ -DECLARE BEGIN seq_name := @extschema@.get_sequence_name(plain_schema, plain_relname); EXECUTE format('DROP SEQUENCE IF EXISTS %s', seq_name); @@ -28,38 +34,91 @@ END $$ LANGUAGE plpgsql; +/* + * Check RANGE partition boundaries. + */ +CREATE OR REPLACE FUNCTION @extschema@.check_boundaries( + parent_relid REGCLASS, + p_attribute TEXT, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT) +RETURNS VOID AS +$$ +DECLARE + v_min p_start_value%TYPE; + v_max p_start_value%TYPE; + v_count BIGINT; + +BEGIN + /* Get min and max values */ + EXECUTE format('SELECT count(*), min(%1$s), max(%1$s) + FROM %2$s WHERE NOT %1$s IS NULL', + p_attribute, parent_relid::TEXT) + INTO v_count, v_min, v_max; + + /* Check if column has NULL values */ + IF v_count > 0 AND (v_min IS NULL OR v_max IS NULL) THEN + RAISE EXCEPTION '''%'' column contains NULL values', p_attribute; + END IF; + + /* Check lower boundary */ + IF p_start_value > v_min THEN + RAISE EXCEPTION 'start value is less than minimum value of ''%''', + p_attribute; + END IF; + + /* Check upper boundary */ + IF p_end_value <= v_max THEN + RAISE EXCEPTION 'not enough partitions to fit all values of ''%''', + p_attribute; + END IF; +END +$$ LANGUAGE plpgsql; + /* * Creates RANGE partitions for specified relation based on datetime attribute */ CREATE OR REPLACE FUNCTION @extschema@.create_range_partitions( - p_relation REGCLASS - , p_attribute TEXT - , p_start_value ANYELEMENT - , p_interval INTERVAL - , p_count INTEGER DEFAULT NULL) + parent_relid REGCLASS, + p_attribute TEXT, + p_start_value ANYELEMENT, + p_interval INTERVAL, + p_count INTEGER DEFAULT NULL, + partition_data BOOLEAN DEFAULT TRUE) RETURNS INTEGER AS $$ DECLARE - v_relname TEXT; - v_rows_count INTEGER; - v_max p_start_value%TYPE; - v_cur_value p_start_value%TYPE := p_start_value; - v_plain_relname TEXT; - v_plain_schema TEXT; - i INTEGER; + v_rows_count INTEGER; + v_atttype REGTYPE; + v_max p_start_value%TYPE; + v_cur_value p_start_value%TYPE := p_start_value; + p_end_value p_start_value%TYPE; + i INTEGER; + BEGIN - v_relname := @extschema@.validate_relname(p_relation); + IF partition_data = true THEN + /* Acquire data modification lock */ + PERFORM @extschema@.prevent_relation_modification(parent_relid); + ELSE + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + END IF; + + PERFORM @extschema@.validate_relname(parent_relid); p_attribute := lower(p_attribute); - PERFORM @extschema@.common_relation_checks(v_relname, p_attribute); + PERFORM @extschema@.common_relation_checks(parent_relid, p_attribute); + + IF p_count < 0 THEN + RAISE EXCEPTION '''p_count'' must not be less than 0'; + END IF; /* Try to determine partitions count if not set */ IF p_count IS NULL THEN - EXECUTE format('SELECT count(*), max(%s) FROM %s' - , p_attribute, p_relation) + EXECUTE format('SELECT count(*), max(%s) FROM %s', p_attribute, parent_relid) INTO v_rows_count, v_max; IF v_rows_count = 0 THEN - RAISE EXCEPTION 'Cannot determine partitions count for empty table'; + RAISE EXCEPTION 'cannot determine partitions count for empty table'; END IF; p_count := 0; @@ -70,45 +129,64 @@ BEGIN END LOOP; END IF; - /* Check boundaries */ - EXECUTE format('SELECT @extschema@.check_boundaries(''%s'', ''%s'', ''%s'', ''%s''::%s)' - , v_relname - , p_attribute - , p_start_value - , p_start_value + p_interval*p_count - , pg_typeof(p_start_value)); + v_atttype := @extschema@.get_base_type(pg_typeof(p_start_value)); + + /* + * In case when user doesn't want to automatically create partitions + * and specifies partition count as 0 then do not check boundaries + */ + IF p_count != 0 THEN + /* compute right bound of partitioning through additions */ + p_end_value := p_start_value; + FOR i IN 1..p_count + LOOP + p_end_value := p_end_value + p_interval; + END LOOP; + + /* Check boundaries */ + EXECUTE format('SELECT @extschema@.check_boundaries(''%s'', ''%s'', ''%s'', ''%s''::%s)', + parent_relid, + p_attribute, + p_start_value, + p_end_value, + v_atttype::TEXT); + END IF; /* Create sequence for child partitions names */ - SELECT * INTO v_plain_schema, v_plain_relname FROM @extschema@.get_plain_schema_and_relname(p_relation); - PERFORM @extschema@.create_or_replace_sequence(v_plain_schema, v_plain_relname); + PERFORM @extschema@.create_or_replace_sequence(schema, relname) + FROM @extschema@.get_plain_schema_and_relname(parent_relid); /* Insert new entry to pathman config */ - INSERT INTO @extschema@.pathman_config (relname, attname, parttype, range_interval) - VALUES (v_relname, p_attribute, 2, p_interval::text); + INSERT INTO @extschema@.pathman_config (partrel, attname, parttype, range_interval) + VALUES (parent_relid, p_attribute, 2, p_interval::TEXT); - /* create first partition */ + /* Create first partition */ FOR i IN 1..p_count LOOP - EXECUTE format('SELECT @extschema@.create_single_range_partition($1, $2, $3::%s);', pg_typeof(p_start_value)) - USING v_relname, p_start_value, p_start_value + p_interval; + EXECUTE + format('SELECT @extschema@.create_single_range_partition($1, $2, $3::%s, tablespace:=$4)', + v_atttype::TEXT) + USING + parent_relid, + p_start_value, + p_start_value + p_interval, + @extschema@.get_rel_tablespace_name(parent_relid); p_start_value := p_start_value + p_interval; END LOOP; - /* Create triggers */ - PERFORM @extschema@.create_range_insert_trigger(v_relname, p_attribute); - -- PERFORM create_hash_update_trigger(relation, attribute, partitions_count); /* Notify backend about changes */ - PERFORM @extschema@.on_create_partitions(p_relation::oid); + PERFORM @extschema@.on_create_partitions(parent_relid); - /* Copy data */ - PERFORM @extschema@.partition_data(p_relation); + /* Relocate data if asked to */ + IF partition_data = true THEN + PERFORM @extschema@.set_enable_parent(parent_relid, false); + PERFORM @extschema@.partition_data(parent_relid); + ELSE + PERFORM @extschema@.set_enable_parent(parent_relid, true); + END IF; RETURN p_count; - -EXCEPTION WHEN others THEN - PERFORM @extschema@.on_remove_partitions(p_relation::integer); - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; END $$ LANGUAGE plpgsql; @@ -116,38 +194,45 @@ $$ LANGUAGE plpgsql; * Creates RANGE partitions for specified relation based on numerical attribute */ CREATE OR REPLACE FUNCTION @extschema@.create_range_partitions( - p_relation REGCLASS - , p_attribute TEXT - , p_start_value ANYELEMENT - , p_interval ANYELEMENT - , p_count INTEGER DEFAULT NULL) + parent_relid REGCLASS, + p_attribute TEXT, + p_start_value ANYELEMENT, + p_interval ANYELEMENT, + p_count INTEGER DEFAULT NULL, + partition_data BOOLEAN DEFAULT TRUE) RETURNS INTEGER AS $$ DECLARE - v_relname TEXT; - v_rows_count INTEGER; - v_max p_start_value%TYPE; - v_cur_value p_start_value%TYPE := p_start_value; - i INTEGER; - v_plain_schema TEXT; - v_plain_relname TEXT; + v_rows_count INTEGER; + v_max p_start_value%TYPE; + v_cur_value p_start_value%TYPE := p_start_value; + p_end_value p_start_value%TYPE; + i INTEGER; + BEGIN - v_relname := @extschema@.validate_relname(p_relation); + IF partition_data = true THEN + /* Acquire data modification lock */ + PERFORM @extschema@.prevent_relation_modification(parent_relid); + ELSE + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + END IF; + + PERFORM @extschema@.validate_relname(parent_relid); p_attribute := lower(p_attribute); - PERFORM @extschema@.common_relation_checks(p_relation, p_attribute); + PERFORM @extschema@.common_relation_checks(parent_relid, p_attribute); - IF p_count <= 0 THEN - RAISE EXCEPTION 'Partitions count must be greater than zero'; + IF p_count < 0 THEN + RAISE EXCEPTION 'partitions count must not be less than zero'; END IF; /* Try to determine partitions count if not set */ IF p_count IS NULL THEN - EXECUTE format('SELECT count(*), max(%s) FROM %s' - , p_attribute, p_relation) + EXECUTE format('SELECT count(*), max(%s) FROM %s', p_attribute, parent_relid) INTO v_rows_count, v_max; IF v_rows_count = 0 THEN - RAISE EXCEPTION 'Cannot determine partitions count for empty table'; + RAISE EXCEPTION 'cannot determine partitions count for empty table'; END IF; IF v_max IS NULL THEN @@ -162,43 +247,57 @@ BEGIN END LOOP; END IF; - /* check boundaries */ - PERFORM @extschema@.check_boundaries(p_relation - , p_attribute - , p_start_value - , p_start_value + p_interval*p_count); + /* + * In case when user doesn't want to automatically create partitions + * and specifies partition count as 0 then do not check boundaries + */ + IF p_count != 0 THEN + /* compute right bound of partitioning through additions */ + p_end_value := p_start_value; + FOR i IN 1..p_count + LOOP + p_end_value := p_end_value + p_interval; + END LOOP; + + /* check boundaries */ + PERFORM @extschema@.check_boundaries(parent_relid, + p_attribute, + p_start_value, + p_end_value); + END IF; /* Create sequence for child partitions names */ - SELECT * INTO v_plain_schema, v_plain_relname FROM @extschema@.get_plain_schema_and_relname(p_relation); - PERFORM @extschema@.create_or_replace_sequence(v_plain_schema, v_plain_relname); + PERFORM @extschema@.create_or_replace_sequence(schema, relname) + FROM @extschema@.get_plain_schema_and_relname(parent_relid); /* Insert new entry to pathman config */ - INSERT INTO @extschema@.pathman_config (relname, attname, parttype, range_interval) - VALUES (v_relname, p_attribute, 2, p_interval::text); + INSERT INTO @extschema@.pathman_config (partrel, attname, parttype, range_interval) + VALUES (parent_relid, p_attribute, 2, p_interval::TEXT); /* create first partition */ FOR i IN 1..p_count LOOP - PERFORM @extschema@.create_single_range_partition(p_relation - , p_start_value - , p_start_value + p_interval); + PERFORM @extschema@.create_single_range_partition( + parent_relid, + p_start_value, + p_start_value + p_interval, + tablespace := @extschema@.get_rel_tablespace_name(parent_relid)); + p_start_value := p_start_value + p_interval; END LOOP; - /* Create triggers */ - PERFORM @extschema@.create_range_insert_trigger(p_relation, p_attribute); - -- PERFORM create_hash_update_trigger(relation, attribute, partitions_count); /* Notify backend about changes */ - PERFORM @extschema@.on_create_partitions(p_relation::regclass::oid); + PERFORM @extschema@.on_create_partitions(parent_relid); - /* Copy data */ - PERFORM @extschema@.partition_data(p_relation); + /* Relocate data if asked to */ + IF partition_data = true THEN + PERFORM @extschema@.set_enable_parent(parent_relid, false); + PERFORM @extschema@.partition_data(parent_relid); + ELSE + PERFORM @extschema@.set_enable_parent(parent_relid, true); + END IF; RETURN p_count; - -EXCEPTION WHEN others THEN - PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer); - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; END $$ LANGUAGE plpgsql; @@ -206,64 +305,72 @@ $$ LANGUAGE plpgsql; * Creates RANGE partitions for specified range */ CREATE OR REPLACE FUNCTION @extschema@.create_partitions_from_range( - p_relation REGCLASS - , p_attribute TEXT - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT - , p_interval ANYELEMENT) + parent_relid REGCLASS, + p_attribute TEXT, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT, + p_interval ANYELEMENT, + partition_data BOOLEAN DEFAULT TRUE) RETURNS INTEGER AS $$ DECLARE - v_relname TEXT; - v_plain_schema TEXT; - v_plain_relname TEXT; - i INTEGER := 0; + part_count INTEGER := 0; + BEGIN - v_relname := @extschema@.validate_relname(p_relation); + IF partition_data = true THEN + /* Acquire data modification lock */ + PERFORM @extschema@.prevent_relation_modification(parent_relid); + ELSE + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + END IF; + + PERFORM @extschema@.validate_relname(parent_relid); p_attribute := lower(p_attribute); - PERFORM @extschema@.common_relation_checks(p_relation, p_attribute); + PERFORM @extschema@.common_relation_checks(parent_relid, p_attribute); IF p_interval <= 0 THEN - RAISE EXCEPTION 'Interval must be positive'; + RAISE EXCEPTION 'interval must be positive'; END IF; - /* Create sequence for child partitions names */ - SELECT * INTO v_plain_schema, v_plain_relname FROM @extschema@.get_plain_schema_and_relname(p_relation); - PERFORM @extschema@.create_or_replace_sequence(v_plain_schema, v_plain_relname); + /* Check boundaries */ + PERFORM @extschema@.check_boundaries(parent_relid, + p_attribute, + p_start_value, + p_end_value); - /* check boundaries */ - PERFORM @extschema@.check_boundaries(p_relation - , p_attribute - , p_start_value - , p_end_value); + /* Create sequence for child partitions names */ + PERFORM @extschema@.create_or_replace_sequence(schema, relname) + FROM @extschema@.get_plain_schema_and_relname(parent_relid); /* Insert new entry to pathman config */ - INSERT INTO @extschema@.pathman_config (relname, attname, parttype, range_interval) - VALUES (v_relname, p_attribute, 2, p_interval::text); + INSERT INTO @extschema@.pathman_config (partrel, attname, parttype, range_interval) + VALUES (parent_relid, p_attribute, 2, p_interval::TEXT); WHILE p_start_value <= p_end_value LOOP - PERFORM @extschema@.create_single_range_partition(p_relation - , p_start_value - , p_start_value + p_interval); + PERFORM @extschema@.create_single_range_partition( + parent_relid, + p_start_value, + p_start_value + p_interval, + tablespace := @extschema@.get_rel_tablespace_name(parent_relid)); + p_start_value := p_start_value + p_interval; - i := i + 1; + part_count := part_count + 1; END LOOP; - /* Create triggers */ - PERFORM @extschema@.create_range_insert_trigger(p_relation, p_attribute); - /* Notify backend about changes */ - PERFORM @extschema@.on_create_partitions(p_relation::regclass::oid); - - /* Copy data */ - PERFORM @extschema@.partition_data(p_relation); + PERFORM @extschema@.on_create_partitions(parent_relid); - RETURN i; + /* Relocate data if asked to */ + IF partition_data = true THEN + PERFORM @extschema@.set_enable_parent(parent_relid, false); + PERFORM @extschema@.partition_data(parent_relid); + ELSE + PERFORM @extschema@.set_enable_parent(parent_relid, true); + END IF; -EXCEPTION WHEN others THEN - PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer); - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; + RETURN part_count; /* number of created partitions */ END $$ LANGUAGE plpgsql; @@ -271,288 +378,261 @@ $$ LANGUAGE plpgsql; * Creates RANGE partitions for specified range based on datetime attribute */ CREATE OR REPLACE FUNCTION @extschema@.create_partitions_from_range( - p_relation REGCLASS - , p_attribute TEXT - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT - , p_interval INTERVAL) + parent_relid REGCLASS, + p_attribute TEXT, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT, + p_interval INTERVAL, + partition_data BOOLEAN DEFAULT TRUE) RETURNS INTEGER AS $$ DECLARE - v_relname TEXT; - v_plain_schema TEXT; - v_plain_relname TEXT; - i INTEGER := 0; + part_count INTEGER := 0; + BEGIN - v_relname := @extschema@.validate_relname(p_relation); + IF partition_data = true THEN + /* Acquire data modification lock */ + PERFORM @extschema@.prevent_relation_modification(parent_relid); + ELSE + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + END IF; + + PERFORM @extschema@.validate_relname(parent_relid); p_attribute := lower(p_attribute); - PERFORM @extschema@.common_relation_checks(p_relation, p_attribute); + PERFORM @extschema@.common_relation_checks(parent_relid, p_attribute); - /* Create sequence for child partitions names */ - SELECT * INTO v_plain_schema, v_plain_relname FROM @extschema@.get_plain_schema_and_relname(p_relation); - PERFORM @extschema@.create_or_replace_sequence(v_plain_schema, v_plain_relname); + /* Check boundaries */ + PERFORM @extschema@.check_boundaries(parent_relid, + p_attribute, + p_start_value, + p_end_value); - /* check boundaries */ - PERFORM @extschema@.check_boundaries(p_relation - , p_attribute - , p_start_value - , p_end_value); + /* Create sequence for child partitions names */ + PERFORM @extschema@.create_or_replace_sequence(schema, relname) + FROM @extschema@.get_plain_schema_and_relname(parent_relid); /* Insert new entry to pathman config */ - INSERT INTO @extschema@.pathman_config (relname, attname, parttype, range_interval) - VALUES (v_relname, p_attribute, 2, p_interval::text); + INSERT INTO @extschema@.pathman_config (partrel, attname, parttype, range_interval) + VALUES (parent_relid, p_attribute, 2, p_interval::TEXT); WHILE p_start_value <= p_end_value LOOP - EXECUTE format('SELECT @extschema@.create_single_range_partition($1, $2, $3::%s);', pg_typeof(p_start_value)) - USING p_relation, p_start_value, p_start_value + p_interval; + EXECUTE + format('SELECT @extschema@.create_single_range_partition($1, $2, $3::%s, tablespace:=$4);', + @extschema@.get_base_type(pg_typeof(p_start_value))::TEXT) + USING + parent_relid, + p_start_value, + p_start_value + p_interval, + @extschema@.get_rel_tablespace_name(parent_relid); + p_start_value := p_start_value + p_interval; - i := i + 1; + part_count := part_count + 1; END LOOP; - /* Create triggers */ - PERFORM @extschema@.create_range_insert_trigger(p_relation, p_attribute); - /* Notify backend about changes */ - PERFORM @extschema@.on_create_partitions(p_relation::regclass::oid); - - /* Copy data */ - PERFORM @extschema@.partition_data(p_relation); - - RETURN i; - -EXCEPTION WHEN others THEN - PERFORM @extschema@.on_remove_partitions(p_relation::regclass::integer); - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; -END -$$ LANGUAGE plpgsql; - -/* - * - */ -CREATE OR REPLACE FUNCTION @extschema@.check_boundaries( - p_relation REGCLASS - , p_attribute TEXT - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT) -RETURNS VOID AS -$$ -DECLARE - v_min p_start_value%TYPE; - v_max p_start_value%TYPE; - v_count INTEGER; -BEGIN - /* Get min and max values */ - EXECUTE format('SELECT count(*), min(%s), max(%s) FROM %s WHERE NOT %s IS NULL', - p_attribute, p_attribute, p_relation::text, p_attribute) - INTO v_count, v_min, v_max; + PERFORM @extschema@.on_create_partitions(parent_relid); - /* check if column has NULL values */ - IF v_count > 0 AND (v_min IS NULL OR v_max IS NULL) THEN - RAISE EXCEPTION '''%'' column has NULL values', p_attribute; - END IF; - - /* check lower boundary */ - IF p_start_value > v_min THEN - RAISE EXCEPTION 'Start value is less than minimum value of ''%''' - , p_attribute; + /* Relocate data if asked to */ + IF partition_data = true THEN + PERFORM @extschema@.set_enable_parent(parent_relid, false); + PERFORM @extschema@.partition_data(parent_relid); + ELSE + PERFORM @extschema@.set_enable_parent(parent_relid, true); END IF; - /* check upper boundary */ - IF p_end_value <= v_max THEN - RAISE EXCEPTION 'Not enough partitions to fit all the values of ''%''' - , p_attribute; - END IF; + RETURN part_count; /* number of created partitions */ END $$ LANGUAGE plpgsql; /* - * Formats range condition. Utility function. + * Creates new RANGE partition. Returns partition name. + * NOTE: This function SHOULD NOT take xact_handling lock (BGWs in 9.5). */ -CREATE OR REPLACE FUNCTION @extschema@.get_range_condition( - p_attname TEXT - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT) +CREATE OR REPLACE FUNCTION @extschema@.create_single_range_partition( + parent_relid REGCLASS, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) RETURNS TEXT AS $$ DECLARE - v_type REGTYPE; - v_sql TEXT; + v_part_num INT; + v_child_relname TEXT; + v_plain_child_relname TEXT; + v_attname TEXT; + v_plain_schema TEXT; + v_plain_relname TEXT; + v_child_relname_exists BOOL; + v_seq_name TEXT; + v_init_callback REGPROCEDURE; + BEGIN - /* determine the type of values */ - v_type := pg_typeof(p_start_value); + v_attname := attname FROM @extschema@.pathman_config + WHERE partrel = parent_relid; - /* we cannot use placeholders in DDL queries, so we are using format(...) */ - IF v_type IN ('date'::regtype, 'timestamp'::regtype, 'timestamptz'::regtype) THEN - v_sql := '%s >= ''%s'' AND %s < ''%s'''; - ELSE - v_sql := '%s >= %s AND %s < %s'; + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; END IF; - v_sql := format(v_sql - , p_attname - , p_start_value - , p_attname - , p_end_value); - RETURN v_sql; -END -$$ -LANGUAGE plpgsql; - -/* - * Creates new RANGE partition. Returns partition name - */ -CREATE OR REPLACE FUNCTION @extschema@.create_single_range_partition( - p_parent REGCLASS - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT) -RETURNS TEXT AS -$$ -DECLARE - v_part_num INT; - v_child_relname TEXT; - v_plain_child_relname TEXT; - v_attname TEXT; - v_sql TEXT; - v_cond TEXT; - v_plain_schema TEXT; - v_plain_relname TEXT; - v_child_relname_exists INTEGER := 1; - v_seq_name TEXT; -BEGIN - v_attname := attname FROM @extschema@.pathman_config - WHERE relname::regclass = p_parent; - SELECT * INTO v_plain_schema, v_plain_relname - FROM @extschema@.get_plain_schema_and_relname(p_parent); + FROM @extschema@.get_plain_schema_and_relname(parent_relid); v_seq_name := @extschema@.get_sequence_name(v_plain_schema, v_plain_relname); - /* get next value from sequence */ - LOOP - v_part_num := nextval(v_seq_name); - v_plain_child_relname := format('%s_%s', v_plain_relname, v_part_num); - v_child_relname := format('%s.%s', - v_plain_schema, - quote_ident(v_plain_child_relname)); - v_child_relname_exists := count(*) - FROM pg_class - WHERE relnamespace::regnamespace || '.' || relname = v_child_relname - LIMIT 1; - EXIT WHEN v_child_relname_exists = 0; - END LOOP; - - /* Skip existing partitions */ - IF EXISTS (SELECT * FROM pg_tables WHERE tablename = v_child_relname) THEN - RAISE WARNING 'Relation % already exists, skipping...', v_child_relname; - RETURN NULL; - END IF; - - EXECUTE format('CREATE TABLE %s (LIKE %s INCLUDING ALL)' - , v_child_relname - , p_parent); - - EXECUTE format('ALTER TABLE %s INHERIT %s' - , v_child_relname - , p_parent); - - v_cond := @extschema@.get_range_condition(v_attname, p_start_value, p_end_value); - v_sql := format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)' - , v_child_relname - , quote_ident(format('%s_%s_check', v_plain_schema, v_plain_child_relname)) - , v_cond); - - EXECUTE v_sql; - RETURN v_child_relname; + IF partition_name IS NULL THEN + /* Get next value from sequence */ + LOOP + v_part_num := nextval(v_seq_name); + v_plain_child_relname := format('%s_%s', v_plain_relname, v_part_num); + v_child_relname := format('%s.%s', + quote_ident(v_plain_schema), + quote_ident(v_plain_child_relname)); + + v_child_relname_exists := count(*) > 0 + FROM pg_class + WHERE relname = v_plain_child_relname AND + relnamespace = v_plain_schema::regnamespace + LIMIT 1; + + EXIT WHEN v_child_relname_exists = false; + END LOOP; + ELSE + v_child_relname := partition_name; + END IF; + + IF tablespace IS NULL THEN + tablespace := @extschema@.get_rel_tablespace_name(parent_relid); + END IF; + + EXECUTE format('CREATE TABLE %1$s (LIKE %2$s INCLUDING ALL) + INHERITS (%2$s) TABLESPACE %3$s', + v_child_relname, + parent_relid::TEXT, + tablespace); + + EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)', + v_child_relname, + @extschema@.build_check_constraint_name(v_child_relname::REGCLASS, + v_attname), + @extschema@.build_range_condition(v_attname, + p_start_value, + p_end_value)); + + PERFORM @extschema@.copy_foreign_keys(parent_relid, v_child_relname::REGCLASS); + + /* Fetch init_callback from 'params' table */ + WITH stub_callback(stub) as (values (0)) + SELECT coalesce(init_callback, 0::REGPROCEDURE) + FROM stub_callback + LEFT JOIN @extschema@.pathman_config_params AS params + ON params.partrel = parent_relid + INTO v_init_callback; + + PERFORM @extschema@.invoke_on_partition_created_callback(parent_relid, + v_child_relname::REGCLASS, + v_init_callback, + p_start_value, + p_end_value); + + RETURN v_child_relname; END -$$ LANGUAGE plpgsql; +$$ LANGUAGE plpgsql +SET client_min_messages = WARNING; /* * Split RANGE partition */ CREATE OR REPLACE FUNCTION @extschema@.split_range_partition( - p_partition REGCLASS - , p_value ANYELEMENT - , OUT p_range ANYARRAY) + p_partition REGCLASS, + p_value ANYELEMENT, + partition_name TEXT DEFAULT NULL, + OUT p_range ANYARRAY) RETURNS ANYARRAY AS $$ DECLARE - v_parent_relid OID; - v_child_relid OID := p_partition::oid; - v_attname TEXT; - v_cond TEXT; - v_new_partition TEXT; - v_part_type INTEGER; - v_part_relname TEXT; - v_plain_schema TEXT; - v_plain_relname TEXT; - v_check_name TEXT; + v_parent REGCLASS; + v_attname TEXT; + v_atttype REGTYPE; + v_cond TEXT; + v_new_partition TEXT; + v_part_type INTEGER; + v_check_name TEXT; + BEGIN - v_part_relname := @extschema@.validate_relname(p_partition); + PERFORM @extschema@.validate_relname(p_partition); + v_parent = @extschema@.get_parent_of_partition(p_partition); + + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(v_parent); - v_parent_relid := inhparent - FROM pg_inherits - WHERE inhrelid = v_child_relid; + /* Acquire data modification lock (prevent further modifications) */ + PERFORM @extschema@.prevent_relation_modification(p_partition); - SELECT attname, parttype INTO v_attname, v_part_type + SELECT attname, parttype FROM @extschema@.pathman_config - WHERE relname::regclass = v_parent_relid::regclass; + WHERE partrel = v_parent + INTO v_attname, v_part_type; - SELECT * INTO v_plain_schema, v_plain_relname - FROM @extschema@.get_plain_schema_and_relname(p_partition); + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', v_parent::TEXT; + END IF; - /* Check if this is RANGE partition */ + /* Check if this is a RANGE partition */ IF v_part_type != 2 THEN - RAISE EXCEPTION 'Specified partition isn''t RANGE partition'; + RAISE EXCEPTION '"%" is not a RANGE partition', p_partition::TEXT; END IF; + v_atttype = @extschema@.get_attribute_type(v_parent, v_attname); + /* Get partition values range */ - p_range := @extschema@.get_partition_range(v_parent_relid, v_child_relid, 0); + EXECUTE format('SELECT @extschema@.get_part_range($1, NULL::%s)', + @extschema@.get_base_type(v_atttype)::TEXT) + USING p_partition + INTO p_range; + IF p_range IS NULL THEN - RAISE EXCEPTION 'Could not find specified partition'; + RAISE EXCEPTION 'could not find specified partition'; END IF; /* Check if value fit into the range */ IF p_range[1] > p_value OR p_range[2] <= p_value THEN - RAISE EXCEPTION 'Specified value does not fit into the range [%, %)', + RAISE EXCEPTION 'specified value does not fit into the range [%, %)', p_range[1], p_range[2]; END IF; /* Create new partition */ - RAISE NOTICE 'Creating new partition...'; - v_new_partition := @extschema@.create_single_range_partition( - @extschema@.get_schema_qualified_name(v_parent_relid::regclass, '.'), - p_value, - p_range[2]); + v_new_partition := @extschema@.create_single_range_partition(v_parent, + p_value, + p_range[2], + partition_name); /* Copy data */ - RAISE NOTICE 'Copying data to new partition...'; - v_cond := @extschema@.get_range_condition(v_attname, p_value, p_range[2]); - EXECUTE format(' - WITH part_data AS ( - DELETE FROM %s WHERE %s RETURNING *) - INSERT INTO %s SELECT * FROM part_data' - , p_partition - , v_cond - , v_new_partition); + v_cond := @extschema@.build_range_condition(v_attname, p_value, p_range[2]); + EXECUTE format('WITH part_data AS (DELETE FROM %s WHERE %s RETURNING *) + INSERT INTO %s SELECT * FROM part_data', + p_partition::TEXT, + v_cond, + v_new_partition); /* Alter original partition */ - RAISE NOTICE 'Altering original partition...'; - v_cond := @extschema@.get_range_condition(v_attname, p_range[1], p_value); - v_check_name := quote_ident(format('%s_%s_check', v_plain_schema, v_plain_relname)); - EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s' - , p_partition::text - , v_check_name); - EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)' - , p_partition - , v_check_name - , v_cond); + v_cond := @extschema@.build_range_condition(v_attname, p_range[1], p_value); + v_check_name := @extschema@.build_check_constraint_name(p_partition, v_attname); - /* Tell backend to reload configuration */ - PERFORM @extschema@.on_update_partitions(v_parent_relid::oid); + EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s', + p_partition::TEXT, + v_check_name); + + EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)', + p_partition::TEXT, + v_check_name, + v_cond); - RAISE NOTICE 'Done!'; + /* Tell backend to reload configuration */ + PERFORM @extschema@.on_update_partitions(v_parent); END $$ LANGUAGE plpgsql; @@ -562,53 +642,58 @@ LANGUAGE plpgsql; * Merge RANGE partitions */ CREATE OR REPLACE FUNCTION @extschema@.merge_range_partitions( - p_partition1 REGCLASS - , p_partition2 REGCLASS) + partition1 REGCLASS, + partition2 REGCLASS) RETURNS VOID AS $$ DECLARE - v_parent_relid1 OID; - v_parent_relid2 OID; - v_part1_relid OID := p_partition1::oid; - v_part2_relid OID := p_partition2::oid; - v_part1_relname TEXT; - v_part2_relname TEXT; - v_attname TEXT; - v_part_type INTEGER; - v_atttype TEXT; -BEGIN - v_part1_relname := @extschema@.validate_relname(p_partition1); - v_part2_relname := @extschema@.validate_relname(p_partition2); + v_parent1 REGCLASS; + v_parent2 REGCLASS; + v_attname TEXT; + v_part_type INTEGER; + v_atttype REGTYPE; - IF v_part1_relid = v_part2_relid THEN - RAISE EXCEPTION 'Cannot merge partition to itself'; +BEGIN + IF partition1 = partition2 THEN + RAISE EXCEPTION 'cannot merge partition with itself'; END IF; - v_parent_relid1 := inhparent FROM pg_inherits WHERE inhrelid = v_part1_relid; - v_parent_relid2 := inhparent FROM pg_inherits WHERE inhrelid = v_part2_relid; + v_parent1 := @extschema@.get_parent_of_partition(partition1); + v_parent2 := @extschema@.get_parent_of_partition(partition2); + + /* Acquire data modification locks (prevent further modifications) */ + PERFORM @extschema@.prevent_relation_modification(partition1); + PERFORM @extschema@.prevent_relation_modification(partition2); - IF v_parent_relid1 != v_parent_relid2 THEN - RAISE EXCEPTION 'Cannot merge partitions having different parents'; + IF v_parent1 != v_parent2 THEN + RAISE EXCEPTION 'cannot merge partitions with different parents'; END IF; - SELECT attname, parttype INTO v_attname, v_part_type + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(v_parent1); + + SELECT attname, parttype FROM @extschema@.pathman_config - WHERE relname::regclass = v_parent_relid1::regclass; + WHERE partrel = v_parent1 + INTO v_attname, v_part_type; + + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', v_parent1::TEXT; + END IF; - /* Check if this is RANGE partition */ + /* Check if this is a RANGE partition */ IF v_part_type != 2 THEN - RAISE EXCEPTION 'Specified partitions aren''t RANGE partitions'; + RAISE EXCEPTION 'specified partitions aren''t RANGE partitions'; END IF; - v_atttype := @extschema@.get_attribute_type_name(p_partition1, v_attname); + v_atttype := @extschema@.get_attribute_type(partition1, v_attname); - EXECUTE format('SELECT @extschema@.merge_range_partitions_internal($1, $2 , $3, NULL::%s)', v_atttype) - USING v_parent_relid1, p_partition1 , p_partition2; + EXECUTE format('SELECT @extschema@.merge_range_partitions_internal($1, $2, $3, NULL::%s)', + @extschema@.get_base_type(v_atttype)::TEXT) + USING v_parent1, partition1, partition2; /* Tell backend to reload configuration */ - PERFORM @extschema@.on_update_partitions(v_parent_relid1::oid); - - RAISE NOTICE 'Done!'; + PERFORM @extschema@.on_update_partitions(v_parent1); END $$ LANGUAGE plpgsql; @@ -618,136 +703,171 @@ LANGUAGE plpgsql; * Merge two partitions. All data will be copied to the first one. Second * partition will be destroyed. * - * Notes: dummy field is used to pass the element type to the function - * (it is neccessary because of pseudo-types used in function) + * NOTE: dummy field is used to pass the element type to the function + * (it is necessary because of pseudo-types used in function). */ CREATE OR REPLACE FUNCTION @extschema@.merge_range_partitions_internal( - p_parent_relid OID - , p_part1 REGCLASS - , p_part2 REGCLASS - , dummy ANYELEMENT - , OUT p_range ANYARRAY) + parent_relid REGCLASS, + partition1 REGCLASS, + partition2 REGCLASS, + dummy ANYELEMENT, + OUT p_range ANYARRAY) RETURNS ANYARRAY AS $$ DECLARE - v_attname TEXT; - v_cond TEXT; - v_plain_schema TEXT; - v_plain_relname TEXT; - v_child_relname TEXT; - v_check_name TEXT; + v_attname TEXT; + v_atttype REGTYPE; + v_check_name TEXT; + BEGIN - SELECT attname INTO v_attname FROM @extschema@.pathman_config - WHERE relname::regclass = p_parent_relid::regclass; + SELECT attname FROM @extschema@.pathman_config + WHERE partrel = parent_relid + INTO v_attname; - SELECT * INTO v_plain_schema, v_plain_relname - FROM @extschema@.get_plain_schema_and_relname(p_part1); + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; - /* - * Get ranges - * first and second elements of array are MIN and MAX of partition1 - * third and forth elements are MIN and MAX of partition2 - */ - p_range := @extschema@.get_partition_range(p_parent_relid, p_part1::oid, 0) || - @extschema@.get_partition_range(p_parent_relid, p_part2::oid, 0); + v_atttype = @extschema@.get_attribute_type(parent_relid, v_attname); + + /* We have to pass fake NULL casted to column's type */ + EXECUTE format('SELECT @extschema@.get_part_range($1, NULL::%1$s) || + @extschema@.get_part_range($2, NULL::%1$s)', + @extschema@.get_base_type(v_atttype)::TEXT) + USING partition1, partition2 + INTO p_range; /* Check if ranges are adjacent */ IF p_range[1] != p_range[4] AND p_range[2] != p_range[3] THEN - RAISE EXCEPTION 'Merge failed. Partitions must be adjacent'; + RAISE EXCEPTION 'merge failed, partitions must be adjacent'; END IF; - /* Extend first partition */ - v_cond := @extschema@.get_range_condition(v_attname - , least(p_range[1], p_range[3]) - , greatest(p_range[2], p_range[4])); - - /* Alter first partition */ - RAISE NOTICE 'Altering first partition...'; - v_check_name := quote_ident(v_plain_schema || '_' || v_plain_relname || '_check'); - EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s' - , p_part1::text - , v_check_name); - EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)' - , p_part1::text - , v_check_name - , v_cond); + /* Drop constraint on first partition... */ + v_check_name := @extschema@.build_check_constraint_name(partition1, v_attname); + EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s', + partition1::TEXT, + v_check_name); + + /* and create a new one */ + EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)', + partition1::TEXT, + v_check_name, + @extschema@.build_range_condition(v_attname, + least(p_range[1], p_range[3]), + greatest(p_range[2], p_range[4]))); /* Copy data from second partition to the first one */ - RAISE NOTICE 'Copying data...'; EXECUTE format('WITH part_data AS (DELETE FROM %s RETURNING *) - INSERT INTO %s SELECT * FROM part_data' - , p_part2::text - , p_part1::text); + INSERT INTO %s SELECT * FROM part_data', + partition2::TEXT, + partition1::TEXT); /* Remove second partition */ - RAISE NOTICE 'Dropping second partition...'; - EXECUTE format('DROP TABLE %s', p_part2::text); + EXECUTE format('DROP TABLE %s', partition2::TEXT); END $$ LANGUAGE plpgsql; /* - * Append new partition + * Append new partition. */ CREATE OR REPLACE FUNCTION @extschema@.append_range_partition( - p_relation REGCLASS) + parent_relid REGCLASS, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) RETURNS TEXT AS $$ DECLARE - v_attname TEXT; - v_atttype TEXT; - v_part_name TEXT; - v_interval TEXT; + v_attname TEXT; + v_atttype REGTYPE; + v_part_name TEXT; + v_interval TEXT; + BEGIN - SELECT attname, range_interval INTO v_attname, v_interval - FROM @extschema@.pathman_config WHERE relname::regclass = p_relation; + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); - v_atttype := @extschema@.get_attribute_type_name(p_relation, v_attname); + SELECT attname, range_interval + FROM @extschema@.pathman_config + WHERE partrel = parent_relid + INTO v_attname, v_interval; - /* Prevent concurrent partition creation */ - PERFORM @extschema@.acquire_partitions_lock(); - - EXECUTE format('SELECT @extschema@.append_partition_internal($1, $2, $3, ARRAY[]::%s[])', v_atttype) - INTO v_part_name - USING p_relation, v_atttype, v_interval; + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; - /* Invalidate cache */ - PERFORM @extschema@.on_update_partitions(p_relation::oid); + v_atttype := @extschema@.get_attribute_type(parent_relid, v_attname); - /* Release lock */ - PERFORM @extschema@.release_partitions_lock(); + EXECUTE + format('SELECT @extschema@.append_partition_internal($1, $2, $3, ARRAY[]::%s[], $4, $5)', + @extschema@.get_base_type(v_atttype)::TEXT) + USING + parent_relid, + v_atttype, + v_interval, + partition_name, + tablespace + INTO + v_part_name; - RAISE NOTICE 'Done!'; + /* Invalidate cache */ + PERFORM @extschema@.on_update_partitions(parent_relid); RETURN v_part_name; - -EXCEPTION WHEN others THEN - PERFORM @extschema@.release_partitions_lock(); - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; END $$ LANGUAGE plpgsql; - +/* + * Spawn logic for append_partition(). We have to + * separate this in order to pass the 'p_range'. + * + * NOTE: we don't take a xact_handling lock here. + */ CREATE OR REPLACE FUNCTION @extschema@.append_partition_internal( - p_relation REGCLASS - , p_atttype TEXT - , p_interval TEXT - , p_range ANYARRAY DEFAULT NULL) + parent_relid REGCLASS, + p_atttype REGTYPE, + p_interval TEXT, + p_range ANYARRAY DEFAULT NULL, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) RETURNS TEXT AS $$ DECLARE - v_part_name TEXT; + v_part_name TEXT; + v_atttype REGTYPE; + BEGIN - p_range := @extschema@.get_range_by_idx(p_relation::oid, -1, 0); - RAISE NOTICE 'Appending new partition...'; - IF @extschema@.is_date(p_atttype::regtype) THEN - v_part_name := @extschema@.create_single_range_partition(p_relation - , p_range[2] - , p_range[2] + p_interval::interval); + IF @extschema@.partitions_count(parent_relid) = 0 THEN + RAISE EXCEPTION 'cannot append to empty partitions set'; + END IF; + + v_atttype := @extschema@.get_base_type(p_atttype); + + /* We have to pass fake NULL casted to column's type */ + EXECUTE format('SELECT @extschema@.get_part_range($1, -1, NULL::%s)', + v_atttype::TEXT) + USING parent_relid + INTO p_range; + + IF @extschema@.is_date_type(p_atttype) THEN + v_part_name := @extschema@.create_single_range_partition( + parent_relid, + p_range[2], + p_range[2] + p_interval::interval, + partition_name, + tablespace); ELSE - EXECUTE format('SELECT @extschema@.create_single_range_partition($1, $2, $2 + $3::%s)', p_atttype) - USING p_relation, p_range[2], p_interval - INTO v_part_name; + EXECUTE + format('SELECT @extschema@.create_single_range_partition($1, $2, $2 + $3::%s, $4, $5)', + v_atttype::TEXT) + USING + parent_relid, + p_range[2], + p_interval, + partition_name, + tablespace + INTO + v_part_name; END IF; RETURN v_part_name; @@ -757,66 +877,102 @@ LANGUAGE plpgsql; /* - * Prepend new partition + * Prepend new partition. */ -CREATE OR REPLACE FUNCTION @extschema@.prepend_range_partition(p_relation REGCLASS) +CREATE OR REPLACE FUNCTION @extschema@.prepend_range_partition( + parent_relid REGCLASS, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) RETURNS TEXT AS $$ DECLARE - v_attname TEXT; - v_atttype TEXT; - v_part_name TEXT; - v_interval TEXT; -BEGIN - SELECT attname, range_interval INTO v_attname, v_interval - FROM @extschema@.pathman_config WHERE relname::regclass = p_relation; - v_atttype := @extschema@.get_attribute_type_name(p_relation, v_attname); + v_attname TEXT; + v_atttype REGTYPE; + v_part_name TEXT; + v_interval TEXT; - /* Prevent concurrent partition creation */ - PERFORM @extschema@.acquire_partitions_lock(); +BEGIN + SELECT attname, range_interval + FROM @extschema@.pathman_config + WHERE partrel = parent_relid + INTO v_attname, v_interval; - EXECUTE format('SELECT @extschema@.prepend_partition_internal($1, $2, $3, ARRAY[]::%s[])', v_atttype) - INTO v_part_name - USING p_relation, v_atttype, v_interval; + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; - /* Invalidate cache */ - PERFORM @extschema@.on_update_partitions(p_relation::oid); + v_atttype := @extschema@.get_attribute_type(parent_relid, v_attname); - /* Release lock */ - PERFORM @extschema@.release_partitions_lock(); + EXECUTE + format('SELECT @extschema@.prepend_partition_internal($1, $2, $3, ARRAY[]::%s[], $4, $5)', + @extschema@.get_base_type(v_atttype)::TEXT) + USING + parent_relid, + v_atttype, + v_interval, + partition_name, + tablespace + INTO + v_part_name; - RAISE NOTICE 'Done!'; + /* Invalidate cache */ + PERFORM @extschema@.on_update_partitions(parent_relid); RETURN v_part_name; - -EXCEPTION WHEN others THEN - PERFORM @extschema@.release_partitions_lock(); - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; END $$ LANGUAGE plpgsql; - +/* + * Spawn logic for prepend_partition(). We have to + * separate this in order to pass the 'p_range'. + * + * NOTE: we don't take a xact_handling lock here. + */ CREATE OR REPLACE FUNCTION @extschema@.prepend_partition_internal( - p_relation REGCLASS - , p_atttype TEXT - , p_interval TEXT - , p_range ANYARRAY DEFAULT NULL) + parent_relid REGCLASS, + p_atttype REGTYPE, + p_interval TEXT, + p_range ANYARRAY DEFAULT NULL, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) RETURNS TEXT AS $$ DECLARE - v_part_name TEXT; + v_part_name TEXT; + v_atttype REGTYPE; + BEGIN - p_range := @extschema@.get_range_by_idx(p_relation::oid, 0, 0); - RAISE NOTICE 'Prepending new partition...'; + IF @extschema@.partitions_count(parent_relid) = 0 THEN + RAISE EXCEPTION 'cannot prepend to empty partitions set'; + END IF; - IF @extschema@.is_date(p_atttype::regtype) THEN - v_part_name := @extschema@.create_single_range_partition(p_relation - , p_range[1] - p_interval::interval - , p_range[1]); + v_atttype := @extschema@.get_base_type(p_atttype); + + /* We have to pass fake NULL casted to column's type */ + EXECUTE format('SELECT @extschema@.get_part_range($1, 0, NULL::%s)', + v_atttype::TEXT) + USING parent_relid + INTO p_range; + + IF @extschema@.is_date_type(p_atttype) THEN + v_part_name := @extschema@.create_single_range_partition( + parent_relid, + p_range[1] - p_interval::interval, + p_range[1], + partition_name, + tablespace); ELSE - EXECUTE format('SELECT @extschema@.create_single_range_partition($1, $2 - $3::%s, $2)', p_atttype) - USING p_relation, p_range[1], p_interval - INTO v_part_name; + EXECUTE + format('SELECT @extschema@.create_single_range_partition($1, $2 - $3::%s, $2, $4, $5)', + v_atttype::TEXT) + USING + parent_relid, + p_range[1], + p_interval, + partition_name, + tablespace + INTO + v_part_name; END IF; RETURN v_part_name; @@ -829,39 +985,39 @@ LANGUAGE plpgsql; * Add new partition */ CREATE OR REPLACE FUNCTION @extschema@.add_range_partition( - p_relation REGCLASS - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT) + parent_relid REGCLASS, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT, + partition_name TEXT DEFAULT NULL, + tablespace TEXT DEFAULT NULL) RETURNS TEXT AS $$ DECLARE - v_part_name TEXT; + v_part_name TEXT; + BEGIN - /* Prevent concurrent partition creation */ - PERFORM @extschema@.acquire_partitions_lock(); + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); - /* check range overlap */ - IF @extschema@.check_overlap(p_relation::oid, p_start_value, p_end_value) != FALSE THEN - RAISE EXCEPTION 'Specified range overlaps with existing partitions'; + IF p_start_value >= p_end_value THEN + RAISE EXCEPTION 'failed to create partition: p_start_value is greater than p_end_value'; END IF; - IF p_start_value >= p_end_value THEN - RAISE EXCEPTION 'Failed to create partition: p_start_value is greater than p_end_value'; + /* check range overlap */ + IF @extschema@.partitions_count(parent_relid) > 0 + AND @extschema@.check_overlap(parent_relid, p_start_value, p_end_value) THEN + RAISE EXCEPTION 'specified range overlaps with existing partitions'; END IF; /* Create new partition */ - v_part_name := @extschema@.create_single_range_partition(p_relation, p_start_value, p_end_value); - PERFORM @extschema@.on_update_partitions(p_relation::oid); - - /* Release lock */ - PERFORM @extschema@.release_partitions_lock(); + v_part_name := @extschema@.create_single_range_partition(parent_relid, + p_start_value, + p_end_value, + partition_name, + tablespace); + PERFORM @extschema@.on_update_partitions(parent_relid); - RAISE NOTICE 'Done!'; RETURN v_part_name; - -EXCEPTION WHEN others THEN - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; - PERFORM @extschema@.release_partitions_lock(); END $$ LANGUAGE plpgsql; @@ -871,97 +1027,140 @@ LANGUAGE plpgsql; * Drop range partition */ CREATE OR REPLACE FUNCTION @extschema@.drop_range_partition( - p_partition REGCLASS) + p_partition REGCLASS, + delete_data BOOLEAN DEFAULT TRUE) RETURNS TEXT AS $$ DECLARE - v_part_name TEXT := p_partition::TEXT; - v_parent TEXT; - v_count INTEGER; + parent_relid REGCLASS; + part_name TEXT; + v_relkind CHAR; + v_rows BIGINT; + v_part_type INTEGER; + BEGIN - /* Prevent concurrent partition management */ - PERFORM @extschema@.acquire_partitions_lock(); + parent_relid := @extschema@.get_parent_of_partition(p_partition); + part_name := p_partition::TEXT; /* save the name to be returned */ - /* Parent table name */ - SELECT inhparent::regclass INTO v_parent - FROM pg_inherits WHERE inhrelid::regclass = p_partition; + SELECT parttype + FROM @extschema@.pathman_config + WHERE partrel = parent_relid + INTO v_part_type; - IF v_parent IS NULL THEN - RAISE EXCEPTION 'Partition ''%'' not found', p_partition; + /* Check if this is a RANGE partition */ + IF v_part_type != 2 THEN + RAISE EXCEPTION '"%" is not a RANGE partition', p_partition::TEXT; END IF; - /* Drop table and update cache */ - EXECUTE format('DROP TABLE %s', p_partition::TEXT); - PERFORM @extschema@.on_update_partitions(v_parent::regclass::oid); + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); - /* Release lock */ - PERFORM @extschema@.release_partitions_lock(); + IF NOT delete_data THEN + EXECUTE format('INSERT INTO %s SELECT * FROM %s', + parent_relid::TEXT, + p_partition::TEXT); + GET DIAGNOSTICS v_rows = ROW_COUNT; - RETURN v_part_name; + /* Show number of copied rows */ + RAISE NOTICE '% rows copied from %', v_rows, p_partition::TEXT; + END IF; + + SELECT relkind FROM pg_catalog.pg_class + WHERE oid = p_partition + INTO v_relkind; + + /* + * Determine the kind of child relation. It can be either regular + * table (r) or foreign table (f). Depending on relkind we use + * DROP TABLE or DROP FOREIGN TABLE. + */ + IF v_relkind = 'f' THEN + EXECUTE format('DROP FOREIGN TABLE %s', p_partition::TEXT); + ELSE + EXECUTE format('DROP TABLE %s', p_partition::TEXT); + END IF; -EXCEPTION WHEN others THEN - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; - PERFORM @extschema@.release_partitions_lock(); + /* Invalidate cache */ + PERFORM @extschema@.on_update_partitions(parent_relid); + + RETURN part_name; END $$ -LANGUAGE plpgsql; +LANGUAGE plpgsql +SET pg_pathman.enable_partitionfilter = off; /* ensures that PartitionFilter is OFF */ /* * Attach range partition */ CREATE OR REPLACE FUNCTION @extschema@.attach_range_partition( - p_relation REGCLASS - , p_partition REGCLASS - , p_start_value ANYELEMENT - , p_end_value ANYELEMENT) + parent_relid REGCLASS, + p_partition REGCLASS, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT) RETURNS TEXT AS $$ DECLARE - v_attname TEXT; - v_cond TEXT; - v_plain_partname TEXT; - v_plain_schema TEXT; + v_attname TEXT; + rel_persistence CHAR; + v_init_callback REGPROCEDURE; + BEGIN - /* Prevent concurrent partition management */ - PERFORM @extschema@.acquire_partitions_lock(); + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + /* Ignore temporary tables */ + SELECT relpersistence FROM pg_catalog.pg_class + WHERE oid = p_partition INTO rel_persistence; - IF @extschema@.check_overlap(p_relation::oid, p_start_value, p_end_value) != FALSE THEN - RAISE EXCEPTION 'Specified range overlaps with existing partitions'; + IF rel_persistence = 't'::CHAR THEN + RAISE EXCEPTION 'temporary table "%" cannot be used as a partition', + p_partition::TEXT; END IF; - IF NOT @extschema@.validate_relations_equality(p_relation, p_partition) THEN - RAISE EXCEPTION 'Partition must have the exact same structure as parent'; - END IF; + IF @extschema@.check_overlap(parent_relid, p_start_value, p_end_value) THEN + RAISE EXCEPTION 'specified range overlaps with existing partitions'; + END IF; + + IF NOT @extschema@.validate_relations_equality(parent_relid, p_partition) THEN + RAISE EXCEPTION 'partition must have the exact same structure as parent'; + END IF; /* Set inheritance */ - EXECUTE format('ALTER TABLE %s INHERIT %s' - , p_partition - , p_relation); + EXECUTE format('ALTER TABLE %s INHERIT %s', p_partition, parent_relid); - /* Set check constraint */ - v_attname := attname FROM @extschema@.pathman_config WHERE relname::regclass = p_relation; - v_cond := @extschema@.get_range_condition(v_attname, p_start_value, p_end_value); + v_attname := attname FROM @extschema@.pathman_config WHERE partrel = parent_relid; - /* Plain partition name and schema */ - SELECT * INTO v_plain_schema, v_plain_partname FROM @extschema@.get_plain_schema_and_relname(p_partition); + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; - EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)' - , p_partition - , v_plain_schema || '_' || quote_ident(v_plain_partname || '_check') - , v_cond); + /* Set check constraint */ + EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s)', + p_partition::TEXT, + @extschema@.build_check_constraint_name(p_partition, v_attname), + @extschema@.build_range_condition(v_attname, + p_start_value, + p_end_value)); + + /* Fetch init_callback from 'params' table */ + WITH stub_callback(stub) as (values (0)) + SELECT coalesce(init_callback, 0::REGPROCEDURE) + FROM stub_callback + LEFT JOIN @extschema@.pathman_config_params AS params + ON params.partrel = parent_relid + INTO v_init_callback; + + PERFORM @extschema@.invoke_on_partition_created_callback(parent_relid, + p_partition, + v_init_callback, + p_start_value, + p_end_value); /* Invalidate cache */ - PERFORM @extschema@.on_update_partitions(p_relation::oid); + PERFORM @extschema@.on_update_partitions(parent_relid); - /* Release lock */ - PERFORM @extschema@.release_partitions_lock(); RETURN p_partition; - -EXCEPTION WHEN others THEN - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; - PERFORM @extschema@.release_partitions_lock(); END $$ LANGUAGE plpgsql; @@ -971,317 +1170,187 @@ LANGUAGE plpgsql; * Detach range partition */ CREATE OR REPLACE FUNCTION @extschema@.detach_range_partition( - p_partition TEXT) + p_partition REGCLASS) RETURNS TEXT AS $$ DECLARE - v_parent TEXT; + v_attname TEXT; + parent_relid REGCLASS; + BEGIN - /* Prevent concurrent partition management */ - PERFORM @extschema@.acquire_partitions_lock(); + parent_relid := @extschema@.get_parent_of_partition(p_partition); - /* Parent table */ - SELECT inhparent::regclass INTO v_parent - FROM pg_inherits WHERE inhrelid = p_partition::regclass::oid; + /* Acquire lock on parent */ + PERFORM @extschema@.lock_partitioned_relation(parent_relid); + + v_attname := attname + FROM @extschema@.pathman_config + WHERE partrel = parent_relid; + + IF v_attname IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; /* Remove inheritance */ - EXECUTE format('ALTER TABLE %s NO INHERIT %s' - , p_partition - , v_parent); + EXECUTE format('ALTER TABLE %s NO INHERIT %s', + p_partition::TEXT, + parent_relid::TEXT); /* Remove check constraint */ - EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s_check' - , p_partition - , @extschema@.get_schema_qualified_name(p_partition::regclass)); + EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s', + p_partition::TEXT, + @extschema@.build_check_constraint_name(p_partition, v_attname)); /* Invalidate cache */ - PERFORM @extschema@.on_update_partitions(v_parent::regclass::oid); + PERFORM @extschema@.on_update_partitions(parent_relid); - /* Release lock */ - PERFORM @extschema@.release_partitions_lock(); RETURN p_partition; - -EXCEPTION WHEN others THEN - RAISE EXCEPTION '% %', SQLERRM, SQLSTATE; - PERFORM @extschema@.release_partitions_lock(); END $$ LANGUAGE plpgsql; -/* - * Creates range partitioning insert trigger - */ -CREATE OR REPLACE FUNCTION @extschema@.create_range_insert_trigger( - v_relation REGCLASS - , v_attname TEXT) -RETURNS VOID AS -$$ -DECLARE - v_func TEXT := ' - CREATE OR REPLACE FUNCTION %s() - RETURNS TRIGGER - AS $body$ - DECLARE - v_part_relid OID; - BEGIN - IF TG_OP = ''INSERT'' THEN - IF NEW.%2$s IS NULL THEN - RAISE EXCEPTION ''ERROR: NULL value in partitioning key''; - END IF; - v_part_relid := @extschema@.find_or_create_range_partition(TG_RELID, NEW.%2$s); - IF NOT v_part_relid IS NULL THEN - EXECUTE format(''INSERT INTO %%s SELECT $1.*'', v_part_relid::regclass) - USING NEW; - ELSE - RAISE EXCEPTION ''ERROR: Cannot find partition''; - END IF; - END IF; - RETURN NULL; - END - $body$ LANGUAGE plpgsql;'; - v_funcname TEXT; - v_trigger TEXT := ' - CREATE TRIGGER %s - BEFORE INSERT ON %s - FOR EACH ROW EXECUTE PROCEDURE %s();'; - v_triggername TEXT; - v_plain_relname TEXT; - v_plain_schema TEXT; -BEGIN - SELECT * INTO v_plain_schema, v_plain_relname - FROM @extschema@.get_plain_schema_and_relname(v_relation); - - v_funcname := format(quote_ident('%s_insert_trigger_func'), v_plain_relname); - v_triggername := format('"%s_%s_insert_trigger"', v_plain_schema, v_plain_relname); - - v_func := format(v_func, v_funcname, v_attname); - v_trigger := format(v_trigger, v_triggername, v_relation, v_funcname); - - EXECUTE v_func; - EXECUTE v_trigger; - RETURN; -END -$$ LANGUAGE plpgsql; - - /* * Creates an update trigger */ CREATE OR REPLACE FUNCTION @extschema@.create_range_update_trigger( - IN relation TEXT) + IN parent_relid REGCLASS) RETURNS TEXT AS $$ DECLARE - func TEXT := ' - CREATE OR REPLACE FUNCTION %s_update_trigger_func() - RETURNS TRIGGER AS - $body$ - DECLARE - old_oid INTEGER; - new_oid INTEGER; - q TEXT; - BEGIN - old_oid := TG_RELID; - new_oid := @extschema@.find_or_create_range_partition(''%1$s''::regclass::oid, NEW.%2$s); - IF old_oid = new_oid THEN RETURN NEW; END IF; - q := format(''DELETE FROM %%s WHERE %4$s'', old_oid::regclass::text); - EXECUTE q USING %5$s; - q := format(''INSERT INTO %%s VALUES (%6$s)'', new_oid::regclass::text); - EXECUTE q USING %7$s; - RETURN NULL; - END $body$ LANGUAGE plpgsql'; - trigger TEXT := 'CREATE TRIGGER %s_update_trigger ' || - 'BEFORE UPDATE ON %s ' || - 'FOR EACH ROW EXECUTE PROCEDURE %s_update_trigger_func()'; - att_names TEXT; - old_fields TEXT; - new_fields TEXT; - att_val_fmt TEXT; - att_fmt TEXT; - relid INTEGER; - rec RECORD; - num INTEGER := 0; - attr TEXT; + func TEXT := 'CREATE OR REPLACE FUNCTION %1$s() + RETURNS TRIGGER AS + $body$ + DECLARE + old_oid Oid; + new_oid Oid; + + BEGIN + old_oid := TG_RELID; + new_oid := @extschema@.find_or_create_range_partition( + ''%2$s''::regclass, NEW.%3$s); + + IF old_oid = new_oid THEN + RETURN NEW; + END IF; + + EXECUTE format(''DELETE FROM %%s WHERE %5$s'', + old_oid::regclass::text) + USING %6$s; + + EXECUTE format(''INSERT INTO %%s VALUES (%7$s)'', + new_oid::regclass::text) + USING %8$s; + + RETURN NULL; + END $body$ + LANGUAGE plpgsql'; + + trigger TEXT := 'CREATE TRIGGER %s ' || + 'BEFORE UPDATE ON %s ' || + 'FOR EACH ROW EXECUTE PROCEDURE %s()'; + + triggername TEXT; + funcname TEXT; + att_names TEXT; + old_fields TEXT; + new_fields TEXT; + att_val_fmt TEXT; + att_fmt TEXT; + attr TEXT; + rec RECORD; + BEGIN - relation := @extschema@.validate_relname(relation); - relid := relation::regclass::oid; + attr := attname FROM @extschema@.pathman_config WHERE partrel = parent_relid; + + IF attr IS NULL THEN + RAISE EXCEPTION 'table "%" is not partitioned', parent_relid::TEXT; + END IF; + SELECT string_agg(attname, ', '), string_agg('OLD.' || attname, ', '), string_agg('NEW.' || attname, ', '), - string_agg('CASE WHEN NOT $' || attnum || ' IS NULL THEN ' || attname || ' = $' || attnum || - ' ELSE ' || attname || ' IS NULL END', ' AND '), + string_agg('CASE WHEN NOT $' || attnum || ' IS NULL THEN ' || + attname || ' = $' || attnum || ' ' || + 'ELSE ' || + attname || ' IS NULL END', + ' AND '), string_agg('$' || attnum, ', ') FROM pg_attribute - WHERE attrelid=relid AND attnum>0 - INTO att_names, - old_fields, - new_fields, - att_val_fmt, - att_fmt; - - attr := attname FROM @extschema@.pathman_config WHERE relname = relation; - EXECUTE format(func, relation, attr, 0, att_val_fmt, + WHERE attrelid::REGCLASS = parent_relid AND attnum > 0 + INTO att_names, + old_fields, + new_fields, + att_val_fmt, + att_fmt; + + /* Build trigger & trigger function's names */ + funcname := @extschema@.build_update_trigger_func_name(parent_relid); + triggername := @extschema@.build_update_trigger_name(parent_relid); + + /* Create function for trigger */ + EXECUTE format(func, funcname, parent_relid, attr, 0, att_val_fmt, old_fields, att_fmt, new_fields); - FOR rec in (SELECT * FROM pg_inherits WHERE inhparent = relation::regclass::oid) + + /* Create trigger on every partition */ + FOR rec in (SELECT * FROM pg_catalog.pg_inherits + WHERE inhparent = parent_relid) LOOP - EXECUTE format(trigger - , @extschema@.get_schema_qualified_name(relation::regclass) - , rec.inhrelid::regclass - , relation); - num := num + 1; + EXECUTE format(trigger, + triggername, + rec.inhrelid::REGCLASS::TEXT, + funcname); END LOOP; - RETURN format('%s_update_trigger_func()', relation); + RETURN funcname; END $$ LANGUAGE plpgsql; - /* - * Drop partitions - * If delete_data set to TRUE then partitions will be dropped with all the data + * Construct CHECK constraint condition for a range partition. */ -CREATE OR REPLACE FUNCTION @extschema@.drop_range_partitions( - relation REGCLASS - , delete_data BOOLEAN DEFAULT FALSE) -RETURNS INTEGER AS -$$ -DECLARE - v_rec RECORD; - v_rows INTEGER; - v_part_count INTEGER := 0; - v_relname TEXT; -BEGIN - v_relname := @extschema@.validate_relname(relation); - - /* Drop trigger first */ - PERFORM @extschema@.drop_range_triggers(relation); - - FOR v_rec IN (SELECT inhrelid::regclass::text AS tbl - FROM pg_inherits WHERE inhparent::regclass = relation) - LOOP - IF NOT delete_data THEN - EXECUTE format('WITH part_data AS (DELETE FROM %s RETURNING *) - INSERT INTO %s SELECT * FROM part_data' - , v_rec.tbl - , relation::text); - GET DIAGNOSTICS v_rows = ROW_COUNT; - RAISE NOTICE '% rows copied from %', v_rows, v_rec.tbl; - END IF; - EXECUTE format('DROP TABLE %s', v_rec.tbl); - v_part_count := v_part_count + 1; - END LOOP; - - DELETE FROM @extschema@.pathman_config WHERE relname::regclass = relation; - - /* Notify backend about changes */ - PERFORM @extschema@.on_remove_partitions(relation::oid); - - RETURN v_part_count; -END -$$ LANGUAGE plpgsql; - +CREATE OR REPLACE FUNCTION @extschema@.build_range_condition( + p_attname TEXT, + p_start_value ANYELEMENT, + p_end_value ANYELEMENT) +RETURNS TEXT AS 'pg_pathman', 'build_range_condition' +LANGUAGE C; /* - * Drop trigger + * Returns N-th range (as an array of two elements). */ -CREATE OR REPLACE FUNCTION @extschema@.drop_range_triggers(IN relation REGCLASS) -RETURNS VOID AS -$$ -DECLARE - schema TEXT; - relname TEXT; -BEGIN - SELECT * INTO schema, relname - FROM @extschema@.get_plain_schema_and_relname(relation); - - EXECUTE format('DROP TRIGGER IF EXISTS %s ON %s CASCADE' - , format('"%s_%s_insert_trigger"', schema, relname) - , relation::TEXT); -END -$$ LANGUAGE plpgsql; - +CREATE OR REPLACE FUNCTION @extschema@.get_part_range( + parent_relid REGCLASS, + partition_idx INTEGER, + dummy ANYELEMENT) +RETURNS ANYARRAY AS 'pg_pathman', 'get_part_range_by_idx' +LANGUAGE C; /* - * Internal function used to create new partitions on insert or update trigger. - * Invoked from C-function find_or_create_range_partition(). + * Returns min and max values for specified RANGE partition. */ -CREATE OR REPLACE FUNCTION @extschema@.append_partitions_on_demand_internal( - p_relid OID - , p_new_value ANYELEMENT) -RETURNS OID AS -$$ -DECLARE - v_relation TEXT; - v_cnt INTEGER := 0; - i INTEGER := 0; - v_part TEXT; - v_interval TEXT; - v_attname TEXT; - v_min p_new_value%TYPE; - v_max p_new_value%TYPE; - v_cur_value p_new_value%TYPE; - v_next_value p_new_value%TYPE; - v_is_date BOOLEAN; -BEGIN - v_relation := @extschema@.validate_relname(p_relid::regclass::text); +CREATE OR REPLACE FUNCTION @extschema@.get_part_range( + partition_relid REGCLASS, + dummy ANYELEMENT) +RETURNS ANYARRAY AS 'pg_pathman', 'get_part_range_by_oid' +LANGUAGE C; - /* get attribute name and interval */ - SELECT attname, range_interval INTO v_attname, v_interval - FROM @extschema@.pathman_config WHERE relname = v_relation; - - v_min := @extschema@.get_min_range_value(p_relid::regclass::oid, p_new_value); - v_max := @extschema@.get_max_range_value(p_relid::regclass::oid, p_new_value); - - v_is_date := @extschema@.is_date(pg_typeof(p_new_value)::regtype); - - IF p_new_value >= v_max THEN - v_cur_value := v_max; - WHILE v_cur_value <= p_new_value AND i < 1000 - LOOP - IF v_is_date THEN - v_next_value := v_cur_value + v_interval::interval; - ELSE - EXECUTE format('SELECT $1 + $2::%s', pg_typeof(p_new_value)) - USING v_cur_value, v_interval - INTO v_next_value; - END IF; - - v_part := @extschema@.create_single_range_partition( - @extschema@.get_schema_qualified_name(p_relid::regclass, '.') - , v_cur_value - , v_next_value); - i := i + 1; - v_cur_value := v_next_value; - RAISE NOTICE 'partition % created', v_part; - END LOOP; - ELSIF p_new_value <= v_min THEN - v_cur_value := v_min; - WHILE v_cur_value >= p_new_value AND i < 1000 - LOOP - IF v_is_date THEN - v_next_value := v_cur_value - v_interval::interval; - ELSE - EXECUTE format('SELECT $1 - $2::%s', pg_typeof(p_new_value)) - USING v_cur_value, v_interval - INTO v_next_value; - END IF; - - v_part := @extschema@.create_single_range_partition( - @extschema@.get_schema_qualified_name(p_relid::regclass, '.') - , v_next_value - , v_cur_value); - i := i + 1; - v_cur_value := v_next_value; - RAISE NOTICE 'partition % created', v_part; - END LOOP; - ELSE - RAISE NOTICE 'Not implemented yet'; - END IF; +/* + * Checks if range overlaps with existing partitions. + * Returns TRUE if overlaps and FALSE otherwise. + */ +CREATE OR REPLACE FUNCTION @extschema@.check_overlap( + parent_relid REGCLASS, + range_min ANYELEMENT, + range_max ANYELEMENT) +RETURNS BOOLEAN AS 'pg_pathman', 'check_overlap' +LANGUAGE C; - IF i > 0 THEN - RETURN v_part::regclass::oid; - END IF; - RETURN NULL; -END -$$ LANGUAGE plpgsql; +/* + * Needed for an UPDATE trigger. + */ +CREATE OR REPLACE FUNCTION @extschema@.find_or_create_range_partition( + parent_relid REGCLASS, + value ANYELEMENT) +RETURNS REGCLASS AS 'pg_pathman', 'find_or_create_range_partition' +LANGUAGE C; diff --git a/contrib/pg_pathman/specs/for_update.spec b/contrib/pg_pathman/specs/for_update.spec new file mode 100644 index 0000000000..55ea24af3a --- /dev/null +++ b/contrib/pg_pathman/specs/for_update.spec @@ -0,0 +1,32 @@ +setup +{ + create extension pg_pathman; + create table test_tbl(id int not null, val real); + insert into test_tbl select i, i from generate_series(1, 1000) as i; + select create_range_partitions('test_tbl', 'id', 1, 100, 10); +} + +teardown +{ + drop table test_tbl cascade; + drop extension pg_pathman; +} + +session "s1" +step "s1_b" { begin; } +step "s1_c" { commit; } +step "s1_r" { rollback; } +step "s1_update" { update test_tbl set id = 2 where id = 1; } + +session "s2" +step "s2_b" { begin; } +step "s2_c" { commit; } +step "s2_select_locked" { select * from test_tbl where id = 1 for share; } +step "s2_select" { select * from test_tbl where id = 1; } + + +permutation "s1_b" "s1_update" "s2_select" "s1_r" + +permutation "s1_b" "s1_update" "s2_select_locked" "s1_r" + +permutation "s1_b" "s1_update" "s2_select_locked" "s1_c" diff --git a/contrib/pg_pathman/specs/insert_trigger.spec b/contrib/pg_pathman/specs/insert_nodes.spec similarity index 95% rename from contrib/pg_pathman/specs/insert_trigger.spec rename to contrib/pg_pathman/specs/insert_nodes.spec index 1b39d74c24..93df4102f6 100644 --- a/contrib/pg_pathman/specs/insert_trigger.spec +++ b/contrib/pg_pathman/specs/insert_nodes.spec @@ -7,7 +7,7 @@ setup teardown { - SELECT drop_range_partitions('range_rel'); + SELECT drop_partitions('range_rel'); DROP TABLE range_rel CASCADE; DROP EXTENSION pg_pathman; } @@ -16,7 +16,7 @@ session "s1" step "s1b" { BEGIN; } step "s1_insert_150" { INSERT INTO range_rel SELECT generate_series(1, 150); } step "s1_insert_300" { INSERT INTO range_rel SELECT generate_series(151, 300); } -step "s1_show_partitions" { SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; } +step "s1_show_partitions" { SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; } step "s1r" { ROLLBACK; } step "s1c" { COMMIT; } @@ -24,7 +24,7 @@ session "s2" step "s2b" { BEGIN; } step "s2_insert_150" { INSERT INTO range_rel SELECT generate_series(1, 150); } step "s2_insert_300" { INSERT INTO range_rel SELECT generate_series(151, 300); } -step "s2_show_partitions" { SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.consrc; } +step "s2_show_partitions" { SELECT c.consrc FROM pg_inherits i LEFT JOIN pg_constraint c ON c.conrelid = i.inhrelid AND c.consrc IS NOT NULL WHERE i.inhparent = 'range_rel'::regclass::oid ORDER BY c.oid; } step "s2r" { ROLLBACK; } step "s2c" { COMMIT; } diff --git a/contrib/pg_pathman/specs/rollback_on_create_partitions.spec b/contrib/pg_pathman/specs/rollback_on_create_partitions.spec new file mode 100644 index 0000000000..41fc48d114 --- /dev/null +++ b/contrib/pg_pathman/specs/rollback_on_create_partitions.spec @@ -0,0 +1,48 @@ +setup +{ + CREATE EXTENSION pg_pathman; + CREATE TABLE range_rel(id serial primary key); +} + +teardown +{ + DROP TABLE range_rel CASCADE; + DROP EXTENSION pg_pathman; +} + +session "s1" +step "begin" { BEGIN; } +step "rollback" { ROLLBACK; } +step "commit" { COMMIT; } +step "insert_data" { INSERT INTO range_rel SELECT generate_series(1, 10000); } +step "create_partitions" { SELECT create_range_partitions('range_rel', 'id', 1, 1000); } +step "drop_partitions" { SELECT drop_partitions('range_rel'); } +step "savepoint_a" { SAVEPOINT a; } +step "rollback_a" { ROLLBACK TO SAVEPOINT a; } +step "savepoint_b" { SAVEPOINT b; } +step "rollback_b" { ROLLBACK TO SAVEPOINT b; } +step "savepoint_c" { SAVEPOINT c; } +step "show_rel" { EXPLAIN (COSTS OFF) SELECT * FROM range_rel; } + +permutation "begin" "insert_data" "create_partitions" "show_rel" "rollback" "show_rel" + +permutation "begin" "insert_data" "create_partitions" "show_rel" "commit" "show_rel" + +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "show_rel" "savepoint_c" "rollback" "show_rel" +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "show_rel" "savepoint_c" "commit" "show_rel" + +# rollback to 'b' after dropping partitions +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "savepoint_c" "rollback_b" "show_rel" "rollback" "show_rel" +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "savepoint_c" "rollback_b" "show_rel" "commit" "show_rel" + +# rollback to 'a' after dropping partitions +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "show_rel" "savepoint_c" "rollback_a" "show_rel" "rollback" "show_rel" +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "show_rel" "savepoint_c" "rollback_a" "show_rel" "commit" "show_rel" + +# drop partitions twice in a single transaction +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "show_rel" "savepoint_c" "rollback_b" "drop_partitions" "show_rel" "rollback" "show_rel" +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "show_rel" "savepoint_c" "rollback_b" "drop_partitions" "show_rel" "commit" "show_rel" + +# create partitions twice in a single transaction +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "rollback_a" "create_partitions" "show_rel" "rollback" "show_rel" +permutation "begin" "insert_data" "savepoint_a" "create_partitions" "savepoint_b" "drop_partitions" "rollback_a" "create_partitions" "show_rel" "commit" "show_rel" diff --git a/contrib/pg_pathman/sql/pg_pathman.sql b/contrib/pg_pathman/sql/pathman_basic.sql similarity index 84% rename from contrib/pg_pathman/sql/pg_pathman.sql rename to contrib/pg_pathman/sql/pathman_basic.sql index c302e8e524..2faadd426d 100644 --- a/contrib/pg_pathman/sql/pg_pathman.sql +++ b/contrib/pg_pathman/sql/pathman_basic.sql @@ -12,6 +12,16 @@ INSERT INTO test.hash_rel VALUES (2, 2); INSERT INTO test.hash_rel VALUES (3, 3); SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3); ALTER TABLE test.hash_rel ALTER COLUMN value SET NOT NULL; +SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3, partition_data:=false); +EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; +SELECT * FROM test.hash_rel; +SELECT pathman.set_enable_parent('test.hash_rel', false); +EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; +SELECT * FROM test.hash_rel; +SELECT pathman.set_enable_parent('test.hash_rel', true); +EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; +SELECT * FROM test.hash_rel; +SELECT pathman.drop_partitions('test.hash_rel'); SELECT pathman.create_hash_partitions('test.hash_rel', 'Value', 3); SELECT COUNT(*) FROM test.hash_rel; SELECT COUNT(*) FROM ONLY test.hash_rel; @@ -46,6 +56,11 @@ INSERT INTO test.num_range_rel SELECT COUNT(*) FROM test.num_range_rel; SELECT COUNT(*) FROM ONLY test.num_range_rel; +SELECT * FROM ONLY test.range_rel UNION SELECT * FROM test.range_rel; + +SET pg_pathman.enable_runtimeappend = OFF; +SET pg_pathman.enable_runtimemergeappend = OFF; + VACUUM; /* update triggers test */ @@ -66,6 +81,16 @@ SET enable_seqscan = ON; EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel; EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value = 2; EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value = 2 OR value = 1; +-- Temporarily commented out +-- EXPLAIN (COSTS OFF) SELECT * FROM test.hash_rel WHERE value BETWEEN 1 AND 2; +-- QUERY PLAN +-- ------------------------------------------------- +-- Append +-- -> Seq Scan on hash_rel_1 +-- Filter: ((value >= 1) AND (value <= 2)) +-- -> Seq Scan on hash_rel_2 +-- Filter: ((value >= 1) AND (value <= 2)) +-- (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id > 2500; EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id >= 1000 AND id < 3000; EXPLAIN (COSTS OFF) SELECT * FROM test.num_range_rel WHERE id >= 1500 AND id < 2500; @@ -112,7 +137,9 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel_1 UNION ALL SELECT * FROM test. * Join */ SET enable_hashjoin = OFF; +set enable_nestloop = OFF; SET enable_mergejoin = ON; + EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel j1 JOIN test.range_rel j2 on j2.id = j1.id @@ -130,11 +157,11 @@ WHERE j1.dt < '2015-03-01' AND j2.dt >= '2015-02-01' ORDER BY j2.dt; * Test CTE query */ EXPLAIN (COSTS OFF) - WITH ttt AS (SELECT * FROM test.range_rel WHERE dt >= '2015-02-01' AND dt < '2015-03-15') + WITH ttt AS (SELECT * FROM test.range_rel WHERE dt >= '2015-02-01' AND dt < '2015-03-15') SELECT * FROM ttt; EXPLAIN (COSTS OFF) - WITH ttt AS (SELECT * FROM test.hash_rel WHERE value = 2) + WITH ttt AS (SELECT * FROM test.hash_rel WHERE value = 2) SELECT * FROM ttt; /* @@ -175,16 +202,32 @@ EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel WHERE dt BETWEEN '2014-11-15' A SELECT pathman.detach_range_partition('test.range_rel_archive'); EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel WHERE dt BETWEEN '2014-11-15' AND '2015-01-15'; CREATE TABLE test.range_rel_test1 ( - id SERIAL PRIMARY KEY, - dt TIMESTAMP, - txt TEXT, - abc INTEGER); + id SERIAL PRIMARY KEY, + dt TIMESTAMP, + txt TEXT, + abc INTEGER); SELECT pathman.attach_range_partition('test.range_rel', 'test.range_rel_test1', '2013-01-01'::DATE, '2014-01-01'::DATE); CREATE TABLE test.range_rel_test2 ( - id SERIAL PRIMARY KEY, - dt TIMESTAMP); + id SERIAL PRIMARY KEY, + dt TIMESTAMP); SELECT pathman.attach_range_partition('test.range_rel', 'test.range_rel_test2', '2013-01-01'::DATE, '2014-01-01'::DATE); +/* + * Zero partitions count and adding partitions with specified name + */ +CREATE TABLE test.zero( + id SERIAL PRIMARY KEY, + value INT NOT NULL); +INSERT INTO test.zero SELECT g, g FROM generate_series(1, 100) as g; +SELECT pathman.create_range_partitions('test.zero', 'value', 50, 10, 0); +SELECT pathman.append_range_partition('test.zero', 'test.zero_0'); +SELECT pathman.prepend_range_partition('test.zero', 'test.zero_1'); +SELECT pathman.add_range_partition('test.zero', 50, 70, 'test.zero_50'); +SELECT pathman.append_range_partition('test.zero', 'test.zero_appended'); +SELECT pathman.prepend_range_partition('test.zero', 'test.zero_prepended'); +SELECT pathman.split_range_partition('test.zero_50', 60, 'test.zero_60'); +DROP TABLE test.zero CASCADE; + /* * Check that altering table columns doesn't break trigger */ @@ -195,14 +238,14 @@ SELECT * FROM test.hash_rel WHERE id = 123; /* * Clean up */ -SELECT pathman.drop_hash_partitions('test.hash_rel'); +SELECT pathman.drop_partitions('test.hash_rel'); SELECT COUNT(*) FROM ONLY test.hash_rel; SELECT pathman.create_hash_partitions('test.hash_rel', 'value', 3); -SELECT pathman.drop_hash_partitions('test.hash_rel', TRUE); +SELECT pathman.drop_partitions('test.hash_rel', TRUE); SELECT COUNT(*) FROM ONLY test.hash_rel; DROP TABLE test.hash_rel CASCADE; -SELECT pathman.drop_range_partitions('test.num_range_rel'); +SELECT pathman.drop_partitions('test.num_range_rel'); DROP TABLE test.num_range_rel CASCADE; DROP TABLE test.range_rel CASCADE; @@ -223,6 +266,11 @@ SELECT * FROM test.range_rel WHERE dt = '2014-12-15'; EXPLAIN (COSTS OFF) SELECT * FROM test.range_rel WHERE dt = '2015-03-15'; SELECT * FROM test.range_rel WHERE dt = '2015-03-15'; +SELECT pathman.set_auto('test.range_rel', false); +INSERT INTO test.range_rel (dt) VALUES ('2015-06-01'); +SELECT pathman.set_auto('test.range_rel', true); +INSERT INTO test.range_rel (dt) VALUES ('2015-06-01'); + DROP TABLE test.range_rel CASCADE; SELECT * FROM pathman.pathman_config; @@ -252,7 +300,7 @@ UPDATE test."TeSt" SET a = 1; SELECT * FROM test."TeSt"; SELECT * FROM test."TeSt" WHERE a = 1; EXPLAIN (COSTS OFF) SELECT * FROM test."TeSt" WHERE a = 1; -SELECT pathman.drop_hash_partitions('test."TeSt"'); +SELECT pathman.drop_partitions('test."TeSt"'); SELECT * FROM test."TeSt"; CREATE TABLE test."RangeRel" ( @@ -266,7 +314,7 @@ SELECT pathman.append_range_partition('test."RangeRel"'); SELECT pathman.prepend_range_partition('test."RangeRel"'); SELECT pathman.merge_range_partitions('test."RangeRel_1"', 'test."RangeRel_' || currval('test."RangeRel_seq"') || '"'); SELECT pathman.split_range_partition('test."RangeRel_1"', '2015-01-01'::DATE); -SELECT pathman.drop_range_partitions('test."RangeRel"'); +SELECT pathman.drop_partitions('test."RangeRel"'); SELECT pathman.create_partitions_from_range('test."RangeRel"', 'dt', '2015-01-01'::DATE, '2015-01-05'::DATE, '1 day'::INTERVAL); DROP TABLE test."RangeRel" CASCADE; SELECT * FROM pathman.pathman_config; @@ -275,7 +323,7 @@ CREATE TABLE test."RangeRel" ( dt TIMESTAMP NOT NULL, txt TEXT); SELECT pathman.create_range_partitions('test."RangeRel"', 'id', 1, 100, 3); -SELECT pathman.drop_range_partitions('test."RangeRel"'); +SELECT pathman.drop_partitions('test."RangeRel"'); SELECT pathman.create_partitions_from_range('test."RangeRel"', 'id', 1, 300, 100); DROP TABLE test."RangeRel" CASCADE; @@ -323,9 +371,9 @@ EXPLAIN (COSTS OFF) DELETE FROM range_rel r USING tmp t WHERE r.dt = '2010-01-02 DELETE FROM range_rel r USING tmp t WHERE r.dt = '2010-01-02' AND r.id = t.id; /* Create range partitions from whole range */ -SELECT drop_range_partitions('range_rel'); +SELECT drop_partitions('range_rel'); SELECT create_partitions_from_range('range_rel', 'id', 1, 1000, 100); -SELECT drop_range_partitions('range_rel', TRUE); +SELECT drop_partitions('range_rel', TRUE); SELECT create_partitions_from_range('range_rel', 'dt', '2015-01-01'::date, '2015-12-01'::date, '1 month'::interval); EXPLAIN (COSTS OFF) SELECT * FROM range_rel WHERE dt = '2015-12-15'; @@ -338,4 +386,7 @@ ALTER TABLE replies DROP CONSTRAINT replies_message_id_fkey; SELECT create_range_partitions('messages', 'id', 1, 100, 2); EXPLAIN (COSTS OFF) SELECT * FROM messages; -DROP EXTENSION pg_pathman; + +DROP SCHEMA test CASCADE; +DROP EXTENSION pg_pathman CASCADE; +DROP SCHEMA pathman CASCADE; diff --git a/contrib/pg_pathman/sql/pathman_callbacks.sql b/contrib/pg_pathman/sql/pathman_callbacks.sql new file mode 100644 index 0000000000..3aa174cd23 --- /dev/null +++ b/contrib/pg_pathman/sql/pathman_callbacks.sql @@ -0,0 +1,41 @@ +\set VERBOSITY terse + +CREATE EXTENSION pg_pathman; +CREATE SCHEMA callbacks; + +/* Check callbacks */ + +CREATE OR REPLACE FUNCTION callbacks.abc_on_part_created_callback( + args JSONB) +RETURNS VOID AS $$ +BEGIN + RAISE WARNING 'callback arg: %', args::TEXT; +END +$$ language plpgsql; + + +/* set callback to be called on RANGE partitions */ +CREATE TABLE callbacks.abc(a serial, b int); +SELECT create_range_partitions('callbacks.abc', 'a', 1, 100, 2); + +SELECT set_init_callback('callbacks.abc', + 'callbacks.abc_on_part_created_callback'); + +INSERT INTO callbacks.abc VALUES (123, 1); +INSERT INTO callbacks.abc VALUES (223, 1); + +SELECT append_range_partition('callbacks.abc'); +SELECT prepend_range_partition('callbacks.abc'); +SELECT add_range_partition('callbacks.abc', 401, 502); + +SELECT drop_partitions('callbacks.abc'); + + +/* set callback to be called on HASH partitions */ +SELECT set_init_callback('callbacks.abc', + 'callbacks.abc_on_part_created_callback'); +SELECT create_hash_partitions('callbacks.abc', 'a', 5); + + +DROP SCHEMA callbacks CASCADE; +DROP EXTENSION pg_pathman CASCADE; diff --git a/contrib/pg_pathman/sql/pathman_domains.sql b/contrib/pg_pathman/sql/pathman_domains.sql new file mode 100644 index 0000000000..bc5d227e4e --- /dev/null +++ b/contrib/pg_pathman/sql/pathman_domains.sql @@ -0,0 +1,37 @@ +\set VERBOSITY terse + +CREATE EXTENSION pg_pathman; +CREATE SCHEMA domains; + +CREATE DOMAIN domains.dom_test AS numeric CHECK (value < 1200); + +CREATE TABLE domains.dom_table(val domains.dom_test NOT NULL); +INSERT INTO domains.dom_table SELECT generate_series(1, 999); + +SELECT create_range_partitions('domains.dom_table', 'val', 1, 100); + +EXPLAIN (COSTS OFF) +SELECT * FROM domains.dom_table +WHERE val < 250; + +INSERT INTO domains.dom_table VALUES(1500); +INSERT INTO domains.dom_table VALUES(-10); + +SELECT append_range_partition('domains.dom_table'); +SELECT prepend_range_partition('domains.dom_table'); +SELECT merge_range_partitions('domains.dom_table_1', 'domains.dom_table_2'); +SELECT split_range_partition('domains.dom_table_1', 50); + +INSERT INTO domains.dom_table VALUES(1101); + +EXPLAIN (COSTS OFF) +SELECT * FROM domains.dom_table +WHERE val < 450; + + +SELECT * FROM pathman_partition_list +ORDER BY range_min::INT, range_max::INT; + + +DROP SCHEMA domains CASCADE; +DROP EXTENSION pg_pathman CASCADE; diff --git a/contrib/pg_pathman/sql/pathman_foreign_keys.sql b/contrib/pg_pathman/sql/pathman_foreign_keys.sql new file mode 100644 index 0000000000..a2032815de --- /dev/null +++ b/contrib/pg_pathman/sql/pathman_foreign_keys.sql @@ -0,0 +1,29 @@ +\set VERBOSITY terse + +CREATE EXTENSION pg_pathman; +CREATE SCHEMA fkeys; + +/* Check primary keys generation */ +CREATE TABLE fkeys.test_ref(comment TEXT UNIQUE); +INSERT INTO fkeys.test_ref VALUES('test'); + +CREATE TABLE fkeys.test_fkey( + id INT NOT NULL, + comment TEXT, + FOREIGN KEY (comment) REFERENCES fkeys.test_ref(comment)); + +INSERT INTO fkeys.test_fkey SELECT generate_series(1, 1000), 'test'; + +SELECT create_range_partitions('fkeys.test_fkey', 'id', 1, 100); +INSERT INTO fkeys.test_fkey VALUES(1, 'wrong'); +INSERT INTO fkeys.test_fkey VALUES(1, 'test'); +SELECT drop_partitions('fkeys.test_fkey'); + +SELECT create_hash_partitions('fkeys.test_fkey', 'id', 10); +INSERT INTO fkeys.test_fkey VALUES(1, 'wrong'); +INSERT INTO fkeys.test_fkey VALUES(1, 'test'); +SELECT drop_partitions('fkeys.test_fkey'); + + +DROP SCHEMA fkeys CASCADE; +DROP EXTENSION pg_pathman CASCADE; diff --git a/contrib/pg_pathman/sql/pathman_rowmarks.sql b/contrib/pg_pathman/sql/pathman_rowmarks.sql new file mode 100644 index 0000000000..8397b7fc01 --- /dev/null +++ b/contrib/pg_pathman/sql/pathman_rowmarks.sql @@ -0,0 +1,62 @@ +CREATE EXTENSION pg_pathman; +CREATE SCHEMA rowmarks; + + +CREATE TABLE rowmarks.first(id int NOT NULL); +CREATE TABLE rowmarks.second(id int NOT NULL); + +INSERT INTO rowmarks.first SELECT generate_series(1, 10); +INSERT INTO rowmarks.second SELECT generate_series(1, 10); + + +SELECT create_hash_partitions('rowmarks.first', 'id', 5); + +/* Not partitioned */ +SELECT * FROM rowmarks.second ORDER BY id FOR UPDATE; + +/* Simple case (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first ORDER BY id FOR UPDATE; + +/* Simple case (execution) */ +SELECT * FROM rowmarks.first ORDER BY id FOR UPDATE; +SELECT FROM rowmarks.first ORDER BY id FOR UPDATE; +SELECT tableoid > 0 FROM rowmarks.first ORDER BY id FOR UPDATE; + +/* A little harder (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.first + ORDER BY id + OFFSET 10 LIMIT 1 + FOR UPDATE) +FOR SHARE; + +/* A little harder (execution) */ +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.first + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + +/* Two tables (plan) */ +EXPLAIN (COSTS OFF) +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.second + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + +/* Two tables (execution) */ +SELECT * FROM rowmarks.first +WHERE id = (SELECT id FROM rowmarks.second + ORDER BY id + OFFSET 5 LIMIT 1 + FOR UPDATE) +FOR SHARE; + + +DROP SCHEMA rowmarks CASCADE; +DROP EXTENSION pg_pathman; diff --git a/contrib/pg_pathman/sql/pathman_runtime_nodes.sql b/contrib/pg_pathman/sql/pathman_runtime_nodes.sql new file mode 100644 index 0000000000..517995b9be --- /dev/null +++ b/contrib/pg_pathman/sql/pathman_runtime_nodes.sql @@ -0,0 +1,272 @@ +\set VERBOSITY terse + +CREATE SCHEMA pathman; +CREATE EXTENSION pg_pathman SCHEMA pathman; +CREATE SCHEMA test; + +/* + * Test RuntimeAppend + */ + +create or replace function test.pathman_assert(smt bool, error_msg text) returns text as $$ +begin + if not smt then + raise exception '%', error_msg; + end if; + + return 'ok'; +end; +$$ language plpgsql; + +create or replace function test.pathman_equal(a text, b text, error_msg text) returns text as $$ +begin + if a != b then + raise exception '''%'' is not equal to ''%'', %', a, b, error_msg; + end if; + + return 'equal'; +end; +$$ language plpgsql; + +create or replace function test.pathman_test(query text) returns jsonb as $$ +declare + plan jsonb; +begin + execute 'explain (analyze, format json)' || query into plan; + + return plan; +end; +$$ language plpgsql; + +create or replace function test.pathman_test_1() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.runtime_test_1 where id = (select * from test.run_values limit 1)'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Custom Plan Provider')::text, + '"RuntimeAppend"', + 'wrong plan provider'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Relation Name')::text, + format('"runtime_test_1_%s"', pathman.get_hash_part_idx(hashint4(1), 6)), + 'wrong partition'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans') into num; + perform test.pathman_equal(num::text, '2', 'expected 2 child plans for custom scan'); + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; + +create or replace function test.pathman_test_2() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.runtime_test_1 where id = any (select * from test.run_values limit 4)'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Nested Loop"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Custom Plan Provider')::text, + '"RuntimeAppend"', + 'wrong plan provider'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans'->1->'Plans') into num; + perform test.pathman_equal(num::text, '4', 'expected 4 child plans for custom scan'); + + for i in 0..3 loop + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Plans'->i->'Relation Name')::text, + format('"runtime_test_1_%s"', pathman.get_hash_part_idx(hashint4(i + 1), 6)), + 'wrong partition'); + + num = plan->0->'Plan'->'Plans'->1->'Plans'->i->'Actual Loops'; + perform test.pathman_equal(num::text, '1', 'expected 1 loop'); + end loop; + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; + +create or replace function test.pathman_test_3() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.runtime_test_1 a join test.run_values b on a.id = b.val'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Nested Loop"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Custom Plan Provider')::text, + '"RuntimeAppend"', + 'wrong plan provider'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans'->1->'Plans') into num; + perform test.pathman_equal(num::text, '6', 'expected 6 child plans for custom scan'); + + for i in 0..5 loop + num = plan->0->'Plan'->'Plans'->1->'Plans'->i->'Actual Loops'; + perform test.pathman_assert(num > 0 and num <= 1718, 'expected no more than 1718 loops'); + end loop; + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; + +create or replace function test.pathman_test_4() returns text as $$ +declare + plan jsonb; + num int; +begin + plan = test.pathman_test('select * from test.category c, lateral' || + '(select * from test.runtime_test_2 g where g.category_id = c.id order by rating limit 4) as tg'); + + perform test.pathman_equal((plan->0->'Plan'->'Node Type')::text, + '"Nested Loop"', + 'wrong plan type'); + + /* Limit -> Custom Scan */ + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->0->'Node Type')::text, + '"Custom Scan"', + 'wrong plan type'); + + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->0->'Custom Plan Provider')::text, + '"RuntimeMergeAppend"', + 'wrong plan provider'); + + select count(*) from jsonb_array_elements_text(plan->0->'Plan'->'Plans'->1->'Plans'->0->'Plans') into num; + perform test.pathman_equal(num::text, '4', 'expected 4 child plans for custom scan'); + + for i in 0..3 loop + perform test.pathman_equal((plan->0->'Plan'->'Plans'->1->'Plans'->0->'Plans'->i->'Relation Name')::text, + format('"runtime_test_2_%s"', pathman.get_hash_part_idx(hashint4(i + 1), 6)), + 'wrong partition'); + + num = plan->0->'Plan'->'Plans'->1->'Plans'->0->'Plans'->i->'Actual Loops'; + perform test.pathman_assert(num = 1, 'expected no more than 1 loops'); + end loop; + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_mergejoin = off +set enable_hashjoin = off; + +create or replace function test.pathman_test_5() returns text as $$ +declare + res record; +begin + select + from test.runtime_test_3 + where id = (select * from test.vals order by val limit 1) + limit 1 + into res; /* test empty tlist */ + + + select id, generate_series(1, 2) gen, val + from test.runtime_test_3 + where id = any (select * from test.vals order by val limit 5) + order by id, gen, val + offset 1 limit 1 + into res; /* without IndexOnlyScan */ + + perform test.pathman_equal(res.id::text, '1', 'id is incorrect (t2)'); + perform test.pathman_equal(res.gen::text, '2', 'gen is incorrect (t2)'); + perform test.pathman_equal(res.val::text, 'k = 1', 'val is incorrect (t2)'); + + + select id + from test.runtime_test_3 + where id = any (select * from test.vals order by val limit 5) + order by id + offset 3 limit 1 + into res; /* with IndexOnlyScan */ + + perform test.pathman_equal(res.id::text, '4', 'id is incorrect (t3)'); + + + select v.val v1, generate_series(2, 2) gen, t.val v2 + from test.runtime_test_3 t join test.vals v on id = v.val + order by v1, gen, v2 + limit 1 + into res; + + perform test.pathman_equal(res.v1::text, '1', 'v1 is incorrect (t4)'); + perform test.pathman_equal(res.gen::text, '2', 'gen is incorrect (t4)'); + perform test.pathman_equal(res.v2::text, 'k = 1', 'v2 is incorrect (t4)'); + + return 'ok'; +end; +$$ language plpgsql +set pg_pathman.enable = true +set enable_hashjoin = off +set enable_mergejoin = off; + + + +create table test.run_values as select generate_series(1, 10000) val; +create table test.runtime_test_1(id serial primary key, val real); +insert into test.runtime_test_1 select generate_series(1, 10000), random(); +select pathman.create_hash_partitions('test.runtime_test_1', 'id', 6); + +create table test.category as (select id, 'cat' || id::text as name from generate_series(1, 4) id); +create table test.runtime_test_2 (id serial, category_id int not null, name text, rating real); +insert into test.runtime_test_2 (select id, (id % 6) + 1 as category_id, 'good' || id::text as name, random() as rating from generate_series(1, 100000) id); +create index on test.runtime_test_2 (category_id, rating); +select pathman.create_hash_partitions('test.runtime_test_2', 'category_id', 6); + +create table test.vals as (select generate_series(1, 10000) as val); +create table test.runtime_test_3(val text, id serial not null); +insert into test.runtime_test_3(id, val) select * from generate_series(1, 10000) k, format('k = %s', k); +select pathman.create_hash_partitions('test.runtime_test_3', 'id', 4); +create index on test.runtime_test_3 (id); +create index on test.runtime_test_3_0 (id); + + +analyze test.run_values; +analyze test.runtime_test_1; +analyze test.runtime_test_2; +analyze test.runtime_test_3; +analyze test.runtime_test_3_0; + +set pg_pathman.enable_runtimeappend = on; +set pg_pathman.enable_runtimemergeappend = on; + +select test.pathman_test_1(); /* RuntimeAppend (select ... where id = (subquery)) */ +select test.pathman_test_2(); /* RuntimeAppend (select ... where id = any(subquery)) */ +select test.pathman_test_3(); /* RuntimeAppend (a join b on a.id = b.val) */ +select test.pathman_test_4(); /* RuntimeMergeAppend (lateral) */ +select test.pathman_test_5(); /* projection tests for RuntimeXXX nodes */ + + +DROP SCHEMA test CASCADE; +DROP EXTENSION pg_pathman CASCADE; +DROP SCHEMA pathman CASCADE; + diff --git a/contrib/pg_pathman/src/copy_stmt_hooking.c b/contrib/pg_pathman/src/copy_stmt_hooking.c new file mode 100644 index 0000000000..7b06a4b436 --- /dev/null +++ b/contrib/pg_pathman/src/copy_stmt_hooking.c @@ -0,0 +1,560 @@ +/* ------------------------------------------------------------------------ + * + * copy_stmt_hooking.c + * Override COPY TO/FROM statement for partitioned tables + * + * Copyright (c) 2016, Postgres Professional + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------ + */ + +#include "copy_stmt_hooking.h" +#include "init.h" +#include "partition_filter.h" +#include "relation_info.h" + +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "access/xact.h" +#include "catalog/namespace.h" +#include "catalog/pg_attribute.h" +#include "commands/copy.h" +#include "commands/trigger.h" +#include "executor/executor.h" +#include "foreign/fdwapi.h" +#include "miscadmin.h" +#include "nodes/makefuncs.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/rel.h" +#include "utils/rls.h" + +#include "libpq/libpq.h" + + +static uint64 PathmanCopyFrom(CopyState cstate, + Relation parent_rel, + List *range_table, + bool old_protocol); + +static void prepare_rri_fdw_for_copy(EState *estate, + ResultRelInfoHolder *rri_holder, + void *arg); + + +/* + * Is pg_pathman supposed to handle this COPY stmt? + */ +bool +is_pathman_related_copy(Node *parsetree) +{ + CopyStmt *copy_stmt = (CopyStmt *) parsetree; + Oid partitioned_table; + + Assert(IsPathmanReady()); + + if (!IsOverrideCopyEnabled()) + { + elog(DEBUG1, "COPY statement hooking is disabled"); + return false; + } + + /* Check that it's a CopyStmt */ + if (!IsA(parsetree, CopyStmt)) + return false; + + /* Also check that stmt->relation exists */ + if (!copy_stmt->relation) + return false; + + /* Get partition's Oid while locking it */ + partitioned_table = RangeVarGetRelid(copy_stmt->relation, + (copy_stmt->is_from ? + RowExclusiveLock : + AccessShareLock), + false); + + /* Check that relation is partitioned */ + if (get_pathman_relation_info(partitioned_table)) + { + ListCell *lc; + + /* Analyze options list */ + foreach (lc, copy_stmt->options) + { + DefElem *defel = (DefElem *) lfirst(lc); + + Assert(IsA(defel, DefElem)); + + /* We do not support freeze */ + if (strcmp(defel->defname, "freeze") == 0) + elog(ERROR, "freeze is not supported for partitioned tables"); + } + + elog(DEBUG1, "Overriding default behavior for COPY [%u]", partitioned_table); + return true; + } + + return false; +} + +/* + * CopyGetAttnums - build an integer list of attnums to be copied + * + * The input attnamelist is either the user-specified column list, + * or NIL if there was none (in which case we want all the non-dropped + * columns). + * + * rel can be NULL ... it's only used for error reports. + */ +static List * +CopyGetAttnums(TupleDesc tupDesc, Relation rel, List *attnamelist) +{ + List *attnums = NIL; + + if (attnamelist == NIL) + { + /* Generate default column list */ + Form_pg_attribute *attr = tupDesc->attrs; + int attr_count = tupDesc->natts; + int i; + + for (i = 0; i < attr_count; i++) + { + if (attr[i]->attisdropped) + continue; + attnums = lappend_int(attnums, i + 1); + } + } + else + { + /* Validate the user-supplied list and extract attnums */ + ListCell *l; + + foreach(l, attnamelist) + { + char *name = strVal(lfirst(l)); + int attnum; + int i; + + /* Lookup column name */ + attnum = InvalidAttrNumber; + for (i = 0; i < tupDesc->natts; i++) + { + if (tupDesc->attrs[i]->attisdropped) + continue; + if (namestrcmp(&(tupDesc->attrs[i]->attname), name) == 0) + { + attnum = tupDesc->attrs[i]->attnum; + break; + } + } + if (attnum == InvalidAttrNumber) + { + if (rel != NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + name, RelationGetRelationName(rel)))); + else + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" does not exist", + name))); + } + /* Check for duplicates */ + if (list_member_int(attnums, attnum)) + ereport(ERROR, + (errcode(ERRCODE_DUPLICATE_COLUMN), + errmsg("column \"%s\" specified more than once", + name))); + attnums = lappend_int(attnums, attnum); + } + } + + return attnums; +} + +/* + * Execute COPY TO/FROM statement for a partitioned table. + * NOTE: based on DoCopy() (see copy.c). + */ +void +PathmanDoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) +{ + CopyState cstate; + bool is_from = stmt->is_from; + bool pipe = (stmt->filename == NULL); + Relation rel; + Node *query = NULL; + List *range_table = NIL; + + /* Disallow COPY TO/FROM file or program except to superusers. */ + if (!pipe && !superuser()) + { + if (stmt->is_program) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to COPY to or from an external program"), + errhint("Anyone can COPY to stdout or from stdin. " + "psql's \\copy command also works for anyone."))); + else + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to COPY to or from a file"), + errhint("Anyone can COPY to stdout or from stdin. " + "psql's \\copy command also works for anyone."))); + } + + if (stmt->relation) + { + TupleDesc tupDesc; + AclMode required_access = (is_from ? ACL_INSERT : ACL_SELECT); + List *attnums; + ListCell *cur; + RangeTblEntry *rte; + + Assert(!stmt->query); + + /* Open the relation (we've locked it in is_pathman_related_copy()) */ + rel = heap_openrv(stmt->relation, NoLock); + + rte = makeNode(RangeTblEntry); + rte->rtekind = RTE_RELATION; + rte->relid = RelationGetRelid(rel); + rte->relkind = rel->rd_rel->relkind; + rte->requiredPerms = required_access; + range_table = list_make1(rte); + + tupDesc = RelationGetDescr(rel); + attnums = CopyGetAttnums(tupDesc, rel, stmt->attlist); + foreach(cur, attnums) + { + int attno = lfirst_int(cur) - FirstLowInvalidHeapAttributeNumber; + + if (is_from) + rte->insertedCols = bms_add_member(rte->insertedCols, attno); + else + rte->selectedCols = bms_add_member(rte->selectedCols, attno); + } + ExecCheckRTPerms(range_table, true); + + /* + * We should perform a query instead of low-level heap scan whenever: + * a) table has a RLS policy; + * b) table is partitioned & it's COPY FROM. + */ + if (check_enable_rls(rte->relid, InvalidOid, false) == RLS_ENABLED || + is_from == false) /* rewrite COPY table TO statements */ + { + SelectStmt *select; + ColumnRef *cr; + ResTarget *target; + RangeVar *from; + + if (is_from) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("COPY FROM not supported with row-level security"), + errhint("Use INSERT statements instead."))); + + /* Build target list */ + cr = makeNode(ColumnRef); + + if (!stmt->attlist) + cr->fields = list_make1(makeNode(A_Star)); + else + cr->fields = stmt->attlist; + + cr->location = 1; + + target = makeNode(ResTarget); + target->name = NULL; + target->indirection = NIL; + target->val = (Node *) cr; + target->location = 1; + + /* + * Build RangeVar for from clause, fully qualified based on the + * relation which we have opened and locked. + */ + from = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)), + RelationGetRelationName(rel), -1); + + /* Build query */ + select = makeNode(SelectStmt); + select->targetList = list_make1(target); + select->fromClause = list_make1(from); + + query = (Node *) select; + + /* + * Close the relation for now, but keep the lock on it to prevent + * changes between now and when we start the query-based COPY. + * + * We'll reopen it later as part of the query-based COPY. + */ + heap_close(rel, NoLock); + rel = NULL; + } + } + else + { + Assert(stmt->query); + + query = stmt->query; + rel = NULL; + } + + /* COPY ... FROM ... */ + if (is_from) + { + bool is_old_protocol = PG_PROTOCOL_MAJOR(FrontendProtocol) < 3 && + stmt->filename == NULL; + + /* There should be relation */ + if (!rel) elog(FATAL, "No relation for PATHMAN COPY FROM"); + + /* check read-only transaction and parallel mode */ + if (XactReadOnly && !rel->rd_islocaltemp) + PreventCommandIfReadOnly("PATHMAN COPY FROM"); + PreventCommandIfParallelMode("PATHMAN COPY FROM"); + + cstate = BeginCopyFrom(rel, stmt->filename, stmt->is_program, + stmt->attlist, stmt->options); + *processed = PathmanCopyFrom(cstate, rel, range_table, is_old_protocol); + EndCopyFrom(cstate); + } + /* COPY ... TO ... */ + else + { + CopyStmt modified_copy_stmt; + + /* We should've created a query */ + Assert(query); + + /* Copy 'stmt' and override some of the fields */ + modified_copy_stmt = *stmt; + modified_copy_stmt.relation = NULL; + modified_copy_stmt.query = query; + + /* Call standard DoCopy using a new CopyStmt */ + DoCopy(&modified_copy_stmt, queryString, processed); + } + + /* + * Close the relation. If reading, we can release the AccessShareLock we + * got; if writing, we should hold the lock until end of transaction to + * ensure that updates will be committed before lock is released. + */ + if (rel != NULL) + heap_close(rel, (is_from ? NoLock : AccessShareLock)); +} + +/* + * Copy FROM file to relation. + */ +static uint64 +PathmanCopyFrom(CopyState cstate, Relation parent_rel, + List *range_table, bool old_protocol) +{ + HeapTuple tuple; + TupleDesc tupDesc; + Datum *values; + bool *nulls; + + ResultPartsStorage parts_storage; + ResultRelInfo *parent_result_rel; + + EState *estate = CreateExecutorState(); /* for ExecConstraints() */ + ExprContext *econtext; + TupleTableSlot *myslot; + MemoryContext oldcontext = CurrentMemoryContext; + + uint64 processed = 0; + + + tupDesc = RelationGetDescr(parent_rel); + + parent_result_rel = makeNode(ResultRelInfo); + InitResultRelInfo(parent_result_rel, + parent_rel, + 1, /* dummy rangetable index */ + 0); + ExecOpenIndices(parent_result_rel, false); + + estate->es_result_relations = parent_result_rel; + estate->es_num_result_relations = 1; + estate->es_result_relation_info = parent_result_rel; + estate->es_range_table = range_table; + + /* Initialize ResultPartsStorage */ + init_result_parts_storage(&parts_storage, estate, false, + ResultPartsStorageStandard, + prepare_rri_fdw_for_copy, NULL); + parts_storage.saved_rel_info = parent_result_rel; + + /* Set up a tuple slot too */ + myslot = ExecInitExtraTupleSlot(estate); + ExecSetSlotDescriptor(myslot, tupDesc); + /* Triggers might need a slot as well */ + estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate); + + /* Prepare to catch AFTER triggers. */ + AfterTriggerBeginQuery(); + + /* + * Check BEFORE STATEMENT insertion triggers. It's debatable whether we + * should do this for COPY, since it's not really an "INSERT" statement as + * such. However, executing these triggers maintains consistency with the + * EACH ROW triggers that we already fire on COPY. + */ + ExecBSInsertTriggers(estate, parent_result_rel); + + values = (Datum *) palloc(tupDesc->natts * sizeof(Datum)); + nulls = (bool *) palloc(tupDesc->natts * sizeof(bool)); + + econtext = GetPerTupleExprContext(estate); + + for (;;) + { + TupleTableSlot *slot; + bool skip_tuple; + Oid tuple_oid = InvalidOid; + + const PartRelationInfo *prel; + ResultRelInfoHolder *rri_holder_child; + ResultRelInfo *child_result_rel; + + CHECK_FOR_INTERRUPTS(); + + ResetPerTupleExprContext(estate); + + /* Fetch PartRelationInfo for parent relation */ + prel = get_pathman_relation_info(RelationGetRelid(parent_rel)); + + /* Switch into per tuple memory context */ + MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + + if (!NextCopyFrom(cstate, econtext, values, nulls, &tuple_oid)) + break; + + if (nulls[prel->attnum - 1]) + elog(ERROR, ERR_PART_ATTR_NULL); + + /* Search for a matching partition */ + rri_holder_child = select_partition_for_insert(prel, &parts_storage, + values[prel->attnum - 1], + estate, false); + child_result_rel = rri_holder_child->result_rel_info; + estate->es_result_relation_info = child_result_rel; + + /* And now we can form the input tuple. */ + tuple = heap_form_tuple(tupDesc, values, nulls); + if (tuple_oid != InvalidOid) + HeapTupleSetOid(tuple, tuple_oid); + + /* + * Constraints might reference the tableoid column, so initialize + * t_tableOid before evaluating them. + */ + tuple->t_tableOid = RelationGetRelid(child_result_rel->ri_RelationDesc); + + /* Triggers and stuff need to be invoked in query context. */ + MemoryContextSwitchTo(oldcontext); + + /* Place tuple in tuple slot --- but slot shouldn't free it */ + slot = myslot; + ExecStoreTuple(tuple, slot, InvalidBuffer, false); + + skip_tuple = false; + + /* BEFORE ROW INSERT Triggers */ + if (child_result_rel->ri_TrigDesc && + child_result_rel->ri_TrigDesc->trig_insert_before_row) + { + slot = ExecBRInsertTriggers(estate, child_result_rel, slot); + + if (slot == NULL) /* "do nothing" */ + skip_tuple = true; + else /* trigger might have changed tuple */ + tuple = ExecMaterializeSlot(slot); + } + + /* Proceed if we still have a tuple */ + if (!skip_tuple) + { + List *recheckIndexes = NIL; + + /* Check the constraints of the tuple */ + if (child_result_rel->ri_RelationDesc->rd_att->constr) + ExecConstraints(child_result_rel, slot, estate); + + /* OK, store the tuple and create index entries for it */ + simple_heap_insert(child_result_rel->ri_RelationDesc, tuple); + + if (child_result_rel->ri_NumIndices > 0) + recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), + estate, false, NULL, NIL); + + /* AFTER ROW INSERT Triggers */ + ExecARInsertTriggers(estate, child_result_rel, tuple, + recheckIndexes); + + list_free(recheckIndexes); + + /* + * We count only tuples not suppressed by a BEFORE INSERT trigger; + * this is the same definition used by execMain.c for counting + * tuples inserted by an INSERT command. + */ + processed++; + } + } + + MemoryContextSwitchTo(oldcontext); + + /* + * In the old protocol, tell pqcomm that we can process normal protocol + * messages again. + */ + if (old_protocol) + pq_endmsgread(); + + /* Execute AFTER STATEMENT insertion triggers */ + ExecASInsertTriggers(estate, parent_result_rel); + + /* Handle queued AFTER triggers */ + AfterTriggerEndQuery(estate); + + pfree(values); + pfree(nulls); + + ExecResetTupleTable(estate->es_tupleTable, false); + + /* Close partitions and destroy hash table */ + fini_result_parts_storage(&parts_storage, true); + + FreeExecutorState(estate); + + return processed; +} + +/* + * COPY FROM does not support FDWs, emit ERROR. + */ +static void +prepare_rri_fdw_for_copy(EState *estate, + ResultRelInfoHolder *rri_holder, + void *arg) +{ + ResultRelInfo *rri = rri_holder->result_rel_info; + FdwRoutine *fdw_routine = rri->ri_FdwRoutine; + + if (fdw_routine != NULL) + elog(ERROR, "cannot copy to foreign partition \"%s\"", + get_rel_name(RelationGetRelid(rri->ri_RelationDesc))); +} diff --git a/contrib/pg_pathman/src/copy_stmt_hooking.h b/contrib/pg_pathman/src/copy_stmt_hooking.h new file mode 100644 index 0000000000..389a411c43 --- /dev/null +++ b/contrib/pg_pathman/src/copy_stmt_hooking.h @@ -0,0 +1,23 @@ +/* ------------------------------------------------------------------------ + * + * copy_stmt_hooking.h + * Transaction-specific locks and other functions + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef COPY_STMT_HOOKING_H +#define COPY_STMT_HOOKING_H + + +#include "postgres.h" +#include "commands/copy.h" +#include "nodes/nodes.h" + + +bool is_pathman_related_copy(Node *parsetree); +void PathmanDoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed); + +#endif diff --git a/contrib/pg_pathman/src/hooks.c b/contrib/pg_pathman/src/hooks.c new file mode 100644 index 0000000000..e3a368b6ab --- /dev/null +++ b/contrib/pg_pathman/src/hooks.c @@ -0,0 +1,637 @@ +/* ------------------------------------------------------------------------ + * + * hooks.c + * definitions of rel_pathlist and join_pathlist hooks + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "copy_stmt_hooking.h" +#include "hooks.h" +#include "init.h" +#include "partition_filter.h" +#include "pg_compat.h" +#include "runtimeappend.h" +#include "runtime_merge_append.h" +#include "utils.h" +#include "xact_handling.h" + +#include "access/transam.h" +#include "miscadmin.h" +#include "optimizer/cost.h" +#include "optimizer/restrictinfo.h" +#include "utils/typcache.h" + + +set_join_pathlist_hook_type set_join_pathlist_next = NULL; +set_rel_pathlist_hook_type set_rel_pathlist_hook_next = NULL; +planner_hook_type planner_hook_next = NULL; +post_parse_analyze_hook_type post_parse_analyze_hook_next = NULL; +shmem_startup_hook_type shmem_startup_hook_next = NULL; +ProcessUtility_hook_type process_utility_hook_next = NULL; + + +/* Take care of joins */ +void +pathman_join_pathlist_hook(PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *outerrel, + RelOptInfo *innerrel, + JoinType jointype, + JoinPathExtraData *extra) +{ + JoinCostWorkspace workspace; + RangeTblEntry *inner_rte = root->simple_rte_array[innerrel->relid]; + const PartRelationInfo *inner_prel; + List *pathkeys = NIL, + *joinclauses, + *otherclauses; + ListCell *lc; + WalkerContext context; + double paramsel; + bool innerrel_rinfo_contains_part_attr; + + /* Call hooks set by other extensions */ + if (set_join_pathlist_next) + set_join_pathlist_next(root, joinrel, outerrel, + innerrel, jointype, extra); + + /* Check that both pg_pathman & RuntimeAppend nodes are enabled */ + if (!IsPathmanReady() || !pg_pathman_enable_runtimeappend) + return; + + if (jointype == JOIN_FULL) + return; /* handling full joins is meaningless */ + + /* Check that innerrel is a BASEREL with inheritors & PartRelationInfo */ + if (innerrel->reloptkind != RELOPT_BASEREL || !inner_rte->inh || + !(inner_prel = get_pathman_relation_info(inner_rte->relid))) + { + return; /* Obviously not our case */ + } + + /* + * These codes are used internally in the planner, but are not supported + * by the executor (nor, indeed, by most of the planner). + */ + if (jointype == JOIN_UNIQUE_OUTER || jointype == JOIN_UNIQUE_INNER) + jointype = JOIN_INNER; /* replace with a proper value */ + + /* Extract join clauses which will separate partitions */ + if (IS_OUTER_JOIN(extra->sjinfo->jointype)) + { + extract_actual_join_clauses(extra->restrictlist, + &joinclauses, &otherclauses); + } + else + { + /* We can treat all clauses alike for an inner join */ + joinclauses = extract_actual_clauses(extra->restrictlist, false); + otherclauses = NIL; + } + + paramsel = 1.0; + foreach (lc, joinclauses) + { + WrapperNode *wrap; + + InitWalkerContext(&context, inner_prel, NULL, false); + + wrap = walk_expr_tree((Expr *) lfirst(lc), &context); + paramsel *= wrap->paramsel; + } + + /* Check that innerrel's RestrictInfos contain partitioned column */ + innerrel_rinfo_contains_part_attr = + get_partitioned_attr_clauses(innerrel->baserestrictinfo, + inner_prel, innerrel->relid) != NULL; + + foreach (lc, innerrel->pathlist) + { + AppendPath *cur_inner_path = (AppendPath *) lfirst(lc); + Path *outer, + *inner; + NestPath *nest_path; /* NestLoop we're creating */ + ParamPathInfo *ppi; /* parameterization info */ + Relids inner_required; /* required paremeterization relids */ + List *filtered_joinclauses = NIL; + ListCell *rinfo_lc; + + if (!IsA(cur_inner_path, AppendPath)) + continue; + + /* Select cheapest path for outerrel */ + outer = outerrel->cheapest_total_path; + + /* Make innerrel path depend on outerrel's column */ + inner_required = bms_union(PATH_REQ_OUTER((Path *) cur_inner_path), + bms_make_singleton(outerrel->relid)); + + /* Get the ParamPathInfo for a parameterized path */ + ppi = get_baserel_parampathinfo(root, innerrel, inner_required); + + /* + * Skip if neither rel->baserestrictinfo nor + * ppi->ppi_clauses reference partition attribute + */ + if (!(innerrel_rinfo_contains_part_attr || + (ppi && get_partitioned_attr_clauses(ppi->ppi_clauses, + inner_prel, + innerrel->relid)))) + continue; + + inner = create_runtimeappend_path(root, cur_inner_path, ppi, paramsel); + + initial_cost_nestloop(root, &workspace, jointype, + outer, inner, /* built paths */ + extra->sjinfo, &extra->semifactors); + + pathkeys = build_join_pathkeys(root, joinrel, jointype, outer->pathkeys); + + nest_path = create_nestloop_path(root, joinrel, jointype, &workspace, + extra->sjinfo, &extra->semifactors, + outer, inner, extra->restrictlist, + pathkeys, + calc_nestloop_required_outer(outer, inner)); + + /* Discard all clauses that are to be evaluated by 'inner' */ + foreach (rinfo_lc, extra->restrictlist) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(rinfo_lc); + + Assert(IsA(rinfo, RestrictInfo)); + if (!join_clause_is_movable_to(rinfo, inner->parent)) + filtered_joinclauses = lappend(filtered_joinclauses, rinfo); + } + + /* + * Override 'rows' value produced by standard estimator. + * Currently we use get_parameterized_joinrel_size() since + * it works just fine, but this might change some day. + */ + nest_path->path.rows = get_parameterized_joinrel_size_compat(root, + joinrel, + outer, + inner, + extra->sjinfo, + filtered_joinclauses); + + /* Finally we can add the new NestLoop path */ + add_path(joinrel, (Path *) nest_path); + } +} + +/* Cope with simple relations */ +void +pathman_rel_pathlist_hook(PlannerInfo *root, + RelOptInfo *rel, + Index rti, + RangeTblEntry *rte) +{ + const PartRelationInfo *prel; + RangeTblEntry **new_rte_array; + RelOptInfo **new_rel_array; + int len; + + /* Invoke original hook if needed */ + if (set_rel_pathlist_hook_next != NULL) + set_rel_pathlist_hook_next(root, rel, rti, rte); + + if (!IsPathmanReady()) + return; /* pg_pathman is not ready */ + + /* This works only for SELECT queries (at least for now) */ + if (root->parse->commandType != CMD_SELECT || + !list_member_oid(inheritance_enabled_relids, rte->relid)) + return; + + /* Proceed iff relation 'rel' is partitioned */ + if ((prel = get_pathman_relation_info(rte->relid)) != NULL) + { + ListCell *lc; + Oid *children; + List *ranges, + *wrappers; + PathKey *pathkeyAsc = NULL, + *pathkeyDesc = NULL; + double paramsel = 1.0; + WalkerContext context; + int i; + bool rel_rinfo_contains_part_attr = false; + + if (prel->parttype == PT_RANGE) + { + /* + * Get pathkeys for ascending and descending sort by partition + * column + */ + List *pathkeys; + Var *var; + Oid vartypeid, + varcollid; + int32 type_mod; + TypeCacheEntry *tce; + + /* Make Var from patition column */ + get_rte_attribute_type(rte, prel->attnum, + &vartypeid, &type_mod, &varcollid); + var = makeVar(rti, prel->attnum, vartypeid, type_mod, varcollid, 0); + var->location = -1; + + /* Determine operator type */ + tce = lookup_type_cache(var->vartype, TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); + + /* Make pathkeys */ + pathkeys = build_expression_pathkey(root, (Expr *)var, NULL, + tce->lt_opr, NULL, false); + if (pathkeys) + pathkeyAsc = (PathKey *) linitial(pathkeys); + pathkeys = build_expression_pathkey(root, (Expr *)var, NULL, + tce->gt_opr, NULL, false); + if (pathkeys) + pathkeyDesc = (PathKey *) linitial(pathkeys); + } + + rte->inh = true; /* we must restore 'inh' flag! */ + + children = PrelGetChildrenArray(prel); + ranges = list_make1_irange(make_irange(0, PrelLastChild(prel), false)); + + /* Make wrappers over restrictions and collect final rangeset */ + InitWalkerContext(&context, prel, NULL, false); + wrappers = NIL; + foreach(lc, rel->baserestrictinfo) + { + WrapperNode *wrap; + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); + + wrap = walk_expr_tree(rinfo->clause, &context); + + paramsel *= wrap->paramsel; + wrappers = lappend(wrappers, wrap); + ranges = irange_list_intersect(ranges, wrap->rangeset); + } + + /* + * Expand simple_rte_array and simple_rel_array + */ + len = irange_list_length(ranges); + if (prel->enable_parent) + len++; + + if (len > 0) + { + /* Expand simple_rel_array and simple_rte_array */ + new_rel_array = (RelOptInfo **) + palloc0((root->simple_rel_array_size + len) * sizeof(RelOptInfo *)); + + /* simple_rte_array is an array equivalent of the rtable list */ + new_rte_array = (RangeTblEntry **) + palloc0((root->simple_rel_array_size + len) * sizeof(RangeTblEntry *)); + + /* Copy relations to the new arrays */ + for (i = 0; i < root->simple_rel_array_size; i++) + { + new_rel_array[i] = root->simple_rel_array[i]; + new_rte_array[i] = root->simple_rte_array[i]; + } + + /* Free old arrays */ + pfree(root->simple_rel_array); + pfree(root->simple_rte_array); + + root->simple_rel_array_size += len; + root->simple_rel_array = new_rel_array; + root->simple_rte_array = new_rte_array; + } + + /* Add parent if needed */ + if (prel->enable_parent) + append_child_relation(root, rel, rti, rte, 0, rte->relid, NULL); + + /* + * Iterate all indexes in rangeset and append corresponding child + * relations. + */ + foreach(lc, ranges) + { + IndexRange irange = lfirst_irange(lc); + + for (i = irange.ir_lower; i <= irange.ir_upper; i++) + append_child_relation(root, rel, rti, rte, i, children[i], + wrappers); + } + + /* Clear old path list */ + list_free(rel->pathlist); + + rel->pathlist = NIL; + set_append_rel_pathlist(root, rel, rti, rte, pathkeyAsc, pathkeyDesc); + set_append_rel_size_compat(root, rel, rti, rte); + + /* No need to go further (both nodes are disabled), return */ + if (!(pg_pathman_enable_runtimeappend || + pg_pathman_enable_runtime_merge_append)) + return; + + /* Runtime[Merge]Append is pointless if there are no params in clauses */ + if (!clause_contains_params((Node *) get_actual_clauses(rel->baserestrictinfo))) + return; + + /* Check that rel's RestrictInfo contains partitioned column */ + rel_rinfo_contains_part_attr = + get_partitioned_attr_clauses(rel->baserestrictinfo, + prel, rel->relid) != NULL; + + foreach (lc, rel->pathlist) + { + AppendPath *cur_path = (AppendPath *) lfirst(lc); + Relids inner_required = PATH_REQ_OUTER((Path *) cur_path); + ParamPathInfo *ppi = get_appendrel_parampathinfo(rel, inner_required); + Path *inner_path = NULL; + + /* Skip if rel contains some join-related stuff or path type mismatched */ + if (!(IsA(cur_path, AppendPath) || IsA(cur_path, MergeAppendPath)) || + rel->has_eclass_joins || rel->joininfo) + { + continue; + } + + /* + * Skip if neither rel->baserestrictinfo nor + * ppi->ppi_clauses reference partition attribute + */ + if (!(rel_rinfo_contains_part_attr || + (ppi && get_partitioned_attr_clauses(ppi->ppi_clauses, + prel, rel->relid)))) + continue; + + if (IsA(cur_path, AppendPath) && pg_pathman_enable_runtimeappend) + inner_path = create_runtimeappend_path(root, cur_path, + ppi, paramsel); + else if (IsA(cur_path, MergeAppendPath) && + pg_pathman_enable_runtime_merge_append) + { + /* Check struct layout compatibility */ + if (offsetof(AppendPath, subpaths) != + offsetof(MergeAppendPath, subpaths)) + elog(FATAL, "Struct layouts of AppendPath and " + "MergeAppendPath differ"); + + inner_path = create_runtimemergeappend_path(root, cur_path, + ppi, paramsel); + } + + if (inner_path) + add_path(rel, inner_path); + } + } +} + +/* + * Intercept 'pg_pathman.enable' GUC assignments. + */ +void +pg_pathman_enable_assign_hook(bool newval, void *extra) +{ + elog(DEBUG2, "pg_pathman_enable_assign_hook() [newval = %s] triggered", + newval ? "true" : "false"); + + /* Return quickly if nothing has changed */ + if (newval == (pg_pathman_init_state.pg_pathman_enable && + pg_pathman_init_state.auto_partition && + pg_pathman_init_state.override_copy && + pg_pathman_enable_runtimeappend && + pg_pathman_enable_runtime_merge_append && + pg_pathman_enable_partition_filter)) + return; + + pg_pathman_init_state.auto_partition = newval; + pg_pathman_init_state.override_copy = newval; + pg_pathman_enable_runtime_merge_append = newval; + pg_pathman_enable_runtimeappend = newval; + pg_pathman_enable_partition_filter = newval; + + elog(NOTICE, + "RuntimeAppend, RuntimeMergeAppend and PartitionFilter nodes " + "and some other options have been %s", + newval ? "enabled" : "disabled"); +} + +/* + * Planner hook. It disables inheritance for tables that have been partitioned + * by pathman to prevent standart PostgreSQL partitioning mechanism from + * handling that tables. + */ +PlannedStmt * +pathman_planner_hook(Query *parse, int cursorOptions, ParamListInfo boundParams) +{ +#define ExecuteForPlanTree(planned_stmt, proc) \ + do { \ + ListCell *lc; \ + proc((planned_stmt)->rtable, (planned_stmt)->planTree); \ + foreach (lc, (planned_stmt)->subplans) \ + proc((planned_stmt)->rtable, (Plan *) lfirst(lc)); \ + } while (0) + + PlannedStmt *result; + + /* FIXME: fix these commands (traverse whole query tree) */ + if (IsPathmanReady()) + { + switch(parse->commandType) + { + case CMD_SELECT: + disable_inheritance(parse); + rowmark_add_tableoids(parse); /* add attributes for rowmarks */ + break; + + case CMD_UPDATE: + case CMD_DELETE: + disable_inheritance_cte(parse); + disable_inheritance_subselect(parse); + handle_modification_query(parse); + break; + + default: + break; + } + } + + /* Invoke original hook if needed */ + if (planner_hook_next) + result = planner_hook_next(parse, cursorOptions, boundParams); + else + result = standard_planner(parse, cursorOptions, boundParams); + + if (IsPathmanReady()) + { + /* Give rowmark-related attributes correct names */ + ExecuteForPlanTree(result, postprocess_lock_rows); + + /* Add PartitionFilter node for INSERT queries */ + ExecuteForPlanTree(result, add_partition_filters); + } + + list_free(inheritance_disabled_relids); + list_free(inheritance_enabled_relids); + inheritance_disabled_relids = NIL; + inheritance_enabled_relids = NIL; + + return result; +} + +/* + * Post parse analysis hook. It makes sure the config is loaded before executing + * any statement, including utility commands + */ +void +pathman_post_parse_analysis_hook(ParseState *pstate, Query *query) +{ + /* Invoke original hook if needed */ + if (post_parse_analyze_hook_next) + post_parse_analyze_hook_next(pstate, query); + + /* We shouldn't do anything on BEGIN or SET ISOLATION LEVEL stmts */ + if (query->commandType == CMD_UTILITY && + (xact_is_transaction_stmt(query->utilityStmt) || + xact_is_set_transaction_stmt(query->utilityStmt))) + { + return; + } + + /* Finish delayed invalidation jobs */ + if (IsPathmanReady()) + finish_delayed_invalidation(); + + /* Load config if pg_pathman exists & it's still necessary */ + if (IsPathmanEnabled() && + !IsPathmanInitialized() && + /* Now evaluate the most expensive clause */ + get_pathman_schema() != InvalidOid) + { + load_config(); /* perform main cache initialization */ + } + + inheritance_disabled_relids = NIL; + inheritance_enabled_relids = NIL; +} + +/* + * Initialize dsm_config & shmem_config. + */ +void +pathman_shmem_startup_hook(void) +{ + /* Invoke original hook if needed */ + if (shmem_startup_hook_next != NULL) + shmem_startup_hook_next(); + + /* Allocate shared memory objects */ + LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); + init_shmem_config(); + LWLockRelease(AddinShmemInitLock); +} + +/* + * Invalidate PartRelationInfo cache entry if needed. + */ +void +pathman_relcache_hook(Datum arg, Oid relid) +{ + PartParentSearch search; + Oid partitioned_table; + + if (!IsPathmanReady()) + return; + + /* We shouldn't even consider special OIDs */ + if (relid < FirstNormalObjectId) + return; + + /* Invalidation event for PATHMAN_CONFIG table (probably DROP) */ + if (relid == get_pathman_config_relid()) + delay_pathman_shutdown(); + + /* Invalidate PartParentInfo cache if needed */ + partitioned_table = forget_parent_of_partition(relid, &search); + + switch (search) + { + /* It is (or was) a valid partition */ + case PPS_ENTRY_PART_PARENT: + case PPS_ENTRY_PARENT: + { + elog(DEBUG2, "Invalidation message for partition %u [%u]", + relid, MyProcPid); + + delay_invalidation_parent_rel(partitioned_table); + } + break; + + /* Both syscache and pathman's cache say it isn't a partition */ + case PPS_ENTRY_NOT_FOUND: + { + if (partitioned_table != InvalidOid) + delay_invalidation_parent_rel(partitioned_table); +#ifdef NOT_USED + elog(DEBUG2, "Invalidation message for relation %u [%u]", + relid, MyProcPid); +#endif + } + break; + + /* We can't say anything (state is not transactional) */ + case PPS_NOT_SURE: + { + elog(DEBUG2, "Invalidation message for vague relation %u [%u]", + relid, MyProcPid); + + delay_invalidation_vague_rel(relid); + } + break; + + default: + elog(ERROR, "Not implemented yet (%s)", + CppAsString(pathman_relcache_hook)); + break; + } +} + +/* + * Utility function invoker hook. + */ +void +pathman_process_utility_hook(Node *parsetree, + const char *queryString, + ProcessUtilityContext context, + ParamListInfo params, + DestReceiver *dest, + char *completionTag) +{ + /* Call hooks set by other extensions */ + if (process_utility_hook_next) + process_utility_hook_next(parsetree, queryString, + context, params, + dest, completionTag); + + /* Override standard COPY statement if needed */ + if (IsPathmanReady() && is_pathman_related_copy(parsetree)) + { + uint64 processed; + + PathmanDoCopy((CopyStmt *) parsetree, queryString, &processed); + if (completionTag) + snprintf(completionTag, COMPLETION_TAG_BUFSIZE, + "PATHMAN COPY " UINT64_FORMAT, processed); + + return; /* don't call standard_ProcessUtility() */ + } + + /* Call internal implementation */ + standard_ProcessUtility(parsetree, queryString, + context, params, + dest, completionTag); +} diff --git a/contrib/pg_pathman/src/hooks.h b/contrib/pg_pathman/src/hooks.h new file mode 100644 index 0000000000..5b349a3440 --- /dev/null +++ b/contrib/pg_pathman/src/hooks.h @@ -0,0 +1,62 @@ +/* ------------------------------------------------------------------------ + * + * hooks.h + * prototypes of rel_pathlist and join_pathlist hooks + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef JOIN_HOOK_H +#define JOIN_HOOK_H + +#include "postgres.h" +#include "optimizer/planner.h" +#include "optimizer/paths.h" +#include "parser/analyze.h" +#include "storage/ipc.h" +#include "tcop/utility.h" + + +extern set_join_pathlist_hook_type set_join_pathlist_next; +extern set_rel_pathlist_hook_type set_rel_pathlist_hook_next; +extern planner_hook_type planner_hook_next; +extern post_parse_analyze_hook_type post_parse_analyze_hook_next; +extern shmem_startup_hook_type shmem_startup_hook_next; +extern ProcessUtility_hook_type process_utility_hook_next; + + +void pathman_join_pathlist_hook(PlannerInfo *root, + RelOptInfo *joinrel, + RelOptInfo *outerrel, + RelOptInfo *innerrel, + JoinType jointype, + JoinPathExtraData *extra); + +void pathman_rel_pathlist_hook(PlannerInfo *root, + RelOptInfo *rel, + Index rti, + RangeTblEntry *rte); + +void pg_pathman_enable_assign_hook(char newval, void *extra); + +PlannedStmt * pathman_planner_hook(Query *parse, + int cursorOptions, + ParamListInfo boundParams); + +void pathman_post_parse_analysis_hook(ParseState *pstate, + Query *query); + +void pathman_shmem_startup_hook(void); + +void pathman_relcache_hook(Datum arg, Oid relid); + +void pathman_process_utility_hook(Node *parsetree, + const char *queryString, + ProcessUtilityContext context, + ParamListInfo params, + DestReceiver *dest, + char *completionTag); + +#endif diff --git a/contrib/pg_pathman/src/init.c b/contrib/pg_pathman/src/init.c new file mode 100644 index 0000000000..83d153713b --- /dev/null +++ b/contrib/pg_pathman/src/init.c @@ -0,0 +1,1081 @@ +/* ------------------------------------------------------------------------ + * + * init.c + * Initialization functions + * + * Copyright (c) 2015-2016, Postgres Professional + * + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------ + */ + +#include "hooks.h" +#include "init.h" +#include "pathman.h" +#include "pathman_workers.h" +#include "relation_info.h" +#include "utils.h" + +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "catalog/indexing.h" +#include "catalog/pg_constraint.h" +#include "catalog/pg_inherits.h" +#include "catalog/pg_inherits_fn.h" +#include "catalog/pg_type.h" +#include "miscadmin.h" +#include "optimizer/clauses.h" +#include "parser/parse_coerce.h" +#include "utils/datum.h" +#include "utils/inval.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/memutils.h" +#include "utils/lsyscache.h" +#include "utils/snapmgr.h" +#include "utils/syscache.h" +#include "utils/typcache.h" + +#if PG_VERSION_NUM >= 90600 +#include "catalog/pg_constraint_fn.h" +#endif + + +/* Help user in case of emergency */ +#define INIT_ERROR_HINT "pg_pathman will be disabled to allow you to resolve this issue" + +/* Initial size of 'partitioned_rels' table */ +#define PART_RELS_SIZE 10 +#define CHILD_FACTOR 500 + + +/* Storage for PartRelationInfos */ +HTAB *partitioned_rels = NULL; + +/* Storage for PartParentInfos */ +HTAB *parent_cache = NULL; + +/* pg_pathman's init status */ +PathmanInitState pg_pathman_init_state; + +/* Shall we install new relcache callback? */ +static bool relcache_callback_needed = true; + +/* Functions for various local caches */ +static bool init_pathman_relation_oids(void); +static void fini_pathman_relation_oids(void); +static void init_local_cache(void); +static void fini_local_cache(void); +static void read_pathman_config(void); + +static Expr *get_partition_constraint_expr(Oid partition, AttrNumber part_attno); + +static int cmp_range_entries(const void *p1, const void *p2, void *arg); + +static bool validate_range_constraint(const Expr *expr, + const PartRelationInfo *prel, + Datum *min, + Datum *max); + +static bool validate_hash_constraint(const Expr *expr, + const PartRelationInfo *prel, + uint32 *part_hash); + +static bool read_opexpr_const(const OpExpr *opexpr, + const PartRelationInfo *prel, + Datum *val); + +static int oid_cmp(const void *p1, const void *p2); + + +/* + * Save and restore main init state. + */ + +void +save_pathman_init_state(PathmanInitState *temp_init_state) +{ + *temp_init_state = pg_pathman_init_state; +} + +void +restore_pathman_init_state(const PathmanInitState *temp_init_state) +{ + pg_pathman_init_state = *temp_init_state; +} + +/* + * Create main GUCs. + */ +void +init_main_pathman_toggles(void) +{ + /* Main toggle, load_config() will enable it */ + DefineCustomBoolVariable("pg_pathman.enable", + "Enables pg_pathman's optimizations during the planner stage", + NULL, + &pg_pathman_init_state.pg_pathman_enable, + true, + PGC_SUSET, + 0, + NULL, + pg_pathman_enable_assign_hook, + NULL); + + /* Global toggle for automatic partition creation */ + DefineCustomBoolVariable("pg_pathman.enable_auto_partition", + "Enables automatic partition creation", + NULL, + &pg_pathman_init_state.auto_partition, + true, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); + + /* Global toggle for COPY stmt handling */ + DefineCustomBoolVariable("pg_pathman.override_copy", + "Override COPY statement handling", + NULL, + &pg_pathman_init_state.override_copy, + true, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); +} + +/* + * Create local PartRelationInfo cache & load pg_pathman's config. + * Return true on success. May occasionally emit ERROR. + */ +bool +load_config(void) +{ + /* + * Try to cache important relids. + * + * Once CREATE EXTENSION stmt is processed, get_pathman_schema() + * function starts returning perfectly valid schema Oid, which + * means we have to check that *ALL* pg_pathman's relations' Oids + * have been cached properly. Only then can we assume that + * initialization is not needed anymore. + */ + if (!init_pathman_relation_oids()) + return false; /* remain 'uninitialized', exit before creating main caches */ + + init_local_cache(); /* create 'partitioned_rels' hash table */ + read_pathman_config(); /* read PATHMAN_CONFIG table & fill cache */ + + /* Register pathman_relcache_hook(), currently we can't unregister it */ + if (relcache_callback_needed) + { + CacheRegisterRelcacheCallback(pathman_relcache_hook, PointerGetDatum(NULL)); + relcache_callback_needed = false; + } + + /* Mark pg_pathman as initialized */ + pg_pathman_init_state.initialization_needed = false; + + elog(DEBUG2, "pg_pathman's config has been loaded successfully [%u]", MyProcPid); + + return true; +} + +/* + * Destroy local caches & free memory. + */ +void +unload_config(void) +{ + /* Don't forget to reset pg_pathman's cached relids */ + fini_pathman_relation_oids(); + + /* Destroy 'partitioned_rels' & 'parent_cache' hash tables */ + fini_local_cache(); + + /* Mark pg_pathman as uninitialized */ + pg_pathman_init_state.initialization_needed = true; + + elog(DEBUG2, "pg_pathman's config has been unloaded successfully [%u]", MyProcPid); +} + +/* + * Estimate total amount of shmem needed for pg_pathman to run. + */ +Size +estimate_pathman_shmem_size(void) +{ + return estimate_concurrent_part_task_slots_size() + + MAXALIGN(sizeof(PathmanState)); +} + +/* + * Cache *all* important pg_pathman's relids at once. + * We should NOT rely on any previously cached values. + */ +static bool +init_pathman_relation_oids(void) +{ + Oid schema = get_pathman_schema(); + Assert(schema != InvalidOid); + + /* Cache PATHMAN_CONFIG relation's Oid */ + pathman_config_relid = get_relname_relid(PATHMAN_CONFIG, schema); + if (pathman_config_relid == InvalidOid) + return false; + + /* Cache PATHMAN_CONFIG_PARAMS relation's Oid */ + pathman_config_params_relid = get_relname_relid(PATHMAN_CONFIG_PARAMS, + schema); + if (pathman_config_params_relid == InvalidOid) + return false; + + /* NOTE: add more relations to be cached right here ^^^ */ + + /* Everything is fine, proceed */ + return true; +} + +/* + * Forget *all* pg_pathman's cached relids. + */ +static void +fini_pathman_relation_oids(void) +{ + pathman_config_relid = InvalidOid; + pathman_config_params_relid = InvalidOid; + + /* NOTE: add more relations to be forgotten right here ^^^ */ +} + +/* + * Initialize per-process resources. + */ +static void +init_local_cache(void) +{ + HASHCTL ctl; + + memset(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(PartRelationInfo); + ctl.hcxt = TopMemoryContext; /* place data to persistent mcxt */ + + partitioned_rels = hash_create("pg_pathman's partitioned relations cache", + PART_RELS_SIZE, &ctl, HASH_ELEM | HASH_BLOBS); + + memset(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(Oid); + ctl.entrysize = sizeof(PartParentInfo); + ctl.hcxt = TopMemoryContext; /* place data to persistent mcxt */ + + parent_cache = hash_create("pg_pathman's partition parents cache", + PART_RELS_SIZE * CHILD_FACTOR, + &ctl, HASH_ELEM | HASH_BLOBS); +} + +/* + * Safely free per-process resources. + */ +static void +fini_local_cache(void) +{ + HASH_SEQ_STATUS status; + PartRelationInfo *prel; + + hash_seq_init(&status, partitioned_rels); + while((prel = (PartRelationInfo *) hash_seq_search(&status)) != NULL) + { + if (PrelIsValid(prel)) + { + FreeChildrenArray(prel); + FreeRangesArray(prel); + } + } + + /* Now we can safely destroy hash tables */ + hash_destroy(partitioned_rels); + hash_destroy(parent_cache); + partitioned_rels = NULL; + parent_cache = NULL; +} + +/* + * Initializes pg_pathman's global state (PathmanState) & locks. + */ +void +init_shmem_config(void) +{ + bool found; + + /* Check if module was initialized in postmaster */ + pmstate = ShmemInitStruct("pg_pathman's global state", + sizeof(PathmanState), &found); + if (!found) + { + /* + * Initialize locks in postmaster + */ + if (!IsUnderPostmaster) + { + /* NOTE: dsm_array is redundant, hence the commented code */ + /* pmstate->dsm_init_lock = LWLockAssign(); */ + } + } + + /* Allocate some space for concurrent part slots */ + init_concurrent_part_task_slots(); +} + +/* + * Fill PartRelationInfo with partition-related info. + */ +void +fill_prel_with_partitions(const Oid *partitions, + const uint32 parts_count, + PartRelationInfo *prel) +{ + uint32 i; + Expr *con_expr; + MemoryContext mcxt = TopMemoryContext; + + /* Allocate memory for 'prel->children' & 'prel->ranges' (if needed) */ + prel->children = MemoryContextAllocZero(mcxt, parts_count * sizeof(Oid)); + if (prel->parttype == PT_RANGE) + prel->ranges = MemoryContextAllocZero(mcxt, parts_count * sizeof(RangeEntry)); + prel->children_count = parts_count; + + for (i = 0; i < PrelChildrenCount(prel); i++) + { + con_expr = get_partition_constraint_expr(partitions[i], prel->attnum); + + /* Perform a partitioning_type-dependent task */ + switch (prel->parttype) + { + case PT_HASH: + { + uint32 hash; /* hash value < parts_count */ + + if (validate_hash_constraint(con_expr, prel, &hash)) + prel->children[hash] = partitions[i]; + else + { + DisablePathman(); /* disable pg_pathman since config is broken */ + ereport(ERROR, + (errmsg("Wrong constraint format for HASH partition \"%s\"", + get_rel_name_or_relid(partitions[i])), + errhint(INIT_ERROR_HINT))); + } + } + break; + + case PT_RANGE: + { + Datum range_min, range_max; + + if (validate_range_constraint(con_expr, prel, + &range_min, &range_max)) + { + prel->ranges[i].child_oid = partitions[i]; + prel->ranges[i].min = range_min; + prel->ranges[i].max = range_max; + } + else + { + DisablePathman(); /* disable pg_pathman since config is broken */ + ereport(ERROR, + (errmsg("Wrong constraint format for RANGE partition \"%s\"", + get_rel_name_or_relid(partitions[i])), + errhint(INIT_ERROR_HINT))); + } + } + break; + + default: + { + DisablePathman(); /* disable pg_pathman since config is broken */ + ereport(ERROR, + (errmsg("Unknown partitioning type for relation \"%s\"", + get_rel_name_or_relid(PrelParentRelid(prel))), + errhint(INIT_ERROR_HINT))); + } + } + } + + /* Finalize 'prel' for a RANGE-partitioned table */ + if (prel->parttype == PT_RANGE) + { + MemoryContext old_mcxt; + + /* Sort partitions by RangeEntry->min asc */ + qsort_arg((void *) prel->ranges, PrelChildrenCount(prel), + sizeof(RangeEntry), cmp_range_entries, + (void *) &prel->cmp_proc); + + /* Initialize 'prel->children' array */ + for (i = 0; i < PrelChildrenCount(prel); i++) + prel->children[i] = prel->ranges[i].child_oid; + + /* Copy all min & max Datums to the persistent mcxt */ + old_mcxt = MemoryContextSwitchTo(TopMemoryContext); + for (i = 0; i < PrelChildrenCount(prel); i++) + { + prel->ranges[i].max = datumCopy(prel->ranges[i].max, + prel->attbyval, + prel->attlen); + + prel->ranges[i].min = datumCopy(prel->ranges[i].min, + prel->attbyval, + prel->attlen); + } + MemoryContextSwitchTo(old_mcxt); + + } + +#ifdef USE_ASSERT_CHECKING + /* Check that each partition Oid has been assigned properly */ + if (prel->parttype == PT_HASH) + for (i = 0; i < PrelChildrenCount(prel); i++) + { + if (prel->children[i] == InvalidOid) + { + DisablePathman(); /* disable pg_pathman since config is broken */ + elog(ERROR, "pg_pathman's cache for relation \"%s\" " + "has not been properly initialized", + get_rel_name_or_relid(PrelParentRelid(prel))); + } + } +#endif +} + +/* + * find_inheritance_children + * + * Returns an array containing the OIDs of all relations which + * inherit *directly* from the relation with OID 'parentrelId'. + * + * The specified lock type is acquired on each child relation (but not on the + * given rel; caller should already have locked it). If lockmode is NoLock + * then no locks are acquired, but caller must beware of race conditions + * against possible DROPs of child relations. + * + * borrowed from pg_inherits.c + */ +Oid * +find_inheritance_children_array(Oid parentrelId, LOCKMODE lockmode, uint32 *size) +{ + Relation relation; + SysScanDesc scan; + ScanKeyData key[1]; + HeapTuple inheritsTuple; + Oid inhrelid; + Oid *oidarr; + uint32 maxoids, + numoids, + i; + + /* + * Can skip the scan if pg_class shows the relation has never had a + * subclass. + */ + if (!has_subclass(parentrelId)) + { + *size = 0; + return NULL; + } + + /* + * Scan pg_inherits and build a working array of subclass OIDs. + */ + maxoids = 32; + oidarr = (Oid *) palloc(maxoids * sizeof(Oid)); + numoids = 0; + + relation = heap_open(InheritsRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_inherits_inhparent, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(parentrelId)); + + scan = systable_beginscan(relation, InheritsParentIndexId, true, + NULL, 1, key); + + while ((inheritsTuple = systable_getnext(scan)) != NULL) + { + inhrelid = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhrelid; + if (numoids >= maxoids) + { + maxoids *= 2; + oidarr = (Oid *) repalloc(oidarr, maxoids * sizeof(Oid)); + } + oidarr[numoids++] = inhrelid; + } + + systable_endscan(scan); + + heap_close(relation, AccessShareLock); + + /* + * If we found more than one child, sort them by OID. This ensures + * reasonably consistent behavior regardless of the vagaries of an + * indexscan. This is important since we need to be sure all backends + * lock children in the same order to avoid needless deadlocks. + */ + if (numoids > 1) + qsort(oidarr, numoids, sizeof(Oid), oid_cmp); + + /* + * Acquire locks and build the result list. + */ + for (i = 0; i < numoids; i++) + { + inhrelid = oidarr[i]; + + if (lockmode != NoLock) + { + /* Get the lock to synchronize against concurrent drop */ + LockRelationOid(inhrelid, lockmode); + + /* + * Now that we have the lock, double-check to see if the relation + * really exists or not. If not, assume it was dropped while we + * waited to acquire lock, and ignore it. + */ + if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(inhrelid))) + { + /* Release useless lock */ + UnlockRelationOid(inhrelid, lockmode); + /* And ignore this relation */ + continue; + } + } + } + + *size = numoids; + return oidarr; +} + +/* + * Generate check constraint name for a partition. + * + * This function does not perform sanity checks at all. + */ +char * +build_check_constraint_name_internal(Oid relid, AttrNumber attno) +{ + return psprintf("pathman_%s_%u_check", get_rel_name(relid), attno); +} + +/* + * Check that relation 'relid' is partitioned by pg_pathman. + * + * Extract tuple into 'values' and 'isnull' if they're provided. + */ +bool +pathman_config_contains_relation(Oid relid, Datum *values, bool *isnull, + TransactionId *xmin) +{ + Relation rel; + HeapScanDesc scan; + ScanKeyData key[1]; + Snapshot snapshot; + HeapTuple htup; + bool contains_rel = false; + + ScanKeyInit(&key[0], + Anum_pathman_config_partrel, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + /* Open PATHMAN_CONFIG with latest snapshot available */ + rel = heap_open(get_pathman_config_relid(), AccessShareLock); + + /* Check that 'partrel' column is if regclass type */ + Assert(RelationGetDescr(rel)-> + attrs[Anum_pathman_config_partrel - 1]-> + atttypid == REGCLASSOID); + + /* Check that number of columns == Natts_pathman_config */ + Assert(RelationGetDescr(rel)->natts == Natts_pathman_config); + + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = heap_beginscan(rel, snapshot, 1, key); + + while ((htup = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + contains_rel = true; /* found partitioned table */ + + /* Extract data if necessary */ + if (values && isnull) + { + heap_deform_tuple(htup, RelationGetDescr(rel), values, isnull); + + /* Perform checks for non-NULL columns */ + Assert(!isnull[Anum_pathman_config_partrel - 1]); + Assert(!isnull[Anum_pathman_config_attname - 1]); + Assert(!isnull[Anum_pathman_config_parttype - 1]); + } + + /* Set xmin if necessary */ + if (xmin) + { + Datum value; + bool isnull; + + value = heap_getsysattr(htup, + MinTransactionIdAttributeNumber, + RelationGetDescr(rel), + &isnull); + + Assert(!isnull); + *xmin = DatumGetTransactionId(value); + } + } + + /* Clean resources */ + heap_endscan(scan); + UnregisterSnapshot(snapshot); + heap_close(rel, AccessShareLock); + + elog(DEBUG2, "PATHMAN_CONFIG table %s relation %u", + (contains_rel ? "contains" : "doesn't contain"), relid); + + return contains_rel; +} + +/* + * Loads additional pathman parameters like 'enable_parent' or 'auto' + * from PATHMAN_CONFIG_PARAMS + */ +bool +read_pathman_params(Oid relid, Datum *values, bool *isnull) +{ + Relation rel; + HeapScanDesc scan; + ScanKeyData key[1]; + Snapshot snapshot; + HeapTuple htup; + bool row_found = false; + + ScanKeyInit(&key[0], + Anum_pathman_config_params_partrel, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + + rel = heap_open(get_pathman_config_params_relid(), AccessShareLock); + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = heap_beginscan(rel, snapshot, 1, key); + + /* There should be just 1 row */ + if ((htup = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + /* Extract data if necessary */ + heap_deform_tuple(htup, RelationGetDescr(rel), values, isnull); + row_found = true; + + /* Perform checks for non-NULL columns */ + Assert(!isnull[Anum_pathman_config_params_partrel - 1]); + Assert(!isnull[Anum_pathman_config_params_enable_parent - 1]); + Assert(!isnull[Anum_pathman_config_params_auto - 1]); + Assert(!isnull[Anum_pathman_config_params_init_callback - 1]); + } + + /* Clean resources */ + heap_endscan(scan); + UnregisterSnapshot(snapshot); + heap_close(rel, AccessShareLock); + + return row_found; +} + +/* + * Go through the PATHMAN_CONFIG table and create PartRelationInfo entries. + */ +static void +read_pathman_config(void) +{ + Relation rel; + HeapScanDesc scan; + Snapshot snapshot; + HeapTuple htup; + + /* Open PATHMAN_CONFIG with latest snapshot available */ + rel = heap_open(get_pathman_config_relid(), AccessShareLock); + + /* Check that 'partrel' column is if regclass type */ + Assert(RelationGetDescr(rel)-> + attrs[Anum_pathman_config_partrel - 1]-> + atttypid == REGCLASSOID); + + /* Check that number of columns == Natts_pathman_config */ + Assert(RelationGetDescr(rel)->natts == Natts_pathman_config); + + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = heap_beginscan(rel, snapshot, 0, NULL); + + /* Examine each row and create a PartRelationInfo in local cache */ + while((htup = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Datum values[Natts_pathman_config]; + bool isnull[Natts_pathman_config]; + Oid relid; /* partitioned table */ + PartType parttype; /* partitioning type */ + text *attname; /* partitioned column name */ + + /* Extract Datums from tuple 'htup' */ + heap_deform_tuple(htup, RelationGetDescr(rel), values, isnull); + + /* These attributes are marked as NOT NULL, check anyway */ + Assert(!isnull[Anum_pathman_config_partrel - 1]); + Assert(!isnull[Anum_pathman_config_parttype - 1]); + Assert(!isnull[Anum_pathman_config_attname - 1]); + + /* Extract values from Datums */ + relid = DatumGetObjectId(values[Anum_pathman_config_partrel - 1]); + parttype = DatumGetPartType(values[Anum_pathman_config_parttype - 1]); + attname = DatumGetTextP(values[Anum_pathman_config_attname - 1]); + + /* Check that relation 'relid' exists */ + if (get_rel_type_id(relid) == InvalidOid) + { + DisablePathman(); /* disable pg_pathman since config is broken */ + ereport(ERROR, + (errmsg("Table \"%s\" contains nonexistent relation %u", + PATHMAN_CONFIG, relid), + errhint(INIT_ERROR_HINT))); + } + + /* Create or update PartRelationInfo for this partitioned table */ + refresh_pathman_relation_info(relid, parttype, text_to_cstring(attname)); + } + + /* Clean resources */ + heap_endscan(scan); + UnregisterSnapshot(snapshot); + heap_close(rel, AccessShareLock); +} + +/* + * Get constraint expression tree for a partition. + * + * build_check_constraint_name_internal() is used to build conname. + */ +static Expr * +get_partition_constraint_expr(Oid partition, AttrNumber part_attno) +{ + Oid conid; /* constraint Oid */ + char *conname; /* constraint name */ + HeapTuple con_tuple; + Datum conbin_datum; + bool conbin_isnull; + Expr *expr; /* expression tree for constraint */ + + conname = build_check_constraint_name_internal(partition, part_attno); + conid = get_relation_constraint_oid(partition, conname, true); + if (conid == InvalidOid) + { + DisablePathman(); /* disable pg_pathman since config is broken */ + ereport(ERROR, + (errmsg("constraint \"%s\" for partition \"%s\" does not exist", + conname, get_rel_name_or_relid(partition)), + errhint(INIT_ERROR_HINT))); + } + + con_tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(conid)); + conbin_datum = SysCacheGetAttr(CONSTROID, con_tuple, + Anum_pg_constraint_conbin, + &conbin_isnull); + if (conbin_isnull) + { + DisablePathman(); /* disable pg_pathman since config is broken */ + ereport(WARNING, + (errmsg("constraint \"%s\" for partition \"%s\" has NULL conbin", + conname, get_rel_name_or_relid(partition)), + errhint(INIT_ERROR_HINT))); + pfree(conname); + + return NULL; /* could not parse */ + } + pfree(conname); + + /* Finally we get a constraint expression tree */ + expr = (Expr *) stringToNode(TextDatumGetCString(conbin_datum)); + + /* Don't foreget to release syscache tuple */ + ReleaseSysCache(con_tuple); + + return expr; +} + +/* qsort comparison function for RangeEntries */ +static int +cmp_range_entries(const void *p1, const void *p2, void *arg) +{ + const RangeEntry *v1 = (const RangeEntry *) p1; + const RangeEntry *v2 = (const RangeEntry *) p2; + + Oid cmp_proc_oid = *(Oid *) arg; + + return OidFunctionCall2(cmp_proc_oid, v1->min, v2->min); +} + +/* + * Validates range constraint. It MUST have this exact format: + * + * VARIABLE >= CONST AND VARIABLE < CONST + * + * Writes 'min' & 'max' values on success. + */ +static bool +validate_range_constraint(const Expr *expr, + const PartRelationInfo *prel, + Datum *min, + Datum *max) +{ + const TypeCacheEntry *tce; + const BoolExpr *boolexpr = (const BoolExpr *) expr; + const OpExpr *opexpr; + + if (!expr) + return false; + + /* it should be an AND operator on top */ + if (!and_clause((Node *) expr)) + return false; + + tce = lookup_type_cache(prel->atttype, TYPECACHE_BTREE_OPFAMILY); + + /* check that left operand is >= operator */ + opexpr = (OpExpr *) linitial(boolexpr->args); + if (BTGreaterEqualStrategyNumber == get_op_opfamily_strategy(opexpr->opno, + tce->btree_opf)) + { + if (!read_opexpr_const(opexpr, prel, min)) + return false; + } + else + return false; + + /* check that right operand is < operator */ + opexpr = (OpExpr *) lsecond(boolexpr->args); + if (BTLessStrategyNumber == get_op_opfamily_strategy(opexpr->opno, + tce->btree_opf)) + { + if (!read_opexpr_const(opexpr, prel, max)) + return false; + } + else + return false; + + return true; +} + +/* + * Reads const value from expressions of kind: + * 1) VAR >= CONST OR VAR < CONST + * 2) RELABELTYPE(VAR) >= CONST OR RELABELTYPE(VAR) < CONST + */ +static bool +read_opexpr_const(const OpExpr *opexpr, + const PartRelationInfo *prel, + Datum *val) +{ + const Node *left; + const Node *right; + const Var *part_attr; /* partitioned column */ + const Const *constant; + + if (list_length(opexpr->args) != 2) + return false; + + left = linitial(opexpr->args); + right = lsecond(opexpr->args); + + /* VAR is a part of RelabelType node */ + if (IsA(left, RelabelType) && IsA(right, Const)) + { + Var *var = (Var *) ((RelabelType *) left)->arg; + + if (IsA(var, Var)) + part_attr = var; + else + return false; + } + /* left arg is of type VAR */ + else if (IsA(left, Var) && IsA(right, Const)) + { + part_attr = (Var *) left; + } + /* Something is wrong, retreat! */ + else return false; + + /* VAR.attno == partitioned attribute number */ + if (part_attr->varoattno != prel->attnum) + return false; + + /* CONST is NOT NULL */ + if (((Const *) right)->constisnull) + return false; + + constant = (Const *) right; + + /* Check that types are binary coercible */ + if (IsBinaryCoercible(constant->consttype, prel->atttype)) + { + *val = constant->constvalue; + } + /* If not, try to perfrom a type cast */ + else + { + CoercionPathType ret; + Oid castfunc = InvalidOid; + + ret = find_coercion_pathway(prel->atttype, constant->consttype, + COERCION_EXPLICIT, &castfunc); + + switch (ret) + { + /* There's a function */ + case COERCION_PATH_FUNC: + { + /* Perform conversion */ + Assert(castfunc != InvalidOid); + *val = OidFunctionCall1(castfunc, constant->constvalue); + } + break; + + /* Types are binary compatible (no implicit cast) */ + case COERCION_PATH_RELABELTYPE: + { + /* We don't perform any checks here */ + *val = constant->constvalue; + } + break; + + /* TODO: implement these if needed */ + case COERCION_PATH_ARRAYCOERCE: + case COERCION_PATH_COERCEVIAIO: + + /* There's no cast available */ + case COERCION_PATH_NONE: + default: + { + elog(WARNING, "Constant type in some check constraint " + "does not match the partitioned column's type"); + return false; + } + } + } + + return true; +} + +/* + * Validate hash constraint. It MUST have this exact format: + * + * get_hash_part_idx(TYPE_HASH_PROC(VALUE), PARTITIONS_COUNT) = CUR_PARTITION_HASH + * + * Writes 'part_hash' hash value for this partition on success. + */ +static bool +validate_hash_constraint(const Expr *expr, + const PartRelationInfo *prel, + uint32 *part_hash) +{ + const TypeCacheEntry *tce; + const OpExpr *eq_expr; + const FuncExpr *get_hash_expr, + *type_hash_proc_expr; + const Var *var; /* partitioned column */ + + if (!expr) + return false; + + if (!IsA(expr, OpExpr)) + return false; + eq_expr = (const OpExpr *) expr; + + /* Check that left expression is a function call */ + if (!IsA(linitial(eq_expr->args), FuncExpr)) + return false; + + get_hash_expr = (FuncExpr *) linitial(eq_expr->args); /* get_hash_part_idx(...) */ + + /* Is 'eqexpr' an equality operator? */ + tce = lookup_type_cache(get_hash_expr->funcresulttype, TYPECACHE_BTREE_OPFAMILY); + if (BTEqualStrategyNumber != get_op_opfamily_strategy(eq_expr->opno, + tce->btree_opf)) + return false; + + if (list_length(get_hash_expr->args) == 2) + { + Node *first = linitial(get_hash_expr->args); /* arg #1: TYPE_HASH_PROC(VALUE) */ + Node *second = lsecond(get_hash_expr->args); /* arg #2: PARTITIONS_COUNT */ + Const *cur_partition_hash; /* hash value for this partition */ + + if (!IsA(first, FuncExpr) || !IsA(second, Const)) + return false; + + type_hash_proc_expr = (FuncExpr *) first; + + /* Check that function is indeed TYPE_HASH_PROC */ + if (type_hash_proc_expr->funcid != prel->hash_proc || + !(IsA(linitial(type_hash_proc_expr->args), Var) || + IsA(linitial(type_hash_proc_expr->args), RelabelType))) + { + return false; + } + + /* Extract argument into 'var' */ + if (IsA(linitial(type_hash_proc_expr->args), RelabelType)) + var = (Var *) ((RelabelType *) linitial(type_hash_proc_expr->args))->arg; + else + var = (Var *) linitial(type_hash_proc_expr->args); + + /* Check that 'var' is the partitioning key attribute */ + if (var->varoattno != prel->attnum) + return false; + + /* Check that PARTITIONS_COUNT is equal to total amount of partitions */ + if (DatumGetUInt32(((Const *) second)->constvalue) != PrelChildrenCount(prel)) + return false; + + /* Check that CUR_PARTITION_HASH is Const */ + if (!IsA(lsecond(eq_expr->args), Const)) + return false; + + cur_partition_hash = lsecond(eq_expr->args); + + /* Check that CUR_PARTITION_HASH is NOT NULL */ + if (cur_partition_hash->constisnull) + return false; + + *part_hash = DatumGetUInt32(cur_partition_hash->constvalue); + if (*part_hash >= PrelChildrenCount(prel)) + return false; + + return true; /* everything seems to be ok */ + } + + return false; +} + +/* needed for find_inheritance_children_array() function */ +static int +oid_cmp(const void *p1, const void *p2) +{ + Oid v1 = *((const Oid *) p1); + Oid v2 = *((const Oid *) p2); + + if (v1 < v2) + return -1; + if (v1 > v2) + return 1; + return 0; +} diff --git a/contrib/pg_pathman/src/init.h b/contrib/pg_pathman/src/init.h new file mode 100644 index 0000000000..effb2675c7 --- /dev/null +++ b/contrib/pg_pathman/src/init.h @@ -0,0 +1,128 @@ +/* ------------------------------------------------------------------------ + * + * init.h + * Initialization functions + * + * Copyright (c) 2015-2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef PATHMAN_INIT_H +#define PATHMAN_INIT_H + +#include "relation_info.h" + +#include "postgres.h" +#include "storage/lmgr.h" +#include "utils/guc.h" +#include "utils/hsearch.h" +#include "utils/snapshot.h" + + +/* + * pg_pathman's initialization state structure. + */ +typedef struct +{ + bool pg_pathman_enable; /* GUC variable implementation */ + bool auto_partition; /* GUC variable for auto partition propagation */ + bool override_copy; /* override COPY TO/FROM */ + bool initialization_needed; /* do we need to perform init? */ +} PathmanInitState; + + +extern HTAB *partitioned_rels; +extern HTAB *parent_cache; + +/* pg_pathman's initialization state */ +extern PathmanInitState pg_pathman_init_state; + + +/* + * Check if pg_pathman is initialized. + */ +#define IsPathmanInitialized() ( !pg_pathman_init_state.initialization_needed ) + +/* + * Check if pg_pathman is enabled. + */ +#define IsPathmanEnabled() ( pg_pathman_init_state.pg_pathman_enable ) + +/* + * Check if pg_pathman is initialized & enabled. + */ +#define IsPathmanReady() ( IsPathmanInitialized() && IsPathmanEnabled() ) + +/* + * Should we override COPY stmt handling? + */ +#define IsOverrideCopyEnabled() ( pg_pathman_init_state.override_copy ) + +/* + * Check if auto partition creation is enabled. + */ +#define IsAutoPartitionEnabled() ( pg_pathman_init_state.auto_partition ) + +/* + * Enable/disable auto partition propagation. Note that this only works if + * partitioned relation supports this. See enable_auto() and disable_auto() + * functions. + */ +#define SetAutoPartitionEnabled(value) \ + do { \ + Assert((value) == true || (value) == false); \ + pg_pathman_init_state.auto_partition = (value); \ + } while (0) + +/* + * Emergency disable mechanism. + */ +#define DisablePathman() \ + do { \ + pg_pathman_init_state.pg_pathman_enable = false; \ + pg_pathman_init_state.auto_partition = false; \ + pg_pathman_init_state.override_copy = false; \ + pg_pathman_init_state.initialization_needed = true; \ + } while (0) + + +/* + * Save and restore PathmanInitState. + */ +void save_pathman_init_state(PathmanInitState *temp_init_state); +void restore_pathman_init_state(const PathmanInitState *temp_init_state); + +/* + * Create main GUC variables. + */ +void init_main_pathman_toggles(void); + +Size estimate_pathman_shmem_size(void); +void init_shmem_config(void); + +bool load_config(void); +void unload_config(void); + + +void fill_prel_with_partitions(const Oid *partitions, + const uint32 parts_count, + PartRelationInfo *prel); + +Oid *find_inheritance_children_array(Oid parentrelId, + LOCKMODE lockmode, + uint32 *size); + +char *build_check_constraint_name_internal(Oid relid, + AttrNumber attno); + +bool pathman_config_contains_relation(Oid relid, + Datum *values, + bool *isnull, + TransactionId *xmin); + +bool read_pathman_params(Oid relid, + Datum *values, + bool *isnull); + +#endif diff --git a/contrib/pg_pathman/src/nodes_common.c b/contrib/pg_pathman/src/nodes_common.c new file mode 100644 index 0000000000..f75bd2f123 --- /dev/null +++ b/contrib/pg_pathman/src/nodes_common.c @@ -0,0 +1,641 @@ +/* ------------------------------------------------------------------------ + * + * nodes_common.c + * Common code for custom nodes + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "nodes_common.h" +#include "runtimeappend.h" +#include "utils.h" + +#include "access/sysattr.h" +#include "optimizer/restrictinfo.h" +#include "optimizer/var.h" +#include "utils/memutils.h" + + +/* Allocation settings */ +#define INITIAL_ALLOC_NUM 10 +#define ALLOC_EXP 2 + + +/* Compare plans by 'original_order' */ +static int +cmp_child_scan_common_by_orig_order(const void *ap, + const void *bp) +{ + ChildScanCommon a = *(ChildScanCommon *) ap; + ChildScanCommon b = *(ChildScanCommon *) bp; + + if (a->original_order > b->original_order) + return 1; + else if (a->original_order < b->original_order) + return -1; + else + return 0; +} + +static void +transform_plans_into_states(RuntimeAppendState *scan_state, + ChildScanCommon *selected_plans, int n, + EState *estate) +{ + int i; + + for (i = 0; i < n; i++) + { + ChildScanCommon child = selected_plans[i]; + PlanState *ps; + + /* Create new node since this plan hasn't been used yet */ + if (child->content_type != CHILD_PLAN_STATE) + { + Assert(child->content_type == CHILD_PLAN); /* no paths allowed */ + + ps = ExecInitNode(child->content.plan, estate, 0); + child->content.plan_state = ps; + child->content_type = CHILD_PLAN_STATE; /* update content type */ + + /* Explain and clear_plan_states rely on this list */ + scan_state->css.custom_ps = lappend(scan_state->css.custom_ps, ps); + } + else + ps = child->content.plan_state; + + /* Node with params will be ReScanned */ + if (scan_state->css.ss.ps.chgParam) + UpdateChangedParamSet(ps, scan_state->css.ss.ps.chgParam); + + /* + * We should ReScan this node manually since + * ExecProcNode won't do this for us in this case. + */ + if (bms_is_empty(ps->chgParam)) + ExecReScan(ps); + + child->content.plan_state = ps; + } +} + +static ChildScanCommon * +select_required_plans(HTAB *children_table, Oid *parts, int nparts, int *nres) +{ + uint32 allocated = INITIAL_ALLOC_NUM, + used = 0; + ChildScanCommon *result; + int i; + + result = (ChildScanCommon *) palloc(allocated * sizeof(ChildScanCommon)); + + for (i = 0; i < nparts; i++) + { + ChildScanCommon child = hash_search(children_table, + (const void *) &parts[i], + HASH_FIND, NULL); + if (!child) + continue; /* no plan for this partition */ + + if (allocated <= used) + { + allocated = allocated * ALLOC_EXP + 1; + result = repalloc(result, allocated * sizeof(ChildScanCommon)); + } + + result[used++] = child; + } + + *nres = used; + return result; +} + +/* Replace Vars' varnos with the value provided by 'parent' */ +static List * +replace_tlist_varnos(List *child_tlist, RelOptInfo *parent) +{ + ListCell *lc; + List *result = NIL; + int i = 1; /* resnos begin with 1 */ + + foreach (lc, child_tlist) + { + Var *var = (Var *) ((TargetEntry *) lfirst(lc))->expr; + Var *newvar = (Var *) palloc(sizeof(Var)); + + Assert(IsA(var, Var)); + + *newvar = *var; + newvar->varno = parent->relid; + newvar->varnoold = parent->relid; + + result = lappend(result, makeTargetEntry((Expr *) newvar, + i++, /* item's index */ + NULL, false)); + } + + return result; +} + +/* Append partition attribute in case it's not present in target list */ +static List * +append_part_attr_to_tlist(List *tlist, Index relno, const PartRelationInfo *prel) +{ + ListCell *lc; + bool part_attr_found = false; + + foreach (lc, tlist) + { + TargetEntry *te = (TargetEntry *) lfirst(lc); + Var *var = (Var *) te->expr; + + if (IsA(var, Var) && var->varoattno == prel->attnum) + part_attr_found = true; + } + + if (!part_attr_found) + { + Var *newvar = makeVar(relno, + prel->attnum, + prel->atttype, + prel->atttypmod, + prel->attcollid, + 0); + + Index last_item = list_length(tlist) + 1; + + tlist = lappend(tlist, makeTargetEntry((Expr *) newvar, + last_item, + NULL, false)); + } + + return tlist; +} + +static void +pack_runtimeappend_private(CustomScan *cscan, RuntimeAppendPath *path, + bool enable_parent) +{ + ChildScanCommon *children = path->children; + int nchildren = path->nchildren; + List *custom_private = NIL, + *custom_oids = NIL; + int i; + + for (i = 0; i < nchildren; i++) + { + /* We've already filled 'custom_paths' in create_runtimeappend_path */ + custom_oids = lappend_oid(custom_oids, children[i]->relid); + pfree(children[i]); + } + + /* Save parent & partition Oids and a flag as first element of 'custom_private' */ + custom_private = lappend(custom_private, + list_make3(list_make1_oid(path->relid), + custom_oids, /* list of Oids */ + list_make1_int(enable_parent))); + + /* Store freshly built 'custom_private' */ + cscan->custom_private = custom_private; +} + +static void +unpack_runtimeappend_private(RuntimeAppendState *scan_state, CustomScan *cscan) +{ + ListCell *oid_cell, + *plan_cell; + List *runtimeappend_private = linitial(cscan->custom_private), + *custom_oids; /* Oids of partitions */ + int custom_oids_count; /* number of partitions */ + + HTAB *children_table; + HASHCTL *children_table_config = &scan_state->children_table_config; + int i; + + /* Extract Oids list from packed data */ + custom_oids = (List *) lsecond(runtimeappend_private); + custom_oids_count = list_length(custom_oids); + + memset(children_table_config, 0, sizeof(HASHCTL)); + children_table_config->keysize = sizeof(Oid); + children_table_config->entrysize = sizeof(ChildScanCommonData); + + children_table = hash_create("RuntimeAppend plan storage", + custom_oids_count, + children_table_config, + HASH_ELEM | HASH_BLOBS); + + i = 0; + forboth (oid_cell, custom_oids, plan_cell, cscan->custom_plans) + { + bool child_found; + Oid cur_oid = lfirst_oid(oid_cell); + + ChildScanCommon child = hash_search(children_table, + (const void *) &cur_oid, + HASH_ENTER, &child_found); + + Assert(!child_found); /* there should be no collisions */ + + child->content_type = CHILD_PLAN; + child->content.plan = (Plan *) lfirst(plan_cell); + child->original_order = i++; /* will be used in EXPLAIN */ + } + + /* Finally fill 'scan_state' with unpacked elements */ + scan_state->children_table = children_table; + scan_state->relid = linitial_oid(linitial(runtimeappend_private)); + scan_state->enable_parent = (bool) linitial_int(lthird(runtimeappend_private)); +} + +/* + * Filter all available clauses and extract relevant ones. + */ +List * +get_partitioned_attr_clauses(List *restrictinfo_list, + const PartRelationInfo *prel, + Index partitioned_rel) +{ +#define AdjustAttno(attno) \ + ( (AttrNumber) (attno + FirstLowInvalidHeapAttributeNumber) ) + + List *result = NIL; + ListCell *l; + + foreach(l, restrictinfo_list) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(l); + Bitmapset *varattnos = NULL; + int part_attno; + + Assert(IsA(rinfo, RestrictInfo)); + pull_varattnos((Node *) rinfo->clause, partitioned_rel, &varattnos); + + if (bms_get_singleton_member(varattnos, &part_attno) && + AdjustAttno(part_attno) == prel->attnum) + { + result = lappend(result, rinfo->clause); + } + } + return result; +} + + +/* Transform partition ranges into plain array of partition Oids */ +Oid * +get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel, + bool include_parent) +{ + ListCell *range_cell; + uint32 allocated = INITIAL_ALLOC_NUM, + used = 0; + Oid *result = (Oid *) palloc(allocated * sizeof(Oid)); + Oid *children = PrelGetChildrenArray(prel); + + /* If required, add parent to result */ + Assert(INITIAL_ALLOC_NUM >= 1); + if (include_parent) + result[used++] = PrelParentRelid(prel); + + /* Deal with selected partitions */ + foreach (range_cell, ranges) + { + uint32 i; + uint32 a = lfirst_irange(range_cell).ir_lower, + b = lfirst_irange(range_cell).ir_upper; + + for (i = a; i <= b; i++) + { + if (allocated <= used) + { + allocated = allocated * ALLOC_EXP + 1; + result = repalloc(result, allocated * sizeof(Oid)); + } + + Assert(i < PrelChildrenCount(prel)); + result[used++] = children[i]; + } + } + + *n = used; + return result; +} + +Path * +create_append_path_common(PlannerInfo *root, + AppendPath *inner_append, + ParamPathInfo *param_info, + CustomPathMethods *path_methods, + uint32 size, + double sel) +{ + RelOptInfo *innerrel = inner_append->path.parent; + ListCell *lc; + int i; + + RangeTblEntry *inner_entry = root->simple_rte_array[innerrel->relid]; + + RuntimeAppendPath *result; + + result = (RuntimeAppendPath *) palloc0(size); + NodeSetTag(result, T_CustomPath); + + result->cpath.path.pathtype = T_CustomScan; + result->cpath.path.parent = innerrel; + result->cpath.path.param_info = param_info; + result->cpath.path.pathkeys = inner_append->path.pathkeys; +#if PG_VERSION_NUM >= 90600 + result->cpath.path.pathtarget = inner_append->path.pathtarget; +#endif + result->cpath.path.rows = inner_append->path.rows * sel; + result->cpath.flags = 0; + result->cpath.methods = path_methods; + + result->cpath.path.startup_cost = 0.0; + result->cpath.path.total_cost = 0.0; + + Assert(inner_entry->relid != 0); + result->relid = inner_entry->relid; + + result->nchildren = list_length(inner_append->subpaths); + result->children = (ChildScanCommon *) + palloc(result->nchildren * sizeof(ChildScanCommon)); + i = 0; + foreach (lc, inner_append->subpaths) + { + Path *path = lfirst(lc); + Index relindex = path->parent->relid; + ChildScanCommon child; + + child = (ChildScanCommon) palloc(sizeof(ChildScanCommonData)); + + result->cpath.path.startup_cost += path->startup_cost; + result->cpath.path.total_cost += path->total_cost; + + child->content_type = CHILD_PATH; + child->content.path = path; + child->relid = root->simple_rte_array[relindex]->relid; + Assert(child->relid != InvalidOid); + + result->cpath.custom_paths = lappend(result->cpath.custom_paths, + child->content.path); + result->children[i] = child; + + i++; + } + + result->cpath.path.startup_cost *= sel; + result->cpath.path.total_cost *= sel; + + return &result->cpath.path; +} + +Plan * +create_append_plan_common(PlannerInfo *root, RelOptInfo *rel, + CustomPath *best_path, List *tlist, + List *clauses, List *custom_plans, + CustomScanMethods *scan_methods) +{ + RuntimeAppendPath *rpath = (RuntimeAppendPath *) best_path; + const PartRelationInfo *prel; + CustomScan *cscan; + + prel = get_pathman_relation_info(rpath->relid); + Assert(prel); + + cscan = makeNode(CustomScan); + cscan->custom_scan_tlist = NIL; /* initial value (empty list) */ + cscan->scan.plan.targetlist = NIL; + + if (custom_plans) + { + ListCell *lc1, + *lc2; + + forboth (lc1, rpath->cpath.custom_paths, lc2, custom_plans) + { + Plan *child_plan = (Plan *) lfirst(lc2); + RelOptInfo *child_rel = ((Path *) lfirst(lc1))->parent; + + /* Replace rel's tlist with a matching one */ + if (!cscan->scan.plan.targetlist) + tlist = replace_tlist_varnos(child_plan->targetlist, rel); + + /* Add partition attribute if necessary (for ExecQual()) */ + child_plan->targetlist = append_part_attr_to_tlist(child_plan->targetlist, + child_rel->relid, + prel); + + /* Now make custom_scan_tlist match child plans' targetlists */ + if (!cscan->custom_scan_tlist) + cscan->custom_scan_tlist = replace_tlist_varnos(child_plan->targetlist, + rel); + } + } + + cscan->scan.plan.qual = NIL; + cscan->scan.plan.targetlist = tlist; + + /* Since we're not scanning any real table directly */ + cscan->scan.scanrelid = 0; + + cscan->custom_exprs = get_partitioned_attr_clauses(clauses, prel, rel->relid); + cscan->custom_plans = custom_plans; + cscan->methods = scan_methods; + + /* Cache 'prel->enable_parent' as well */ + pack_runtimeappend_private(cscan, rpath, prel->enable_parent); + + return &cscan->scan.plan; +} + +Node * +create_append_scan_state_common(CustomScan *node, + CustomExecMethods *exec_methods, + uint32 size) +{ + RuntimeAppendState *scan_state; + + scan_state = (RuntimeAppendState *) palloc0(size); + NodeSetTag(scan_state, T_CustomScanState); + + scan_state->css.flags = node->flags; + scan_state->css.methods = exec_methods; + scan_state->custom_exprs = node->custom_exprs; + + unpack_runtimeappend_private(scan_state, node); + + scan_state->cur_plans = NULL; + scan_state->ncur_plans = 0; + scan_state->running_idx = 0; + + return (Node *) scan_state; +} + +void +begin_append_common(CustomScanState *node, EState *estate, int eflags) +{ + RuntimeAppendState *scan_state = (RuntimeAppendState *) node; + + scan_state->custom_expr_states = + (List *) ExecInitExpr((Expr *) scan_state->custom_exprs, + (PlanState *) scan_state); + + node->ss.ps.ps_TupFromTlist = false; +} + +TupleTableSlot * +exec_append_common(CustomScanState *node, + void (*fetch_next_tuple) (CustomScanState *node)) +{ + RuntimeAppendState *scan_state = (RuntimeAppendState *) node; + + /* ReScan if no plans are selected */ + if (scan_state->ncur_plans == 0) + ExecReScan(&node->ss.ps); + + for (;;) + { + /* Fetch next tuple if we're done with Projections */ + if (!node->ss.ps.ps_TupFromTlist) + { + fetch_next_tuple(node); /* use specific callback */ + + if (TupIsNull(scan_state->slot)) + return NULL; + } + + if (node->ss.ps.ps_ProjInfo) + { + ExprDoneCond isDone; + TupleTableSlot *result; + + ResetExprContext(node->ss.ps.ps_ExprContext); + + node->ss.ps.ps_ProjInfo->pi_exprContext->ecxt_scantuple = scan_state->slot; + result = ExecProject(node->ss.ps.ps_ProjInfo, &isDone); + + if (isDone != ExprEndResult) + { + node->ss.ps.ps_TupFromTlist = (isDone == ExprMultipleResult); + + return result; + } + else + node->ss.ps.ps_TupFromTlist = false; + } + else + return scan_state->slot; + } +} + +void +end_append_common(CustomScanState *node) +{ + RuntimeAppendState *scan_state = (RuntimeAppendState *) node; + + clear_plan_states(&scan_state->css); + hash_destroy(scan_state->children_table); +} + +void +rescan_append_common(CustomScanState *node) +{ + RuntimeAppendState *scan_state = (RuntimeAppendState *) node; + ExprContext *econtext = node->ss.ps.ps_ExprContext; + const PartRelationInfo *prel; + List *ranges; + ListCell *lc; + WalkerContext wcxt; + Oid *parts; + int nparts; + + prel = get_pathman_relation_info(scan_state->relid); + Assert(prel); + + /* First we select all available partitions... */ + ranges = list_make1_irange(make_irange(0, PrelLastChild(prel), false)); + + InitWalkerContext(&wcxt, prel, econtext, false); + foreach (lc, scan_state->custom_exprs) + { + WrapperNode *wn; + + /* ... then we cut off irrelevant ones using the provided clauses */ + wn = walk_expr_tree((Expr *) lfirst(lc), &wcxt); + ranges = irange_list_intersect(ranges, wn->rangeset); + } + + /* Get Oids of the required partitions */ + parts = get_partition_oids(ranges, &nparts, prel, scan_state->enable_parent); + + /* Select new plans for this run using 'parts' */ + if (scan_state->cur_plans) + pfree(scan_state->cur_plans); /* shallow free since cur_plans + * belong to children_table */ + scan_state->cur_plans = select_required_plans(scan_state->children_table, + parts, nparts, + &scan_state->ncur_plans); + pfree(parts); + + /* Transform selected plans into executable plan states */ + transform_plans_into_states(scan_state, + scan_state->cur_plans, + scan_state->ncur_plans, + scan_state->css.ss.ps.state); + + scan_state->running_idx = 0; +} + +void +explain_append_common(CustomScanState *node, HTAB *children_table, ExplainState *es) +{ + /* Construct excess PlanStates */ + if (!es->analyze) + { + uint32 allocated = INITIAL_ALLOC_NUM, + used = 0; + ChildScanCommon *custom_ps, + child; + HASH_SEQ_STATUS seqstat; + int i; + + custom_ps = (ChildScanCommon *) palloc(allocated * sizeof(ChildScanCommon)); + + /* There can't be any nodes since we're not scanning anything */ + Assert(!node->custom_ps); + + /* Iterate through node's ChildScanCommon table */ + hash_seq_init(&seqstat, children_table); + + while ((child = (ChildScanCommon) hash_seq_search(&seqstat))) + { + if (allocated <= used) + { + allocated = allocated * ALLOC_EXP + 1; + custom_ps = repalloc(custom_ps, allocated * sizeof(ChildScanCommon)); + } + + custom_ps[used++] = child; + } + + /* + * We have to restore the original plan order + * which has been lost within the hash table + */ + qsort(custom_ps, used, sizeof(ChildScanCommon), + cmp_child_scan_common_by_orig_order); + + /* + * These PlanStates will be used by EXPLAIN, + * end_append_common will destroy them eventually + */ + for (i = 0; i < used; i++) + node->custom_ps = lappend(node->custom_ps, + ExecInitNode(custom_ps[i]->content.plan, + node->ss.ps.state, + 0)); + } +} diff --git a/contrib/pg_pathman/src/nodes_common.h b/contrib/pg_pathman/src/nodes_common.h new file mode 100644 index 0000000000..f0423a48e8 --- /dev/null +++ b/contrib/pg_pathman/src/nodes_common.h @@ -0,0 +1,103 @@ +/* ------------------------------------------------------------------------ + * + * nodes_common.h + * Common function prototypes and structs for custom nodes + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef NODES_COMMON_H +#define NODES_COMMON_H + +#include "relation_info.h" + +#include "postgres.h" +#include "commands/explain.h" +#include "optimizer/planner.h" + +#if PG_VERSION_NUM >= 90600 +#include "nodes/extensible.h" +#endif + + +/* + * Common structure for storing selected + * Paths/Plans/PlanStates in a hash table + * or its slice. + */ +typedef struct +{ + Oid relid; /* partition relid */ + + enum + { + CHILD_PATH = 0, + CHILD_PLAN, + CHILD_PLAN_STATE + } content_type; + + union + { + Path *path; + Plan *plan; + PlanState *plan_state; + } content; + + int original_order; /* for sorting in EXPLAIN */ +} ChildScanCommonData; + +typedef ChildScanCommonData *ChildScanCommon; + +/* + * Destroy exhausted plan states + */ +inline static void +clear_plan_states(CustomScanState *scan_state) +{ + ListCell *state_cell; + + foreach (state_cell, scan_state->custom_ps) + { + ExecEndNode((PlanState *) lfirst(state_cell)); + } +} + +List * get_partitioned_attr_clauses(List *restrictinfo_list, + const PartRelationInfo *prel, + Index partitioned_rel); + +Oid * get_partition_oids(List *ranges, int *n, const PartRelationInfo *prel, + bool include_parent); + +Path * create_append_path_common(PlannerInfo *root, + AppendPath *inner_append, + ParamPathInfo *param_info, + CustomPathMethods *path_methods, + uint32 size, + double sel); + +Plan * create_append_plan_common(PlannerInfo *root, RelOptInfo *rel, + CustomPath *best_path, List *tlist, + List *clauses, List *custom_plans, + CustomScanMethods *scan_methods); + +Node * create_append_scan_state_common(CustomScan *node, + CustomExecMethods *exec_methods, + uint32 size); + +void begin_append_common(CustomScanState *node, EState *estate, int eflags); + +TupleTableSlot * exec_append_common(CustomScanState *node, + void (*fetch_next_tuple) (CustomScanState *node)); + +void end_append_common(CustomScanState *node); + +void rescan_append_common(CustomScanState *node); + +void explain_append_common(CustomScanState *node, + HTAB *children_table, + ExplainState *es); + +#endif diff --git a/contrib/pg_pathman/src/partition_filter.c b/contrib/pg_pathman/src/partition_filter.c new file mode 100644 index 0000000000..51f09923e0 --- /dev/null +++ b/contrib/pg_pathman/src/partition_filter.c @@ -0,0 +1,839 @@ +/* ------------------------------------------------------------------------ + * + * partition_filter.c + * Select partition for INSERT operation + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "init.h" +#include "nodes_common.h" +#include "partition_filter.h" +#include "utils.h" + +#include "foreign/fdwapi.h" +#include "foreign/foreign.h" +#include "nodes/nodeFuncs.h" +#include "utils/guc.h" +#include "utils/memutils.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + + +#define ALLOC_EXP 2 + + +/* + * We use this struct as an argument for fake + * MemoryContextCallback pf_memcxt_callback() + * in order to attach some additional info to + * EState (estate->es_query_cxt is involved). + */ +typedef struct +{ + int estate_alloc_result_rels; /* number of allocated result rels */ + bool estate_not_modified; /* did we modify EState somehow? */ +} estate_mod_data; + +/* + * Allow INSERTs into any FDW \ postgres_fdw \ no FDWs at all. + */ +typedef enum +{ + PF_FDW_INSERT_DISABLED = 0, /* INSERTs into FDWs are prohibited */ + PF_FDW_INSERT_POSTGRES, /* INSERTs into postgres_fdw are OK */ + PF_FDW_INSERT_ANY_FDW /* INSERTs into any FDWs are OK */ +} PF_insert_fdw_mode; + +static const struct config_enum_entry pg_pathman_insert_into_fdw_options[] = { + { "disabled", PF_FDW_INSERT_DISABLED, false }, + { "postgres", PF_FDW_INSERT_POSTGRES, false }, + { "any_fdw", PF_FDW_INSERT_ANY_FDW, false }, + { NULL, 0, false } +}; + + +bool pg_pathman_enable_partition_filter = true; +int pg_pathman_insert_into_fdw = PF_FDW_INSERT_POSTGRES; + +CustomScanMethods partition_filter_plan_methods; +CustomExecMethods partition_filter_exec_methods; + + +static estate_mod_data * fetch_estate_mod_data(EState *estate); +static void partition_filter_visitor(Plan *plan, void *context); +static List * pfilter_build_tlist(List *tlist); +static Index append_rte_to_estate(EState *estate, RangeTblEntry *rte); +static int append_rri_to_estate(EState *estate, ResultRelInfo *rri); +static void prepare_rri_fdw_for_insert(EState *estate, + ResultRelInfoHolder *rri_holder, + void *arg); + + +void +init_partition_filter_static_data(void) +{ + partition_filter_plan_methods.CustomName = "PartitionFilter"; + partition_filter_plan_methods.CreateCustomScanState = partition_filter_create_scan_state; + + partition_filter_exec_methods.CustomName = "PartitionFilter"; + partition_filter_exec_methods.BeginCustomScan = partition_filter_begin; + partition_filter_exec_methods.ExecCustomScan = partition_filter_exec; + partition_filter_exec_methods.EndCustomScan = partition_filter_end; + partition_filter_exec_methods.ReScanCustomScan = partition_filter_rescan; + partition_filter_exec_methods.MarkPosCustomScan = NULL; + partition_filter_exec_methods.RestrPosCustomScan = NULL; + partition_filter_exec_methods.ExplainCustomScan = partition_filter_explain; + + DefineCustomBoolVariable("pg_pathman.enable_partitionfilter", + "Enables the planner's use of PartitionFilter custom node.", + NULL, + &pg_pathman_enable_partition_filter, + true, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); + + DefineCustomEnumVariable("pg_pathman.insert_into_fdw", + "Allow INSERTS into FDW partitions.", + NULL, + &pg_pathman_insert_into_fdw, + PF_FDW_INSERT_POSTGRES, + pg_pathman_insert_into_fdw_options, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); +} + + +/* + * Add PartitionFilter nodes to the plan tree + */ +void +add_partition_filters(List *rtable, Plan *plan) +{ + if (pg_pathman_enable_partition_filter) + plan_tree_walker(plan, partition_filter_visitor, rtable); +} + + +/* + * Initialize ResultPartsStorage (hash table etc). + */ +void +init_result_parts_storage(ResultPartsStorage *parts_storage, + EState *estate, + bool speculative_inserts, + Size table_entry_size, + on_new_rri_holder on_new_rri_holder_cb, + void *on_new_rri_holder_cb_arg) +{ + HASHCTL *result_rels_table_config = &parts_storage->result_rels_table_config; + + memset(result_rels_table_config, 0, sizeof(HASHCTL)); + result_rels_table_config->keysize = sizeof(Oid); + + /* Use sizeof(ResultRelInfoHolder) if table_entry_size is 0 */ + if (table_entry_size == ResultPartsStorageStandard) + result_rels_table_config->entrysize = sizeof(ResultRelInfoHolder); + else + result_rels_table_config->entrysize = table_entry_size; + + parts_storage->result_rels_table = hash_create("ResultRelInfo storage", 10, + result_rels_table_config, + HASH_ELEM | HASH_BLOBS); + parts_storage->estate = estate; + parts_storage->saved_rel_info = NULL; + + parts_storage->on_new_rri_holder_callback = on_new_rri_holder_cb; + parts_storage->callback_arg = on_new_rri_holder_cb_arg; + + /* Currenly ResultPartsStorage is used only for INSERTs */ + parts_storage->command_type = CMD_INSERT; + parts_storage->speculative_inserts = speculative_inserts; + + /* Partitions must remain locked till transaction's end */ + parts_storage->head_open_lock_mode = RowExclusiveLock; + parts_storage->heap_close_lock_mode = NoLock; +} + +/* + * Free ResultPartsStorage (close relations etc). + */ +void +fini_result_parts_storage(ResultPartsStorage *parts_storage, bool close_rels) +{ + /* Close partitions and their indices if asked to */ + if (close_rels) + { + HASH_SEQ_STATUS stat; + ResultRelInfoHolder *rri_holder; /* ResultRelInfo holder */ + + hash_seq_init(&stat, parts_storage->result_rels_table); + while ((rri_holder = (ResultRelInfoHolder *) hash_seq_search(&stat)) != NULL) + { + ExecCloseIndices(rri_holder->result_rel_info); + + heap_close(rri_holder->result_rel_info->ri_RelationDesc, + parts_storage->heap_close_lock_mode); + } + } + + /* Finally destroy hash table */ + hash_destroy(parts_storage->result_rels_table); +} + +/* + * Find a ResultRelInfo for the partition using ResultPartsStorage. + */ +ResultRelInfoHolder * +scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage) +{ +#define CopyToResultRelInfo(field_name) \ + ( part_result_rel_info->field_name = parts_storage->saved_rel_info->field_name ) + + ResultRelInfoHolder *rri_holder; + bool found; + + rri_holder = hash_search(parts_storage->result_rels_table, + (const void *) &partid, + HASH_ENTER, &found); + + /* If not found, create & cache new ResultRelInfo */ + if (!found) + { + Relation child_rel; + RangeTblEntry *child_rte, + *parent_rte; + Index child_rte_idx; + ResultRelInfo *part_result_rel_info; + + /* Lock partition and check if it exists */ + LockRelationOid(partid, parts_storage->head_open_lock_mode); + if(!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(partid))) + { + UnlockRelationOid(partid, parts_storage->head_open_lock_mode); + return NULL; + } + + parent_rte = rt_fetch(parts_storage->saved_rel_info->ri_RangeTableIndex, + parts_storage->estate->es_range_table); + + /* Open relation and check if it is a valid target */ + child_rel = heap_open(partid, NoLock); + CheckValidResultRel(child_rel, parts_storage->command_type); + + /* Create RangeTblEntry for partition */ + child_rte = makeNode(RangeTblEntry); + + child_rte->rtekind = RTE_RELATION; + child_rte->relid = partid; + child_rte->relkind = child_rel->rd_rel->relkind; + child_rte->eref = parent_rte->eref; + child_rte->requiredPerms = parent_rte->requiredPerms; + child_rte->checkAsUser = parent_rte->checkAsUser; + child_rte->insertedCols = parent_rte->insertedCols; + + /* Check permissions for partition */ + ExecCheckRTPerms(list_make1(child_rte), true); + + /* Append RangeTblEntry to estate->es_range_table */ + child_rte_idx = append_rte_to_estate(parts_storage->estate, child_rte); + + /* Create ResultRelInfo for partition */ + part_result_rel_info = makeNode(ResultRelInfo); + + /* Check that 'saved_rel_info' is set */ + if (!parts_storage->saved_rel_info) + elog(ERROR, "ResultPartsStorage contains no saved_rel_info"); + + InitResultRelInfo(part_result_rel_info, + child_rel, + child_rte_idx, + parts_storage->estate->es_instrument); + + if (parts_storage->command_type != CMD_DELETE) + ExecOpenIndices(part_result_rel_info, parts_storage->speculative_inserts); + + /* Copy necessary fields from saved ResultRelInfo */ + CopyToResultRelInfo(ri_WithCheckOptions); + CopyToResultRelInfo(ri_WithCheckOptionExprs); + CopyToResultRelInfo(ri_junkFilter); + CopyToResultRelInfo(ri_projectReturning); + CopyToResultRelInfo(ri_onConflictSetProj); + CopyToResultRelInfo(ri_onConflictSetWhere); + + /* ri_ConstraintExprs will be initialized by ExecRelCheck() */ + part_result_rel_info->ri_ConstraintExprs = NULL; + + /* Finally fill the ResultRelInfo holder */ + rri_holder->partid = partid; + rri_holder->result_rel_info = part_result_rel_info; + + /* Call on_new_rri_holder_callback() if needed */ + if (parts_storage->on_new_rri_holder_callback) + parts_storage->on_new_rri_holder_callback(parts_storage->estate, + rri_holder, + parts_storage->callback_arg); + + /* Append ResultRelInfo to storage->es_alloc_result_rels */ + append_rri_to_estate(parts_storage->estate, part_result_rel_info); + } + + return rri_holder; +} + +/* + * Find matching partitions for 'value' using PartRelationInfo. + */ +Oid * +find_partitions_for_value(Datum value, const PartRelationInfo *prel, + ExprContext *econtext, int *nparts) +{ +#define CopyToTempConst(const_field, attr_field) \ + ( temp_const.const_field = prel->attr_field ) + + Const temp_const; /* temporary const for expr walker */ + WalkerContext wcxt; + List *ranges = NIL; + + /* Prepare dummy Const node */ + NodeSetTag(&temp_const, T_Const); + temp_const.location = -1; + + /* Fill const with value ... */ + temp_const.constvalue = value; + temp_const.constisnull = false; + + /* ... and some other important data */ + CopyToTempConst(consttype, atttype); + CopyToTempConst(consttypmod, atttypmod); + CopyToTempConst(constcollid, attcollid); + CopyToTempConst(constlen, attlen); + CopyToTempConst(constbyval, attbyval); + + InitWalkerContext(&wcxt, prel, econtext, true); + ranges = walk_expr_tree((Expr *) &temp_const, &wcxt)->rangeset; + return get_partition_oids(ranges, nparts, prel, false); +} + + +Plan * +make_partition_filter(Plan *subplan, Oid partitioned_table, + OnConflictAction conflict_action) +{ + CustomScan *cscan = makeNode(CustomScan); + + cscan->scan.plan.startup_cost = subplan->startup_cost; + cscan->scan.plan.total_cost = subplan->total_cost; + cscan->scan.plan.plan_rows = subplan->plan_rows; + cscan->scan.plan.plan_width = subplan->plan_width; + + cscan->methods = &partition_filter_plan_methods; + cscan->custom_plans = list_make1(subplan); + + cscan->scan.plan.targetlist = pfilter_build_tlist(subplan->targetlist); + + /* No relation will be scanned */ + cscan->scan.scanrelid = 0; + cscan->custom_scan_tlist = subplan->targetlist; + + /* Pack partitioned table's Oid and conflict_action */ + cscan->custom_private = list_make2_int(partitioned_table, conflict_action); + + return &cscan->scan.plan; +} + +Node * +partition_filter_create_scan_state(CustomScan *node) +{ + PartitionFilterState *state; + + state = (PartitionFilterState *) palloc0(sizeof(PartitionFilterState)); + NodeSetTag(state, T_CustomScanState); + + state->css.flags = node->flags; + state->css.methods = &partition_filter_exec_methods; + + /* Extract necessary variables */ + state->subplan = (Plan *) linitial(node->custom_plans); + state->partitioned_table = linitial_int(node->custom_private); + state->on_conflict_action = lsecond_int(node->custom_private); + + /* Check boundaries */ + Assert(state->on_conflict_action >= ONCONFLICT_NONE || + state->on_conflict_action <= ONCONFLICT_UPDATE); + + /* There should be exactly one subplan */ + Assert(list_length(node->custom_plans) == 1); + + return (Node *) state; +} + +void +partition_filter_begin(CustomScanState *node, EState *estate, int eflags) +{ + PartitionFilterState *state = (PartitionFilterState *) node; + + /* It's convenient to store PlanState in 'custom_ps' */ + node->custom_ps = list_make1(ExecInitNode(state->subplan, estate, eflags)); + + /* Init ResultRelInfo cache */ + init_result_parts_storage(&state->result_parts, estate, + state->on_conflict_action != ONCONFLICT_NONE, + ResultPartsStorageStandard, prepare_rri_fdw_for_insert, NULL); + + state->warning_triggered = false; +} + +TupleTableSlot * +partition_filter_exec(CustomScanState *node) +{ + PartitionFilterState *state = (PartitionFilterState *) node; + + ExprContext *econtext = node->ss.ps.ps_ExprContext; + EState *estate = node->ss.ps.state; + PlanState *child_ps = (PlanState *) linitial(node->custom_ps); + TupleTableSlot *slot; + + slot = ExecProcNode(child_ps); + + /* Save original ResultRelInfo */ + if (!state->result_parts.saved_rel_info) + state->result_parts.saved_rel_info = estate->es_result_relation_info; + + if (!TupIsNull(slot)) + { + MemoryContext old_cxt; + const PartRelationInfo *prel; + ResultRelInfoHolder *rri_holder; + bool isnull; + Datum value; + + /* Fetch PartRelationInfo for this partitioned relation */ + prel = get_pathman_relation_info(state->partitioned_table); + if (!prel) + { + if (!state->warning_triggered) + elog(WARNING, "Relation \"%s\" is not partitioned, " + "PartitionFilter will behave as a normal INSERT", + get_rel_name_or_relid(state->partitioned_table)); + + return slot; + } + + /* Extract partitioned column's value (also check types) */ + Assert(slot->tts_tupleDescriptor-> + attrs[prel->attnum - 1]->atttypid == prel->atttype); + value = slot_getattr(slot, prel->attnum, &isnull); + if (isnull) + elog(ERROR, ERR_PART_ATTR_NULL); + + /* Switch to per-tuple context */ + old_cxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + + /* Search for a matching partition */ + rri_holder = select_partition_for_insert(prel, + &state->result_parts, + value, estate, true); + estate->es_result_relation_info = rri_holder->result_rel_info; + + /* Switch back and clean up per-tuple context */ + MemoryContextSwitchTo(old_cxt); + ResetExprContext(econtext); + + return slot; + } + + return NULL; +} + +void +partition_filter_end(CustomScanState *node) +{ + PartitionFilterState *state = (PartitionFilterState *) node; + + /* Executor will close rels via estate->es_result_relations */ + fini_result_parts_storage(&state->result_parts, false); + + Assert(list_length(node->custom_ps) == 1); + ExecEndNode((PlanState *) linitial(node->custom_ps)); +} + +void +partition_filter_rescan(CustomScanState *node) +{ + Assert(list_length(node->custom_ps) == 1); + ExecReScan((PlanState *) linitial(node->custom_ps)); +} + +void +partition_filter_explain(CustomScanState *node, List *ancestors, ExplainState *es) +{ + /* Nothing to do here now */ +} + +/* + * Smart wrapper for scan_result_parts_storage(). + */ +ResultRelInfoHolder * +select_partition_for_insert(const PartRelationInfo *prel, + ResultPartsStorage *parts_storage, + Datum value, EState *estate, + bool spawn_partitions) +{ + MemoryContext old_cxt; + ExprContext *econtext; + ResultRelInfoHolder *rri_holder; + Oid selected_partid = InvalidOid; + Oid *parts; + int nparts; + + econtext = GetPerTupleExprContext(estate); + + /* Search for matching partitions */ + parts = find_partitions_for_value(value, prel, econtext, &nparts); + + if (nparts > 1) + elog(ERROR, ERR_PART_ATTR_MULTIPLE); + else if (nparts == 0) + { + /* + * If auto partition propagation is enabled then try to create + * new partitions for the key + */ + if (prel->auto_partition && IsAutoPartitionEnabled() && spawn_partitions) + { + selected_partid = create_partitions(PrelParentRelid(prel), + value, prel->atttype); + + /* get_pathman_relation_info() will refresh this entry */ + invalidate_pathman_relation_info(PrelParentRelid(prel), NULL); + } + else + elog(ERROR, ERR_PART_ATTR_NO_PART, + datum_to_cstring(value, prel->atttype)); + } + else selected_partid = parts[0]; + + /* Replace parent table with a suitable partition */ + old_cxt = MemoryContextSwitchTo(estate->es_query_cxt); + rri_holder = scan_result_parts_storage(selected_partid, parts_storage); + MemoryContextSwitchTo(old_cxt); + + /* Could not find suitable partition */ + if (rri_holder == NULL) + elog(ERROR, ERR_PART_ATTR_NO_PART, + datum_to_cstring(value, prel->atttype)); + + return rri_holder; +} + +/* + * Callback to be executed on FDW partitions. + */ +static void +prepare_rri_fdw_for_insert(EState *estate, + ResultRelInfoHolder *rri_holder, + void *arg) +{ + ResultRelInfo *rri = rri_holder->result_rel_info; + FdwRoutine *fdw_routine = rri->ri_FdwRoutine; + Oid partid; + + /* Nothing to do if not FDW */ + if (fdw_routine == NULL) + return; + + partid = RelationGetRelid(rri->ri_RelationDesc); + + /* Perform some checks according to 'pg_pathman_insert_into_fdw' */ + switch (pg_pathman_insert_into_fdw) + { + case PF_FDW_INSERT_DISABLED: + elog(ERROR, "INSERTs into FDW partitions are disabled"); + break; + + case PF_FDW_INSERT_POSTGRES: + { + ForeignDataWrapper *fdw; + ForeignServer *fserver; + + /* Check if it's PostgreSQL FDW */ + fserver = GetForeignServer(GetForeignTable(partid)->serverid); + fdw = GetForeignDataWrapper(fserver->fdwid); + if (strcmp("postgres_fdw", fdw->fdwname) != 0) + elog(ERROR, "FDWs other than postgres_fdw are restricted"); + } + break; + + case PF_FDW_INSERT_ANY_FDW: + { + ForeignDataWrapper *fdw; + ForeignServer *fserver; + + fserver = GetForeignServer(GetForeignTable(partid)->serverid); + fdw = GetForeignDataWrapper(fserver->fdwid); + if (strcmp("postgres_fdw", fdw->fdwname) != 0) + elog(WARNING, "unrestricted FDW mode may lead to \"%s\" crashes", + fdw->fdwname); + } + break; /* do nothing */ + + default: + elog(ERROR, "Mode is not implemented yet"); + break; + } + + if (fdw_routine->PlanForeignModify) + { + RangeTblEntry *rte; + ModifyTableState mtstate; + List *fdw_private; + Query query; + PlannedStmt *plan; + TupleDesc tupdesc; + int i, + target_attr; + + /* Fetch RangeTblEntry for partition */ + rte = rt_fetch(rri->ri_RangeTableIndex, estate->es_range_table); + + /* Fetch tuple descriptor */ + tupdesc = RelationGetDescr(rri->ri_RelationDesc); + + /* Create fake Query node */ + memset((void *) &query, 0, sizeof(Query)); + NodeSetTag(&query, T_Query); + + query.commandType = CMD_INSERT; + query.querySource = QSRC_ORIGINAL; + query.resultRelation = 1; + query.rtable = list_make1(copyObject(rte)); + query.jointree = makeNode(FromExpr); + + query.targetList = NIL; + query.returningList = NIL; + + /* Generate 'query.targetList' using 'tupdesc' */ + target_attr = 1; + for (i = 0; i < tupdesc->natts; i++) + { + Form_pg_attribute attr; + TargetEntry *te; + Param *param; + + attr = tupdesc->attrs[i]; + + if (attr->attisdropped) + continue; + + param = makeNode(Param); + param->paramkind = PARAM_EXTERN; + param->paramid = target_attr; + param->paramtype = attr->atttypid; + param->paramtypmod = attr->atttypmod; + param->paramcollid = attr->attcollation; + param->location = -1; + + te = makeTargetEntry((Expr *) param, target_attr, + pstrdup(NameStr(attr->attname)), + false); + + query.targetList = lappend(query.targetList, te); + + target_attr++; + } + + /* Create fake ModifyTableState */ + memset((void *) &mtstate, 0, sizeof(ModifyTableState)); + NodeSetTag(&mtstate, T_ModifyTableState); + mtstate.ps.state = estate; + mtstate.operation = CMD_INSERT; + mtstate.resultRelInfo = rri; + mtstate.mt_onconflict = ONCONFLICT_NONE; + + /* Plan fake query in for FDW access to be planned as well */ + elog(DEBUG1, "FDW(%u): plan fake query for fdw_private", partid); + plan = standard_planner(&query, 0, NULL); + + /* Extract fdw_private from useless plan */ + elog(DEBUG1, "FDW(%u): extract fdw_private", partid); + fdw_private = (List *) + linitial(((ModifyTable *) plan->planTree)->fdwPrivLists); + + /* call BeginForeignModify on 'rri' */ + elog(DEBUG1, "FDW(%u): call BeginForeignModify on a fake INSERT node", partid); + fdw_routine->BeginForeignModify(&mtstate, rri, fdw_private, 0, 0); + + /* Report success */ + elog(DEBUG1, "FDW(%u): success", partid); + } +} + +/* + * Used by fetch_estate_mod_data() to find estate_mod_data. + */ +static void +pf_memcxt_callback(void *arg) { elog(DEBUG1, "EState is destroyed"); } + +/* + * Fetch (or create) a estate_mod_data structure we've hidden inside es_query_cxt. + */ +static estate_mod_data * +fetch_estate_mod_data(EState *estate) +{ + MemoryContext estate_mcxt = estate->es_query_cxt; + estate_mod_data *emd_struct; + MemoryContextCallback *cb = estate_mcxt->reset_cbs; + + /* Go through callback list */ + while (cb != NULL) + { + /* This is the dummy callback we're looking for! */ + if (cb->func == pf_memcxt_callback) + return (estate_mod_data *) cb->arg; + + cb = estate_mcxt->reset_cbs->next; + } + + /* Have to create a new one */ + emd_struct = MemoryContextAlloc(estate_mcxt, sizeof(estate_mod_data)); + emd_struct->estate_not_modified = true; + emd_struct->estate_alloc_result_rels = estate->es_num_result_relations; + + cb = MemoryContextAlloc(estate_mcxt, sizeof(MemoryContextCallback)); + cb->func = pf_memcxt_callback; + cb->arg = emd_struct; + + MemoryContextRegisterResetCallback(estate_mcxt, cb); + + return emd_struct; +} + +/* + * Append RangeTblEntry 'rte' to estate->es_range_table. + */ +static Index +append_rte_to_estate(EState *estate, RangeTblEntry *rte) +{ + estate_mod_data *emd_struct = fetch_estate_mod_data(estate); + + /* Copy estate->es_range_table if it's first time expansion */ + if (emd_struct->estate_not_modified) + estate->es_range_table = list_copy(estate->es_range_table); + + estate->es_range_table = lappend(estate->es_range_table, rte); + + /* Update estate_mod_data */ + emd_struct->estate_not_modified = false; + + return list_length(estate->es_range_table); +} + +/* + * Append ResultRelInfo 'rri' to estate->es_result_relations. + */ +static int +append_rri_to_estate(EState *estate, ResultRelInfo *rri) +{ + estate_mod_data *emd_struct = fetch_estate_mod_data(estate); + int result_rels_allocated = emd_struct->estate_alloc_result_rels; + + /* Reallocate estate->es_result_relations if needed */ + if (result_rels_allocated <= estate->es_num_result_relations) + { + ResultRelInfo *rri_array = estate->es_result_relations; + + result_rels_allocated = result_rels_allocated * ALLOC_EXP + 1; + estate->es_result_relations = palloc(result_rels_allocated * + sizeof(ResultRelInfo)); + memcpy(estate->es_result_relations, + rri_array, + estate->es_num_result_relations * sizeof(ResultRelInfo)); + } + + /* + * Append ResultRelInfo to 'es_result_relations' array. + * NOTE: this is probably safe since ResultRelInfo + * contains nothing but pointers to various structs. + */ + estate->es_result_relations[estate->es_num_result_relations] = *rri; + + /* Update estate_mod_data */ + emd_struct->estate_alloc_result_rels = result_rels_allocated; + emd_struct->estate_not_modified = false; + + return estate->es_num_result_relations++; +} + +/* + * Build partition filter's target list pointing to subplan tuple's elements + */ +static List * +pfilter_build_tlist(List *tlist) +{ + List *result_tlist = NIL; + ListCell *lc; + int i = 1; + + foreach (lc, tlist) + { + TargetEntry *tle = (TargetEntry *) lfirst(lc); + + Var *var = makeVar(INDEX_VAR, /* point to subplan's elements */ + i, /* direct attribute mapping */ + exprType((Node *) tle->expr), + exprTypmod((Node *) tle->expr), + exprCollation((Node *) tle->expr), + 0); + + result_tlist = lappend(result_tlist, + makeTargetEntry((Expr *) var, + i, + NULL, + tle->resjunk)); + i++; /* next resno */ + } + + return result_tlist; +} + +/* + * Add partition filters to ModifyTable node's children. + * + * 'context' should point to the PlannedStmt->rtable. + */ +static void +partition_filter_visitor(Plan *plan, void *context) +{ + List *rtable = (List *) context; + ModifyTable *modify_table = (ModifyTable *) plan; + ListCell *lc1, + *lc2; + + /* Skip if not ModifyTable with 'INSERT' command */ + if (!IsA(modify_table, ModifyTable) || modify_table->operation != CMD_INSERT) + return; + + Assert(rtable && IsA(rtable, List)); + + forboth (lc1, modify_table->plans, lc2, modify_table->resultRelations) + { + Index rindex = lfirst_int(lc2); + Oid relid = getrelid(rindex, rtable); + const PartRelationInfo *prel = get_pathman_relation_info(relid); + + /* Check that table is partitioned */ + if (prel) + lfirst(lc1) = make_partition_filter((Plan *) lfirst(lc1), + relid, + modify_table->onConflictAction); + } +} diff --git a/contrib/pg_pathman/src/partition_filter.h b/contrib/pg_pathman/src/partition_filter.h new file mode 100644 index 0000000000..f0cf05845b --- /dev/null +++ b/contrib/pg_pathman/src/partition_filter.h @@ -0,0 +1,139 @@ +/* ------------------------------------------------------------------------ + * + * partition_filter.h + * Select partition for INSERT operation + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef RUNTIME_INSERT_H +#define RUNTIME_INSERT_H + +#include "relation_info.h" +#include "utils.h" + +#include "postgres.h" +#include "commands/explain.h" +#include "optimizer/planner.h" + +#if PG_VERSION_NUM >= 90600 +#include "nodes/extensible.h" +#endif + + +#define ERR_PART_ATTR_NULL "partitioned column's value should not be NULL" +#define ERR_PART_ATTR_NO_PART "no suitable partition for key '%s'" +#define ERR_PART_ATTR_MULTIPLE "PartitionFilter selected more than one partition" + + +/* + * Single element of 'result_rels_table'. + */ +typedef struct +{ + Oid partid; /* partition's relid */ + ResultRelInfo *result_rel_info; /* cached ResultRelInfo */ +} ResultRelInfoHolder; + +/* + * Callback to be fired at rri_holder creation. + */ +typedef void (*on_new_rri_holder)(EState *estate, + ResultRelInfoHolder *rri_holder, + void *arg); + +/* + * Cached ResultRelInfos of partitions. + */ +typedef struct +{ + ResultRelInfo *saved_rel_info; /* original ResultRelInfo (parent) */ + HTAB *result_rels_table; + HASHCTL result_rels_table_config; + + bool speculative_inserts; /* for ExecOpenIndices() */ + + on_new_rri_holder on_new_rri_holder_callback; + void *callback_arg; + + EState *estate; /* pointer to executor's state */ + + CmdType command_type; /* currenly we only allow INSERT */ + LOCKMODE head_open_lock_mode; + LOCKMODE heap_close_lock_mode; +} ResultPartsStorage; + +/* + * Standard size of ResultPartsStorage entry. + */ +#define ResultPartsStorageStandard 0 + +typedef struct +{ + CustomScanState css; + + Oid partitioned_table; + OnConflictAction on_conflict_action; + + Plan *subplan; /* proxy variable to store subplan */ + ResultPartsStorage result_parts; /* partition ResultRelInfo cache */ + + bool warning_triggered; /* warning message counter */ +} PartitionFilterState; + + +extern bool pg_pathman_enable_partition_filter; +extern int pg_pathman_insert_into_fdw; + +extern CustomScanMethods partition_filter_plan_methods; +extern CustomExecMethods partition_filter_exec_methods; + + +void init_partition_filter_static_data(void); + +void add_partition_filters(List *rtable, Plan *plan); + +/* ResultPartsStorage init\fini\scan function */ +void init_result_parts_storage(ResultPartsStorage *parts_storage, + EState *estate, + bool speculative_inserts, + Size table_entry_size, + on_new_rri_holder on_new_rri_holder_cb, + void *on_new_rri_holder_cb_arg); +void fini_result_parts_storage(ResultPartsStorage *parts_storage, + bool close_rels); +ResultRelInfoHolder * scan_result_parts_storage(Oid partid, + ResultPartsStorage *storage); + +/* Find suitable partition using 'value' */ +Oid *find_partitions_for_value(Datum value, const PartRelationInfo *prel, + ExprContext *econtext, int *nparts); + +Plan * make_partition_filter(Plan *subplan, + Oid partitioned_table, + OnConflictAction conflict_action); + +Node * partition_filter_create_scan_state(CustomScan *node); + +void partition_filter_begin(CustomScanState *node, + EState *estate, + int eflags); + +TupleTableSlot * partition_filter_exec(CustomScanState *node); + +void partition_filter_end(CustomScanState *node); + +void partition_filter_rescan(CustomScanState *node); + +void partition_filter_explain(CustomScanState *node, + List *ancestors, + ExplainState *es); + +ResultRelInfoHolder * select_partition_for_insert(const PartRelationInfo *prel, + ResultPartsStorage *parts_storage, + Datum value, EState *estate, + bool spawn_partitions); + +#endif diff --git a/contrib/pg_pathman/src/pathman.h b/contrib/pg_pathman/src/pathman.h new file mode 100644 index 0000000000..84d71dd9ab --- /dev/null +++ b/contrib/pg_pathman/src/pathman.h @@ -0,0 +1,194 @@ +/* ------------------------------------------------------------------------ + * + * pathman.h + * structures and prototypes for pathman functions + * + * Copyright (c) 2015-2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef PATHMAN_H +#define PATHMAN_H + +#include "relation_info.h" +#include "rangeset.h" + +#include "postgres.h" +#include "nodes/makefuncs.h" +#include "nodes/primnodes.h" +#include "nodes/execnodes.h" +#include "optimizer/planner.h" +#include "parser/parsetree.h" + + +/* Check PostgreSQL version (9.5.4 contains an important fix for BGW) */ +#if PG_VERSION_NUM < 90503 + #error "Cannot build pg_pathman with PostgreSQL version lower than 9.5.3" +#elif PG_VERSION_NUM < 90504 + #warning "It is STRONGLY recommended to use pg_pathman with PostgreSQL 9.5.4 since it contains important fixes" +#endif + +/* Get CString representation of Datum (simple wrapper) */ +#ifdef USE_ASSERT_CHECKING + #include "utils.h" + #define DebugPrintDatum(datum, typid) ( datum_to_cstring((datum), (typid)) ) +#else + #define DebugPrintDatum(datum, typid) ( "[use --enable-cassert]" ) +#endif + + +/* + * Definitions for the "pathman_config" table. + */ +#define PATHMAN_CONFIG "pathman_config" +#define Natts_pathman_config 4 +#define Anum_pathman_config_partrel 1 /* partitioned relation (regclass) */ +#define Anum_pathman_config_attname 2 /* partitioned column (text) */ +#define Anum_pathman_config_parttype 3 /* partitioning type (1|2) */ +#define Anum_pathman_config_range_interval 4 /* interval for RANGE pt. (text) */ + +/* type modifier (typmod) for 'range_interval' */ +#define PATHMAN_CONFIG_interval_typmod -1 + +/* + * Definitions for the "pathman_config_params" table. + */ +#define PATHMAN_CONFIG_PARAMS "pathman_config_params" +#define Natts_pathman_config_params 4 +#define Anum_pathman_config_params_partrel 1 /* primary key */ +#define Anum_pathman_config_params_enable_parent 2 /* include parent into plan */ +#define Anum_pathman_config_params_auto 3 /* auto partitions creation */ +#define Anum_pathman_config_params_init_callback 4 /* partition action callback */ + +/* + * Definitions for the "pathman_partition_list" view. + */ +#define PATHMAN_PARTITION_LIST "pathman_partition_list" +#define Natts_pathman_partition_list 6 +#define Anum_pathman_pl_parent 1 /* partitioned relation (regclass) */ +#define Anum_pathman_pl_partition 2 /* child partition (regclass) */ +#define Anum_pathman_pl_parttype 3 /* partitioning type (1|2) */ +#define Anum_pathman_pl_partattr 4 /* partitioned column (text) */ +#define Anum_pathman_pl_range_min 5 /* partition's min value */ +#define Anum_pathman_pl_range_max 6 /* partition's max value */ + + +/* + * Cache current PATHMAN_CONFIG relid (set during load_config()). + */ +extern Oid pathman_config_relid; +extern Oid pathman_config_params_relid; + +/* + * Just to clarify our intentions (return the corresponding relid). + */ +Oid get_pathman_config_relid(void); +Oid get_pathman_config_params_relid(void); + +/* + * pg_pathman's global state structure. + */ +typedef struct PathmanState +{ + LWLock *dsm_init_lock; /* unused */ +} PathmanState; + + +/* + * Result of search_range_partition_eq(). + */ +typedef enum +{ + SEARCH_RANGEREL_OUT_OF_RANGE = 0, + SEARCH_RANGEREL_GAP, + SEARCH_RANGEREL_FOUND +} search_rangerel_result; + + +/* + * The list of partitioned relation relids that must be handled by pg_pathman + */ +extern List *inheritance_enabled_relids; + +/* + * This list is used to ensure that partitioned relation isn't used both + * with and without ONLY modifiers + */ +extern List *inheritance_disabled_relids; + +/* + * pg_pathman's global state. + */ +extern PathmanState *pmstate; + + +int append_child_relation(PlannerInfo *root, RelOptInfo *rel, Index rti, + RangeTblEntry *rte, int index, Oid childOID, List *wrappers); + +search_rangerel_result search_range_partition_eq(const Datum value, + FmgrInfo *cmp_func, + const PartRelationInfo *prel, + RangeEntry *out_re); + +uint32 hash_to_part_index(uint32 value, uint32 partitions); + +void handle_modification_query(Query *parse); +void disable_inheritance(Query *parse); +void disable_inheritance_cte(Query *parse); +void disable_inheritance_subselect(Query *parse); + +/* copied from allpaths.h */ +void set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte); +void set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, Index rti, + RangeTblEntry *rte, PathKey *pathkeyAsc, + PathKey *pathkeyDesc); + +typedef struct +{ + const Node *orig; /* examined expression */ + List *args; /* extracted from 'orig' */ + List *rangeset; /* IndexRanges representing selected parts */ + bool found_gap; /* were there any gaps? */ + double paramsel; /* estimated selectivity */ +} WrapperNode; + +typedef struct +{ + const PartRelationInfo *prel; /* main partitioning structure */ + ExprContext *econtext; /* for ExecEvalExpr() */ + bool for_insert; /* are we in PartitionFilter now? */ +} WalkerContext; + +/* + * Usual initialization procedure for WalkerContext. + */ +#define InitWalkerContext(context, prel_info, ecxt, for_ins) \ + do { \ + (context)->prel = (prel_info); \ + (context)->econtext = (ecxt); \ + (context)->for_insert = (for_ins); \ + } while (0) + +/* Check that WalkerContext contains ExprContext (plan execution stage) */ +#define WcxtHasExprContext(wcxt) ( (wcxt)->econtext ) + +/* + * Functions for partition creation, use create_partitions(). + */ +Oid create_partitions(Oid relid, Datum value, Oid value_type); +Oid create_partitions_bg_worker(Oid relid, Datum value, Oid value_type); +Oid create_partitions_internal(Oid relid, Datum value, Oid value_type); + +void select_range_partitions(const Datum value, + FmgrInfo *cmp_func, + const RangeEntry *ranges, + const int nranges, + const int strategy, + WrapperNode *result); + +/* Examine expression in order to select partitions. */ +WrapperNode *walk_expr_tree(Expr *expr, WalkerContext *context); + +#endif /* PATHMAN_H */ diff --git a/contrib/pg_pathman/src/pathman_workers.c b/contrib/pg_pathman/src/pathman_workers.c new file mode 100644 index 0000000000..c913a71061 --- /dev/null +++ b/contrib/pg_pathman/src/pathman_workers.c @@ -0,0 +1,807 @@ +/*------------------------------------------------------------------------- + * + * pathman_workers.c + * + * There are two purposes of this subsystem: + * + * * Create new partitions for INSERT in separate transaction + * * Process concurrent partitioning operations + * + * Background worker API is used for both cases. + * + * Copyright (c) 2015-2016, Postgres Professional + * + *------------------------------------------------------------------------- + */ + +#include "init.h" +#include "pathman_workers.h" +#include "relation_info.h" +#include "utils.h" + +#include "access/htup_details.h" +#include "access/xact.h" +#include "catalog/pg_type.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "postmaster/bgworker.h" +#include "storage/dsm.h" +#include "storage/ipc.h" +#include "storage/latch.h" +#include "utils/builtins.h" +#include "utils/datum.h" +#include "utils/memutils.h" +#include "utils/lsyscache.h" +#include "utils/typcache.h" +#include "utils/resowner.h" +#include "utils/snapmgr.h" + + + +/* Declarations for ConcurrentPartWorker */ +PG_FUNCTION_INFO_V1( partition_table_concurrently ); +PG_FUNCTION_INFO_V1( show_concurrent_part_tasks_internal ); +PG_FUNCTION_INFO_V1( stop_concurrent_part_task ); + + +static void handle_sigterm(SIGNAL_ARGS); +static void bg_worker_load_config(const char *bgw_name); +static void start_bg_worker(const char bgworker_name[BGW_MAXLEN], + bgworker_main_type bgw_main_func, + Datum bgw_arg, bool wait_for_shutdown); + +static void bgw_main_spawn_partitions(Datum main_arg); +static void bgw_main_concurrent_part(Datum main_arg); + + +/* + * Function context for concurrent_part_tasks_internal() SRF. + */ +typedef struct +{ + int cur_idx; /* current slot to be processed */ +} active_workers_cxt; + + +/* + * Slots for concurrent partitioning tasks. + */ +static ConcurrentPartSlot *concurrent_part_slots; + + +/* + * Available workers' names. + */ +static const char *spawn_partitions_bgw = "SpawnPartitionsWorker"; +static const char *concurrent_part_bgw = "ConcurrentPartWorker"; + + +/* + * Estimate amount of shmem needed for concurrent partitioning. + */ +Size +estimate_concurrent_part_task_slots_size(void) +{ + return sizeof(ConcurrentPartSlot) * PART_WORKER_SLOTS; +} + +/* + * Initialize shared memory needed for concurrent partitioning. + */ +void +init_concurrent_part_task_slots(void) +{ + bool found; + Size size = estimate_concurrent_part_task_slots_size(); + int i; + + concurrent_part_slots = (ConcurrentPartSlot *) + ShmemInitStruct("array of ConcurrentPartSlots", size, &found); + + /* Initialize 'concurrent_part_slots' if needed */ + if (!found) + { + memset(concurrent_part_slots, 0, size); + + for (i = 0; i < PART_WORKER_SLOTS; i++) + SpinLockInit(&concurrent_part_slots[i].mutex); + } +} + + +/* + * ------------------------------------------------- + * Common utility functions for background workers + * ------------------------------------------------- + */ + +/* + * Handle SIGTERM in BGW's process. + */ +static void +handle_sigterm(SIGNAL_ARGS) +{ + int save_errno = errno; + + SetLatch(MyLatch); + + if (!proc_exit_inprogress) + { + InterruptPending = true; + ProcDiePending = true; + } + + errno = save_errno; +} + +/* + * Initialize pg_pathman's local config in BGW's process. + */ +static void +bg_worker_load_config(const char *bgw_name) +{ + /* Try to load config */ + if (!load_config()) + elog(ERROR, "%s: could not load pg_pathman's config [%u]", + bgw_name, MyProcPid); + else + elog(LOG, "%s: loaded pg_pathman's config [%u]", + bgw_name, MyProcPid); +} + +/* + * Common function to start background worker. + */ +static void +start_bg_worker(const char bgworker_name[BGW_MAXLEN], + bgworker_main_type bgw_main_func, + Datum bgw_arg, bool wait_for_shutdown) +{ +#define HandleError(condition, new_state) \ + if (condition) { exec_state = (new_state); goto handle_exec_state; } + + /* Execution state to be checked */ + enum + { + BGW_OK = 0, /* everything is fine (default) */ + BGW_COULD_NOT_START, /* could not start worker */ + BGW_PM_DIED /* postmaster died */ + } exec_state = BGW_OK; + + BackgroundWorker worker; + BackgroundWorkerHandle *bgw_handle; + BgwHandleStatus bgw_status; + bool bgw_started; + pid_t pid; + + /* Initialize worker struct */ + memcpy(worker.bgw_name, bgworker_name, BGW_MAXLEN); + worker.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION; + worker.bgw_start_time = BgWorkerStart_RecoveryFinished; + worker.bgw_restart_time = BGW_NEVER_RESTART; + worker.bgw_main = bgw_main_func; + worker.bgw_main_arg = bgw_arg; + worker.bgw_notify_pid = MyProcPid; + + /* Start dynamic worker */ + bgw_started = RegisterDynamicBackgroundWorker(&worker, &bgw_handle); + HandleError(bgw_started == false, BGW_COULD_NOT_START); + + /* Wait till the worker starts */ + bgw_status = WaitForBackgroundWorkerStartup(bgw_handle, &pid); + HandleError(bgw_status == BGWH_POSTMASTER_DIED, BGW_PM_DIED); + + /* Wait till the edn if we're asked to */ + if (wait_for_shutdown) + { + /* Wait till the worker finishes job */ + bgw_status = WaitForBackgroundWorkerShutdown(bgw_handle); + HandleError(bgw_status == BGWH_POSTMASTER_DIED, BGW_PM_DIED); + } + +/* end execution */ +handle_exec_state: + + switch (exec_state) + { + case BGW_COULD_NOT_START: + elog(ERROR, "Unable to create background %s for pg_pathman", + bgworker_name); + break; + + case BGW_PM_DIED: + ereport(ERROR, + (errmsg("Postmaster died during the pg_pathman background worker process"), + errhint("More details may be available in the server log."))); + break; + + default: + break; + } +} + + +/* + * -------------------------------------- + * SpawnPartitionsWorker implementation + * -------------------------------------- + */ + +/* + * Create args segment for partitions bgw. + */ +static dsm_segment * +create_partitions_bg_worker_segment(Oid relid, Datum value, Oid value_type) +{ + TypeCacheEntry *typcache; + Size datum_size; + Size segment_size; + dsm_segment *segment; + SpawnPartitionArgs *args; + + typcache = lookup_type_cache(value_type, 0); + + /* Calculate segment size */ + datum_size = datumGetSize(value, typcache->typbyval, typcache->typlen); + segment_size = offsetof(SpawnPartitionArgs, value) + datum_size; + + segment = dsm_create(segment_size, 0); + + /* Initialize BGW args */ + args = (SpawnPartitionArgs *) dsm_segment_address(segment); + + args->userid = GetAuthenticatedUserId(); + + args->result = InvalidOid; + args->dbid = MyDatabaseId; + args->partitioned_table = relid; + + /* Write value-related stuff */ + args->value_type = value_type; + args->value_size = datum_size; + args->value_byval = typcache->typbyval; + + PackDatumToByteArray((void *) args->value, value, + datum_size, args->value_byval); + + return segment; +} + +/* + * Starts background worker that will create new partitions, + * waits till it finishes the job and returns the result (new partition oid) + * + * NB: This function should not be called directly, use create_partitions() instead. + */ +Oid +create_partitions_bg_worker(Oid relid, Datum value, Oid value_type) +{ + dsm_segment *segment; + dsm_handle segment_handle; + SpawnPartitionArgs *bgw_args; + Oid child_oid = InvalidOid; + + /* Create a dsm segment for the worker to pass arguments */ + segment = create_partitions_bg_worker_segment(relid, value, value_type); + segment_handle = dsm_segment_handle(segment); + bgw_args = (SpawnPartitionArgs *) dsm_segment_address(segment); + + /* Start worker and wait for it to finish */ + start_bg_worker(spawn_partitions_bgw, + bgw_main_spawn_partitions, + UInt32GetDatum(segment_handle), + true); + + /* Save the result (partition Oid) */ + child_oid = bgw_args->result; + + /* Free dsm segment */ + dsm_detach(segment); + + if (child_oid == InvalidOid) + ereport(ERROR, + (errmsg("Attempt to spawn new partitions of relation \"%s\" failed", + get_rel_name_or_relid(relid)), + errhint("See server log for more details."))); + + return child_oid; +} + +/* + * Entry point for SpawnPartitionsWorker's process. + */ +static void +bgw_main_spawn_partitions(Datum main_arg) +{ + dsm_handle handle = DatumGetUInt32(main_arg); + dsm_segment *segment; + SpawnPartitionArgs *args; + Datum value; + + /* Establish signal handlers before unblocking signals. */ + pqsignal(SIGTERM, handle_sigterm); + + /* We're now ready to receive signals */ + BackgroundWorkerUnblockSignals(); + + /* Create resource owner */ + CurrentResourceOwner = ResourceOwnerCreate(NULL, spawn_partitions_bgw); + + if (!handle) + elog(ERROR, "%s: invalid dsm_handle [%u]", + spawn_partitions_bgw, MyProcPid); + + /* Attach to dynamic shared memory */ + if ((segment = dsm_attach(handle)) == NULL) + elog(ERROR, "%s: cannot attach to segment [%u]", + spawn_partitions_bgw, MyProcPid); + args = dsm_segment_address(segment); + + /* Establish connection and start transaction */ + BackgroundWorkerInitializeConnectionByOid(args->dbid, args->userid); + + /* Start new transaction (syscache access etc.) */ + StartTransactionCommand(); + + /* Initialize pg_pathman's local config */ + bg_worker_load_config(spawn_partitions_bgw); + + /* Upack Datum from segment to 'value' */ + UnpackDatumFromByteArray(&value, + args->value_size, + args->value_byval, + (const void *) args->value); + +/* Print 'arg->value' for debug purposes */ +#ifdef USE_ASSERT_CHECKING + elog(LOG, "%s: arg->value is '%s' [%u]", + spawn_partitions_bgw, + DebugPrintDatum(value, args->value_type), MyProcPid); +#endif + + /* Create partitions and save the Oid of the last one */ + args->result = create_partitions_internal(args->partitioned_table, + value, /* unpacked Datum */ + args->value_type); + + /* Finish transaction in an appropriate way */ + if (args->result == InvalidOid) + AbortCurrentTransaction(); + else + CommitTransactionCommand(); + + dsm_detach(segment); +} + + +/* + * ------------------------------------- + * ConcurrentPartWorker implementation + * ------------------------------------- + */ + +/* + * Entry point for ConcurrentPartWorker's process. + */ +static void +bgw_main_concurrent_part(Datum main_arg) +{ + int rows; + bool failed; + int failures_count = 0; + char *sql = NULL; + ConcurrentPartSlot *part_slot; + + /* Establish signal handlers before unblocking signals. */ + pqsignal(SIGTERM, handle_sigterm); + + /* We're now ready to receive signals */ + BackgroundWorkerUnblockSignals(); + + /* Create resource owner */ + CurrentResourceOwner = ResourceOwnerCreate(NULL, concurrent_part_bgw); + + /* Update concurrent part slot */ + part_slot = &concurrent_part_slots[DatumGetInt32(main_arg)]; + part_slot->pid = MyProcPid; + + /* Disable auto partition propagation */ + SetAutoPartitionEnabled(false); + + /* Establish connection and start transaction */ + BackgroundWorkerInitializeConnectionByOid(part_slot->dbid, part_slot->userid); + + /* Initialize pg_pathman's local config */ + StartTransactionCommand(); + bg_worker_load_config(concurrent_part_bgw); + CommitTransactionCommand(); + + /* Do the job */ + do + { + MemoryContext old_mcxt; + + Oid types[2] = { OIDOID, INT4OID }; + Datum vals[2] = { part_slot->relid, part_slot->batch_size }; + bool nulls[2] = { false, false }; + + /* Reset loop variables */ + failed = false; + rows = 0; + + /* Start new transaction (syscache access etc.) */ + StartTransactionCommand(); + + /* We'll need this to recover from errors */ + old_mcxt = CurrentMemoryContext; + + SPI_connect(); + PushActiveSnapshot(GetTransactionSnapshot()); + + /* Prepare the query if needed */ + if (sql == NULL) + { + MemoryContext current_mcxt; + + /* + * Allocate as SQL query in top memory context because current + * context will be destroyed after transaction finishes + */ + current_mcxt = MemoryContextSwitchTo(TopMemoryContext); + sql = psprintf("SELECT %s._partition_data_concurrent($1::oid, p_limit:=$2)", + get_namespace_name(get_pathman_schema())); + MemoryContextSwitchTo(current_mcxt); + } + + /* Exec ret = _partition_data_concurrent() */ + PG_TRY(); + { + int ret; + bool isnull; + + ret = SPI_execute_with_args(sql, 2, types, vals, nulls, false, 0); + if (ret == SPI_OK_SELECT) + { + TupleDesc tupdesc = SPI_tuptable->tupdesc; + HeapTuple tuple = SPI_tuptable->vals[0]; + + Assert(SPI_processed == 1); /* there should be 1 result at most */ + + rows = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 1, &isnull)); + + Assert(!isnull); /* ... and ofc it must not be NULL */ + } + } + PG_CATCH(); + { + ErrorData *error; + char *sleep_time_str; + + /* Switch to the original context & copy edata */ + MemoryContextSwitchTo(old_mcxt); + error = CopyErrorData(); + FlushErrorState(); + + /* Print messsage for this BGWorker to server log */ + sleep_time_str = datum_to_cstring(Float8GetDatum(part_slot->sleep_time), + FLOAT8OID); + failures_count++; + ereport(LOG, + (errmsg("%s: %s", concurrent_part_bgw, error->message), + errdetail("attempt: %d/%d, sleep time: %s", + failures_count, + PART_WORKER_MAX_ATTEMPTS, + sleep_time_str))); + pfree(sleep_time_str); /* free the time string */ + + FreeErrorData(error); + + /* + * The most common exception we can catch here is a deadlock with + * concurrent user queries. Check that attempts count doesn't exceed + * some reasonable value + */ + if (failures_count >= PART_WORKER_MAX_ATTEMPTS) + { + /* Mark slot as FREE */ + cps_set_status(part_slot, CPS_FREE); + + elog(LOG, + "concurrent partitioning worker has canceled the task because " + "maximum amount of attempts (%d) had been exceeded, " + "see the error message below", + PART_WORKER_MAX_ATTEMPTS); + + return; /* exit quickly */ + } + + /* Set 'failed' flag */ + failed = true; + } + PG_END_TRY(); + + SPI_finish(); + PopActiveSnapshot(); + + if (failed) + { + /* Abort transaction and sleep for a second */ + AbortCurrentTransaction(); + DirectFunctionCall1(pg_sleep, Float8GetDatum(part_slot->sleep_time)); + } + else + { + /* Commit transaction and reset 'failures_count' */ + CommitTransactionCommand(); + failures_count = 0; + + /* Add rows to total_rows */ + SpinLockAcquire(&part_slot->mutex); + part_slot->total_rows += rows; +/* Report debug message */ +#ifdef USE_ASSERT_CHECKING + elog(DEBUG1, "%s: relocated %d rows, total: %lu [%u]", + concurrent_part_bgw, rows, part_slot->total_rows, MyProcPid); +#endif + SpinLockRelease(&part_slot->mutex); + } + + /* If other backend requested to stop us, quit */ + if (cps_check_status(part_slot) == CPS_STOPPING) + break; + } + while(rows > 0 || failed); /* do while there's still rows to be relocated */ + + /* Reclaim the resources */ + pfree(sql); + + /* Mark slot as FREE */ + cps_set_status(part_slot, CPS_FREE); +} + + +/* + * ----------------------------------------------- + * Public interface for the ConcurrentPartWorker + * ----------------------------------------------- + */ + +/* + * Start concurrent partitioning worker to redistribute rows. + * NOTE: this function returns immediately. + */ +Datum +partition_table_concurrently(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int empty_slot_idx = -1, /* do we have a slot for BGWorker? */ + i; + + /* Check if relation is a partitioned table */ + shout_if_prel_is_invalid(relid, + /* We also lock the parent relation */ + get_pathman_relation_info_after_lock(relid, true), + /* Partitioning type does not matter here */ + PT_INDIFFERENT); + /* + * Look for an empty slot and also check that a concurrent + * partitioning operation for this table hasn't been started yet + */ + for (i = 0; i < PART_WORKER_SLOTS; i++) + { + ConcurrentPartSlot *cur_slot = &concurrent_part_slots[i]; + bool keep_this_lock = false; + + /* Lock current slot */ + SpinLockAcquire(&cur_slot->mutex); + + /* Should we take this slot into account? (it should be FREE) */ + if (empty_slot_idx < 0 && cur_slot->worker_status == CPS_FREE) + { + empty_slot_idx = i; /* yes, remember this slot */ + keep_this_lock = true; /* also don't unlock it */ + } + + /* Oops, looks like we already have BGWorker for this table */ + if (cur_slot->relid == relid && + cur_slot->dbid == MyDatabaseId && + cur_slot->worker_status != CPS_FREE) + { + /* Unlock current slot */ + SpinLockRelease(&cur_slot->mutex); + + /* Release borrowed slot for new BGWorker too */ + if (empty_slot_idx >= 0 && empty_slot_idx != i) + SpinLockRelease(&concurrent_part_slots[empty_slot_idx].mutex); + + elog(ERROR, + "table \"%s\" is already being partitioned", + get_rel_name(relid)); + } + + /* Normally we don't want to keep it */ + if (!keep_this_lock) + SpinLockRelease(&cur_slot->mutex); + } + + /* Looks like we could not find an empty slot */ + if (empty_slot_idx < 0) + elog(ERROR, "no empty worker slots found"); + else + { + /* Initialize concurrent part slot */ + InitConcurrentPartSlot(&concurrent_part_slots[empty_slot_idx], + GetAuthenticatedUserId(), CPS_WORKING, + MyDatabaseId, relid, 1000, 1.0); + + /* Now we can safely unlock slot for new BGWorker */ + SpinLockRelease(&concurrent_part_slots[empty_slot_idx].mutex); + } + + /* Start worker (we should not wait) */ + start_bg_worker(concurrent_part_bgw, + bgw_main_concurrent_part, + Int32GetDatum(empty_slot_idx), + false); + + /* Tell user everything's fine */ + elog(NOTICE, + "worker started, you can stop it " + "with the following command: select %s('%s');", + CppAsString(stop_concurrent_part_task), + get_rel_name(relid)); + + PG_RETURN_VOID(); +} + +/* + * Return list of active concurrent partitioning workers. + * NOTE: this is a set-returning-function (SRF). + */ +Datum +show_concurrent_part_tasks_internal(PG_FUNCTION_ARGS) +{ + FuncCallContext *funcctx; + active_workers_cxt *userctx; + int i; + + /* + * Initialize tuple descriptor & function call context. + */ + if (SRF_IS_FIRSTCALL()) + { + TupleDesc tupdesc; + MemoryContext old_mcxt; + + funcctx = SRF_FIRSTCALL_INIT(); + + old_mcxt = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + userctx = (active_workers_cxt *) palloc(sizeof(active_workers_cxt)); + userctx->cur_idx = 0; + + /* Create tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(Natts_pathman_cp_tasks, false); + + TupleDescInitEntry(tupdesc, Anum_pathman_cp_tasks_userid, + "userid", REGROLEOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_cp_tasks_pid, + "pid", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_cp_tasks_dbid, + "dbid", OIDOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_cp_tasks_relid, + "relid", REGCLASSOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_cp_tasks_processed, + "processed", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_cp_tasks_status, + "status", TEXTOID, -1, 0); + + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + funcctx->user_fctx = (void *) userctx; + + MemoryContextSwitchTo(old_mcxt); + } + + funcctx = SRF_PERCALL_SETUP(); + userctx = (active_workers_cxt *) funcctx->user_fctx; + + /* Iterate through worker slots */ + for (i = userctx->cur_idx; i < PART_WORKER_SLOTS; i++) + { + ConcurrentPartSlot *cur_slot = &concurrent_part_slots[i]; + HeapTuple htup = NULL; + + HOLD_INTERRUPTS(); + SpinLockAcquire(&cur_slot->mutex); + + if (cur_slot->worker_status != CPS_FREE) + { + Datum values[Natts_pathman_cp_tasks]; + bool isnull[Natts_pathman_cp_tasks] = { 0 }; + + values[Anum_pathman_cp_tasks_userid - 1] = cur_slot->userid; + values[Anum_pathman_cp_tasks_pid - 1] = cur_slot->pid; + values[Anum_pathman_cp_tasks_dbid - 1] = cur_slot->dbid; + values[Anum_pathman_cp_tasks_relid - 1] = cur_slot->relid; + values[Anum_pathman_cp_tasks_processed - 1] = cur_slot->total_rows; + + /* Now build a status string */ + switch(cur_slot->worker_status) + { + case CPS_WORKING: + values[Anum_pathman_cp_tasks_status - 1] = + PointerGetDatum(cstring_to_text("working")); + break; + + case CPS_STOPPING: + values[Anum_pathman_cp_tasks_status - 1] = + PointerGetDatum(cstring_to_text("stopping")); + break; + + default: + values[Anum_pathman_cp_tasks_status - 1] = + PointerGetDatum(cstring_to_text("[unknown]")); + } + + /* Form output tuple */ + htup = heap_form_tuple(funcctx->tuple_desc, values, isnull); + + /* Switch to next worker */ + userctx->cur_idx = i + 1; + } + + SpinLockRelease(&cur_slot->mutex); + RESUME_INTERRUPTS(); + + /* Return tuple if needed */ + if (htup) + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(htup)); + } + + SRF_RETURN_DONE(funcctx); +} + +/* + * Stop the specified concurrent partitioning worker. + * NOTE: worker will stop after it finishes a batch. + */ +Datum +stop_concurrent_part_task(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + bool worker_found = false; + int i; + + for (i = 0; i < PART_WORKER_SLOTS && !worker_found; i++) + { + ConcurrentPartSlot *cur_slot = &concurrent_part_slots[i]; + + HOLD_INTERRUPTS(); + SpinLockAcquire(&cur_slot->mutex); + + if (cur_slot->worker_status != CPS_FREE && + cur_slot->relid == relid && + cur_slot->dbid == MyDatabaseId) + { + elog(NOTICE, "worker will stop after it finishes current batch"); + + /* Change worker's state & set 'worker_found' */ + cur_slot->worker_status = CPS_STOPPING; + worker_found = true; + } + + SpinLockRelease(&cur_slot->mutex); + RESUME_INTERRUPTS(); + } + + if (worker_found) + PG_RETURN_BOOL(true); + else + { + elog(ERROR, "cannot find worker for relation \"%s\"", + get_rel_name_or_relid(relid)); + + PG_RETURN_BOOL(false); /* keep compiler happy */ + } +} diff --git a/contrib/pg_pathman/src/pathman_workers.h b/contrib/pg_pathman/src/pathman_workers.h new file mode 100644 index 0000000000..dfa14d53fb --- /dev/null +++ b/contrib/pg_pathman/src/pathman_workers.h @@ -0,0 +1,181 @@ +/*------------------------------------------------------------------------- + * + * pathman_workers.h + * + * There are two purposes of this subsystem: + * + * * Create new partitions for INSERT in separate transaction + * * Process concurrent partitioning operations + * + * Background worker API is used for both cases. + * + * Copyright (c) 2015-2016, Postgres Professional + * + *------------------------------------------------------------------------- + */ + +#ifndef PATHMAN_WORKERS_H +#define PATHMAN_WORKERS_H + +#include "postgres.h" +#include "storage/spin.h" + + +/* + * Store args, result and execution status of CreatePartitionsWorker. + */ +typedef struct +{ + Oid userid; /* connect as a specified user */ + + Oid result; /* target partition */ + Oid dbid; /* database which stores 'partitioned_table' */ + Oid partitioned_table; + + /* Needed to decode Datum from 'values' */ + Oid value_type; + Size value_size; + bool value_byval; + + /* Store Datum as flexible array */ + uint8 value[FLEXIBLE_ARRAY_MEMBER]; +} SpawnPartitionArgs; + + +typedef enum +{ + CPS_FREE = 0, /* slot is empty */ + CPS_WORKING, /* occupied by live worker */ + CPS_STOPPING /* worker is going to shutdown */ + +} ConcurrentPartSlotStatus; + +/* + * Store args and execution status of a single ConcurrentPartWorker. + */ +typedef struct +{ + slock_t mutex; /* protect slot from race conditions */ + + ConcurrentPartSlotStatus worker_status; /* status of a particular worker */ + + Oid userid; /* connect as a specified user */ + pid_t pid; /* worker's PID */ + Oid dbid; /* database which contains the relation */ + Oid relid; /* table to be partitioned concurrently */ + uint64 total_rows; /* total amount of rows processed */ + + int32 batch_size; /* number of rows in a batch */ + float8 sleep_time; /* how long should we sleep in case of error? */ +} ConcurrentPartSlot; + +#define InitConcurrentPartSlot(slot, user, w_status, db, rel, batch_sz, sleep_t) \ + do { \ + (slot)->userid = (user); \ + (slot)->worker_status = (w_status); \ + (slot)->pid = 0; \ + (slot)->dbid = (db); \ + (slot)->relid = (rel); \ + (slot)->total_rows = 0; \ + (slot)->batch_size = (batch_sz); \ + (slot)->sleep_time = (sleep_t); \ + } while (0) + +static inline ConcurrentPartSlotStatus +cps_check_status(ConcurrentPartSlot *slot) +{ + ConcurrentPartSlotStatus status; + + SpinLockAcquire(&slot->mutex); + status = slot->worker_status; + SpinLockRelease(&slot->mutex); + + return status; +} + +static inline void +cps_set_status(ConcurrentPartSlot *slot, ConcurrentPartSlotStatus status) +{ + SpinLockAcquire(&slot->mutex); + slot->worker_status = status; + SpinLockRelease(&slot->mutex); +} + + + +/* Number of worker slots for concurrent partitioning */ +#define PART_WORKER_SLOTS 10 + +/* Max number of attempts per batch */ +#define PART_WORKER_MAX_ATTEMPTS 60 + + +/* + * Definitions for the "pathman_concurrent_part_tasks" view. + */ +#define PATHMAN_CONCURRENT_PART_TASKS "pathman_concurrent_part_tasks" +#define Natts_pathman_cp_tasks 6 +#define Anum_pathman_cp_tasks_userid 1 +#define Anum_pathman_cp_tasks_pid 2 +#define Anum_pathman_cp_tasks_dbid 3 +#define Anum_pathman_cp_tasks_relid 4 +#define Anum_pathman_cp_tasks_processed 5 +#define Anum_pathman_cp_tasks_status 6 + + +/* + * Concurrent partitioning slots are stored in shmem. + */ +Size estimate_concurrent_part_task_slots_size(void); +void init_concurrent_part_task_slots(void); + + +/* + * Useful datum packing\unpacking functions for BGW. + */ + +static inline void * +PackDatumToByteArray(void *byte_array, Datum datum, Size datum_size, bool typbyval) +{ + if (typbyval) + /* We have to copy all Datum's bytes */ + datum_size = Max(sizeof(Datum), datum_size); + + memcpy((void *) byte_array, + (const void *) (typbyval ? + (Pointer) &datum : /* treat Datum as byte array */ + DatumGetPointer(datum)), /* extract pointer to data */ + datum_size); + + return ((uint8 *) byte_array) + datum_size; +} + +static inline void * +UnpackDatumFromByteArray(Datum *datum, Size datum_size, bool typbyval, + const void *byte_array) +{ + void *dst; + + if (typbyval) + { + /* Write Data to Datum directly */ + dst = datum; + + /* We have to copy all Datum's bytes */ + datum_size = Max(sizeof(Datum), datum_size); + } + else + { + /* Allocate space for Datum's internals */ + dst = palloc(datum_size); + + /* Save pointer to Datum */ + *datum = PointerGetDatum(dst); + } + + memcpy(dst, byte_array, datum_size); + + return ((uint8 *) byte_array) + datum_size; +} + +#endif diff --git a/contrib/pg_pathman/src/pg_compat.c b/contrib/pg_pathman/src/pg_compat.c new file mode 100644 index 0000000000..7474d6897e --- /dev/null +++ b/contrib/pg_pathman/src/pg_compat.c @@ -0,0 +1,114 @@ +/* ------------------------------------------------------------------------ + * + * pg_compat.c + * Compatibility tools + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "pg_compat.h" + +#include "optimizer/pathnode.h" +#include "port.h" +#include "utils.h" + +#include + + +void +set_append_rel_size_compat(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte) +{ + double parent_rows = 0; + double parent_size = 0; + ListCell *l; + + foreach(l, root->append_rel_list) + { + AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + Index childRTindex, + parentRTindex = rti; + RelOptInfo *childrel; + + /* append_rel_list contains all append rels; ignore others */ + if (appinfo->parent_relid != parentRTindex) + continue; + + childRTindex = appinfo->child_relid; + + childrel = find_base_rel(root, childRTindex); + Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL); + + /* + * Accumulate size information from each live child. + */ + Assert(childrel->rows > 0); + + parent_rows += childrel->rows; +#if PG_VERSION_NUM >= 90600 + parent_size += childrel->reltarget->width * childrel->rows; +#else + parent_size += childrel->width * childrel->rows; +#endif + } + + rel->rows = parent_rows; +#if PG_VERSION_NUM >= 90600 + rel->reltarget->width = rint(parent_size / parent_rows); +#else + rel->width = rint(parent_size / parent_rows); +#endif + rel->tuples = parent_rows; +} + +extern +void copy_targetlist_compat(RelOptInfo *dest, RelOptInfo *rel) +{ + ListCell *lc; + +#if PG_VERSION_NUM >= 90600 + dest->reltarget->exprs = NIL; + foreach(lc, rel->reltarget->exprs) +#else + dest->reltargetlist = NIL; + foreach(lc, rel->reltargetlist) +#endif + { + Node *new_target; + Node *node; + + node = (Node *) lfirst(lc); + new_target = copyObject(node); + change_varnos(new_target, rel->relid, dest->relid); +#if PG_VERSION_NUM >= 90600 + dest->reltarget->exprs = lappend(dest->reltarget->exprs, new_target); +#else + dest->reltargetlist = lappend(dest->reltargetlist, new_target); +#endif + } +} + +#if PG_VERSION_NUM >= 90600 +/* + * make_result + * Build a Result plan node + */ +Result * +make_result(List *tlist, + Node *resconstantqual, + Plan *subplan) +{ + Result *node = makeNode(Result); + Plan *plan = &node->plan; + + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = subplan; + plan->righttree = NULL; + node->resconstantqual = resconstantqual; + + return node; +} +#endif diff --git a/contrib/pg_pathman/src/pg_compat.h b/contrib/pg_pathman/src/pg_compat.h new file mode 100644 index 0000000000..7bef6778ee --- /dev/null +++ b/contrib/pg_pathman/src/pg_compat.h @@ -0,0 +1,74 @@ +/* ------------------------------------------------------------------------ + * + * pg_compat.h + * Compatibility tools + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef PG_COMPAT_H +#define PG_COMPAT_H + +#include "postgres.h" + +#include "nodes/relation.h" +#include "nodes/pg_list.h" +#include "optimizer/cost.h" +#include "optimizer/paths.h" + + +extern void set_append_rel_size_compat(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte); +extern void copy_targetlist_compat(RelOptInfo *dest, RelOptInfo *rel); + +#if PG_VERSION_NUM >= 90600 + +#define get_parameterized_joinrel_size_compat(root, rel, outer_path, \ + inner_path, sjinfo, \ + restrict_clauses) \ + get_parameterized_joinrel_size(root, rel, outer_path, \ + inner_path, sjinfo, \ + restrict_clauses) + +#define check_index_predicates_compat(rool, rel) \ + check_index_predicates(root, rel) + +#define create_append_path_compat(rel, subpaths, required_outer, parallel_workers) \ + create_append_path(rel, subpaths, required_outer, parallel_workers) + +#define pull_var_clause_compat(node, aggbehavior, phbehavior) \ + pull_var_clause(node, aggbehavior | phbehavior) + +extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); +#define make_result_compat(root, tlist, resconstantqual, subplan) \ + make_result(tlist, resconstantqual, subplan) + +#else /* PG_VERSION_NUM >= 90500 */ + +#define get_parameterized_joinrel_size_compat(root, rel, \ + outer_path, \ + inner_path, \ + sjinfo, restrict_clauses) \ + get_parameterized_joinrel_size(root, rel, \ + (outer_path)->rows, \ + (inner_path)->rows, \ + sjinfo, restrict_clauses) + +#define check_index_predicates_compat(rool, rel) \ + check_partial_indexes(root, rel) + +#define create_append_path_compat(rel, subpaths, required_outer, parallel_workers) \ + create_append_path(rel, subpaths, required_outer) + +#define pull_var_clause_compat(node, aggbehavior, phbehavior) \ + pull_var_clause(node, aggbehavior, phbehavior) + +#define make_result_compat(root, tlist, resconstantqual, subplan) \ + make_result(root, tlist, resconstantqual, subplan) + +#endif + + +#endif /* PG_COMPAT_H */ diff --git a/contrib/pg_pathman/src/pg_pathman.c b/contrib/pg_pathman/src/pg_pathman.c new file mode 100644 index 0000000000..113df1b4bf --- /dev/null +++ b/contrib/pg_pathman/src/pg_pathman.c @@ -0,0 +1,2136 @@ +/* ------------------------------------------------------------------------ + * + * pg_pathman.c + * This module sets planner hooks, handles SELECT queries and produces + * paths for partitioned tables + * + * Copyright (c) 2015-2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "pg_compat.h" + +#include "pathman.h" +#include "init.h" +#include "hooks.h" +#include "utils.h" +#include "partition_filter.h" +#include "runtimeappend.h" +#include "runtime_merge_append.h" +#include "xact_handling.h" + +#include "postgres.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/transam.h" +#include "access/xact.h" +#include "catalog/pg_cast.h" +#include "catalog/pg_type.h" +#include "executor/spi.h" +#include "foreign/fdwapi.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "optimizer/clauses.h" +#include "optimizer/prep.h" +#include "optimizer/restrictinfo.h" +#include "optimizer/cost.h" +#include "utils/builtins.h" +#include "utils/datum.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "utils/selfuncs.h" +#include "utils/snapmgr.h" +#include "utils/typcache.h" + +PG_MODULE_MAGIC; + + +List *inheritance_disabled_relids = NIL; +List *inheritance_enabled_relids = NIL; +PathmanState *pmstate; +Oid pathman_config_relid = InvalidOid; +Oid pathman_config_params_relid = InvalidOid; + + +/* pg module functions */ +void _PG_init(void); + +/* Utility functions */ +static Node *wrapper_make_expression(WrapperNode *wrap, int index, bool *alwaysTrue); +static bool disable_inheritance_subselect_walker(Node *node, void *context); + +/* "Partition creation"-related functions */ +static Datum extract_binary_interval_from_text(Datum interval_text, + Oid part_atttype, + Oid *interval_type); +static bool spawn_partitions(Oid partitioned_rel, + Datum value, + Datum leading_bound, + Oid leading_bound_type, + FmgrInfo *cmp_proc, + Datum interval_binary, + Oid interval_type, + bool forward, + Oid *last_partition); + +/* Expression tree handlers */ +static WrapperNode *handle_const(const Const *c, WalkerContext *context); +static void handle_binary_opexpr(WalkerContext *context, WrapperNode *result, const Node *varnode, const Const *c); +static void handle_binary_opexpr_param(const PartRelationInfo *prel, WrapperNode *result, const Node *varnode); +static WrapperNode *handle_opexpr(const OpExpr *expr, WalkerContext *context); +static WrapperNode *handle_boolexpr(const BoolExpr *expr, WalkerContext *context); +static WrapperNode *handle_arrexpr(const ScalarArrayOpExpr *expr, WalkerContext *context); +static RestrictInfo *rebuild_restrictinfo(Node *clause, RestrictInfo *old_rinfo); +static bool pull_var_param(const WalkerContext *ctx, const OpExpr *expr, Node **var_ptr, Node **param_ptr); + +/* copied from allpaths.h */ +static void set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, + RangeTblEntry *rte); +static void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte); +static List *accumulate_append_subpath(List *subpaths, Path *path); +static void generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels, + List *all_child_pathkeys, + PathKey *pathkeyAsc, + PathKey *pathkeyDesc); +static Path *get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer); + + +/* + * Compare two Datums with the given comarison function + * + * flinfo is a pointer to an instance of FmgrInfo + * arg1, arg2 are Datum instances + */ +#define check_lt(finfo, arg1, arg2) \ + ((int) FunctionCall2(finfo, arg1, arg2) < 0) +#define check_le(finfo, arg1, arg2) \ + ((int) FunctionCall2(finfo, arg1, arg2) <= 0) +#define check_eq(finfo, arg1, arg2) \ + ((int) FunctionCall2(finfo, arg1, arg2) == 0) +#define check_ge(finfo, arg1, arg2) \ + ((int) FunctionCall2(finfo, arg1, arg2) >= 0) +#define check_gt(finfo, arg1, arg2) \ + ((int) FunctionCall2(finfo, arg1, arg2) > 0) + +/* We can transform Param into Const provided that 'econtext' is available */ +#define IsConstValue(wcxt, node) \ + ( IsA((node), Const) || (WcxtHasExprContext(wcxt) ? IsA((node), Param) : false) ) + +#define ExtractConst(wcxt, node) \ + ( IsA((node), Param) ? extract_const((wcxt), (Param *) (node)) : ((Const *) (node)) ) + + +/* + * Set initial values for all Postmaster's forks. + */ +void +_PG_init(void) +{ + PathmanInitState temp_init_state; + + if (!process_shared_preload_libraries_in_progress) + { + elog(ERROR, "pg_pathman module must be initialized by Postmaster. " + "Put the following line to configuration file: " + "shared_preload_libraries='pg_pathman'"); + } + + /* Request additional shared resources */ + RequestAddinShmemSpace(estimate_pathman_shmem_size()); + + /* NOTE: we don't need LWLocks now. RequestAddinLWLocks(1); */ + + /* Assign pg_pathman's initial state */ + temp_init_state.initialization_needed = true; + temp_init_state.pg_pathman_enable = true; + + /* Apply initial state */ + restore_pathman_init_state(&temp_init_state); + + /* Initialize 'next' hook pointers */ + set_rel_pathlist_hook_next = set_rel_pathlist_hook; + set_rel_pathlist_hook = pathman_rel_pathlist_hook; + set_join_pathlist_next = set_join_pathlist_hook; + set_join_pathlist_hook = pathman_join_pathlist_hook; + shmem_startup_hook_next = shmem_startup_hook; + shmem_startup_hook = pathman_shmem_startup_hook; + post_parse_analyze_hook_next = post_parse_analyze_hook; + post_parse_analyze_hook = pathman_post_parse_analysis_hook; + planner_hook_next = planner_hook; + planner_hook = pathman_planner_hook; + process_utility_hook_next = ProcessUtility_hook; + ProcessUtility_hook = pathman_process_utility_hook; + + /* Initialize static data for all subsystems */ + init_main_pathman_toggles(); + init_runtimeappend_static_data(); + init_runtime_merge_append_static_data(); + init_partition_filter_static_data(); +} + +/* + * Disables inheritance for partitioned by pathman relations. + * It must be done to prevent PostgresSQL from exhaustive search. + */ +void +disable_inheritance(Query *parse) +{ + const PartRelationInfo *prel; + RangeTblEntry *rte; + MemoryContext oldcontext; + ListCell *lc; + + /* If query contains CTE (WITH statement) then handle subqueries too */ + disable_inheritance_cte(parse); + + /* If query contains subselects */ + disable_inheritance_subselect(parse); + + foreach(lc, parse->rtable) + { + rte = (RangeTblEntry *) lfirst(lc); + + switch(rte->rtekind) + { + case RTE_RELATION: + if (rte->inh) + { + /* Look up this relation in pathman local cache */ + prel = get_pathman_relation_info(rte->relid); + if (prel) + { + /* We'll set this flag later */ + rte->inh = false; + + /* + * Sometimes user uses the ONLY statement and in this case + * rte->inh is also false. We should differ the case + * when user uses ONLY statement from case when we + * make rte->inh false intentionally. + */ + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + inheritance_enabled_relids = \ + lappend_oid(inheritance_enabled_relids, rte->relid); + MemoryContextSwitchTo(oldcontext); + + /* + * Check if relation was already found with ONLY modifier. In + * this case throw an error because we cannot handle + * situations when partitioned table used both with and + * without ONLY modifier in SELECT queries + */ + if (list_member_oid(inheritance_disabled_relids, rte->relid)) + goto disable_error; + + goto disable_next; + } + } + + oldcontext = MemoryContextSwitchTo(TopMemoryContext); + inheritance_disabled_relids = \ + lappend_oid(inheritance_disabled_relids, rte->relid); + MemoryContextSwitchTo(oldcontext); + + /* Check if relation was already found withoud ONLY modifier */ + if (list_member_oid(inheritance_enabled_relids, rte->relid)) + goto disable_error; + break; + case RTE_SUBQUERY: + /* Recursively disable inheritance for subqueries */ + disable_inheritance(rte->subquery); + break; + default: + break; + } + +disable_next: + ; + } + + return; + +disable_error: + elog(ERROR, "It is prohibited to query partitioned tables both " + "with and without ONLY modifier"); +} + +void +disable_inheritance_cte(Query *parse) +{ + ListCell *lc; + + foreach(lc, parse->cteList) + { + CommonTableExpr *cte = (CommonTableExpr*) lfirst(lc); + + if (IsA(cte->ctequery, Query)) + disable_inheritance((Query *) cte->ctequery); + } +} + +void +disable_inheritance_subselect(Query *parse) +{ + Node *quals; + + if (!parse->jointree || !parse->jointree->quals) + return; + + quals = parse->jointree->quals; + disable_inheritance_subselect_walker(quals, NULL); +} + +static bool +disable_inheritance_subselect_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + + if (IsA(node, SubLink)) + { + disable_inheritance((Query *) (((SubLink *) node)->subselect)); + return false; + } + + return expression_tree_walker(node, disable_inheritance_subselect_walker, (void *) context); +} + +/* + * Checks if query affects only one partition. If true then substitute + */ +void +handle_modification_query(Query *parse) +{ + const PartRelationInfo *prel; + List *ranges; + RangeTblEntry *rte; + WrapperNode *wrap; + Expr *expr; + WalkerContext context; + + Assert(parse->commandType == CMD_UPDATE || + parse->commandType == CMD_DELETE); + Assert(parse->resultRelation > 0); + + rte = rt_fetch(parse->resultRelation, parse->rtable); + prel = get_pathman_relation_info(rte->relid); + + if (!prel) + return; + + /* Parse syntax tree and extract partition ranges */ + ranges = list_make1_irange(make_irange(0, PrelLastChild(prel), false)); + expr = (Expr *) eval_const_expressions(NULL, parse->jointree->quals); + if (!expr) + return; + + /* Parse syntax tree and extract partition ranges */ + InitWalkerContext(&context, prel, NULL, false); + wrap = walk_expr_tree(expr, &context); + + ranges = irange_list_intersect(ranges, wrap->rangeset); + + /* If only one partition is affected then substitute parent table with partition */ + if (irange_list_length(ranges) == 1) + { + IndexRange irange = linitial_irange(ranges); + if (irange.ir_lower == irange.ir_upper) + { + Oid *children = PrelGetChildrenArray(prel); + rte->relid = children[irange.ir_lower]; + rte->inh = false; + } + } + + return; +} + +/* + * Creates child relation and adds it to root. + * Returns child index in simple_rel_array + */ +int +append_child_relation(PlannerInfo *root, RelOptInfo *rel, Index rti, + RangeTblEntry *rte, int index, Oid childOid, List *wrappers) +{ + RangeTblEntry *childrte; + RelOptInfo *childrel; + Index childRTindex; + AppendRelInfo *appinfo; + ListCell *lc, + *lc2; + Relation newrelation; + PlanRowMark *parent_rowmark; + PlanRowMark *child_rowmark; + AttrNumber i; + + /* FIXME: acquire a suitable lock on partition */ + newrelation = heap_open(childOid, NoLock); + + /* + * Create RangeTblEntry for child relation. + * This code partially based on expand_inherited_rtentry() function. + */ + childrte = copyObject(rte); + childrte->relid = childOid; + childrte->relkind = newrelation->rd_rel->relkind; + childrte->inh = false; + childrte->requiredPerms = 0; + root->parse->rtable = lappend(root->parse->rtable, childrte); + childRTindex = list_length(root->parse->rtable); + root->simple_rte_array[childRTindex] = childrte; + + /* Create RelOptInfo */ + childrel = build_simple_rel(root, childRTindex, RELOPT_OTHER_MEMBER_REL); + + /* Copy targetlist */ + copy_targetlist_compat(childrel, rel); + + /* Copy attr_needed & attr_widths */ + childrel->attr_needed = (Relids *) + palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(Relids)); + childrel->attr_widths = (int32 *) + palloc0((rel->max_attr - rel->min_attr + 1) * sizeof(int32)); + + for (i = 0; i < rel->max_attr - rel->min_attr + 1; i++) + childrel->attr_needed[i] = bms_copy(rel->attr_needed[i]); + + memcpy(childrel->attr_widths, rel->attr_widths, + (rel->max_attr - rel->min_attr + 1) * sizeof(int32)); + + /* + * Copy restrictions. If it's not the parent table then copy only those + * restrictions that reference to this partition + */ + childrel->baserestrictinfo = NIL; + if (rte->relid != childOid) + { + forboth(lc, wrappers, lc2, rel->baserestrictinfo) + { + bool alwaysTrue; + WrapperNode *wrap = (WrapperNode *) lfirst(lc); + Node *new_clause = wrapper_make_expression(wrap, index, &alwaysTrue); + RestrictInfo *old_rinfo = (RestrictInfo *) lfirst(lc2); + + if (alwaysTrue) + { + continue; + } + Assert(new_clause); + + if (and_clause((Node *) new_clause)) + { + ListCell *alc; + + foreach(alc, ((BoolExpr *) new_clause)->args) + { + Node *arg = (Node *) lfirst(alc); + RestrictInfo *new_rinfo = rebuild_restrictinfo(arg, old_rinfo); + + change_varnos((Node *)new_rinfo, rel->relid, childrel->relid); + childrel->baserestrictinfo = lappend(childrel->baserestrictinfo, + new_rinfo); + } + } + else + { + RestrictInfo *new_rinfo = rebuild_restrictinfo(new_clause, old_rinfo); + + /* Replace old relids with new ones */ + change_varnos((Node *)new_rinfo, rel->relid, childrel->relid); + + childrel->baserestrictinfo = lappend(childrel->baserestrictinfo, + (void *) new_rinfo); + } + } + } + /* If it's the parent table then copy all restrictions */ + else + { + foreach(lc, rel->baserestrictinfo) + { + RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc); + RestrictInfo *new_rinfo = (RestrictInfo *) copyObject(rinfo); + + change_varnos((Node *)new_rinfo, rel->relid, childrel->relid); + childrel->baserestrictinfo = lappend(childrel->baserestrictinfo, + (void *) new_rinfo); + } + } + + /* Build an AppendRelInfo for this parent and child */ + appinfo = makeNode(AppendRelInfo); + appinfo->parent_relid = rti; + appinfo->child_relid = childRTindex; + appinfo->parent_reloid = rte->relid; + root->append_rel_list = lappend(root->append_rel_list, appinfo); + root->total_table_pages += (double) childrel->pages; + + /* Add equivalence members */ + foreach(lc, root->eq_classes) + { + EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc); + + /* Copy equivalence member from parent and make some modifications */ + foreach(lc2, cur_ec->ec_members) + { + EquivalenceMember *cur_em = (EquivalenceMember *) lfirst(lc2); + EquivalenceMember *em; + + if (!bms_is_member(rti, cur_em->em_relids)) + continue; + + em = makeNode(EquivalenceMember); + em->em_expr = copyObject(cur_em->em_expr); + change_varnos((Node *) em->em_expr, rti, childRTindex); + em->em_relids = bms_add_member(NULL, childRTindex); + em->em_nullable_relids = cur_em->em_nullable_relids; + em->em_is_const = false; + em->em_is_child = true; + em->em_datatype = cur_em->em_datatype; + cur_ec->ec_members = lappend(cur_ec->ec_members, em); + } + } + childrel->has_eclass_joins = rel->has_eclass_joins; + + /* Recalc parent relation tuples count */ + rel->tuples += childrel->tuples; + + /* Close child relations, but keep locks */ + heap_close(newrelation, NoLock); + + + /* Create rowmarks required for child rels */ + parent_rowmark = get_plan_rowmark(root->rowMarks, rti); + if (parent_rowmark) + { + child_rowmark = makeNode(PlanRowMark); + + child_rowmark->rti = childRTindex; + child_rowmark->prti = rti; + child_rowmark->rowmarkId = parent_rowmark->rowmarkId; + /* Reselect rowmark type, because relkind might not match parent */ + child_rowmark->markType = select_rowmark_type(childrte, + parent_rowmark->strength); + child_rowmark->allMarkTypes = (1 << child_rowmark->markType); + child_rowmark->strength = parent_rowmark->strength; + child_rowmark->waitPolicy = parent_rowmark->waitPolicy; + child_rowmark->isParent = false; + + /* Include child's rowmark type in parent's allMarkTypes */ + parent_rowmark->allMarkTypes |= child_rowmark->allMarkTypes; + + root->rowMarks = lappend(root->rowMarks, child_rowmark); + + parent_rowmark->isParent = true; + } + + return childRTindex; +} + +/* Create new restriction based on clause */ +static RestrictInfo * +rebuild_restrictinfo(Node *clause, RestrictInfo *old_rinfo) +{ + return make_restrictinfo((Expr *) clause, + old_rinfo->is_pushed_down, + old_rinfo->outerjoin_delayed, + old_rinfo->pseudoconstant, + old_rinfo->required_relids, + old_rinfo->outer_relids, + old_rinfo->nullable_relids); +} + +/* Convert wrapper into expression for given index */ +static Node * +wrapper_make_expression(WrapperNode *wrap, int index, bool *alwaysTrue) +{ + bool lossy, found; + + *alwaysTrue = false; + /* + * TODO: use faster algorithm using knowledge that we enumerate indexes + * sequntially. + */ + found = irange_list_find(wrap->rangeset, index, &lossy); + + /* Return NULL for always true and always false. */ + if (!found) + return NULL; + if (!lossy) + { + *alwaysTrue = true; + return NULL; + } + + if (IsA(wrap->orig, BoolExpr)) + { + const BoolExpr *expr = (const BoolExpr *) wrap->orig; + BoolExpr *result; + + if (expr->boolop == OR_EXPR || expr->boolop == AND_EXPR) + { + ListCell *lc; + List *args = NIL; + + foreach (lc, wrap->args) + { + Node *arg; + bool childAlwaysTrue; + + arg = wrapper_make_expression((WrapperNode *) lfirst(lc), + index, &childAlwaysTrue); +#ifdef USE_ASSERT_CHECKING + /* + * We shouldn't get there for always true clause under OR and + * always false clause under AND. + */ + if (expr->boolop == OR_EXPR) + Assert(!childAlwaysTrue); + if (expr->boolop == AND_EXPR) + Assert(arg || childAlwaysTrue); +#endif + if (arg) + args = lappend(args, arg); + } + + Assert(list_length(args) >= 1); + + /* Remove redundant OR/AND when child is single. */ + if (list_length(args) == 1) + return (Node *) linitial(args); + + result = makeNode(BoolExpr); + result->xpr.type = T_BoolExpr; + result->args = args; + result->boolop = expr->boolop; + result->location = expr->location; + return (Node *) result; + } + else + return copyObject(wrap->orig); + } + else + return copyObject(wrap->orig); +} + +/* + * Recursive function to walk through conditions tree + */ +WrapperNode * +walk_expr_tree(Expr *expr, WalkerContext *context) +{ + BoolExpr *boolexpr; + OpExpr *opexpr; + ScalarArrayOpExpr *arrexpr; + WrapperNode *result; + + switch (expr->type) + { + /* Useful for INSERT optimization */ + case T_Const: + return handle_const((Const *) expr, context); + + /* AND, OR, NOT expressions */ + case T_BoolExpr: + boolexpr = (BoolExpr *) expr; + return handle_boolexpr(boolexpr, context); + + /* =, !=, <, > etc. */ + case T_OpExpr: + opexpr = (OpExpr *) expr; + return handle_opexpr(opexpr, context); + + /* IN expression */ + case T_ScalarArrayOpExpr: + arrexpr = (ScalarArrayOpExpr *) expr; + return handle_arrexpr(arrexpr, context); + + default: + result = (WrapperNode *) palloc(sizeof(WrapperNode)); + result->orig = (const Node *) expr; + result->args = NIL; + result->rangeset = list_make1_irange( + make_irange(0, PrelLastChild(context->prel), true)); + result->paramsel = 1.0; + return result; + } +} + +/* + * Append\prepend partitions if there's no partition to store 'value'. + * + * Used by create_partitions_internal(). + * + * NB: 'value' type is not needed since we've already taken + * it into account while searching for the 'cmp_proc'. + */ +static bool +spawn_partitions(Oid partitioned_rel, /* parent's Oid */ + Datum value, /* value to be INSERTed */ + Datum leading_bound, /* current global min\max */ + Oid leading_bound_type, /* type of the boundary */ + FmgrInfo *cmp_proc, /* cmp(value, leading_bound) */ + Datum interval_binary, /* interval in binary form */ + Oid interval_type, /* INTERVALOID or prel->atttype */ + bool forward, /* append\prepend */ + Oid *last_partition) /* result (Oid of the last partition) */ +{ +/* Cache "+"(leading_bound, interval) or "-"(leading_bound, interval) operator */ +#define CacheOperator(finfo, opname, arg1, arg2, is_cached) \ + do { \ + if (!is_cached) \ + { \ + fmgr_info(get_binary_operator_oid((opname), (arg1), (arg2)), \ + (finfo)); \ + is_cached = true; \ + } \ + } while (0) + +/* Use "<" for prepend & ">=" for append */ +#define do_compare(compar, a, b, fwd) \ + ( \ + (fwd) ? \ + check_ge((compar), (a), (b)) : \ + check_lt((compar), (a), (b)) \ + ) + + FmgrInfo interval_move_bound; /* function to move upper\lower boundary */ + bool interval_move_bound_cached = false; /* is it cached already? */ + bool spawned = false; + + Datum cur_part_leading = leading_bound; + + char *query; + + /* Create querty statement */ + query = psprintf("SELECT part::regclass " + "FROM %s.create_single_range_partition($1, $2, $3) AS part", + get_namespace_name(get_pathman_schema())); + + /* Execute comparison function cmp(value, cur_part_leading) */ + while (do_compare(cmp_proc, value, cur_part_leading, forward)) + { + char *nulls = NULL; /* no params are NULL */ + Oid types[3] = { REGCLASSOID, leading_bound_type, leading_bound_type }; + Datum values[3]; + int ret; + + /* Assign the 'following' boundary to current 'leading' value */ + Datum cur_part_following = cur_part_leading; + + CacheOperator(&interval_move_bound, (forward ? "+" : "-"), + leading_bound_type, interval_type, interval_move_bound_cached); + + /* Move leading bound by interval (leading +\- INTERVAL) */ + cur_part_leading = FunctionCall2(&interval_move_bound, + cur_part_leading, + interval_binary); + + /* Fill in 'values' with parent's Oid and correct boundaries... */ + values[0] = partitioned_rel; /* partitioned table's Oid */ + values[1] = forward ? cur_part_following : cur_part_leading; /* value #1 */ + values[2] = forward ? cur_part_leading : cur_part_following; /* value #2 */ + + /* ...and create partition */ + ret = SPI_execute_with_args(query, 3, types, values, nulls, false, 0); + if (ret != SPI_OK_SELECT) + elog(ERROR, "Could not spawn a partition"); + + /* Set 'last_partition' if necessary */ + if (last_partition) + { + HeapTuple htup = SPI_tuptable->vals[0]; + Datum partid; + bool isnull; + + Assert(SPI_processed == 1); + Assert(SPI_tuptable->tupdesc->natts == 1); + partid = SPI_getbinval(htup, SPI_tuptable->tupdesc, 1, &isnull); + + *last_partition = DatumGetObjectId(partid); + } + +#ifdef USE_ASSERT_CHECKING + elog(DEBUG2, "%s partition with following='%s' & leading='%s' [%u]", + (forward ? "Appending" : "Prepending"), + DebugPrintDatum(cur_part_following, leading_bound_type), + DebugPrintDatum(cur_part_leading, leading_bound_type), + MyProcPid); +#endif + + /* We have spawned at least 1 partition */ + spawned = true; + } + + pfree(query); + + return spawned; +} + +/* + * Convert interval from TEXT to binary form using partitioned column's type. + */ +static Datum +extract_binary_interval_from_text(Datum interval_text, /* interval as TEXT */ + Oid part_atttype, /* partitioned column's type */ + Oid *interval_type) /* returned value */ +{ + Datum interval_binary; + const char *interval_cstring; + + interval_cstring = TextDatumGetCString(interval_text); + + /* If 'part_atttype' is a *date type*, cast 'range_interval' to INTERVAL */ + if (is_date_type_internal(part_atttype)) + { + int32 interval_typmod = PATHMAN_CONFIG_interval_typmod; + + /* Convert interval from CSTRING to internal form */ + interval_binary = DirectFunctionCall3(interval_in, + CStringGetDatum(interval_cstring), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(interval_typmod)); + if (interval_type) + *interval_type = INTERVALOID; + } + /* Otherwise cast it to the partitioned column's type */ + else + { + HeapTuple htup; + Oid typein_proc = InvalidOid; + + htup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(part_atttype)); + if (HeapTupleIsValid(htup)) + { + typein_proc = ((Form_pg_type) GETSTRUCT(htup))->typinput; + ReleaseSysCache(htup); + } + else + elog(ERROR, "Cannot find input function for type %u", part_atttype); + + /* + * Convert interval from CSTRING to 'prel->atttype'. + * + * Note: We pass 3 arguments in case + * 'typein_proc' also takes Oid & typmod. + */ + interval_binary = OidFunctionCall3(typein_proc, + CStringGetDatum(interval_cstring), + ObjectIdGetDatum(part_atttype), + Int32GetDatum(-1)); + if (interval_type) + *interval_type = part_atttype; + } + + return interval_binary; +} + +/* + * Append partitions (if needed) and return Oid of the partition to contain value. + * + * NB: This function should not be called directly, use create_partitions() instead. + */ +Oid +create_partitions_internal(Oid relid, Datum value, Oid value_type) +{ + MemoryContext old_mcxt = CurrentMemoryContext; + Oid partid = InvalidOid; /* last created partition (or InvalidOid) */ + + PG_TRY(); + { + const PartRelationInfo *prel; + Datum values[Natts_pathman_config]; + bool isnull[Natts_pathman_config]; + + /* Get both PartRelationInfo & PATHMAN_CONFIG contents for this relation */ + if (pathman_config_contains_relation(relid, values, isnull, NULL)) + { + Oid base_atttype; /* base type of prel->atttype */ + Oid base_value_type; /* base type of value_type */ + + Datum min_rvalue, /* absolute MIN */ + max_rvalue; /* absolute MAX */ + + Oid interval_type = InvalidOid; + Datum interval_binary, /* assigned 'width' of a single partition */ + interval_text; + + FmgrInfo interval_type_cmp; + + /* Fetch PartRelationInfo by 'relid' */ + prel = get_pathman_relation_info(relid); + shout_if_prel_is_invalid(relid, prel, PT_RANGE); + + /* Fetch base types of prel->atttype & value_type */ + base_atttype = getBaseType(prel->atttype); + base_value_type = getBaseType(value_type); + + /* Read max & min range values from PartRelationInfo */ + min_rvalue = PrelGetRangesArray(prel)[0].min; + max_rvalue = PrelGetRangesArray(prel)[PrelLastChild(prel)].max; + + /* Copy datums on order to protect them from cache invalidation */ + min_rvalue = datumCopy(min_rvalue, prel->attbyval, prel->attlen); + max_rvalue = datumCopy(max_rvalue, prel->attbyval, prel->attlen); + + /* Retrieve interval as TEXT from tuple */ + interval_text = values[Anum_pathman_config_range_interval - 1]; + + /* Convert interval to binary representation */ + interval_binary = extract_binary_interval_from_text(interval_text, + base_atttype, + &interval_type); + + /* Fill the FmgrInfo struct with a cmp(value, part_attribute) function */ + fill_type_cmp_fmgr_info(&interval_type_cmp, base_value_type, base_atttype); + + if (SPI_connect() != SPI_OK_CONNECT) + elog(ERROR, "could not connect using SPI"); + + /* while (value >= MAX) ... */ + spawn_partitions(PrelParentRelid(prel), value, max_rvalue, + base_atttype, &interval_type_cmp, interval_binary, + interval_type, true, &partid); + + /* while (value < MIN) ... */ + if (partid == InvalidOid) + spawn_partitions(PrelParentRelid(prel), value, min_rvalue, + base_atttype, &interval_type_cmp, interval_binary, + interval_type, false, &partid); + + SPI_finish(); /* close SPI connection */ + } + else + elog(ERROR, "pg_pathman's config does not contain relation \"%s\"", + get_rel_name_or_relid(relid)); + } + PG_CATCH(); + { + ErrorData *edata; + + /* Switch to the original context & copy edata */ + MemoryContextSwitchTo(old_mcxt); + edata = CopyErrorData(); + FlushErrorState(); + + elog(LOG, "create_partitions_internal(): %s [%u]", + edata->message, MyProcPid); + + FreeErrorData(edata); + + SPI_finish(); /* no problem if not connected */ + + /* Reset 'partid' in case of error */ + partid = InvalidOid; + } + PG_END_TRY(); + + return partid; +} + +/* + * Create RANGE partitions (if needed) using either BGW or current backend. + * + * Returns Oid of the partition to store 'value'. + */ +Oid +create_partitions(Oid relid, Datum value, Oid value_type) +{ + TransactionId rel_xmin; + Oid last_partition = InvalidOid; + + /* Check that table is partitioned and fetch xmin */ + if (pathman_config_contains_relation(relid, NULL, NULL, &rel_xmin)) + { + bool part_in_prev_xact = + TransactionIdPrecedes(rel_xmin, GetCurrentTransactionId()) || + TransactionIdEquals(rel_xmin, FrozenTransactionId); + + /* + * If table has been partitioned in some previous xact AND + * we don't hold any conflicting locks, run BGWorker. + */ + if (part_in_prev_xact && !xact_bgw_conflicting_lock_exists(relid)) + { + elog(DEBUG2, "create_partitions(): chose BGWorker [%u]", MyProcPid); + last_partition = create_partitions_bg_worker(relid, value, value_type); + } + /* Else it'd be better for the current backend to create partitions */ + else + { + elog(DEBUG2, "create_partitions(): chose backend [%u]", MyProcPid); + last_partition = create_partitions_internal(relid, value, value_type); + } + } + else + elog(ERROR, "relation \"%s\" is not partitioned by pg_pathman", + get_rel_name_or_relid(relid)); + + /* Check that 'last_partition' is valid */ + if (last_partition == InvalidOid) + elog(ERROR, "could not create new partitions for relation \"%s\"", + get_rel_name_or_relid(relid)); + + return last_partition; +} + +/* + * Given RangeEntry array and 'value', return selected + * RANGE partitions inside the WrapperNode. + */ +void +select_range_partitions(const Datum value, + FmgrInfo *cmp_func, + const RangeEntry *ranges, + const int nranges, + const int strategy, + WrapperNode *result) +{ + const RangeEntry *current_re; + bool lossy = false, + is_less, + is_greater; + +#ifdef USE_ASSERT_CHECKING + bool found = false; + int counter = 0; +#endif + + int i, + startidx = 0, + endidx = nranges - 1, + cmp_min, + cmp_max; + + /* Initial value (no missing partitions found) */ + result->found_gap = false; + + /* Check boundaries */ + if (nranges == 0) + { + result->rangeset = NIL; + return; + } + else + { + Assert(ranges); + Assert(cmp_func); + + /* Corner cases */ + cmp_min = FunctionCall2(cmp_func, value, ranges[startidx].min), + cmp_max = FunctionCall2(cmp_func, value, ranges[endidx].max); + + if ((cmp_min <= 0 && strategy == BTLessStrategyNumber) || + (cmp_min < 0 && (strategy == BTLessEqualStrategyNumber || + strategy == BTEqualStrategyNumber))) + { + result->rangeset = NIL; + return; + } + + if (cmp_max >= 0 && (strategy == BTGreaterEqualStrategyNumber || + strategy == BTGreaterStrategyNumber || + strategy == BTEqualStrategyNumber)) + { + result->rangeset = NIL; + return; + } + + if ((cmp_min < 0 && strategy == BTGreaterStrategyNumber) || + (cmp_min <= 0 && strategy == BTGreaterEqualStrategyNumber)) + { + result->rangeset = list_make1_irange(make_irange(startidx, endidx, false)); + return; + } + + if (cmp_max >= 0 && (strategy == BTLessEqualStrategyNumber || + strategy == BTLessStrategyNumber)) + { + result->rangeset = list_make1_irange(make_irange(startidx, endidx, false)); + return; + } + } + + /* Binary search */ + while (true) + { + Assert(cmp_func); + + i = startidx + (endidx - startidx) / 2; + Assert(i >= 0 && i < nranges); + + current_re = &ranges[i]; + + cmp_min = FunctionCall2(cmp_func, value, current_re->min); + cmp_max = FunctionCall2(cmp_func, value, current_re->max); + + is_less = (cmp_min < 0 || (cmp_min == 0 && strategy == BTLessStrategyNumber)); + is_greater = (cmp_max > 0 || (cmp_max >= 0 && strategy != BTLessStrategyNumber)); + + if (!is_less && !is_greater) + { + if (strategy == BTGreaterEqualStrategyNumber && cmp_min == 0) + lossy = false; + else if (strategy == BTLessStrategyNumber && cmp_max == 0) + lossy = false; + else + lossy = true; +#ifdef USE_ASSERT_CHECKING + found = true; +#endif + break; + } + + /* If we still haven't found partition then it doesn't exist */ + if (startidx >= endidx) + { + result->rangeset = NIL; + result->found_gap = true; + return; + } + + if (is_less) + endidx = i - 1; + else if (is_greater) + startidx = i + 1; + + /* For debug's sake */ + Assert(++counter < 100); + } + + Assert(found); + + /* Filter partitions */ + switch(strategy) + { + case BTLessStrategyNumber: + case BTLessEqualStrategyNumber: + if (lossy) + { + result->rangeset = list_make1_irange(make_irange(i, i, true)); + if (i > 0) + result->rangeset = lcons_irange(make_irange(0, i - 1, false), + result->rangeset); + } + else + { + result->rangeset = list_make1_irange(make_irange(0, i, false)); + } + break; + + case BTEqualStrategyNumber: + result->rangeset = list_make1_irange(make_irange(i, i, true)); + break; + + case BTGreaterEqualStrategyNumber: + case BTGreaterStrategyNumber: + if (lossy) + { + result->rangeset = list_make1_irange(make_irange(i, i, true)); + if (i < nranges - 1) + result->rangeset = + lappend_irange(result->rangeset, + make_irange(i + 1, + nranges - 1, + false)); + } + else + { + result->rangeset = + list_make1_irange(make_irange(i, + nranges - 1, + false)); + } + break; + + default: + elog(ERROR, "Unknown btree strategy (%u)", strategy); + break; + } +} + +/* + * This function determines which partitions should appear in query plan. + */ +static void +handle_binary_opexpr(WalkerContext *context, WrapperNode *result, + const Node *varnode, const Const *c) +{ + int strategy; + TypeCacheEntry *tce; + FmgrInfo cmp_func; + Oid vartype; + const OpExpr *expr = (const OpExpr *) result->orig; + const PartRelationInfo *prel = context->prel; + + Assert(IsA(varnode, Var) || IsA(varnode, RelabelType)); + + vartype = !IsA(varnode, RelabelType) ? + ((Var *) varnode)->vartype : + ((RelabelType *) varnode)->resulttype; + + tce = lookup_type_cache(vartype, TYPECACHE_BTREE_OPFAMILY); + strategy = get_op_opfamily_strategy(expr->opno, tce->btree_opf); + fill_type_cmp_fmgr_info(&cmp_func, + getBaseType(c->consttype), + getBaseType(prel->atttype)); + + switch (prel->parttype) + { + case PT_HASH: + if (strategy == BTEqualStrategyNumber) + { + Datum value = OidFunctionCall1(prel->hash_proc, c->constvalue); + uint32 idx = hash_to_part_index(DatumGetInt32(value), + PrelChildrenCount(prel)); + + result->rangeset = list_make1_irange(make_irange(idx, idx, true)); + + return; /* exit on equal */ + } + break; /* continue to function's end */ + + case PT_RANGE: + { + select_range_partitions(c->constvalue, + &cmp_func, + PrelGetRangesArray(context->prel), + PrelChildrenCount(context->prel), + strategy, + result); + return; + } + + default: + elog(ERROR, "Unknown partitioning type %u", prel->parttype); + } + + result->rangeset = list_make1_irange(make_irange(0, PrelLastChild(prel), true)); + result->paramsel = 1.0; +} + +/* + * Estimate selectivity of parametrized quals. + */ +static void +handle_binary_opexpr_param(const PartRelationInfo *prel, + WrapperNode *result, const Node *varnode) +{ + const OpExpr *expr = (const OpExpr *)result->orig; + TypeCacheEntry *tce; + int strategy; + Oid vartype; + + Assert(IsA(varnode, Var) || IsA(varnode, RelabelType)); + + vartype = !IsA(varnode, RelabelType) ? + ((Var *) varnode)->vartype : + ((RelabelType *) varnode)->resulttype; + + /* Determine operator type */ + tce = lookup_type_cache(vartype, TYPECACHE_BTREE_OPFAMILY); + strategy = get_op_opfamily_strategy(expr->opno, tce->btree_opf); + + result->rangeset = list_make1_irange(make_irange(0, PrelLastChild(prel), true)); + + if (strategy == BTEqualStrategyNumber) + { + result->paramsel = 1.0 / (double) PrelChildrenCount(prel); + } + else if (prel->parttype == PT_RANGE && strategy > 0) + { + result->paramsel = DEFAULT_INEQ_SEL; + } + else + { + result->paramsel = 1.0; + } +} + +/* + * Convert hash value to the partition index. + */ +uint32 +hash_to_part_index(uint32 value, uint32 partitions) +{ + return value % partitions; +} + +search_rangerel_result +search_range_partition_eq(const Datum value, + FmgrInfo *cmp_func, + const PartRelationInfo *prel, + RangeEntry *out_re) /* returned RangeEntry */ +{ + RangeEntry *ranges; + int nranges; + WrapperNode result; + + ranges = PrelGetRangesArray(prel); + nranges = PrelChildrenCount(prel); + + select_range_partitions(value, + cmp_func, + ranges, + nranges, + BTEqualStrategyNumber, + &result); + + if (result.found_gap) + { + return SEARCH_RANGEREL_GAP; + } + else if (result.rangeset == NIL) + { + return SEARCH_RANGEREL_OUT_OF_RANGE; + } + else + { + IndexRange irange = linitial_irange(result.rangeset); + + Assert(list_length(result.rangeset) == 1); + Assert(irange.ir_lower == irange.ir_upper); + Assert(irange.ir_valid); + + /* Write result to the 'out_rentry' if necessary */ + if (out_re) + memcpy((void *) out_re, + (const void *) &ranges[irange.ir_lower], + sizeof(RangeEntry)); + + return SEARCH_RANGEREL_FOUND; + } +} + +static Const * +extract_const(WalkerContext *wcxt, Param *param) +{ + ExprState *estate = ExecInitExpr((Expr *) param, NULL); + bool isnull; + Datum value = ExecEvalExpr(estate, wcxt->econtext, &isnull, NULL); + + return makeConst(param->paramtype, param->paramtypmod, + param->paramcollid, get_typlen(param->paramtype), + value, isnull, get_typbyval(param->paramtype)); +} + +static WrapperNode * +handle_const(const Const *c, WalkerContext *context) +{ + const PartRelationInfo *prel = context->prel; + WrapperNode *result = (WrapperNode *) palloc(sizeof(WrapperNode)); + + result->orig = (const Node *) c; + + /* + * Had to add this check for queries like: + * select * from test.hash_rel where txt = NULL; + */ + if (!context->for_insert) + { + result->rangeset = list_make1_irange(make_irange(0, + PrelLastChild(prel), + true)); + result->paramsel = 1.0; + + return result; + } + + switch (prel->parttype) + { + case PT_HASH: + { + Datum value = OidFunctionCall1(prel->hash_proc, c->constvalue); + uint32 idx = hash_to_part_index(DatumGetInt32(value), + PrelChildrenCount(prel)); + result->rangeset = list_make1_irange(make_irange(idx, idx, true)); + } + break; + + case PT_RANGE: + { + TypeCacheEntry *tce; + + tce = lookup_type_cache(c->consttype, TYPECACHE_CMP_PROC_FINFO); + + select_range_partitions(c->constvalue, + &tce->cmp_proc_finfo, + PrelGetRangesArray(context->prel), + PrelChildrenCount(context->prel), + BTEqualStrategyNumber, + result); + } + break; + + default: + elog(ERROR, "Unknown partitioning type %u", prel->parttype); + break; + } + + return result; +} + +/* + * Operator expression handler + */ +static WrapperNode * +handle_opexpr(const OpExpr *expr, WalkerContext *context) +{ + WrapperNode *result = (WrapperNode *)palloc(sizeof(WrapperNode)); + Node *var, *param; + const PartRelationInfo *prel = context->prel; + + result->orig = (const Node *)expr; + result->args = NIL; + + if (list_length(expr->args) == 2) + { + if (pull_var_param(context, expr, &var, ¶m)) + { + if (IsConstValue(context, param)) + { + handle_binary_opexpr(context, result, var, ExtractConst(context, param)); + return result; + } + else if (IsA(param, Param) || IsA(param, Var)) + { + handle_binary_opexpr_param(prel, result, var); + return result; + } + } + } + + result->rangeset = list_make1_irange(make_irange(0, PrelLastChild(prel), true)); + result->paramsel = 1.0; + return result; +} + +/* + * Checks if expression is a KEY OP PARAM or PARAM OP KEY, + * where KEY is partition key (it could be Var or RelableType) and PARAM is + * whatever. Function returns variable (or RelableType) and param via var_ptr + * and param_ptr pointers. If partition key isn't in expression then function + * returns false. + */ +static bool +pull_var_param(const WalkerContext *ctx, + const OpExpr *expr, + Node **var_ptr, + Node **param_ptr) +{ + Node *left = linitial(expr->args), + *right = lsecond(expr->args); + Var *v = NULL; + + /* Check the case when variable is on the left side */ + if (IsA(left, Var) || IsA(left, RelabelType)) + { + v = !IsA(left, RelabelType) ? + (Var *) left : + (Var *) ((RelabelType *) left)->arg; + + if (v->varoattno == ctx->prel->attnum) + { + *var_ptr = left; + *param_ptr = right; + return true; + } + } + + /* ... variable is on the right side */ + if (IsA(right, Var) || IsA(right, RelabelType)) + { + v = !IsA(right, RelabelType) ? + (Var *) right : + (Var *) ((RelabelType *) right)->arg; + + if (v->varoattno == ctx->prel->attnum) + { + *var_ptr = right; + *param_ptr = left; + return true; + } + } + + /* Variable isn't a partitionig key */ + return false; +} + +/* + * Boolean expression handler + */ +static WrapperNode * +handle_boolexpr(const BoolExpr *expr, WalkerContext *context) +{ + WrapperNode *result = (WrapperNode *)palloc(sizeof(WrapperNode)); + ListCell *lc; + const PartRelationInfo *prel = context->prel; + + result->orig = (const Node *)expr; + result->args = NIL; + result->paramsel = 1.0; + + if (expr->boolop == AND_EXPR) + result->rangeset = list_make1_irange(make_irange(0, + PrelLastChild(prel), + false)); + else + result->rangeset = NIL; + + foreach (lc, expr->args) + { + WrapperNode *arg; + + arg = walk_expr_tree((Expr *)lfirst(lc), context); + result->args = lappend(result->args, arg); + switch (expr->boolop) + { + case OR_EXPR: + result->rangeset = irange_list_union(result->rangeset, arg->rangeset); + break; + case AND_EXPR: + result->rangeset = irange_list_intersect(result->rangeset, arg->rangeset); + result->paramsel *= arg->paramsel; + break; + default: + result->rangeset = list_make1_irange(make_irange(0, + PrelLastChild(prel), + false)); + break; + } + } + + if (expr->boolop == OR_EXPR) + { + int totallen = irange_list_length(result->rangeset); + + foreach (lc, result->args) + { + WrapperNode *arg = (WrapperNode *) lfirst(lc); + int len = irange_list_length(arg->rangeset); + + result->paramsel *= (1.0 - arg->paramsel * (double)len / (double)totallen); + } + result->paramsel = 1.0 - result->paramsel; + } + + return result; +} + +/* + * Scalar array expression + */ +static WrapperNode * +handle_arrexpr(const ScalarArrayOpExpr *expr, WalkerContext *context) +{ + WrapperNode *result = (WrapperNode *)palloc(sizeof(WrapperNode)); + Node *varnode = (Node *) linitial(expr->args); + Var *var; + Node *arraynode = (Node *) lsecond(expr->args); + const PartRelationInfo *prel = context->prel; + + result->orig = (const Node *)expr; + result->args = NIL; + result->paramsel = 1.0; + + Assert(varnode != NULL); + + /* If variable is not the partition key then skip it */ + if (IsA(varnode, Var) || IsA(varnode, RelabelType)) + { + var = !IsA(varnode, RelabelType) ? + (Var *) varnode : + (Var *) ((RelabelType *) varnode)->arg; + if (var->varoattno != prel->attnum) + goto handle_arrexpr_return; + } + else + goto handle_arrexpr_return; + + if (arraynode && IsA(arraynode, Const) && + !((Const *) arraynode)->constisnull) + { + ArrayType *arrayval; + int16 elmlen; + bool elmbyval; + char elmalign; + int num_elems; + Datum *elem_values; + bool *elem_nulls; + int i; + + /* Extract values from array */ + arrayval = DatumGetArrayTypeP(((Const *) arraynode)->constvalue); + get_typlenbyvalalign(ARR_ELEMTYPE(arrayval), + &elmlen, &elmbyval, &elmalign); + deconstruct_array(arrayval, + ARR_ELEMTYPE(arrayval), + elmlen, elmbyval, elmalign, + &elem_values, &elem_nulls, &num_elems); + + result->rangeset = NIL; + + /* Construct OIDs list */ + for (i = 0; i < num_elems; i++) + { + Datum value; + uint32 idx; + + /* Invoke base hash function for value type */ + value = OidFunctionCall1(prel->hash_proc, elem_values[i]); + idx = hash_to_part_index(DatumGetInt32(value), PrelChildrenCount(prel)); + result->rangeset = irange_list_union(result->rangeset, + list_make1_irange(make_irange(idx, + idx, + true))); + } + + /* Free resources */ + pfree(elem_values); + pfree(elem_nulls); + + return result; + } + + if (arraynode && IsA(arraynode, Param)) + result->paramsel = DEFAULT_INEQ_SEL; + +handle_arrexpr_return: + result->rangeset = list_make1_irange(make_irange(0, PrelLastChild(prel), true)); + return result; +} + +/* + * Theres are functions below copied from allpaths.c with (or without) some + * modifications. Couldn't use original because of 'static' modifier. + */ + +/* + * set_plain_rel_size + * Set size estimates for a plain relation (no subquery, no inheritance) + */ +static void +set_plain_rel_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + /* + * Test any partial indexes of rel for applicability. We must do this + * first since partial unique indexes can affect size estimates. + */ + check_index_predicates_compat(root, rel); + + /* Mark rel with estimated output rows, width, etc */ + set_baserel_size_estimates(root, rel); +} + +/* + * set_plain_rel_pathlist + * Build access paths for a plain relation (no subquery, no inheritance) + */ +static void +set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + Relids required_outer; + Path *path; + + /* + * We don't support pushing join clauses into the quals of a seqscan, but + * it could still have required parameterization due to LATERAL refs in + * its tlist. + */ + required_outer = rel->lateral_relids; + + /* Consider sequential scan */ +#if PG_VERSION_NUM >= 90600 + path = create_seqscan_path(root, rel, required_outer, 0); +#else + path = create_seqscan_path(root, rel, required_outer); +#endif + add_path(rel, path); + + /* Consider index scans */ + create_index_paths(root, rel); + + /* Consider TID scans */ + create_tidscan_paths(root, rel); +} + +/* + * set_foreign_size + * Set size estimates for a foreign table RTE + */ +static void +set_foreign_size(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + /* Mark rel with estimated output rows, width, etc */ + set_foreign_size_estimates(root, rel); + + /* Let FDW adjust the size estimates, if it can */ + rel->fdwroutine->GetForeignRelSize(root, rel, rte->relid); + + /* ... but do not let it set the rows estimate to zero */ + rel->rows = clamp_row_est(rel->rows); +} + +/* + * set_foreign_pathlist + * Build access paths for a foreign table RTE + */ +static void +set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte) +{ + /* Call the FDW's GetForeignPaths function to generate path(s) */ + rel->fdwroutine->GetForeignPaths(root, rel, rte->relid); +} + +/* + * set_append_rel_pathlist + * Build access paths for an "append relation" + */ +void +set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, + Index rti, RangeTblEntry *rte, + PathKey *pathkeyAsc, PathKey *pathkeyDesc) +{ + Index parentRTindex = rti; + List *live_childrels = NIL; + List *subpaths = NIL; + bool subpaths_valid = true; + List *all_child_pathkeys = NIL; + List *all_child_outers = NIL; + ListCell *l; + + /* + * Generate access paths for each member relation, and remember the + * cheapest path for each one. Also, identify all pathkeys (orderings) + * and parameterizations (required_outer sets) available for the member + * relations. + */ + foreach(l, root->append_rel_list) + { + AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + Index childRTindex; + RangeTblEntry *childRTE; + RelOptInfo *childrel; + ListCell *lcp; + + /* append_rel_list contains all append rels; ignore others */ + if (appinfo->parent_relid != parentRTindex) + continue; + + /* Re-locate the child RTE and RelOptInfo */ + childRTindex = appinfo->child_relid; + childRTE = root->simple_rte_array[childRTindex]; + childrel = root->simple_rel_array[childRTindex]; + + /* + * Compute the child's access paths. + */ + if (childRTE->relkind == RELKIND_FOREIGN_TABLE) + { + set_foreign_size(root, childrel, childRTE); + set_foreign_pathlist(root, childrel, childRTE); + } + else + { + set_plain_rel_size(root, childrel, childRTE); + set_plain_rel_pathlist(root, childrel, childRTE); + } + set_cheapest(childrel); + + /* + * If child is dummy, ignore it. + */ + if (IS_DUMMY_REL(childrel)) + continue; + + /* + * Child is live, so add it to the live_childrels list for use below. + */ + live_childrels = lappend(live_childrels, childrel); + + /* + * If child has an unparameterized cheapest-total path, add that to + * the unparameterized Append path we are constructing for the parent. + * If not, there's no workable unparameterized path. + */ + if (childrel->cheapest_total_path->param_info == NULL) + subpaths = accumulate_append_subpath(subpaths, + childrel->cheapest_total_path); + else + subpaths_valid = false; + + /* + * Collect lists of all the available path orderings and + * parameterizations for all the children. We use these as a + * heuristic to indicate which sort orderings and parameterizations we + * should build Append and MergeAppend paths for. + */ + foreach(lcp, childrel->pathlist) + { + Path *childpath = (Path *) lfirst(lcp); + List *childkeys = childpath->pathkeys; + Relids childouter = PATH_REQ_OUTER(childpath); + + /* Unsorted paths don't contribute to pathkey list */ + if (childkeys != NIL) + { + ListCell *lpk; + bool found = false; + + /* Have we already seen this ordering? */ + foreach(lpk, all_child_pathkeys) + { + List *existing_pathkeys = (List *) lfirst(lpk); + + if (compare_pathkeys(existing_pathkeys, + childkeys) == PATHKEYS_EQUAL) + { + found = true; + break; + } + } + if (!found) + { + /* No, so add it to all_child_pathkeys */ + all_child_pathkeys = lappend(all_child_pathkeys, + childkeys); + } + } + + /* Unparameterized paths don't contribute to param-set list */ + if (childouter) + { + ListCell *lco; + bool found = false; + + /* Have we already seen this param set? */ + foreach(lco, all_child_outers) + { + Relids existing_outers = (Relids) lfirst(lco); + + if (bms_equal(existing_outers, childouter)) + { + found = true; + break; + } + } + if (!found) + { + /* No, so add it to all_child_outers */ + all_child_outers = lappend(all_child_outers, + childouter); + } + } + } + } + + /* + * If we found unparameterized paths for all children, build an unordered, + * unparameterized Append path for the rel. (Note: this is correct even + * if we have zero or one live subpath due to constraint exclusion.) + */ + if (subpaths_valid) + add_path(rel, + (Path *) create_append_path_compat(rel, subpaths, NULL, 0)); + + /* + * Also build unparameterized MergeAppend paths based on the collected + * list of child pathkeys. + */ + if (subpaths_valid) + generate_mergeappend_paths(root, rel, live_childrels, + all_child_pathkeys, pathkeyAsc, + pathkeyDesc); + + /* + * Build Append paths for each parameterization seen among the child rels. + * (This may look pretty expensive, but in most cases of practical + * interest, the child rels will expose mostly the same parameterizations, + * so that not that many cases actually get considered here.) + * + * The Append node itself cannot enforce quals, so all qual checking must + * be done in the child paths. This means that to have a parameterized + * Append path, we must have the exact same parameterization for each + * child path; otherwise some children might be failing to check the + * moved-down quals. To make them match up, we can try to increase the + * parameterization of lesser-parameterized paths. + */ + foreach(l, all_child_outers) + { + Relids required_outer = (Relids) lfirst(l); + ListCell *lcr; + + /* Select the child paths for an Append with this parameterization */ + subpaths = NIL; + subpaths_valid = true; + foreach(lcr, live_childrels) + { + RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr); + Path *subpath; + + subpath = get_cheapest_parameterized_child_path(root, + childrel, + required_outer); + if (subpath == NULL) + { + /* failed to make a suitable path for this child */ + subpaths_valid = false; + break; + } + subpaths = accumulate_append_subpath(subpaths, subpath); + } + + if (subpaths_valid) + add_path(rel, (Path *) + create_append_path_compat(rel, subpaths, required_outer, 0)); + } +} + +static List * +accumulate_append_subpath(List *subpaths, Path *path) +{ + return lappend(subpaths, path); +} + +/* + * get_cheapest_parameterized_child_path + * Get cheapest path for this relation that has exactly the requested + * parameterization. + * + * Returns NULL if unable to create such a path. + */ +static Path * +get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel, + Relids required_outer) +{ + Path *cheapest; + ListCell *lc; + + /* + * Look up the cheapest existing path with no more than the needed + * parameterization. If it has exactly the needed parameterization, we're + * done. + */ + cheapest = get_cheapest_path_for_pathkeys(rel->pathlist, + NIL, + required_outer, + TOTAL_COST); + Assert(cheapest != NULL); + if (bms_equal(PATH_REQ_OUTER(cheapest), required_outer)) + return cheapest; + + /* + * Otherwise, we can "reparameterize" an existing path to match the given + * parameterization, which effectively means pushing down additional + * joinquals to be checked within the path's scan. However, some existing + * paths might check the available joinquals already while others don't; + * therefore, it's not clear which existing path will be cheapest after + * reparameterization. We have to go through them all and find out. + */ + cheapest = NULL; + foreach(lc, rel->pathlist) + { + Path *path = (Path *) lfirst(lc); + + /* Can't use it if it needs more than requested parameterization */ + if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer)) + continue; + + /* + * Reparameterization can only increase the path's cost, so if it's + * already more expensive than the current cheapest, forget it. + */ + if (cheapest != NULL && + compare_path_costs(cheapest, path, TOTAL_COST) <= 0) + continue; + + /* Reparameterize if needed, then recheck cost */ + if (!bms_equal(PATH_REQ_OUTER(path), required_outer)) + { + path = reparameterize_path(root, path, required_outer, 1.0); + if (path == NULL) + continue; /* failed to reparameterize this one */ + Assert(bms_equal(PATH_REQ_OUTER(path), required_outer)); + + if (cheapest != NULL && + compare_path_costs(cheapest, path, TOTAL_COST) <= 0) + continue; + } + + /* We have a new best path */ + cheapest = path; + } + + /* Return the best path, or NULL if we found no suitable candidate */ + return cheapest; +} + +/* + * generate_mergeappend_paths + * Generate MergeAppend paths for an append relation + * + * Generate a path for each ordering (pathkey list) appearing in + * all_child_pathkeys. + * + * We consider both cheapest-startup and cheapest-total cases, ie, for each + * interesting ordering, collect all the cheapest startup subpaths and all the + * cheapest total paths, and build a MergeAppend path for each case. + * + * We don't currently generate any parameterized MergeAppend paths. While + * it would not take much more code here to do so, it's very unclear that it + * is worth the planning cycles to investigate such paths: there's little + * use for an ordered path on the inside of a nestloop. In fact, it's likely + * that the current coding of add_path would reject such paths out of hand, + * because add_path gives no credit for sort ordering of parameterized paths, + * and a parameterized MergeAppend is going to be more expensive than the + * corresponding parameterized Append path. If we ever try harder to support + * parameterized mergejoin plans, it might be worth adding support for + * parameterized MergeAppends to feed such joins. (See notes in + * optimizer/README for why that might not ever happen, though.) + */ +static void +generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, + List *live_childrels, + List *all_child_pathkeys, + PathKey *pathkeyAsc, PathKey *pathkeyDesc) +{ + ListCell *lcp; + + foreach(lcp, all_child_pathkeys) + { + List *pathkeys = (List *) lfirst(lcp); + List *startup_subpaths = NIL; + List *total_subpaths = NIL; + bool startup_neq_total = false; + bool presorted = true; + ListCell *lcr; + + /* Select the child paths for this ordering... */ + foreach(lcr, live_childrels) + { + RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr); + Path *cheapest_startup, + *cheapest_total; + + /* Locate the right paths, if they are available. */ + cheapest_startup = + get_cheapest_path_for_pathkeys(childrel->pathlist, + pathkeys, + NULL, + STARTUP_COST); + cheapest_total = + get_cheapest_path_for_pathkeys(childrel->pathlist, + pathkeys, + NULL, + TOTAL_COST); + + /* + * If we can't find any paths with the right order just use the + * cheapest-total path; we'll have to sort it later. + */ + if (cheapest_startup == NULL || cheapest_total == NULL) + { + cheapest_startup = cheapest_total = + childrel->cheapest_total_path; + /* Assert we do have an unparameterized path for this child */ + Assert(cheapest_total->param_info == NULL); + presorted = false; + } + + /* + * Notice whether we actually have different paths for the + * "cheapest" and "total" cases; frequently there will be no point + * in two create_merge_append_path() calls. + */ + if (cheapest_startup != cheapest_total) + startup_neq_total = true; + + startup_subpaths = + accumulate_append_subpath(startup_subpaths, cheapest_startup); + total_subpaths = + accumulate_append_subpath(total_subpaths, cheapest_total); + } + + /* + * When first pathkey matching ascending/descending sort by partition + * column then build path with Append node, because MergeAppend is not + * required in this case. + */ + if ((PathKey *) linitial(pathkeys) == pathkeyAsc && presorted) + { + Path *path; + + path = (Path *) create_append_path_compat(rel, startup_subpaths, + NULL, 0); + path->pathkeys = pathkeys; + add_path(rel, path); + + if (startup_neq_total) + { + path = (Path *) create_append_path_compat(rel, total_subpaths, + NULL, 0); + path->pathkeys = pathkeys; + add_path(rel, path); + } + } + else if ((PathKey *) linitial(pathkeys) == pathkeyDesc && presorted) + { + /* + * When pathkey is descending sort by partition column then we + * need to scan partitions in reversed order. + */ + Path *path; + + path = (Path *) create_append_path_compat(rel, + list_reverse(startup_subpaths), NULL, 0); + path->pathkeys = pathkeys; + add_path(rel, path); + + if (startup_neq_total) + { + path = (Path *) create_append_path_compat(rel, + list_reverse(total_subpaths), NULL, 0); + path->pathkeys = pathkeys; + add_path(rel, path); + } + } + else + { + /* ... and build the MergeAppend paths */ + add_path(rel, (Path *) create_merge_append_path(root, + rel, + startup_subpaths, + pathkeys, + NULL)); + if (startup_neq_total) + add_path(rel, (Path *) create_merge_append_path(root, + rel, + total_subpaths, + pathkeys, + NULL)); + } + } +} + +/* + * Get cached PATHMAN_CONFIG relation Oid. + */ +Oid +get_pathman_config_relid(void) +{ + return pathman_config_relid; +} + +/* + * Get cached PATHMAN_CONFIG_PARAMS relation Oid. + */ +Oid +get_pathman_config_params_relid(void) +{ + return pathman_config_params_relid; +} diff --git a/contrib/pg_pathman/src/pl_funcs.c b/contrib/pg_pathman/src/pl_funcs.c new file mode 100644 index 0000000000..a7c19b2e3b --- /dev/null +++ b/contrib/pg_pathman/src/pl_funcs.c @@ -0,0 +1,883 @@ +/* ------------------------------------------------------------------------ + * + * pl_funcs.c + * Utility C functions for stored procedures + * + * Copyright (c) 2015-2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "init.h" +#include "utils.h" +#include "pathman.h" +#include "relation_info.h" +#include "xact_handling.h" + +#include "access/htup_details.h" +#include "access/nbtree.h" +#include "catalog/indexing.h" +#include "catalog/pg_type.h" +#include "commands/tablespace.h" +#include "funcapi.h" +#include "miscadmin.h" +#include "utils/builtins.h" +#include "utils/inval.h" +#include "utils/jsonb.h" +#include "utils/snapmgr.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" + + +/* Function declarations */ + +PG_FUNCTION_INFO_V1( on_partitions_created ); +PG_FUNCTION_INFO_V1( on_partitions_updated ); +PG_FUNCTION_INFO_V1( on_partitions_removed ); + +PG_FUNCTION_INFO_V1( get_parent_of_partition_pl ); +PG_FUNCTION_INFO_V1( get_base_type_pl ); +PG_FUNCTION_INFO_V1( get_attribute_type_pl ); +PG_FUNCTION_INFO_V1( get_rel_tablespace_name ); + +PG_FUNCTION_INFO_V1( show_partition_list_internal ); + +PG_FUNCTION_INFO_V1( build_update_trigger_func_name ); +PG_FUNCTION_INFO_V1( build_update_trigger_name ); +PG_FUNCTION_INFO_V1( build_check_constraint_name_attnum ); +PG_FUNCTION_INFO_V1( build_check_constraint_name_attname ); + +PG_FUNCTION_INFO_V1( is_date_type ); +PG_FUNCTION_INFO_V1( is_attribute_nullable ); + +PG_FUNCTION_INFO_V1( add_to_pathman_config ); +PG_FUNCTION_INFO_V1( invalidate_relcache ); + +PG_FUNCTION_INFO_V1( lock_partitioned_relation ); +PG_FUNCTION_INFO_V1( prevent_relation_modification ); + +PG_FUNCTION_INFO_V1( validate_on_part_init_callback_pl ); +PG_FUNCTION_INFO_V1( invoke_on_partition_created_callback ); + +PG_FUNCTION_INFO_V1( debug_capture ); + + +/* + * User context for function show_partition_list_internal(). + */ +typedef struct +{ + Relation pathman_config; + HeapScanDesc pathman_config_scan; + Snapshot snapshot; + + const PartRelationInfo *current_prel; /* selected PartRelationInfo */ + + uint32 child_number; /* child we're looking at */ +} show_partition_list_cxt; + + +static void on_partitions_created_internal(Oid partitioned_table, bool add_callbacks); +static void on_partitions_updated_internal(Oid partitioned_table, bool add_callbacks); +static void on_partitions_removed_internal(Oid partitioned_table, bool add_callbacks); + + +/* + * Extracted common check. + */ +static bool +check_relation_exists(Oid relid) +{ + return get_rel_type_id(relid) != InvalidOid; +} + + +/* + * ---------------------------- + * Partition events callbacks + * ---------------------------- + */ + +static void +on_partitions_created_internal(Oid partitioned_table, bool add_callbacks) +{ + elog(DEBUG2, "on_partitions_created() [add_callbacks = %s] " + "triggered for relation %u", + (add_callbacks ? "true" : "false"), partitioned_table); +} + +static void +on_partitions_updated_internal(Oid partitioned_table, bool add_callbacks) +{ + bool entry_found; + + elog(DEBUG2, "on_partitions_updated() [add_callbacks = %s] " + "triggered for relation %u", + (add_callbacks ? "true" : "false"), partitioned_table); + + invalidate_pathman_relation_info(partitioned_table, &entry_found); +} + +static void +on_partitions_removed_internal(Oid partitioned_table, bool add_callbacks) +{ + elog(DEBUG2, "on_partitions_removed() [add_callbacks = %s] " + "triggered for relation %u", + (add_callbacks ? "true" : "false"), partitioned_table); +} + + +Datum +on_partitions_created(PG_FUNCTION_ARGS) +{ + on_partitions_created_internal(PG_GETARG_OID(0), true); + PG_RETURN_NULL(); +} + +Datum +on_partitions_updated(PG_FUNCTION_ARGS) +{ + on_partitions_updated_internal(PG_GETARG_OID(0), true); + PG_RETURN_NULL(); +} + +Datum +on_partitions_removed(PG_FUNCTION_ARGS) +{ + on_partitions_removed_internal(PG_GETARG_OID(0), true); + PG_RETURN_NULL(); +} + + +/* + * ------------------------ + * Various useful getters + * ------------------------ + */ + +/* + * Get parent of a specified partition. + */ +Datum +get_parent_of_partition_pl(PG_FUNCTION_ARGS) +{ + Oid partition = PG_GETARG_OID(0); + PartParentSearch parent_search; + Oid parent; + + /* Fetch parent & write down search status */ + parent = get_parent_of_partition(partition, &parent_search); + + /* We MUST be sure :) */ + Assert(parent_search != PPS_NOT_SURE); + + /* It must be parent known by pg_pathman */ + if (parent_search == PPS_ENTRY_PART_PARENT) + PG_RETURN_OID(parent); + else + { + elog(ERROR, "\"%s\" is not a partition", + get_rel_name_or_relid(partition)); + + PG_RETURN_NULL(); + } +} + +/* + * Extract basic type of a domain. + */ +Datum +get_base_type_pl(PG_FUNCTION_ARGS) +{ + PG_RETURN_OID(getBaseType(PG_GETARG_OID(0))); +} + +/* + * Get type (as REGTYPE) of a given attribute. + */ +Datum +get_attribute_type_pl(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + text *attname = PG_GETARG_TEXT_P(1); + Oid result; + HeapTuple tp; + + /* NOTE: for now it's the most efficient way */ + tp = SearchSysCacheAttName(relid, text_to_cstring(attname)); + if (HeapTupleIsValid(tp)) + { + Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + result = att_tup->atttypid; + ReleaseSysCache(tp); + + PG_RETURN_OID(result); + } + else + elog(ERROR, "Cannot find type name for attribute \"%s\" " + "of relation \"%s\"", + text_to_cstring(attname), get_rel_name_or_relid(relid)); + + PG_RETURN_NULL(); /* keep compiler happy */ +} + +/* + * Return tablespace name for specified relation + */ +Datum +get_rel_tablespace_name(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + Oid tablespace_id; + char *result; + + tablespace_id = get_rel_tablespace(relid); + + /* If tablespace id is InvalidOid then use the default tablespace */ + if (!OidIsValid(tablespace_id)) + { + tablespace_id = GetDefaultTablespace(get_rel_persistence(relid)); + + /* If tablespace is still invalid then use database's default */ + if (!OidIsValid(tablespace_id)) + tablespace_id = MyDatabaseTableSpace; + } + + result = get_tablespace_name(tablespace_id); + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + + +/* + * ---------------------- + * Common purpose VIEWs + * ---------------------- + */ + +/* + * List all existing partitions and their parents. + */ +Datum +show_partition_list_internal(PG_FUNCTION_ARGS) +{ + show_partition_list_cxt *usercxt; + FuncCallContext *funccxt; + + /* + * Initialize tuple descriptor & function call context. + */ + if (SRF_IS_FIRSTCALL()) + { + TupleDesc tupdesc; + MemoryContext old_mcxt; + + funccxt = SRF_FIRSTCALL_INIT(); + + old_mcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx); + + usercxt = (show_partition_list_cxt *) palloc(sizeof(show_partition_list_cxt)); + + /* Open PATHMAN_CONFIG with latest snapshot available */ + usercxt->pathman_config = heap_open(get_pathman_config_relid(), + AccessShareLock); + usercxt->snapshot = RegisterSnapshot(GetLatestSnapshot()); + usercxt->pathman_config_scan = heap_beginscan(usercxt->pathman_config, + usercxt->snapshot, 0, NULL); + + usercxt->current_prel = NULL; + + /* Create tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(Natts_pathman_partition_list, false); + + TupleDescInitEntry(tupdesc, Anum_pathman_pl_parent, + "parent", REGCLASSOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_pl_partition, + "partition", REGCLASSOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_pl_parttype, + "parttype", INT4OID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_pl_partattr, + "partattr", TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_pl_range_min, + "range_min", TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, Anum_pathman_pl_range_max, + "range_max", TEXTOID, -1, 0); + + funccxt->tuple_desc = BlessTupleDesc(tupdesc); + funccxt->user_fctx = (void *) usercxt; + + MemoryContextSwitchTo(old_mcxt); + } + + funccxt = SRF_PERCALL_SETUP(); + usercxt = (show_partition_list_cxt *) funccxt->user_fctx; + + /* Iterate through pathman cache */ + for(;;) + { + const PartRelationInfo *prel; + HeapTuple htup; + Datum values[Natts_pathman_partition_list]; + bool isnull[Natts_pathman_partition_list] = { 0 }; + char *partattr_cstr; + + /* Fetch next PartRelationInfo if needed */ + if (usercxt->current_prel == NULL) + { + HeapTuple pathman_config_htup; + Datum parent_table; + bool parent_table_isnull; + Oid parent_table_oid; + + pathman_config_htup = heap_getnext(usercxt->pathman_config_scan, + ForwardScanDirection); + if (!HeapTupleIsValid(pathman_config_htup)) + break; + + parent_table = heap_getattr(pathman_config_htup, + Anum_pathman_config_partrel, + RelationGetDescr(usercxt->pathman_config), + &parent_table_isnull); + + Assert(parent_table_isnull == false); + parent_table_oid = DatumGetObjectId(parent_table); + + usercxt->current_prel = get_pathman_relation_info(parent_table_oid); + if (usercxt->current_prel == NULL) + continue; + + usercxt->child_number = 0; + } + + /* Alias to 'usercxt->current_prel' */ + prel = usercxt->current_prel; + + /* If we've run out of partitions, switch to the next 'prel' */ + if (usercxt->child_number >= PrelChildrenCount(prel)) + { + usercxt->current_prel = NULL; + usercxt->child_number = 0; + + continue; + } + + partattr_cstr = get_attname(PrelParentRelid(prel), prel->attnum); + if (!partattr_cstr) + { + /* Parent does not exist, go to the next 'prel' */ + usercxt->current_prel = NULL; + continue; + } + + /* Fill in common values */ + values[Anum_pathman_pl_parent - 1] = PrelParentRelid(prel); + values[Anum_pathman_pl_parttype - 1] = prel->parttype; + values[Anum_pathman_pl_partattr - 1] = CStringGetTextDatum(partattr_cstr); + + switch (prel->parttype) + { + case PT_HASH: + { + Oid *children = PrelGetChildrenArray(prel), + child_oid = children[usercxt->child_number]; + + values[Anum_pathman_pl_partition - 1] = child_oid; + isnull[Anum_pathman_pl_range_min - 1] = true; + isnull[Anum_pathman_pl_range_max - 1] = true; + } + break; + + case PT_RANGE: + { + RangeEntry *re; + Datum rmin, + rmax; + + re = &PrelGetRangesArray(prel)[usercxt->child_number]; + + rmin = CStringGetTextDatum(datum_to_cstring(re->min, + prel->atttype)); + rmax = CStringGetTextDatum(datum_to_cstring(re->max, + prel->atttype)); + + values[Anum_pathman_pl_partition - 1] = re->child_oid; + values[Anum_pathman_pl_range_min - 1] = rmin; + values[Anum_pathman_pl_range_max - 1] = rmax; + } + break; + + default: + elog(ERROR, "Unknown partitioning type %u", prel->parttype); + } + + /* Switch to the next child */ + usercxt->child_number++; + + /* Form output tuple */ + htup = heap_form_tuple(funccxt->tuple_desc, values, isnull); + + SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(htup)); + } + + /* Clean resources */ + heap_endscan(usercxt->pathman_config_scan); + UnregisterSnapshot(usercxt->snapshot); + heap_close(usercxt->pathman_config, AccessShareLock); + + SRF_RETURN_DONE(funccxt); +} + + +/* + * -------- + * Traits + * -------- + */ + +Datum +is_date_type(PG_FUNCTION_ARGS) +{ + PG_RETURN_BOOL(is_date_type_internal(PG_GETARG_OID(0))); +} + +Datum +is_attribute_nullable(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + text *attname = PG_GETARG_TEXT_P(1); + bool result = true; + HeapTuple tp; + + tp = SearchSysCacheAttName(relid, text_to_cstring(attname)); + if (HeapTupleIsValid(tp)) + { + Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); + result = !att_tup->attnotnull; + ReleaseSysCache(tp); + } + else + elog(ERROR, "Cannot find type name for attribute \"%s\" " + "of relation \"%s\"", + text_to_cstring(attname), get_rel_name_or_relid(relid)); + + PG_RETURN_BOOL(result); /* keep compiler happy */ +} + + +/* + * ------------------------ + * Useful string builders + * ------------------------ + */ + +Datum +build_update_trigger_func_name(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0), + nspid; + const char *result; + + /* Check that relation exists */ + if (!check_relation_exists(relid)) + elog(ERROR, "Invalid relation %u", relid); + + nspid = get_rel_namespace(relid); + result = psprintf("%s.%s", + quote_identifier(get_namespace_name(nspid)), + quote_identifier(psprintf("%s_upd_trig_func", + get_rel_name(relid)))); + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + +Datum +build_update_trigger_name(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + const char *result; /* trigger's name can't be qualified */ + + /* Check that relation exists */ + if (!check_relation_exists(relid)) + elog(ERROR, "Invalid relation %u", relid); + + result = quote_identifier(psprintf("%s_upd_trig", get_rel_name(relid))); + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} + +Datum +build_check_constraint_name_attnum(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + AttrNumber attnum = PG_GETARG_INT16(1); + const char *result; + + if (!check_relation_exists(relid)) + elog(ERROR, "Invalid relation %u", relid); + + /* We explicitly do not support system attributes */ + if (attnum == InvalidAttrNumber || attnum < 0) + elog(ERROR, "Cannot build check constraint name: " + "invalid attribute number %i", attnum); + + result = build_check_constraint_name_internal(relid, attnum); + + PG_RETURN_TEXT_P(cstring_to_text(quote_identifier(result))); +} + +Datum +build_check_constraint_name_attname(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + text *attname = PG_GETARG_TEXT_P(1); + AttrNumber attnum = get_attnum(relid, text_to_cstring(attname)); + const char *result; + + if (!check_relation_exists(relid)) + elog(ERROR, "Invalid relation %u", relid); + + if (attnum == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column '%s'", + get_rel_name_or_relid(relid), text_to_cstring(attname)); + + result = build_check_constraint_name_internal(relid, attnum); + + PG_RETURN_TEXT_P(cstring_to_text(quote_identifier(result))); +} + + +/* + * ------------------------ + * Cache & config updates + * ------------------------ + */ + +/* + * Try to add previously partitioned table to PATHMAN_CONFIG. + */ +Datum +add_to_pathman_config(PG_FUNCTION_ARGS) +{ + Oid relid; + text *attname; + PartType parttype; + + Relation pathman_config; + Datum values[Natts_pathman_config]; + bool isnull[Natts_pathman_config]; + HeapTuple htup; + CatalogIndexState indstate; + + PathmanInitState init_state; + MemoryContext old_mcxt = CurrentMemoryContext; + + if (PG_ARGISNULL(0)) + elog(ERROR, "parent_relid should not be null"); + + if (PG_ARGISNULL(1)) + elog(ERROR, "attname should not be null"); + + /* Read parameters */ + relid = PG_GETARG_OID(0); + attname = PG_GETARG_TEXT_P(1); + + /* Check that relation exists */ + if (!check_relation_exists(relid)) + elog(ERROR, "Invalid relation %u", relid); + + if (get_attnum(relid, text_to_cstring(attname)) == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column '%s'", + get_rel_name_or_relid(relid), text_to_cstring(attname)); + + /* Select partitioning type using 'range_interval' */ + parttype = PG_ARGISNULL(2) ? PT_HASH : PT_RANGE; + + /* + * Initialize columns (partrel, attname, parttype, range_interval). + */ + values[Anum_pathman_config_partrel - 1] = ObjectIdGetDatum(relid); + isnull[Anum_pathman_config_partrel - 1] = false; + + values[Anum_pathman_config_attname - 1] = PointerGetDatum(attname); + isnull[Anum_pathman_config_attname - 1] = false; + + values[Anum_pathman_config_parttype - 1] = Int32GetDatum(parttype); + isnull[Anum_pathman_config_parttype - 1] = false; + + values[Anum_pathman_config_range_interval - 1] = PG_GETARG_DATUM(2); + isnull[Anum_pathman_config_range_interval - 1] = PG_ARGISNULL(2); + + /* Insert new row into PATHMAN_CONFIG */ + pathman_config = heap_open(get_pathman_config_relid(), RowExclusiveLock); + htup = heap_form_tuple(RelationGetDescr(pathman_config), values, isnull); + simple_heap_insert(pathman_config, htup); + indstate = CatalogOpenIndexes(pathman_config); + CatalogIndexInsert(indstate, htup); + CatalogCloseIndexes(indstate); + heap_close(pathman_config, RowExclusiveLock); + + /* Now try to create a PartRelationInfo */ + PG_TRY(); + { + /* Some flags might change during refresh attempt */ + save_pathman_init_state(&init_state); + + refresh_pathman_relation_info(relid, parttype, text_to_cstring(attname)); + } + PG_CATCH(); + { + ErrorData *edata; + + /* Switch to the original context & copy edata */ + MemoryContextSwitchTo(old_mcxt); + edata = CopyErrorData(); + FlushErrorState(); + + /* We have to restore all changed flags */ + restore_pathman_init_state(&init_state); + + /* Show error message */ + elog(ERROR, "%s", edata->message); + + FreeErrorData(edata); + } + PG_END_TRY(); + + PG_RETURN_BOOL(true); +} + + +/* + * Invalidate relcache for a specified relation. + */ +Datum +invalidate_relcache(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + if (check_relation_exists(relid)) + CacheInvalidateRelcacheByRelid(relid); + + PG_RETURN_VOID(); +} + + +/* + * -------------------------- + * Special locking routines + * -------------------------- + */ + +/* + * Acquire appropriate lock on a partitioned relation. + */ +Datum +lock_partitioned_relation(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + /* Lock partitioned relation till transaction's end */ + xact_lock_partitioned_rel(relid, false); + + PG_RETURN_VOID(); +} + +/* + * Lock relation exclusively & check for current isolation level. + */ +Datum +prevent_relation_modification(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + + /* + * Check that isolation level is READ COMMITTED. + * Else we won't be able to see new rows + * which could slip through locks. + */ + if (!xact_is_level_read_committed()) + ereport(ERROR, + (errmsg("Cannot perform blocking partitioning operation"), + errdetail("Expected READ COMMITTED isolation level"))); + + /* + * Check if table is being modified + * concurrently in a separate transaction. + */ + if (!xact_lock_rel_exclusive(relid, true)) + ereport(ERROR, + (errmsg("Cannot perform blocking partitioning operation"), + errdetail("Table \"%s\" is being modified concurrently", + get_rel_name_or_relid(relid)))); + + PG_RETURN_VOID(); +} + + +/* + * ------------------------------------------- + * User-defined partition creation callbacks + * ------------------------------------------- + */ + +/* + * Checks that callback function meets specific requirements. + * It must have the only JSONB argument and BOOL return type. + */ +Datum +validate_on_part_init_callback_pl(PG_FUNCTION_ARGS) +{ + validate_on_part_init_cb(PG_GETARG_OID(0), true); + + PG_RETURN_VOID(); +} + +/* + * Builds JSONB object containing new partition parameters + * and invokes the callback. + */ +Datum +invoke_on_partition_created_callback(PG_FUNCTION_ARGS) +{ +#define JSB_INIT_VAL(value, val_type, val_cstring) \ + do { \ + (value)->type = jbvString; \ + (value)->val.string.len = strlen(val_cstring); \ + (value)->val.string.val = val_cstring; \ + pushJsonbValue(&jsonb_state, val_type, (value)); \ + } while (0) + +#define ARG_PARENT 0 /* parent table */ +#define ARG_CHILD 1 /* partition */ +#define ARG_CALLBACK 2 /* callback to be invoked */ +#define ARG_RANGE_START 3 /* start_value */ +#define ARG_RANGE_END 4 /* end_value */ + + Oid parent_oid = PG_GETARG_OID(ARG_PARENT), + partition_oid = PG_GETARG_OID(ARG_CHILD); + PartType part_type; + + Oid cb_oid = PG_GETARG_OID(ARG_CALLBACK); + FmgrInfo cb_flinfo; + FunctionCallInfoData cb_fcinfo; + + JsonbParseState *jsonb_state = NULL; + JsonbValue *result, + key, + val; + + /* If there's no callback function specified, we're done */ + if (cb_oid == InvalidOid) + PG_RETURN_VOID(); + + if (PG_ARGISNULL(ARG_PARENT)) + elog(ERROR, "parent_relid should not be null"); + + if (PG_ARGISNULL(ARG_CHILD)) + elog(ERROR, "partition should not be null"); + + switch (PG_NARGS()) + { + case 3: + part_type = PT_HASH; + break; + + case 5: + { + if (PG_ARGISNULL(ARG_RANGE_START) || PG_ARGISNULL(ARG_RANGE_START)) + elog(ERROR, "both bounds must be provided for RANGE partition"); + + part_type = PT_RANGE; + } + break; + + default: + elog(ERROR, "error in function \"%s\"", + CppAsString(invoke_on_partition_created_callback)); + } + + /* Build JSONB according to partitioning type */ + switch (part_type) + { + case PT_HASH: + { + pushJsonbValue(&jsonb_state, WJB_BEGIN_OBJECT, NULL); + + JSB_INIT_VAL(&key, WJB_KEY, "parent"); + JSB_INIT_VAL(&val, WJB_VALUE, get_rel_name_or_relid(parent_oid)); + JSB_INIT_VAL(&key, WJB_KEY, "partition"); + JSB_INIT_VAL(&val, WJB_VALUE, get_rel_name_or_relid(partition_oid)); + JSB_INIT_VAL(&key, WJB_KEY, "parttype"); + JSB_INIT_VAL(&val, WJB_VALUE, PartTypeToCString(PT_HASH)); + + result = pushJsonbValue(&jsonb_state, WJB_END_OBJECT, NULL); + } + break; + + case PT_RANGE: + { + char *start_value, + *end_value; + Oid type = get_fn_expr_argtype(fcinfo->flinfo, ARG_RANGE_START); + + /* Convert min & max to CSTRING */ + start_value = datum_to_cstring(PG_GETARG_DATUM(ARG_RANGE_START), type); + end_value = datum_to_cstring(PG_GETARG_DATUM(ARG_RANGE_END), type); + + pushJsonbValue(&jsonb_state, WJB_BEGIN_OBJECT, NULL); + + JSB_INIT_VAL(&key, WJB_KEY, "parent"); + JSB_INIT_VAL(&val, WJB_VALUE, get_rel_name_or_relid(parent_oid)); + JSB_INIT_VAL(&key, WJB_KEY, "partition"); + JSB_INIT_VAL(&val, WJB_VALUE, get_rel_name_or_relid(partition_oid)); + JSB_INIT_VAL(&key, WJB_KEY, "parttype"); + JSB_INIT_VAL(&val, WJB_VALUE, PartTypeToCString(PT_RANGE)); + JSB_INIT_VAL(&key, WJB_KEY, "range_min"); + JSB_INIT_VAL(&val, WJB_VALUE, start_value); + JSB_INIT_VAL(&key, WJB_KEY, "range_max"); + JSB_INIT_VAL(&val, WJB_VALUE, end_value); + + result = pushJsonbValue(&jsonb_state, WJB_END_OBJECT, NULL); + } + break; + + default: + elog(ERROR, "Unknown partitioning type %u", part_type); + break; + } + + /* Validate the callback's signature */ + validate_on_part_init_cb(cb_oid, true); + + fmgr_info(cb_oid, &cb_flinfo); + + InitFunctionCallInfoData(cb_fcinfo, &cb_flinfo, 1, InvalidOid, NULL, NULL); + cb_fcinfo.arg[0] = PointerGetDatum(JsonbValueToJsonb(result)); + cb_fcinfo.argnull[0] = false; + + /* Invoke the callback */ + FunctionCallInvoke(&cb_fcinfo); + + PG_RETURN_VOID(); +} + + +/* + * ------- + * DEBUG + * ------- + */ + +/* + * NOTE: used for DEBUG, set breakpoint here. + */ +Datum +debug_capture(PG_FUNCTION_ARGS) +{ + static float8 sleep_time = 0; + DirectFunctionCall1(pg_sleep, Float8GetDatum(sleep_time)); + + /* Write something (doesn't really matter) */ + elog(WARNING, "debug_capture [%u]", MyProcPid); + + PG_RETURN_VOID(); +} diff --git a/contrib/pg_pathman/src/pl_hash_funcs.c b/contrib/pg_pathman/src/pl_hash_funcs.c new file mode 100644 index 0000000000..6dc0916fbb --- /dev/null +++ b/contrib/pg_pathman/src/pl_hash_funcs.c @@ -0,0 +1,46 @@ +/* ------------------------------------------------------------------------ + * + * pl_hash_funcs.c + * Utility C functions for stored HASH procedures + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "pathman.h" + +#include "utils/typcache.h" + + +/* Function declarations */ + +PG_FUNCTION_INFO_V1( get_type_hash_func ); +PG_FUNCTION_INFO_V1( get_hash_part_idx ); + + +/* + * Returns hash function's OID for a specified type. + */ +Datum +get_type_hash_func(PG_FUNCTION_ARGS) +{ + TypeCacheEntry *tce; + Oid type_oid = PG_GETARG_OID(0); + + tce = lookup_type_cache(type_oid, TYPECACHE_HASH_PROC); + + PG_RETURN_OID(tce->hash_proc); +} + +/* + * Wrapper for hash_to_part_index(). + */ +Datum +get_hash_part_idx(PG_FUNCTION_ARGS) +{ + uint32 value = PG_GETARG_UINT32(0), + part_count = PG_GETARG_UINT32(1); + + PG_RETURN_UINT32(hash_to_part_index(value, part_count)); +} diff --git a/contrib/pg_pathman/src/pl_range_funcs.c b/contrib/pg_pathman/src/pl_range_funcs.c new file mode 100644 index 0000000000..bd71ce0979 --- /dev/null +++ b/contrib/pg_pathman/src/pl_range_funcs.c @@ -0,0 +1,278 @@ +/* ------------------------------------------------------------------------ + * + * pl_range_funcs.c + * Utility C functions for stored RANGE procedures + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "pathman.h" +#include "relation_info.h" +#include "utils.h" + +#include "utils/array.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" + + +/* Function declarations */ + +PG_FUNCTION_INFO_V1( find_or_create_range_partition); +PG_FUNCTION_INFO_V1( check_overlap ); + +PG_FUNCTION_INFO_V1( get_part_range_by_oid ); +PG_FUNCTION_INFO_V1( get_part_range_by_idx ); + +PG_FUNCTION_INFO_V1( build_range_condition ); + + +/* + * ----------------------------- + * Partition creation & checks + * ----------------------------- + */ + +/* + * Returns partition oid for specified parent relid and value. + * In case when partition doesn't exist try to create one. + */ +Datum +find_or_create_range_partition(PG_FUNCTION_ARGS) +{ + Oid parent_oid = PG_GETARG_OID(0); + Datum value = PG_GETARG_DATUM(1); + Oid value_type = get_fn_expr_argtype(fcinfo->flinfo, 1); + const PartRelationInfo *prel; + FmgrInfo cmp_func; + RangeEntry found_rentry; + search_rangerel_result search_state; + + prel = get_pathman_relation_info(parent_oid); + shout_if_prel_is_invalid(parent_oid, prel, PT_RANGE); + + fill_type_cmp_fmgr_info(&cmp_func, + getBaseType(value_type), + getBaseType(prel->atttype)); + + /* Use available PartRelationInfo to find partition */ + search_state = search_range_partition_eq(value, &cmp_func, prel, + &found_rentry); + + /* + * If found then just return oid, else create new partitions + */ + if (search_state == SEARCH_RANGEREL_FOUND) + PG_RETURN_OID(found_rentry.child_oid); + /* + * If not found and value is between first and last partitions + */ + else if (search_state == SEARCH_RANGEREL_GAP) + PG_RETURN_NULL(); + else + { + Oid child_oid = create_partitions(parent_oid, value, value_type); + + /* get_pathman_relation_info() will refresh this entry */ + invalidate_pathman_relation_info(parent_oid, NULL); + + PG_RETURN_OID(child_oid); + } +} + +/* + * Checks if range overlaps with existing partitions. + * Returns TRUE if overlaps and FALSE otherwise. + */ +Datum +check_overlap(PG_FUNCTION_ARGS) +{ + Oid parent_oid = PG_GETARG_OID(0); + + Datum p1 = PG_GETARG_DATUM(1), + p2 = PG_GETARG_DATUM(2); + + Oid p1_type = get_fn_expr_argtype(fcinfo->flinfo, 1), + p2_type = get_fn_expr_argtype(fcinfo->flinfo, 2), + part_type; + + FmgrInfo cmp_func_1, + cmp_func_2; + + uint32 i; + RangeEntry *ranges; + const PartRelationInfo *prel; + + prel = get_pathman_relation_info(parent_oid); + shout_if_prel_is_invalid(parent_oid, prel, PT_RANGE); + + part_type = getBaseType(prel->atttype); + + /* Fetch comparison functions */ + fill_type_cmp_fmgr_info(&cmp_func_1, getBaseType(p1_type), part_type); + fill_type_cmp_fmgr_info(&cmp_func_2, getBaseType(p2_type), part_type); + + ranges = PrelGetRangesArray(prel); + for (i = 0; i < PrelChildrenCount(prel); i++) + { + int c1 = FunctionCall2(&cmp_func_1, p1, ranges[i].max); + int c2 = FunctionCall2(&cmp_func_2, p2, ranges[i].min); + + if (c1 < 0 && c2 > 0) + PG_RETURN_BOOL(true); + } + + PG_RETURN_BOOL(false); +} + + +/* + * ------------------------ + * Various useful getters + * ------------------------ + */ + +/* + * Returns range entry (min, max) (in form of array). + * + * arg #1 is the parent's Oid. + * arg #2 is the partition's Oid. + */ +Datum +get_part_range_by_oid(PG_FUNCTION_ARGS) +{ + Oid partition_relid = InvalidOid, + parent_relid; + PartParentSearch parent_search; + uint32 i; + RangeEntry *ranges; + const PartRelationInfo *prel; + + if (PG_ARGISNULL(0)) + elog(ERROR, "'partition_relid' should not be NULL"); + else + partition_relid = PG_GETARG_OID(0); + + parent_relid = get_parent_of_partition(partition_relid, &parent_search); + if (parent_search != PPS_ENTRY_PART_PARENT) + elog(ERROR, "relation \"%s\" is not a partition", + get_rel_name_or_relid(partition_relid)); + + prel = get_pathman_relation_info(parent_relid); + shout_if_prel_is_invalid(parent_relid, prel, PT_RANGE); + + ranges = PrelGetRangesArray(prel); + + /* Look for the specified partition */ + for (i = 0; i < PrelChildrenCount(prel); i++) + if (ranges[i].child_oid == partition_relid) + { + ArrayType *arr; + Datum elems[2] = { ranges[i].min, ranges[i].max }; + + arr = construct_array(elems, 2, prel->atttype, + prel->attlen, prel->attbyval, + prel->attalign); + + PG_RETURN_ARRAYTYPE_P(arr); + } + + /* No partition found, report error */ + elog(ERROR, "relation \"%s\" has no partition \"%s\"", + get_rel_name_or_relid(parent_relid), + get_rel_name_or_relid(partition_relid)); + + PG_RETURN_NULL(); /* keep compiler happy */ +} + +/* + * Returns N-th range entry (min, max) (in form of array). + * + * arg #1 is the parent's Oid. + * arg #2 is the index of the range + * (if it is negative then the last range will be returned). + */ +Datum +get_part_range_by_idx(PG_FUNCTION_ARGS) +{ + Oid parent_relid = InvalidOid; + int partition_idx = 0; + Datum elems[2]; + RangeEntry *ranges; + const PartRelationInfo *prel; + + if (PG_ARGISNULL(0)) + elog(ERROR, "'parent_relid' should not be NULL"); + else + parent_relid = PG_GETARG_OID(0); + + if (PG_ARGISNULL(1)) + elog(ERROR, "'partition_idx' should not be NULL"); + else + partition_idx = PG_GETARG_INT32(1); + + prel = get_pathman_relation_info(parent_relid); + shout_if_prel_is_invalid(parent_relid, prel, PT_RANGE); + + /* Now we have to deal with 'idx' */ + if (partition_idx < -1) + { + elog(ERROR, "negative indices other than -1 (last partition) are not allowed"); + } + else if (partition_idx == -1) + { + partition_idx = PrelLastChild(prel); + } + else if (((uint32) abs(partition_idx)) >= PrelChildrenCount(prel)) + { + elog(ERROR, "partition #%d does not exist (total amount is %u)", + partition_idx, PrelChildrenCount(prel)); + } + + ranges = PrelGetRangesArray(prel); + + elems[0] = ranges[partition_idx].min; + elems[1] = ranges[partition_idx].max; + + PG_RETURN_ARRAYTYPE_P(construct_array(elems, 2, + prel->atttype, + prel->attlen, + prel->attbyval, + prel->attalign)); +} + + +/* + * ------------------------ + * Useful string builders + * ------------------------ + */ + +/* Build range condition for a CHECK CONSTRAINT. */ +Datum +build_range_condition(PG_FUNCTION_ARGS) +{ + text *attname = PG_GETARG_TEXT_P(0); + + Datum min_bound = PG_GETARG_DATUM(1), + max_bound = PG_GETARG_DATUM(2); + + Oid min_bound_type = get_fn_expr_argtype(fcinfo->flinfo, 1), + max_bound_type = get_fn_expr_argtype(fcinfo->flinfo, 2); + + char *result; + + /* This is not going to trigger (not now, at least), just for the safety */ + if (min_bound_type != max_bound_type) + elog(ERROR, "cannot build range condition: " + "boundaries should be of the same type"); + + /* Create range condition CSTRING */ + result = psprintf("%1$s >= '%2$s' AND %1$s < '%3$s'", + text_to_cstring(attname), + datum_to_cstring(min_bound, min_bound_type), + datum_to_cstring(max_bound, max_bound_type)); + + PG_RETURN_TEXT_P(cstring_to_text(result)); +} diff --git a/contrib/pg_pathman/rangeset.c b/contrib/pg_pathman/src/rangeset.c similarity index 65% rename from contrib/pg_pathman/rangeset.c rename to contrib/pg_pathman/src/rangeset.c index cfc6c7072d..beff56de32 100644 --- a/contrib/pg_pathman/rangeset.c +++ b/contrib/pg_pathman/src/rangeset.c @@ -1,69 +1,49 @@ /* ------------------------------------------------------------------------ * * rangeset.c - * Index range functions + * IndexRange functions * * Copyright (c) 2015-2016, Postgres Professional * * ------------------------------------------------------------------------ */ -#include "pathman.h" + +#include "rangeset.h" /* Check if two ranges are intersecting */ bool irange_intersects(IndexRange a, IndexRange b) { - return (irange_lower(a) <= irange_upper(b)) && - (irange_lower(b) <= irange_upper(a)); + return (a.ir_lower <= b.ir_upper) && + (b.ir_lower <= a.ir_upper); } /* Check if two ranges are conjuncted */ bool irange_conjuncted(IndexRange a, IndexRange b) { - return (irange_lower(a) - 1 <= irange_upper(b)) && - (irange_lower(b) - 1 <= irange_upper(a)); + return (a.ir_lower - 1 <= b.ir_upper) && + (b.ir_lower - 1 <= a.ir_upper); } /* Make union of two ranges. They should have the same lossiness. */ IndexRange irange_union(IndexRange a, IndexRange b) { - Assert(irange_is_lossy(a) == irange_is_lossy(b)); - return make_irange(Min(irange_lower(a), irange_lower(b)), - Max(irange_upper(a), irange_upper(b)), - irange_is_lossy(a)); + Assert(a.ir_lossy == b.ir_lossy); + return make_irange(Min(a.ir_lower, b.ir_lower), + Max(a.ir_upper, b.ir_upper), + a.ir_lossy); } /* Get intersection of two ranges */ IndexRange irange_intersect(IndexRange a, IndexRange b) { - return make_irange(Max(irange_lower(a), irange_lower(b)), - Min(irange_upper(a), irange_upper(b)), - irange_is_lossy(a) || irange_is_lossy(b)); -} - -#ifdef NOT_USED -/* Print range list in debug purposes */ -static char * -print_irange(List *l) -{ - ListCell *c; - StringInfoData str; - - initStringInfo(&str); - - foreach (c, l) - { - IndexRange ir = lfirst_irange(c); - - appendStringInfo(&str, "[%d,%d]%c ", irange_lower(ir), irange_upper(ir), - irange_is_lossy(ir) ? 'l' : 'e'); - } - return str.data; + return make_irange(Max(a.ir_lower, b.ir_lower), + Min(a.ir_upper, b.ir_upper), + a.ir_lossy || b.ir_lossy); } -#endif /* * Make union of two index rage lists. @@ -74,7 +54,7 @@ irange_list_union(List *a, List *b) ListCell *ca, *cb; List *result = NIL; - IndexRange cur = 0; + IndexRange cur = InvalidIndexRange; bool have_cur = false; ca = list_head(a); @@ -82,12 +62,12 @@ irange_list_union(List *a, List *b) while (ca || cb) { - IndexRange next = 0; + IndexRange next = InvalidIndexRange; /* Fetch next range with lesser lower bound */ if (ca && cb) { - if (irange_lower(lfirst_irange(ca)) <= irange_lower(lfirst_irange(cb))) + if (lfirst_irange(ca).ir_lower <= lfirst_irange(cb).ir_lower) { next = lfirst_irange(ca); ca = lnext(ca); @@ -122,25 +102,25 @@ irange_list_union(List *a, List *b) /* * Ranges are conjuncted, try to unify them. */ - if (irange_is_lossy(next) == irange_is_lossy(cur)) + if (next.ir_lossy == cur.ir_lossy) { cur = irange_union(next, cur); } else { - if (!irange_is_lossy(cur)) + if (!cur.ir_lossy) { result = lappend_irange(result, cur); - cur = make_irange(irange_upper(cur) + 1, - irange_upper(next), - irange_is_lossy(next)); + cur = make_irange(cur.ir_upper + 1, + next.ir_upper, + next.ir_lossy); } else { - result = lappend_irange(result, - make_irange(irange_lower(cur), - irange_lower(next) - 1, - irange_is_lossy(cur))); + result = lappend_irange(result, + make_irange(cur.ir_lower, + next.ir_lower - 1, + cur.ir_lossy)); cur = next; } } @@ -196,10 +176,10 @@ irange_list_intersect(List *a, List *b) if (result != NIL) { last = llast_irange(result); - if (irange_conjuncted(last, intersect) && - irange_is_lossy(last) == irange_is_lossy(intersect)) + if (irange_conjuncted(last, intersect) && + last.ir_lossy == intersect.ir_lossy) { - llast_int(result) = irange_union(last, intersect); + llast(result) = alloc_irange(irange_union(last, intersect)); } else { @@ -217,9 +197,9 @@ irange_list_intersect(List *a, List *b) * which lists to fetch, since lower bound of next range is greater (or * equal) to upper bound of current. */ - if (irange_upper(ra) <= irange_upper(rb)) + if (ra.ir_upper <= rb.ir_upper) ca = lnext(ca); - if (irange_upper(ra) >= irange_upper(rb)) + if (ra.ir_upper >= rb.ir_upper) cb = lnext(cb); } return result; @@ -235,7 +215,7 @@ irange_list_length(List *rangeset) foreach (lc, rangeset) { IndexRange irange = lfirst_irange(lc); - result += irange_upper(irange) - irange_lower(irange) + 1; + result += irange.ir_upper - irange.ir_lower + 1; } return result; } @@ -249,10 +229,10 @@ irange_list_find(List *rangeset, int index, bool *lossy) foreach (lc, rangeset) { IndexRange irange = lfirst_irange(lc); - if (index >= irange_lower(irange) && index <= irange_upper(irange)) + if (index >= irange.ir_lower && index <= irange.ir_upper) { if (lossy) - *lossy = irange_is_lossy(irange) ? true : false; + *lossy = irange.ir_lossy; return true; } } diff --git a/contrib/pg_pathman/src/rangeset.h b/contrib/pg_pathman/src/rangeset.h new file mode 100644 index 0000000000..ffe7f31fc8 --- /dev/null +++ b/contrib/pg_pathman/src/rangeset.h @@ -0,0 +1,75 @@ +/* ------------------------------------------------------------------------ + * + * rangeset.h + * IndexRange functions + * + * Copyright (c) 2015-2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef PATHMAN_RANGESET_H +#define PATHMAN_RANGESET_H + + +#include "pathman.h" +#include "nodes/pg_list.h" + + +/* + * IndexRange contains a set of selected partitions. + */ +typedef struct { + bool ir_valid : 1; + bool ir_lossy : 1; /* should we use IndexScan? */ + uint32 ir_lower : 31; /* lower bound */ + uint32 ir_upper : 31; /* upper bound */ +} IndexRange; + + +#define RANGE_MASK 0xEFFFFFFF +#define InvalidIndexRange { false, false, 0, 0 } + + +inline static IndexRange +make_irange(uint32 lower, uint32 upper, bool lossy) +{ + IndexRange result; + + result.ir_valid = true; + result.ir_lossy = lossy; + result.ir_lower = (lower & RANGE_MASK); + result.ir_upper = (upper & RANGE_MASK); + + return result; +} + +inline static IndexRange * +alloc_irange(IndexRange irange) +{ + IndexRange *result = (IndexRange *) palloc(sizeof(IndexRange)); + + memcpy((void *) result, (void *) &irange, sizeof(IndexRange)); + + return result; +} + +#define lfirst_irange(lc) ( *(IndexRange *) lfirst(lc) ) +#define lappend_irange(list, irange) ( lappend((list), alloc_irange(irange)) ) +#define lcons_irange(irange, list) ( lcons(alloc_irange(irange), (list)) ) +#define list_make1_irange(irange) ( lcons(alloc_irange(irange), NIL) ) +#define llast_irange(list) ( lfirst_irange(list_tail(list)) ) +#define linitial_irange(list) ( lfirst_irange(list_head(list)) ) + + +/* rangeset.c */ +bool irange_intersects(IndexRange a, IndexRange b); +bool irange_conjuncted(IndexRange a, IndexRange b); +IndexRange irange_union(IndexRange a, IndexRange b); +IndexRange irange_intersect(IndexRange a, IndexRange b); +List *irange_list_union(List *a, List *b); +List *irange_list_intersect(List *a, List *b); +int irange_list_length(List *rangeset); +bool irange_list_find(List *rangeset, int index, bool *lossy); + +#endif diff --git a/contrib/pg_pathman/src/relation_info.c b/contrib/pg_pathman/src/relation_info.c new file mode 100644 index 0000000000..7028726535 --- /dev/null +++ b/contrib/pg_pathman/src/relation_info.c @@ -0,0 +1,703 @@ +/* ------------------------------------------------------------------------ + * + * relation_info.c + * Data structures describing partitioned relations + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "relation_info.h" +#include "init.h" +#include "utils.h" +#include "xact_handling.h" + +#include "access/htup_details.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "catalog/indexing.h" +#include "catalog/pg_inherits.h" +#include "miscadmin.h" +#include "storage/lmgr.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/hsearch.h" +#include "utils/lsyscache.h" +#include "utils/memutils.h" +#include "utils/snapmgr.h" +#include "utils/typcache.h" + + +/* + * We delay all invalidation jobs received in relcache hook. + */ +static List *delayed_invalidation_parent_rels = NIL; +static List *delayed_invalidation_vague_rels = NIL; +static bool delayed_shutdown = false; /* pathman was dropped */ + + +/* Add unique Oid to list, allocate in TopMemoryContext */ +#define list_add_unique(list, oid) \ + do { \ + MemoryContext old_mcxt = MemoryContextSwitchTo(TopMemoryContext); \ + list = list_append_unique_oid(list, ObjectIdGetDatum(oid)); \ + MemoryContextSwitchTo(old_mcxt); \ + } while (0) + +#define free_invalidation_list(list) \ + do { \ + list_free(list); \ + list = NIL; \ + } while (0) + + +static bool try_perform_parent_refresh(Oid parent); +static Oid try_syscache_parent_search(Oid partition, PartParentSearch *status); +static Oid get_parent_of_partition_internal(Oid partition, + PartParentSearch *status, + HASHACTION action); + + +/* + * refresh\invalidate\get\remove PartRelationInfo functions. + */ + +/* Create or update PartRelationInfo in local cache. Might emit ERROR. */ +const PartRelationInfo * +refresh_pathman_relation_info(Oid relid, + PartType partitioning_type, + const char *part_column_name) +{ + const LOCKMODE lockmode = AccessShareLock; + const TypeCacheEntry *typcache; + Oid *prel_children; + uint32 prel_children_count = 0, + i; + bool found; + PartRelationInfo *prel; + Datum param_values[Natts_pathman_config_params]; + bool param_isnull[Natts_pathman_config_params]; + + prel = (PartRelationInfo *) hash_search(partitioned_rels, + (const void *) &relid, + HASH_ENTER, &found); + elog(DEBUG2, + found ? + "Refreshing record for relation %u in pg_pathman's cache [%u]" : + "Creating new record for relation %u in pg_pathman's cache [%u]", + relid, MyProcPid); + + /* + * NOTE: Trick clang analyzer (first access without NULL pointer check). + * Access to field 'valid' results in a dereference of a null pointer. + */ + prel->cmp_proc = InvalidOid; + + /* Clear outdated resources */ + if (found && PrelIsValid(prel)) + { + /* Free these arrays iff they're not NULL */ + FreeChildrenArray(prel); + FreeRangesArray(prel); + } + + /* First we assume that this entry is invalid */ + prel->valid = false; + + /* Make both arrays point to NULL */ + prel->children = NULL; + prel->ranges = NULL; + + /* Set partitioning type */ + prel->parttype = partitioning_type; + + /* Initialize PartRelationInfo using syscache & typcache */ + prel->attnum = get_attnum(relid, part_column_name); + + /* Attribute number sanity check */ + if (prel->attnum == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + get_rel_name_or_relid(relid), part_column_name); + + /* Fetch atttypid, atttypmod, and attcollation in a single cache lookup */ + get_atttypetypmodcoll(relid, prel->attnum, + &prel->atttype, &prel->atttypmod, &prel->attcollid); + + /* Fetch HASH & CMP fuctions and other stuff from type cache */ + typcache = lookup_type_cache(prel->atttype, + TYPECACHE_CMP_PROC | TYPECACHE_HASH_PROC); + + prel->attbyval = typcache->typbyval; + prel->attlen = typcache->typlen; + prel->attalign = typcache->typalign; + + prel->cmp_proc = typcache->cmp_proc; + prel->hash_proc = typcache->hash_proc; + + LockRelationOid(relid, lockmode); + prel_children = find_inheritance_children_array(relid, lockmode, + &prel_children_count); + UnlockRelationOid(relid, lockmode); + + /* If there's no children at all, remove this entry */ + if (prel_children_count == 0) + { + remove_pathman_relation_info(relid); + return NULL; + } + + /* + * Fill 'prel' with partition info, raise ERROR if anything is wrong. + * This way PartRelationInfo will remain 'invalid', and 'get' procedure + * will try to refresh it again (and again), until the error is fixed + * by user manually (i.e. invalid check constraints etc). + */ + fill_prel_with_partitions(prel_children, prel_children_count, prel); + + /* Add "partition+parent" tuple to cache */ + for (i = 0; i < prel_children_count; i++) + cache_parent_of_partition(prel_children[i], relid); + + pfree(prel_children); + + /* Read additional parameters ('enable_parent' and 'auto' at the moment) */ + if (read_pathman_params(relid, param_values, param_isnull)) + { + prel->enable_parent = param_values[Anum_pathman_config_params_enable_parent - 1]; + prel->auto_partition = param_values[Anum_pathman_config_params_auto - 1]; + prel->init_callback = param_values[Anum_pathman_config_params_init_callback - 1]; + } + /* Else set default values if they cannot be found */ + else + { + prel->enable_parent = false; + prel->auto_partition = true; + prel->init_callback = InvalidOid; + } + + /* We've successfully built a cache entry */ + prel->valid = true; + + return prel; +} + +/* Invalidate PartRelationInfo cache entry. Create new entry if 'found' is NULL. */ +void +invalidate_pathman_relation_info(Oid relid, bool *found) +{ + bool prel_found; + HASHACTION action = found ? HASH_FIND : HASH_ENTER; + PartRelationInfo *prel; + + prel = hash_search(partitioned_rels, + (const void *) &relid, + action, &prel_found); + + if ((action == HASH_FIND || + (action == HASH_ENTER && prel_found)) && PrelIsValid(prel)) + { + FreeChildrenArray(prel); + FreeRangesArray(prel); + + prel->valid = false; /* now cache entry is invalid */ + } + /* Handle invalid PartRelationInfo */ + else if (prel) + { + prel->children = NULL; + prel->ranges = NULL; + + prel->valid = false; /* now cache entry is invalid */ + } + + /* Set 'found' if necessary */ + if (found) *found = prel_found; + + elog(DEBUG2, + "Invalidating record for relation %u in pg_pathman's cache [%u]", + relid, MyProcPid); +} + +/* Get PartRelationInfo from local cache. */ +const PartRelationInfo * +get_pathman_relation_info(Oid relid) +{ + const PartRelationInfo *prel = hash_search(partitioned_rels, + (const void *) &relid, + HASH_FIND, NULL); + + /* Refresh PartRelationInfo if needed */ + if (prel && !PrelIsValid(prel)) + { + Datum values[Natts_pathman_config]; + bool isnull[Natts_pathman_config]; + + /* Check that PATHMAN_CONFIG table contains this relation */ + if (pathman_config_contains_relation(relid, values, isnull, NULL)) + { + PartType part_type; + const char *attname; + + /* We can't use 'part_type' & 'attname' from invalid prel */ + part_type = DatumGetPartType(values[Anum_pathman_config_parttype - 1]); + attname = TextDatumGetCString(values[Anum_pathman_config_attname - 1]); + + /* Refresh partitioned table cache entry (might turn NULL) */ + /* TODO: possible refactoring, pass found 'prel' instead of searching */ + prel = refresh_pathman_relation_info(relid, + part_type, + attname); + } + /* Else clear remaining cache entry */ + else remove_pathman_relation_info(relid); + } + + elog(DEBUG2, + "Fetching %s record for relation %u from pg_pathman's cache [%u]", + (prel ? "live" : "NULL"), relid, MyProcPid); + + return prel; +} + +/* Acquire lock on a table and try to get PartRelationInfo */ +const PartRelationInfo * +get_pathman_relation_info_after_lock(Oid relid, bool unlock_if_not_found) +{ + const PartRelationInfo *prel; + + /* Restrict concurrent partition creation (it's dangerous) */ + xact_lock_partitioned_rel(relid, false); + + prel = get_pathman_relation_info(relid); + if (!prel && unlock_if_not_found) + xact_unlock_partitioned_rel(relid); + + return prel; +} + +/* Remove PartRelationInfo from local cache. */ +void +remove_pathman_relation_info(Oid relid) +{ + PartRelationInfo *prel = hash_search(partitioned_rels, + (const void *) &relid, + HASH_FIND, NULL); + if (prel && PrelIsValid(prel)) + { + /* Free these arrays iff they're not NULL */ + FreeChildrenArray(prel); + FreeRangesArray(prel); + } + + /* Now let's remove the entry completely */ + hash_search(partitioned_rels, + (const void *) &relid, + HASH_REMOVE, NULL); + + elog(DEBUG2, + "Removing record for relation %u in pg_pathman's cache [%u]", + relid, MyProcPid); +} + + +/* + * Functions for delayed invalidation. + */ + +/* Add new delayed pathman shutdown job (DROP EXTENSION) */ +void +delay_pathman_shutdown(void) +{ + delayed_shutdown = true; +} + +/* Add new delayed invalidation job for a [ex-]parent relation */ +void +delay_invalidation_parent_rel(Oid parent) +{ + list_add_unique(delayed_invalidation_parent_rels, parent); +} + +/* Add new delayed invalidation job for a vague relation */ +void +delay_invalidation_vague_rel(Oid vague_rel) +{ + list_add_unique(delayed_invalidation_vague_rels, vague_rel); +} + +/* Finish all pending invalidation jobs if possible */ +void +finish_delayed_invalidation(void) +{ + /* Exit early if there's nothing to do */ + if (delayed_invalidation_parent_rels == NIL && + delayed_invalidation_vague_rels == NIL && + delayed_shutdown == false) + { + return; + } + + /* Check that current state is transactional */ + if (IsTransactionState()) + { + ListCell *lc; + + /* Handle the probable 'DROP EXTENSION' case */ + if (delayed_shutdown) + { + Oid cur_pathman_config_relid; + + /* Unset 'shutdown' flag */ + delayed_shutdown = false; + + /* Get current PATHMAN_CONFIG relid */ + cur_pathman_config_relid = get_relname_relid(PATHMAN_CONFIG, + get_pathman_schema()); + + /* Check that PATHMAN_CONFIG table has indeed been dropped */ + if (cur_pathman_config_relid == InvalidOid || + cur_pathman_config_relid != get_pathman_config_relid()) + { + /* Ok, let's unload pg_pathman's config */ + unload_config(); + + /* Disregard all remaining invalidation jobs */ + free_invalidation_list(delayed_invalidation_parent_rels); + free_invalidation_list(delayed_invalidation_vague_rels); + + /* No need to continue, exit */ + return; + } + } + + /* Process relations that are (or were) definitely partitioned */ + foreach (lc, delayed_invalidation_parent_rels) + { + Oid parent = lfirst_oid(lc); + + /* Skip if it's a TOAST table */ + if (IsToastNamespace(get_rel_namespace(parent))) + continue; + + if (!pathman_config_contains_relation(parent, NULL, NULL, NULL)) + remove_pathman_relation_info(parent); + else + /* get_pathman_relation_info() will refresh this entry */ + invalidate_pathman_relation_info(parent, NULL); + } + + /* Process all other vague cases */ + foreach (lc, delayed_invalidation_vague_rels) + { + Oid vague_rel = lfirst_oid(lc); + + /* Skip if it's a TOAST table */ + if (IsToastNamespace(get_rel_namespace(vague_rel))) + continue; + + /* It might be a partitioned table or a partition */ + if (!try_perform_parent_refresh(vague_rel)) + { + PartParentSearch search; + Oid parent; + + parent = get_parent_of_partition(vague_rel, &search); + + switch (search) + { + /* It's still parent */ + case PPS_ENTRY_PART_PARENT: + try_perform_parent_refresh(parent); + break; + + /* It *might have been* parent before (not in PATHMAN_CONFIG) */ + case PPS_ENTRY_PARENT: + remove_pathman_relation_info(parent); + break; + + /* How come we still don't know?? */ + case PPS_NOT_SURE: + elog(ERROR, "Unknown table status, this should never happen"); + break; + + default: + break; + } + } + } + + free_invalidation_list(delayed_invalidation_parent_rels); + free_invalidation_list(delayed_invalidation_vague_rels); + } +} + + +/* + * cache\forget\get PartParentInfo functions. + */ + +/* Create "partition+parent" pair in local cache */ +void +cache_parent_of_partition(Oid partition, Oid parent) +{ + bool found; + PartParentInfo *ppar; + + ppar = hash_search(parent_cache, + (const void *) &partition, + HASH_ENTER, &found); + + elog(DEBUG2, + found ? + "Refreshing record for child %u in pg_pathman's cache [%u]" : + "Creating new record for child %u in pg_pathman's cache [%u]", + partition, MyProcPid); + + ppar->child_rel = partition; + ppar->parent_rel = parent; +} + +/* Remove "partition+parent" pair from cache & return parent's Oid */ +Oid +forget_parent_of_partition(Oid partition, PartParentSearch *status) +{ + return get_parent_of_partition_internal(partition, status, HASH_REMOVE); +} + +/* Return partition parent's Oid */ +Oid +get_parent_of_partition(Oid partition, PartParentSearch *status) +{ + return get_parent_of_partition_internal(partition, status, HASH_FIND); +} + +/* + * Get [and remove] "partition+parent" pair from cache, + * also check syscache if 'status' is provided. + * + * "status == NULL" implies that we don't care about + * neither syscache nor PATHMAN_CONFIG table contents. + */ +static Oid +get_parent_of_partition_internal(Oid partition, + PartParentSearch *status, + HASHACTION action) +{ + const char *action_str; /* "Fetching"\"Resetting" */ + Oid parent; + PartParentInfo *ppar = hash_search(parent_cache, + (const void *) &partition, + HASH_FIND, NULL); + + /* Set 'action_str' */ + switch (action) + { + case HASH_REMOVE: + action_str = "Resetting"; + break; + + case HASH_FIND: + action_str = "Fetching"; + break; + + default: + elog(ERROR, "Unexpected HTAB action %u", action); + } + + elog(DEBUG2, + "%s %s record for child %u from pg_pathman's cache [%u]", + action_str, (ppar ? "live" : "NULL"), partition, MyProcPid); + + if (ppar) + { + if (status) *status = PPS_ENTRY_PART_PARENT; + parent = ppar->parent_rel; + + /* Remove entry if necessary */ + if (action == HASH_REMOVE) + hash_search(parent_cache, + (const void *) &partition, + HASH_REMOVE, NULL); + } + /* Try fetching parent from syscache if 'status' is provided */ + else if (status) + parent = try_syscache_parent_search(partition, status); + else + parent = InvalidOid; /* we don't have to set status */ + + return parent; +} + +/* Try to find parent of a partition using syscache & PATHMAN_CONFIG */ +static Oid +try_syscache_parent_search(Oid partition, PartParentSearch *status) +{ + if (!IsTransactionState()) + { + /* We could not perform search */ + if (status) *status = PPS_NOT_SURE; + + return InvalidOid; + } + else + { + Relation relation; + Snapshot snapshot; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple inheritsTuple; + Oid parent = InvalidOid; + + /* At first we assume parent does not exist (not a partition) */ + if (status) *status = PPS_ENTRY_NOT_FOUND; + + relation = heap_open(InheritsRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_inherits_inhrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(partition)); + + snapshot = RegisterSnapshot(GetLatestSnapshot()); + scan = systable_beginscan(relation, InheritsRelidSeqnoIndexId, + true, NULL, 1, key); + + while ((inheritsTuple = systable_getnext(scan)) != NULL) + { + parent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent; + + /* + * NB: don't forget that 'inh' flag does not immediately + * mean that this is a pg_pathman's partition. It might + * be just a casual inheriting table. + */ + if (status) *status = PPS_ENTRY_PARENT; + + /* Check that PATHMAN_CONFIG contains this table */ + if (pathman_config_contains_relation(parent, NULL, NULL, NULL)) + { + /* We've found the entry, update status */ + if (status) *status = PPS_ENTRY_PART_PARENT; + } + + break; /* there should be no more rows */ + } + + systable_endscan(scan); + UnregisterSnapshot(snapshot); + heap_close(relation, AccessShareLock); + + return parent; + } +} + +/* + * Try to refresh cache entry for relation 'parent'. + * + * Return true on success. + */ +static bool +try_perform_parent_refresh(Oid parent) +{ + Datum values[Natts_pathman_config]; + bool isnull[Natts_pathman_config]; + + if (pathman_config_contains_relation(parent, values, isnull, NULL)) + { + text *attname; + PartType parttype; + + parttype = DatumGetPartType(values[Anum_pathman_config_parttype - 1]); + attname = DatumGetTextP(values[Anum_pathman_config_attname - 1]); + + /* If anything went wrong, return false (actually, it might throw ERROR) */ + if (!PrelIsValid(refresh_pathman_relation_info(parent, parttype, + text_to_cstring(attname)))) + return false; + } + /* Not a partitioned relation */ + else return false; + + return true; +} + +/* + * Safe PartType wrapper. + */ +PartType +DatumGetPartType(Datum datum) +{ + uint32 val = DatumGetUInt32(datum); + + if (val < 1 || val > 2) + elog(ERROR, "Unknown partitioning type %u", val); + + return (PartType) val; +} + +char * +PartTypeToCString(PartType parttype) +{ + static char *hash_str = "1", + *range_str = "2"; + + switch (parttype) + { + case PT_HASH: + return hash_str; + + case PT_RANGE: + return range_str; + + default: + elog(ERROR, "Unknown partitioning type %u", parttype); + return NULL; /* keep compiler happy */ + } +} + +/* + * Common PartRelationInfo checks. Emit ERROR if anything is wrong. + */ +void +shout_if_prel_is_invalid(Oid parent_oid, + const PartRelationInfo *prel, + PartType expected_part_type) +{ + if (!prel) + elog(ERROR, "relation \"%s\" has no partitions", + get_rel_name_or_relid(parent_oid)); + + if (!PrelIsValid(prel)) + elog(ERROR, "pg_pathman's cache contains invalid entry " + "for relation \"%s\" [%u]", + get_rel_name_or_relid(parent_oid), + MyProcPid); + + /* Check partitioning type unless it's "indifferent" */ + if (expected_part_type != PT_INDIFFERENT && + expected_part_type != prel->parttype) + { + char *expected_str; + + switch (expected_part_type) + { + case PT_HASH: + expected_str = "HASH"; + break; + + case PT_RANGE: + expected_str = "RANGE"; + break; + + default: + elog(ERROR, + "expected_str selection not implemented for type %d", + expected_part_type); + } + + elog(ERROR, "relation \"%s\" is not partitioned by %s", + get_rel_name_or_relid(parent_oid), + expected_str); + } +} diff --git a/contrib/pg_pathman/src/relation_info.h b/contrib/pg_pathman/src/relation_info.h new file mode 100644 index 0000000000..5b50005a9c --- /dev/null +++ b/contrib/pg_pathman/src/relation_info.h @@ -0,0 +1,200 @@ +/* ------------------------------------------------------------------------ + * + * relation_info.h + * Data structures describing partitioned relations + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef RELATION_INFO_H +#define RELATION_INFO_H + +#include "postgres.h" +#include "access/attnum.h" +#include "port/atomics.h" + + +/* + * Partitioning type. + */ +typedef enum +{ + PT_INDIFFERENT = 0, /* for part type traits (virtual type) */ + PT_HASH, + PT_RANGE +} PartType; + +/* + * Child relation info for RANGE partitioning + */ +typedef struct +{ + Oid child_oid; + + Datum min, + max; +} RangeEntry; + +/* + * PartRelationInfo + * Per-relation partitioning information + */ +typedef struct +{ + Oid key; /* partitioned table's Oid */ + bool valid; /* is this entry valid? */ + bool enable_parent; /* include parent to the plan */ + bool auto_partition; /* auto partition creation */ + Oid init_callback; /* callback for partition creation */ + + uint32 children_count; + Oid *children; /* Oids of child partitions */ + RangeEntry *ranges; /* per-partition range entry or NULL */ + + PartType parttype; /* partitioning type (HASH | RANGE) */ + AttrNumber attnum; /* partitioned column's index */ + Oid atttype; /* partitioned column's type */ + int32 atttypmod; /* partitioned column type modifier */ + bool attbyval; /* is partitioned column stored by value? */ + int16 attlen; /* length of the partitioned column's type */ + int attalign; /* alignment of the part column's type */ + Oid attcollid; /* collation of the partitioned column */ + + Oid cmp_proc, /* comparison fuction for 'atttype' */ + hash_proc; /* hash function for 'atttype' */ +} PartRelationInfo; + +/* + * RelParentInfo + * Cached parent of the specified partition. + * Allows us to quickly search for PartRelationInfo. + */ +typedef struct +{ + Oid child_rel; /* key */ + Oid parent_rel; +} PartParentInfo; + +/* + * PartParentSearch + * Represents status of a specific cached entry. + * Returned by [for]get_parent_of_partition(). + */ +typedef enum +{ + PPS_ENTRY_NOT_FOUND = 0, + PPS_ENTRY_PARENT, /* entry was found, but pg_pathman doesn't know it */ + PPS_ENTRY_PART_PARENT, /* entry is parent and is known by pg_pathman */ + PPS_NOT_SURE /* can't determine (not transactional state) */ +} PartParentSearch; + + +/* + * PartRelationInfo field access macros. + */ + +#define PrelParentRelid(prel) ( (prel)->key ) + +#define PrelGetChildrenArray(prel) ( (prel)->children ) + +#define PrelGetRangesArray(prel) ( (prel)->ranges ) + +#define PrelChildrenCount(prel) ( (prel)->children_count ) + +#define PrelIsValid(prel) ( (prel) && (prel)->valid ) + +inline static uint32 +PrelLastChild(const PartRelationInfo *prel) +{ + Assert(PrelIsValid(prel)); + + if (PrelChildrenCount(prel) == 0) + elog(ERROR, "pg_pathman's cache entry for relation %u has 0 children", + PrelParentRelid(prel)); + + return PrelChildrenCount(prel) - 1; /* last partition */ +} + + +const PartRelationInfo *refresh_pathman_relation_info(Oid relid, + PartType partitioning_type, + const char *part_column_name); +void invalidate_pathman_relation_info(Oid relid, bool *found); +void remove_pathman_relation_info(Oid relid); +const PartRelationInfo *get_pathman_relation_info(Oid relid); +const PartRelationInfo *get_pathman_relation_info_after_lock(Oid relid, + bool unlock_if_not_found); + +void delay_pathman_shutdown(void); +void delay_invalidation_parent_rel(Oid parent); +void delay_invalidation_vague_rel(Oid vague_rel); +void finish_delayed_invalidation(void); + +void cache_parent_of_partition(Oid partition, Oid parent); +Oid forget_parent_of_partition(Oid partition, PartParentSearch *status); +Oid get_parent_of_partition(Oid partition, PartParentSearch *status); + +PartType DatumGetPartType(Datum datum); +char * PartTypeToCString(PartType parttype); + +void shout_if_prel_is_invalid(Oid parent_oid, + const PartRelationInfo *prel, + PartType expected_part_type); + + +/* + * Useful static functions for freeing memory. + */ + +static inline void +FreeChildrenArray(PartRelationInfo *prel) +{ + uint32 i; + + Assert(PrelIsValid(prel)); + + /* Remove relevant PartParentInfos */ + if ((prel)->children) + { + for (i = 0; i < PrelChildrenCount(prel); i++) + { + Oid child = (prel)->children[i]; + + /* If it's *always been* relid's partition, free cache */ + if (PrelParentRelid(prel) == get_parent_of_partition(child, NULL)) + forget_parent_of_partition(child, NULL); + } + + pfree((prel)->children); + (prel)->children = NULL; + } +} + +static inline void +FreeRangesArray(PartRelationInfo *prel) +{ + uint32 i; + + Assert(PrelIsValid(prel)); + + /* Remove RangeEntries array */ + if ((prel)->ranges) + { + /* Remove persistent entries if not byVal */ + if (!(prel)->attbyval) + { + for (i = 0; i < PrelChildrenCount(prel); i++) + { + pfree(DatumGetPointer((prel)->ranges[i].min)); + pfree(DatumGetPointer((prel)->ranges[i].max)); + } + } + + pfree((prel)->ranges); + (prel)->ranges = NULL; + } +} + +#endif diff --git a/contrib/pg_pathman/src/runtime_merge_append.c b/contrib/pg_pathman/src/runtime_merge_append.c new file mode 100644 index 0000000000..e021d3ce83 --- /dev/null +++ b/contrib/pg_pathman/src/runtime_merge_append.c @@ -0,0 +1,941 @@ +/* ------------------------------------------------------------------------ + * + * runtime_merge_append.c + * RuntimeMergeAppend node's function definitions and global variables + * + * Copyright (c) 2016, Postgres Professional + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------ + */ + +#include "pg_compat.h" + +#include "runtime_merge_append.h" +#include "pathman.h" + +#include "postgres.h" +#include "catalog/pg_collation.h" +#include "miscadmin.h" +#include "nodes/nodeFuncs.h" +#include "nodes/plannodes.h" +#include "optimizer/clauses.h" +#include "optimizer/cost.h" +#include "optimizer/planmain.h" +#include "optimizer/tlist.h" +#include "optimizer/var.h" +#include "utils/builtins.h" +#include "utils/guc.h" +#include "utils/lsyscache.h" +#include "utils/typcache.h" +#include "utils/memutils.h" +#include "utils/ruleutils.h" + +#include "lib/binaryheap.h" + + +bool pg_pathman_enable_runtime_merge_append = true; + +CustomPathMethods runtime_merge_append_path_methods; +CustomScanMethods runtime_merge_append_plan_methods; +CustomExecMethods runtime_merge_append_exec_methods; + +typedef struct +{ + int numCols; + AttrNumber *sortColIdx; + Oid *sortOperators; + Oid *collations; + bool *nullsFirst; +} MergeAppendGuts; + +static Plan * prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, + Relids relids, const AttrNumber *reqColIdx, + bool adjust_tlist_in_place, int *p_numsortkeys, + AttrNumber **p_sortColIdx, Oid **p_sortOperators, + Oid **p_collations, bool **p_nullsFirst); + +static Sort * make_sort(PlannerInfo *root, Plan *lefttree, int numCols, + AttrNumber *sortColIdx, Oid *sortOperators, + Oid *collations, bool *nullsFirst, + double limit_tuples); + +static void copy_plan_costsize(Plan *dest, Plan *src); + +static void show_sort_group_keys(PlanState *planstate, const char *qlabel, + int nkeys, AttrNumber *keycols, + Oid *sortOperators, Oid *collations, bool *nullsFirst, + List *ancestors, ExplainState *es); + +/* + * We have one slot for each item in the heap array. We use SlotNumber + * to store slot indexes. This doesn't actually provide any formal + * type-safety, but it makes the code more self-documenting. + */ +typedef int32 SlotNumber; + +/* + * Compare the tuples in the two given slots. + */ +static int32 +heap_compare_slots(Datum a, Datum b, void *arg) +{ + RuntimeMergeAppendState *node = (RuntimeMergeAppendState *) arg; + SlotNumber slot1 = DatumGetInt32(a); + SlotNumber slot2 = DatumGetInt32(b); + + TupleTableSlot *s1 = node->ms_slots[slot1]; + TupleTableSlot *s2 = node->ms_slots[slot2]; + int nkey; + + Assert(!TupIsNull(s1)); + Assert(!TupIsNull(s2)); + + for (nkey = 0; nkey < node->ms_nkeys; nkey++) + { + SortSupport sortKey = node->ms_sortkeys + nkey; + AttrNumber attno = sortKey->ssup_attno; + Datum datum1, + datum2; + bool isNull1, + isNull2; + int compare; + + datum1 = slot_getattr(s1, attno, &isNull1); + datum2 = slot_getattr(s2, attno, &isNull2); + + compare = ApplySortComparator(datum1, isNull1, + datum2, isNull2, + sortKey); + if (compare != 0) + return -compare; + } + return 0; +} + +static void +pack_runtimemergeappend_private(CustomScan *cscan, MergeAppendGuts *mag) +{ + List *runtimemergeappend_private = NIL; + List *sortColIdx = NIL, + *sortOperators = NIL, + *collations = NIL, + *nullsFirst = NIL; + int i; + + for (i = 0; i < mag->numCols; i++) + { + sortColIdx = lappend_int(sortColIdx, mag->sortColIdx[i]); + sortOperators = lappend_oid(sortOperators, mag->sortOperators[i]); + collations = lappend_oid(collations, mag->collations[i]); + nullsFirst = lappend_int(nullsFirst, mag->nullsFirst[i]); + } + + runtimemergeappend_private = list_make2(makeInteger(mag->numCols), + list_make4(sortColIdx, + sortOperators, + collations, + nullsFirst)); + + /* + * Append RuntimeMergeAppend's data to the 'custom_private' (2nd). + * + * This way some sort of hierarchy is maintained in 'custom_private': + * inherited structure (in this case RuntimeAppend) is stored first, + * so we can think of pack\unpack functions as 'constructors' to some + * extent. + */ + cscan->custom_private = lappend(cscan->custom_private, + runtimemergeappend_private); +} + +static void +unpack_runtimemergeappend_private(RuntimeMergeAppendState *scan_state, + CustomScan *cscan) +{ +#define FillStateField(name, type, method) \ + do \ + { \ + ListCell *lc; \ + int i = 0; \ + Assert(scan_state->numCols == list_length(name)); \ + scan_state->name = palloc0(scan_state->numCols * sizeof(type)); \ + foreach (lc, name) \ + scan_state->name[i++] = method(lc); \ + } \ + while (0) + + List *runtimemergeappend_private = NIL; + List *sortColIdx, + *sortOperators, + *collations, + *nullsFirst; + + /* + * RuntimeMergeAppend node's private data is stored in + * second element of the 'custom_private' list, right + * after the RuntimeAppend node's private data (2nd) + */ + runtimemergeappend_private = lsecond(cscan->custom_private); + scan_state->numCols = intVal(linitial(runtimemergeappend_private)); + + sortColIdx = linitial(lsecond(runtimemergeappend_private)); + sortOperators = lsecond(lsecond(runtimemergeappend_private)); + collations = lthird(lsecond(runtimemergeappend_private)); + nullsFirst = lfourth(lsecond(runtimemergeappend_private)); + + FillStateField(sortColIdx, AttrNumber, lfirst_int); + FillStateField(sortOperators, Oid, lfirst_oid); + FillStateField(collations, Oid, lfirst_oid); + FillStateField(nullsFirst, bool, lfirst_int); +} + +void +init_runtime_merge_append_static_data(void) +{ + runtime_merge_append_path_methods.CustomName = "RuntimeMergeAppend"; + runtime_merge_append_path_methods.PlanCustomPath = create_runtimemergeappend_plan; + + runtime_merge_append_plan_methods.CustomName = "RuntimeMergeAppend"; + runtime_merge_append_plan_methods.CreateCustomScanState = runtimemergeappend_create_scan_state; + + runtime_merge_append_exec_methods.CustomName = "RuntimeMergeAppend"; + runtime_merge_append_exec_methods.BeginCustomScan = runtimemergeappend_begin; + runtime_merge_append_exec_methods.ExecCustomScan = runtimemergeappend_exec; + runtime_merge_append_exec_methods.EndCustomScan = runtimemergeappend_end; + runtime_merge_append_exec_methods.ReScanCustomScan = runtimemergeappend_rescan; + runtime_merge_append_exec_methods.MarkPosCustomScan = NULL; + runtime_merge_append_exec_methods.RestrPosCustomScan = NULL; + runtime_merge_append_exec_methods.ExplainCustomScan = runtimemergeappend_explain; + + DefineCustomBoolVariable("pg_pathman.enable_runtimemergeappend", + "Enables the planner's use of RuntimeMergeAppend custom node.", + NULL, + &pg_pathman_enable_runtime_merge_append, + true, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); +} + +Path * +create_runtimemergeappend_path(PlannerInfo *root, + AppendPath *inner_append, + ParamPathInfo *param_info, + double sel) +{ + RelOptInfo *rel = inner_append->path.parent; + Path *path; + double limit_tuples; + + path = create_append_path_common(root, inner_append, + param_info, + &runtime_merge_append_path_methods, + sizeof(RuntimeMergeAppendPath), + sel); + + if (bms_equal(rel->relids, root->all_baserels)) + limit_tuples = root->limit_tuples; + else + limit_tuples = -1.0; + + ((RuntimeMergeAppendPath *) path)->limit_tuples = limit_tuples; + + return path; +} + +Plan * +create_runtimemergeappend_plan(PlannerInfo *root, RelOptInfo *rel, + CustomPath *best_path, List *tlist, + List *clauses, List *custom_plans) +{ + CustomScan *node; + Plan *plan; + List *pathkeys = best_path->path.pathkeys; + double limit_tuples = ((RuntimeMergeAppendPath *) best_path)->limit_tuples; + + MergeAppendGuts mag; + + ListCell *path_cell; + ListCell *plan_cell; + + plan = create_append_plan_common(root, rel, + best_path, tlist, + clauses, custom_plans, + &runtime_merge_append_plan_methods); + + node = (CustomScan *) plan; + + (void) prepare_sort_from_pathkeys(root, plan, pathkeys, + best_path->path.parent->relids, + NULL, + true, + &mag.numCols, + &mag.sortColIdx, + &mag.sortOperators, + &mag.collations, + &mag.nullsFirst); + + /* + * Now prepare the child plans. We must apply prepare_sort_from_pathkeys + * even to subplans that don't need an explicit sort, to make sure they + * are returning the same sort key columns the MergeAppend expects. + */ + forboth(path_cell, best_path->custom_paths, plan_cell, custom_plans) + { + Path *subpath = (Path *) lfirst(path_cell); + Plan *subplan = (Plan *) lfirst(plan_cell); + + int numsortkeys; + AttrNumber *sortColIdx; + Oid *sortOperators; + Oid *collations; + bool *nullsFirst; + + /* Compute sort column info, and adjust subplan's tlist as needed */ + subplan = prepare_sort_from_pathkeys(root, subplan, pathkeys, + subpath->parent->relids, + mag.sortColIdx, + false, + &numsortkeys, + &sortColIdx, + &sortOperators, + &collations, + &nullsFirst); + + /* + * Check that we got the same sort key information. We just Assert + * that the sortops match, since those depend only on the pathkeys; + * but it seems like a good idea to check the sort column numbers + * explicitly, to ensure the tlists really do match up. + */ + Assert(numsortkeys == mag.numCols); + if (memcmp(sortColIdx, mag.sortColIdx, + numsortkeys * sizeof(AttrNumber)) != 0) + elog(ERROR, "RuntimeMergeAppend child's targetlist doesn't match RuntimeMergeAppend"); + Assert(memcmp(sortOperators, mag.sortOperators, + numsortkeys * sizeof(Oid)) == 0); + Assert(memcmp(collations, mag.collations, + numsortkeys * sizeof(Oid)) == 0); + Assert(memcmp(nullsFirst, mag.nullsFirst, + numsortkeys * sizeof(bool)) == 0); + + /* Now, insert a Sort node if subplan isn't sufficiently ordered */ + if (!pathkeys_contained_in(pathkeys, subpath->pathkeys)) + subplan = (Plan *) make_sort(root, subplan, numsortkeys, + sortColIdx, sortOperators, + collations, nullsFirst, + limit_tuples); + + /* Replace subpath with subplan */ + lfirst(plan_cell) = subplan; + } + + pack_runtimemergeappend_private(node, &mag); + + return plan; +} + +Node * +runtimemergeappend_create_scan_state(CustomScan *node) +{ + Node *state; + state = create_append_scan_state_common(node, + &runtime_merge_append_exec_methods, + sizeof(RuntimeMergeAppendState)); + + unpack_runtimemergeappend_private((RuntimeMergeAppendState *) state, node); + + return state; +} + +void +runtimemergeappend_begin(CustomScanState *node, EState *estate, int eflags) +{ + begin_append_common(node, estate, eflags); +} + +static void +fetch_next_tuple(CustomScanState *node) +{ + RuntimeMergeAppendState *scan_state = (RuntimeMergeAppendState *) node; + RuntimeAppendState *rstate = &scan_state->rstate; + PlanState *ps; + int i; + + if (!scan_state->ms_initialized) + { + for (i = 0; i < scan_state->rstate.ncur_plans; i++) + { + ChildScanCommon child = scan_state->rstate.cur_plans[i]; + PlanState *ps = child->content.plan_state; + + Assert(child->content_type == CHILD_PLAN_STATE); + + scan_state->ms_slots[i] = ExecProcNode(ps); + if (!TupIsNull(scan_state->ms_slots[i])) + binaryheap_add_unordered(scan_state->ms_heap, Int32GetDatum(i)); + } + binaryheap_build(scan_state->ms_heap); + scan_state->ms_initialized = true; + } + else + { + i = DatumGetInt32(binaryheap_first(scan_state->ms_heap)); + ps = scan_state->rstate.cur_plans[i]->content.plan_state; + + for (;;) + { + bool quals; + + scan_state->ms_slots[i] = ExecProcNode(ps); + + if (TupIsNull(scan_state->ms_slots[i])) + { + (void) binaryheap_remove_first(scan_state->ms_heap); + break; + } + + node->ss.ps.ps_ExprContext->ecxt_scantuple = scan_state->ms_slots[i]; + quals = ExecQual(rstate->custom_expr_states, + node->ss.ps.ps_ExprContext, false); + + ResetExprContext(node->ss.ps.ps_ExprContext); + + if (quals) + { + binaryheap_replace_first(scan_state->ms_heap, Int32GetDatum(i)); + break; + } + } + } + + if (binaryheap_empty(scan_state->ms_heap)) + { + /* All the subplans are exhausted, and so is the heap */ + rstate->slot = NULL; + return; + } + else + { + i = DatumGetInt32(binaryheap_first(scan_state->ms_heap)); + rstate->slot = scan_state->ms_slots[i]; + return; + } +} + +TupleTableSlot * +runtimemergeappend_exec(CustomScanState *node) +{ + return exec_append_common(node, fetch_next_tuple); +} + +void +runtimemergeappend_end(CustomScanState *node) +{ + RuntimeMergeAppendState *scan_state = (RuntimeMergeAppendState *) node; + + end_append_common(node); + + if (scan_state->ms_heap) + binaryheap_free(scan_state->ms_heap); +} + +void +runtimemergeappend_rescan(CustomScanState *node) +{ + RuntimeMergeAppendState *scan_state = (RuntimeMergeAppendState *) node; + int nplans; + int i; + + rescan_append_common(node); + + nplans = scan_state->rstate.ncur_plans; + + scan_state->ms_slots = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans); + scan_state->ms_heap = binaryheap_allocate(nplans, heap_compare_slots, scan_state); + + /* + * initialize sort-key information + */ + scan_state->ms_nkeys = scan_state->numCols; + scan_state->ms_sortkeys = (SortSupport) + palloc0(sizeof(SortSupportData) * scan_state->numCols); + + for (i = 0; i < scan_state->numCols; i++) + { + SortSupport sortKey = scan_state->ms_sortkeys + i; + + sortKey->ssup_cxt = CurrentMemoryContext; + sortKey->ssup_collation = scan_state->collations[i]; + sortKey->ssup_nulls_first = scan_state->nullsFirst[i]; + sortKey->ssup_attno = scan_state->sortColIdx[i]; + + /* + * It isn't feasible to perform abbreviated key conversion, since + * tuples are pulled into mergestate's binary heap as needed. It + * would likely be counter-productive to convert tuples into an + * abbreviated representation as they're pulled up, so opt out of that + * additional optimization entirely. + */ + sortKey->abbreviate = false; + + PrepareSortSupportFromOrderingOp(scan_state->sortOperators[i], sortKey); + } + + binaryheap_reset(scan_state->ms_heap); + scan_state->ms_initialized = false; +} + +void +runtimemergeappend_explain(CustomScanState *node, List *ancestors, ExplainState *es) +{ + RuntimeMergeAppendState *scan_state = (RuntimeMergeAppendState *) node; + + explain_append_common(node, scan_state->rstate.children_table, es); + + /* We should print sort keys as well */ + show_sort_group_keys((PlanState *) &node->ss.ps, "Sort Key", + scan_state->numCols, scan_state->sortColIdx, + scan_state->sortOperators, scan_state->collations, + scan_state->nullsFirst, ancestors, es); +} + + +/* + * Copied from createplan.c + */ + +static void +copy_plan_costsize(Plan *dest, Plan *src) +{ + if (src) + { + dest->startup_cost = src->startup_cost; + dest->total_cost = src->total_cost; + dest->plan_rows = src->plan_rows; + dest->plan_width = src->plan_width; + } + else + { + dest->startup_cost = 0; + dest->total_cost = 0; + dest->plan_rows = 0; + dest->plan_width = 0; + } +} + +/* Copied from createplan.c */ +static Sort * +make_sort(PlannerInfo *root, Plan *lefttree, int numCols, + AttrNumber *sortColIdx, Oid *sortOperators, + Oid *collations, bool *nullsFirst, + double limit_tuples) +{ + Sort *node = makeNode(Sort); + Plan *plan = &node->plan; + Path sort_path; /* dummy for result of cost_sort */ + + copy_plan_costsize(plan, lefttree); /* only care about copying size */ + cost_sort(&sort_path, root, NIL, + lefttree->total_cost, + lefttree->plan_rows, + lefttree->plan_width, + 0.0, + work_mem, + limit_tuples); + plan->startup_cost = sort_path.startup_cost; + plan->total_cost = sort_path.total_cost; + plan->targetlist = lefttree->targetlist; + plan->qual = NIL; + plan->lefttree = lefttree; + plan->righttree = NULL; + node->numCols = numCols; + node->sortColIdx = sortColIdx; + node->sortOperators = sortOperators; + node->collations = collations; + node->nullsFirst = nullsFirst; + + return node; +} + +static EquivalenceMember * +find_ec_member_for_tle(EquivalenceClass *ec, + TargetEntry *tle, + Relids relids) +{ + Expr *tlexpr; + ListCell *lc; + + /* We ignore binary-compatible relabeling on both ends */ + tlexpr = tle->expr; + while (tlexpr && IsA(tlexpr, RelabelType)) + tlexpr = ((RelabelType *) tlexpr)->arg; + + foreach(lc, ec->ec_members) + { + EquivalenceMember *em = (EquivalenceMember *) lfirst(lc); + Expr *emexpr; + + /* + * We shouldn't be trying to sort by an equivalence class that + * contains a constant, so no need to consider such cases any further. + */ + if (em->em_is_const) + continue; + + /* + * Ignore child members unless they match the rel being sorted. + */ + if (em->em_is_child && + !bms_equal(em->em_relids, relids)) + continue; + + /* Match if same expression (after stripping relabel) */ + emexpr = em->em_expr; + while (emexpr && IsA(emexpr, RelabelType)) + emexpr = ((RelabelType *) emexpr)->arg; + + if (equal(emexpr, tlexpr)) + return em; + } + + return NULL; +} + +static Plan * +prepare_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys, + Relids relids, + const AttrNumber *reqColIdx, + bool adjust_tlist_in_place, + int *p_numsortkeys, + AttrNumber **p_sortColIdx, + Oid **p_sortOperators, + Oid **p_collations, + bool **p_nullsFirst) +{ + List *tlist = lefttree->targetlist; + ListCell *i; + int numsortkeys; + AttrNumber *sortColIdx; + Oid *sortOperators; + Oid *collations; + bool *nullsFirst; + + /* + * We will need at most list_length(pathkeys) sort columns; possibly less + */ + numsortkeys = list_length(pathkeys); + sortColIdx = (AttrNumber *) palloc(numsortkeys * sizeof(AttrNumber)); + sortOperators = (Oid *) palloc(numsortkeys * sizeof(Oid)); + collations = (Oid *) palloc(numsortkeys * sizeof(Oid)); + nullsFirst = (bool *) palloc(numsortkeys * sizeof(bool)); + + numsortkeys = 0; + + foreach(i, pathkeys) + { + PathKey *pathkey = (PathKey *) lfirst(i); + EquivalenceClass *ec = pathkey->pk_eclass; + EquivalenceMember *em; + TargetEntry *tle = NULL; + Oid pk_datatype = InvalidOid; + Oid sortop; + ListCell *j; + + if (ec->ec_has_volatile) + { + /* + * If the pathkey's EquivalenceClass is volatile, then it must + * have come from an ORDER BY clause, and we have to match it to + * that same targetlist entry. + */ + if (ec->ec_sortref == 0) /* can't happen */ + elog(ERROR, "volatile EquivalenceClass has no sortref"); + tle = get_sortgroupref_tle(ec->ec_sortref, tlist); + Assert(tle); + Assert(list_length(ec->ec_members) == 1); + pk_datatype = ((EquivalenceMember *) linitial(ec->ec_members))->em_datatype; + } + else if (reqColIdx != NULL) + { + /* + * If we are given a sort column number to match, only consider + * the single TLE at that position. It's possible that there is + * no such TLE, in which case fall through and generate a resjunk + * targetentry (we assume this must have happened in the parent + * plan as well). If there is a TLE but it doesn't match the + * pathkey's EC, we do the same, which is probably the wrong thing + * but we'll leave it to caller to complain about the mismatch. + */ + tle = get_tle_by_resno(tlist, reqColIdx[numsortkeys]); + if (tle) + { + em = find_ec_member_for_tle(ec, tle, relids); + if (em) + { + /* found expr at right place in tlist */ + pk_datatype = em->em_datatype; + } + else + tle = NULL; + } + } + else + { + /* + * Otherwise, we can sort by any non-constant expression listed in + * the pathkey's EquivalenceClass. For now, we take the first + * tlist item found in the EC. If there's no match, we'll generate + * a resjunk entry using the first EC member that is an expression + * in the input's vars. (The non-const restriction only matters + * if the EC is below_outer_join; but if it isn't, it won't + * contain consts anyway, else we'd have discarded the pathkey as + * redundant.) + * + * XXX if we have a choice, is there any way of figuring out which + * might be cheapest to execute? (For example, int4lt is likely + * much cheaper to execute than numericlt, but both might appear + * in the same equivalence class...) Not clear that we ever will + * have an interesting choice in practice, so it may not matter. + */ + foreach(j, tlist) + { + tle = (TargetEntry *) lfirst(j); + em = find_ec_member_for_tle(ec, tle, relids); + if (em) + { + /* found expr already in tlist */ + pk_datatype = em->em_datatype; + break; + } + tle = NULL; + } + } + + if (!tle) + { + /* + * No matching tlist item; look for a computable expression. Note + * that we treat Aggrefs as if they were variables; this is + * necessary when attempting to sort the output from an Agg node + * for use in a WindowFunc (since grouping_planner will have + * treated the Aggrefs as variables, too). + */ + Expr *sortexpr = NULL; + + foreach(j, ec->ec_members) + { + EquivalenceMember *em = (EquivalenceMember *) lfirst(j); + List *exprvars; + ListCell *k; + + /* + * We shouldn't be trying to sort by an equivalence class that + * contains a constant, so no need to consider such cases any + * further. + */ + if (em->em_is_const) + continue; + + /* + * Ignore child members unless they match the rel being + * sorted. + */ + if (em->em_is_child && + !bms_equal(em->em_relids, relids)) + continue; + + sortexpr = em->em_expr; + exprvars = pull_var_clause_compat((Node *) sortexpr, + PVC_INCLUDE_AGGREGATES, + PVC_INCLUDE_PLACEHOLDERS); + foreach(k, exprvars) + { + if (!tlist_member_ignore_relabel(lfirst(k), tlist)) + break; + } + list_free(exprvars); + if (!k) + { + pk_datatype = em->em_datatype; + break; /* found usable expression */ + } + } + if (!j) + elog(ERROR, "could not find pathkey item to sort"); + + /* + * Do we need to insert a Result node? + */ + if (!adjust_tlist_in_place && + !is_projection_capable_plan(lefttree)) + { + /* copy needed so we don't modify input's tlist below */ + tlist = copyObject(tlist); + lefttree = (Plan *) make_result_compat(root, tlist, NULL, + lefttree); + } + + /* Don't bother testing is_projection_capable_plan again */ + adjust_tlist_in_place = true; + + /* + * Add resjunk entry to input's tlist + */ + tle = makeTargetEntry(sortexpr, + list_length(tlist) + 1, + NULL, + true); + tlist = lappend(tlist, tle); + lefttree->targetlist = tlist; /* just in case NIL before */ + } + + /* + * Look up the correct sort operator from the PathKey's slightly + * abstracted representation. + */ + sortop = get_opfamily_member(pathkey->pk_opfamily, + pk_datatype, + pk_datatype, + pathkey->pk_strategy); + if (!OidIsValid(sortop)) /* should not happen */ + elog(ERROR, "could not find member %d(%u,%u) of opfamily %u", + pathkey->pk_strategy, pk_datatype, pk_datatype, + pathkey->pk_opfamily); + + /* Add the column to the sort arrays */ + sortColIdx[numsortkeys] = tle->resno; + sortOperators[numsortkeys] = sortop; + collations[numsortkeys] = ec->ec_collation; + nullsFirst[numsortkeys] = pathkey->pk_nulls_first; + numsortkeys++; + } + + /* Return results */ + *p_numsortkeys = numsortkeys; + *p_sortColIdx = sortColIdx; + *p_sortOperators = sortOperators; + *p_collations = collations; + *p_nullsFirst = nullsFirst; + + return lefttree; +} + +/* + * Append nondefault characteristics of the sort ordering of a column to buf + * (collation, direction, NULLS FIRST/LAST) + */ +static void +show_sortorder_options(StringInfo buf, Node *sortexpr, + Oid sortOperator, Oid collation, bool nullsFirst) +{ + Oid sortcoltype = exprType(sortexpr); + bool reverse = false; + TypeCacheEntry *typentry; + + typentry = lookup_type_cache(sortcoltype, + TYPECACHE_LT_OPR | TYPECACHE_GT_OPR); + + /* + * Print COLLATE if it's not default. There are some cases where this is + * redundant, eg if expression is a column whose declared collation is + * that collation, but it's hard to distinguish that here. + */ + if (OidIsValid(collation) && collation != DEFAULT_COLLATION_OID) + { + char *collname = get_collation_name(collation); + + if (collname == NULL) + elog(ERROR, "cache lookup failed for collation %u", collation); + appendStringInfo(buf, " COLLATE %s", quote_identifier(collname)); + } + + /* Print direction if not ASC, or USING if non-default sort operator */ + if (sortOperator == typentry->gt_opr) + { + appendStringInfoString(buf, " DESC"); + reverse = true; + } + else if (sortOperator != typentry->lt_opr) + { + char *opname = get_opname(sortOperator); + + if (opname == NULL) + elog(ERROR, "cache lookup failed for operator %u", sortOperator); + appendStringInfo(buf, " USING %s", opname); + /* Determine whether operator would be considered ASC or DESC */ + (void) get_equality_op_for_ordering_op(sortOperator, &reverse); + } + + /* Add NULLS FIRST/LAST only if it wouldn't be default */ + if (nullsFirst && !reverse) + { + appendStringInfoString(buf, " NULLS FIRST"); + } + else if (!nullsFirst && reverse) + { + appendStringInfoString(buf, " NULLS LAST"); + } +} + +/* + * Common code to show sort/group keys, which are represented in plan nodes + * as arrays of targetlist indexes. If it's a sort key rather than a group + * key, also pass sort operators/collations/nullsFirst arrays. + */ +static void +show_sort_group_keys(PlanState *planstate, const char *qlabel, + int nkeys, AttrNumber *keycols, + Oid *sortOperators, Oid *collations, bool *nullsFirst, + List *ancestors, ExplainState *es) +{ + Plan *plan = planstate->plan; + List *context; + List *result = NIL; + StringInfoData sortkeybuf; + bool useprefix; + int keyno; + + if (nkeys <= 0) + return; + + initStringInfo(&sortkeybuf); + + /* Set up deparsing context */ + context = set_deparse_context_planstate(es->deparse_cxt, + (Node *) planstate, + ancestors); + useprefix = (list_length(es->rtable) > 1 || es->verbose); + + for (keyno = 0; keyno < nkeys; keyno++) + { + /* find key expression in tlist */ + AttrNumber keyresno = keycols[keyno]; + TargetEntry *target = get_tle_by_resno(plan->targetlist, + keyresno); + char *exprstr; + + if (!target) + elog(ERROR, "no tlist entry for key %d", keyresno); + /* Deparse the expression, showing any top-level cast */ + exprstr = deparse_expression((Node *) target->expr, context, + useprefix, true); + resetStringInfo(&sortkeybuf); + appendStringInfoString(&sortkeybuf, exprstr); + /* Append sort order information, if relevant */ + if (sortOperators != NULL) + show_sortorder_options(&sortkeybuf, + (Node *) target->expr, + sortOperators[keyno], + collations[keyno], + nullsFirst[keyno]); + /* Emit one property-list item per sort key */ + result = lappend(result, pstrdup(sortkeybuf.data)); + } + + ExplainPropertyList(qlabel, result, es); +} diff --git a/contrib/pg_pathman/src/runtime_merge_append.h b/contrib/pg_pathman/src/runtime_merge_append.h new file mode 100644 index 0000000000..8dd8dcb116 --- /dev/null +++ b/contrib/pg_pathman/src/runtime_merge_append.h @@ -0,0 +1,81 @@ +/* ------------------------------------------------------------------------ + * + * runtime_merge_append.h + * RuntimeMergeAppend node's function prototypes and structures + * + * Copyright (c) 2016, Postgres Professional + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------ + */ + +#ifndef RUNTIME_MERGE_APPEND_H +#define RUNTIME_MERGE_APPEND_H + +#include "runtimeappend.h" +#include "pathman.h" + +#include "postgres.h" + + +typedef struct +{ + RuntimeAppendPath rpath; + + double limit_tuples; +} RuntimeMergeAppendPath; + +typedef struct +{ + RuntimeAppendState rstate; + + int numCols; /* number of sort-key columns */ + AttrNumber *sortColIdx; /* their indexes in the target list */ + Oid *sortOperators; /* OIDs of operators to sort them by */ + Oid *collations; /* OIDs of collations */ + bool *nullsFirst; /* NULLS FIRST/LAST directions */ + + int ms_nkeys; + SortSupport ms_sortkeys; + TupleTableSlot **ms_slots; + struct binaryheap *ms_heap; + bool ms_initialized; +} RuntimeMergeAppendState; + + +extern bool pg_pathman_enable_runtime_merge_append; + +extern CustomPathMethods runtime_merge_append_path_methods; +extern CustomScanMethods runtime_merge_append_plan_methods; +extern CustomExecMethods runtime_merge_append_exec_methods; + + +void init_runtime_merge_append_static_data(void); + +Path * create_runtimemergeappend_path(PlannerInfo *root, + AppendPath *inner_append, + ParamPathInfo *param_info, + double sel); + +Plan * create_runtimemergeappend_plan(PlannerInfo *root, RelOptInfo *rel, + CustomPath *best_path, List *tlist, + List *clauses, List *custom_plans); + +Node * runtimemergeappend_create_scan_state(CustomScan *node); + +void runtimemergeappend_begin(CustomScanState *node, + EState *estate, + int eflags); + +TupleTableSlot * runtimemergeappend_exec(CustomScanState *node); + +void runtimemergeappend_end(CustomScanState *node); + +void runtimemergeappend_rescan(CustomScanState *node); + +void runtimemergeappend_explain(CustomScanState *node, + List *ancestors, + ExplainState *es); + +#endif diff --git a/contrib/pg_pathman/src/runtimeappend.c b/contrib/pg_pathman/src/runtimeappend.c new file mode 100644 index 0000000000..7260ab2c0c --- /dev/null +++ b/contrib/pg_pathman/src/runtimeappend.c @@ -0,0 +1,156 @@ +/* ------------------------------------------------------------------------ + * + * runtimeappend.c + * RuntimeAppend node's function definitions and global variables + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "runtimeappend.h" + +#include "postgres.h" +#include "utils/memutils.h" +#include "utils/guc.h" + + +bool pg_pathman_enable_runtimeappend = true; + +CustomPathMethods runtimeappend_path_methods; +CustomScanMethods runtimeappend_plan_methods; +CustomExecMethods runtimeappend_exec_methods; + + +void +init_runtimeappend_static_data(void) +{ + runtimeappend_path_methods.CustomName = "RuntimeAppend"; + runtimeappend_path_methods.PlanCustomPath = create_runtimeappend_plan; + + runtimeappend_plan_methods.CustomName = "RuntimeAppend"; + runtimeappend_plan_methods.CreateCustomScanState = runtimeappend_create_scan_state; + + runtimeappend_exec_methods.CustomName = "RuntimeAppend"; + runtimeappend_exec_methods.BeginCustomScan = runtimeappend_begin; + runtimeappend_exec_methods.ExecCustomScan = runtimeappend_exec; + runtimeappend_exec_methods.EndCustomScan = runtimeappend_end; + runtimeappend_exec_methods.ReScanCustomScan = runtimeappend_rescan; + runtimeappend_exec_methods.MarkPosCustomScan = NULL; + runtimeappend_exec_methods.RestrPosCustomScan = NULL; + runtimeappend_exec_methods.ExplainCustomScan = runtimeappend_explain; + + DefineCustomBoolVariable("pg_pathman.enable_runtimeappend", + "Enables the planner's use of RuntimeAppend custom node.", + NULL, + &pg_pathman_enable_runtimeappend, + true, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); +} + +Path * +create_runtimeappend_path(PlannerInfo *root, + AppendPath *inner_append, + ParamPathInfo *param_info, + double sel) +{ + return create_append_path_common(root, inner_append, + param_info, + &runtimeappend_path_methods, + sizeof(RuntimeAppendPath), + sel); +} + +Plan * +create_runtimeappend_plan(PlannerInfo *root, RelOptInfo *rel, + CustomPath *best_path, List *tlist, + List *clauses, List *custom_plans) +{ + return create_append_plan_common(root, rel, + best_path, tlist, + clauses, custom_plans, + &runtimeappend_plan_methods); +} + +Node * +runtimeappend_create_scan_state(CustomScan *node) +{ + return create_append_scan_state_common(node, + &runtimeappend_exec_methods, + sizeof(RuntimeAppendState)); +} + +void +runtimeappend_begin(CustomScanState *node, EState *estate, int eflags) +{ + begin_append_common(node, estate, eflags); +} + +static void +fetch_next_tuple(CustomScanState *node) +{ + RuntimeAppendState *scan_state = (RuntimeAppendState *) node; + TupleTableSlot *slot = NULL; + + while (scan_state->running_idx < scan_state->ncur_plans) + { + ChildScanCommon child = scan_state->cur_plans[scan_state->running_idx]; + PlanState *state = child->content.plan_state; + bool quals; + + for (;;) + { + slot = ExecProcNode(state); + + if (TupIsNull(slot)) + break; + + node->ss.ps.ps_ExprContext->ecxt_scantuple = slot; + quals = ExecQual(scan_state->custom_expr_states, + node->ss.ps.ps_ExprContext, false); + + ResetExprContext(node->ss.ps.ps_ExprContext); + + if (quals) + { + scan_state->slot = slot; + return; + } + } + + scan_state->running_idx++; + } + + scan_state->slot = slot; + return; +} + +TupleTableSlot * +runtimeappend_exec(CustomScanState *node) +{ + return exec_append_common(node, fetch_next_tuple); +} + +void +runtimeappend_end(CustomScanState *node) +{ + end_append_common(node); +} + +void +runtimeappend_rescan(CustomScanState *node) +{ + rescan_append_common(node); +} + +void +runtimeappend_explain(CustomScanState *node, List *ancestors, ExplainState *es) +{ + RuntimeAppendState *scan_state = (RuntimeAppendState *) node; + + explain_append_common(node, scan_state->children_table, es); +} diff --git a/contrib/pg_pathman/src/runtimeappend.h b/contrib/pg_pathman/src/runtimeappend.h new file mode 100644 index 0000000000..55c1320e99 --- /dev/null +++ b/contrib/pg_pathman/src/runtimeappend.h @@ -0,0 +1,94 @@ +/* ------------------------------------------------------------------------ + * + * runtimeappend.h + * RuntimeAppend node's function prototypes and structures + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef RUNTIME_APPEND_H +#define RUNTIME_APPEND_H + +#include "pathman.h" +#include "nodes_common.h" + +#include "postgres.h" +#include "optimizer/paths.h" +#include "optimizer/pathnode.h" +#include "commands/explain.h" + + +typedef struct +{ + CustomPath cpath; + Oid relid; /* relid of the partitioned table */ + + ChildScanCommon *children; /* all available plans */ + int nchildren; +} RuntimeAppendPath; + +typedef struct +{ + CustomScanState css; + Oid relid; /* relid of the partitioned table */ + + /* Restrictions to be checked during ReScan and Exec */ + List *custom_exprs; + List *custom_expr_states; + + /* All available plans \ plan states */ + HTAB *children_table; + HASHCTL children_table_config; + + /* Currently selected plans \ plan states */ + ChildScanCommon *cur_plans; + int ncur_plans; + + /* Should we include parent table? Cached for prepared statements */ + bool enable_parent; + + /* Index of the selected plan state */ + int running_idx; + + /* Last saved tuple (for SRF projections) */ + TupleTableSlot *slot; +} RuntimeAppendState; + + +extern bool pg_pathman_enable_runtimeappend; + +extern CustomPathMethods runtimeappend_path_methods; +extern CustomScanMethods runtimeappend_plan_methods; +extern CustomExecMethods runtimeappend_exec_methods; + + +void init_runtimeappend_static_data(void); + +Path * create_runtimeappend_path(PlannerInfo *root, + AppendPath *inner_append, + ParamPathInfo *param_info, + double sel); + +Plan * create_runtimeappend_plan(PlannerInfo *root, RelOptInfo *rel, + CustomPath *best_path, List *tlist, + List *clauses, List *custom_plans); + +Node * runtimeappend_create_scan_state(CustomScan *node); + +void runtimeappend_begin(CustomScanState *node, + EState *estate, + int eflags); + +TupleTableSlot * runtimeappend_exec(CustomScanState *node); + +void runtimeappend_end(CustomScanState *node); + +void runtimeappend_rescan(CustomScanState *node); + +void runtimeappend_explain(CustomScanState *node, + List *ancestors, + ExplainState *es); + +#endif diff --git a/contrib/pg_pathman/src/utils.c b/contrib/pg_pathman/src/utils.c new file mode 100644 index 0000000000..b22c1fd0de --- /dev/null +++ b/contrib/pg_pathman/src/utils.c @@ -0,0 +1,728 @@ +/* ------------------------------------------------------------------------ + * + * utils.c + * definitions of various support functions + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "utils.h" + +#include "access/htup_details.h" +#include "access/nbtree.h" +#include "access/sysattr.h" +#include "access/xact.h" +#include "catalog/heap.h" +#include "catalog/pg_type.h" +#include "catalog/pg_extension.h" +#include "catalog/pg_proc.h" +#include "commands/extension.h" +#include "miscadmin.h" +#include "optimizer/var.h" +#include "optimizer/restrictinfo.h" +#include "parser/parse_oper.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" +#include "utils/syscache.h" +#include "utils/typcache.h" + + +#define TABLEOID_STR(subst) ( "pathman_tableoid" subst ) +#define TABLEOID_STR_BASE_LEN ( sizeof(TABLEOID_STR("")) - 1 ) + + +static bool clause_contains_params_walker(Node *node, void *context); +static void change_varnos_in_restrinct_info(RestrictInfo *rinfo, + change_varno_context *context); +static bool change_varno_walker(Node *node, change_varno_context *context); +static List *get_tableoids_list(List *tlist); +static void lock_rows_visitor(Plan *plan, void *context); +static bool rowmark_add_tableoids_walker(Node *node, void *context); + + +/* + * Check whether clause contains PARAMs or not + */ +bool +clause_contains_params(Node *clause) +{ + return expression_tree_walker(clause, + clause_contains_params_walker, + NULL); +} + +static bool +clause_contains_params_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + if (IsA(node, Param)) + return true; + return expression_tree_walker(node, + clause_contains_params_walker, + context); +} + +/* + * Extract target entries with resnames beginning with TABLEOID_STR + * and var->varoattno == TableOidAttributeNumber + */ +static List * +get_tableoids_list(List *tlist) +{ + List *result = NIL; + ListCell *lc; + + foreach (lc, tlist) + { + TargetEntry *te = (TargetEntry *) lfirst(lc); + Var *var = (Var *) te->expr; + + if (!IsA(var, Var)) + continue; + + /* Check that column name begins with TABLEOID_STR & it's tableoid */ + if (var->varoattno == TableOidAttributeNumber && + (te->resname && strlen(te->resname) > TABLEOID_STR_BASE_LEN) && + 0 == strncmp(te->resname, TABLEOID_STR(""), TABLEOID_STR_BASE_LEN)) + { + result = lappend(result, te); + } + } + + return result; +} + +/* + * Find 'TABLEOID_STR%u' attributes that were manually + * created for partitioned tables and replace Oids + * (used for '%u') with expected rc->rowmarkIds + */ +static void +lock_rows_visitor(Plan *plan, void *context) +{ + List *rtable = (List *) context; + LockRows *lock_rows = (LockRows *) plan; + Plan *lock_child = outerPlan(plan); + List *tableoids; + ListCell *lc; + + if (!IsA(lock_rows, LockRows)) + return; + + Assert(rtable && IsA(rtable, List) && lock_child); + + /* Select tableoid attributes that must be renamed */ + tableoids = get_tableoids_list(lock_child->targetlist); + if (!tableoids) + return; /* this LockRows has nothing to do with partitioned table */ + + foreach (lc, lock_rows->rowMarks) + { + PlanRowMark *rc = (PlanRowMark *) lfirst(lc); + Oid parent_oid = getrelid(rc->rti, rtable); + ListCell *mark_lc; + List *finished_tes = NIL; /* postprocessed target entries */ + + foreach (mark_lc, tableoids) + { + TargetEntry *te = (TargetEntry *) lfirst(mark_lc); + const char *cur_oid_str = &(te->resname[TABLEOID_STR_BASE_LEN]); + Datum cur_oid_datum; + + cur_oid_datum = DirectFunctionCall1(oidin, CStringGetDatum(cur_oid_str)); + + if (DatumGetObjectId(cur_oid_datum) == parent_oid) + { + char resname[64]; + + /* Replace 'TABLEOID_STR:Oid' with 'tableoid:rowmarkId' */ + snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId); + te->resname = pstrdup(resname); + + finished_tes = lappend(finished_tes, te); + } + } + + /* Remove target entries that have been processed in this step */ + foreach (mark_lc, finished_tes) + tableoids = list_delete_ptr(tableoids, lfirst(mark_lc)); + + if (list_length(tableoids) == 0) + break; /* nothing to do */ + } +} + +/* + * Print Bitmapset as cstring. + */ +#ifdef __GNUC__ +__attribute__((unused)) +#endif +static char * +bms_print(Bitmapset *bms) +{ + StringInfoData str; + int x; + + initStringInfo(&str); + x = -1; + while ((x = bms_next_member(bms, x)) >= 0) + appendStringInfo(&str, " %d", x); + + return str.data; +} + +/* + * Copied from util/plancat.c + * + * Build a targetlist representing the columns of the specified index. + */ +List * +build_index_tlist(PlannerInfo *root, IndexOptInfo *index, + Relation heapRelation) +{ + List *tlist = NIL; + Index varno = index->rel->relid; + ListCell *indexpr_item; + int i; + + indexpr_item = list_head(index->indexprs); + for (i = 0; i < index->ncolumns; i++) + { + int indexkey = index->indexkeys[i]; + Expr *indexvar; + + if (indexkey != 0) + { + /* simple column */ + Form_pg_attribute att_tup; + + if (indexkey < 0) + att_tup = SystemAttributeDefinition(indexkey, + heapRelation->rd_rel->relhasoids); + else + att_tup = heapRelation->rd_att->attrs[indexkey - 1]; + + indexvar = (Expr *) makeVar(varno, + indexkey, + att_tup->atttypid, + att_tup->atttypmod, + att_tup->attcollation, + 0); + } + else + { + /* expression column */ + if (indexpr_item == NULL) + elog(ERROR, "wrong number of index expressions"); + indexvar = (Expr *) lfirst(indexpr_item); + indexpr_item = lnext(indexpr_item); + } + + tlist = lappend(tlist, + makeTargetEntry(indexvar, + i + 1, + NULL, + false)); + } + if (indexpr_item != NULL) + elog(ERROR, "wrong number of index expressions"); + + return tlist; +} + +/* + * Get BTORDER_PROC for two types described by Oids + */ +void +fill_type_cmp_fmgr_info(FmgrInfo *finfo, Oid type1, Oid type2) +{ + Oid cmp_proc_oid; + TypeCacheEntry *tce; + + tce = lookup_type_cache(type1, TYPECACHE_BTREE_OPFAMILY); + + cmp_proc_oid = get_opfamily_proc(tce->btree_opf, + type1, + type2, + BTORDER_PROC); + + if (cmp_proc_oid == InvalidOid) + elog(ERROR, "missing comparison function for types %s & %s", + format_type_be(type1), format_type_be(type2)); + + fmgr_info(cmp_proc_oid, finfo); + + return; +} + +List * +list_reverse(List *l) +{ + List *result = NIL; + ListCell *lc; + + foreach (lc, l) + { + result = lcons(lfirst(lc), result); + } + return result; +} + +/* + * Changes varno attribute in all variables nested in the node + */ +void +change_varnos(Node *node, Oid old_varno, Oid new_varno) +{ + change_varno_context context; + context.old_varno = old_varno; + context.new_varno = new_varno; + + change_varno_walker(node, &context); +} + +static bool +change_varno_walker(Node *node, change_varno_context *context) +{ + ListCell *lc; + Var *var; + EquivalenceClass *ec; + EquivalenceMember *em; + + if (node == NULL) + return false; + + switch(node->type) + { + case T_Var: + var = (Var *) node; + if (var->varno == context->old_varno) + { + var->varno = context->new_varno; + var->varnoold = context->new_varno; + } + return false; + + case T_RestrictInfo: + change_varnos_in_restrinct_info((RestrictInfo *) node, context); + return false; + + case T_PathKey: + change_varno_walker((Node *) ((PathKey *) node)->pk_eclass, context); + return false; + + case T_EquivalenceClass: + ec = (EquivalenceClass *) node; + + foreach(lc, ec->ec_members) + change_varno_walker((Node *) lfirst(lc), context); + foreach(lc, ec->ec_derives) + change_varno_walker((Node *) lfirst(lc), context); + return false; + + case T_EquivalenceMember: + em = (EquivalenceMember *) node; + change_varno_walker((Node *) em->em_expr, context); + if (bms_is_member(context->old_varno, em->em_relids)) + { + em->em_relids = bms_del_member(em->em_relids, context->old_varno); + em->em_relids = bms_add_member(em->em_relids, context->new_varno); + } + return false; + + case T_TargetEntry: + change_varno_walker((Node *) ((TargetEntry *) node)->expr, context); + return false; + + case T_List: + foreach(lc, (List *) node) + change_varno_walker((Node *) lfirst(lc), context); + return false; + + default: + break; + } + + /* Should not find an unplanned subquery */ + Assert(!IsA(node, Query)); + + return expression_tree_walker(node, change_varno_walker, (void *) context); +} + +static void +change_varnos_in_restrinct_info(RestrictInfo *rinfo, change_varno_context *context) +{ + ListCell *lc; + + change_varno_walker((Node *) rinfo->clause, context); + if (rinfo->left_em) + change_varno_walker((Node *) rinfo->left_em->em_expr, context); + + if (rinfo->right_em) + change_varno_walker((Node *) rinfo->right_em->em_expr, context); + + if (rinfo->orclause) + foreach(lc, ((BoolExpr *) rinfo->orclause)->args) + { + Node *node = (Node *) lfirst(lc); + change_varno_walker(node, context); + } + + if (bms_is_member(context->old_varno, rinfo->clause_relids)) + { + rinfo->clause_relids = bms_del_member(rinfo->clause_relids, context->old_varno); + rinfo->clause_relids = bms_add_member(rinfo->clause_relids, context->new_varno); + } + if (bms_is_member(context->old_varno, rinfo->left_relids)) + { + rinfo->left_relids = bms_del_member(rinfo->left_relids, context->old_varno); + rinfo->left_relids = bms_add_member(rinfo->left_relids, context->new_varno); + } + if (bms_is_member(context->old_varno, rinfo->right_relids)) + { + rinfo->right_relids = bms_del_member(rinfo->right_relids, context->old_varno); + rinfo->right_relids = bms_add_member(rinfo->right_relids, context->new_varno); + } +} + +/* + * Basic plan tree walker + * + * 'visitor' is applied right before return + */ +void +plan_tree_walker(Plan *plan, + void (*visitor) (Plan *plan, void *context), + void *context) +{ + ListCell *l; + + if (plan == NULL) + return; + + check_stack_depth(); + + /* Plan-type-specific fixes */ + switch (nodeTag(plan)) + { + case T_SubqueryScan: + plan_tree_walker(((SubqueryScan *) plan)->subplan, visitor, context); + break; + + case T_CustomScan: + foreach(l, ((CustomScan *) plan)->custom_plans) + plan_tree_walker((Plan *) lfirst(l), visitor, context); + break; + + case T_ModifyTable: + foreach (l, ((ModifyTable *) plan)->plans) + plan_tree_walker((Plan *) lfirst(l), visitor, context); + break; + + /* Since they look alike */ + case T_MergeAppend: + case T_Append: + foreach(l, ((Append *) plan)->appendplans) + plan_tree_walker((Plan *) lfirst(l), visitor, context); + break; + + case T_BitmapAnd: + foreach(l, ((BitmapAnd *) plan)->bitmapplans) + plan_tree_walker((Plan *) lfirst(l), visitor, context); + break; + + case T_BitmapOr: + foreach(l, ((BitmapOr *) plan)->bitmapplans) + plan_tree_walker((Plan *) lfirst(l), visitor, context); + break; + + default: + break; + } + + plan_tree_walker(plan->lefttree, visitor, context); + plan_tree_walker(plan->righttree, visitor, context); + + /* Apply visitor to the current node */ + visitor(plan, context); +} + +static bool +rowmark_add_tableoids_walker(Node *node, void *context) +{ + if (node == NULL) + return false; + + if (IsA(node, Query)) + { + Query *parse = (Query *) node; + ListCell *lc; + + /* Generate 'tableoid' for partitioned table rowmark */ + foreach (lc, parse->rowMarks) + { + RowMarkClause *rc = (RowMarkClause *) lfirst(lc); + Oid parent = getrelid(rc->rti, parse->rtable); + Var *var; + TargetEntry *tle; + char resname[64]; + + /* Check that table is partitioned */ + if (!get_pathman_relation_info(parent)) + continue; + + var = makeVar(rc->rti, + TableOidAttributeNumber, + OIDOID, + -1, + InvalidOid, + 0); + + /* Use parent's Oid as TABLEOID_STR's key (%u) */ + snprintf(resname, sizeof(resname), TABLEOID_STR("%u"), parent); + + tle = makeTargetEntry((Expr *) var, + list_length(parse->targetList) + 1, + pstrdup(resname), + true); + + /* There's no problem here since new attribute is junk */ + parse->targetList = lappend(parse->targetList, tle); + } + + return query_tree_walker((Query *) node, + rowmark_add_tableoids_walker, + NULL, 0); + } + + return expression_tree_walker(node, rowmark_add_tableoids_walker, NULL); +} + +/* + * Add missing 'TABLEOID_STR%u' junk attributes for inherited partitions + * + * This is necessary since preprocess_targetlist() heavily + * depends on the 'inh' flag which we have to unset. + * + * postprocess_lock_rows() will later transform 'TABLEOID_STR:Oid' + * relnames into 'tableoid:rowmarkId'. + */ +void +rowmark_add_tableoids(Query *parse) +{ + rowmark_add_tableoids_walker((Node *) parse, NULL); +} + +/* + * Final rowmark processing for partitioned tables + */ +void +postprocess_lock_rows(List *rtable, Plan *plan) +{ + plan_tree_walker(plan, lock_rows_visitor, rtable); +} + +/* + * Returns pg_pathman schema's Oid or InvalidOid if that's not possible. + */ +Oid +get_pathman_schema(void) +{ + Oid result; + Relation rel; + SysScanDesc scandesc; + HeapTuple tuple; + ScanKeyData entry[1]; + Oid ext_schema; + + /* It's impossible to fetch pg_pathman's schema now */ + if (!IsTransactionState()) + return InvalidOid; + + ext_schema = get_extension_oid("pg_pathman", true); + if (ext_schema == InvalidOid) + return InvalidOid; /* exit if pg_pathman does not exist */ + + ScanKeyInit(&entry[0], + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(ext_schema)); + + rel = heap_open(ExtensionRelationId, AccessShareLock); + scandesc = systable_beginscan(rel, ExtensionOidIndexId, true, + NULL, 1, entry); + + tuple = systable_getnext(scandesc); + + /* We assume that there can be at most one matching tuple */ + if (HeapTupleIsValid(tuple)) + result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace; + else + result = InvalidOid; + + systable_endscan(scandesc); + + heap_close(rel, AccessShareLock); + + return result; +} + +/* + * Check if this is a "date"-related type. + */ +bool +is_date_type_internal(Oid typid) +{ + return typid == TIMESTAMPOID || + typid == TIMESTAMPTZOID || + typid == DATEOID; +} + +/* + * Check if this is a string type. + */ +bool +is_string_type_internal(Oid typid) +{ + return typid == TEXTOID || + typid == CSTRINGOID; +} + + +/* + * Try to find binary operator. + * + * Returns operator function's Oid or throws an ERROR on InvalidOid. + */ +Oid +get_binary_operator_oid(char *oprname, Oid arg1, Oid arg2) +{ + Oid funcid = InvalidOid; + Operator op; + + op = oper(NULL, list_make1(makeString(oprname)), arg1, arg2, true, -1); + if (op) + { + funcid = oprfuncid(op); + ReleaseSysCache(op); + } + else + elog(ERROR, "Cannot find operator \"%s\"(%u, %u)", oprname, arg1, arg2); + + return funcid; +} + +/* + * Get CSTRING representation of Datum using the type Oid. + */ +char * +datum_to_cstring(Datum datum, Oid typid) +{ + char *result; + HeapTuple tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + + if (HeapTupleIsValid(tup)) + { + Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tup); + result = OidOutputFunctionCall(typtup->typoutput, datum); + ReleaseSysCache(tup); + } + else + result = pstrdup("[error]"); + + return result; +} + +/* + * Try to get relname or at least relid as cstring. + */ +char * +get_rel_name_or_relid(Oid relid) +{ + char *relname = get_rel_name(relid); + + if (!relname) + return DatumGetCString(DirectFunctionCall1(oidout, + ObjectIdGetDatum(relid))); + return relname; +} + +/* + * Try to get opname or at least opid as cstring. + */ +char * +get_op_name_or_opid(Oid opid) +{ + char *opname = get_opname(opid); + + if (!opname) + return DatumGetCString(DirectFunctionCall1(oidout, + ObjectIdGetDatum(opid))); + return opname; +} + + +#if PG_VERSION_NUM < 90600 +/* + * Returns the relpersistence associated with a given relation. + * + * NOTE: this function is implemented in 9.6 + */ +char +get_rel_persistence(Oid relid) +{ + HeapTuple tp; + Form_pg_class reltup; + char result; + + tp = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for relation %u", relid); + + reltup = (Form_pg_class) GETSTRUCT(tp); + result = reltup->relpersistence; + ReleaseSysCache(tp); + + return result; +} +#endif + +/* + * Checks that callback function meets specific requirements. + * It must have the only JSONB argument and BOOL return type. + */ +bool +validate_on_part_init_cb(Oid procid, bool emit_error) +{ + HeapTuple tp; + Form_pg_proc functup; + bool is_ok = true; + + if (procid == InvalidOid) + return true; + + tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(procid)); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for function %u", procid); + + functup = (Form_pg_proc) GETSTRUCT(tp); + + if (functup->pronargs != 1 || + functup->proargtypes.values[0] != JSONBOID || + functup->prorettype != VOIDOID) + is_ok = false; + + ReleaseSysCache(tp); + + if (emit_error && !is_ok) + elog(ERROR, + "Callback function must have the following signature: " + "callback(arg JSONB) RETURNS VOID"); + + return is_ok; +} diff --git a/contrib/pg_pathman/src/utils.h b/contrib/pg_pathman/src/utils.h new file mode 100644 index 0000000000..1b2af2ee56 --- /dev/null +++ b/contrib/pg_pathman/src/utils.h @@ -0,0 +1,76 @@ +/* ------------------------------------------------------------------------ + * + * utils.h + * prototypes of various support functions + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef PATHMAN_UTILS_H +#define PATHMAN_UTILS_H + +#include "pathman.h" + +#include "postgres.h" +#include "utils/rel.h" +#include "nodes/relation.h" +#include "nodes/nodeFuncs.h" + + +typedef struct +{ + Oid old_varno; + Oid new_varno; +} change_varno_context; + + +/* + * Plan tree modification. + */ +void plan_tree_walker(Plan *plan, + void (*visitor) (Plan *plan, void *context), + void *context); +List * build_index_tlist(PlannerInfo *root, + IndexOptInfo *index, + Relation heapRelation); +void change_varnos(Node *node, Oid old_varno, Oid new_varno); + +/* + * Rowmark processing. + */ +void rowmark_add_tableoids(Query *parse); +void postprocess_lock_rows(List *rtable, Plan *plan); + +/* + * Various traits. + */ +bool clause_contains_params(Node *clause); +bool is_date_type_internal(Oid typid); +bool is_string_type_internal(Oid typid); +bool validate_on_part_init_cb(Oid procid, bool emit_error); + +/* + * Misc. + */ +Oid get_pathman_schema(void); +List * list_reverse(List *l); + +#if PG_VERSION_NUM < 90600 +char get_rel_persistence(Oid relid); +#endif + +/* + * Handy execution-stage functions. + */ +char * get_rel_name_or_relid(Oid relid); +char * get_op_name_or_opid(Oid opid); + +Oid get_binary_operator_oid(char *opname, Oid arg1, Oid arg2); +void fill_type_cmp_fmgr_info(FmgrInfo *finfo, + Oid type1, + Oid type2); +char * datum_to_cstring(Datum datum, Oid typid); + +#endif diff --git a/contrib/pg_pathman/src/xact_handling.c b/contrib/pg_pathman/src/xact_handling.c new file mode 100644 index 0000000000..44d9195bd0 --- /dev/null +++ b/contrib/pg_pathman/src/xact_handling.c @@ -0,0 +1,190 @@ +/* ------------------------------------------------------------------------ + * + * xact_handling.c + * Transaction-specific locks and other functions + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#include "xact_handling.h" + +#include "postgres.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "miscadmin.h" +#include "storage/lmgr.h" + + +static inline void SetLocktagRelationOid(LOCKTAG *tag, Oid relid); +static inline bool do_we_hold_the_lock(Oid relid, LOCKMODE lockmode); + + +/* + * Lock certain partitioned relation to disable concurrent access. + */ +bool +xact_lock_partitioned_rel(Oid relid, bool nowait) +{ + if (nowait) + { + if (ConditionalLockRelationOid(relid, ShareUpdateExclusiveLock)) + return true; + return false; + } + else + LockRelationOid(relid, ShareUpdateExclusiveLock); + + return true; +} + +/* + * Unlock partitioned relation. + */ +void +xact_unlock_partitioned_rel(Oid relid) +{ + UnlockRelationOid(relid, ShareUpdateExclusiveLock); +} + +/* + * Lock relation exclusively (SELECTs are possible). + */ +bool +xact_lock_rel_exclusive(Oid relid, bool nowait) +{ + if (nowait) + { + if (ConditionalLockRelationOid(relid, ExclusiveLock)) + return true; + return false; + } + else + LockRelationOid(relid, ExclusiveLock); + + return true; +} + +/* + * Unlock relation (exclusive lock). + */ +void +xact_unlock_rel_exclusive(Oid relid) +{ + UnlockRelationOid(relid, ExclusiveLock); +} + +/* + * Check whether we already hold a lock that + * might conflict with partition spawning BGW. + */ +bool +xact_bgw_conflicting_lock_exists(Oid relid) +{ + LOCKMODE lockmode; + + /* Try each lock >= ShareUpdateExclusiveLock */ + for (lockmode = ShareUpdateExclusiveLock; + lockmode <= AccessExclusiveLock; + lockmode++) + { + if (do_we_hold_the_lock(relid, lockmode)) + return true; + } + + return false; +} + + +/* + * Check if current transaction's level is READ COMMITTED. + */ +bool +xact_is_level_read_committed(void) +{ + if (XactIsoLevel <= XACT_READ_COMMITTED) + return true; + + return false; +} + +/* + * Check if 'stmt' is BEGIN\ROLLBACK etc transaction statement. + */ +bool +xact_is_transaction_stmt(Node *stmt) +{ + if (!stmt) + return false; + + if (IsA(stmt, TransactionStmt)) + return true; + + return false; +} + +/* + * Check if 'stmt' is SET TRANSACTION statement. + */ +bool +xact_is_set_transaction_stmt(Node *stmt) +{ + if (!stmt) + return false; + + if (IsA(stmt, VariableSetStmt)) + { + VariableSetStmt *var_set_stmt = (VariableSetStmt *) stmt; + + /* special case for SET TRANSACTION ... */ + if (var_set_stmt->kind == VAR_SET_MULTI) + return true; + } + + return false; +} + +/* + * Do we hold the specified lock? + */ +static inline bool +do_we_hold_the_lock(Oid relid, LOCKMODE lockmode) +{ + LOCKTAG tag; + + /* Create a tag for lock */ + SetLocktagRelationOid(&tag, relid); + + /* If lock is alredy held, release it one time (decrement) */ + switch (LockAcquire(&tag, lockmode, false, true)) + { + case LOCKACQUIRE_ALREADY_HELD: + LockRelease(&tag, lockmode, false); + return true; + + case LOCKACQUIRE_OK: + LockRelease(&tag, lockmode, false); + return false; + + default: + return false; + } +} + +/* + * SetLocktagRelationOid + * Set up a locktag for a relation, given only relation OID + */ +static inline void +SetLocktagRelationOid(LOCKTAG *tag, Oid relid) +{ + Oid dbid; + + if (IsSharedRelation(relid)) + dbid = InvalidOid; + else + dbid = MyDatabaseId; + + SET_LOCKTAG_RELATION(*tag, dbid, relid); +} diff --git a/contrib/pg_pathman/src/xact_handling.h b/contrib/pg_pathman/src/xact_handling.h new file mode 100644 index 0000000000..b5f8ed3c6c --- /dev/null +++ b/contrib/pg_pathman/src/xact_handling.h @@ -0,0 +1,36 @@ +/* ------------------------------------------------------------------------ + * + * xact_handling.h + * Transaction-specific locks and other functions + * + * Copyright (c) 2016, Postgres Professional + * + * ------------------------------------------------------------------------ + */ + +#ifndef XACT_HANDLING_H +#define XACT_HANDLING_H + +#include "pathman.h" + +#include "postgres.h" + + +/* + * Transaction locks. + */ +bool xact_lock_partitioned_rel(Oid relid, bool nowait); +void xact_unlock_partitioned_rel(Oid relid); + +bool xact_lock_rel_exclusive(Oid relid, bool nowait); +void xact_unlock_rel_exclusive(Oid relid); + +/* + * Utility checks. + */ +bool xact_bgw_conflicting_lock_exists(Oid relid); +bool xact_is_level_read_committed(void); +bool xact_is_transaction_stmt(Node *stmt); +bool xact_is_set_transaction_stmt(Node *stmt); + +#endif diff --git a/contrib/pg_pathman/tests/README.md b/contrib/pg_pathman/tests/README.md new file mode 100644 index 0000000000..8d07cc445b --- /dev/null +++ b/contrib/pg_pathman/tests/README.md @@ -0,0 +1,34 @@ +# Tests + +This directory contains script to tests some features which cannot be tested +with only regression tests + +## Running + +First of all you need to install `testgres` python module which contains useful +functions to start postgres clusters and make queries: + +``` +pip install testgres +``` + +To run tests execute: + +``` +python -m unittest partitioning_test +``` + +from current directory. If you want to run a specific postgres build then +you should specify the path to your pg_config executable by setting PG_CONFIG +environment variable: + +``` +export PG_CONFIG=/path/to/pg_config +``` + +To test FDW features you need to install postgres_fdw contrib module first. +If you want to skip FDW tests set the FDW_DISABLED environment variable: + +``` +export FDW_DISABLED=1 +``` diff --git a/contrib/pg_pathman/tests/__init__.py b/contrib/pg_pathman/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/contrib/pg_pathman/tests/partitioning_test.py b/contrib/pg_pathman/tests/partitioning_test.py new file mode 100644 index 0000000000..c71c9b9ba5 --- /dev/null +++ b/contrib/pg_pathman/tests/partitioning_test.py @@ -0,0 +1,411 @@ +# coding: utf-8 +""" + concurrent_partitioning_test.py + Tests concurrent partitioning worker with simultaneous update queries + + Copyright (c) 2015-2016, Postgres Professional +""" + +import unittest +from testgres import get_new_node, stop_all +import time +import os + + +def if_fdw_enabled(func): + """To run tests with FDW support set environment variable TEST_FDW=1""" + def wrapper(*args, **kwargs): + if os.environ.get('FDW_DISABLED') != '1': + func(*args, **kwargs) + else: + print('Warning: FDW features tests are disabled, skipping...') + return wrapper + + +class PartitioningTests(unittest.TestCase): + + def setUp(self): + self.setup_cmd = [ + # 'create extension pg_pathman', + 'create table abc(id serial, t text)', + 'insert into abc select generate_series(1, 300000)', + 'select create_hash_partitions(\'abc\', \'id\', 3, partition_data := false)', + ] + + def tearDown(self): + stop_all() + # clean_all() + + def start_new_pathman_cluster(self, name='test', allows_streaming=False): + node = get_new_node(name) + node.init(allows_streaming=allows_streaming) + node.append_conf( + 'postgresql.conf', + 'shared_preload_libraries=\'pg_pathman\'\n') + node.start() + node.psql('postgres', 'create extension pg_pathman') + return node + + def init_test_data(self, node): + """Initialize pg_pathman extension and test data""" + for cmd in self.setup_cmd: + node.safe_psql('postgres', cmd) + + def catchup_replica(self, master, replica): + """Wait until replica synchronizes with master""" + master.poll_query_until( + 'postgres', + 'SELECT pg_current_xlog_location() <= replay_location ' + 'FROM pg_stat_replication WHERE application_name = \'%s\'' + % replica.name) + + def printlog(self, logfile): + with open(logfile, 'r') as log: + for line in log.readlines(): + print(line) + + def test_concurrent(self): + """Tests concurrent partitioning""" + try: + node = self.start_new_pathman_cluster() + self.init_test_data(node) + + node.psql( + 'postgres', + 'select partition_table_concurrently(\'abc\')') + + while True: + # update some rows to check for deadlocks + node.safe_psql( + 'postgres', + ''' + update abc set t = 'test' + where id in (select (random() * 300000)::int + from generate_series(1, 3000)) + ''') + + count = node.execute( + 'postgres', + 'select count(*) from pathman_concurrent_part_tasks') + + # if there is no active workers then it means work is done + if count[0][0] == 0: + break + time.sleep(1) + + data = node.execute('postgres', 'select count(*) from only abc') + self.assertEqual(data[0][0], 0) + data = node.execute('postgres', 'select count(*) from abc') + self.assertEqual(data[0][0], 300000) + + node.stop() + except Exception, e: + self.printlog(node.logs_dir + '/postgresql.log') + raise e + + def test_replication(self): + """Tests how pg_pathman works with replication""" + node = get_new_node('master') + replica = get_new_node('repl') + + try: + # initialize master server + node = self.start_new_pathman_cluster(allows_streaming=True) + node.backup('my_backup') + + # initialize replica from backup + replica.init_from_backup(node, 'my_backup', has_streaming=True) + replica.start() + + # initialize pg_pathman extension and some test data + self.init_test_data(node) + + # wait until replica catches up + self.catchup_replica(node, replica) + + # check that results are equal + self.assertEqual( + node.psql('postgres', 'explain (costs off) select * from abc'), + replica.psql('postgres', 'explain (costs off) select * from abc') + ) + + # enable parent and see if it is enabled in replica + node.psql('postgres', 'select enable_parent(\'abc\'') + + self.catchup_replica(node, replica) + self.assertEqual( + node.psql('postgres', 'explain (costs off) select * from abc'), + replica.psql('postgres', 'explain (costs off) select * from abc') + ) + self.assertEqual( + node.psql('postgres', 'select * from abc'), + replica.psql('postgres', 'select * from abc') + ) + self.assertEqual( + node.execute('postgres', 'select count(*) from abc')[0][0], + 300000 + ) + + # check that direct UPDATE in pathman_config_params invalidates + # cache + node.psql( + 'postgres', + 'update pathman_config_params set enable_parent = false') + self.catchup_replica(node, replica) + self.assertEqual( + node.psql('postgres', 'explain (costs off) select * from abc'), + replica.psql('postgres', 'explain (costs off) select * from abc') + ) + self.assertEqual( + node.psql('postgres', 'select * from abc'), + replica.psql('postgres', 'select * from abc') + ) + self.assertEqual( + node.execute('postgres', 'select count(*) from abc')[0][0], + 0 + ) + except Exception, e: + self.printlog(node.logs_dir + '/postgresql.log') + self.printlog(replica.logs_dir + '/postgresql.log') + raise e + + def test_locks(self): + """Test that a session trying to create new partitions waits for other + sessions if they doing the same""" + + import threading + import time + + class Flag: + def __init__(self, value): + self.flag = value + + def set(self, value): + self.flag = value + + def get(self): + return self.flag + + # There is one flag for each thread which shows if thread have done + # its work + flags = [Flag(False) for i in xrange(3)] + + # All threads synchronizes though this lock + lock = threading.Lock() + + # Define thread function + def add_partition(node, flag, query): + """ We expect that this query will wait until another session + commits or rolls back""" + node.safe_psql('postgres', query) + with lock: + flag.set(True) + + # Initialize master server + node = get_new_node('master') + + try: + node.init() + node.append_conf( + 'postgresql.conf', + 'shared_preload_libraries=\'pg_pathman\'\n') + node.start() + node.safe_psql( + 'postgres', + 'create extension pg_pathman; ' + + 'create table abc(id serial, t text); ' + + 'insert into abc select generate_series(1, 100000); ' + + 'select create_range_partitions(\'abc\', \'id\', 1, 50000);' + ) + + # Start transaction that will create partition + con = node.connect() + con.begin() + con.execute('select append_range_partition(\'abc\')') + + # Start threads that suppose to add new partitions and wait some + # time + query = [ + 'select prepend_range_partition(\'abc\')', + 'select append_range_partition(\'abc\')', + 'select add_range_partition(\'abc\', 500000, 550000)', + ] + threads = [] + for i in range(3): + thread = threading.Thread( + target=add_partition, + args=(node, flags[i], query[i])) + threads.append(thread) + thread.start() + time.sleep(3) + + # This threads should wait until current transaction finished + with lock: + for i in range(3): + self.assertEqual(flags[i].get(), False) + + # Commit transaction. Since then other sessions can create + # partitions + con.commit() + + # Now wait until each thread finishes + for thread in threads: + thread.join() + + # Check flags, it should be true which means that threads are + # finished + with lock: + for i in range(3): + self.assertEqual(flags[i].get(), True) + + # Check that all partitions are created + self.assertEqual( + node.safe_psql( + 'postgres', + 'select count(*) from pg_inherits where inhparent=\'abc\'::regclass' + ), + '6\n' + ) + except Exception, e: + self.printlog(node.logs_dir + '/postgresql.log') + raise e + + def test_tablespace(self): + """Check tablespace support""" + + def check_tablespace(node, tablename, tablespace): + res = node.execute( + 'postgres', + 'select get_rel_tablespace_name(\'{}\')'.format(tablename)) + if len(res) == 0: + return False + + return res[0][0] == tablespace + + node = get_new_node('master') + node.init() + node.append_conf( + 'postgresql.conf', + 'shared_preload_libraries=\'pg_pathman\'\n') + node.start() + node.psql('postgres', 'create extension pg_pathman') + + # create tablespace + path = os.path.join(node.data_dir, 'test_space_location') + os.mkdir(path) + node.psql( + 'postgres', + 'create tablespace test_space location \'{}\''.format(path)) + + # create table in this tablespace + node.psql( + 'postgres', + 'create table abc(a serial, b int) tablespace test_space') + + # create three partitions. Excpect that they will be created in the + # same tablespace as the parent table + node.psql( + 'postgres', + 'select create_range_partitions(\'abc\', \'a\', 1, 10, 3)') + self.assertTrue(check_tablespace(node, 'abc', 'test_space')) + + # check tablespace for appended partition + node.psql( + 'postgres', + 'select append_range_partition(\'abc\', \'abc_appended\')') + self.assertTrue(check_tablespace(node, 'abc_appended', 'test_space')) + + # check tablespace for prepended partition + node.psql( + 'postgres', + 'select prepend_range_partition(\'abc\', \'abc_prepended\')') + self.assertTrue(check_tablespace(node, 'abc_prepended', 'test_space')) + + # check tablespace for prepended partition + node.psql( + 'postgres', + 'select add_range_partition(\'abc\', 41, 51, \'abc_added\')') + self.assertTrue(check_tablespace(node, 'abc_added', 'test_space')) + + # now let's specify tablespace explicitly + node.psql( + 'postgres', + 'select append_range_partition(\'abc\', \'abc_appended_2\', \'pg_default\')') + node.psql( + 'postgres', + 'select prepend_range_partition(\'abc\', \'abc_prepended_2\', \'pg_default\')') + node.psql( + 'postgres', + 'select add_range_partition(\'abc\', 61, 71, \'abc_added_2\', \'pg_default\')') + self.assertTrue(check_tablespace(node, 'abc_appended_2', 'pg_default')) + self.assertTrue(check_tablespace(node, 'abc_prepended_2', 'pg_default')) + self.assertTrue(check_tablespace(node, 'abc_added_2', 'pg_default')) + + @if_fdw_enabled + def test_foreign_table(self): + """Test foreign tables""" + + # Start master server + master = get_new_node('test') + master.init() + master.append_conf( + 'postgresql.conf', + 'shared_preload_libraries=\'pg_pathman, postgres_fdw\'\n') + master.start() + master.psql('postgres', 'create extension pg_pathman') + master.psql('postgres', 'create extension postgres_fdw') + master.psql( + 'postgres', + '''create table abc(id serial, name text); + select create_range_partitions('abc', 'id', 0, 10, 2)''') + + # Current user name (needed for user mapping) + username = master.execute('postgres', 'select current_user')[0][0] + + # Start foreign server + fserv = get_new_node('fserv') + fserv.init().start() + fserv.safe_psql('postgres', 'create table ftable(id serial, name text)') + fserv.safe_psql('postgres', 'insert into ftable values (25, \'foreign\')') + + # Create foreign table and attach it to partitioned table + master.safe_psql( + 'postgres', + '''create server fserv + foreign data wrapper postgres_fdw + options (dbname 'postgres', host '127.0.0.1', port '{}')'''.format(fserv.port) + ) + master.safe_psql( + 'postgres', + '''create user mapping for {0} + server fserv + options (user '{0}')'''.format(username) + ) + master.safe_psql( + 'postgres', + '''import foreign schema public limit to (ftable) + from server fserv into public''' + ) + master.safe_psql( + 'postgres', + 'select attach_range_partition(\'abc\', \'ftable\', 20, 30)') + + # Check that table attached to partitioned table + self.assertEqual( + master.safe_psql('postgres', 'select * from ftable'), + '25|foreign\n' + ) + + # Check that we can successfully insert new data into foreign partition + master.safe_psql('postgres', 'insert into abc values (26, \'part\')') + self.assertEqual( + master.safe_psql('postgres', 'select * from ftable order by id'), + '25|foreign\n26|part\n' + ) + + # Testing drop partitions (including foreign partitions) + master.safe_psql('postgres', 'select drop_partitions(\'abc\')') + + +if __name__ == "__main__": + unittest.main() diff --git a/contrib/pg_pathman/travis/apt.postgresql.org.sh b/contrib/pg_pathman/travis/apt.postgresql.org.sh new file mode 100644 index 0000000000..22814fa7d2 --- /dev/null +++ b/contrib/pg_pathman/travis/apt.postgresql.org.sh @@ -0,0 +1,136 @@ +#!/bin/sh + +# script to add apt.postgresql.org to sources.list + +# from command like +CODENAME="$1" +# lsb_release is the best interface, but not always available +if [ -z "$CODENAME" ]; then + CODENAME=$(lsb_release -cs 2>/dev/null) +fi +# parse os-release (unreliable, does not work on Ubuntu) +if [ -z "$CODENAME" -a -f /etc/os-release ]; then + . /etc/os-release + # Debian: VERSION="7.0 (wheezy)" + # Ubuntu: VERSION="13.04, Raring Ringtail" + CODENAME=$(echo $VERSION | sed -ne 's/.*(\(.*\)).*/\1/') +fi +# guess from sources.list +if [ -z "$CODENAME" ]; then + CODENAME=$(grep '^deb ' /etc/apt/sources.list | head -n1 | awk '{ print $3 }') +fi +# complain if no result yet +if [ -z "$CODENAME" ]; then + cat < /etc/apt/sources.list.d/pgdg.list < cppcheck.log + + if [ -s cppcheck.log ]; then + cat cppcheck.log + status=1 # error + fi + + exit $status + fi + + # don't forget to "make clean" + make clean USE_PGXS=1 PG_CONFIG=$config_path +fi + +# build pg_pathman +make USE_PGXS=1 PG_CONFIG=$config_path +sudo make install USE_PGXS=1 PG_CONFIG=$config_path + +# add pg_pathman to shared_preload_libraries and restart cluster 'test' +sudo bash -c "echo \"shared_preload_libraries = 'pg_pathman'\" >> /etc/postgresql/$PGVERSION/test/postgresql.conf" +sudo pg_ctlcluster $PGVERSION test restart + +# run regression tests +PGPORT=55435 make installcheck USE_PGXS=1 PGUSER=postgres PG_CONFIG=$config_path || status=$? + +# show diff if it exists +if test -f regression.diffs; then cat regression.diffs; fi + +set +u + +# create a virtual environment and activate it +virtualenv /tmp/envs/pg_pathman +source /tmp/envs/pg_pathman/bin/activate + +# install pip packages +pip install $pip_packages + +# set permission to write postgres locks +sudo chmod a+w /var/run/postgresql/ + +# run python tests +cd tests +PG_CONFIG=$config_path python -m unittest partitioning_test || status=$? + +set -u + +exit $status diff --git a/contrib/pg_pathman/worker.c b/contrib/pg_pathman/worker.c deleted file mode 100644 index d2f280a7fd..0000000000 --- a/contrib/pg_pathman/worker.c +++ /dev/null @@ -1,211 +0,0 @@ -#include "pathman.h" -#include "miscadmin.h" -#include "postmaster/bgworker.h" -#include "catalog/pg_type.h" -#include "executor/spi.h" -#include "storage/dsm.h" -#include "access/xact.h" -#include "utils/snapmgr.h" -#include "utils/typcache.h" - -/*------------------------------------------------------------------------- - * - * worker.c - * - * The purpose of this module is to create partitions in a separate - * transaction. To do so we create a separate background worker, - * pass arguments to it (see PartitionArgs) and gather the result - * (which is the new partition oid). - * - *------------------------------------------------------------------------- - */ - -static dsm_segment *segment; - -static void bg_worker_main(Datum main_arg); - -typedef struct PartitionArgs -{ - Oid dbid; - Oid relid; - #ifdef HAVE_INT64_TIMESTAMP - int64 value; - #else - double value; - #endif - Oid value_type; - bool by_val; - Oid result; - bool crashed; -} PartitionArgs; - -/* - * Starts background worker that will create new partitions, - * waits till it finishes the job and returns the result (new partition oid) - */ -Oid -create_partitions_bg_worker(Oid relid, Datum value, Oid value_type, bool *crashed) -{ - BackgroundWorker worker; - BackgroundWorkerHandle *worker_handle; - BgwHandleStatus status; - dsm_segment *segment; - dsm_handle segment_handle; - pid_t pid; - PartitionArgs *args; - Oid child_oid; - TypeCacheEntry *tce; - - /* Create a dsm segment for the worker to pass arguments */ - segment = dsm_create(sizeof(PartitionArgs), 0); - segment_handle = dsm_segment_handle(segment); - - tce = lookup_type_cache(value_type, 0); - - /* Fill arguments structure */ - args = (PartitionArgs *) dsm_segment_address(segment); - args->dbid = MyDatabaseId; - args->relid = relid; - if (tce->typbyval) - args->value = value; - else - memcpy(&args->value, DatumGetPointer(value), sizeof(args->value)); - args->by_val = tce->typbyval; - args->value_type = value_type; - args->result = 0; - - /* Initialize worker struct */ - worker.bgw_flags = BGWORKER_SHMEM_ACCESS | - BGWORKER_BACKEND_DATABASE_CONNECTION; - worker.bgw_start_time = BgWorkerStart_RecoveryFinished; - worker.bgw_restart_time = BGW_NEVER_RESTART; - worker.bgw_main = bg_worker_main; - worker.bgw_main_arg = Int32GetDatum(segment_handle); - worker.bgw_notify_pid = MyProcPid; - - /* Start dynamic worker */ - if (!RegisterDynamicBackgroundWorker(&worker, &worker_handle)) - { - elog(WARNING, "Unable to create background worker for pg_pathman"); - } - - status = WaitForBackgroundWorkerStartup(worker_handle, &pid); - if (status == BGWH_POSTMASTER_DIED) - { - ereport(WARNING, - (errmsg("Postmaster died during the pg_pathman background worker process"), - errhint("More details may be available in the server log."))); - } - - /* Wait till the worker finishes its job */ - status = WaitForBackgroundWorkerShutdown(worker_handle); - *crashed = args->crashed; - child_oid = args->result; - - /* Free dsm segment */ - dsm_detach(segment); - - return child_oid; -} - -/* - * Main worker routine. Accepts dsm_handle as an argument - */ -static void -bg_worker_main(Datum main_arg) -{ - PartitionArgs *args; - dsm_handle handle = DatumGetInt32(main_arg); - - /* Create resource owner */ - CurrentResourceOwner = ResourceOwnerCreate(NULL, "CreatePartitionsWorker"); - - /* Attach to dynamic shared memory */ - if (!handle) - { - ereport(WARNING, - (errmsg("pg_pathman worker: invalid dsm_handle"))); - } - segment = dsm_attach(handle); - args = dsm_segment_address(segment); - - /* Establish connection and start transaction */ - BackgroundWorkerInitializeConnectionByOid(args->dbid, InvalidOid); - StartTransactionCommand(); - SPI_connect(); - PushActiveSnapshot(GetTransactionSnapshot()); - - /* Create partitions */ - args->result = create_partitions(args->relid, PATHMAN_GET_DATUM(args->value, args->by_val), args->value_type, &args->crashed); - - /* Cleanup */ - SPI_finish(); - PopActiveSnapshot(); - CommitTransactionCommand(); - - dsm_detach(segment); -} - -/* - * Create partitions and return an OID of the partition that contain value - */ -Oid -create_partitions(Oid relid, Datum value, Oid value_type, bool *crashed) -{ - int ret; - RangeEntry *ranges; - Datum vals[2]; - Oid oids[] = {OIDOID, value_type}; - bool nulls[] = {false, false}; - char *sql; - bool found; - int pos; - PartRelationInfo *prel; - RangeRelation *rangerel; - FmgrInfo cmp_func; - char *schema; - - *crashed = false; - schema = get_extension_schema(); - - prel = get_pathman_relation_info(relid, NULL); - rangerel = get_pathman_range_relation(relid, NULL); - ranges = dsm_array_get_pointer(&rangerel->ranges); - - /* Comparison function */ - cmp_func = *get_cmp_func(value_type, prel->atttype); - - vals[0] = ObjectIdGetDatum(relid); - vals[1] = value; - - /* Perform PL procedure */ - sql = psprintf("SELECT %s.append_partitions_on_demand_internal($1, $2)", - schema); - PG_TRY(); - { - ret = SPI_execute_with_args(sql, 2, oids, vals, nulls, false, 0); - if (ret > 0) - { - /* Update relation info */ - free_dsm_array(&rangerel->ranges); - free_dsm_array(&prel->children); - load_check_constraints(relid, GetCatalogSnapshot(relid)); - } - } - PG_CATCH(); - { - elog(WARNING, "Attempt to create new partitions failed"); - if (crashed != NULL) - *crashed = true; - return 0; - } - PG_END_TRY(); - - /* Repeat binary search */ - ranges = dsm_array_get_pointer(&rangerel->ranges); - pos = range_binary_search(rangerel, &cmp_func, value, &found); - if (found) - return ranges[pos].child_oid; - - return 0; -} diff --git a/contrib/pg_query_state/Makefile b/contrib/pg_query_state/Makefile new file mode 100644 index 0000000000..c01ef3f6c4 --- /dev/null +++ b/contrib/pg_query_state/Makefile @@ -0,0 +1,45 @@ +# contrib/pg_query_state/Makefile + +MODULE_big = pg_query_state +OBJS = pg_query_state.o signal_handler.o $(WIN32RES) +EXTENSION = pg_query_state +EXTVERSION = 1.0 +DATA = $(EXTENSION)--$(EXTVERSION).sql +PGFILEDESC = "pg_query_state - facility to track progress of plan execution" + +EXTRA_CLEAN = ./isolation_output + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = contrib/pg_query_state +top_builddir = ../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif + +check: isolationcheck + +ISOLATIONCHECKS=corner_cases + +submake-isolation: + $(MAKE) -C $(top_builddir)/src/test/isolation all + +isolationcheck: | submake-isolation temp-install + $(MKDIR_P) isolation_output + $(pg_isolation_regress_check) \ + --temp-config $(top_srcdir)/contrib/pg_query_state/test.conf \ + --outputdir=isolation_output \ + $(ISOLATIONCHECKS) + +isolationcheck-install-force: all | submake-isolation temp-install + $(MKDIR_P) isolation_output + $(pg_isolation_regress_installcheck) \ + --outputdir=isolation_output \ + $(ISOLATIONCHECKS) + +.PHONY: isolationcheck isolationcheck-install-force check + +temp-install: EXTRA_INSTALL=contrib/pg_query_state diff --git a/contrib/pg_query_state/README.md b/contrib/pg_query_state/README.md new file mode 100644 index 0000000000..98ee513336 --- /dev/null +++ b/contrib/pg_query_state/README.md @@ -0,0 +1,284 @@ +# pg\_query\_state +The `pg_query_state` module provides facility to know the current state of query execution on working backend. To enable this extension you have to patch the latest stable version of PostgreSQL. Different branches are intended for different version numbers of PostgreSQL, e.g., branch _PG9_5_ corresponds to PostgreSQL 9.5. + +## Overview +Each complex query statement (SELECT/INSERT/UPDATE/DELETE) after optimization/planning stage is translated into plan tree wich is kind of imperative representation of declarative SQL query. EXPLAIN ANALYZE request allows to demonstrate execution statistics gathered from each node of plan tree (full time of execution, number rows emitted to upper nodes, etc). But this statistics is collected after execution of query. This module allows to show actual statistics of query running on external backend. At that, format of resulting output is almost identical to ordinal EXPLAIN ANALYZE. Thus users are able to track of query execution in progress. + +In fact, this module is able to explore external backend and determine its actual state. Particularly it's helpful when backend executes a heavy query or gets stuck. + +## Use cases +Using this module there can help in the following things: + - detect a long query (along with other monitoring tools) + - overwatch the query execution ([example](https://asciinema.org/a/c0jon1i6g92hnb5q4492n1rzn)) + +## Installation +To install `pg_query_state`, please apply patches `custom_signal.patch`, `executor_hooks.patch` and `runtime_explain.patch` to the latest stable version of PostgreSQL and rebuild PostgreSQL. + +Correspondence branch names to PostgreSQL version numbers: +- _PG9_5_ --- PostgreSQL 9.5 +- _PGPRO9_5_ --- PostgresPro 9.5 + +Then execute this in the module's directory: +``` +make install USE_PGXS=1 +``` +Add module name to the `shared_preload_libraries` parameter in `postgresql.conf`: +``` +shared_preload_libraries = 'pg_query_state' +``` +It is essential to restart the PostgreSQL instance. After that, execute the following query in psql: +``` +CREATE EXTENSION pg_query_state; +``` +Done! + +## Tests +Tests using parallel sessions using python 2.7 script: + ``` + python tests/pg_qs_test_runner.py [OPTION]... + ``` +*prerequisite packages*: +* `psycopg2` version 2.6 or later +* `PyYAML` version 3.11 or later + +*options*: +* *- -host* --- postgres server host, default value is *localhost* +* *- -port* --- postgres server port, default value is *5432* +* *- -database* --- database name, default value is *postgres* +* *- -user* --- user name, default value is *postgres* +* *- -password* --- user's password, default value is empty + +## Function pg\_query\_state +```plpgsql +pg_query_state(integer pid, + verbose boolean DEFAULT FALSE, + costs boolean DEFAULT FALSE, + timing boolean DEFAULT FALSE, + buffers boolean DEFAULT FALSE, + triggers boolean DEFAULT FALSE, + format text DEFAULT 'text') +``` +Extract current query state from backend with specified `pid`. Since a function call causes nested subqueries so that state of execution may be viewed as stack of running queries, return value of `pg_query_state` has type `TABLE (query_text text, plan text)` and represents table where each row specifies stack frame -- correspondence between query and plan tree. + +In process of execution some nodes of plan tree can take loops of full execution. Therefore statistics for each node consists of two parts: average statistics for previous loops just like in EXPLAIN ANALYZE output and statistics for current loop if node have not finished. + +Optional arguments: + + - `verbose` --- use EXPLAIN VERBOSE for plan printing; + - `costs` --- add costs for each node; + - `timing` --- print timing data for each node, if collecting of timing statistics is turned off on called side resulting output will contain WARNING message `timing statistics disabled`; + - `buffers` --- print buffers usage, if collecting of buffers statistics is turned off on called side resulting output will contain WARNING message `buffers statistics disabled`; + - `triggers` --- include triggers statistics in result plan trees; + - `format` --- EXPLAIN format to be used for plans printing, posible values: {`text`, `xml`, `json`, `yaml`}. + +If callable backend is not executing any query the function prints INFO message about backend's state taken from `pg_stat_activity` view if it exists there. + +Calling role have to be superuser or member of the role whose backend is being called. Othrewise function prints ERROR message `permission denied`. + +## Configuration settings +There are several user-accessible [GUC](https://www.postgresql.org/docs/9.5/static/config-setting.html) variables designed to toggle the whole module and the collecting of specific statistic parameters while query is running: + + - `pg_query_state.enable` --- disable (or enable) `pg_query_state` completely, default value is `true` + - `pg_query_state.enable_timing` --- collect timing data for each node, default value is `false` + - `pg_query_state.enable_buffers` --- collect buffers usage, default value is `false` + +This parameters is set on called side before running any queries whose states are attempted to extract. **_Warning_**: if `pg_query_state.enable_timing` is turned off the calling side cannot get time statistics, similarly for `pg_query_state.enable_buffers` parameter. + +## Examples +Assume one backend with pid = 20102 performs a simple query: +``` +postgres=# select pg_backend_pid(); + pg_backend_pid + ---------------- + 20102 +(1 row) +postgres=# select count(*) from foo join bar on foo.c1=bar.c1; +``` +Other backend can extract intermediate state of execution that query: +``` +postgres=# \x +postgres=# select * from pg_query_state(20102); +-[ RECORD 1 ]----------------------------------------------------------------------------------- +query_text | select count(*) from foo join bar on foo.c1=bar.c1; +plan | Aggregate (Current loop: actual rows=0, loop number=1) + + | -> Nested Loop (Current loop: actual rows=6, loop number=1) + + | Join Filter: (foo.c1 = bar.c1) + + | Rows Removed by Join Filter: 0 + + | -> Seq Scan on bar (Current loop: actual rows=6, loop number=1) + + | -> Materialize (actual rows=1000001 loops=5) (Current loop: actual rows=742878, loop number=6)+ + | -> Seq Scan on foo (Current loop: actual rows=1000001, loop number=1) +``` +In example above `Materialize` node has statistics on passed loops (average number of rows delivered to `Nested Loop` and number of passed loops are shown) and statistics on current loop. Other nodes has statistics only for current loop as this loop is first (`loop number` = 1). + +Assume first backend executes some function: +``` +postgres=# select n_join_foo_bar(); +``` +Other backend can get the follow output: +``` +postgres=# select * from pg_query_state(20102); +-[ RECORD 1 ]--------------------------------------------------------------------------------------------------------------- +query_text | select n_join_foo_bar(); +plan | Result (Current loop: actual rows=0, loop number=1) +-[ RECORD 2 ]--------------------------------------------------------------------------------------------------------------- +query_text | SELECT (select count(*) from foo join bar on foo.c1=bar.c1) +plan | Result (Current loop: actual rows=0, loop number=1) + + | InitPlan 1 (returns $0) + + | -> Aggregate (Current loop: actual rows=0, loop number=1) + + | -> Nested Loop (Current loop: actual rows=8, loop number=1) + + | Join Filter: (foo.c1 = bar.c1) + + | Rows Removed by Join Filter: 0 + + | -> Seq Scan on bar (Current loop: actual rows=9, loop number=1) + + | -> Materialize (actual rows=1000001 loops=8) (Current loop: actual rows=665090, loop number=9)+ + | -> Seq Scan on foo (Current loop: actual rows=1000001, loop number=1) +``` +First row corresponds to function call, second - to query which is in the body of that function. + +We can get result plans in different format (e.g. `json`): +``` +postgres=# select * from pg_query_state(pid := 20102, format := 'json'); +-[ RECORD 1 ]----------------------------------------------------------- +query_text | select n_join_foo_bar(); +plan | { + + | "Plan": { + + | "Node Type": "Result", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 0 + + | } + + | } + + | } +-[ RECORD 2 ]----------------------------------------------------------- +query_text | SELECT (select count(*) from foo join bar on foo.c1=bar.c1) +plan | { + + | "Plan": { + + | "Node Type": "Result", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 0 + + | }, + + | "Plans": [ + + | { + + | "Node Type": "Aggregate", + + | "Strategy": "Plain", + + | "Parent Relationship": "InitPlan", + + | "Subplan Name": "InitPlan 1 (returns $0)", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 0 + + | }, + + | "Plans": [ + + | { + + | "Node Type": "Hash Join", + + | "Parent Relationship": "Outer", + + | "Join Type": "Inner", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 124911 + + | }, + + | "Hash Cond": "(foo.c1 = bar.c1)", + + | "Plans": [ + + | { + + | "Node Type": "Seq Scan", + + | "Parent Relationship": "Outer", + + | "Relation Name": "foo", + + | "Alias": "foo", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 1000004 + + | } + + | }, + + | { + + | "Node Type": "Hash", + + | "Parent Relationship": "Inner", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 500000 + + | }, + + | "Hash Buckets": 131072, + + | "Original Hash Buckets": 131072, + + | "Hash Batches": 8, + + | "Original Hash Batches": 8, + + | "Peak Memory Usage": 3221, + + | "Plans": [ + + | { + + | "Node Type": "Seq Scan", + + | "Parent Relationship": "Outer", + + | "Relation Name": "bar", + + | "Alias": "bar", + + | "Current loop": { + + | "Actual Loop Number": 1, + + | "Actual Rows": 500000 + + | } + + | } + + | ] + + | } + + | ] + + | } + + | ] + + | } + + | ] + + | } + + | } +``` + +## Functions for tracing query execution +For the purpose to achieve a slightly deterministic result from `pg_query_state` function under regression tests this module introduces specific functions for query tracing running on external backend process. In this case query is suspended after any node has worked off one step in pipeline structure of plan tree execution. Thus we can execute query specific number of steps and get its state which will be deterministic at least on number of emitted rows of each node. + +Function `executor_step` which takes `pid` of traceable backend provides facility to perform single step of query execution. Function `executor_continue` which also takes `pid` completes query without trace interrupts. + +Trace mode is set through GUC parameter `pg_query_state.executor_trace` which default is `off`. **_Warning_**: after setting this parameter any following queries (even specified implicitly, e.g., autocompletion of input in _psql_) will be interrupted and to resume their `executor_continue` must be accomplished on external backend. Only after that user can turn off trace mode. + +### Examples with trace mode +Assume one backend with pid = 20102 sets trace mode and executes a simple query: +``` +postgres=# set pg_query_state.executor_trace to on; +SET +postgres=# select count(*) from foo join bar on foo.c1=bar.c1; +``` +This query is suspended. Then other backend can extract its state: +``` +postgres=# select * from pg_query_state(pid := 20102); +-[ RECORD 1 ]------------------------------------------------------------------------------ +query_text | select count(*) from foo join bar on foo.c1=bar.c1; +plan | Aggregate (Current loop: actual rows=0, loop number=1) + + | -> Hash Join (Current loop: actual rows=0, loop number=1) + + | Hash Cond: (foo.c1 = bar.c1) + + | -> Seq Scan on foo (Current loop: actual rows=0, loop number=1) + + | -> Hash (Current loop: actual rows=0, loop number=1) + + | -> Seq Scan on bar (Current loop: actual rows=0, loop number=1) +``` +As you can see none of nodes is executed. We can make one step of execution and see renewed state of query: +``` +postgres=# select executor_step(20102); +-[ RECORD 1 ]-+- +executor_step | + +postgres=# select * from pg_query_state(pid := 20102); +-[ RECORD 1 ]------------------------------------------------------------------------------ +query_text | select count(*) from foo join bar on foo.c1=bar.c1; +plan | Aggregate (Current loop: actual rows=0, loop number=1) + + | -> Hash Join (Current loop: actual rows=0, loop number=1) + + | Hash Cond: (foo.c1 = bar.c1) + + | -> Seq Scan on foo (Current loop: actual rows=1, loop number=1) + + | -> Hash (Current loop: actual rows=0, loop number=1) + + | -> Seq Scan on bar (Current loop: actual rows=0, loop number=1) +``` +Node `Seq Scan on foo` has emitted first row to `Hash Join`. Completion of traceable query is performed as follows: +``` +postgres=# select executor_continue(pid := 20102); +-[ RECORD 1 ]-----+- +executor_continue | +``` +At the same time first backend prints result of query execution: +``` +postgres=# select count(*) from foo join bar on foo.c1=bar.c1; +-[ RECORD 1 ]- +count | 500000 +``` + +## Feedback +Do not hesitate to post your issues, questions and new ideas at the [issues](https://github.com/postgrespro/pg_query_state/issues) page. + +## Authors +Maksim Milyutin Postgres Professional Ltd., Russia diff --git a/contrib/pg_query_state/custom_signals.patch b/contrib/pg_query_state/custom_signals.patch new file mode 100644 index 0000000000..a936b31214 --- /dev/null +++ b/contrib/pg_query_state/custom_signals.patch @@ -0,0 +1,219 @@ +diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c +index 0abde43..961d267 100644 +--- a/src/backend/storage/ipc/procsignal.c ++++ b/src/backend/storage/ipc/procsignal.c +@@ -67,12 +67,17 @@ typedef struct + */ + bool set_latch_on_sigusr1; + ++static bool CustomSignalPendings[NUM_CUSTOM_PROCSIGNALS]; ++static ProcSignalHandler_type CustomHandlers[NUM_CUSTOM_PROCSIGNALS]; ++ + static ProcSignalSlot *ProcSignalSlots = NULL; + static volatile ProcSignalSlot *MyProcSignalSlot = NULL; + + static bool CheckProcSignal(ProcSignalReason reason); + static void CleanupProcSignalState(int status, Datum arg); + ++static void CustomSignalInterrupt(ProcSignalReason reason); ++ + /* + * ProcSignalShmemSize + * Compute space needed for procsignal's shared memory +@@ -173,6 +178,57 @@ CleanupProcSignalState(int status, Datum arg) + } + + /* ++ * RegisterCustomProcSignalHandler ++ * Assign specific handler of custom process signal with new ProcSignalReason key. ++ * Return INVALID_PROCSIGNAL if all custom signals have been assigned. ++ */ ++ProcSignalReason ++RegisterCustomProcSignalHandler(ProcSignalHandler_type handler) ++{ ++ ProcSignalReason reason; ++ ++ /* iterate through custom signal keys to find free spot */ ++ for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++) ++ if (!CustomHandlers[reason - PROCSIG_CUSTOM_1]) ++ { ++ CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler; ++ return reason; ++ } ++ return INVALID_PROCSIGNAL; ++} ++ ++/* ++ * AssignCustomProcSignalHandler ++ * Assign handler of custom process signal with specific ProcSignalReason key. ++ * Return old ProcSignal handler. ++ * Assume incoming reason is one of custom ProcSignals. ++ */ ++ProcSignalHandler_type ++AssignCustomProcSignalHandler(ProcSignalReason reason, ProcSignalHandler_type handler) ++{ ++ ProcSignalHandler_type old; ++ ++ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); ++ ++ old = CustomHandlers[reason - PROCSIG_CUSTOM_1]; ++ CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler; ++ return old; ++} ++ ++/* ++ * GetCustomProcSignalHandler ++ * Get handler of custom process signal. ++ * Assume incoming reason is one of custom ProcSignals. ++ */ ++ProcSignalHandler_type ++GetCustomProcSignalHandler(ProcSignalReason reason) ++{ ++ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); ++ ++ return CustomHandlers[reason - PROCSIG_CUSTOM_1]; ++} ++ ++/* + * SendProcSignal + * Send a signal to a Postgres process + * +@@ -267,7 +323,8 @@ CheckProcSignal(ProcSignalReason reason) + void + procsignal_sigusr1_handler(SIGNAL_ARGS) + { +- int save_errno = errno; ++ int save_errno = errno; ++ ProcSignalReason reason; + + if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT)) + HandleCatchupInterrupt(); +@@ -296,6 +353,10 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) + if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN)) + RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); + ++ for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++) ++ if (CheckProcSignal(reason)) ++ CustomSignalInterrupt(reason); ++ + if (set_latch_on_sigusr1) + SetLatch(MyLatch); + +@@ -303,3 +364,45 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) + + errno = save_errno; + } ++ ++/* ++ * Handle receipt of an interrupt indicating a custom process signal. ++ */ ++static void ++CustomSignalInterrupt(ProcSignalReason reason) ++{ ++ int save_errno = errno; ++ ++ Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); ++ ++ /* set interrupt flags */ ++ InterruptPending = true; ++ CustomSignalPendings[reason - PROCSIG_CUSTOM_1] = true; ++ ++ /* make sure the event is processed in due course */ ++ SetLatch(MyLatch); ++ ++ errno = save_errno; ++} ++ ++/* ++ * CheckAndHandleCustomSignals ++ * Check custom signal flags and call handler assigned to that signal if it is not NULL. ++ * This function is called within CHECK_FOR_INTERRUPTS if interrupt have been occurred. ++ */ ++void ++CheckAndHandleCustomSignals(void) ++{ ++ int i; ++ ++ for (i = 0; i < NUM_CUSTOM_PROCSIGNALS; i++) ++ if (CustomSignalPendings[i]) ++ { ++ ProcSignalHandler_type handler; ++ ++ CustomSignalPendings[i] = false; ++ handler = CustomHandlers[i]; ++ if (handler) ++ handler(); ++ } ++} +diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c +index f78321d..9ef7dd8 100644 +--- a/src/backend/tcop/postgres.c ++++ b/src/backend/tcop/postgres.c +@@ -3006,6 +3006,8 @@ ProcessInterrupts(void) + + if (ParallelMessagePending) + HandleParallelMessages(); ++ ++ CheckAndHandleCustomSignals(); + } + + +diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h +index af1a0cd..507a63c 100644 +--- a/src/include/storage/procsignal.h ++++ b/src/include/storage/procsignal.h +@@ -17,6 +17,8 @@ + #include "storage/backendid.h" + + ++#define NUM_CUSTOM_PROCSIGNALS 64 ++ + /* + * Reasons for signalling a Postgres child process (a backend or an auxiliary + * process, like checkpointer). We can cope with concurrent signals for different +@@ -29,6 +31,8 @@ + */ + typedef enum + { ++ INVALID_PROCSIGNAL = -1, /* Must be first */ ++ + PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ + PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ + PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */ +@@ -41,9 +45,20 @@ typedef enum + PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, + PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + ++ PROCSIG_CUSTOM_1, ++ /* ++ * PROCSIG_CUSTOM_2, ++ * ..., ++ * PROCSIG_CUSTOM_N-1, ++ */ ++ PROCSIG_CUSTOM_N = PROCSIG_CUSTOM_1 + NUM_CUSTOM_PROCSIGNALS - 1, ++ + NUM_PROCSIGNALS /* Must be last! */ + } ProcSignalReason; + ++/* Handler of custom process signal */ ++typedef void (*ProcSignalHandler_type) (void); ++ + /* + * prototypes for functions in procsignal.c + */ +@@ -51,9 +66,15 @@ extern Size ProcSignalShmemSize(void); + extern void ProcSignalShmemInit(void); + + extern void ProcSignalInit(int pss_idx); ++extern ProcSignalReason RegisterCustomProcSignalHandler(ProcSignalHandler_type handler); ++extern ProcSignalHandler_type AssignCustomProcSignalHandler(ProcSignalReason reason, ++ ProcSignalHandler_type handler); ++extern ProcSignalHandler_type GetCustomProcSignalHandler(ProcSignalReason reason); + extern int SendProcSignal(pid_t pid, ProcSignalReason reason, + BackendId backendId); + ++extern void CheckAndHandleCustomSignals(void); ++ + extern void procsignal_sigusr1_handler(SIGNAL_ARGS); + extern PGDLLIMPORT bool set_latch_on_sigusr1; + diff --git a/contrib/pg_query_state/executor_hooks.patch b/contrib/pg_query_state/executor_hooks.patch new file mode 100644 index 0000000000..375d9e0336 --- /dev/null +++ b/contrib/pg_query_state/executor_hooks.patch @@ -0,0 +1,66 @@ +diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c +index 03c2feb..a33e645c 100644 +--- a/src/backend/executor/execProcnode.c ++++ b/src/backend/executor/execProcnode.c +@@ -115,7 +115,6 @@ + #include "executor/nodeWorktablescan.h" + #include "miscadmin.h" + +- + /* ------------------------------------------------------------------------ + * ExecInitNode + * +@@ -356,6 +355,9 @@ ExecInitNode(Plan *node, EState *estate, int eflags) + return result; + } + ++/* Hooks for plugins to pre/post process ExecProcNode */ ++PreExecProcNode_hook_type preExecProcNode_hook = NULL; ++PostExecProcNode_hook_type postExecProcNode_hook = NULL; + + /* ---------------------------------------------------------------- + * ExecProcNode +@@ -374,7 +376,12 @@ ExecProcNode(PlanState *node) + ExecReScan(node); /* let ReScan handle this */ + + if (node->instrument) ++ { ++ if (preExecProcNode_hook) ++ preExecProcNode_hook(node); ++ + InstrStartNode(node->instrument); ++ } + + switch (nodeTag(node)) + { +@@ -527,8 +534,13 @@ ExecProcNode(PlanState *node) + } + + if (node->instrument) ++ { + InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0); + ++ if (postExecProcNode_hook) ++ postExecProcNode_hook(node, result); ++ } ++ + return result; + } + +diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h +index 110bc93..8801419 100644 +--- a/src/include/executor/executor.h ++++ b/src/include/executor/executor.h +@@ -95,6 +95,12 @@ extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook; + typedef bool (*ExecutorCheckPerms_hook_type) (List *, bool); + extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook; + ++/* Hook for plugins to pre/post process ExecProcNode() */ ++typedef void (*PreExecProcNode_hook_type) (PlanState *node); ++typedef void (*PostExecProcNode_hook_type) (PlanState *node, TupleTableSlot *result); ++extern PGDLLIMPORT PreExecProcNode_hook_type preExecProcNode_hook; ++extern PGDLLIMPORT PostExecProcNode_hook_type postExecProcNode_hook; ++ + + /* + * prototypes from functions in execAmi.c diff --git a/contrib/pg_query_state/expected/corner_cases.out b/contrib/pg_query_state/expected/corner_cases.out new file mode 100644 index 0000000000..8320e1f1a2 --- /dev/null +++ b/contrib/pg_query_state/expected/corner_cases.out @@ -0,0 +1,64 @@ +Parsed test spec with 2 sessions + +starting permutation: s1_pg_qs_1 +step s1_pg_qs_1: select pg_query_state(1); +ERROR: backend with pid=1 not found + +starting permutation: s1_pg_qs_2 +step s1_pg_qs_2: select pg_query_state(pg_backend_pid()); +ERROR: attempt to extract state of current process + +starting permutation: s1_save_pid s2_pg_qs_counterpart +step s1_save_pid: select save_own_pid(0); +save_own_pid + + +INFO: state of backend is idle +step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0)); +pg_query_state + + +starting permutation: s1_save_pid s1_disable_pg_qs s2_pg_qs_counterpart +step s1_save_pid: select save_own_pid(0); +save_own_pid + + +step s1_disable_pg_qs: set pg_query_state.enable to off; +INFO: query execution statistics disabled +step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0)); +pg_query_state + + +starting permutation: s1_set_bob s2_set_bob s1_save_pid s2_pg_qs_counterpart +step s1_set_bob: set role bob; +step s2_set_bob: set role bob; +step s1_save_pid: select save_own_pid(0); +save_own_pid + + +INFO: state of backend is idle +step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0)); +pg_query_state + + +starting permutation: s1_set_bob s2_set_su s1_save_pid s2_pg_qs_counterpart +step s1_set_bob: set role bob; +step s2_set_su: set role super; +step s1_save_pid: select save_own_pid(0); +save_own_pid + + +INFO: state of backend is idle +step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0)); +pg_query_state + + +starting permutation: s1_set_bob s2_set_alice s1_save_pid s2_pg_qs_counterpart +step s1_set_bob: set role bob; +step s2_set_alice: set role alice; +step s1_save_pid: select save_own_pid(0); +save_own_pid + + +step s2_pg_qs_counterpart: select pg_query_state(counterpart_pid(0)); +ERROR: permission denied diff --git a/contrib/pg_query_state/pg_query_state--1.0.sql b/contrib/pg_query_state/pg_query_state--1.0.sql new file mode 100644 index 0000000000..6631d04807 --- /dev/null +++ b/contrib/pg_query_state/pg_query_state--1.0.sql @@ -0,0 +1,21 @@ +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION pg_query_state" to load this file. \quit + +CREATE FUNCTION pg_query_state(pid integer + , verbose boolean = FALSE + , costs boolean = FALSE + , timing boolean = FALSE + , buffers boolean = FALSE + , triggers boolean = FALSE + , format text = 'text') + RETURNS TABLE (query_text text, plan text) + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT VOLATILE; + +CREATE FUNCTION executor_step(pid integer) RETURNS VOID + AS 'MODULE_PATHNAME' + LANGUAGE C VOLATILE; + +CREATE FUNCTION executor_continue(pid integer) RETURNS VOID + AS 'MODULE_PATHNAME' + LANGUAGE C VOLATILE; diff --git a/contrib/pg_query_state/pg_query_state.c b/contrib/pg_query_state/pg_query_state.c new file mode 100644 index 0000000000..1e2a73b752 --- /dev/null +++ b/contrib/pg_query_state/pg_query_state.c @@ -0,0 +1,783 @@ +/* + * pg_query_state.c + * Extract information about query state of other backend + * + * Copyright (c) 2016-2016, Postgres Professional + * + * IDENTIFICATION + * contrib/pg_query_state/pg_query_state.c + */ + +#include "pg_query_state.h" + +#include "access/htup_details.h" +#include "catalog/pg_type.h" +#include "funcapi.h" +#include "executor/executor.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "storage/ipc.h" +#include "storage/procarray.h" +#include "storage/procsignal.h" +#include "storage/shm_toc.h" +#include "utils/guc.h" + +#ifdef PG_MODULE_MAGIC +PG_MODULE_MAGIC; +#endif + +#define QUEUE_SIZE (16 * 1024) +#define PG_QS_MODULE_KEY 0xCA94B108 +#define PG_QUERY_STATE_KEY 0 +#define EXECUTOR_TRACE_KEY 1 + +#define TEXT_CSTR_CMP(text, cstr) \ + (memcmp(VARDATA(text), (cstr), VARSIZE(text) - VARHDRSZ)) + +/* GUC variables */ +bool pg_qs_enable = true; +bool pg_qs_timing = false; +bool pg_qs_buffers = false; +bool pg_qs_trace = false; + +/* Saved hook values in case of unload */ +static ExecutorStart_hook_type prev_ExecutorStart = NULL; +static ExecutorRun_hook_type prev_ExecutorRun = NULL; +static ExecutorFinish_hook_type prev_ExecutorFinish = NULL; +static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; +static shmem_startup_hook_type prev_shmem_startup_hook = NULL; +static PostExecProcNode_hook_type prev_postExecProcNode = NULL; + +void _PG_init(void); +void _PG_fini(void); + +/* hooks defined in this module */ +static void qs_ExecutorStart(QueryDesc *queryDesc, int eflags); +static void qs_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count); +static void qs_ExecutorFinish(QueryDesc *queryDesc); +static void qs_ExecutorEnd(QueryDesc *queryDesc); +static void qs_postExecProcNode(PlanState *planstate, TupleTableSlot *result); + +/* Global variables */ +List *QueryDescStack = NIL; +static ProcSignalReason QueryStatePollReason; +static bool module_initialized = false; +static const char *be_state_str[] = { /* BackendState -> string repr */ + "undefined", /* STATE_UNDEFINED */ + "idle", /* STATE_IDLE */ + "active", /* STATE_RUNNING */ + "idle in transaction", /* STATE_IDLEINTRANSACTION */ + "fastpath function call", /* STATE_FASTPATH */ + "idle in transaction (aborted)", /* STATE_IDLEINTRANSACTION_ABORTED */ + "disabled", /* STATE_DISABLED */ + }; + +/* + * Kinds of trace commands + */ +typedef enum +{ + STEP, + CONTINUE +} trace_cmd; + +/* + * Trace command transmitted to counterpart + */ +typedef struct +{ + trace_cmd command; + pid_t tracer; + pid_t traceable; +} trace_request; + +/* Shared memory variables */ +shm_toc *toc = NULL; +user_data *caller = NULL; +pg_qs_params *params = NULL; +trace_request *trace_req = NULL; +shm_mq *mq = NULL; + +/* + * Estimate amount of shared memory needed. + */ +static Size +pg_qs_shmem_size() +{ + shm_toc_estimator e; + Size size; + int nkeys; + + shm_toc_initialize_estimator(&e); + + nkeys = 4; + + shm_toc_estimate_chunk(&e, sizeof(user_data)); + shm_toc_estimate_chunk(&e, sizeof(pg_qs_params)); + shm_toc_estimate_chunk(&e, sizeof(trace_request)); + shm_toc_estimate_chunk(&e, (Size) QUEUE_SIZE); + + shm_toc_estimate_keys(&e, nkeys); + size = shm_toc_estimate(&e); + + return size; +} + +/* + * Distribute shared memory. + */ +static void +pg_qs_shmem_startup(void) +{ + bool found; + Size shmem_size = pg_qs_shmem_size(); + void *shmem; + + shmem = ShmemInitStruct("pg_query_state", shmem_size, &found); + if (!found) + { + toc = shm_toc_create(PG_QS_MODULE_KEY, shmem, shmem_size); + + caller = shm_toc_allocate(toc, sizeof(user_data)); + shm_toc_insert(toc, 0, caller); + params = shm_toc_allocate(toc, sizeof(pg_qs_params)); + shm_toc_insert(toc, 1, params); + trace_req = shm_toc_allocate(toc, sizeof(trace_request)); + shm_toc_insert(toc, 2, trace_req); + MemSet(trace_req, 0, sizeof(trace_request)); + mq = shm_toc_allocate(toc, QUEUE_SIZE); + shm_toc_insert(toc, 3, mq); + } + else + { + toc = shm_toc_attach(PG_QS_MODULE_KEY, shmem); + + caller = shm_toc_lookup(toc, 0); + params = shm_toc_lookup(toc, 1); + trace_req = shm_toc_lookup(toc, 2); + mq = shm_toc_lookup(toc, 3); + } + + if (prev_shmem_startup_hook) + prev_shmem_startup_hook(); + + module_initialized = true; +} + +/* + * Module load callback + */ +void +_PG_init(void) +{ + if (!process_shared_preload_libraries_in_progress) + return; + + /* + * Request additional shared resources. (These are no-ops if we're not in + * the postmaster process.) We'll allocate or attach to the shared + * resources in qs_shmem_startup(). + */ + RequestAddinShmemSpace(pg_qs_shmem_size()); + + /* Register interrupt on custom signal of polling query state */ + QueryStatePollReason = RegisterCustomProcSignalHandler(SendQueryState); + if (QueryStatePollReason == INVALID_PROCSIGNAL) + { + ereport(WARNING, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), + errmsg("pg_query_state isn't loaded: insufficient custom ProcSignal slots"))); + return; + } + + /* Define custom GUC variables */ + DefineCustomBoolVariable("pg_query_state.enable", + "Enable module.", + NULL, + &pg_qs_enable, + true, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); + DefineCustomBoolVariable("pg_query_state.enable_timing", + "Collect timing data, not just row counts.", + NULL, + &pg_qs_timing, + false, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); + DefineCustomBoolVariable("pg_query_state.enable_buffers", + "Collect buffer usage.", + NULL, + &pg_qs_buffers, + false, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); + DefineCustomBoolVariable("pg_query_state.executor_trace", + "Turn on trace of plan execution.", + NULL, + &pg_qs_trace, + false, + PGC_SUSET, + 0, + NULL, + NULL, + NULL); + EmitWarningsOnPlaceholders("pg_query_state"); + + /* Install hooks */ + prev_ExecutorStart = ExecutorStart_hook; + ExecutorStart_hook = qs_ExecutorStart; + prev_ExecutorRun = ExecutorRun_hook; + ExecutorRun_hook = qs_ExecutorRun; + prev_ExecutorFinish = ExecutorFinish_hook; + ExecutorFinish_hook = qs_ExecutorFinish; + prev_ExecutorEnd = ExecutorEnd_hook; + ExecutorEnd_hook = qs_ExecutorEnd; + prev_shmem_startup_hook = shmem_startup_hook; + shmem_startup_hook = pg_qs_shmem_startup; + prev_postExecProcNode = postExecProcNode_hook; +} + +/* + * Module unload callback + */ +void +_PG_fini(void) +{ + module_initialized = false; + + /* clear global state */ + list_free(QueryDescStack); + AssignCustomProcSignalHandler(QueryStatePollReason, NULL); + + /* Uninstall hooks. */ + ExecutorStart_hook = prev_ExecutorStart; + ExecutorRun_hook = prev_ExecutorRun; + ExecutorFinish_hook = prev_ExecutorFinish; + ExecutorEnd_hook = prev_ExecutorEnd; + shmem_startup_hook = prev_shmem_startup_hook; + postExecProcNode_hook = prev_postExecProcNode; +} + +/* + * In trace mode suspend query execution until other backend resumes it + */ +static void +suspend_traceable_query() +{ + for (;;) + { + /* Check whether current backend is traced */ + if (MyProcPid == trace_req->traceable) + { + PGPROC *tracer = BackendPidGetProc(trace_req->tracer); + + Assert(tracer != NULL); + + if (trace_req->command == CONTINUE) + postExecProcNode_hook = prev_postExecProcNode; + trace_req->traceable = 0; + SetLatch(&tracer->procLatch); + break; + } + + /* + * Wait for our latch to be set. It might already be set for some + * unrelated reason, but that'll just result in one extra trip through + * the loop. It's worth it to avoid resetting the latch at top of + * loop, because setting an already-set latch is much cheaper than + * setting one that has been reset. + */ + WaitLatch(MyLatch, WL_LATCH_SET, 0); + + /* An interrupt may have occurred while we were waiting. */ + CHECK_FOR_INTERRUPTS(); + + /* Reset the latch so we don't spin. */ + ResetLatch(MyLatch); + } +} + +/* + * postExecProcNode_hook: + * interrupt before execution next node of plan tree + * until other process resumes it through function calls: + * 'executor_step()' + * 'executor_continue()' + */ +static void +qs_postExecProcNode(PlanState *planstate, TupleTableSlot *result) +{ + suspend_traceable_query(); + + if (prev_postExecProcNode) + prev_postExecProcNode(planstate, result); +} + +/* + * ExecutorStart hook: + * set up flags to store runtime statistics, + * push current query description in global stack + */ +static void +qs_ExecutorStart(QueryDesc *queryDesc, int eflags) +{ + PG_TRY(); + { + /* Enable per-node instrumentation */ + if (pg_qs_enable && ((eflags & EXEC_FLAG_EXPLAIN_ONLY) == 0)) + { + queryDesc->instrument_options |= INSTRUMENT_ROWS; + if (pg_qs_timing) + queryDesc->instrument_options |= INSTRUMENT_TIMER; + if (pg_qs_buffers) + queryDesc->instrument_options |= INSTRUMENT_BUFFERS; + } + + if (prev_ExecutorStart) + prev_ExecutorStart(queryDesc, eflags); + else + standard_ExecutorStart(queryDesc, eflags); + + /* push structure about current query in global stack */ + QueryDescStack = lcons(queryDesc, QueryDescStack); + + /* set/reset hook for trace mode before start of upper level query */ + if (list_length(QueryDescStack) == 1) + postExecProcNode_hook = (pg_qs_enable && pg_qs_trace) ? + qs_postExecProcNode : prev_postExecProcNode; + + /* suspend traceable query if it is not continued (hook is not thrown off) */ + if (postExecProcNode_hook == qs_postExecProcNode) + suspend_traceable_query(); + } + PG_CATCH(); + { + QueryDescStack = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); +} + +/* + * ExecutorRun: + * Catch any fatal signals + */ +static void +qs_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, long count) +{ + PG_TRY(); + { + if (prev_ExecutorRun) + prev_ExecutorRun(queryDesc, direction, count); + else + standard_ExecutorRun(queryDesc, direction, count); + } + PG_CATCH(); + { + QueryDescStack = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); +} + +/* + * ExecutorFinish: + * Catch any fatal signals + */ +static void +qs_ExecutorFinish(QueryDesc *queryDesc) +{ + PG_TRY(); + { + if (prev_ExecutorFinish) + prev_ExecutorFinish(queryDesc); + else + standard_ExecutorFinish(queryDesc); + } + PG_CATCH(); + { + QueryDescStack = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); +} + +/* + * ExecutorEnd hook: + * pop current query description from global stack + */ +static void +qs_ExecutorEnd(QueryDesc *queryDesc) +{ + PG_TRY(); + { + QueryDescStack = list_delete_first(QueryDescStack); + + if (prev_ExecutorEnd) + prev_ExecutorEnd(queryDesc); + else + standard_ExecutorEnd(queryDesc); + } + PG_CATCH(); + { + QueryDescStack = NIL; + PG_RE_THROW(); + } + PG_END_TRY(); +} + +/* + * Find PgBackendStatus entry + */ +static PgBackendStatus * +search_be_status(int pid) +{ + int beid; + + if (pid <= 0) + return NULL; + + for (beid = 1; beid <= pgstat_fetch_stat_numbackends(); beid++) + { + PgBackendStatus *be_status = pgstat_fetch_stat_beentry(beid); + + if (be_status && be_status->st_procpid == pid) + return be_status; + } + + return NULL; +} + +/* + * Init userlock + */ +static void +init_lock_tag(LOCKTAG *tag, uint32 key) +{ + tag->locktag_field1 = PG_QS_MODULE_KEY; + tag->locktag_field2 = key; + tag->locktag_field3 = 0; + tag->locktag_field4 = 0; + tag->locktag_type = LOCKTAG_USERLOCK; + tag->locktag_lockmethodid = USER_LOCKMETHOD; +} + +/* + * Structure of stack frame of fucntion call which transfers through message queue + */ +typedef struct +{ + text *query; + text *plan; +} stack_frame; + +/* + * Convert serialized stack frame into stack_frame record + * Increment '*src' pointer to the next serialized stack frame + */ +static stack_frame * +deserialize_stack_frame(char **src) +{ + stack_frame *result = palloc(sizeof(stack_frame)); + text *query = (text *) *src, + *plan = (text *) (*src + INTALIGN(VARSIZE(query))); + + result->query = palloc(VARSIZE(query)); + memcpy(result->query, query, VARSIZE(query)); + result->plan = palloc(VARSIZE(plan)); + memcpy(result->plan, plan, VARSIZE(plan)); + + *src = (char *) plan + INTALIGN(VARSIZE(plan)); + return result; +} + +/* + * Convert serialized stack frames into List of stack_frame records + */ +static List * +deserialize_stack(char *src, int stack_depth) +{ + List *result = NIL; + char *curr_ptr = src; + int i; + + for (i = 0; i < stack_depth; i++) + { + stack_frame *frame = deserialize_stack_frame(&curr_ptr); + result = lappend(result, frame); + } + + return result; +} + +/* + * Implementation of pg_query_state function + */ +PG_FUNCTION_INFO_V1(pg_query_state); +Datum +pg_query_state(PG_FUNCTION_ARGS) +{ + /* multicall context type */ + typedef struct + { + ListCell *cursor; + List *stack; + } pg_qs_fctx; + + FuncCallContext *funcctx; + MemoryContext oldcontext; + pg_qs_fctx *fctx; + + if (SRF_IS_FIRSTCALL()) + { + LOCKTAG tag; + pid_t pid = PG_GETARG_INT32(0); + bool verbose = PG_GETARG_BOOL(1), + costs = PG_GETARG_BOOL(2), + timing = PG_GETARG_BOOL(3), + buffers = PG_GETARG_BOOL(4), + triggers = PG_GETARG_BOOL(5); + text *format_text = PG_GETARG_TEXT_P(6); + ExplainFormat format; + PGPROC *proc; + shm_mq_handle *mqh; + shm_mq_result mq_receive_result; + int send_signal_result; + Size len; + shm_mq_msg *msg; + + if (!module_initialized) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("pg_query_state wasn't initialized yet"))); + + if (pid == MyProcPid) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("attempt to extract state of current process"))); + + proc = BackendPidGetProc(pid); + if (!proc || proc->backendId == InvalidBackendId) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("backend with pid=%d not found", pid))); + + if (TEXT_CSTR_CMP(format_text, "text") == 0) + format = EXPLAIN_FORMAT_TEXT; + else if (TEXT_CSTR_CMP(format_text, "xml") == 0) + format = EXPLAIN_FORMAT_XML; + else if (TEXT_CSTR_CMP(format_text, "json") == 0) + format = EXPLAIN_FORMAT_JSON; + else if (TEXT_CSTR_CMP(format_text, "yaml") == 0) + format = EXPLAIN_FORMAT_YAML; + else + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized 'format' argument"))); + /* + * init and acquire lock so that any other concurrent calls of this fuction + * can not occupy shared queue for transfering query state + */ + init_lock_tag(&tag, PG_QUERY_STATE_KEY); + LockAcquire(&tag, ExclusiveLock, false, false); + + /* fill in caller's user data */ + caller->user_id = GetUserId(); + caller->superuser = superuser(); + + /* fill in parameters of query state request */ + params->verbose = verbose; + params->costs = costs; + params->timing = timing; + params->buffers = buffers; + params->triggers = triggers; + params->format = format; + + /* prepare message queue to transfer data */ + mq = shm_mq_create(mq, QUEUE_SIZE); + shm_mq_set_sender(mq, proc); + shm_mq_set_receiver(mq, MyProc); + + /* send signal to specified backend to extract its state */ + send_signal_result = SendProcSignal(pid, QueryStatePollReason, proc->backendId); + if (send_signal_result == -1) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("invalid send signal"))); + + /* retrieve data from message queue */ + mqh = shm_mq_attach(mq, NULL, NULL); + mq_receive_result = shm_mq_receive(mqh, &len, (void **) &msg, false); + if (mq_receive_result != SHM_MQ_SUCCESS) + ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), + errmsg("invalid read from message queue"))); + shm_mq_detach(mq); + + Assert(len == msg->length); + + funcctx = SRF_FIRSTCALL_INIT(); + switch (msg->result_code) + { + case QUERY_NOT_RUNNING: + { + PgBackendStatus *be_status = search_be_status(pid); + + if (be_status) + elog(INFO, "state of backend is %s", + be_state_str[be_status->st_state - STATE_UNDEFINED]); + else + elog(INFO, "backend is not running query"); + + LockRelease(&tag, ExclusiveLock, false); + SRF_RETURN_DONE(funcctx); + } + case PERM_DENIED: + ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied"))); + case STAT_DISABLED: + elog(INFO, "query execution statistics disabled"); + LockRelease(&tag, ExclusiveLock, false); + SRF_RETURN_DONE(funcctx); + case QS_RETURNED: + { + List *qs_stack; + TupleDesc tupdesc; + + /* print warnings if exist */ + if (msg->warnings & TIMINIG_OFF_WARNING) + ereport(WARNING, (errcode(ERRCODE_WARNING), + errmsg("timing statistics disabled"))); + if (msg->warnings & BUFFERS_OFF_WARNING) + ereport(WARNING, (errcode(ERRCODE_WARNING), + errmsg("buffers statistics disabled"))); + + oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); + + /* save stack of calls and current cursor in multicall context */ + fctx = (pg_qs_fctx *) palloc(sizeof(pg_qs_fctx)); + qs_stack = deserialize_stack(msg->stack, msg->stack_depth); + fctx->stack = qs_stack; + fctx->cursor = list_head(qs_stack); + + funcctx->user_fctx = fctx; + funcctx->max_calls = list_length(qs_stack); + + /* Make tuple descriptor */ + tupdesc = CreateTemplateTupleDesc(2, false); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "query_text", TEXTOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 2, "plan", TEXTOID, -1, 0); + funcctx->tuple_desc = BlessTupleDesc(tupdesc); + + LockRelease(&tag, ExclusiveLock, false); + MemoryContextSwitchTo(oldcontext); + } + break; + } + } + + /* restore function multicall context */ + funcctx = SRF_PERCALL_SETUP(); + fctx = funcctx->user_fctx; + + if (funcctx->call_cntr < funcctx->max_calls) + { + HeapTuple tuple; + Datum values[2]; + bool nulls[2]; + stack_frame *frame = (stack_frame *) lfirst(fctx->cursor); + + /* Make and return next tuple to caller */ + MemSet(values, 0, sizeof(values)); + MemSet(nulls, 0, sizeof(nulls)); + values[0] = PointerGetDatum(frame->query); + values[1] = PointerGetDatum(frame->plan); + tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls); + + /* increment cursor */ + fctx->cursor = lnext(fctx->cursor); + + SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple)); + } + else + SRF_RETURN_DONE(funcctx); +} + +/* + * Execute specific tracing command of other backend with specified 'pid' + */ +static void +exec_trace_cmd(pid_t pid, trace_cmd cmd) +{ + LOCKTAG tag; + PGPROC *proc; + + if (!module_initialized) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("pg_query_state wasn't initialized yet"))); + + if (pid == MyProcPid) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("attempt to trace self process"))); + + proc = BackendPidGetProc(pid); + if (!proc || proc->backendId == InvalidBackendId) + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("backend with pid=%d not found", pid))); + + init_lock_tag(&tag, EXECUTOR_TRACE_KEY); + LockAcquire(&tag, ExclusiveLock, false, false); + + trace_req->tracer = MyProcPid; + trace_req->traceable = pid; + trace_req->command = cmd; + SetLatch(&proc->procLatch); + + /* + * Wait until traceable backend handles trace command (resets its pid in shared memory) + * so that next 'executor_*' call can not rewrite the shared structure 'trace_req' + */ + for (;;) + { + /* Check whether traceable backend is reset its pid */ + if (0 == trace_req->traceable) + break; + + WaitLatch(MyLatch, WL_LATCH_SET, 0); + CHECK_FOR_INTERRUPTS(); + ResetLatch(MyLatch); + } + + LockRelease(&tag, ExclusiveLock, false); +} + +/* + * Take a step in tracing of backend with specified pid + */ +PG_FUNCTION_INFO_V1(executor_step); +Datum +executor_step(PG_FUNCTION_ARGS) +{ + pid_t pid = PG_GETARG_INT32(0); + + exec_trace_cmd(pid, STEP); + + PG_RETURN_VOID(); +} + +/* + * Continue to execute query under tracing of backend with specified pid + */ +PG_FUNCTION_INFO_V1(executor_continue); +Datum +executor_continue(PG_FUNCTION_ARGS) +{ + pid_t pid = PG_GETARG_INT32(0); + + exec_trace_cmd(pid, CONTINUE); + + PG_RETURN_VOID(); +} diff --git a/contrib/pg_query_state/pg_query_state.control b/contrib/pg_query_state/pg_query_state.control new file mode 100644 index 0000000000..0c1bdbacbc --- /dev/null +++ b/contrib/pg_query_state/pg_query_state.control @@ -0,0 +1,5 @@ +# pg_query_state extension +comment = 'tool for inspection query progress' +default_version = '1.0' +module_pathname = '$libdir/pg_query_state' +relocatable = true diff --git a/contrib/pg_query_state/pg_query_state.h b/contrib/pg_query_state/pg_query_state.h new file mode 100644 index 0000000000..838f9176b8 --- /dev/null +++ b/contrib/pg_query_state/pg_query_state.h @@ -0,0 +1,77 @@ +/* + * pg_query_state.h + * Headers for pg_query_state extension. + * + * Copyright (c) 2016-2016, Postgres Professional + * + * IDENTIFICATION + * contrib/pg_query_state/pg_query_state.h + */ +#ifndef __PG_QUERY_STATE_H__ +#define __PG_QUERY_STATE_H__ + +#include + +#include "commands/explain.h" +#include "nodes/pg_list.h" +#include "storage/shm_mq.h" + +#define TIMINIG_OFF_WARNING 1 +#define BUFFERS_OFF_WARNING 2 + +/* + * Result status on query state request from asked backend + */ +typedef enum +{ + QUERY_NOT_RUNNING, /* Backend doesn't execute any query */ + PERM_DENIED, /* Requested party has not enough permission to get query state */ + STAT_DISABLED, /* Collection of execution statistics is disabled */ + QS_RETURNED /* Backend succesfully returned its query state */ +} PG_QS_RequestResult; + +/* + * Format of transmited data through message queue + */ +typedef struct +{ + int length; /* size of message record, for sanity check */ + PG_QS_RequestResult result_code; + int warnings; /* bitmap of warnings */ + int stack_depth; + char stack[FLEXIBLE_ARRAY_MEMBER]; /* sequencially laid out stack frames in form of + text records */ +} shm_mq_msg; + +#define BASE_SIZEOF_SHM_MQ_MSG (offsetof(shm_mq_msg, stack_depth)) + +typedef struct +{ + Oid user_id; + bool superuser; +} user_data; + +/* pg_query_state arguments */ +typedef struct +{ + bool verbose; + bool costs; + bool timing; + bool buffers; + bool triggers; + ExplainFormat format; +} pg_qs_params; + +/* pg_query_state */ +extern bool pg_qs_enable; +extern bool pg_qs_timing; +extern bool pg_qs_buffers; +extern List *QueryDescStack; +extern user_data *caller; +extern pg_qs_params *params; +extern shm_mq *mq; + +/* signal_handler.c */ +extern void SendQueryState(void); + +#endif diff --git a/contrib/pg_query_state/runtime_explain.patch b/contrib/pg_query_state/runtime_explain.patch new file mode 100644 index 0000000000..a5fb7cf26c --- /dev/null +++ b/contrib/pg_query_state/runtime_explain.patch @@ -0,0 +1,283 @@ +diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c +index 11047f7..3f5c638 100644 +--- a/src/backend/commands/explain.c ++++ b/src/backend/commands/explain.c +@@ -653,15 +653,35 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es) + Instrumentation *instr = rInfo->ri_TrigInstrument + nt; + char *relname; + char *conname = NULL; ++ instr_time starttimespan; ++ double total; ++ double ntuples; ++ double ncalls; + +- /* Must clean up instrumentation state */ +- InstrEndLoop(instr); ++ if (!es->runtime) ++ { ++ /* Must clean up instrumentation state */ ++ InstrEndLoop(instr); ++ } ++ ++ /* Collect statistic variables */ ++ if (!INSTR_TIME_IS_ZERO(instr->starttime)) ++ { ++ INSTR_TIME_SET_CURRENT(starttimespan); ++ INSTR_TIME_SUBTRACT(starttimespan, instr->starttime); ++ } ++ else ++ INSTR_TIME_SET_ZERO(starttimespan); ++ total = instr->total + INSTR_TIME_GET_DOUBLE(instr->counter) ++ + INSTR_TIME_GET_DOUBLE(starttimespan); ++ ntuples = instr->ntuples + instr->tuplecount; ++ ncalls = ntuples + !INSTR_TIME_IS_ZERO(starttimespan); + + /* + * We ignore triggers that were never invoked; they likely aren't + * relevant to the current query type. + */ +- if (instr->ntuples == 0) ++ if (ncalls == 0) + continue; + + ExplainOpenGroup("Trigger", NULL, true, es); +@@ -687,9 +707,9 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es) + appendStringInfo(es->str, " on %s", relname); + if (es->timing) + appendStringInfo(es->str, ": time=%.3f calls=%.0f\n", +- 1000.0 * instr->total, instr->ntuples); ++ 1000.0 * total, ncalls); + else +- appendStringInfo(es->str, ": calls=%.0f\n", instr->ntuples); ++ appendStringInfo(es->str, ": calls=%.0f\n", ncalls); + } + else + { +@@ -698,8 +718,8 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es) + ExplainPropertyText("Constraint Name", conname, es); + ExplainPropertyText("Relation", relname, es); + if (es->timing) +- ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es); +- ExplainPropertyFloat("Calls", instr->ntuples, 0, es); ++ ExplainPropertyFloat("Time", 1000.0 * total, 3, es); ++ ExplainPropertyFloat("Calls", ncalls, 0, es); + } + + if (conname) +@@ -1247,8 +1267,11 @@ ExplainNode(PlanState *planstate, List *ancestors, + * instrumentation results the user didn't ask for. But we do the + * InstrEndLoop call anyway, if possible, to reduce the number of cases + * auto_explain has to contend with. ++ * ++ * if flag es->stateinfo is set i.e. when printing the current execution state ++ * this step of cleaning up is miss + */ +- if (planstate->instrument) ++ if (planstate->instrument && !es->runtime) + InstrEndLoop(planstate->instrument); + + if (es->analyze && +@@ -1281,7 +1304,7 @@ ExplainNode(PlanState *planstate, List *ancestors, + ExplainPropertyFloat("Actual Loops", nloops, 0, es); + } + } +- else if (es->analyze) ++ else if (es->analyze && !es->runtime) + { + if (es->format == EXPLAIN_FORMAT_TEXT) + appendStringInfoString(es->str, " (never executed)"); +@@ -1297,6 +1320,75 @@ ExplainNode(PlanState *planstate, List *ancestors, + } + } + ++ /* ++ * print the progress of node execution at current loop ++ */ ++ if (planstate->instrument && es->analyze && es->runtime) ++ { ++ instr_time starttimespan; ++ double startup_sec; ++ double total_sec; ++ double rows; ++ double loop_num; ++ bool finished; ++ ++ if (!INSTR_TIME_IS_ZERO(planstate->instrument->starttime)) ++ { ++ INSTR_TIME_SET_CURRENT(starttimespan); ++ INSTR_TIME_SUBTRACT(starttimespan, planstate->instrument->starttime); ++ } ++ else ++ INSTR_TIME_SET_ZERO(starttimespan); ++ startup_sec = 1000.0 * planstate->instrument->firsttuple; ++ total_sec = 1000.0 * (INSTR_TIME_GET_DOUBLE(planstate->instrument->counter) ++ + INSTR_TIME_GET_DOUBLE(starttimespan)); ++ rows = planstate->instrument->tuplecount; ++ loop_num = planstate->instrument->nloops + 1; ++ ++ finished = planstate->instrument->nloops > 0 ++ && !planstate->instrument->running ++ && INSTR_TIME_IS_ZERO(starttimespan); ++ ++ if (!finished) ++ { ++ ExplainOpenGroup("Current loop", "Current loop", true, es); ++ if (es->format == EXPLAIN_FORMAT_TEXT) ++ { ++ if (es->timing) ++ { ++ if (planstate->instrument->running) ++ appendStringInfo(es->str, ++ " (Current loop: actual time=%.3f..%.3f rows=%.0f, loop number=%.0f)", ++ startup_sec, total_sec, rows, loop_num); ++ else ++ appendStringInfo(es->str, ++ " (Current loop: running time=%.3f actual rows=0, loop number=%.0f)", ++ total_sec, loop_num); ++ } ++ else ++ appendStringInfo(es->str, ++ " (Current loop: actual rows=%.0f, loop number=%.0f)", ++ rows, loop_num); ++ } ++ else ++ { ++ ExplainPropertyFloat("Actual Loop Number", loop_num, 0, es); ++ if (es->timing) ++ { ++ if (planstate->instrument->running) ++ { ++ ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es); ++ ExplainPropertyFloat("Actual Total Time", total_sec, 3, es); ++ } ++ else ++ ExplainPropertyFloat("Running Time", total_sec, 3, es); ++ } ++ ExplainPropertyFloat("Actual Rows", rows, 0, es); ++ } ++ ExplainCloseGroup("Current loop", "Current loop", true, es); ++ } ++ } ++ + /* in text format, first line ends here */ + if (es->format == EXPLAIN_FORMAT_TEXT) + appendStringInfoChar(es->str, '\n'); +@@ -2293,20 +2385,17 @@ show_instrumentation_count(const char *qlabel, int which, + if (!es->analyze || !planstate->instrument) + return; + ++ nloops = planstate->instrument->nloops; + if (which == 2) +- nfiltered = planstate->instrument->nfiltered2; ++ nfiltered = ((nloops > 0) ? planstate->instrument->accum_nfiltered2 / nloops : 0) ++ + planstate->instrument->nfiltered2; + else +- nfiltered = planstate->instrument->nfiltered1; +- nloops = planstate->instrument->nloops; ++ nfiltered = ((nloops > 0) ? planstate->instrument->accum_nfiltered1 / nloops : 0) ++ + planstate->instrument->nfiltered1; + + /* In text mode, suppress zero counts; they're not interesting enough */ + if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT) +- { +- if (nloops > 0) +- ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es); +- else +- ExplainPropertyFloat(qlabel, 0.0, 0, es); +- } ++ ExplainPropertyFloat(qlabel, nfiltered, 0, es); + } + + /* +@@ -2658,14 +2747,28 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, + double insert_path; + double other_path; + +- InstrEndLoop(mtstate->mt_plans[0]->instrument); ++ if (!es->runtime) ++ InstrEndLoop(mtstate->mt_plans[0]->instrument); + + /* count the number of source rows */ +- total = mtstate->mt_plans[0]->instrument->ntuples; +- other_path = mtstate->ps.instrument->nfiltered2; +- insert_path = total - other_path; ++ other_path = mtstate->ps.instrument->accum_nfiltered2 ++ + mtstate->ps.instrument->nfiltered2; ++ ++ /* ++ * Insert occurs after extracting row from subplan and in runtime mode ++ * we can appear between these two operations - situation when ++ * total > insert_path + other_path. Therefore we don't know exactly ++ * whether last row from subplan is inserted. ++ * We don't print inserted tuples in runtime mode in order to not print ++ * inconsistent data ++ */ ++ if (!es->runtime) ++ { ++ total = mtstate->mt_plans[0]->instrument->ntuples; ++ insert_path = total - other_path; ++ ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es); ++ } + +- ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es); + ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es); + } + } +diff --git a/src/backend/executor/instrument.c b/src/backend/executor/instrument.c +index f5351eb..591ea0f 100644 +--- a/src/backend/executor/instrument.c ++++ b/src/backend/executor/instrument.c +@@ -118,6 +118,8 @@ InstrEndLoop(Instrumentation *instr) + instr->total += totaltime; + instr->ntuples += instr->tuplecount; + instr->nloops += 1; ++ instr->accum_nfiltered1 += instr->nfiltered1; ++ instr->accum_nfiltered2 += instr->nfiltered2; + + /* Reset for next cycle (if any) */ + instr->running = false; +@@ -125,6 +127,8 @@ InstrEndLoop(Instrumentation *instr) + INSTR_TIME_SET_ZERO(instr->counter); + instr->firsttuple = 0; + instr->tuplecount = 0; ++ instr->nfiltered1 = 0; ++ instr->nfiltered2 = 0; + } + + /* dst += add - sub */ +diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h +index 26fcc5b..2ad3fb8 100644 +--- a/src/include/commands/explain.h ++++ b/src/include/commands/explain.h +@@ -35,6 +35,8 @@ typedef struct ExplainState + bool timing; /* print detailed node timing */ + bool summary; /* print total planning and execution timing */ + ExplainFormat format; /* output format */ ++ bool runtime; /* print intermediate state of query execution, ++ not after completion */ + /* other states */ + PlannedStmt *pstmt; /* top of plan */ + List *rtable; /* range table */ +diff --git a/src/include/executor/instrument.h b/src/include/executor/instrument.h +index c9a2129..c53517f 100644 +--- a/src/include/executor/instrument.h ++++ b/src/include/executor/instrument.h +@@ -52,14 +52,16 @@ typedef struct Instrumentation + instr_time counter; /* Accumulated runtime for this node */ + double firsttuple; /* Time for first tuple of this cycle */ + double tuplecount; /* Tuples emitted so far this cycle */ ++ double nfiltered1; /* # tuples removed by scanqual or joinqual */ ++ double nfiltered2; /* # tuples removed by "other" quals */ + BufferUsage bufusage_start; /* Buffer usage at start */ + /* Accumulated statistics across all completed cycles: */ + double startup; /* Total startup time (in seconds) */ + double total; /* Total total time (in seconds) */ + double ntuples; /* Total tuples produced */ + double nloops; /* # of run cycles for this node */ +- double nfiltered1; /* # tuples removed by scanqual or joinqual */ +- double nfiltered2; /* # tuples removed by "other" quals */ ++ double accum_nfiltered1; /* # tuples removed by scanqual or joinqual on previous loops */ ++ double accum_nfiltered2; /* # tuples removed by "other" quals on previous loops */ + BufferUsage bufusage; /* Total buffer usage */ + } Instrumentation; + diff --git a/contrib/pg_query_state/signal_handler.c b/contrib/pg_query_state/signal_handler.c new file mode 100644 index 0000000000..796f055f3f --- /dev/null +++ b/contrib/pg_query_state/signal_handler.c @@ -0,0 +1,216 @@ +/* + * signal_handler.c + * Collect current query state and send it to requestor in custom signal handler + * + * Copyright (c) 2016-2016, Postgres Professional + * + * IDENTIFICATION + * contrib/pg_query_state/signal_handler.c + */ + +#include "pg_query_state.h" + +#include "commands/explain.h" +#include "miscadmin.h" +#include "utils/builtins.h" +#include "utils/memutils.h" + +/* + * Structure of stack frame of fucntion call which resulted from analyze of query state + */ +typedef struct +{ + const char *query; + char *plan; +} stack_frame; + +/* + * Get List of stack_frames as a stack of function calls starting from outermost call. + * Each entry contains query text and query state in form of EXPLAIN ANALYZE output. + * Assume extension is enabled and QueryDescStack is not empty + */ +static List * +runtime_explain() +{ + ExplainState *es; + ListCell *i; + List *result = NIL; + + Assert(list_length(QueryDescStack) > 0); + + /* initialize explain state with all config parameters */ + es = NewExplainState(); + es->analyze = true; + es->verbose = params->verbose; + es->costs = params->costs; + es->buffers = params->buffers && pg_qs_buffers; + es->timing = params->timing && pg_qs_timing; + es->summary = false; + es->format = params->format; + es->runtime = true; + + /* collect query state outputs of each plan entry of stack */ + foreach(i, QueryDescStack) + { + QueryDesc *currentQueryDesc = (QueryDesc *) lfirst(i); + stack_frame *qs_frame = palloc(sizeof(stack_frame)); + + /* save query text */ + qs_frame->query = currentQueryDesc->sourceText; + + /* save plan with statistics */ + initStringInfo(es->str); + ExplainBeginOutput(es); + ExplainPrintPlan(es, currentQueryDesc); + if (params->triggers) + ExplainPrintTriggers(es, currentQueryDesc); + ExplainEndOutput(es); + + /* Remove last line break */ + if (es->str->len > 0 && es->str->data[es->str->len - 1] == '\n') + es->str->data[--es->str->len] = '\0'; + + /* Fix JSON to output an object */ + if (params->format == EXPLAIN_FORMAT_JSON) + { + es->str->data[0] = '{'; + es->str->data[es->str->len - 1] = '}'; + } + + qs_frame->plan = es->str->data; + + result = lcons(qs_frame, result); + } + + return result; +} + +/* + * Compute length of serialized stack frame + */ +static int +serialized_stack_frame_length(stack_frame *qs_frame) +{ + return INTALIGN(strlen(qs_frame->query) + VARHDRSZ) + + INTALIGN(strlen(qs_frame->plan) + VARHDRSZ); +} + +/* + * Compute overall length of serialized stack of function calls + */ +static int +serialized_stack_length(List *qs_stack) +{ + ListCell *i; + int result = 0; + + foreach(i, qs_stack) + { + stack_frame *qs_frame = (stack_frame *) lfirst(i); + + result += serialized_stack_frame_length(qs_frame); + } + + return result; +} + +/* + * Convert stack_frame record into serialized text format version + * Increment '*dest' pointer to the next serialized stack frame + */ +static void +serialize_stack_frame(char **dest, stack_frame *qs_frame) +{ + SET_VARSIZE(*dest, strlen(qs_frame->query) + VARHDRSZ); + memcpy(VARDATA(*dest), qs_frame->query, strlen(qs_frame->query)); + *dest += INTALIGN(VARSIZE(*dest)); + + SET_VARSIZE(*dest, strlen(qs_frame->plan) + VARHDRSZ); + memcpy(VARDATA(*dest), qs_frame->plan, strlen(qs_frame->plan)); + *dest += INTALIGN(VARSIZE(*dest)); +} + +/* + * Convert List of stack_frame records into serialized structures laid out sequentially + */ +static void +serialize_stack(char *dest, List *qs_stack) +{ + ListCell *i; + + foreach(i, qs_stack) + { + stack_frame *qs_frame = (stack_frame *) lfirst(i); + + serialize_stack_frame(&dest, qs_frame); + } +} + +/* + * Send state of current query to shared queue. + * This function is called when fire custom signal QueryStatePollReason + */ +void +SendQueryState(void) +{ + shm_mq_handle *mqh; + MemoryContext curCxt; + MemoryContext oldCxt; + + curCxt = AllocSetContextCreate(CurrentMemoryContext, + "pg_query_state signal handler context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldCxt = MemoryContextSwitchTo(curCxt); + + mqh = shm_mq_attach(mq, NULL, NULL); + + /* check if module is enabled */ + if (!pg_qs_enable) + { + shm_mq_msg msg = { BASE_SIZEOF_SHM_MQ_MSG, STAT_DISABLED }; + + shm_mq_send(mqh, msg.length, &msg, false); + } + + /* check if current user has not grants to request state of remote backend process */ + else if (!(caller->superuser || (GetUserId() == caller->user_id))) + { + shm_mq_msg msg = { BASE_SIZEOF_SHM_MQ_MSG, PERM_DENIED }; + + shm_mq_send(mqh, msg.length, &msg, false); + } + + /* check if backend doesn't execute any query */ + else if (list_length(QueryDescStack) == 0) + { + shm_mq_msg msg = { BASE_SIZEOF_SHM_MQ_MSG, QUERY_NOT_RUNNING }; + + shm_mq_send(mqh, msg.length, &msg, false); + } + + /* happy path */ + else + { + List *qs_stack = runtime_explain(); + int msglen = sizeof(shm_mq_msg) + serialized_stack_length(qs_stack); + shm_mq_msg *msg = palloc(msglen); + + msg->length = msglen; + msg->result_code = QS_RETURNED; + + msg->warnings = 0; + if (params->timing && !pg_qs_timing) + msg->warnings |= TIMINIG_OFF_WARNING; + if (params->buffers && !pg_qs_buffers) + msg->warnings |= BUFFERS_OFF_WARNING; + + msg->stack_depth = list_length(qs_stack); + serialize_stack(msg->stack, qs_stack); + shm_mq_send(mqh, msglen, msg, false); + } + + MemoryContextSwitchTo(oldCxt); + MemoryContextDelete(curCxt); +} diff --git a/contrib/pg_query_state/specs/corner_cases.spec b/contrib/pg_query_state/specs/corner_cases.spec new file mode 100644 index 0000000000..292b39dec0 --- /dev/null +++ b/contrib/pg_query_state/specs/corner_cases.spec @@ -0,0 +1,75 @@ +setup +{ + CREATE EXTENSION pg_query_state; + CREATE ROLE alice; + CREATE ROLE bob; + CREATE ROLE super SUPERUSER; + CREATE TABLE IF NOT EXISTS pid_storage ( + id integer CONSTRAINT unique_entry UNIQUE, + pid integer + ); + CREATE OR REPLACE FUNCTION save_own_pid(integer) RETURNS void AS $$ + BEGIN + INSERT INTO pid_storage VALUES($1, pg_backend_pid()) + ON CONFLICT ON CONSTRAINT unique_entry DO + UPDATE SET pid = pg_backend_pid(); + END; + $$ LANGUAGE plpgsql; + CREATE OR REPLACE FUNCTION counterpart_pid(integer) RETURNS integer AS $$ + BEGIN + return (SELECT pid FROM pid_storage WHERE id = $1); + END; + $$ LANGUAGE plpgsql; + GRANT SELECT, INSERT, UPDATE on pid_storage to alice, bob; +} + +teardown +{ + DROP FUNCTION save_own_pid(integer); + DROP FUNCTION counterpart_pid(integer); + DROP TABLE pid_storage; + DROP ROLE super; + DROP ROLE bob; + DROP ROLE alice; + DROP EXTENSION pg_query_state; +} + +session "s1" +step "s1_save_pid" { select save_own_pid(0); } +step "s1_pg_qs_counterpart" { select pg_query_state(counterpart_pid(1)); } +step "s1_set_bob" { set role bob; } +step "s1_disable_pg_qs" { set pg_query_state.enable to off; } +step "s1_enable_pg_qs" { set pg_query_state.enable to on; } +step "s1_pg_qs_1" { select pg_query_state(1); } +step "s1_pg_qs_2" { select pg_query_state(pg_backend_pid()); } +teardown +{ + reset role; + set pg_query_state.enable to on; +} + +session "s2" +step "s2_save_pid" { select save_own_pid(1); } +step "s2_pg_qs_counterpart" { select pg_query_state(counterpart_pid(0)); } +step "s2_set_bob" { set role bob; } +step "s2_set_alice" { set role alice; } +step "s2_set_su" { set role super; } +teardown +{ + reset role; +} + +# Check invalid pid +permutation "s1_pg_qs_1" +permutation "s1_pg_qs_2" + +# Check idle +permutation "s1_save_pid" "s2_pg_qs_counterpart" + +# Check module disable +permutation "s1_save_pid" "s1_disable_pg_qs" "s2_pg_qs_counterpart" + +# Check roles correspondence +permutation "s1_set_bob" "s2_set_bob" "s1_save_pid" "s2_pg_qs_counterpart" +permutation "s1_set_bob" "s2_set_su" "s1_save_pid" "s2_pg_qs_counterpart" +permutation "s1_set_bob" "s2_set_alice" "s1_save_pid" "s2_pg_qs_counterpart" diff --git a/contrib/pg_query_state/test.conf b/contrib/pg_query_state/test.conf new file mode 100644 index 0000000000..d706f742b9 --- /dev/null +++ b/contrib/pg_query_state/test.conf @@ -0,0 +1 @@ +shared_preload_libraries='pg_query_state' diff --git a/contrib/pg_query_state/tests/pg_qs_test_runner.py b/contrib/pg_query_state/tests/pg_qs_test_runner.py new file mode 100644 index 0000000000..8a12b50a9a --- /dev/null +++ b/contrib/pg_query_state/tests/pg_qs_test_runner.py @@ -0,0 +1,104 @@ +''' +pg_qs_test_cases.py + Tests extract query state from running backend (including concurrent extracts) +Copyright (c) 2016-2016, Postgres Professional +''' + +import argparse +import psycopg2 +import sys +from test_cases import * + +class PasswordPromptAction(argparse.Action): + def __call__(self, parser, args, values, option_string=None): + password = getpass.getpass() + setattr(args, self.dest, password) + +class SetupException(Exception): pass +class TeardownException(Exception): pass + +setup_cmd = [ + 'drop extension if exists pg_query_state cascade', + 'drop table if exists foo cascade', + 'drop table if exists bar cascade', + 'create extension pg_query_state', + 'create table foo(c1 integer, c2 text)', + 'create table bar(c1 integer, c2 boolean)', + 'insert into foo select i, md5(random()::text) from generate_series(1, 1000000) as i', + 'insert into bar select i, i%2=1 from generate_series(1, 500000) as i', + 'analyze foo', + 'analyze bar', + ] + +teardown_cmd = [ + 'drop table foo cascade', + 'drop table bar cascade', + 'drop extension pg_query_state cascade', + ] + +tests = [ + test_deadlock, + test_simple_query, + test_concurrent_access, + test_nested_call, + test_insert_on_conflict, + test_trigger, + test_costs, + test_buffers, + test_timing, + test_formats, + test_timing_buffers_conflicts, + ] + +def setup(con): + ''' Creates pg_query_state extension, creates tables for tests, fills it with data ''' + print 'setting up...' + try: + cur = con.cursor() + for cmd in setup_cmd: + cur.execute(cmd) + con.commit() + cur.close() + except Exception, e: + raise SetupException('Setup failed: %s' % e) + print 'done!' + +def teardown(con): + ''' Drops table and extension ''' + print 'tearing down...' + try: + cur = con.cursor() + for cmd in teardown_cmd: + cur.execute(cmd) + con.commit() + cur.close() + except Exception, e: + raise TeardownException('Teardown failed: %s' % e) + print 'done!' + +def main(config): + ''' Main test function ''' + con = psycopg2.connect(**config) + setup(con) + + for i, test in enumerate(tests): + if test.__doc__: + descr = test.__doc__ + else: + descr = 'test case %d' % (i+1) + print ("%s..." % descr),; sys.stdout.flush() + test(config) + print 'ok!' + + teardown(con) + con.close() + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Query state of running backends tests') + parser.add_argument('--host', default='localhost', help='postgres server host') + parser.add_argument('--port', type=int, default=5432, help='postgres server port') + parser.add_argument('--user', dest='user', default='postgres', help='user name') + parser.add_argument('--database', dest='database', default='postgres', help='database name') + parser.add_argument('--password', dest='password', nargs=0, action=PasswordPromptAction, default='') + args = parser.parse_args() + main(args.__dict__) diff --git a/contrib/pg_query_state/tests/test_cases.py b/contrib/pg_query_state/tests/test_cases.py new file mode 100644 index 0000000000..2384e609d3 --- /dev/null +++ b/contrib/pg_query_state/tests/test_cases.py @@ -0,0 +1,451 @@ +import json +import psycopg2 +import psycopg2.extensions +import re +import select +import time +import xml.etree.ElementTree as ET +import yaml + +def wait(conn): + """wait for some event on connection to postgres""" + while 1: + state = conn.poll() + if state == psycopg2.extensions.POLL_OK: + break + elif state == psycopg2.extensions.POLL_WRITE: + select.select([], [conn.fileno()], []) + elif state == psycopg2.extensions.POLL_READ: + select.select([conn.fileno()], [], []) + else: + raise psycopg2.OperationalError("poll() returned %s" % state) + +def n_async_connect(config, n=1): + """establish n asynchronious connections to the postgres with specified config""" + + aconfig = config.copy() + aconfig['async'] = True + + result = [] + for _ in xrange(n): + conn = psycopg2.connect(**aconfig) + wait(conn) + result.append(conn) + return result + +def n_close(conns): + """close connections to postgres""" + + for conn in conns: + conn.close() + +notices = [] + +def pg_query_state(config, pid, verbose=False, costs=False, timing=False, \ + buffers=False, triggers=False, format='text'): + """ + Get query state from backend with specified pid and optional parameters. + Save any warning, info, notice and log data in global variable 'notices' + """ + + global notices + + conn = psycopg2.connect(**config) + curs = conn.cursor() + + curs.callproc('pg_query_state', (pid, verbose, costs, timing, buffers, triggers, format)) + result = curs.fetchall() + + notices = conn.notices[:] + conn.close() + return result + +def test_deadlock(config): + """test when two backends try to extract state of each other""" + + acon1, acon2 = n_async_connect(config, 2) + acurs1 = acon1.cursor() + acurs2 = acon2.cursor() + + while True: + acurs1.callproc('pg_query_state', (acon2.get_backend_pid(),)) + acurs2.callproc('pg_query_state', (acon1.get_backend_pid(),)) + + # listen acon1, acon2 with timeout = 10 sec to determine deadlock + r, w, x = select.select([acon1.fileno(), acon2.fileno()], [], [], 10) + assert (r or w or x), "Deadlock is happened under cross reading of query states" + + wait(acon1) + wait(acon2) + + # exit from loop if one backend could read state of execution 'pg_query_state' + # from other backend + if acurs1.fetchone() or acurs2.fetchone(): + break + + n_close((acon1, acon2)) + +def query_state(config, async_conn, query, steps, args={}): + """ + Get intermediate state of 'query' on connection 'async_conn' after number of 'steps' + of node executions from start of query + """ + + acurs = async_conn.cursor() + conn = psycopg2.connect(**config) + curs = conn.cursor() + + set_guc(async_conn, 'enable_mergejoin', 'off') + set_guc(async_conn, 'pg_query_state.executor_trace', 'on') + + # execute 'query' specific number of 'steps' + acurs.execute(query) + for _ in xrange(steps): + curs.callproc('executor_step', (async_conn.get_backend_pid(),)) + # import ipdb; ipdb.set_trace() + + # extract current state of query progress + pg_qs_args = { + 'config': config, + 'pid': async_conn.get_backend_pid() + } + for k, v in args.iteritems(): + pg_qs_args[k] = v + result = pg_query_state(**pg_qs_args) + + # resume query progress and complete it + curs.callproc('executor_continue', (async_conn.get_backend_pid(),)) + wait(async_conn) + + set_guc(async_conn, 'pg_query_state.executor_trace', 'off') + set_guc(async_conn, 'enable_mergejoin', 'on') + + conn.close() + return result + +def test_simple_query(config): + """test statistics of simple query""" + + acon, = n_async_connect(config) + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + num_steps = 10 + expected = r"""Aggregate \(Current loop: actual rows=0, loop number=1\) + -> Hash Join \(Current loop: actual rows=0, loop number=1\) + Hash Cond: \(foo.c1 = bar.c1\) + -> Seq Scan on foo \(Current loop: actual rows=1, loop number=1\) + -> Hash \(Current loop: actual rows=0, loop number=1\) + Buckets: \d+ Batches: \d+ Memory Usage: \d+kB + -> Seq Scan on bar \(Current loop: actual rows=9, loop number=1\)""" + + qs = query_state(config, acon, query, num_steps) + assert len(qs) == 1 and qs[0][0] == query and re.match(expected, qs[0][1]) + assert len(notices) == 0 + + n_close((acon,)) + +def test_concurrent_access(config): + """test when two backends compete with each other to extract state from third running backend""" + + acon1, acon2, acon3 = n_async_connect(config, 3) + acurs1, acurs2, acurs3 = acon1.cursor(), acon2.cursor(), acon3.cursor() + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + + acurs3.execute(query) + time.sleep(0.1) + acurs1.callproc('pg_query_state', (acon3.get_backend_pid(),)) + acurs2.callproc('pg_query_state', (acon3.get_backend_pid(),)) + wait(acon1) + wait(acon2) + wait(acon3) + + qs1, qs2 = acurs1.fetchall(), acurs2.fetchall() + assert len(qs1) == len(qs2) == 1 \ + and qs1[0][0] == qs2[0][0] == query \ + and len(qs1[0][1]) > 0 and len(qs2[0][1]) > 0 + assert len(notices) == 0 + + n_close((acon1, acon2, acon3)) + +def test_nested_call(config): + """test statistics under calling function""" + + acon, = n_async_connect(config) + util_conn = psycopg2.connect(**config) + util_curs = util_conn.cursor() + create_function = """ + create or replace function n_join_foo_bar() returns integer as $$ + begin + return (select count(*) from foo join bar on foo.c1=bar.c1); + end; + $$ language plpgsql""" + drop_function = 'drop function n_join_foo_bar()' + call_function = 'select * from n_join_foo_bar()' + nested_query = 'SELECT (select count(*) from foo join bar on foo.c1=bar.c1)' + num_steps = 10 + expected = 'Function Scan on n_join_foo_bar (Current loop: actual rows=0, loop number=1)' + expected_nested = r"""Result \(Current loop: actual rows=0, loop number=1\) + InitPlan 1 \(returns \$0\) + -> Aggregate \(Current loop: actual rows=0, loop number=1\) + -> Hash Join \(Current loop: actual rows=0, loop number=1\) + Hash Cond: \(foo.c1 = bar.c1\) + -> Seq Scan on foo \(Current loop: actual rows=1, loop number=1\) + -> Hash \(Current loop: actual rows=0, loop number=1\) + Buckets: \d+ Batches: \d+ Memory Usage: \d+kB + -> Seq Scan on bar \(Current loop: actual rows=8, loop number=1\)""" + + util_curs.execute(create_function) + util_conn.commit() + + qs = query_state(config, acon, call_function, num_steps) + assert len(qs) == 2 \ + and qs[0][0] == call_function and qs[0][1] == expected \ + and qs[1][0] == nested_query and re.match(expected_nested, qs[1][1]) + assert len(notices) == 0 + + + util_curs.execute(drop_function) + + util_conn.close() + n_close((acon,)) + +def test_insert_on_conflict(config): + """test statistics on conflicting tuples under INSERT ON CONFLICT query""" + + acon, = n_async_connect(config) + util_conn = psycopg2.connect(**config) + util_curs = util_conn.cursor() + add_field_uniqueness = 'alter table foo add constraint unique_c1 unique(c1)' + drop_field_uniqueness = 'alter table foo drop constraint unique_c1' + num_steps = 10 + query = 'insert into foo select i, md5(random()::text) from generate_series(1, %d) as i on conflict do nothing' % (num_steps + 1) + expected = """Insert on foo (Current loop: actual rows=0, loop number=1) + Conflict Resolution: NOTHING + Conflicting Tuples: 9 + -> Function Scan on generate_series i (Current loop: actual rows=10, loop number=1)""" + + util_curs.execute(add_field_uniqueness) + util_conn.commit() + + qs = query_state(config, acon, query, num_steps) + assert len(qs) == 1 and qs[0][0] == query and qs[0][1] == expected + assert len(notices) == 0 + + util_curs.execute(drop_field_uniqueness) + + util_conn.close() + n_close((acon,)) + +def set_guc(async_conn, param, value): + acurs = async_conn.cursor() + acurs.execute('set %s to %s' % (param, value)) + wait(async_conn) + +def test_trigger(config): + """test trigger statistics""" + + acon, = n_async_connect(config) + acurs = acon.cursor() + util_conn = psycopg2.connect(**config) + util_curs = util_conn.cursor() + create_trigger_function = """ + create or replace function unique_c1_in_foo() returns trigger as $$ + begin + if new.c1 in (select c1 from foo) then + return null; + end if; + return new; + end; + $$ language plpgsql""" + create_trigger = """ + create trigger unique_foo_c1 + before insert or update of c1 on foo for row + execute procedure unique_c1_in_foo()""" + drop_temps = 'drop function unique_c1_in_foo() cascade' + num_steps = 10 + query = 'insert into foo select i, md5(random()::text) from generate_series(1, %d) as i' % (num_steps + 1) + expected_upper = """Insert on foo (Current loop: actual rows=0, loop number=1) + -> Function Scan on generate_series i (Current loop: actual rows=2, loop number=1)""" + trigger_suffix = 'Trigger unique_foo_c1: calls=1' + expected_inner = """Result (Current loop: actual rows=0, loop number=1) + SubPlan 1 + -> Materialize (Current loop: actual rows=1, loop number=1) + -> Seq Scan on foo (Current loop: actual rows=1, loop number=1)""" + + util_curs.execute(create_trigger_function) + util_curs.execute(create_trigger) + util_conn.commit() + + qs = query_state(config, acon, query, num_steps, {'triggers': True}) + assert len(qs) == 2 \ + and qs[0][0] == query and qs[0][1] == expected_upper + '\n' + trigger_suffix \ + and qs[1][0] == 'SELECT new.c1 in (select c1 from foo)' and qs[1][1] == expected_inner + assert len(notices) == 0 + + qs = query_state(config, acon, query, num_steps, {'triggers': False}) + assert len(qs) == 2 \ + and qs[0][0] == query and qs[0][1] == expected_upper \ + and qs[1][0] == 'SELECT new.c1 in (select c1 from foo)' and qs[1][1] == expected_inner + assert len(notices) == 0 + + util_curs.execute(drop_temps) + + util_conn.close() + n_close((acon,)) + +def test_costs(config): + """test plan costs""" + + acon, = n_async_connect(config) + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + num_steps = 10 + expected = r"""Aggregate \(cost=\d+.\d+..\d+.\d+ rows=\d+ width=0\) \(Current loop: actual rows=0, loop number=1\) + -> Hash Join \(cost=\d+.\d+..\d+.\d+ rows=\d+ width=0\) \(Current loop: actual rows=0, loop number=1\) + Hash Cond: \(foo.c1 = bar.c1\) + -> Seq Scan on foo \(cost=0.00..\d+.\d+ rows=\d+ width=4\) \(Current loop: actual rows=1, loop number=1\) + -> Hash \(cost=\d+.\d+..\d+.\d+ rows=\d+ width=4\) \(Current loop: actual rows=0, loop number=1\) + Buckets: \d+ Batches: \d+ Memory Usage: \d+kB + -> Seq Scan on bar \(cost=0.00..\d+.\d+ rows=\d+ width=4\) \(Current loop: actual rows=9, loop number=1\)""" + + qs = query_state(config, acon, query, num_steps, {'costs': True}) + assert len(qs) == 1 and re.match(expected, qs[0][1]) + assert len(notices) == 0 + + n_close((acon,)) + +def test_buffers(config): + """test buffer statistics""" + + acon, = n_async_connect(config) + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + num_steps = 10 + expected = r"""Aggregate \(Current loop: actual rows=0, loop number=1\) + -> Hash Join \(Current loop: actual rows=0, loop number=1\) + Hash Cond: \(foo.c1 = bar.c1\) + -> Seq Scan on foo \(Current loop: actual rows=1, loop number=1\) + Buffers: [^\n]* + -> Hash \(Current loop: actual rows=0, loop number=1\) + Buckets: \d+ Batches: \d+ Memory Usage: \d+kB + -> Seq Scan on bar \(Current loop: actual rows=9, loop number=1\) + Buffers: .*""" + + set_guc(acon, 'pg_query_state.enable_buffers', 'on') + + qs = query_state(config, acon, query, num_steps, {'buffers': True}) + assert len(qs) == 1 and re.match(expected, qs[0][1]) + assert len(notices) == 0 + + n_close((acon,)) + +def test_timing(config): + """test timing statistics""" + + acon, = n_async_connect(config) + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + num_steps = 10 + expected = r"""Aggregate \(Current loop: running time=\d+.\d+ actual rows=0, loop number=1\) + -> Hash Join \(Current loop: running time=\d+.\d+ actual rows=0, loop number=1\) + Hash Cond: \(foo.c1 = bar.c1\) + -> Seq Scan on foo \(Current loop: actual time=\d+.\d+..\d+.\d+ rows=1, loop number=1\) + -> Hash \(Current loop: running time=\d+.\d+ actual rows=0, loop number=1\) + Buckets: \d+ Batches: \d+ Memory Usage: \d+kB + -> Seq Scan on bar \(Current loop: actual time=\d+.\d+..\d+.\d+ rows=9, loop number=1\)""" + + set_guc(acon, 'pg_query_state.enable_timing', 'on') + + qs = query_state(config, acon, query, num_steps, {'timing': True}) + assert len(qs) == 1 and re.match(expected, qs[0][1]) + assert len(notices) == 0 + + n_close((acon,)) + +def check_plan(plan): + assert plan.has_key('Current loop') + cur_loop = plan['Current loop'] + assert cur_loop.has_key('Actual Loop Number') \ + and cur_loop.has_key('Actual Rows') + + if not plan.has_key('Plans'): + return + + for subplan in plan['Plans']: + check_plan(subplan) + +def check_xml(root): + prefix = '{http://www.postgresql.org/2009/explain}' + for plan in root.iter(prefix + 'Plan'): + cur_loop = plan.find(prefix + 'Current-loop') + assert cur_loop != None \ + and cur_loop.find(prefix + 'Actual-Loop-Number') != None \ + and cur_loop.find(prefix + 'Actual-Rows') != None + +def test_formats(config): + """test all formats of pg_query_state output""" + + acon, = n_async_connect(config) + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + num_steps = 10 + expected = r"""Aggregate \(Current loop: actual rows=0, loop number=1\) + -> Hash Join \(Current loop: actual rows=0, loop number=1\) + Hash Cond: \(foo.c1 = bar.c1\) + -> Seq Scan on foo \(Current loop: actual rows=1, loop number=1\) + -> Hash \(Current loop: actual rows=0, loop number=1\) + Buckets: \d+ Batches: \d+ Memory Usage: \d+kB + -> Seq Scan on bar \(Current loop: actual rows=9, loop number=1\)""" + + qs = query_state(config, acon, query, num_steps, {'format': 'text'}) + assert len(qs) == 1 and re.match(expected, qs[0][1]) + assert len(notices) == 0 + + qs = query_state(config, acon, query, num_steps, {'format': 'json'}) + try: + js_obj = json.loads(qs[0][1]) + except ValueError: + assert False, 'Invalid json format' + assert len(qs) == 1 + assert len(notices) == 0 + check_plan(js_obj['Plan']) + + qs = query_state(config, acon, query, num_steps, {'format': 'xml'}) + assert len(qs) == 1 + assert len(notices) == 0 + try: + xml_root = ET.fromstring(qs[0][1]) + except: + assert False, 'Invalid xml format' + check_xml(xml_root) + + qs = query_state(config, acon, query, num_steps, {'format': 'yaml'}) + try: + yaml_doc = yaml.load(qs[0][1]) + except: + assert False, 'Invalid yaml format' + assert len(qs) == 1 + assert len(notices) == 0 + check_plan(yaml_doc['Plan']) + + n_close((acon,)) + +def test_timing_buffers_conflicts(config): + """test when caller requests timing and buffers but counterpart turned off its""" + + acon, = n_async_connect(config) + query = 'select count(*) from foo join bar on foo.c1=bar.c1' + num_steps = 10 + timing_pattern = '(?:running time=\d+.\d+)|(?:actual time=\d+.\d+..\d+.\d+)' + buffers_pattern = 'Buffers:' + + qs = query_state(config, acon, query, num_steps, {'timing': True, 'buffers': False}) + assert len(qs) == 1 and not re.search(timing_pattern, qs[0][1]) + assert notices == ['WARNING: timing statistics disabled\n'] + + qs = query_state(config, acon, query, num_steps, {'timing': False, 'buffers': True}) + assert len(qs) == 1 and not re.search(buffers_pattern, qs[0][1]) + assert notices == ['WARNING: buffers statistics disabled\n'] + + qs = query_state(config, acon, query, num_steps, {'timing': True, 'buffers': True}) + assert len(qs) == 1 and not re.search(timing_pattern, qs[0][1]) \ + and not re.search(buffers_pattern, qs[0][1]) + assert len(notices) == 2 and 'WARNING: timing statistics disabled\n' in notices \ + and 'WARNING: buffers statistics disabled\n' in notices + + n_close((acon,)) diff --git a/contrib/pg_variables/README.md b/contrib/pg_variables/README.md index 279f0ec485..259a7389e1 100644 --- a/contrib/pg_variables/README.md +++ b/contrib/pg_variables/README.md @@ -5,6 +5,23 @@ The **pg_variables** module provides functions to work with variables of various types. Created variables live only in the current user session. +Note that the module does **not support transactions and savepoints**. For +example: + +```sql +SELECT pgv_set_int('vars', 'int1', 101); +BEGIN; +SELECT pgv_set_int('vars', 'int2', 102); +ROLLBACK; + +SELECT * FROM pgv_list() order by package, name; + package | name +---------+------ + vars | int1 + vars | int2 +(2 rows) +``` + ## License This module available under the same license as @@ -22,6 +39,35 @@ Typical installation procedure may look like this: ## Module functions +The functions provided by the **pg_variables** module are shown in the tables +below. The module supports the following scalar and record types. + +To use **pgv_get_()** functions required package and variable must exists. It is +necessary to set variable with **pgv_set_()** functions to use **pgv_get_()** +functions. + +If a package does not exists you will get the following error: + +```sql +SELECT pgv_get_int('vars', 'int1'); +ERROR: unrecognized package "vars" +``` + +If a variable does not exists you will get the following error: + +```sql +SELECT pgv_get_int('vars', 'int1'); +ERROR: unrecognized variable "int1" +``` + +**pgv_get_()** functions check the variable type. If the variable type does not +match with the function type the error will be raised: + +```sql +SELECT pgv_get_text('vars', 'int1'); +ERROR: variable "int1" requires "integer" value +``` + ### Integer variables Function | Returns @@ -73,25 +119,37 @@ Function | Returns ### Records -Function | Returns --------- | ------- -`pgv_insert(package text, name text, r record)` | `void` -`pgv_update(package text, name text, r record)` | `boolean` -`pgv_delete(package text, name text, value anynonarray)` | `boolean` -`pgv_select(package text, name text)` | `set of record` -`pgv_select(package text, name text, value anynonarray)` | `record` -`pgv_select(package text, name text, value anyarray)` | `set of record` +The following functions are provided by the module to work with collections of +record types. + +To use **pgv_update()**, **pgv_delete()** and **pgv_select()** functions +required package and variable must exists. Otherwise the error will be raised. +It is necessary to set variable with **pgv_insert()** function to use these +functions. + +**pgv_update()**, **pgv_delete()** and **pgv_select()** functions check the +variable type. If the variable type does not **record** type the error will be +raised. + +Function | Returns | Description +-------- | ------- | ----------- +`pgv_insert(package text, name text, r record)` | `void` | Inserts a record to the variable collection. If package and variable do not exists they will be created. The first column of **r** will be a primary key. If exists a record with the same primary key the error will be raised. If this variable collection has other structure the error will be raised. +`pgv_update(package text, name text, r record)` | `boolean` | Updates a record with the corresponding primary key (the first column of **r** is a primary key). Returns **true** if a record was found. If this variable collection has other structure the error will be raised. +`pgv_delete(package text, name text, value anynonarray)` | `boolean` | Deletes a record with the corresponding primary key (the first column of **r** is a primary key). Returns **true** if a record was found. +`pgv_select(package text, name text)` | `set of record` | Returns the variable collection records. +`pgv_select(package text, name text, value anynonarray)` | `record` | Returns the record with the corresponding primary key (the first column of **r** is a primary key). +`pgv_select(package text, name text, value anyarray)` | `set of record` | Returns the variable collection records with the corresponding primary keys (the first column of **r** is a primary key). ### Miscellaneous functions -Function | Returns --------- | ------- -`pgv_exists(package text, name text)` | `bool` -`pgv_remove(package text, name text)` | `void` -`pgv_remove(package text)` | `void` -`pgv_free()` | `void` -`pgv_list()` | `table(package text, name text)` -`pgv_stats()` | `table(package text, used_memory bigint)` +Function | Returns | Description +-------- | ------- | ----------- +`pgv_exists(package text, name text)` | `bool` | Returns **true** if package and variable exists. +`pgv_remove(package text, name text)` | `void` | Removes the variable with the corresponding name. Required package and variable must exists, otherwise the error will be raised. +`pgv_remove(package text)` | `void` | Removes the package and all package variables with the corresponding name. Required package must exists, otherwise the error will be raised. +`pgv_free()` | `void` | Removes all packages and variables. +`pgv_list()` | `table(package text, name text)` | Returns set of records of assigned packages and variables. +`pgv_stats()` | `table(package text, used_memory bigint)` | Returns list of assigned packages and used memory in bytes. Note that **pgv_stats()** works only with the PostgreSQL 9.6 and newer. diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c index cb8ba2633d..02ff976c25 100644 --- a/contrib/pgcrypto/internal.c +++ b/contrib/pgcrypto/internal.c @@ -620,15 +620,6 @@ px_find_cipher(const char *name, PX_Cipher **res) * Randomness provider */ -/* - * Use always strong randomness. - */ -int -px_get_pseudo_random_bytes(uint8 *dst, unsigned count) -{ - return px_get_random_bytes(dst, count); -} - static time_t seed_time = 0; static time_t check_time = 0; diff --git a/contrib/pgcrypto/openssl.c b/contrib/pgcrypto/openssl.c index 976af70591..682683c210 100644 --- a/contrib/pgcrypto/openssl.c +++ b/contrib/pgcrypto/openssl.c @@ -40,6 +40,9 @@ #include #include +#include "utils/memutils.h" +#include "utils/resowner.h" + /* * Max lengths we might want to handle. */ @@ -199,18 +202,73 @@ compat_find_digest(const char *name, PX_MD **res) * Hashes */ +/* + * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest + * objects in a linked list, allocated in TopMemoryContext. We use the + * ResourceOwner mechanism to free them on abort. + */ typedef struct OSSLDigest { const EVP_MD *algo; - EVP_MD_CTX ctx; + EVP_MD_CTX *ctx; + + ResourceOwner owner; + struct OSSLDigest *next; + struct OSSLDigest *prev; } OSSLDigest; +static OSSLDigest *open_digests = NULL; +static bool resowner_callback_registered = false; + +static void +free_openssldigest(OSSLDigest *digest) +{ + EVP_MD_CTX_destroy(digest->ctx); + if (digest->prev) + digest->prev->next = digest->next; + else + open_digests = digest->next; + if (digest->next) + digest->next->prev = digest->prev; + pfree(digest); +} + +/* + * Close any open OpenSSL handles on abort. + */ +static void +digest_free_callback(ResourceReleasePhase phase, + bool isCommit, + bool isTopLevel, + void *arg) +{ + OSSLDigest *curr; + OSSLDigest *next; + + if (phase != RESOURCE_RELEASE_AFTER_LOCKS) + return; + + next = open_digests; + while (next) + { + curr = next; + next = curr->next; + + if (curr->owner == CurrentResourceOwner) + { + if (isCommit) + elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr); + free_openssldigest(curr); + } + } +} + static unsigned digest_result_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - return EVP_MD_CTX_size(&digest->ctx); + return EVP_MD_CTX_size(digest->ctx); } static unsigned @@ -218,7 +276,7 @@ digest_block_size(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - return EVP_MD_CTX_block_size(&digest->ctx); + return EVP_MD_CTX_block_size(digest->ctx); } static void @@ -226,7 +284,7 @@ digest_reset(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL); + EVP_DigestInit_ex(digest->ctx, digest->algo, NULL); } static void @@ -234,7 +292,7 @@ digest_update(PX_MD *h, const uint8 *data, unsigned dlen) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestUpdate(&digest->ctx, data, dlen); + EVP_DigestUpdate(digest->ctx, data, dlen); } static void @@ -242,7 +300,7 @@ digest_finish(PX_MD *h, uint8 *dst) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_DigestFinal_ex(&digest->ctx, dst, NULL); + EVP_DigestFinal_ex(digest->ctx, dst, NULL); } static void @@ -250,9 +308,7 @@ digest_free(PX_MD *h) { OSSLDigest *digest = (OSSLDigest *) h->p.ptr; - EVP_MD_CTX_cleanup(&digest->ctx); - - px_free(digest); + free_openssldigest(digest); px_free(h); } @@ -264,6 +320,7 @@ int px_find_digest(const char *name, PX_MD **res) { const EVP_MD *md; + EVP_MD_CTX *ctx; PX_MD *h; OSSLDigest *digest; @@ -273,17 +330,43 @@ px_find_digest(const char *name, PX_MD **res) OpenSSL_add_all_algorithms(); } + if (!resowner_callback_registered) + { + RegisterResourceReleaseCallback(digest_free_callback, NULL); + resowner_callback_registered = true; + } + md = EVP_get_digestbyname(name); if (md == NULL) return compat_find_digest(name, res); - digest = px_alloc(sizeof(*digest)); - digest->algo = md; + /* + * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object. + * The order is crucial, to make sure we don't leak anything on + * out-of-memory or other error. + */ + digest = MemoryContextAlloc(TopMemoryContext, sizeof(*digest)); - EVP_MD_CTX_init(&digest->ctx); - if (EVP_DigestInit_ex(&digest->ctx, digest->algo, NULL) == 0) + ctx = EVP_MD_CTX_create(); + if (!ctx) + { + pfree(digest); + return -1; + } + if (EVP_DigestInit_ex(ctx, md, NULL) == 0) + { + pfree(digest); return -1; + } + + digest->algo = md; + digest->ctx = ctx; + digest->owner = CurrentResourceOwner; + digest->next = open_digests; + digest->prev = NULL; + open_digests = digest; + /* The PX_MD object is allocated in the current memory context. */ h = px_alloc(sizeof(*h)); h->result_size = digest_result_size; h->block_size = digest_block_size; @@ -987,7 +1070,13 @@ static void init_openssl_rand(void) { if (RAND_get_rand_method() == NULL) + { +#ifdef HAVE_RAND_OPENSSL + RAND_set_rand_method(RAND_OpenSSL()); +#else RAND_set_rand_method(RAND_SSLeay()); +#endif + } openssl_random_init = 1; } @@ -1006,21 +1095,6 @@ px_get_random_bytes(uint8 *dst, unsigned count) return PXE_OSSL_RAND_ERROR; } -int -px_get_pseudo_random_bytes(uint8 *dst, unsigned count) -{ - int res; - - if (!openssl_random_init) - init_openssl_rand(); - - res = RAND_pseudo_bytes(dst, count); - if (res == 0 || res == 1) - return count; - - return PXE_OSSL_RAND_ERROR; -} - int px_add_entropy(const uint8 *data, unsigned count) { diff --git a/contrib/pgcrypto/pgcrypto.c b/contrib/pgcrypto/pgcrypto.c index 2d446d8cc9..27b96c7cc4 100644 --- a/contrib/pgcrypto/pgcrypto.c +++ b/contrib/pgcrypto/pgcrypto.c @@ -454,7 +454,7 @@ pg_random_uuid(PG_FUNCTION_ARGS) int err; /* generate random bits */ - err = px_get_pseudo_random_bytes(buf, UUID_LEN); + err = px_get_random_bytes(buf, UUID_LEN); if (err < 0) ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), diff --git a/contrib/pgcrypto/pgp-s2k.c b/contrib/pgcrypto/pgp-s2k.c index 193dd95173..0bcb95ae8c 100644 --- a/contrib/pgcrypto/pgp-s2k.c +++ b/contrib/pgcrypto/pgp-s2k.c @@ -222,13 +222,13 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo) case 0: break; case 1: - res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); + res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT); break; case 3: - res = px_get_pseudo_random_bytes(s2k->salt, PGP_S2K_SALT); + res = px_get_random_bytes(s2k->salt, PGP_S2K_SALT); if (res < 0) break; - res = px_get_pseudo_random_bytes(&tmp, 1); + res = px_get_random_bytes(&tmp, 1); if (res < 0) break; s2k->iter = decide_count(tmp); diff --git a/contrib/pgcrypto/px-crypt.c b/contrib/pgcrypto/px-crypt.c index e3246fc5b9..3d42393850 100644 --- a/contrib/pgcrypto/px-crypt.c +++ b/contrib/pgcrypto/px-crypt.c @@ -153,7 +153,7 @@ px_gen_salt(const char *salt_type, char *buf, int rounds) return PXE_BAD_SALT_ROUNDS; } - res = px_get_pseudo_random_bytes((uint8 *) rbuf, g->input_len); + res = px_get_random_bytes((uint8 *) rbuf, g->input_len); if (res < 0) return res; diff --git a/contrib/pgcrypto/px.c b/contrib/pgcrypto/px.c index cfb3b50985..7e69da696f 100644 --- a/contrib/pgcrypto/px.c +++ b/contrib/pgcrypto/px.c @@ -48,7 +48,7 @@ static const struct error_desc px_err_list[] = { {PXE_BAD_OPTION, "Unknown option"}, {PXE_BAD_FORMAT, "Badly formatted type"}, {PXE_KEY_TOO_BIG, "Key was too big"}, - {PXE_CIPHER_INIT, "Cipher cannot be initalized ?"}, + {PXE_CIPHER_INIT, "Cipher cannot be initialized ?"}, {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"}, {PXE_DEV_READ_ERROR, "Error reading from random device"}, {PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"}, diff --git a/contrib/pgcrypto/px.h b/contrib/pgcrypto/px.h index 0f6bbd7a8d..9174e137db 100644 --- a/contrib/pgcrypto/px.h +++ b/contrib/pgcrypto/px.h @@ -190,7 +190,6 @@ int px_find_cipher(const char *name, PX_Cipher **res); int px_find_combo(const char *name, PX_Combo **res); int px_get_random_bytes(uint8 *dst, unsigned count); -int px_get_pseudo_random_bytes(uint8 *dst, unsigned count); int px_add_entropy(const uint8 *data, unsigned count); unsigned px_acquire_system_randomness(uint8 *dst); diff --git a/contrib/postgres_fdw/deparse.c b/contrib/postgres_fdw/deparse.c index 8f09cd51ca..dd25699d83 100644 --- a/contrib/postgres_fdw/deparse.c +++ b/contrib/postgres_fdw/deparse.c @@ -1806,10 +1806,27 @@ deparseNullTest(NullTest *node, deparse_expr_cxt *context) appendStringInfoChar(buf, '('); deparseExpr(node->arg, context); - if (node->nulltesttype == IS_NULL) - appendStringInfoString(buf, " IS NULL)"); + + /* + * For scalar inputs, we prefer to print as IS [NOT] NULL, which is + * shorter and traditional. If it's a rowtype input but we're applying a + * scalar test, must print IS [NOT] DISTINCT FROM NULL to be semantically + * correct. + */ + if (node->argisrow || !type_is_rowtype(exprType((Node *) node->arg))) + { + if (node->nulltesttype == IS_NULL) + appendStringInfoString(buf, " IS NULL)"); + else + appendStringInfoString(buf, " IS NOT NULL)"); + } else - appendStringInfoString(buf, " IS NOT NULL)"); + { + if (node->nulltesttype == IS_NULL) + appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL)"); + else + appendStringInfoString(buf, " IS DISTINCT FROM NULL)"); + } } /* diff --git a/contrib/tcn/tcn.c b/contrib/tcn/tcn.c index b4b6ea9b4e..ef88f45f5b 100644 --- a/contrib/tcn/tcn.c +++ b/contrib/tcn/tcn.c @@ -138,7 +138,7 @@ triggered_change_notification(PG_FUNCTION_ARGS) /* we're only interested if it is the primary key and valid */ if (index->indisprimary && IndexIsValid(index)) { - int indnkeyatts = index->indnkeyatts; + int indnkeyatts = index->indnkeyatts; if (indnkeyatts > 0) { diff --git a/contrib/test_decoding/expected/xact.out b/contrib/test_decoding/expected/xact.out index 507b701c3a..ec4745005d 100644 --- a/contrib/test_decoding/expected/xact.out +++ b/contrib/test_decoding/expected/xact.out @@ -6,9 +6,9 @@ SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_d init (1 row) --- bug #13844, xids in non-decoded records need to be inspected CREATE TABLE xact_test(data text); INSERT INTO xact_test VALUES ('before-test'); +-- bug #13844, xids in non-decoded records need to be inspected BEGIN; -- perform operation in xact that creates and logs xid, but isn't decoded SELECT * FROM xact_test FOR UPDATE; @@ -33,6 +33,28 @@ SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'inc COMMIT (6 rows) +-- bug #14279, do not propagate null snapshot from subtransaction +BEGIN; +-- first insert +INSERT INTO xact_test VALUES ('main-txn'); +SAVEPOINT foo; +-- now perform operation in subxact that creates and logs xid, but isn't decoded +SELECT 1 FROM xact_test FOR UPDATE LIMIT 1; + ?column? +---------- + 1 +(1 row) + +COMMIT; +-- and now show those changes +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + data +------------------------------------------------------- + BEGIN + table public.xact_test: INSERT: data[text]:'main-txn' + COMMIT +(3 rows) + DROP TABLE xact_test; SELECT pg_drop_replication_slot('regression_slot'); pg_drop_replication_slot diff --git a/contrib/test_decoding/sql/xact.sql b/contrib/test_decoding/sql/xact.sql index 9ce238f62d..aa555911e8 100644 --- a/contrib/test_decoding/sql/xact.sql +++ b/contrib/test_decoding/sql/xact.sql @@ -3,10 +3,10 @@ SET synchronous_commit = on; SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding'); --- bug #13844, xids in non-decoded records need to be inspected CREATE TABLE xact_test(data text); INSERT INTO xact_test VALUES ('before-test'); +-- bug #13844, xids in non-decoded records need to be inspected BEGIN; -- perform operation in xact that creates and logs xid, but isn't decoded SELECT * FROM xact_test FOR UPDATE; @@ -17,6 +17,17 @@ COMMIT; -- and now show those changes SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); +-- bug #14279, do not propagate null snapshot from subtransaction +BEGIN; +-- first insert +INSERT INTO xact_test VALUES ('main-txn'); +SAVEPOINT foo; +-- now perform operation in subxact that creates and logs xid, but isn't decoded +SELECT 1 FROM xact_test FOR UPDATE LIMIT 1; +COMMIT; +-- and now show those changes +SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + DROP TABLE xact_test; SELECT pg_drop_replication_slot('regression_slot'); diff --git a/contrib/tsearch2/expected/tsearch2.out b/contrib/tsearch2/expected/tsearch2.out index e07c0bc783..e84e4d27f2 100644 --- a/contrib/tsearch2/expected/tsearch2.out +++ b/contrib/tsearch2/expected/tsearch2.out @@ -1067,7 +1067,7 @@ select rank(' a:1 s:2 d g'::tsvector, 'a & s'); insert into test_tsvector (t) values ('foo bar foo the over foo qq bar'); drop trigger tsvectorupdate on test_tsvector; -select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word collate "C"; word | ndoc | nentry -----------+------+-------- qq | 109 | 109 @@ -2220,28 +2220,28 @@ select * from stat('select a from test_tsvector') order by ndoc desc, nentry des insert into test_tsvector values ('1', 'a:1a,2,3b b:5a,6a,7c,8'); insert into test_tsvector values ('1', 'a:1a,2,3c b:5a,6b,7c,8b'); -select * from stat('select a from test_tsvector','a') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector','a') order by ndoc desc, nentry desc, word collate "C"; word | ndoc | nentry ------+------+-------- b | 2 | 3 a | 2 | 2 (2 rows) -select * from stat('select a from test_tsvector','b') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector','b') order by ndoc desc, nentry desc, word collate "C"; word | ndoc | nentry ------+------+-------- b | 1 | 2 a | 1 | 1 (2 rows) -select * from stat('select a from test_tsvector','c') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector','c') order by ndoc desc, nentry desc, word collate "C"; word | ndoc | nentry ------+------+-------- b | 2 | 2 a | 1 | 1 (2 rows) -select * from stat('select a from test_tsvector','d') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector','d') order by ndoc desc, nentry desc, word collate "C"; word | ndoc | nentry -----------+------+-------- a | 2 | 2 @@ -2254,7 +2254,7 @@ select * from stat('select a from test_tsvector','d') order by ndoc desc, nentry qwerti | 1 | 1 (8 rows) -select * from stat('select a from test_tsvector','ad') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector','ad') order by ndoc desc, nentry desc, word collate "C"; word | ndoc | nentry -----------+------+-------- a | 2 | 4 diff --git a/contrib/tsearch2/expected/tsearch2_1.out b/contrib/tsearch2/expected/tsearch2_1.out deleted file mode 100644 index 349733b6fd..0000000000 --- a/contrib/tsearch2/expected/tsearch2_1.out +++ /dev/null @@ -1,2969 +0,0 @@ -CREATE EXTENSION tsearch2; ---tsvector -SELECT '1'::tsvector; - tsvector ----------- - '1' -(1 row) - -SELECT '1 '::tsvector; - tsvector ----------- - '1' -(1 row) - -SELECT ' 1'::tsvector; - tsvector ----------- - '1' -(1 row) - -SELECT ' 1 '::tsvector; - tsvector ----------- - '1' -(1 row) - -SELECT '1 2'::tsvector; - tsvector ----------- - '1' '2' -(1 row) - -SELECT '''1 2'''::tsvector; - tsvector ----------- - '1 2' -(1 row) - -SELECT E'''1 \\''2'''::tsvector; - tsvector ----------- - '1 ''2' -(1 row) - -SELECT E'''1 \\''2''3'::tsvector; - tsvector -------------- - '1 ''2' '3' -(1 row) - -SELECT E'''1 \\''2'' 3'::tsvector; - tsvector -------------- - '1 ''2' '3' -(1 row) - -SELECT E'''1 \\''2'' '' 3'' 4 '::tsvector; - tsvector ------------------- - ' 3' '1 ''2' '4' -(1 row) - -select '''w'':4A,3B,2C,1D,5 a:8'; - ?column? ------------------------ - 'w':4A,3B,2C,1D,5 a:8 -(1 row) - -select 'a:3A b:2a'::tsvector || 'ba:1234 a:1B'; - ?column? ----------------------------- - 'a':3A,4B 'b':2A 'ba':1237 -(1 row) - -select setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c'); - setweight ----------------------------------------------------------- - 'a':1C,3C 'asd':1C 'w':5C,6C,12C,13C 'zxc':81C,222C,567C -(1 row) - -select strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector); - strip ---------------- - 'a' 'asd' 'w' -(1 row) - ---tsquery -SELECT '1'::tsquery; - tsquery ---------- - '1' -(1 row) - -SELECT '1 '::tsquery; - tsquery ---------- - '1' -(1 row) - -SELECT ' 1'::tsquery; - tsquery ---------- - '1' -(1 row) - -SELECT ' 1 '::tsquery; - tsquery ---------- - '1' -(1 row) - -SELECT '''1 2'''::tsquery; - tsquery ---------- - '1 2' -(1 row) - -SELECT E'''1 \\''2'''::tsquery; - tsquery ---------- - '1 ''2' -(1 row) - -SELECT '!1'::tsquery; - tsquery ---------- - !'1' -(1 row) - -SELECT '1|2'::tsquery; - tsquery ------------ - '1' | '2' -(1 row) - -SELECT '1|!2'::tsquery; - tsquery ------------- - '1' | !'2' -(1 row) - -SELECT '!1|2'::tsquery; - tsquery ------------- - !'1' | '2' -(1 row) - -SELECT '!1|!2'::tsquery; - tsquery -------------- - !'1' | !'2' -(1 row) - -SELECT '!(!1|!2)'::tsquery; - tsquery ------------------- - !( !'1' | !'2' ) -(1 row) - -SELECT '!(!1|2)'::tsquery; - tsquery ------------------ - !( !'1' | '2' ) -(1 row) - -SELECT '!(1|!2)'::tsquery; - tsquery ------------------ - !( '1' | !'2' ) -(1 row) - -SELECT '!(1|2)'::tsquery; - tsquery ----------------- - !( '1' | '2' ) -(1 row) - -SELECT '1&2'::tsquery; - tsquery ------------ - '1' & '2' -(1 row) - -SELECT '!1&2'::tsquery; - tsquery ------------- - !'1' & '2' -(1 row) - -SELECT '1&!2'::tsquery; - tsquery ------------- - '1' & !'2' -(1 row) - -SELECT '!1&!2'::tsquery; - tsquery -------------- - !'1' & !'2' -(1 row) - -SELECT '(1&2)'::tsquery; - tsquery ------------ - '1' & '2' -(1 row) - -SELECT '1&(2)'::tsquery; - tsquery ------------ - '1' & '2' -(1 row) - -SELECT '!(1)&2'::tsquery; - tsquery ------------- - !'1' & '2' -(1 row) - -SELECT '!(1&2)'::tsquery; - tsquery ----------------- - !( '1' & '2' ) -(1 row) - -SELECT '1|2&3'::tsquery; - tsquery ------------------ - '1' | '2' & '3' -(1 row) - -SELECT '1|(2&3)'::tsquery; - tsquery ------------------ - '1' | '2' & '3' -(1 row) - -SELECT '(1|2)&3'::tsquery; - tsquery ---------------------- - ( '1' | '2' ) & '3' -(1 row) - -SELECT '1|2&!3'::tsquery; - tsquery ------------------- - '1' | '2' & !'3' -(1 row) - -SELECT '1|!2&3'::tsquery; - tsquery ------------------- - '1' | !'2' & '3' -(1 row) - -SELECT '!1|2&3'::tsquery; - tsquery ------------------- - !'1' | '2' & '3' -(1 row) - -SELECT '!1|(2&3)'::tsquery; - tsquery ------------------- - !'1' | '2' & '3' -(1 row) - -SELECT '!(1|2)&3'::tsquery; - tsquery ----------------------- - !( '1' | '2' ) & '3' -(1 row) - -SELECT '(!1|2)&3'::tsquery; - tsquery ----------------------- - ( !'1' | '2' ) & '3' -(1 row) - -SELECT '1|(2|(4|(5|6)))'::tsquery; - tsquery ------------------------------------------ - '1' | ( '2' | ( '4' | ( '5' | '6' ) ) ) -(1 row) - -SELECT '1|2|4|5|6'::tsquery; - tsquery ------------------------------------------ - ( ( ( '1' | '2' ) | '4' ) | '5' ) | '6' -(1 row) - -SELECT '1&(2&(4&(5&6)))'::tsquery; - tsquery ------------------------------ - '1' & '2' & '4' & '5' & '6' -(1 row) - -SELECT '1&2&4&5&6'::tsquery; - tsquery ------------------------------ - '1' & '2' & '4' & '5' & '6' -(1 row) - -SELECT '1&(2&(4&(5|6)))'::tsquery; - tsquery ---------------------------------- - '1' & '2' & '4' & ( '5' | '6' ) -(1 row) - -SELECT '1&(2&(4&(5|!6)))'::tsquery; - tsquery ----------------------------------- - '1' & '2' & '4' & ( '5' | !'6' ) -(1 row) - -SELECT E'1&(''2''&('' 4''&(\\|5 | ''6 \\'' !|&'')))'::tsquery; - tsquery ------------------------------------------- - '1' & '2' & ' 4' & ( '|5' | '6 '' !|&' ) -(1 row) - -SELECT '''the wether'':dc & '' sKies '':BC & a:d b:a'; - ?column? ------------------------------------------- - 'the wether':dc & ' sKies ':BC & a:d b:a -(1 row) - -select 'a' < 'b & c'::tsquery; - ?column? ----------- - t -(1 row) - -select 'a' > 'b & c'::tsquery; - ?column? ----------- - f -(1 row) - -select 'a | f' < 'b & c'::tsquery; - ?column? ----------- - t -(1 row) - -select 'a | ff' < 'b & c'::tsquery; - ?column? ----------- - f -(1 row) - -select 'a | f | g' < 'b & c'::tsquery; - ?column? ----------- - f -(1 row) - -select numnode( 'new'::tsquery ); - numnode ---------- - 1 -(1 row) - -select numnode( 'new & york'::tsquery ); - numnode ---------- - 3 -(1 row) - -select numnode( 'new & york | qwery'::tsquery ); - numnode ---------- - 5 -(1 row) - -create table test_tsquery (txtkeyword text, txtsample text); -\set ECHO none -alter table test_tsquery add column keyword tsquery; -update test_tsquery set keyword = to_tsquery('english', txtkeyword); -alter table test_tsquery add column sample tsquery; -update test_tsquery set sample = to_tsquery('english', txtsample::text); -create unique index bt_tsq on test_tsquery (keyword); -select count(*) from test_tsquery where keyword < 'new & york'; - count -------- - 1 -(1 row) - -select count(*) from test_tsquery where keyword <= 'new & york'; - count -------- - 2 -(1 row) - -select count(*) from test_tsquery where keyword = 'new & york'; - count -------- - 1 -(1 row) - -select count(*) from test_tsquery where keyword >= 'new & york'; - count -------- - 3 -(1 row) - -select count(*) from test_tsquery where keyword > 'new & york'; - count -------- - 2 -(1 row) - -set enable_seqscan=off; -select count(*) from test_tsquery where keyword < 'new & york'; - count -------- - 1 -(1 row) - -select count(*) from test_tsquery where keyword <= 'new & york'; - count -------- - 2 -(1 row) - -select count(*) from test_tsquery where keyword = 'new & york'; - count -------- - 1 -(1 row) - -select count(*) from test_tsquery where keyword >= 'new & york'; - count -------- - 3 -(1 row) - -select count(*) from test_tsquery where keyword > 'new & york'; - count -------- - 2 -(1 row) - -set enable_seqscan=on; -select rewrite('foo & bar & qq & new & york', 'new & york'::tsquery, 'big & apple | nyc | new & york & city'); - rewrite ----------------------------------------------------------------------------------- - 'foo' & 'bar' & 'qq' & ( 'city' & 'new' & 'york' | ( 'nyc' | 'big' & 'apple' ) ) -(1 row) - -select rewrite('moscow', 'select keyword, sample from test_tsquery'::text ); - rewrite ---------------------- - 'moskva' | 'moscow' -(1 row) - -select rewrite('moscow & hotel', 'select keyword, sample from test_tsquery'::text ); - rewrite ------------------------------------ - 'hotel' & ( 'moskva' | 'moscow' ) -(1 row) - -select rewrite('bar & new & qq & foo & york', 'select keyword, sample from test_tsquery'::text ); - rewrite -------------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) ) -(1 row) - -select rewrite( ARRAY['moscow', keyword, sample] ) from test_tsquery; - rewrite ---------------------- - 'moskva' | 'moscow' -(1 row) - -select rewrite( ARRAY['moscow & hotel', keyword, sample] ) from test_tsquery; - rewrite ------------------------------------ - ( 'moskva' | 'moscow' ) & 'hotel' -(1 row) - -select rewrite( ARRAY['bar & new & qq & foo & york', keyword, sample] ) from test_tsquery; - rewrite -------------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) ) -(1 row) - -select keyword from test_tsquery where keyword @> 'new'; - keyword ----------------- - 'new' & 'york' -(1 row) - -select keyword from test_tsquery where keyword @> 'moscow'; - keyword ----------- - 'moscow' -(1 row) - -select keyword from test_tsquery where keyword <@ 'new'; - keyword ---------- -(0 rows) - -select keyword from test_tsquery where keyword <@ 'moscow'; - keyword ----------- - 'moscow' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow') as query where keyword <@ query; - rewrite ---------------------- - 'moskva' | 'moscow' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow & hotel') as query where keyword <@ query; - rewrite ------------------------------------ - ( 'moskva' | 'moscow' ) & 'hotel' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'bar & new & qq & foo & york') as query where keyword <@ query; - rewrite -------------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) ) -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow') as query where query @> keyword; - rewrite ---------------------- - 'moskva' | 'moscow' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow & hotel') as query where query @> keyword; - rewrite ------------------------------------ - ( 'moskva' | 'moscow' ) & 'hotel' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'bar & new & qq & foo & york') as query where query @> keyword; - rewrite -------------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) ) -(1 row) - -create index qq on test_tsquery using gist (keyword gist_tp_tsquery_ops); -set enable_seqscan='off'; -select keyword from test_tsquery where keyword @> 'new'; - keyword ----------------- - 'new' & 'york' -(1 row) - -select keyword from test_tsquery where keyword @> 'moscow'; - keyword ----------- - 'moscow' -(1 row) - -select keyword from test_tsquery where keyword <@ 'new'; - keyword ---------- -(0 rows) - -select keyword from test_tsquery where keyword <@ 'moscow'; - keyword ----------- - 'moscow' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow') as query where keyword <@ query; - rewrite ---------------------- - 'moskva' | 'moscow' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow & hotel') as query where keyword <@ query; - rewrite ------------------------------------ - ( 'moskva' | 'moscow' ) & 'hotel' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'bar & new & qq & foo & york') as query where keyword <@ query; - rewrite -------------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) ) -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow') as query where query @> keyword; - rewrite ---------------------- - 'moskva' | 'moscow' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'moscow & hotel') as query where query @> keyword; - rewrite ------------------------------------ - ( 'moskva' | 'moscow' ) & 'hotel' -(1 row) - -select rewrite( ARRAY[query, keyword, sample] ) from test_tsquery, to_tsquery('english', 'bar & new & qq & foo & york') as query where query @> keyword; - rewrite -------------------------------------------------------------------------------------- - 'citi' & 'foo' & ( 'bar' | 'qq' ) & ( 'nyc' | ( 'big' & 'appl' | 'new' & 'york' ) ) -(1 row) - -set enable_seqscan='on'; -select lexize('simple', 'ASD56 hsdkf'); - lexize ------------------ - {"asd56 hsdkf"} -(1 row) - -select lexize('english_stem', 'SKIES Problems identity'); - lexize --------------------------- - {"skies problems ident"} -(1 row) - -select * from token_type('default'); - tokid | alias | descr --------+-----------------+------------------------------------------ - 1 | asciiword | Word, all ASCII - 2 | word | Word, all letters - 3 | numword | Word, letters and digits - 4 | email | Email address - 5 | url | URL - 6 | host | Host - 7 | sfloat | Scientific notation - 8 | version | Version number - 9 | hword_numpart | Hyphenated word part, letters and digits - 10 | hword_part | Hyphenated word part, all letters - 11 | hword_asciipart | Hyphenated word part, all ASCII - 12 | blank | Space symbols - 13 | tag | XML tag - 14 | protocol | Protocol head - 15 | numhword | Hyphenated word, letters and digits - 16 | asciihword | Hyphenated word, all ASCII - 17 | hword | Hyphenated word, all letters - 18 | url_path | URL path - 19 | file | File or path name - 20 | float | Decimal notation - 21 | int | Signed integer - 22 | uint | Unsigned integer - 23 | entity | XML entity -(23 rows) - -select * from parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005 teodor@stack.net qwe-wer asdf qwer jf sdjk ewr1> ewri2 -/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234 - wow < jqw <> qwerty'); - tokid | token --------+-------------------------------------- - 22 | 345 - 12 | - 1 | qwe - 12 | @ - 19 | efd.r - 12 | ' - 14 | http:// - 6 | www.com - 12 | / - 14 | http:// - 5 | aew.werc.ewr/?ad=qwe&dw - 6 | aew.werc.ewr - 18 | /?ad=qwe&dw - 12 | - 5 | 1aew.werc.ewr/?ad=qwe&dw - 6 | 1aew.werc.ewr - 18 | /?ad=qwe&dw - 12 | - 6 | 2aew.werc.ewr - 12 | - 14 | http:// - 5 | 3aew.werc.ewr/?ad=qwe&dw - 6 | 3aew.werc.ewr - 18 | /?ad=qwe&dw - 12 | - 14 | http:// - 6 | 4aew.werc.ewr - 12 | - 14 | http:// - 5 | 5aew.werc.ewr:8100/? - 6 | 5aew.werc.ewr:8100 - 18 | /? - 12 | - 1 | ad - 12 | = - 1 | qwe - 12 | & - 1 | dw - 12 | - 5 | 6aew.werc.ewr:8100/?ad=qwe&dw - 6 | 6aew.werc.ewr:8100 - 18 | /?ad=qwe&dw - 12 | - 5 | 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 - 6 | 7aew.werc.ewr:8100 - 18 | /?ad=qwe&dw=%20%32 - 12 | - 7 | +4.0e-10 - 12 | - 1 | qwe - 12 | - 1 | qwe - 12 | - 1 | qwqwe - 12 | - 20 | 234.435 - 12 | - 22 | 455 - 12 | - 20 | 5.005 - 12 | - 4 | teodor@stack.net - 12 | - 16 | qwe-wer - 11 | qwe - 12 | - - 11 | wer - 12 | - 1 | asdf - 12 | - 13 | - 1 | qwer - 12 | - 1 | jf - 12 | - 1 | sdjk - 12 | < - 1 | we - 12 | - 1 | hjwer - 12 | - 13 | - 12 | - 3 | ewr1 - 12 | > - 3 | ewri2 - 12 | - 13 | - 12 | + - | - 19 | /usr/local/fff - 12 | - 19 | /awdf/dwqe/4325 - 12 | - 19 | rewt/ewr - 12 | - 1 | wefjn - 12 | - 19 | /wqe-324/ewr - 12 | - 19 | gist.h - 12 | - 19 | gist.h.c - 12 | - 19 | gist.c - 12 | . - 1 | readline - 12 | - 20 | 4.2 - 12 | - 20 | 4.2 - 12 | . - 20 | 4.2 - 12 | , - 1 | readline - 20 | -4.2 - 12 | - 1 | readline - 20 | -4.2 - 12 | . - 22 | 234 - 12 | + - | - 12 | < - 1 | i - 12 | - 13 | - 12 | - 1 | wow - 12 | - 12 | < - 1 | jqw - 12 | - 12 | <> - 1 | qwerty -(133 rows) - -SELECT to_tsvector('english', '345 qwe@efd.r '' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005 teodor@stack.net qwe-wer asdf qwer jf sdjk ewr1> ewri2 -/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234 - wow < jqw <> qwerty'); - to_tsvector ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - '+4.0e-10':28 '-4.2':60,62 '/?':18 '/?ad=qwe&dw':7,10,14,24 '/?ad=qwe&dw=%20%32':27 '/awdf/dwqe/4325':48 '/usr/local/fff':47 '/wqe-324/ewr':51 '1aew.werc.ewr':9 '1aew.werc.ewr/?ad=qwe&dw':8 '234':63 '234.435':32 '2aew.werc.ewr':11 '345':1 '3aew.werc.ewr':13 '3aew.werc.ewr/?ad=qwe&dw':12 '4.2':56,57,58 '455':33 '4aew.werc.ewr':15 '5.005':34 '5aew.werc.ewr:8100':17 '5aew.werc.ewr:8100/?':16 '6aew.werc.ewr:8100':23 '6aew.werc.ewr:8100/?ad=qwe&dw':22 '7aew.werc.ewr:8100':26 '7aew.werc.ewr:8100/?ad=qwe&dw=%20%32':25 'ad':19 'aew.werc.ewr':6 'aew.werc.ewr/?ad=qwe&dw':5 'asdf':39 'dw':21 'efd.r':3 'ewr1':45 'ewri2':46 'gist.c':54 'gist.h':52 'gist.h.c':53 'hjwer':44 'jf':41 'jqw':66 'qwe':2,20,29,30,37 'qwe-wer':36 'qwer':40 'qwerti':67 'qwqwe':31 'readlin':55,59,61 'rewt/ewr':49 'sdjk':42 'teodor@stack.net':35 'wefjn':50 'wer':38 'wow':65 'www.com':4 -(1 row) - -SELECT length(to_tsvector('english', '345 qw')); - length --------- - 2 -(1 row) - -SELECT length(to_tsvector('english', '345 qwe@efd.r '' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005 teodor@stack.net qwe-wer asdf qwer jf sdjk ewr1> ewri2 -/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234 - wow < jqw <> qwerty')); - length --------- - 53 -(1 row) - -select to_tsquery('english', 'qwe & sKies '); - to_tsquery ---------------- - 'qwe' & 'sky' -(1 row) - -select to_tsquery('simple', 'qwe & sKies '); - to_tsquery ------------------ - 'qwe' & 'skies' -(1 row) - -select to_tsquery('english', '''the wether'':dc & '' sKies '':BC '); - to_tsquery ------------------------- - 'wether':CD & 'sky':BC -(1 row) - -select to_tsquery('english', 'asd&(and|fghj)'); - to_tsquery ----------------- - 'asd' & 'fghj' -(1 row) - -select to_tsquery('english', '(asd&and)|fghj'); - to_tsquery ----------------- - 'asd' | 'fghj' -(1 row) - -select to_tsquery('english', '(asd&!and)|fghj'); - to_tsquery ----------------- - 'asd' | 'fghj' -(1 row) - -select to_tsquery('english', '(the|and&(i&1))&fghj'); - to_tsquery --------------- - '1' & 'fghj' -(1 row) - -select plainto_tsquery('english', 'the and z 1))& fghj'); - plainto_tsquery --------------------- - 'z' & '1' & 'fghj' -(1 row) - -select plainto_tsquery('english', 'foo bar') && plainto_tsquery('english', 'asd'); - ?column? ------------------------ - 'foo' & 'bar' & 'asd' -(1 row) - -select plainto_tsquery('english', 'foo bar') || plainto_tsquery('english', 'asd fg'); - ?column? ------------------------------- - 'foo' & 'bar' | 'asd' & 'fg' -(1 row) - -select plainto_tsquery('english', 'foo bar') || !!plainto_tsquery('english', 'asd fg'); - ?column? ------------------------------------ - 'foo' & 'bar' | !( 'asd' & 'fg' ) -(1 row) - -select plainto_tsquery('english', 'foo bar') && 'asd | fg'; - ?column? ----------------------------------- - 'foo' & 'bar' & ( 'asd' | 'fg' ) -(1 row) - -select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca'; - ?column? ----------- - t -(1 row) - -select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:B'; - ?column? ----------- - t -(1 row) - -select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:A'; - ?column? ----------- - t -(1 row) - -select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:C'; - ?column? ----------- - f -(1 row) - -select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:CB'; - ?column? ----------- - t -(1 row) - -CREATE TABLE test_tsvector( t text, a tsvector ); -\copy test_tsvector from 'data/test_tsearch.data' -SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; - count -------- - 158 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh'; - count -------- - 17 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt'; - count -------- - 6 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt'; - count -------- - 98 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)'; - count -------- - 23 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)'; - count -------- - 39 -(1 row) - -create index wowidx on test_tsvector using gist (a); -set enable_seqscan=off; -SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; - count -------- - 158 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh'; - count -------- - 17 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt'; - count -------- - 6 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt'; - count -------- - 98 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)'; - count -------- - 23 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)'; - count -------- - 39 -(1 row) - -select set_curcfg('english'); - set_curcfg ------------- - -(1 row) - -CREATE TRIGGER tsvectorupdate -BEFORE UPDATE OR INSERT ON test_tsvector -FOR EACH ROW EXECUTE PROCEDURE tsearch2(a, t); -SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); - count -------- - 0 -(1 row) - -INSERT INTO test_tsvector (t) VALUES ('345 qwerty'); -SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); - count -------- - 1 -(1 row) - -UPDATE test_tsvector SET t = null WHERE t = '345 qwerty'; -SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); - count -------- - 0 -(1 row) - -insert into test_tsvector (t) values ('345 qwerty copyright'); -select count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); - count -------- - 1 -(1 row) - -select count(*) FROM test_tsvector WHERE a @@ to_tsquery('copyright'); - count -------- - 1 -(1 row) - -select rank(' a:1 s:2C d g'::tsvector, 'a | s'); - rank ------------ - 0.0911891 -(1 row) - -select rank(' a:1 s:2B d g'::tsvector, 'a | s'); - rank ----------- - 0.151982 -(1 row) - -select rank(' a:1 s:2 d g'::tsvector, 'a | s'); - rank ------------ - 0.0607927 -(1 row) - -select rank(' a:1 s:2C d g'::tsvector, 'a & s'); - rank ----------- - 0.140153 -(1 row) - -select rank(' a:1 s:2B d g'::tsvector, 'a & s'); - rank ----------- - 0.198206 -(1 row) - -select rank(' a:1 s:2 d g'::tsvector, 'a & s'); - rank ------------ - 0.0991032 -(1 row) - -insert into test_tsvector (t) values ('foo bar foo the over foo qq bar'); -drop trigger tsvectorupdate on test_tsvector; -select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word; - word | ndoc | nentry ------------+------+-------- - qq | 109 | 109 - qt | 102 | 102 - qe | 100 | 100 - qh | 98 | 98 - qw | 98 | 98 - qa | 97 | 97 - ql | 94 | 94 - qs | 94 | 94 - qi | 92 | 92 - qr | 92 | 92 - qj | 91 | 91 - qd | 87 | 87 - qz | 87 | 87 - qc | 86 | 86 - qn | 86 | 86 - qv | 85 | 85 - qo | 84 | 84 - qy | 84 | 84 - wp | 84 | 84 - qf | 81 | 81 - qk | 80 | 80 - wt | 80 | 80 - qu | 79 | 79 - qg | 78 | 78 - wb | 78 | 78 - qx | 77 | 77 - wr | 77 | 77 - ws | 73 | 73 - wy | 73 | 73 - wa | 72 | 72 - wf | 70 | 70 - wg | 70 | 70 - wi | 70 | 70 - wu | 70 | 70 - wc | 69 | 69 - wj | 69 | 69 - qp | 68 | 68 - wh | 68 | 68 - wv | 68 | 68 - qb | 66 | 66 - eu | 65 | 65 - we | 65 | 65 - wl | 65 | 65 - wq | 65 | 65 - wk | 64 | 64 - ee | 63 | 63 - eo | 63 | 63 - qm | 63 | 63 - wn | 63 | 63 - ef | 62 | 62 - eh | 62 | 62 - ex | 62 | 62 - re | 62 | 62 - rl | 62 | 62 - rr | 62 | 62 - eb | 61 | 61 - ek | 61 | 61 - ww | 61 | 61 - ea | 60 | 60 - ei | 60 | 60 - em | 60 | 60 - eq | 60 | 60 - ew | 60 | 60 - ro | 60 | 60 - rw | 60 | 60 - tl | 60 | 60 - eg | 59 | 59 - en | 59 | 59 - ez | 59 | 59 - rj | 59 | 59 - ry | 59 | 59 - tw | 59 | 59 - tx | 59 | 59 - ej | 58 | 58 - es | 58 | 58 - ra | 58 | 58 - rd | 58 | 58 - rg | 58 | 58 - rx | 58 | 58 - tb | 58 | 58 - wd | 58 | 58 - ed | 57 | 57 - tc | 57 | 57 - wx | 57 | 57 - er | 56 | 56 - wm | 56 | 56 - wo | 56 | 56 - yw | 56 | 56 - ep | 55 | 55 - rk | 55 | 55 - rp | 55 | 55 - rz | 55 | 55 - ta | 55 | 55 - rq | 54 | 54 - yn | 54 | 54 - ec | 53 | 53 - el | 53 | 53 - ru | 53 | 53 - rv | 53 | 53 - tz | 53 | 53 - un | 53 | 53 - wz | 53 | 53 - ys | 53 | 53 - oe | 52 | 52 - tn | 52 | 52 - tq | 52 | 52 - ty | 52 | 52 - uq | 52 | 52 - yg | 52 | 52 - ym | 52 | 52 - oi | 51 | 51 - to | 51 | 51 - yi | 51 | 51 - pn | 50 | 50 - rb | 50 | 50 - ri | 50 | 50 - rn | 50 | 50 - ti | 50 | 50 - tv | 50 | 50 - um | 50 | 50 - ut | 50 | 50 - ya | 50 | 50 - et | 49 | 49 - ix | 49 | 49 - ox | 49 | 49 - q3 | 49 | 49 - yf | 49 | 49 - yl | 49 | 49 - yo | 49 | 49 - yr | 49 | 49 - ev | 48 | 48 - ey | 48 | 48 - ot | 48 | 48 - rc | 48 | 48 - rm | 48 | 48 - th | 48 | 48 - uo | 48 | 48 - ia | 47 | 47 - q1 | 47 | 47 - rh | 47 | 47 - yq | 47 | 47 - yz | 47 | 47 - av | 46 | 46 - im | 46 | 46 - os | 46 | 46 - tk | 46 | 46 - yy | 46 | 46 - ir | 45 | 45 - iv | 45 | 45 - iw | 45 | 45 - oj | 45 | 45 - pl | 45 | 45 - pv | 45 | 45 - te | 45 | 45 - tu | 45 | 45 - uv | 45 | 45 - ux | 45 | 45 - yd | 45 | 45 - yx | 45 | 45 - ij | 44 | 44 - pa | 44 | 44 - se | 44 | 44 - tg | 44 | 44 - ue | 44 | 44 - yb | 44 | 44 - yt | 44 | 44 - if | 43 | 43 - ik | 43 | 43 - in | 43 | 43 - ph | 43 | 43 - pj | 43 | 43 - q5 | 43 | 43 - rt | 43 | 43 - ub | 43 | 43 - ud | 43 | 43 - uh | 43 | 43 - uj | 43 | 43 - w7 | 43 | 43 - ye | 43 | 43 - yv | 43 | 43 - db | 42 | 42 - do | 42 | 42 - id | 42 | 42 - ie | 42 | 42 - ii | 42 | 42 - of | 42 | 42 - pr | 42 | 42 - q4 | 42 | 42 - rf | 42 | 42 - td | 42 | 42 - uk | 42 | 42 - up | 42 | 42 - yh | 42 | 42 - yk | 42 | 42 - io | 41 | 41 - it | 41 | 41 - pb | 41 | 41 - q0 | 41 | 41 - q7 | 41 | 41 - rs | 41 | 41 - tj | 41 | 41 - ur | 41 | 41 - ig | 40 | 40 - iu | 40 | 40 - iy | 40 | 40 - od | 40 | 40 - q6 | 40 | 40 - tt | 40 | 40 - ug | 40 | 40 - ul | 40 | 40 - us | 40 | 40 - uu | 40 | 40 - uz | 40 | 40 - ah | 39 | 39 - ar | 39 | 39 - as | 39 | 39 - dl | 39 | 39 - dt | 39 | 39 - hk | 39 | 39 - iq | 39 | 39 - is | 39 | 39 - oc | 39 | 39 - ov | 39 | 39 - oy | 39 | 39 - uf | 39 | 39 - ui | 39 | 39 - aa | 38 | 38 - ad | 38 | 38 - fh | 38 | 38 - gm | 38 | 38 - ic | 38 | 38 - jd | 38 | 38 - om | 38 | 38 - or | 38 | 38 - oz | 38 | 38 - pm | 38 | 38 - q8 | 38 | 38 - sf | 38 | 38 - sm | 38 | 38 - sv | 38 | 38 - uc | 38 | 38 - ak | 37 | 37 - aq | 37 | 37 - di | 37 | 37 - e4 | 37 | 37 - fi | 37 | 37 - fx | 37 | 37 - ha | 37 | 37 - hp | 37 | 37 - ih | 37 | 37 - og | 37 | 37 - po | 37 | 37 - pw | 37 | 37 - sn | 37 | 37 - su | 37 | 37 - sw | 37 | 37 - w6 | 37 | 37 - yj | 37 | 37 - yu | 37 | 37 - ag | 36 | 36 - am | 36 | 36 - at | 36 | 36 - e1 | 36 | 36 - ff | 36 | 36 - gx | 36 | 36 - he | 36 | 36 - hj | 36 | 36 - ib | 36 | 36 - iz | 36 | 36 - lm | 36 | 36 - ok | 36 | 36 - pk | 36 | 36 - pp | 36 | 36 - pu | 36 | 36 - sp | 36 | 36 - tf | 36 | 36 - tm | 36 | 36 - ay | 35 | 35 - dy | 35 | 35 - fu | 35 | 35 - ku | 35 | 35 - lh | 35 | 35 - lq | 35 | 35 - ob | 35 | 35 - on | 35 | 35 - op | 35 | 35 - o6 | 35 | 35 - pd | 35 | 35 - ps | 35 | 35 - si | 35 | 35 - sl | 35 | 35 - sx | 35 | 35 - tp | 35 | 35 - tr | 35 | 35 - w3 | 35 | 35 - y1 | 35 | 35 - al | 34 | 34 - ap | 34 | 34 - az | 34 | 34 - dc | 34 | 34 - dd | 34 | 34 - dz | 34 | 34 - e0 | 34 | 34 - fj | 34 | 34 - fp | 34 | 34 - gd | 34 | 34 - gg | 34 | 34 - gk | 34 | 34 - go | 34 | 34 - ho | 34 | 34 - jc | 34 | 34 - oa | 34 | 34 - oh | 34 | 34 - oo | 34 | 34 - pe | 34 | 34 - px | 34 | 34 - sd | 34 | 34 - sq | 34 | 34 - sy | 34 | 34 - ab | 33 | 33 - ae | 33 | 33 - af | 33 | 33 - aw | 33 | 33 - e5 | 33 | 33 - fk | 33 | 33 - gu | 33 | 33 - gy | 33 | 33 - hb | 33 | 33 - hm | 33 | 33 - hy | 33 | 33 - jl | 33 | 33 - jr | 33 | 33 - ls | 33 | 33 - oq | 33 | 33 - pt | 33 | 33 - sa | 33 | 33 - sh | 33 | 33 - sj | 33 | 33 - so | 33 | 33 - sz | 33 | 33 - t7 | 33 | 33 - uw | 33 | 33 - w8 | 33 | 33 - yp | 33 | 33 - y0 | 33 | 33 - dh | 32 | 32 - dp | 32 | 32 - dq | 32 | 32 - e7 | 32 | 32 - fn | 32 | 32 - fo | 32 | 32 - fr | 32 | 32 - ga | 32 | 32 - gq | 32 | 32 - hh | 32 | 32 - il | 32 | 32 - ip | 32 | 32 - jv | 32 | 32 - lc | 32 | 32 - ol | 32 | 32 - pc | 32 | 32 - q9 | 32 | 32 - ds | 31 | 31 - e9 | 31 | 31 - fd | 31 | 31 - fe | 31 | 31 - ft | 31 | 31 - gs | 31 | 31 - hl | 31 | 31 - hs | 31 | 31 - jb | 31 | 31 - kc | 31 | 31 - kw | 31 | 31 - mj | 31 | 31 - q2 | 31 | 31 - r3 | 31 | 31 - sb | 31 | 31 - sk | 31 | 31 - ts | 31 | 31 - ua | 31 | 31 - yc | 31 | 31 - zw | 31 | 31 - ao | 30 | 30 - du | 30 | 30 - fw | 30 | 30 - gj | 30 | 30 - hu | 30 | 30 - kh | 30 | 30 - kl | 30 | 30 - kv | 30 | 30 - ld | 30 | 30 - lf | 30 | 30 - pq | 30 | 30 - py | 30 | 30 - sc | 30 | 30 - sr | 30 | 30 - uy | 30 | 30 - vg | 30 | 30 - w2 | 30 | 30 - xg | 30 | 30 - xo | 30 | 30 - au | 29 | 29 - cx | 29 | 29 - fv | 29 | 29 - gh | 29 | 29 - gl | 29 | 29 - gt | 29 | 29 - hw | 29 | 29 - ji | 29 | 29 - km | 29 | 29 - la | 29 | 29 - ou | 29 | 29 - r0 | 29 | 29 - w0 | 29 | 29 - y9 | 29 | 29 - zm | 29 | 29 - zs | 29 | 29 - zy | 29 | 29 - ax | 28 | 28 - cd | 28 | 28 - dj | 28 | 28 - dn | 28 | 28 - dr | 28 | 28 - ht | 28 | 28 - jf | 28 | 28 - lo | 28 | 28 - lr | 28 | 28 - na | 28 | 28 - ng | 28 | 28 - r8 | 28 | 28 - ss | 28 | 28 - xt | 28 | 28 - y6 | 28 | 28 - aj | 27 | 27 - ca | 27 | 27 - cg | 27 | 27 - df | 27 | 27 - dg | 27 | 27 - dv | 27 | 27 - gc | 27 | 27 - gn | 27 | 27 - gr | 27 | 27 - hd | 27 | 27 - i8 | 27 | 27 - jn | 27 | 27 - jt | 27 | 27 - lp | 27 | 27 - ow | 27 | 27 - o9 | 27 | 27 - r9 | 27 | 27 - t8 | 27 | 27 - u5 | 27 | 27 - w4 | 27 | 27 - xm | 27 | 27 - zz | 27 | 27 - ac | 26 | 26 - ai | 26 | 26 - a2 | 26 | 26 - cm | 26 | 26 - cu | 26 | 26 - cw | 26 | 26 - dk | 26 | 26 - e2 | 26 | 26 - fc | 26 | 26 - fg | 26 | 26 - fl | 26 | 26 - fs | 26 | 26 - ge | 26 | 26 - gv | 26 | 26 - hc | 26 | 26 - hi | 26 | 26 - hx | 26 | 26 - jj | 26 | 26 - jm | 26 | 26 - kg | 26 | 26 - kk | 26 | 26 - kn | 26 | 26 - ko | 26 | 26 - kt | 26 | 26 - ln | 26 | 26 - mx | 26 | 26 - pg | 26 | 26 - r4 | 26 | 26 - t6 | 26 | 26 - u1 | 26 | 26 - u4 | 26 | 26 - vi | 26 | 26 - vr | 26 | 26 - w1 | 26 | 26 - w9 | 26 | 26 - xk | 26 | 26 - xs | 26 | 26 - zf | 26 | 26 - bb | 25 | 25 - dm | 25 | 25 - dw | 25 | 25 - e8 | 25 | 25 - fb | 25 | 25 - gw | 25 | 25 - hf | 25 | 25 - hg | 25 | 25 - hn | 25 | 25 - hv | 25 | 25 - h8 | 25 | 25 - i0 | 25 | 25 - i3 | 25 | 25 - jg | 25 | 25 - jo | 25 | 25 - jx | 25 | 25 - kq | 25 | 25 - lw | 25 | 25 - lx | 25 | 25 - o3 | 25 | 25 - pf | 25 | 25 - pi | 25 | 25 - pz | 25 | 25 - p7 | 25 | 25 - r2 | 25 | 25 - r5 | 25 | 25 - t9 | 25 | 25 - u7 | 25 | 25 - ve | 25 | 25 - vu | 25 | 25 - y5 | 25 | 25 - y8 | 25 | 25 - zt | 25 | 25 - an | 24 | 24 - bj | 24 | 24 - dx | 24 | 24 - fm | 24 | 24 - fz | 24 | 24 - gb | 24 | 24 - gi | 24 | 24 - gp | 24 | 24 - hr | 24 | 24 - hz | 24 | 24 - i5 | 24 | 24 - jq | 24 | 24 - kb | 24 | 24 - ke | 24 | 24 - kf | 24 | 24 - kp | 24 | 24 - lv | 24 | 24 - lz | 24 | 24 - o8 | 24 | 24 - r1 | 24 | 24 - sg | 24 | 24 - s7 | 24 | 24 - u3 | 24 | 24 - vj | 24 | 24 - vt | 24 | 24 - w5 | 24 | 24 - zj | 24 | 24 - be | 23 | 23 - bi | 23 | 23 - bn | 23 | 23 - cn | 23 | 23 - cy | 23 | 23 - da | 23 | 23 - e6 | 23 | 23 - fa | 23 | 23 - js | 23 | 23 - ki | 23 | 23 - kz | 23 | 23 - li | 23 | 23 - mt | 23 | 23 - mz | 23 | 23 - nu | 23 | 23 - o2 | 23 | 23 - p5 | 23 | 23 - p8 | 23 | 23 - r7 | 23 | 23 - t0 | 23 | 23 - t1 | 23 | 23 - t3 | 23 | 23 - vm | 23 | 23 - xh | 23 | 23 - xx | 23 | 23 - zp | 23 | 23 - zr | 23 | 23 - a3 | 22 | 22 - bg | 22 | 22 - de | 22 | 22 - e3 | 22 | 22 - fq | 22 | 22 - i2 | 22 | 22 - i7 | 22 | 22 - ja | 22 | 22 - jk | 22 | 22 - jy | 22 | 22 - kr | 22 | 22 - kx | 22 | 22 - ly | 22 | 22 - nb | 22 | 22 - nh | 22 | 22 - ns | 22 | 22 - s3 | 22 | 22 - u2 | 22 | 22 - vn | 22 | 22 - xe | 22 | 22 - y4 | 22 | 22 - zh | 22 | 22 - zo | 22 | 22 - zq | 22 | 22 - a1 | 21 | 21 - bl | 21 | 21 - bo | 21 | 21 - cb | 21 | 21 - co | 21 | 21 - cq | 21 | 21 - cv | 21 | 21 - d7 | 21 | 21 - g8 | 21 | 21 - ch | 21 | 21 - je | 21 | 21 - jp | 21 | 21 - jz | 21 | 21 - lg | 21 | 21 - me | 21 | 21 - nc | 21 | 21 - p4 | 21 | 21 - st | 21 | 21 - vb | 21 | 21 - vw | 21 | 21 - vz | 21 | 21 - xj | 21 | 21 - xq | 21 | 21 - xu | 21 | 21 - xy | 21 | 21 - zb | 21 | 21 - bv | 20 | 20 - bz | 20 | 20 - cj | 20 | 20 - cp | 20 | 20 - cs | 20 | 20 - d8 | 20 | 20 - ju | 20 | 20 - ks | 20 | 20 - ky | 20 | 20 - k0 | 20 | 20 - lb | 20 | 20 - lj | 20 | 20 - lu | 20 | 20 - l1 | 20 | 20 - nm | 20 | 20 - nw | 20 | 20 - nz | 20 | 20 - o7 | 20 | 20 - p6 | 20 | 20 - vh | 20 | 20 - vp | 20 | 20 - vs | 20 | 20 - xb | 20 | 20 - xr | 20 | 20 - zv | 20 | 20 - z3 | 20 | 20 - bq | 19 | 19 - br | 19 | 19 - by | 19 | 19 - cl | 19 | 19 - d2 | 19 | 19 - f1 | 19 | 19 - f4 | 19 | 19 - gf | 19 | 19 - hq | 19 | 19 - ka | 19 | 19 - kd | 19 | 19 - kj | 19 | 19 - k9 | 19 | 19 - md | 19 | 19 - mi | 19 | 19 - ml | 19 | 19 - my | 19 | 19 - nj | 19 | 19 - ny | 19 | 19 - o1 | 19 | 19 - s4 | 19 | 19 - s8 | 19 | 19 - t5 | 19 | 19 - u0 | 19 | 19 - xl | 19 | 19 - zg | 19 | 19 - zi | 19 | 19 - a5 | 18 | 18 - bh | 18 | 18 - bx | 18 | 18 - b9 | 18 | 18 - d3 | 18 | 18 - fy | 18 | 18 - g2 | 18 | 18 - i4 | 18 | 18 - i6 | 18 | 18 - i9 | 18 | 18 - jw | 18 | 18 - lk | 18 | 18 - mb | 18 | 18 - mv | 18 | 18 - nd | 18 | 18 - nr | 18 | 18 - nt | 18 | 18 - t2 | 18 | 18 - xf | 18 | 18 - xv | 18 | 18 - zc | 18 | 18 - zd | 18 | 18 - a7 | 17 | 17 - bc | 17 | 17 - bd | 17 | 17 - ce | 17 | 17 - cf | 17 | 17 - cr | 17 | 17 - g9 | 17 | 17 - j0 | 17 | 17 - j5 | 17 | 17 - mp | 17 | 17 - mr | 17 | 17 - mw | 17 | 17 - nk | 17 | 17 - no | 17 | 17 - o0 | 17 | 17 - o4 | 17 | 17 - s0 | 17 | 17 - s1 | 17 | 17 - t4 | 17 | 17 - u9 | 17 | 17 - vf | 17 | 17 - vx | 17 | 17 - xi | 17 | 17 - xn | 17 | 17 - xz | 17 | 17 - x3 | 17 | 17 - zl | 17 | 17 - zn | 17 | 17 - a0 | 16 | 16 - bu | 16 | 16 - bw | 16 | 16 - ci | 16 | 16 - ck | 16 | 16 - d0 | 16 | 16 - d4 | 16 | 16 - d6 | 16 | 16 - f5 | 16 | 16 - gz | 16 | 16 - g1 | 16 | 16 - h4 | 16 | 16 - jh | 16 | 16 - lt | 16 | 16 - l4 | 16 | 16 - mg | 16 | 16 - mh | 16 | 16 - mo | 16 | 16 - ni | 16 | 16 - nl | 16 | 16 - nq | 16 | 16 - p2 | 16 | 16 - u8 | 16 | 16 - vl | 16 | 16 - vo | 16 | 16 - v9 | 16 | 16 - xp | 16 | 16 - y3 | 16 | 16 - y7 | 16 | 16 - za | 16 | 16 - zx | 16 | 16 - z7 | 16 | 16 - bf | 15 | 15 - bp | 15 | 15 - cc | 15 | 15 - g0 | 15 | 15 - j2 | 15 | 15 - j9 | 15 | 15 - le | 15 | 15 - ll | 15 | 15 - l6 | 15 | 15 - ma | 15 | 15 - mu | 15 | 15 - m8 | 15 | 15 - nf | 15 | 15 - r6 | 15 | 15 - s5 | 15 | 15 - vd | 15 | 15 - vk | 15 | 15 - xa | 15 | 15 - xw | 15 | 15 - y2 | 15 | 15 - ze | 15 | 15 - zu | 15 | 15 - z8 | 15 | 15 - a6 | 14 | 14 - bk | 14 | 14 - bt | 14 | 14 - c0 | 14 | 14 - f8 | 14 | 14 - g3 | 14 | 14 - g4 | 14 | 14 - g7 | 14 | 14 - h6 | 14 | 14 - h7 | 14 | 14 - h9 | 14 | 14 - i1 | 14 | 14 - k1 | 14 | 14 - k2 | 14 | 14 - k6 | 14 | 14 - k7 | 14 | 14 - mc | 14 | 14 - nn | 14 | 14 - p9 | 14 | 14 - u6 | 14 | 14 - xd | 14 | 14 - zk | 14 | 14 - z6 | 14 | 14 - a4 | 13 | 13 - a9 | 13 | 13 - bm | 13 | 13 - cz | 13 | 13 - f2 | 13 | 13 - f3 | 13 | 13 - f6 | 13 | 13 - g6 | 13 | 13 - h2 | 13 | 13 - j1 | 13 | 13 - k5 | 13 | 13 - mf | 13 | 13 - mq | 13 | 13 - m1 | 13 | 13 - np | 13 | 13 - nx | 13 | 13 - o5 | 13 | 13 - p0 | 13 | 13 - p1 | 13 | 13 - s6 | 13 | 13 - s9 | 13 | 13 - va | 13 | 13 - vc | 13 | 13 - v6 | 13 | 13 - xc | 13 | 13 - z0 | 13 | 13 - c9 | 12 | 12 - d1 | 12 | 12 - h0 | 12 | 12 - h1 | 12 | 12 - j8 | 12 | 12 - k4 | 12 | 12 - l5 | 12 | 12 - l9 | 12 | 12 - m2 | 12 | 12 - m6 | 12 | 12 - m9 | 12 | 12 - nv | 12 | 12 - n7 | 12 | 12 - p3 | 12 | 12 - vq | 12 | 12 - vy | 12 | 12 - x1 | 12 | 12 - x2 | 12 | 12 - z5 | 12 | 12 - ct | 11 | 11 - c1 | 11 | 11 - c3 | 11 | 11 - f9 | 11 | 11 - g5 | 11 | 11 - j6 | 11 | 11 - l8 | 11 | 11 - n1 | 11 | 11 - vv | 11 | 11 - v7 | 11 | 11 - x5 | 11 | 11 - x8 | 11 | 11 - z2 | 11 | 11 - b0 | 10 | 10 - b2 | 10 | 10 - b8 | 10 | 10 - c6 | 10 | 10 - f0 | 10 | 10 - f7 | 10 | 10 - h5 | 10 | 10 - j3 | 10 | 10 - j4 | 10 | 10 - j7 | 10 | 10 - l7 | 10 | 10 - mm | 10 | 10 - mn | 10 | 10 - m0 | 10 | 10 - m7 | 10 | 10 - n8 | 10 | 10 - v1 | 10 | 10 - x0 | 10 | 10 - x6 | 10 | 10 - x7 | 10 | 10 - x9 | 10 | 10 - a8 | 9 | 9 - ba | 9 | 9 - bs | 9 | 9 - b1 | 9 | 9 - b4 | 9 | 9 - b5 | 9 | 9 - b6 | 9 | 9 - c5 | 9 | 9 - d5 | 9 | 9 - k8 | 9 | 9 - l0 | 9 | 9 - mk | 9 | 9 - ms | 9 | 9 - m5 | 9 | 9 - ne | 9 | 9 - n3 | 9 | 9 - n4 | 9 | 9 - n6 | 9 | 9 - v0 | 9 | 9 - v3 | 9 | 9 - v5 | 9 | 9 - v8 | 9 | 9 - b3 | 8 | 8 - b7 | 8 | 8 - c2 | 8 | 8 - c7 | 8 | 8 - c8 | 8 | 8 - d9 | 8 | 8 - k3 | 8 | 8 - l3 | 8 | 8 - m3 | 8 | 8 - m4 | 8 | 8 - n0 | 8 | 8 - n5 | 8 | 8 - v4 | 8 | 8 - x4 | 8 | 8 - z1 | 8 | 8 - z9 | 8 | 8 - l2 | 7 | 7 - s2 | 7 | 7 - z4 | 7 | 7 - c4 | 6 | 6 - h3 | 6 | 6 - n2 | 6 | 6 - n9 | 6 | 6 - v2 | 6 | 6 - 1l | 6 | 6 - 1o | 6 | 6 - 1t | 6 | 6 - 2e | 6 | 6 - 2o | 6 | 6 - 2l | 5 | 5 - 2u | 5 | 5 - 3k | 5 | 5 - 4p | 5 | 5 - 1a | 4 | 4 - 1i | 4 | 4 - 18 | 4 | 4 - 2s | 4 | 4 - 3q | 4 | 4 - 3y | 4 | 4 - 5y | 4 | 4 - 1f | 3 | 3 - 1h | 3 | 3 - 1m | 3 | 3 - 1p | 3 | 3 - 1s | 3 | 3 - 1v | 3 | 3 - 1x | 3 | 3 - 2a | 3 | 3 - 2b | 3 | 3 - 2h | 3 | 3 - 2n | 3 | 3 - 2p | 3 | 3 - 2v | 3 | 3 - 2y | 3 | 3 - 27 | 3 | 3 - 3d | 3 | 3 - 3w | 3 | 3 - 3z | 3 | 3 - 4a | 3 | 3 - 4d | 3 | 3 - 4v | 3 | 3 - 4z | 3 | 3 - 5e | 3 | 3 - 5i | 3 | 3 - 5k | 3 | 3 - 5o | 3 | 3 - 5t | 3 | 3 - 6b | 3 | 3 - 6d | 3 | 3 - 6o | 3 | 3 - 6w | 3 | 3 - 7a | 3 | 3 - 7h | 3 | 3 - 7r | 3 | 3 - 93 | 3 | 3 - 1b | 2 | 2 - 1d | 2 | 2 - 1g | 2 | 2 - 1j | 2 | 2 - 1n | 2 | 2 - 1r | 2 | 2 - 1u | 2 | 2 - 1w | 2 | 2 - 1y | 2 | 2 - 10 | 2 | 2 - 12 | 2 | 2 - 15 | 2 | 2 - 16 | 2 | 2 - 19 | 2 | 2 - 2d | 2 | 2 - 2i | 2 | 2 - 2j | 2 | 2 - 2k | 2 | 2 - 2q | 2 | 2 - 2r | 2 | 2 - 2t | 2 | 2 - 2w | 2 | 2 - 2z | 2 | 2 - 20 | 2 | 2 - 25 | 2 | 2 - 3b | 2 | 2 - 3f | 2 | 2 - 3h | 2 | 2 - 3o | 2 | 2 - 3p | 2 | 2 - 3r | 2 | 2 - 3s | 2 | 2 - 3v | 2 | 2 - 4f | 2 | 2 - 4g | 2 | 2 - 4h | 2 | 2 - 4j | 2 | 2 - 4m | 2 | 2 - 4r | 2 | 2 - 4s | 2 | 2 - 4t | 2 | 2 - 4u | 2 | 2 - 42 | 2 | 2 - 43 | 2 | 2 - 5c | 2 | 2 - 5f | 2 | 2 - 5h | 2 | 2 - 5p | 2 | 2 - 5q | 2 | 2 - 5z | 2 | 2 - 6a | 2 | 2 - 6h | 2 | 2 - 6q | 2 | 2 - 6r | 2 | 2 - 6t | 2 | 2 - 6y | 2 | 2 - 7c | 2 | 2 - 7g | 2 | 2 - 7k | 2 | 2 - 7o | 2 | 2 - 7u | 2 | 2 - 70 | 2 | 2 - 8j | 2 | 2 - 8w | 2 | 2 - 9f | 2 | 2 - 9y | 2 | 2 - foo | 1 | 3 - bar | 1 | 2 - copyright | 1 | 1 - qwerti | 1 | 1 - 0e | 1 | 1 - 0h | 1 | 1 - 0p | 1 | 1 - 0w | 1 | 1 - 0z | 1 | 1 - 1k | 1 | 1 - 1q | 1 | 1 - 1z | 1 | 1 - 11 | 1 | 1 - 13 | 1 | 1 - 14 | 1 | 1 - 17 | 1 | 1 - 2f | 1 | 1 - 24 | 1 | 1 - 26 | 1 | 1 - 28 | 1 | 1 - 3a | 1 | 1 - 3e | 1 | 1 - 3g | 1 | 1 - 3i | 1 | 1 - 3m | 1 | 1 - 3t | 1 | 1 - 3u | 1 | 1 - 30 | 1 | 1 - 345 | 1 | 1 - 37 | 1 | 1 - 39 | 1 | 1 - 4b | 1 | 1 - 4c | 1 | 1 - 4i | 1 | 1 - 4k | 1 | 1 - 4n | 1 | 1 - 4o | 1 | 1 - 4q | 1 | 1 - 4w | 1 | 1 - 4y | 1 | 1 - 40 | 1 | 1 - 41 | 1 | 1 - 44 | 1 | 1 - 45 | 1 | 1 - 48 | 1 | 1 - 5a | 1 | 1 - 5d | 1 | 1 - 5g | 1 | 1 - 5j | 1 | 1 - 5l | 1 | 1 - 5s | 1 | 1 - 5u | 1 | 1 - 5x | 1 | 1 - 51 | 1 | 1 - 55 | 1 | 1 - 56 | 1 | 1 - 6c | 1 | 1 - 6f | 1 | 1 - 6g | 1 | 1 - 6i | 1 | 1 - 6k | 1 | 1 - 6n | 1 | 1 - 6p | 1 | 1 - 6s | 1 | 1 - 6u | 1 | 1 - 6x | 1 | 1 - 64 | 1 | 1 - 68 | 1 | 1 - 7f | 1 | 1 - 7j | 1 | 1 - 7n | 1 | 1 - 7p | 1 | 1 - 7w | 1 | 1 - 7y | 1 | 1 - 7z | 1 | 1 - 72 | 1 | 1 - 8d | 1 | 1 - 8i | 1 | 1 - 8l | 1 | 1 - 8n | 1 | 1 - 8p | 1 | 1 - 8t | 1 | 1 - 8x | 1 | 1 - 80 | 1 | 1 - 82 | 1 | 1 - 85 | 1 | 1 - 9a | 1 | 1 - 9e | 1 | 1 - 9h | 1 | 1 - 9r | 1 | 1 - 9w | 1 | 1 - 95 | 1 | 1 - 97 | 1 | 1 -(1146 rows) - -insert into test_tsvector values ('1', 'a:1a,2,3b b:5a,6a,7c,8'); -insert into test_tsvector values ('1', 'a:1a,2,3c b:5a,6b,7c,8b'); -select * from stat('select a from test_tsvector','a') order by ndoc desc, nentry desc, word; - word | ndoc | nentry -------+------+-------- - b | 2 | 3 - a | 2 | 2 -(2 rows) - -select * from stat('select a from test_tsvector','b') order by ndoc desc, nentry desc, word; - word | ndoc | nentry -------+------+-------- - b | 1 | 2 - a | 1 | 1 -(2 rows) - -select * from stat('select a from test_tsvector','c') order by ndoc desc, nentry desc, word; - word | ndoc | nentry -------+------+-------- - b | 2 | 2 - a | 1 | 1 -(2 rows) - -select * from stat('select a from test_tsvector','d') order by ndoc desc, nentry desc, word; - word | ndoc | nentry ------------+------+-------- - a | 2 | 2 - foo | 1 | 3 - bar | 1 | 2 - b | 1 | 1 - copyright | 1 | 1 - qq | 1 | 1 - qwerti | 1 | 1 - 345 | 1 | 1 -(8 rows) - -select * from stat('select a from test_tsvector','ad') order by ndoc desc, nentry desc, word; - word | ndoc | nentry ------------+------+-------- - a | 2 | 4 - b | 2 | 4 - foo | 1 | 3 - bar | 1 | 2 - copyright | 1 | 1 - qq | 1 | 1 - qwerti | 1 | 1 - 345 | 1 | 1 -(8 rows) - -select to_tsquery('english', 'skies & books'); - to_tsquery ----------------- - 'sky' & 'book' -(1 row) - -select rank_cd(to_tsvector('Erosion It took the sea a thousand years, -A thousand years to trace -The granite features of this cliff -In crag and scarp and base. -It took the sea an hour one night -An hour of storm to place -The sculpture of these granite seams, -Upon a woman s face. E. J. Pratt (1882 1964) -'), to_tsquery('sea&thousand&years')); - rank_cd ------------ - 0.0555556 -(1 row) - -select rank_cd(to_tsvector('Erosion It took the sea a thousand years, -A thousand years to trace -The granite features of this cliff -In crag and scarp and base. -It took the sea an hour one night -An hour of storm to place -The sculpture of these granite seams, -Upon a woman s face. E. J. Pratt (1882 1964) -'), to_tsquery('granite&sea')); - rank_cd ------------ - 0.0238095 -(1 row) - -select rank_cd(to_tsvector('Erosion It took the sea a thousand years, -A thousand years to trace -The granite features of this cliff -In crag and scarp and base. -It took the sea an hour one night -An hour of storm to place -The sculpture of these granite seams, -Upon a woman s face. E. J. Pratt (1882 1964) -'), to_tsquery('sea')); - rank_cd ---------- - 0.2 -(1 row) - -select headline('Erosion It took the sea a thousand years, -A thousand years to trace -The granite features of this cliff -In crag and scarp and base. -It took the sea an hour one night -An hour of storm to place -The sculpture of these granite seams, -Upon a woman s face. E. J. Pratt (1882 1964) -', to_tsquery('sea&thousand&years')); - headline --------------------------------------------- - sea a thousand years,+ - A thousand years to trace + - The granite features of this cliff -(1 row) - -select headline('Erosion It took the sea a thousand years, -A thousand years to trace -The granite features of this cliff -In crag and scarp and base. -It took the sea an hour one night -An hour of storm to place -The sculpture of these granite seams, -Upon a woman s face. E. J. Pratt (1882 1964) -', to_tsquery('granite&sea')); - headline -------------------------------------------- - sea a thousand years, + - A thousand years to trace + - The granite features of this cliff -(1 row) - -select headline('Erosion It took the sea a thousand years, -A thousand years to trace -The granite features of this cliff -In crag and scarp and base. -It took the sea an hour one night -An hour of storm to place -The sculpture of these granite seams, -Upon a woman s face. E. J. Pratt (1882 1964) -', to_tsquery('sea')); - headline ------------------------------------- - sea a thousand years, + - A thousand years to trace + - The granite features of this cliff -(1 row) - -select headline(' - - - -Sea view wow foo bar qq -YES   -ff-bg - - -', -to_tsquery('sea&foo'), 'HighlightAll=true'); - headline ------------------------------------------------------------------------------ - + - + - + - + - Sea view wow foo bar qq + - YES  + - ff-bg + - + - + - -(1 row) - ---check debug -select * from public.ts_debug('Tsearch module for PostgreSQL 7.3.3'); - ts_name | tok_type | description | token | dict_name | tsvector ----------+-----------+-----------------+------------+----------------+-------------- - english | asciiword | Word, all ASCII | Tsearch | {english_stem} | 'tsearch' - english | blank | Space symbols | | {} | - english | asciiword | Word, all ASCII | module | {english_stem} | 'modul' - english | blank | Space symbols | | {} | - english | asciiword | Word, all ASCII | for | {english_stem} | - english | blank | Space symbols | | {} | - english | asciiword | Word, all ASCII | PostgreSQL | {english_stem} | 'postgresql' - english | blank | Space symbols | | {} | - english | version | Version number | 7.3.3 | {simple} | '7.3.3' -(9 rows) - ---check ordering -insert into test_tsvector values (null, null); -select a is null, a from test_tsvector order by a; - ?column? | a -----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - f | - f | - f | - f | - f | - f | - f | - f | - f | - f | 'a':1A,2,3B 'b':5A,6A,7C,8 - f | 'a':1A,2,3C 'b':5A,6B,7C,8B - f | 'bar':2,8 'foo':1,3,6 'qq':7 - f | '345':1 'copyright':3 'qwerti':2 - f | '7w' 'ch' 'd7' 'eo' 'gw' 'i4' 'lq' 'o6' 'qt' 'y0' - f | 'ar' 'ei' 'kq' 'ma' 'qa' 'qh' 'qq' 'qz' 'rx' 'st' - f | 'gs' 'i6' 'i9' 'j2' 'l0' 'oq' 'qx' 'sc' 'xe' 'yu' - f | 'ap' 'i2' 'k0' 'n4' 'ou' 'px' 'qe' 'qo' 'qr' 't1' 'yz' - f | 'cb' 'ib' 'ih' 'jx' 'oy' 'ph' 'tl' 'ty' 'vb' 'vu' 'wu' - f | 'cp' 'i0' 'ia' 'jh' 'kh' 'kl' 'ql' 'sb' 'u3' 'wy' 'ys' - f | 'cy' 'ey' 'gr' 'lq' 'n1' 'pp' 'pq' 'qb' 'qe' 'se' 'wb' - f | 'ja' 'k2' 'ko' 'o6' 'ob' 'ps' 't9' 'tz' 'uk' 'um' 'vv' - f | '5e' 'a2' 'ag' 'ay' 'dc' 'ef' 'jd' 'mn' 'pl' 'qp' 'wu' 'xd' - f | '7a' 'ap' 'bl' 'fl' 'g7' 'ko' 'ma' 'qi' 'ri' 'rp' 'y5' 'yo' - f | 'a4' 'an' 'go' 'ki' 'px' 'qq' 'td' 'tm' 'ur' 'wc' 'wp' 'yx' - f | 'aa' 'ah' 'bo' 'dz' 'pd' 'pm' 'qf' 'qw' 'rd' 'rn' 'tf' 'wu' - f | 'aj' 'ar' 'ay' 'eb' 'g5' 'ic' 'la' 'u2' 'up' 'wb' 'x8' 'yr' - f | 'aw' 'dz' 'el' 'hb' 'iu' 'lc' 'm9' 'r5' 'rt' 'uz' 'x2' 'zp' - f | 'dz' 'ea' 'h8' 'j9' 'mr' 'pc' 'qa' 'qt' 'rm' 'rv' 'ub' 'wg' - f | 'ew' 'fi' 'g2' 'ku' 'od' 'pk' 'tm' 'tq' 'tu' 'uf' 'wn' 'y1' - f | 'gi' 'n3' 'n7' 'om' 'qa' 'r7' 're' 'ug' 'w7' 'wi' 'x4' 'yn' - f | '3k' 'f5' 'if' 'kg' 'lj' 'ol' 'qr' 'so' 'ta' 'u1' 'vu' 'wr' 'y2' - f | '70' 'e0' 'ep' 'ex' 'hh' 'jn' 'kg' 'nq' 'rg' 'rj' 'uf' 'vs' 'ys' - f | 'ag' 'al' 'ay' 'fw' 'hi' 'ou' 'p6' 'qy' 'rg' 'rz' 'sx' 'uy' 'zb' - f | 'cm' 'dm' 'eh' 'em' 'ik' 'j0' 'kk' 'lp' 'ng' 'or' 'pu' 'qd' 'tw' - f | 'di' 'ec' 'i4' 'iq' 'iw' 'ko' 'l3' 'mw' 'py' 'qo' 'rx' 'wt' 'yl' - f | '5q' 'av' 'd2' 'd4' 'e5' 'jc' 'km' 'mm' 'pa' 'rs' 's4' 'si' 'tc' 'ut' - f | '6o' 'av' 'ed' 'ee' 'gf' 'ii' 'o8' 'og' 'om' 'qs' 'ta' 'th' 'tk' 'w0' - f | '7y' 'aq' 'cu' 'd3' 'h2' 'ih' 'oc' 'qh' 'rc' 'rs' 't3' 'ud' 'we' 'zt' - f | 'b7' 'eu' 'g4' 'hw' 'in' 'pi' 'qt' 'r0' 'rg' 'sn' 'sz' 'tc' 'wd' 'zs' - f | 'fb' 'in' 'iy' 'lu' 'p4' 'pd' 'qa' 'qq' 's6' 'ta' 'y1' 'yg' 'yy' 'zk' - f | 'at' 'ec' 'hs' 'ix' 'ks' 'lq' 'ls' 'pk' 'qs' 'qy' 'rc' 'ut' 'xv' 'yo' 'ys' - f | 'az' 'bl' 'dl' 'ec' 'gg' 'jq' 'o0' 'oj' 'q8' 'qq' 'ta' 'un' 'wb' 'wo' 'xu' - f | 'c0' 'd4' 'dw' 'ef' 'em' 'j2' 'kj' 'ql' 'rn' 'ta' 'uk' 'vv' 'wf' 'y9' 'zq' - f | 'gn' 'gx' 'hf' 'ji' 'kx' 'nh' 'o6' 'pe' 'q1' 'qt' 'rw' 'sc' 'ss' 'yh' 'zm' - f | 'h7' 'in' 'is' 'o7' 'q0' 'qa' 'qq' 'rl' 'rs' 'tu' 'u9' 'v3' 'vr' 'yq' 'zy' - f | 'ae' 'af' 'ay' 'da' 'dp' 'dq' 'e1' 'gi' 'gk' 'rl' 'sf' 'ta' 'td' 'tf' 'tt' 'tw' - f | 'aj' 'cl' 'cy' 'ee' 'i3' 'ir' 'nx' 'oz' 'qm' 'qw' 'r2' 't2' 'u0' 'ub' 'ur' 'wj' - f | 'av' 'dp' 'ff' 'fx' 'jk' 'ke' 'lb' 'lm' 'n1' 'ql' 'rv' 's4' 'uv' 'wl' 'ws' 'yj' - f | 'b8' 'eh' 'g5' 'gn' 'jo' 'mx' 'og' 'ol' 'on' 'px' 'rr' 'sl' 'un' 'uz' 'wv' 'yf' - f | 'bt' 'dy' 'gy' 'hg' 'i7' 'it' 'jv' 'lh' 'ox' 'qo' 'ri' 's3' 'ss' 'u1' 'uq' 'wr' - f | 'ef' 'ej' 'fn' 'ho' 'ia' 'il' 'iq' 'mj' 'nr' 'p5' 'rm' 'sd' 'ux' 'vi' 'wq' 'y6' - f | '25' 'cd' 'd2' 'dv' 'eo' 'es' 'f4' 'oc' 'qc' 'sh' 'te' 'tv' 'wd' 'wn' 'wo' 'xp' 'zt' - f | '2y' '8i' 'by' 'dl' 'h6' 'hj' 'm3' 'ml' 'qa' 'qx' 'r1' 'rm' 'rn' 'u4' 'uj' 'wo' 'xv' - f | 'ad' 'bs' 'dx' 'fi' 'i5' 'ia' 'j3' 'm5' 'mn' 'nr' 'ox' 'tg' 'un' 'vo' 'wj' 'wt' 'ys' - f | 'am' 'hw' 'jd' 'na' 'oe' 'pw' 'ql' 'qr' 's9' 'sk' 'u7' 'wa' 'wg' 'wu' 'x6' 'xr' 'yf' - f | 'de' 'mc' 'q1' 'q8' 'qp' 'qt' 'rq' 'rv' 'sa' 'sn' 'u8' 'vs' 'w9' 'wo' 'wp' 'ww' 'yl' - f | 'aa' 'af' 'ee' 'hb' 'ih' 'j2' 'lv' 'mw' 'pp' 'q3' 'rd' 'tb' 'td' 'ua' 'ug' 'up' 'xh' 'yy' - f | 'an' 'cp' 'dq' 'ej' 'ez' 'lj' 'ln' 'nu' 'qy' 'sm' 't8' 'td' 'tg' 'us' 'uw' 'vn' 'y4' 'z9' - f | 'ca' 'do' 'h5' 'i9' 'io' 'jk' 'jl' 'kn' 'qq' 'tm' 'ul' 'w9' 'wb' 'wp' 'wt' 'wx' 'y3' 'zd' - f | '16' 'ae' 'al' 'ef' 'eg' 'ew' 'gi' 'ha' 'id' 'ng' 'o3' 'on' 'p9' 'rz' 'uf' 'vg' 'wo' 'wr' 'zh' - f | 'ca' 'fu' 'hv' 'la' 'mt' 'ov' 'pl' 'q8' 'r3' 'sp' 'sy' 'tg' 'to' 'tv' 'wn' 'x4' 'yh' 'yp' 'ze' - f | 'cv' 'ds' 'dx' 'dy' 'ex' 'hh' 'lf' 'mq' 'qe' 'qu' 'rb' 'tb' 'tv' 'tz' 'ue' 'ui' 'wi' 'yb' 'zz' - f | 'ec' 'fd' 'gm' 'it' 'iu' 'kx' 'l1' 'pi' 'q1' 'qe' 'qs' 'ra' 'ri' 'rp' 'tn' 'to' 'vx' 'wh' 'wl' - f | 'eq' 'g7' 'jc' 'jf' 'ji' 'lw' 'ma' 'oe' 'p7' 'qb' 'qj' 'qo' 'u7' 'v7' 'w3' 'wd' 'wz' 'xg' 'yr' - f | 'a2' 'cs' 'ee' 'em' 'gk' 'hv' 'iy' 'kq' 'nc' 'pb' 'q5' 'qy' 'rq' 'rr' 'ts' 'uq' 'vt' 'w0' 'y6' 'yz' - f | 'al' 'fh' 'fk' 'gy' 'he' 'ie' 'iz' 'lq' 'oh' 'pu' 'q7' 's6' 'sd' 'sr' 'sw' 'uu' 'uz' 'v6' 'ws' 'xo' - f | 'aw' 'bm' 'dw' 'e5' 'ht' 'j4' 'kv' 'm5' 'oi' 'qa' 'qe' 'qf' 'ri' 'rj' 't6' 't8' 'un' 'wc' 'yb' 'yj' - f | 'az' 'bl' 'bo' 'cf' 'gt' 'h0' 'hx' 'iq' 'k2' 'kb' 'oc' 'qg' 'qn' 'qz' 're' 'rl' 'rv' 'xp' 'y8' 'yf' - f | 'bj' 'dq' 'e2' 'ec' 'fs' 'g8' 'gd' 'iw' 'jt' 'nn' 'ns' 'o9' 'p0' 'tb' 'u7' 'uv' 'wf' 'wr' 'xf' 'z3' - f | 'bs' 'ee' 'gz' 'hv' 'ib' 'kc' 'lb' 'nu' 'ps' 'pt' 'qh' 'ud' 'vo' 'vq' 'vu' 'wb' 'wj' 'x3' 'xu' 'yf' - f | '2o' 'a5' 'cg' 'ch' 'cp' 'eb' 'eg' 'eh' 'ew' 'fu' 'g4' 'hc' 'hx' 'il' 'li' 'rd' 'sf' 'sw' 'tg' 'uc' 'zj' - f | '6d' '8t' 'bl' 'gu' 'iu' 'kd' 'kj' 'kq' 'nw' 'nx' 'o6' 'oa' 'qk' 'ql' 'rd' 'ri' 'uc' 'vi' 'wy' 'xq' 'z2' - f | 'a3' 'ch' 'cs' 'e1' 'gq' 'gx' 'lz' 'nh' 'os' 'po' 'qs' 'rr' 'tx' 'ud' 'uj' 'uv' 've' 'w0' 'wj' 'xo' 'xz' - f | 'aa' 'al' 'e9' 'hm' 'ir' 'kc' 'l0' 'pi' 'po' 'qa' 'qk' 'r0' 'rd' 'rz' 'se' 'sr' 'vp' 'w6' 'w8' 'yd' 'yk' - f | 'am' 'bv' 'dt' 'dy' 'ed' 'gx' 'm7' 'mt' 'q5' 'qv' 'rr' 'sh' 'th' 'ut' 'wd' 'wm' 'y1' 'ym' 'yq' 'yr' 'yt' - f | '4f' 'e4' 'ep' 'fa' 'ff' 'iv' 'j4' 'kw' 'oj' 'pa' 'pw' 'q0' 'rv' 'ry' 't3' 'ul' 'vq' 'w1' 'wj' 'xm' 'ye' 'yu' - f | '7a' 'a3' 'dl' 'fo' 'hb' 'ki' 'kk' 'lo' 'pl' 'q5' 'qy' 'r1' 'rj' 'sy' 'tv' 'w3' 'wm' 'wn' 'yj' 'yr' 'zi' 'zq' - f | '1l' 'b5' 'dq' 'fw' 'hz' 'in' 'ml' 'nb' 'nu' 'o2' 'or' 'q7' 'qb' 'qh' 'qt' 'rv' 'so' 'tp' 'tr' 'u0' 'v6' 'wl' 'xb' - f | '5y' 'aw' 'e2' 'gd' 'gn' 'hn' 'ig' 'k9' 'ki' 'oj' 'pk' 'ql' 'qz' 'sl' 't3' 'u4' 'v8' 'wg' 'wu' 'xk' 'ya' 'yf' 'zr' - f | '6t' 'a9' 'db' 'ea' 'ec' 'ez' 'fq' 'gj' 'hb' 'hs' 'lc' 'or' 'p4' 'ph' 'pp' 'qr' 'qx' 'rc' 'rl' 'tn' 'u5' 'w9' 'x1' - f | 'bt' 'c5' 'd1' 'd7' 'g6' 'gk' 'ib' 'iv' 'ml' 'om' 'qd' 'qg' 'ql' 'r3' 'rc' 'u4' 'uh' 'uo' 'wh' 'y0' 'yn' 'yz' 'zo' - f | '1b' 'cp' 'di' 'ed' 'fv' 'gx' 'hs' 'i8' 'lh' 'lq' 'lz' 'p7' 'p8' 'pc' 'ql' 'qn' 'qw' 're' 'rg' 'tv' 'we' 'wp' 'yr' 'zj' - f | '1i' 'db' 'e4' 'er' 'fh' 'ft' 'hm' 'lg' 'll' 'of' 'og' 'q6' 'qj' 'r0' 're' 'th' 'up' 'ut' 'uw' 'vf' 'wq' 'ws' 'wx' 'zi' - f | 'a0' 'ck' 'fp' 'g4' 'ib' 'ih' 'im' 'iq' 'kz' 'll' 'lv' 'nc' 'oq' 'qf' 'qv' 'rg' 'rk' 'tc' 'tn' 'u1' 'u8' 'uj' 'un' 'vv' - f | 'ak' 'ar' 'dg' 'ds' 'ep' 'fv' 'ge' 'jd' 'no' 'on' 'q5' 'qd' 'qo' 'qv' 'qx' 'r7' 'ra' 'ru' 'sa' 'ud' 'uo' 'wl' 'ye' 'yl' - f | 'av' 'es' 'fl' 'gt' 'he' 'it' 'kp' 'mu' 'nc' 'ol' 'om' 'ph' 'qr' 'ra' 'rk' 'ui' 'vh' 'w6' 'wm' 'ws' 'yu' 'z0' 'zl' 'zm' - f | 'da' 'e5' 'ec' 'gd' 'gf' 'jj' 'kx' 'ly' 'pd' 'pj' 'q6' 'qk' 'rm' 'sa' 'te' 'ut' 'wa' 'wc' 'wl' 'ws' 'wv' 'zb' 'zk' 'zz' - f | '12' 'ao' 'ed' 'ek' 'ew' 'ey' 'fm' 'gr' 'hc' 'ht' 'io' 'ir' 'jb' 'jw' 'ke' 'ld' 'qj' 'se' 'tm' 'tn' 'tw' 'wv' 'y5' 'yt' 'z6' - f | '1p' '51' 'aj' 'av' 'bj' 'bn' 'c1' 'dx' 'ex' 'gz' 'he' 'ia' 'ic' 'ip' 'kn' 'mx' 'o6' 'or' 'ql' 'rc' 'wf' 'wi' 'wn' 'y8' 'yr' - f | 'av' 'ej' 'el' 'ep' 'fp' 'hh' 'hz' 'l9' 'mr' 'q3' 'qn' 'qq' 'qy' 'rh' 'tw' 'vt' 'vu' 'w5' 'wg' 'wk' 'wo' 'x5' 'y9' 'yk' 'zm' - f | 'b6' 'bq' 'dv' 'e1' 'ez' 'f5' 'fh' 'ik' 'iy' 'jy' 'li' 'm2' 'qe' 'rp' 'te' 'u4' 'u8' 'uo' 'w3' 'w8' 'we' 'wo' 'wu' 'x5' 'yl' - f | 'cq' 'er' 'hy' 'ie' 'jg' 'ke' 'lw' 'mf' 'p0' 'pe' 'pv' 'qk' 'qt' 'qy' 'sh' 'th' 'ti' 'ue' 'w5' 'wl' 'y4' 'y5' 'yi' 'yy' 'za' - f | 'a3' 'bh' 'c2' 'ca' 'e1' 'fb' 'fe' 'hd' 'hx' 'jc' 'md' 'nl' 'q9' 'qi' 'qq' 'qs' 'qt' 'rx' 'te' 'tv' 'u2' 'w8' 'wi' 'wr' 'xq' 'y9' - f | 'af' 'dt' 'e4' 'e8' 'eq' 'et' 'gr' 'kr' 'kv' 'lu' 'oy' 'pb' 'qh' 'ql' 'qw' 'r4' 't8' 'tb' 'td' 'tn' 'uc' 'uj' 'wh' 'xn' 'xs' 'yi' - f | 'au' 'bo' 'dz' 'ek' 'eq' 'et' 'fa' 'hw' 'id' 'im' 'kr' 'p4' 'qx' 'rb' 'rx' 'sf' 'tl' 'tx' 'uf' 'ui' 'uw' 'vr' 'wb' 'wn' 'xw' 'yd' - f | 'ay' 'bg' 'bp' 'cm' 'eg' 'ev' 'ff' 'go' 'hc' 'hl' 'jj' 'l0' 'os' 'q9' 'qc' 'qh' 'qo' 'rt' 'rx' 'so' 'sr' 'to' 'tx' 'uk' 'wb' 'y4' - f | 'd6' 'e4' 'ev' 'fd' 'i3' 'if' 'j1' 'j5' 'o8' 'oj' 'ok' 'pw' 'qc' 'qd' 'qf' 'qt' 't8' 'tw' 'u1' 'u7' 'wr' 'wv' 'ww' 'yh' 'yn' 'yz' - f | '1j' 'ag' 'c3' 'cl' 'e4' 'ef' 'eh' 'f5' 'fi' 'gy' 'hx' 'lw' 'oa' 'pu' 'qa' 'qi' 'qt' 'qu' 'rl' 'ro' 'rs' 'sg' 'uq' 'wq' 'ya' 'yh' 'ys' - f | 'a7' 'ah' 'cj' 'co' 'cv' 'dt' 'ex' 'fs' 'gx' 'hn' 'jv' 'kp' 'l5' 'od' 'on' 'pr' 'q6' 'q8' 'qi' 'qq' 'qr' 'rl' 'u2' 'wb' 'wx' 'yh' 'zq' - f | 'bg' 'eh' 'eq' 'gg' 'gh' 'gm' 'gx' 'i7' 'iv' 'm3' 'mv' 'n3' 'o6' 'ox' 'oz' 'pb' 'qk' 'rj' 'rs' 'sk' 'su' 'tg' 'uf' 'uj' 've' 'ww' 'yf' - f | 'cd' 'dl' 'e6' 'en' 'eu' 'gg' 'je' 'kp' 'lv' 'pv' 'q0' 'q3' 'qc' 'qd' 'qo' 'qs' 'qz' 'rw' 'se' 'tx' 'uh' 'uj' 'ul' 'wo' 'ye' 'yi' 'zx' - f | 'd6' 'do' 'e4' 'eg' 'hm' 'i3' 'kg' 'nz' 'ow' 'pc' 'pv' 'q0' 'q4' 'q6' 'qx' 'r0' 'ri' 'sm' 'sn' 'tw' 'u9' 'ul' 'up' 'vk' 'we' 'wm' 'zv' - f | 'a1' 'cd' 'cl' 'd8' 'ek' 'ig' 'ih' 'in' 'lq' 'o3' 'ow' 'px' 'qg' 'qm' 'qq' 'qr' 'qs' 'qy' 'rd' 'rh' 'to' 'tq' 'ul' 'wc' 'x9' 'ya' 'yf' 'yw' - f | 'aa' 'as' 'cg' 'dh' 'dn' 'dr' 'e0' 'h2' 'hr' 'j2' 'jf' 'js' 'kc' 'kw' 'ld' 'lh' 'mk' 'n3' 'q3' 'qe' 'ql' 'rv' 's3' 'w0' 'xg' 'ym' 'yt' 'zv' - f | 'ap' 'ca' 'dt' 'dx' 'ep' 'f5' 'fg' 'gq' 'hi' 'hj' 'i4' 'ic' 'it' 'iy' 'jl' 'lz' 'nd' 'o9' 'og' 'oq' 'pk' 'q6' 'qo' 'ra' 'sf' 'wd' 'wt' 'x9' - f | 'e2' 'ef' 'ev' 'fe' 'ij' 'j8' 'jm' 'kw' 'nb' 'ny' 'o6' 'o7' 'ou' 'pb' 'qd' 'qv' 'rh' 'rp' 's7' 'ti' 'ub' 'uk' 'wh' 'wi' 'wj' 'xj' 'xo' 'yx' - f | '3d' 'ad' 'dr' 'ee' 'ez' 'f4' 'fd' 'fg' 'fu' 'g9' 'gk' 'h9' 'hl' 'iz' 'jd' 'nb' 'o0' 'oo' 'oy' 'qj' 'qt' 'rp' 'ru' 'sv' 'tl' 'tv' 'wf' 'wp' 'wy' - f | '5t' 'al' 'db' 'dt' 'dx' 'ea' 'en' 'g6' 'gc' 'gm' 'gy' 'if' 'ii' 'ik' 'jb' 'jv' 'k5' 'po' 'pv' 'py' 'qj' 'qp' 'rz' 'ux' 'v1' 'w4' 'w8' 'wi' 'yv' - f | 'a1' 'b0' 'd0' 'db' 'ef' 'er' 'ev' 'ew' 'fe' 'fm' 'g8' 'la' 'n5' 'oh' 'os' 'pk' 'pn' 'qq' 'r7' 'sq' 'tw' 'ua' 'uu' 'wa' 'wk' 'wr' 'wu' 'xc' 'yi' - f | 'ab' 'c1' 'cl' 'd3' 'do' 'e5' 'e8' 'eg' 'ek' 'ex' 'gy' 'ia' 'iq' 'iw' 'jf' 'kv' 'm9' 'n4' 'nh' 'nj' 'q3' 'qa' 'qe' 'qg' 'qm' 'sy' 'ta' 'w5' 'w6' - f | 'av' 'bh' 'cd' 'cw' 'dv' 'em' 'gn' 'iw' 'ja' 'ki' 'lc' 'lx' 'my' 'oi' 'ox' 'q0' 'qb' 'qi' 'qn' 'uf' 'ux' 'we' 'wn' 'xd' 'xq' 'y4' 'y9' 'zf' 'zs' - f | 'ch' 'e1' 'fi' 'g8' 'go' 'hf' 'i1' 'ic' 'in' 'it' 'j7' 'jk' 'jl' 'jv' 'nm' 'of' 'oz' 'r8' 'rc' 'rk' 'rp' 'rx' 'sp' 'tb' 'tv' 'tw' 'ul' 'wx' 'zj' - f | 'an' 'dh' 'do' 'hs' 'hv' 'ia' 'ic' 'ne' 'of' 'oi' 'oq' 'pe' 'pg' 'q9' 'r5' 'rk' 'sc' 'sf' 'sh' 'ta' 'tb' 'tq' 'um' 'wb' 'wj' 'wm' 'wq' 'wt' 'yi' 'ym' - f | 'bb' 'bq' 'c2' 'cw' 'cy' 'db' 'dd' 'f3' 'fl' 'fn' 'id' 'ig' 'jb' 'kc' 'kl' 'lp' 'lx' 'mh' 'o0' 'pk' 'qi' 'qx' 'rq' 've' 'w8' 'wd' 'x1' 'y4' 'ye' 'zm' - f | 'c7' 'eb' 'er' 'gb' 'if' 'ko' 'ml' 'oq' 'ot' 'pa' 'qk' 'qs' 'rl' 'rp' 'sc' 'tf' 'tv' 'tw' 'uc' 'ud' 'uz' 'vk' 'vm' 'w0' 'wm' 'wu' 'yd' 'yq' 'yy' 'zu' - f | '27' '2e' '2p' 'aa' 'eh' 'en' 'eq' 'eu' 'ew' 'ff' 'g8' 'hv' 'mx' 'oi' 'pd' 'q3' 'qs' 'rl' 'sa' 'sw' 'te' 'tn' 'ty' 'uh' 'uo' 'wb' 'wh' 'wy' 'xx' 'z8' 'zt' - f | '3k' 'di' 'dp' 'em' 'ew' 'f5' 'hb' 'hn' 'j3' 'k0' 'lk' 'm4' 'mq' 'pr' 'qe' 'qo' 'qy' 'rc' 'ri' 'rt' 'so' 'ts' 've' 'w4' 'w7' 'wl' 'wn' 'wy' 'xf' 'y6' 'yt' - f | '3v' 'ab' 'at' 'bn' 'bz' 'cx' 'eh' 'gd' 'hd' 'hr' 'i9' 'j8' 'jg' 'jx' 'lf' 'ng' 'oj' 'ov' 'oz' 'pn' 'ps' 'qq' 'qr' 'ro' 'rt' 'u9' 'up' 'uz' 'yl' 'yw' 'zi' - f | '6n' 'da' 'dl' 'dx' 'el' 'ew' 'ff' 'fl' 'gc' 'iu' 'jh' 'jt' 'kt' 'lz' 'pd' 'q6' 'qj' 'ql' 'r3' 'ra' 'rn' 'ry' 'sg' 'tf' 'tp' 'tt' 'ub' 'ye' 'yf' 'yl' 'yp' - f | 'a3' 'ai' 'at' 'd7' 'eu' 'fu' 'gd' 'ii' 'ik' 'j0' 'je' 'lw' 'ly' 'mx' 'n7' 'pm' 'qf' 'qk' 'qt' 'ss' 'to' 'tq' 'un' 'vn' 'vq' 'wo' 'wz' 'yk' 'yy' 'zf' 'zg' - f | 'aa' 'ch' 'cm' 'db' 'dd' 'e7' 'eu' 'f5' 'fr' 'gg' 'ie' 'jc' 'kt' 'na' 'on' 'or' 'po' 'q0' 're' 's3' 'tb' 'tc' 'td' 'tt' 'tv' 'uf' 'wi' 'wq' 'wt' 'y8' 'ys' - f | 'ac' 'al' 'b3' 'bg' 'ci' 'cn' 'ea' 'f4' 'ih' 'ix' 'kt' 'p8' 'pk' 'qd' 'qe' 'qi' 'rb' 'rc' 'ru' 'te' 'th' 'tl' 'tn' 'vb' 'wb' 'ws' 'ww' 'xk' 'xo' 'yb' 'zf' - f | 'az' 'eq' 'fe' 'go' 'gv' 'ig' 'iz' 'ja' 'l4' 'mo' 'nm' 'no' 'of' 'pk' 'q9' 'qb' 'ql' 'qt' 'r7' 'rc' 'rm' 'tg' 'tv' 'u3' 'u7' 'wc' 'x4' 'xw' 'yl' 'zk' 'zn' - f | 'c8' 'db' 'dh' 'fh' 'g7' 'gm' 'if' 'ih' 'jd' 'li' 'ms' 'mt' 'no' 'or' 'p7' 'pc' 'qb' 'qm' 'sh' 'tk' 'uf' 'uz' 'vb' 'vp' 'wh' 'wr' 'wv' 'xh' 'xm' 'xp' 'zj' - f | '5s' 'aa' 'ar' 'bu' 'c2' 'cw' 'd2' 'ej' 'g8' 'gy' 'ij' 'iv' 'k0' 'l1' 'lb' 'm1' 'od' 'pm' 'q1' 'q4' 'q5' 'qd' 'rn' 'ry' 'sj' 'sm' 'ta' 'th' 'u8' 'vf' 'wr' 'xm' - f | '6d' 'ao' 'bo' 'cq' 'e0' 'fi' 'fm' 'h6' 'i2' 'jl' 'kn' 'mj' 'nv' 'oq' 'p6' 'qd' 'qi' 'qn' 'r2' 'r8' 'rd' 'sd' 'sl' 'ta' 'tp' 'ub' 'uh' 'w3' 'wh' 'y1' 'yj' 'zk' - f | 'aa' 'cb' 'd2' 'dd' 'de' 'e4' 'gd' 'go' 'hc' 'ic' 'in' 'ip' 'js' 'lm' 'o1' 'o3' 'pl' 'ra' 'rx' 'sj' 'ti' 'tu' 'tv' 'wc' 'we' 'wl' 'wq' 'wx' 'xg' 'xi' 'yc' 'yi' - f | 'ad' 'ai' 'ak' 'df' 'ee' 'fr' 'gg' 'i2' 'i5' 'ig' 'ij' 'ir' 'j1' 'kk' 'km' 'l9' 'qb' 'ql' 'qt' 'qw' 'rb' 's2' 'te' 'ue' 'w0' 'wk' 'wu' 'y4' 'yb' 'yf' 'yp' 'zn' - f | 'ap' 'aw' 'ba' 'cz' 'dw' 'eh' 'g5' 'g9' 'gc' 'gi' 'go' 'ir' 'j8' 'kl' 'mg' 'p6' 'ql' 'qu' 'qz' 'sa' 't7' 'tw' 'v5' 'v7' 'wj' 'xt' 'y6' 'yg' 'yh' 'yq' 'z5' 'zj' - f | 'bp' 'cy' 'd6' 'd7' 'em' 'et' 'gf' 'gt' 'hl' 'ib' 'io' 'kz' 'mx' 'nm' 'oe' 'pd' 'qf' 'qk' 'rk' 'rz' 'se' 'si' 'tq' 'tu' 'uu' 'v3' 'wa' 'wf' 'wg' 'wx' 'yd' 'ym' - f | '15' '72' 'av' 'ba' 'dt' 'ev' 'hd' 'hu' 'jy' 'lo' 'mo' 'mt' 'oe' 'oi' 'pa' 'qc' 'qe' 'qt' 'r1' 'rg' 'ry' 'td' 'tk' 'us' 'wk' 'wq' 'ww' 'wz' 'x7' 'xq' 'y9' 'yx' 'z3' - f | '3q' 'an' 'cp' 'ej' 'fx' 'gj' 'i3' 'ib' 'ik' 'jt' 'k5' 'n9' 'no' 'os' 'pg' 'qo' 'qp' 'qx' 'rb' 'rk' 'su' 'tk' 'tv' 'u1' 'up' 'w1' 'we' 'wj' 'wr' 'yf' 'yq' 'z5' 'zd' - f | 'ak' 'dx' 'eb' 'es' 'eu' 'fd' 'ga' 'gf' 'hl' 'i2' 'kb' 'kd' 'mz' 'n1' 'o8' 'qe' 'qs' 'qw' 'rp' 'sf' 'sk' 'sp' 't0' 'tu' 'uh' 'v9' 'vj' 'vs' 'vw' 'wv' 'xs' 'yo' 'z2' - f | '25' 'ad' 'ao' 'at' 'ch' 'db' 'dz' 'eq' 'fp' 'gq' 'ih' 'iu' 'jo' 'km' 'p1' 'pb' 'qa' 'qb' 'qc' 'qg' 'ql' 'qq' 'qy' 'rb' 'rf' 'rl' 'rw' 'sp' 'ty' 'uk' 'ur' 'wu' 'wv' 'yw' - f | '1o' '3w' 'aw' 'be' 'bx' 'e7' 'eo' 'ey' 'ff' 'fx' 'ht' 'jb' 'km' 'kv' 'l6' 'la' 'nu' 'ny' 'pk' 'qc' 'qi' 'rk' 'ro' 'rw' 's3' 'sh' 't5' 'u1' 'uy' 'vi' 'vm' 'wi' 'x3' 'xo' 'yn' - f | '2a' '5d' 'ag' 'ar' 'at' 'dc' 'fa' 'fh' 'gn' 'gx' 'hh' 'iy' 'kd' 'ke' 'ld' 'nd' 'nx' 'oz' 'qc' 'qd' 'qo' 'qp' 'qu' 'r0' 'rg' 't5' 'tc' 'tg' 'th' 'tk' 'w2' 'w5' 'wt' 'yl' 'zn' - f | '30' 'cl' 'dl' 'e7' 'ee' 'ef' 'eh' 'el' 'fk' 'fn' 'fs' 'gi' 'gw' 'i2' 'il' 'l7' 'm6' 'm9' 'mf' 'o8' 'ob' 'ok' 'pc' 'pe' 'qb' 'qe' 'qn' 'qr' 'tu' 'uc' 'ud' 'wp' 'xq' 'ym' 'ys' - f | '5o' 'ar' 'at' 'az' 'bf' 'bv' 'e0' 'ew' 'fh' 'hd' 'ij' 'in' 'is' 'iu' 'ji' 'l5' 'ld' 'mz' 'nk' 'oc' 'p2' 'ph' 'px' 'q9' 'qi' 'qn' 'qo' 'qq' 'qv' 'rw' 'sf' 'sp' 'te' 'up' 'y8' - f | 'a2' 'bx' 'e4' 'em' 'eu' 'ey' 'gd' 'jj' 'k1' 'lm' 'my' 'oz' 'p8' 'pa' 'pj' 'qj' 'qp' 'qy' 'ri' 'rw' 'sj' 'sw' 'tv' 'uj' 'uk' 'um' 'ux' 'vs' 'wd' 'wf' 'xj' 'xs' 'xx' 'xy' 'yd' - f | 'ab' 'at' 'cr' 'e9' 'g0' 'gv' 'ib' 'iv' 'iz' 'jb' 'jm' 'k0' 'kh' 'o2' 'o7' 'oq' 'ot' 'pj' 'ps' 'qj' 'qz' 'r9' 'rn' 'sa' 't1' 'ti' 'tq' 'ue' 'us' 'wc' 'wo' 'ww' 'yi' 'ys' 'za' - f | 'by' 'c1' 'da' 'ec' 'ej' 'ew' 'g4' 'gq' 'gt' 'ir' 'jv' 'kl' 'kz' 'l5' 'nm' 'oi' 'on' 'pc' 'q2' 'qx' 'qz' 'rd' 'se' 'sq' 'ti' 'tk' 'to' 'ur' 'w8' 'wm' 'wr' 'y1' 'yn' 'yp' 'zy' - f | 'd8' 'dm' 'eg' 'et' 'ge' 'gz' 'i8' 'ig' 'il' 'iy' 'jo' 'k6' 'lm' 'oj' 'p3' 'pw' 'qd' 'qp' 'qq' 'qz' 'r7' 's1' 'sr' 'sx' 't4' 'uz' 'vm' 'vr' 'w0' 'wj' 'wp' 'xc' 'y1' 'yj' 'zd' - f | '0w' 'bu' 'df' 'dj' 'du' 'dy' 'dz' 'gj' 'ho' 'je' 'kw' 'm1' 'o3' 'oo' 'pf' 'qh' 'qn' 'qu' 'rf' 'rj' 'ro' 'rv' 'ss' 't4' 'tc' 'tf' 'um' 'uo' 'v6' 'v8' 'wn' 'wo' 'xh' 'y0' 'yz' 'zr' - f | 'a3' 'do' 'ef' 'hp' 'ih' 'im' 'jp' 'km' 'lv' 'mt' 'nh' 'oc' 'od' 'ph' 'pi' 'pj' 'qe' 'qh' 'qr' 'rq' 'rr' 'rs' 'sc' 'st' 'ts' 'tt' 'tw' 'ut' 'vv' 'w7' 'wv' 'x3' 'xa' 'xc' 'xl' 'zc' - f | 'ad' 'aj' 'ar' 'b4' 'dj' 'eo' 'eu' 'ex' 'gt' 'hj' 'ie' 'ij' 'iz' 'kg' 'ks' 'l1' 'ld' 'me' 'my' 'mz' 'oi' 'pr' 'qb' 'ry' 'sd' 'to' 'u5' 'wc' 'wf' 'wl' 'xs' 'y2' 'yg' 'z1' 'zj' 'zt' - f | '2y' 'a3' 'ac' 'ae' 'ar' 'dp' 'ec' 'f8' 'f9' 'ga' 'gq' 'gs' 'hm' 'ib' 'if' 'im' 'j0' 'na' 'pb' 'pf' 'q9' 'qa' 'qu' 'qw' 'ra' 'rj' 'rm' 'rr' 'su' 'tj' 'vw' 'wb' 'wf' 'wk' 'wo' 'ym' 'yu' - f | '5y' 'a2' 'by' 'c9' 'e6' 'fd' 'fn' 'g7' 'h9' 'hj' 'j9' 'kg' 'kk' 'kn' 'kx' 'ln' 'q3' 'qa' 'qh' 'rb' 'rh' 'sj' 'sn' 'tx' 'tz' 'un' 'us' 've' 'vf' 'vh' 'wf' 'wp' 'wz' 'xj' 'xq' 'yi' 'yz' - f | 'a1' 'aj' 'bi' 'cd' 'cw' 'd2' 'e4' 'e9' 'gz' 'ij' 'k1' 'kb' 'kn' 'lw' 'me' 'nj' 'oq' 'p4' 'ph' 'ps' 'q3' 'q4' 'qj' 's7' 'sp' 'sx' 'tc' 'tw' 'v1' 'vj' 'vt' 'w7' 'wa' 'wb' 'wp' 'y1' 'zc' - f | 'a9' 'av' 'aw' 'dj' 'e0' 'ej' 'er' 'eu' 'ez' 'fr' 'gq' 'hh' 'hp' 'ko' 'kq' 'lw' 'n8' 'pe' 'pl' 'pn' 'pp' 'pv' 'q9' 'qc' 'qj' 'qs' 'qw' 'r6' 'rl' 'tq' 'u5' 'uu' 'uz' 'wn' 'wp' 'wr' 'zo' - f | 'dq' 'ed' 'el' 'fg' 'fv' 'gh' 'hx' 'i2' 'iv' 'jc' 'la' 'ld' 'nb' 'oa' 'of' 'oi' 'py' 'q7' 'qe' 'qr' 'qs' 'qw' 'qx' 'qz' 'rl' 'rr' 'sp' 't3' 'te' 'ti' 'tu' 'ue' 'w0' 'wa' 'wq' 'wu' 'xn' - f | '4p' 'bw' 'cq' 'dk' 'dr' 'dx' 'e3' 'e8' 'ex' 'ez' 'g9' 'h9' 'ih' 'in' 'kt' 'lt' 'me' 'o7' 'od' 'oi' 'on' 'p1' 'pu' 'qa' 'qd' 'qm' 'rz' 'sd' 'tn' 'ua' 'uz' 'vg' 'vx' 'wx' 'xy' 'ya' 'yl' 'yx' - f | '6b' 'af' 'd3' 'df' 'dg' 'ds' 'e1' 'eb' 'er' 'f3' 'ft' 'ho' 'ik' 'k1' 'k2' 'li' 'mj' 'ni' 'py' 'qx' 'rb' 'rp' 'rv' 'sd' 'sh' 'sl' 'u5' 'uf' 'vk' 'vs' 'vx' 'wg' 'wm' 'wr' 'ws' 'wz' 'xn' 'zh' - f | '4u' 'a3' 'ck' 'dw' 'e5' 'fu' 'ij' 'iu' 'jd' 'jp' 'ka' 'kb' 'ld' 'op' 'p1' 'po' 'pw' 'q5' 'q7' 'qf' 'qq' 'qr' 'qv' 'rm' 'sv' 't6' 'td' 'tp' 'uw' 'vb' 'w4' 'w6' 'wq' 'xh' 'y2' 'yf' 'yt' 'zj' 'zz' - f | '7n' 'ai' 'aj' 'ap' 'b9' 'bx' 'cu' 'dn' 'e1' 'e2' 'ed' 'eg' 'eo' 'hu' 'ie' 'ln' 'lq' 'nl' 'oa' 'qa' 'qe' 'qo' 'r5' 'ra' 'ri' 'rm' 'rw' 'ss' 'sx' 't3' 'tz' 'ut' 'uz' 'wd' 'we' 'wn' 'wq' 'wr' 'ws' - f | '8p' 'ao' 'aq' 'c1' 'dh' 'dt' 'e9' 'eo' 'ev' 'fp' 'fu' 'gc' 'gz' 'hk' 'i5' 'id' 'ip' 'iy' 'jg' 'jr' 'k2' 'lo' 'mb' 'mf' 'oi' 'ou' 'qp' 'qr' 'qw' 'qx' 'ra' 'rj' 'tl' 'ui' 'uu' 'uy' 'vb' 'wh' 'yt' - f | 'a7' 'bq' 'el' 'ey' 'fp' 'fu' 'fx' 'gr' 'hi' 'hl' 'jm' 'ki' 'kp' 'n6' 'o9' 'oj' 'op' 'ou' 'p7' 'pm' 'pp' 'q7' 'qa' 'qc' 'qj' 'qk' 'qm' 'si' 'st' 'tn' 'uc' 'w6' 'wp' 'xu' 'y5' 'yk' 'ys' 'yu' 'zs' - f | 'ah' 'ai' 'b8' 'ci' 'd2' 'ea' 'ed' 'en' 'et' 'fj' 'fv' 'ht' 'iu' 'iv' 'iw' 'jb' 'jd' 'ky' 'mj' 'nt' 'q1' 'qb' 'qe' 'ql' 'qz' 'ru' 'sg' 'tl' 'tm' 'tn' 'tw' 'ty' 'u1' 'ud' 'us' 'wj' 'y1' 'zd' 'zj' - f | 'bf' 'cf' 'cg' 'cj' 'ef' 'ej' 'ek' 'ep' 'fk' 'gi' 'ik' 'ir' 'j0' 'km' 'ko' 'lu' 'mr' 'n6' 'oc' 'op' 'pt' 'q4' 'qe' 'qk' 'qv' 'rc' 'rt' 's8' 't3' 'tk' 'ut' 'wc' 'we' 'ws' 'wt' 'ww' 'y8' 'yd' 'yr' - f | '1d' 'a2' 'af' 'bb' 'dd' 'dg' 'dl' 'du' 'ee' 'ff' 'g0' 'hj' 'hk' 'i4' 'iy' 'jt' 'kq' 'm6' 'mh' 'ov' 'qf' 'qh' 'qq' 'rt' 'sw' 'ta' 'tc' 'we' 'wn' 'wy' 'wz' 'xd' 'xs' 'y2' 'yg' 'yj' 'yk' 'zi' 'zq' 'zw' - f | '1l' 'e2' 'e4' 'eo' 'ep' 'fd' 'ha' 'hp' 'hx' 'io' 'iu' 'jr' 'jx' 'k4' 'l8' 'nb' 'oa' 'om' 'on' 'ow' 'p2' 'qh' 'qp' 'qz' 'ra' 'rz' 'sy' 'tk' 'tt' 'ul' 'uq' 'vm' 'wt' 'xg' 'xn' 'ya' 'yf' 'yw' 'yx' 'zp' - f | '2l' '55' 'aq' 'aw' 'cm' 'dq' 'eb' 'fl' 'fo' 'fp' 'fy' 'gk' 'hy' 'ic' 'iu' 'jc' 'jl' 'lc' 'mb' 'nx' 'oe' 'oo' 'oz' 'p5' 'pa' 'pf' 'qr' 'rj' 'sc' 'sz' 'td' 'tz' 'u1' 'vq' 'wu' 'xb' 'xx' 'y0' 'za' 'zc' - f | '4z' 'a2' 'eg' 'f4' 'g9' 'gi' 'hd' 'hn' 'ij' 'io' 'ix' 'iz' 'jb' 'jd' 'kk' 'l4' 'lh' 'lq' 'p9' 'pa' 'pb' 'q7' 'qh' 'qi' 'qk' 'qs' 'r9' 'rc' 'ro' 'rr' 's4' 'tj' 'tz' 'vi' 'we' 'wp' 'xe' 'yd' 'yg' 'zj' - f | '7h' 'an' 'b6' 'cl' 'e1' 'e4' 'en' 'ey' 'ff' 'gn' 'h7' 'ht' 'i5' 'i9' 'ia' 'iw' 'jx' 'kl' 'ku' 'op' 'pe' 'pt' 'qb' 'ql' 'qp' 'qy' 'ri' 'se' 'si' 'ta' 'ti' 'tl' 'tp' 'uo' 'vr' 'w4' 'wn' 'xi' 'xs' 'ym' - f | '7k' 'et' 'ew' 'ez' 'g9' 'gk' 'he' 'hp' 'ip' 'jp' 'jq' 'jr' 'jv' 'kb' 'kk' 'ku' 'lx' 'o0' 'o3' 'oa' 'or' 'ou' 'q7' 'qa' 'qf' 'qg' 'qh' 'qo' 'ro' 'rx' 'tl' 'us' 'vk' 'vw' 'wc' 'wp' 'x0' 'xz' 'yg' 'z5' - f | 'a5' 'ab' 'ad' 'ao' 'b6' 'ea' 'es' 'ez' 'gm' 'gv' 'i0' 'in' 'jw' 'lh' 'lm' 'my' 'oj' 'ox' 'oy' 'pv' 'q1' 'qf' 'qh' 'qj' 'qo' 'qs' 'qt' 'qw' 'r0' 'ri' 'rk' 'ry' 's4' 'vs' 'wa' 'xy' 'y5' 'yg' 'yl' 'zm' - f | 'aa' 'ap' 'b0' 'c6' 'e1' 'ex' 'fe' 'fu' 'fz' 'g1' 'g8' 'go' 'hl' 'iz' 'k3' 'ls' 'mw' 'mz' 'oa' 'ow' 'p6' 'q5' 'qh' 'qq' 'qx' 'ra' 'rh' 'rp' 'rw' 'tf' 'tk' 'tl' 'uc' 'wi' 'x1' 'xb' 'yb' 'yw' 'yz' 'zm' - f | 'ad' 'as' 'dn' 'dq' 'e7' 'ei' 'ey' 'fj' 'h2' 'hu' 'hw' 'i7' 'i9' 'iu' 'jr' 'ma' 'na' 'nh' 'nk' 'pa' 'q5' 'qd' 'qn' 's0' 'so' 'sx' 'u7' 'uc' 'um' 'vb' 'w9' 'wf' 'wh' 'wl' 'wn' 'wr' 'xl' 'y8' 'yl' 'zw' - f | 'ae' 'ai' 'di' 'ea' 'eb' 'ec' 'gw' 'h8' 'hb' 'iw' 'iz' 'jf' 'jg' 'ks' 'le' 'p8' 'pl' 'pp' 'qd' 'qg' 'qm' 'qn' 'qu' 'qy' 'r4' 'rf' 'rq' 's1' 'sc' 'sq' 'v8' 'vh' 'vk' 'wd' 'x7' 'y7' 'ym' 'yp' 'yr' 'yw' - f | 'ah' 'aw' 'e5' 'en' 'ew' 'fi' 'fm' 'gq' 'gt' 'hy' 'ib' 'ie' 'ir' 'j9' 'jr' 'js' 'ny' 'ob' 'or' 'ot' 'oy' 'pt' 'qi' 'rd' 'ri' 'rl' 'ro' 'rt' 'ss' 'tb' 'tg' 'th' 'vy' 'wq' 'wz' 'xt' 'y6' 'y8' 'zf' 'zh' - f | '43' '9w' 'ah' 'av' 'bl' 'dr' 'ef' 'es' 'fm' 'ft' 'gy' 'hg' 'hq' 'hy' 'iu' 'ix' 'j1' 'jn' 'lg' 'np' 'o9' 'op' 'ou' 'ox' 'qq' 'st' 'sw' 't8' 't9' 'vs' 'vw' 'wd' 'wx' 'wz' 'xr' 'xt' 'xv' 'y5' 'y8' 'yi' 'ze' - f | '5f' '5i' 'ak' 'cg' 'dh' 'di' 'dk' 'eq' 'f6' 'g1' 'g8' 'ie' 'md' 'o0' 'oj' 'oq' 'pt' 'q7' 'qb' 'qd' 'qe' 'qo' 'ro' 'ru' 'rv' 'rx' 'sp' 'sr' 'tf' 'tp' 'uh' 'ul' 'vs' 'xn' 'xw' 'y2' 'yh' 'yk' 'zg' 'zm' 'zq' - f | 'ab' 'ac' 'b9' 'br' 'c8' 'eh' 'en' 'eq' 'ev' 'ew' 'f6' 'gd' 'ik' 'j5' 'jm' 'kc' 'ke' 'ok' 'p6' 'pa' 'qv' 'ri' 'rm' 'ro' 'rp' 'rq' 'rx' 'rz' 'se' 'tb' 'td' 'ti' 'tj' 'tn' 'ul' 'wj' 'wp' 'ws' 'yh' 'zb' 'zc' - f | 'ak' 'at' 'cs' 'di' 'dt' 'ef' 'eq' 'f1' 'f8' 'fb' 'fh' 'fv' 'g4' 'hs' 'j2' 'jo' 'kq' 'lf' 'lq' 'no' 'oa' 'ot' 'q0' 'qh' 'qs' 'qw' 'se' 'so' 'sx' 't3' 'ul' 'un' 'uu' 'wn' 'ws' 'wx' 'y0' 'y3' 'yf' 'zb' 'zc' - f | 'bq' 'cc' 'cg' 'dc' 'fu' 'ho' 'ja' 'jt' 'km' 'lk' 'ln' 'o2' 'ob' 'ou' 'pd' 'ph' 'pn' 'pt' 'pz' 'q5' 'qa' 'ql' 'qq' 'qv' 'rk' 'rm' 'ry' 'sq' 'su' 'sx' 'uc' 'un' 'uo' 'ur' 'uy' 'w9' 'wj' 'wl' 'wm' 'yk' 'ym' - f | 'ca' 'cm' 'cr' 'eh' 'fd' 'fp' 'g8' 'ga' 'gh' 'h1' 'iu' 'je' 'jy' 'kh' 'lx' 'o4' 'oi' 'ov' 'ph' 'pm' 'qi' 'qv' 're' 'rg' 'rv' 'ry' 'si' 'sl' 'sv' 'sx' 'tq' 'tz' 'uh' 'uq' 'uy' 'wi' 'wo' 'y7' 'yc' 'yn' 'yy' - f | '1u' '5k' 'ax' 'az' 'c4' 'eo' 'fi' 'gq' 'hg' 'ho' 'is' 'jq' 'ki' 'oq' 'ov' 'p4' 'pl' 'po' 'qe' 'qf' 'qn' 'qy' 'r3' 'rm' 'sd' 'se' 'sz' 'tb' 'td' 'u4' 'u5' 'vl' 'vv' 'wb' 'we' 'wh' 'wz' 'y5' 'ye' 'yv' 'zh' 'zj' - f | '4r' 'ae' 'd9' 'da' 'ef' 'em' 'en' 'gi' 'h8' 'jq' 'kf' 'kh' 'kr' 'kv' 'li' 'lq' 'lr' 'm2' 'ny' 'po' 'q0' 'q8' 'qf' 'qg' 'qu' 'qw' 'qx' 'rd' 'rh' 'ry' 'sm' 'st' 't3' 'tc' 'u5' 'un' 'uw' 'wg' 'wt' 'yt' 'z9' 'zc' - f | '4t' 'ay' 'b3' 'dz' 'eo' 'ep' 'fd' 'fh' 'ht' 'hw' 'i3' 'jl' 'kn' 'op' 'qb' 'qd' 'ql' 'qm' 'qp' 'qy' 'rc' 'rh' 'rs' 'rw' 'sm' 't9' 'td' 'tu' 'tw' 'tz' 'u1' 'ug' 'uh' 'ur' 'vt' 'we' 'wi' 'wn' 'x7' 'y8' 'yn' 'yy' - f | '5z' 'ai' 'al' 'ax' 'cd' 'dr' 'e1' 'ep' 'fi' 'gh' 'gk' 'ha' 'hc' 'ht' 'i5' 'ic' 'id' 'iq' 'iz' 'kk' 'kt' 'ld' 'mi' 'oh' 'ov' 'pn' 'q2' 'q7' 'qm' 'qy' 'ri' 'ru' 'rv' 'sq' 'u8' 'u9' 'un' 'wq' 'wt' 'yd' 'yk' 'ys' - f | 'ar' 'c3' 'c6' 'e0' 'e9' 'ed' 'ex' 'fh' 'fi' 'gu' 'ha' 'hr' 'id' 'jr' 'kk' 'kr' 'kz' 'm0' 'mp' 'ng' 'om' 'pa' 'qa' 'qf' 'rj' 'sp' 'to' 'tu' 'ty' 'ub' 'ud' 'ug' 'uk' 'vj' 'vp' 'wf' 'wl' 'wu' 'x6' 'xs' 'y0' 'ya' - f | 'bt' 'dg' 'dz' 'e4' 'ek' 'ep' 'fi' 'gk' 'gl' 'gu' 'hl' 'ho' 'io' 'ls' 'ni' 'nw' 'pv' 'px' 'qe' 'qf' 'qj' 'ql' 'qu' 'qy' 'rw' 'rx' 'ss' 't7' 'tt' 'ty' 'ud' 'up' 'uq' 'uw' 'wn' 'wy' 'xt' 'yv' 'yx' 'za' 'zv' 'zw' - f | '2o' '6t' 'a7' 'bv' 'di' 'dm' 'ea' 'eo' 'fd' 'fj' 'ft' 'fw' 'gs' 'hu' 'hz' 'ik' 'it' 'jc' 'js' 'jx' 'jz' 'k4' 'lp' 'lx' 'ol' 'p3' 'pf' 'q9' 'qu' 'qv' 'qx' 're' 'rl' 'ro' 'sb' 'ur' 'vf' 'wd' 'wk' 'wo' 'wx' 'yp' 'zo' - f | '5y' 'av' 'ax' 'cl' 'cw' 'dh' 'di' 'g7' 'ga' 'gi' 'gx' 'gy' 'i0' 'iu' 'iv' 'jk' 'jv' 'k3' 'l2' 'lo' 'lq' 'mj' 'oj' 'pd' 'pn' 'pv' 'q6' 'qq' 'qv' 'sc' 'tt' 'tv' 'ug' 'ut' 've' 'vy' 'wi' 'xg' 'xo' 'yi' 'yl' 'yv' 'zm' - f | 'ab' 'av' 'c9' 'cs' 'cx' 'dy' 'e4' 'eb' 'ej' 'er' 'ez' 'f0' 'f2' 'ft' 'gk' 'h5' 'i5' 'ic' 'ig' 'io' 'ki' 'kz' 'lj' 'mm' 'of' 'og' 'ov' 'oz' 'p4' 'pl' 'qh' 'qx' 'rw' 's1' 'sf' 'tw' 'uc' 'ui' 'uo' 'uw' 'x4' 'xk' 'ze' - f | 'ac' 'bv' 'd2' 'de' 'e8' 'ea' 'go' 'gw' 'h4' 'ht' 'iy' 'jm' 'ot' 'pp' 'pw' 'pz' 'qd' 'qn' 'qu' 'qy' 'r1' 'ra' 'rg' 'rh' 'rp' 's0' 'sb' 'sn' 'st' 'td' 'uz' 'vg' 'w1' 'w6' 'wa' 'wc' 'we' 'wi' 'wj' 'wu' 'ww' 'y9' 'zr' - f | 'ak' 'bg' 'bj' 'bn' 'co' 'e6' 'e7' 'ec' 'ek' 'el' 'ew' 'ez' 'fo' 'im' 'jm' 'js' 'lc' 'lh' 'ob' 'oi' 'os' 'ot' 'ou' 'p0' 'pu' 'q0' 'qh' 'ra' 'rc' 'rm' 'rr' 'sd' 'sq' 'tc' 'tl' 'wj' 'wy' 'x2' 'xw' 'y6' 'yp' 'yv' 'zj' - f | 'ao' 'ei' 'ep' 'fc' 'fm' 'gr' 'ha' 'he' 'i5' 'ia' 'if' 'kh' 'lv' 'ml' 'ms' 'n9' 'nh' 'nl' 'oe' 'of' 'ow' 'pb' 'pu' 'pw' 'q0' 'qr' 'qt' 'qu' 'qv' 'qw' 'ra' 'sv' 'ti' 'u0' 'u4' 'ug' 'uq' 'vx' 'w1' 'wy' 'x1' 'xh' 'xz' - f | 'cr' 'd3' 'e5' 'ei' 'fb' 'gd' 'gx' 'hm' 'it' 'jp' 'ku' 'lf' 'lh' 'lp' 'ma' 'md' 'nt' 'o9' 'ot' 'pk' 'pm' 'ps' 'qc' 'qi' 'qp' 'qt' 'ra' 'rk' 'rq' 'rt' 'tb' 'tc' 'tg' 'to' 'u8' 'vg' 'vj' 'vt' 'w0' 'wr' 'wx' 'yd' 'zx' - f | '3p' '5x' 'ag' 'au' 'aw' 'dl' 'eg' 'f2' 'f8' 'fb' 'fn' 'g9' 'ge' 'gt' 'hd' 'i7' 'ia' 'ij' 'is' 'jc' 'ku' 'kx' 'l7' 'lb' 'lq' 'mc' 'o3' 'oj' 'q1' 'qa' 'qg' 'qt' 'r9' 'rg' 'tw' 'tz' 'u6' 'us' 'w2' 'wr' 'wt' 'wu' 'x3' 'xx' - f | 'aa' 'al' 'ay' 'c1' 'ca' 'de' 'ea' 'ee' 'eq' 'er' 'ez' 'fc' 'gy' 'i1' 'jb' 'jn' 'jz' 'lp' 'o5' 'om' 'os' 'ou' 'ox' 'px' 'q3' 'qc' 'qs' 'rm' 'rq' 'rt' 'rx' 'ry' 'rz' 'ss' 'ta' 'tg' 'ti' 'tr' 'u6' 'uv' 'vp' 'wn' 'wu' 'zt' - f | 'ak' 'bg' 'bk' 'du' 'eb' 'ef' 'el' 'ft' 'gb' 'gc' 'hc' 'ho' 'i6' 'iv' 'ji' 'ke' 'mo' 'oc' 'oh' 'pe' 'pj' 'q6' 'qe' 'qg' 'qs' 'qv' 'r1' 'rr' 'rx' 'tc' 'te' 'tf' 'tk' 'tq' 'ua' 'uq' 'ur' 'wq' 'wx' 'wz' 'xi' 'xq' 'yk' 'yo' - f | 'al' 'ar' 'cl' 'dl' 'dz' 'ej' 'fj' 'gu' 'i2' 'i6' 'ih' 'jx' 'k9' 'ln' 'ls' 'mf' 'mx' 'oi' 'om' 'pn' 'q4' 'qd' 'qe' 'qg' 'qk' 'qp' 'qr' 'qw' 'qx' 'rr' 'sd' 'sf' 'ub' 'uh' 'um' 'uu' 'vg' 'w6' 'wj' 'wp' 'ws' 'yn' 'zc' 'zm' - f | 'am' 'aw' 'ay' 'bj' 'df' 'eb' 'eo' 'eq' 'et' 'ey' 'f9' 'fo' 'g0' 'gg' 'h4' 'hq' 'in' 'k4' 'k7' 'kb' 'kl' 'my' 'nt' 'o3' 'og' 'pc' 'q4' 'qg' 'qi' 'qm' 'qy' 'ri' 'rv' 's9' 'sv' 'tl' 'ue' 'uo' 'v6' 'wb' 'wt' 'wx' 'xi' 'xu' - f | 'bs' 'cd' 'ci' 'cq' 'dd' 'el' 'ev' 'f4' 'f6' 'f7' 'fh' 'fu' 'hi' 'ib' 'kp' 'nn' 'nu' 'oc' 'os' 'qc' 'qj' 'qm' 'qn' 'qu' 'qw' 'qx' 'r7' 'rc' 'rv' 't1' 'tl' 'tr' 'u0' 'vi' 'wl' 'wp' 'wu' 'xc' 'y2' 'yu' 'zc' 'zi' 'zw' 'zy' - f | 'bt' 'c9' 'db' 'dy' 'ee' 'ej' 'eo' 'et' 'fr' 'gm' 'hz' 'ic' 'ik' 'is' 'jk' 'ls' 'lt' 'oj' 'or' 'ox' 'p8' 'pl' 'pz' 'q1' 'qq' 'qt' 'rw' 's7' 't4' 't8' 'to' 'tp' 'u7' 'ub' 'vx' 'w4' 'ws' 'wt' 'wv' 'x8' 'xs' 'xt' 'yg' 'yo' - f | 'cm' 'd2' 'en' 'ex' 'f4' 'f9' 'fp' 'ga' 'gk' 'hy' 'i3' 'j4' 'j9' 'jb' 'kj' 'ls' 'lw' 'mb' 'mq' 'o9' 'qg' 'qi' 'qm' 'qo' 'qw' 'qy' 'rc' 'rf' 'rj' 'rm' 's8' 'tb' 'tl' 'tp' 'um' 'vg' 'vn' 'wb' 'wf' 'wl' 'xw' 'yl' 'zf' 'zt' - f | '28' 'b1' 'bj' 'bm' 'cz' 'dd' 'ds' 'ed' 'em' 'hh' 'hr' 'ie' 'ii' 'im' 'io' 'jn' 'jw' 'lg' 'lo' 'm6' 'mn' 'mw' 'ny' 'o6' 'p7' 'q4' 'qd' 'qf' 'qn' 'qq' 'qt' 'r1' 'r2' 'rn' 'rt' 'sh' 'ur' 'uv' 'ux' 'vc' 'wb' 'wn' 'xh' 'xx' 'yw' - f | '2e' 'al' 'am' 'bt' 'eo' 'ff' 'fl' 'ge' 'gz' 'h0' 'hb' 'i0' 'j2' 'lh' 'lm' 'ls' 'mg' 'mw' 'on' 'ox' 'pa' 'pb' 'pg' 'q3' 'q6' 'qe' 'ra' 're' 'rm' 'rr' 'rt' 'ry' 'sc' 'sm' 't9' 'tu' 'tx' 'ul' 'ux' 'vh' 'wn' 'wt' 'wv' 'ys' 'yw' - f | '3d' 'at' 'aw' 'bt' 'by' 'cg' 'dk' 'do' 'ec' 'eu' 'gv' 'is' 'k9' 'kb' 'kc' 'me' 'mm' 'o5' 'oe' 'pr' 'qa' 'qn' 'rc' 'rl' 'rn' 'rw' 'sc' 'sk' 'st' 't1' 't7' 'td' 'to' 'ue' 'up' 'ur' 'uy' 've' 'wi' 'xf' 'xu' 'yf' 'z9' 'zo' 'zr' - f | '40' '6a' '8j' 'am' 'bf' 'dp' 'dz' 'ew' 'gh' 'he' 'hh' 'ib' 'ii' 'iq' 'is' 'iu' 'kt' 'mf' 'oh' 'or' 'p8' 'pa' 'pb' 'pi' 'qc' 'qo' 'qp' 'qq' 'qs' 'qt' 'qu' 'r4' 'rf' 'rl' 'sd' 'sl' 't4' 'tb' 'ua' 'ue' 'ut' 'wh' 'wm' 'y0' 'y6' - f | 'a0' 'a6' 'aa' 'bk' 'dk' 'dv' 'e8' 'ff' 'fo' 'go' 'hh' 'hl' 'hu' 'if' 'jx' 'kc' 'kq' 'lr' 'lx' 'n6' 'ni' 'ob' 'ol' 'ql' 'rf' 'ry' 'sm' 'sn' 't7' 'tu' 'tz' 'uc' 'um' 'uv' 'wf' 'wr' 'ws' 'wu' 'ww' 'xi' 'ym' 'z7' 'zo' 'zv' 'zz' - f | 'as' 'dj' 'dq' 'e3' 'ej' 'es' 'fn' 'fp' 'fu' 'ga' 'hb' 'hy' 'jz' 'l6' 'mp' 'ps' 'q4' 'qd' 'qm' 'qw' 'qy' 'qz' 'sa' 'sv' 'td' 'tn' 'tu' 'tx' 'ud' 'ue' 'uq' 'uv' 'v0' 'wi' 'wk' 'wm' 'wx' 'xh' 'y3' 'yd' 'yi' 'yn' 'yx' 'yy' 'zc' - f | 'cx' 'dg' 'do' 'dt' 'e7' 'ek' 'ez' 'fn' 'hj' 'hv' 'i2' 'i6' 'is' 'it' 'ka' 'kh' 'l5' 'lg' 'p5' 'qa' 'qf' 'qj' 'qw' 'qz' 'rl' 'sl' 'sr' 't7' 'tf' 'tu' 'uc' 'ud' 'uv' 'vr' 'w0' 'we' 'wf' 'wj' 'ws' 'ww' 'xe' 'xh' 'xn' 'y9' 'yv' - f | '2a' '4s' 'c4' 'cd' 'dh' 'dv' 'eh' 'ek' 'ew' 'ex' 'ez' 'fm' 'hh' 'hj' 'ig' 'jf' 'ld' 'ly' 'mg' 'mx' 'o5' 'or' 'pa' 'pv' 'q1' 'qe' 'qj' 'qq' 'qr' 'qw' 'rb' 'rr' 's4' 's9' 'tm' 'uj' 'wc' 'wv' 'x0' 'xt' 'yc' 'ye' 'yh' 'yi' 'yk' 'yy' - f | 'a2' 'a9' 'ac' 'bw' 'cu' 'dm' 'e8' 'ee' 'ej' 'ep' 'f7' 'fh' 'ga' 'go' 'im' 'it' 'jv' 'kg' 'lb' 'ml' 'oi' 'p5' 'p9' 'pe' 'pf' 'pp' 'qk' 'rg' 'rh' 'sn' 'sv' 't5' 'tj' 'tk' 'tq' 'ty' 'v6' 'vk' 'w2' 'w5' 'wh' 'wy' 'y7' 'yf' 'zq' 'zt' - f | 'aa' 'am' 'av' 'dt' 'du' 'eh' 'em' 'ev' 'ex' 'gu' 'h0' 'i4' 'i8' 'ku' 'la' 'lo' 'lw' 'n0' 'n9' 'on' 'pc' 'pl' 'pn' 'pr' 'q8' 'qc' 'ql' 'qn' 'qz' 'ra' 'rd' 'ry' 'sp' 'tn' 'ts' 'u4' 'vg' 'vs' 'w7' 'wj' 'wm' 'xl' 'yg' 'yh' 'z0' 'zs' - f | 'ak' 'ar' 'cm' 'cq' 'da' 'df' 'e3' 'ew' 'fe' 'fr' 'gm' 'id' 'io' 'iy' 'jg' 'jt' 'jx' 'kb' 'lf' 'nv' 'od' 'qy' 'r3' 'r4' 'ro' 'rq' 'rw' 'sl' 'ss' 'su' 'sw' 't7' 'th' 'ti' 'tp' 'u9' 'uq' 'v9' 'vq' 'vw' 'we' 'wg' 'wk' 'ws' 'xr' 'yf' - f | 'bv' 'cv' 'dy' 'ec' 'ef' 'eg' 'eh' 'eu' 'ew' 'fc' 'fn' 'fs' 'g9' 'hj' 'hk' 'i3' 'iu' 'ja' 'k6' 'l1' 'la' 'nl' 'oh' 'oi' 'oy' 'pc' 'qe' 'ql' 'qq' 'qs' 'qu' 're' 'sf' 'sq' 'tb' 'up' 'w1' 'w2' 'wg' 'wi' 'xd' 'xt' 'xv' 'yf' 'zn' 'zz' - f | '3y' 'ak' 'am' 'b8' 'cp' 'd7' 'df' 'di' 'eg' 'em' 'en' 'eo' 'es' 'f6' 'fc' 'gg' 'gt' 'gv' 'hd' 'i3' 'jk' 'k6' 'la' 'lc' 'ol' 'ov' 'ow' 'p5' 'pl' 'qc' 'qf' 'rl' 'rn' 'rt' 'rx' 't1' 'tf' 'tj' 'tz' 'ug' 'uo' 'we' 'wg' 'wk' 'wp' 'wv' 'y7' - f | '5g' 'a5' 'dj' 'dl' 'dr' 'e9' 'ed' 'ep' 'er' 'gb' 'hh' 'hl' 'i0' 'if' 'ig' 'io' 'it' 'k2' 'ki' 'll' 'o9' 'om' 'ot' 'p5' 'q1' 'q6' 'qa' 'qp' 'qw' 'qy' 'r9' 'rb' 'rm' 'ry' 's7' 'tl' 'ts' 'ut' 'w0' 'wd' 'wu' 'wv' 'xk' 'ya' 'z5' 'zq' 'zs' - f | '5l' 'a2' 'ak' 'au' 'cj' 'cx' 'ed' 'eg' 'ej' 'em' 'es' 'ex' 'fs' 'ft' 'hm' 'i9' 'ky' 'l3' 'lz' 'mi' 'o2' 'oc' 'oe' 'ok' 'p2' 'q1' 'q5' 'qo' 'qv' 'qw' 'rf' 'rm' 'rv' 'sc' 'si' 'tx' 'uq' 'v3' 'v4' 'vo' 'w4' 'wf' 'wl' 'wq' 'wt' 'xj' 'yr' - f | 'al' 'ar' 'av' 'bg' 'bh' 'bz' 'e9' 'ed' 'ee' 'ef' 'eh' 'es' 'fl' 'fz' 'gl' 'h1' 'he' 'hf' 'hv' 'hw' 'i1' 'jg' 'kj' 'kn' 'kz' 'lr' 'pp' 'q1' 'qa' 'qf' 'qt' 'qz' 'rg' 'rj' 's5' 'sv' 'sx' 't4' 'th' 'tn' 'ur' 'wz' 'xp' 'yg' 'ym' 'yr' 'ze' - f | 'az' 'cx' 'dm' 'do' 'dq' 'e2' 'e5' 'e8' 'eb' 'fh' 'fj' 'fq' 'gj' 'gl' 'hq' 'im' 'iq' 'iz' 'jn' 'ku' 'l1' 'mz' 'nt' 'o6' 'q1' 'qn' 'qo' 'qz' 'r4' 'rh' 'rn' 'rw' 'sn' 'sv' 't7' 'ud' 'ue' 'ur' 'uv' 'w9' 'wh' 'wk' 'wy' 'xq' 'yh' 'zs' 'zw' - f | '18' 'bf' 'bj' 'cs' 'dw' 'el' 'ep' 'ez' 'fr' 'g1' 'gv' 'hu' 'hz' 'ii' 'jc' 'je' 'jj' 'jo' 'jv' 'n5' 'ni' 'ns' 'oh' 'oi' 'ov' 'pe' 'q8' 'qg' 'qi' 'qr' 'r6' 'rh' 's3' 'sj' 'sr' 't0' 'ta' 'u2' 'uj' 'ur' 'vu' 'wb' 'wh' 'wx' 'yn' 'yq' 'zg' 'zr' - f | '2s' 'a5' 'aw' 'b5' 'b7' 'ce' 'cq' 'dc' 'dp' 'eb' 'eq' 'ez' 'ff' 'gg' 'gy' 'iw' 'jd' 'jl' 'kw' 'ky' 'mt' 'ng' 'o9' 'od' 'oe' 'po' 'pp' 'qa' 'qe' 'qk' 'ql' 'qp' 'r4' 'r9' 'rb' 'si' 'sl' 'sn' 'sq' 'tg' 'ti' 'tx' 'uh' 'ws' 'xf' 'yv' 'z1' 'zm' - f | '4j' 'bi' 'bk' 'c0' 'c5' 'dh' 'dy' 'e8' 'fw' 'g3' 'g8' 'h6' 'hd' 'hn' 'jl' 'kc' 'kj' 'km' 'll' 'lo' 'nh' 'nj' 'nt' 'ob' 'on' 'oq' 'or' 'ox' 'ph' 'qc' 'qj' 'ql' 'qm' 'qo' 'qu' 'qz' 'sr' 't7' 'tc' 'ug' 'uq' 'wn' 'wr' 'ws' 'yv' 'z3' 'zj' 'zz' - f | '6w' 'af' 'ak' 'b7' 'bf' 'bi' 'bv' 'cx' 'dy' 'es' 'ey' 'ez' 'f0' 'fe' 'fw' 'ge' 'gt' 'iw' 'j9' 'jh' 'kh' 'l0' 'l1' 'l8' 'm5' 'nv' 'o6' 'pw' 'qi' 'r0' 'se' 'ta' 'tf' 'th' 'to' 'u8' 'ux' 'vm' 'w4' 'w6' 'wa' 'wt' 'wu' 'xo' 'xu' 'yo' 'z0' 'zc' - f | 'au' 'bl' 'c4' 'd7' 'dc' 'dm' 'ea' 'eo' 'ft' 'gb' 'h3' 'ia' 'ix' 'jr' 'kc' 'ke' 'lq' 'lr' 'mn' 'op' 'pj' 'qc' 'qj' 'qn' 'qq' 'qx' 'r8' 'rb' 'ri' 'rm' 'rn' 'rx' 't6' 'tf' 'tv' 'um' 'vg' 'vi' 'we' 'wp' 'wz' 'x6' 'xb' 'xd' 'xg' 'xv' 'yx' 'yz' - f | '7r' 'a8' 'aa' 'ag' 'bo' 'bp' 'c7' 'd0' 'd6' 'e5' 'er' 'fc' 'ff' 'go' 'ha' 'hs' 'jj' 'jq' 'ki' 'lc' 'le' 'no' 'pf' 'qc' 'qh' 'qq' 'qs' 'qv' 'rf' 'rj' 'rx' 'su' 'ta' 'ti' 'tu' 'tv' 'ty' 'ug' 'un' 'up' 'vb' 'vi' 'wp' 'wu' 'wz' 'xt' 'y0' 'yd' 'yu' - f | 'at' 'b7' 'be' 'c3' 'cc' 'cd' 'cj' 'e8' 'eb' 'ei' 'fd' 'g8' 'gh' 'go' 'gv' 'if' 'ih' 'j7' 'jy' 'kj' 'lh' 'mc' 'oe' 'og' 'oy' 'oz' 'pm' 'qd' 'qe' 'qo' 'rg' 'rq' 'rx' 'se' 'su' 't3' 't6' 't9' 'u5' 'us' 'vw' 'w4' 'wb' 'wg' 'ws' 'xw' 'yu' 'yx' 'zj' - f | '18' 'a6' 'af' 'ax' 'du' 'dy' 'e7' 'ei' 'ej' 'es' 'eu' 'fj' 'gt' 'hn' 'hu' 'ky' 'le' 'lo' 'm8' 'nb' 'of' 'oj' 'ok' 'op' 'oz' 'pw' 'q7' 'qi' 'qu' 'r4' 'rp' 's7' 'sk' 'tb' 'tf' 'tp' 'ua' 'um' 'up' 'ur' 'uz' 'w4' 'wc' 'wn' 'wv' 'wx' 'wy' 'yc' 'yq' 'yx' - f | '82' 'a2' 'ad' 'dp' 'el' 'ep' 'fk' 'gd' 'hj' 'ij' 'lc' 'lm' 'lv' 'ml' 'n2' 'n6' 'o1' 'oi' 'on' 'oo' 'ow' 'pb' 'pe' 'pq' 'q6' 'qi' 'qo' 'qp' 'qw' 'rs' 'rv' 's6' 'sa' 'sk' 't8' 'tl' 'tt' 'tx' 'ub' 'ue' 'uf' 'uj' 'va' 'wl' 'xv' 'y1' 'ye' 'ym' 'yw' 'zm' - f | 'a3' 'b9' 'c0' 'cg' 'ct' 'cu' 'dy' 'eh' 'el' 'ge' 'gt' 'hh' 'hu' 'if' 'j5' 'kq' 'lb' 'mh' 'o3' 'o6' 'oe' 'oi' 'ow' 'p5' 'ph' 'pw' 'q0' 'qh' 'ql' 'qy' 'r7' 'si' 'sk' 'sv' 'tf' 'tm' 'to' 'tt' 'ty' 'u3' 'uj' 'uo' 'vi' 'vl' 'wc' 'wf' 'xx' 'y0' 'ya' 'yu' - f | 'ad' 'am' 'av' 'ax' 'dl' 'dt' 'dw' 'ej' 'ez' 'f6' 'fe' 'g5' 'ga' 'gv' 'hr' 'hx' 'id' 'ie' 'ii' 'im' 'ix' 'jd' 'kn' 'ml' 'nu' 'ol' 'oo' 'pu' 'qd' 'qm' 'qt' 'r5' 'rb' 'rd' 'rg' 'ru' 'sg' 'ub' 'uk' 'vm' 'wl' 'wr' 'wz' 'x4' 'yf' 'yu' 'yv' 'yw' 'yx' 'zt' - f | 'bw' 'ci' 'cp' 'cu' 'cw' 'd7' 'e0' 'e3' 'em' 'ev' 'fi' 'fk' 'fm' 'fu' 'ht' 'ix' 'jn' 'kc' 'kw' 'lm' 'mo' 'n8' 'od' 'oo' 'q1' 'qd' 'qw' 'rs' 'sd' 'su' 'sz' 'th' 'ti' 'ts' 'tw' 'ty' 'u3' 'ua' 'wa' 'wt' 'wy' 'xg' 'xh' 'xp' 'xr' 'yd' 'yj' 'yq' 'yx' 'zu' - f | '1d' 'a4' 'ai' 'av' 'b9' 'be' 'c9' 'cc' 'cy' 'de' 'ee' 'g8' 'gg' 'gl' 'gs' 'gu' 'hb' 'kl' 'kr' 'ky' 'mi' 'mz' 'nd' 'og' 'op' 'pr' 'q0' 'q5' 'qk' 'qy' 'r4' 'sk' 'sz' 't1' 't8' 'td' 'tn' 'tx' 'ty' 'tz' 'uc' 'up' 'vq' 'wa' 'ws' 'wv' 'x3' 'yn' 'yq' 'yy' 'zm' - f | '1u' 'ad' 'al' 'c4' 'cz' 'db' 'dk' 'dr' 'e5' 'e7' 'ea' 'f6' 'fk' 'fw' 'g3' 'gl' 'gt' 'gu' 'ha' 'hk' 'hv' 'ie' 'ka' 'kq' 'ks' 'lr' 'nf' 'pk' 'q3' 'q8' 'qf' 'qj' 'qo' 'rp' 'rr' 'rz' 'ss' 'sv' 'sx' 'tb' 'th' 'tt' 'ur' 'vp' 'wj' 'ws' 'wt' 'xk' 'xo' 'ym' 'yz' - f | '3f' '93' 'am' 'an' 'at' 'bj' 'bm' 'bw' 'c6' 'eb' 'ef' 'em' 'eq' 'es' 'g9' 'hc' 'hl' 'hm' 'kg' 'kt' 'mg' 'nq' 'op' 'ox' 'pc' 'py' 'qd' 'qn' 'qz' 'rb' 'rw' 's6' 'se' 'sr' 'sy' 'ts' 'u4' 'ud' 'un' 'w3' 'w8' 'wb' 'wf' 'wg' 'wy' 'x1' 'xl' 'xy' 'yk' 'yo' 'zp' - f | 'a6' 'ad' 'aj' 'b1' 'bz' 'cd' 'df' 'ed' 'eg' 'eh' 'ev' 'fi' 'fo' 'gj' 'h3' 'he' 'ib' 'j0' 'jc' 'jz' 'kz' 'lc' 'mh' 'pk' 'pu' 'q4' 'qc' 'qk' 'qr' 'qw' 'rc' 'rl' 'ro' 'rr' 'so' 'sw' 'td' 'tw' 'tx' 'ue' 'us' 'ut' 'vd' 'wi' 'wu' 'xm' 'y2' 'y8' 'ym' 'z6' 'zm' - f | '2e' '3y' 'ap' 'as' 'bl' 'di' 'dl' 'e9' 'eh' 'er' 'ff' 'fg' 'fh' 'gc' 'gg' 'hp' 'hq' 'i3' 'ih' 'jm' 'kw' 'lc' 'li' 'ls' 'nm' 'ok' 'pc' 'pn' 'q1' 'qf' 'qi' 'qk' 'r0' 'rl' 'sp' 'sy' 'sz' 'ta' 'to' 'ts' 'tv' 'uh' 'uk' 'vb' 'wa' 'wg' 'wi' 'wp' 'yl' 'yq' 'yw' 'yy' - f | '2h' '9y' 'ac' 'at' 'cf' 'e3' 'e6' 'ec' 'ek' 'en' 'f1' 'fa' 'fn' 'gm' 'gx' 'hk' 'i7' 'id' 'iw' 'ke' 'kl' 'ks' 'l6' 'l8' 'ls' 'lx' 'me' 'o4' 'oi' 'oj' 'ox' 'pn' 'qa' 'qh' 'qk' 'ql' 'rp' 'tb' 'te' 'tn' 'ts' 'u4' 'u9' 'ud' 'vj' 'vz' 'wc' 'wr' 'ye' 'yk' 'yq' 'zq' - f | '4j' 'af' 'ap' 'bn' 'ch' 'dc' 'df' 'e0' 'ef' 'eg' 'er' 'g3' 'hh' 'hi' 'hw' 'i1' 'if' 'ii' 'in' 'iy' 'l1' 'mx' 'og' 'px' 'q3' 'qc' 'qg' 'qt' 'qy' 'r3' 'r6' 'rd' 'rj' 'rz' 'sm' 't2' 't4' 'td' 'tj' 'tm' 'tx' 'ty' 'u9' 'uo' 'up' 'v8' 'wv' 'ye' 'zb' 'zc' 'zi' 'zy' - f | 'a0' 'ai' 'bx' 'ca' 'e2' 'eb' 'ed' 'eg' 'eh' 'eo' 'et' 'hn' 'ix' 'jh' 'ki' 'lm' 'lw' 'm8' 'mb' 'mh' 'mk' 'nc' 'o3' 'o9' 'of' 'qc' 'qe' 'qf' 'qh' 'qi' 'qq' 'qr' 'qz' 'r2' 'r3' 'rc' 'rh' 'rs' 'rv' 'sr' 'uk' 'up' 'ur' 'uv' 'wm' 'wr' 'wz' 'xd' 'y3' 'ya' 'yv' 'zr' - f | 'ab' 'ae' 'al' 'am' 'an' 'ap' 'be' 'd2' 'eb' 'ec' 'ep' 'eq' 'fn' 'hp' 'hx' 'i9' 'ie' 'jn' 'kh' 'kv' 'mi' 'mq' 'mv' 'ox' 'oz' 'pn' 'qk' 'qo' 'qr' 'r8' 're' 'rf' 'rp' 't8' 'uj' 'uk' 'up' 'ur' 'vo' 'w7' 'wf' 'wp' 'ws' 'wt' 'ww' 'wx' 'xw' 'yd' 'yj' 'yn' 'yv' 'zr' - f | 'ax' 'ch' 'de' 'dl' 'e1' 'el' 'fl' 'fo' 'fp' 'fx' 'gb' 'gj' 'gx' 'hg' 'ho' 'hs' 'ip' 'jr' 'kg' 'l6' 'li' 'ln' 'mg' 'mm' 'mo' 'o2' 'os' 'pm' 'q2' 'q6' 'qr' 're' 'ro' 'rr' 'rt' 'rw' 'rx' 'sk' 'tl' 'to' 'tr' 'tt' 'u3' 'u6' 'vo' 'w4' 'w5' 'wb' 'wo' 'wt' 'yi' 'zh' - f | 'bl' 'bn' 'cy' 'ea' 'ed' 'ef' 'ei' 'em' 'er' 'es' 'fp' 'gb' 'hi' 'hp' 'if' 'io' 'ir' 'kw' 'lg' 'lo' 'ls' 'n8' 'nj' 'np' 'oa' 'of' 'oi' 'p6' 'pw' 'q3' 'q4' 'q8' 'qf' 'qh' 'qo' 'qw' 'rg' 'rt' 'sy' 't3' 'u8' 'ug' 'uo' 'uv' 'w6' 'we' 'wg' 'wl' 'wy' 'x9' 'yy' 'yz' - f | '16' '64' 'aj' 'aw' 'bf' 'c0' 'ca' 'd2' 'd6' 'ec' 'ed' 'eq' 'ew' 'go' 'h2' 'in' 'is' 'j0' 'jd' 'ji' 'kv' 'l5' 'lp' 'lz' 'og' 'pb' 'pw' 'q9' 'qb' 'qe' 'qf' 'qg' 'qn' 'qp' 'qt' 'qy' 'r7' 'rh' 'rw' 'sz' 't8' 'tb' 'te' 'tx' 'ui' 'un' 'uq' 'wa' 'wp' 'wu' 'wy' 'yn' 'ys' - f | '1m' '1s' 'aa' 'b0' 'be' 'cb' 'dc' 'dd' 'dh' 'eq' 'fa' 'ib' 'if' 'ik' 'it' 'jr' 'jz' 'ka' 'lq' 'lu' 'm2' 'o2' 'ob' 'oc' 'of' 'om' 'oz' 'pv' 'q4' 'qb' 'qk' 'qn' 'qs' 'qu' 'r3' 'r9' 'rs' 'rw' 'sg' 'si' 'sv' 't9' 'tw' 'vq' 'vy' 'w2' 'w6' 'w9' 'y0' 'y1' 'ye' 'yq' 'z1' - f | '1o' 'a0' 'aa' 'bd' 'bj' 'ch' 'cm' 'dj' 'e2' 'eq' 'eu' 'fj' 'fo' 'g9' 'go' 'hi' 'ia' 'ix' 'jh' 'jl' 'jy' 'lh' 'nd' 'nw' 'ox' 'p3' 'pi' 'pm' 'pt' 'q3' 'qh' 'qn' 'ra' 'ri' 'rr' 'ru' 'rv' 't3' 'tm' 'u3' 'ue' 'us' 'uz' 'vn' 'w1' 'wl' 'wo' 'wx' 'xj' 'xn' 'yc' 'yp' 'zr' - f | '3b' 'am' 'aq' 'ar' 'bm' 'de' 'e7' 'ed' 'eh' 'es' 'ey' 'fx' 'g5' 'gf' 'gs' 'hl' 'i7' 'iy' 'jn' 'k9' 'kf' 'km' 'll' 'ly' 'm0' 'm5' 'mh' 'nm' 'nq' 'of' 'or' 'p5' 'pn' 'pz' 'qp' 'qt' 'qv' 'r0' 'rb' 'sg' 'sv' 'uv' 'w3' 'w8' 'w9' 'wa' 'we' 'wj' 'wn' 'wr' 'yd' 'yk' 'zq' - f | '4t' 'a3' 'ac' 'au' 'bp' 'br' 'e5' 'ei' 'ek' 'ez' 'fz' 'g5' 'gn' 'ik' 'k9' 'kb' 'kc' 'lm' 'ls' 'ly' 'mj' 'mx' 'nk' 'nr' 'ny' 'o2' 'o8' 'pb' 'pu' 'q2' 'qa' 'qc' 'qh' 'qi' 'qs' 'qx' 'qz' 'rv' 'rx' 'tc' 'tk' 'tv' 'u8' 'ui' 'uz' 'vo' 'w2' 'wm' 'wp' 'xt' 'yf' 'yv' 'zl' - f | 'aa' 'ab' 'ag' 'ar' 'az' 'bp' 'bx' 'cx' 'eb' 'eh' 'ek' 'eo' 'eq' 'ez' 'fl' 'gm' 'gw' 'hd' 'ib' 'ig' 'jz' 'kg' 'lf' 'nw' 'oh' 'ok' 'om' 'oy' 'pg' 'ph' 'pi' 'qb' 'qi' 'qn' 'qs' 'qt' 'qy' 'rl' 'sy' 'tc' 'tt' 'up' 'ur' 'uy' 'w6' 'w8' 'wb' 'wh' 'wv' 'ww' 'y5' 'yi' 'yp' - f | 'aa' 'af' 'ah' 'am' 'as' 'cd' 'ch' 'dd' 'dg' 'dr' 'e2' 'eb' 'eq' 'er' 'fb' 'fj' 'fk' 'fn' 'fx' 'gk' 'gs' 'h8' 'hg' 'hj' 'ia' 'ij' 'in' 'jw' 'l9' 'lj' 'lw' 'nk' 'nt' 'o1' 'ob' 'oo' 'p5' 'pd' 'pk' 'qq' 'sb' 'sd' 'sg' 'u4' 'wl' 'wq' 'wr' 'wu' 'xc' 'xj' 'xt' 'yq' 'zl' - f | 'ad' 'ao' 'au' 'az' 'ci' 'dj' 'dv' 'e1' 'ei' 'ej' 'em' 'eq' 'fa' 'fi' 'fj' 'fn' 'fw' 'he' 'i8' 'in' 'io' 'jd' 'jt' 'jv' 'lr' 'mt' 'mx' 'ns' 'nt' 'oc' 'oe' 'oi' 'pz' 'qe' 'ql' 'qt' 'qy' 'rq' 'sc' 'sp' 'te' 'um' 'wo' 'wv' 'x6' 'xu' 'yf' 'yi' 'yo' 'yv' 'yw' 'yz' 'zg' - f | 'ag' 'ay' 'b6' 'bk' 'c6' 'cp' 'da' 'ea' 'eh' 'es' 'f1' 'fj' 'fv' 'gb' 'gn' 'ic' 'id' 'in' 'iq' 'iw' 'kx' 'ly' 'n7' 'o5' 'oc' 'og' 'op' 'os' 'pa' 'pr' 'q4' 'q6' 'qf' 'qg' 'qh' 'qp' 'qq' 'qu' 'qw' 'qy' 'qz' 'rj' 'rm' 'ro' 's1' 'w2' 'we' 'wl' 'wn' 'wp' 'yj' 'yp' 'yx' - f | 'ah' 'bg' 'bw' 'ca' 'cn' 'cy' 'da' 'dq' 'dt' 'eq' 'ex' 'fe' 'ff' 'ga' 'gr' 'kv' 'ld' 'my' 'od' 'oq' 'p3' 'p5' 'pc' 'pf' 'q5' 'qa' 'qc' 'qi' 'ql' 'qr' 'qx' 'qz' 'rd' 'rk' 'rq' 'ru' 'rw' 's7' 'sa' 'sh' 'tk' 'um' 'un' 'v4' 'vw' 'wg' 'wr' 'wt' 'xt' 'ya' 'yo' 'z6' 'zm' - f | '2r' '7g' 'a1' 'ar' 'av' 'b8' 'dj' 'dr' 'e7' 'ee' 'fd' 'fn' 'fp' 'gf' 'gp' 'gq' 'gw' 'jm' 'jv' 'ke' 'ki' 'kl' 'l9' 'lc' 'lg' 'lh' 'nm' 'oc' 'oq' 'px' 'q6' 'qe' 'qh' 'qu' 'rs' 's8' 't0' 'tt' 'tw' 'u2' 'uu' 'uy' 'vr' 'vs' 'wg' 'wt' 'ww' 'x3' 'x5' 'xu' 'yw' 'zh' 'zp' 'zt' - f | '4u' 'a2' 'aq' 'as' 'b8' 'bu' 'cc' 'cp' 'cv' 'dg' 'e3' 'e9' 'eh' 'fg' 'fh' 'g9' 'gf' 'gk' 'gx' 'hp' 'il' 'jq' 'kc' 'l4' 'lm' 'mt' 'my' 'nw' 'oq' 'pe' 'qe' 'qu' 'qz' 'r1' 'rb' 'sh' 'sx' 't5' 'td' 'tl' 'tr' 'vb' 'vd' 'w6' 'wh' 'wk' 'wp' 'wv' 'y0' 'ye' 'yq' 'z2' 'zj' 'zz' - f | 'a1' 'a5' 'aw' 'b5' 'cd' 'dz' 'em' 'eq' 'eu' 'fx' 'gk' 'hi' 'hq' 'ju' 'k8' 'kl' 'kw' 'la' 'lk' 'lm' 'm1' 'mj' 'mp' 'nz' 'o6' 'o8' 'oc' 'q0' 'q1' 'qg' 'qh' 'qw' 'rc' 'rd' 'ro' 'rr' 'sg' 'sy' 'th' 'ti' 'tt' 'uk' 'uo' 'ut' 'vy' 'wg' 'wi' 'x7' 'yr' 'yu' 'yx' 'yz' 'zr' 'zz' - f | 'a6' 'au' 'aw' 'bj' 'bn' 'cy' 'dg' 'e3' 'ei' 'ek' 'em' 'et' 'ex' 'fi' 'fm' 'g4' 'gm' 'gz' 'hp' 'ia' 'ie' 'jd' 'lg' 'lj' 'm6' 'mi' 'nd' 'oj' 'oo' 'ov' 'px' 'q0' 'q4' 'qj' 'qp' 'qq' 'r1' 'r5' 'rh' 'ro' 'tg' 'tr' 'tu' 'ty' 'u2' 'uk' 'ux' 'we' 'wi' 'wk' 'wq' 'wu' 'xy' 'y0' - f | 'a9' 'aa' 'aq' 'ay' 'bb' 'cg' 'db' 'de' 'do' 'e4' 'e5' 'e9' 'ek' 'ep' 'er' 'fi' 'fp' 'gb' 'hj' 'hk' 'hw' 'ir' 'iy' 'l1' 'lj' 'mb' 'nq' 'oi' 'pj' 'px' 'q9' 'qe' 'qu' 'qw' 'qz' 'rh' 'rl' 'sv' 'tc' 'ts' 'tv' 'uo' 'ur' 'vh' 'vp' 'w7' 'wf' 'wh' 'wo' 'wr' 'xu' 'z4' 'zc' 'zv' - f | 'au' 'cm' 'dj' 'e1' 'eh' 'ey' 'f3' 'fd' 'fg' 'fv' 'hn' 'i0' 'ia' 'jt' 'jy' 'k2' 'll' 'ne' 'o0' 'o2' 'op' 'pa' 'pf' 'qq' 'qx' 'rr' 'rs' 's4' 'sn' 'so' 'sq' 'tc' 'tn' 'ts' 'ty' 'tz' 'un' 'va' 'vg' 'vj' 'w8' 'wa' 'wb' 'wk' 'wo' 'wp' 'wr' 'x3' 'xx' 'yj' 'yz' 'z3' 'z7' 'zn' - f | '1f' '2u' 'ap' 'as' 'ax' 'bb' 'bf' 'cg' 'di' 'du' 'g3' 'g7' 'gk' 'ha' 'hv' 'hw' 'i6' 'jw' 'kg' 'ko' 'lu' 'ob' 'pn' 'qb' 'qg' 'qi' 'qs' 'qw' 'r3' 'r7' 'r9' 'rc' 're' 'rf' 'rn' 'ru' 'rz' 'sh' 'sq' 't7' 'ta' 'td' 'u2' 'ua' 'uy' 'v8' 'va' 'wk' 'wn' 'wu' 'wy' 'xr' 'yi' 'yt' 'za' - f | '1p' 'a7' 'ae' 'b2' 'dd' 'ef' 'eh' 'el' 'em' 'eo' 'fc' 'g0' 'hf' 'hh' 'i8' 'i9' 'in' 'is' 'iy' 'j3' 'ja' 'jl' 'js' 'jt' 'kz' 'lk' 'ng' 'nu' 'o6' 'oc' 'oe' 'om' 'ox' 'pi' 'pp' 'pq' 'ps' 'qc' 'qe' 'qy' 'rh' 'rk' 'rn' 's3' 'sc' 'so' 'st' 'tc' 'tm' 'tp' 'tq' 'vh' 'wa' 'ya' 'zq' - f | '1w' '2r' '9e' '9r' 'ci' 'es' 'f1' 'f4' 'fb' 'fx' 'g6' 'ga' 'gk' 'hj' 'hm' 'hu' 'i5' 'ii' 'jg' 'ji' 'ko' 'ku' 'l2' 'ld' 'lx' 'mt' 'n1' 'no' 'nw' 'o7' 'oi' 'pk' 'qy' 'r9' 'rj' 'rr' 'rt' 's6' 'sd' 't0' 'tc' 'to' 'tp' 'tv' 'ud' 'ux' 'vk' 'wr' 'wy' 'xb' 'xr' 'xt' 'yc' 'yp' 'zy' - f | '2k' '4s' 'd2' 'dk' 'dm' 'ea' 'ej' 'ep' 'et' 'eu' 'fr' 'gk' 'gs' 'hm' 'iu' 'jq' 'kj' 'km' 'lm' 'nb' 'nr' 'o1' 'oc' 'od' 'of' 'oj' 'ox' 'pf' 'pj' 'px' 'q0' 'q2' 'qa' 'qe' 'qh' 'qv' 'r5' 'r9' 'rb' 'rh' 'ti' 'tl' 'tw' 'u2' 'vb' 'vc' 'vs' 'xe' 'xn' 'y7' 'yb' 'yg' 'yy' 'zb' 'zl' - f | '48' 'ae' 'au' 'az' 'b2' 'di' 'ep' 'eq' 'ev' 'f7' 'fw' 'gh' 'gj' 'gn' 'hz' 'i5' 'iy' 'jf' 'kg' 'kj' 'kk' 'nc' 'nm' 'o4' 'oc' 'oe' 'of' 'oh' 'ol' 'ov' 'oz' 'pt' 'pv' 'q5' 'q7' 'qb' 'qe' 'qf' 'rh' 'ry' 'se' 'so' 'tv' 'ua' 'vd' 'wb' 'wg' 'wi' 'wp' 'xf' 'xo' 'yl' 'yr' 'yy' 'z0' - f | '70' 'ai' 'bj' 'bm' 'cj' 'ct' 'eb' 'ef' 'ek' 'es' 'fg' 'gh' 'gu' 'hg' 'ia' 'iu' 'iw' 'jt' 'ko' 'kq' 'mb' 'n1' 'o1' 'ox' 'pa' 'pr' 'q4' 'qd' 'qo' 'qr' 'qt' 'qw' 'qz' 'r3' 'r5' 'rg' 'ri' 'rj' 'rn' 'rp' 's7' 'sn' 't9' 'tq' 'tx' 'ty' 'uj' 'v0' 'vt' 'vz' 'w1' 'ww' 'xb' 'z6' 'zi' - f | 'a1' 'aa' 'c1' 'd7' 'dc' 'df' 'dh' 'e4' 'e9' 'ec' 'es' 'et' 'eu' 'ev' 'f3' 'g2' 'gu' 'he' 'il' 'j1' 'j6' 'jt' 'jv' 'ke' 'm8' 'm9' 'mh' 'ng' 'o8' 'on' 'pe' 'pf' 'pi' 'pn' 'qf' 'qn' 'qu' 'qv' 'qw' 'rh' 'rl' 'rr' 'ru' 'sg' 'sk' 'uk' 'ul' 'ux' 'vd' 'vj' 'wk' 'yd' 'yn' 'yx' 'z0' - f | 'af' 'bq' 'c9' 'cg' 'eg' 'ei' 'eq' 'ez' 'fo' 'fp' 'gl' 'i6' 'it' 'iz' 'jg' 'ka' 'lf' 'lm' 'lr' 'mv' 'oc' 'oj' 'om' 'or' 'p1' 'p4' 'pt' 'q3' 'qd' 'qe' 'qh' 'qx' 'ra' 'rd' 'sr' 'sz' 'tb' 'tc' 'tj' 'ug' 'uh' 'ux' 'wb' 'wc' 'wj' 'wy' 'xa' 'xb' 'y0' 'yj' 'yp' 'yz' 'zf' 'zl' 'zq' - f | '1a' '4p' 'bn' 'br' 'dk' 'ec' 'en' 'eu' 'gd' 'h0' 'ha' 'hm' 'if' 'il' 'io' 'ip' 'is' 'iz' 'jl' 'jq' 'k6' 'kd' 'kf' 'kn' 'kp' 'ld' 'lf' 'lt' 'n8' 'na' 'nl' 'o1' 'pd' 'pr' 'q8' 'qf' 'qr' 'qw' 're' 'rx' 'sa' 'sf' 'ta' 'tq' 'ux' 'v3' 'w6' 'wp' 'x2' 'y9' 'yi' 'yw' 'yx' 'z5' 'zl' 'zs' - f | '1y' '5p' '6o' 'au' 'b2' 'bg' 'do' 'dw' 'e1' 'e9' 'ea' 'ei' 'em' 'ev' 'f0' 'gc' 'hj' 'hx' 'k7' 'km' 'kp' 'kx' 'mj' 'mu' 'o3' 'oz' 'pf' 'q5' 'qe' 'qg' 'qh' 'qk' 'ql' 'qn' 'qo' 'rh' 'rk' 'ru' 'rx' 't1' 't3' 'th' 'v2' 'vx' 'w2' 'wc' 'wl' 'wm' 'wn' 'ws' 'x5' 'ye' 'yh' 'yk' 'yu' 'zw' - f | '2b' '3f' '5e' '7o' 'a4' 'ai' 'as' 'bc' 'bn' 'cz' 'd8' 'dg' 'dj' 'du' 'e5' 'el' 'et' 'ex' 'gc' 'gj' 'hi' 'hn' 'ig' 'ij' 'j3' 'js' 'l3' 'l6' 'lh' 'ls' 'mb' 'n1' 'o0' 'ot' 'q5' 'qd' 'qh' 'qv' 'qz' 'ra' 'rj' 's8' 'tb' 'tf' 'th' 'tx' 'ty' 'vm' 'wf' 'wg' 'wh' 'wn' 'y1' 'y5' 'yw' 'yz' - f | '2j' 'ai' 'al' 'ch' 'dy' 'dz' 'ed' 'ei' 'fg' 'fk' 'gp' 'i0' 'il' 'ip' 'iv' 'ix' 'js' 'lm' 'na' 'p1' 'pq' 'pu' 'qe' 'qi' 'qk' 'ql' 'qq' 'qv' 'qx' 'r0' 'rl' 'rm' 'rv' 'sf' 'sj' 'te' 'tk' 'tq' 'tt' 'tu' 'uc' 'ud' 'um' 'un' 'uq' 'vg' 'vu' 'vz' 'w8' 'wa' 'wf' 'xg' 'yj' 'yw' 'yy' 'z6' - f | '4c' '4z' 'ag' 'ak' 'an' 'as' 'aw' 'bl' 'd7' 'dy' 'e7' 'eb' 'ec' 'eq' 'et' 'fx' 'gg' 'gm' 'ht' 'hv' 'ik' 'in' 'ip' 'j6' 'k6' 'ka' 'lc' 'md' 'mx' 'n7' 'pw' 'py' 'q7' 'qa' 'qg' 'qh' 'qn' 'qo' 'qt' 'ri' 'rl' 'rs' 'sj' 'su' 'tj' 'u0' 'ua' 'w0' 'wh' 'wi' 'wp' 'wr' 'wx' 'wz' 'ys' 'yx' - f | '1y' '4f' 'ao' 'bv' 'co' 'cq' 'dd' 'df' 'dy' 'eq' 'eu' 'ex' 'gg' 'gm' 'gr' 'hm' 'iw' 'j9' 'jb' 'jg' 'jo' 'ju' 'k0' 'km' 'lf' 'ng' 'np' 'nw' 'nz' 'od' 'oj' 'or' 'pp' 'pr' 'pu' 'q5' 'q7' 'q9' 'qc' 'qd' 'qn' 'qx' 'r9' 'rd' 'rk' 'ro' 'sb' 'ta' 'th' 'tv' 'ty' 'tz' 'uq' 'vb' 'wb' 'wj' 'xo' - f | '4m' 'at' 'be' 'bo' 'bz' 'cv' 'd0' 'd8' 'ea' 'ec' 'ed' 'ex' 'f9' 'ff' 'fk' 'fv' 'gc' 'ge' 'i8' 'ij' 'is' 'k4' 'k6' 'mw' 'ob' 'ov' 'oy' 'pv' 'q1' 'q2' 'q9' 'qc' 'ql' 'r4' 'rn' 'ru' 'rx' 'ry' 'sj' 'tg' 'ts' 'tv' 'uj' 'vf' 'vh' 'w4' 'wc' 'ww' 'x5' 'xf' 'xx' 'y5' 'yg' 'yy' 'zg' 'zn' 'zw' - f | '4p' 'am' 'bj' 'bq' 'cg' 'cm' 'cz' 'dm' 'ds' 'du' 'e6' 'eg' 'en' 'eo' 'eq' 'et' 'ev' 'ex' 'fw' 'go' 'hb' 'hq' 'i0' 'ij' 'k6' 'kg' 'l6' 'lm' 'lq' 'mr' 'ms' 'oa' 'p6' 'q7' 'qa' 'qi' 'qk' 'r8' 'ra' 're' 'rr' 's8' 'sj' 't6' 't9' 'tc' 'v1' 'vd' 'w1' 'wf' 'wj' 'xy' 'yd' 'yn' 'yo' 'yt' 'yu' - f | 'a6' 'aa' 'ae' 'bn' 'c0' 'c7' 'ck' 'df' 'dn' 'ds' 'dt' 'e0' 'ea' 'eo' 'eu' 'f0' 'f6' 'g1' 'gd' 'i4' 'j6' 'ja' 'je' 'jt' 'mv' 'no' 'of' 'os' 'ou' 'ox' 'pi' 'pq' 'pr' 'q6' 'qk' 'ql' 'qv' 'qw' 'rh' 'rm' 'rv' 'sv' 't6' 'u2' 'un' 'ux' 'wc' 'wl' 'wo' 'wp' 'xg' 'y7' 'y8' 'ya' 'yn' 'yx' 'zl' - f | 'ab' 'am' 'aq' 'b9' 'bj' 'ck' 'cw' 'e2' 'e8' 'ek' 'eo' 'ew' 'f2' 'ff' 'fh' 'ft' 'gl' 'gs' 'h7' 'i0' 'ik' 'jl' 'jo' 'jq' 'jr' 'kc' 'kg' 'kw' 'mm' 'mo' 'pb' 'pn' 'qe' 'qg' 'qk' 'qr' 'qu' 'r2' 's8' 'sd' 'sq' 'su' 'td' 'tr' 'uh' 'uu' 'v2' 'vl' 'w8' 'wg' 'wm' 'wt' 'xl' 'xq' 'yi' 'yo' 'yq' - f | 'ah' 'ar' 'bk' 'db' 'dd' 'dq' 'eo' 'fe' 'fj' 'fv' 'g2' 'gc' 'hp' 'i7' 'j2' 'k9' 'kt' 'l9' 'ld' 'lu' 'lz' 'me' 'mr' 'mu' 'mx' 'nr' 'o6' 'ol' 'or' 'pa' 'ph' 'pi' 'q4' 'qn' 'qp' 'r5' 'rb' 'rn' 's8' 'sf' 't6' 'tl' 'tq' 'tx' 'u6' 'uc' 'uv' 'wf' 'x1' 'x7' 'xa' 'xl' 'xm' 'yb' 'yh' 'yw' 'zw' - f | '1m' '2u' 'ai' 'ap' 'bb' 'bd' 'cb' 'dn' 'fl' 'fm' 'fo' 'fu' 'gi' 'gl' 'gs' 'hg' 'hi' 'hm' 'hp' 'i0' 'if' 'ij' 'jn' 'jt' 'ju' 'k8' 'ld' 'lm' 'oe' 'ox' 'pa' 'q7' 'qe' 'qi' 'qo' 'qw' 'rf' 'rg' 'ry' 'sq' 't7' 'tk' 'tn' 'tz' 'u5' 'uc' 'v4' 'vr' 'w4' 'w6' 'wd' 'wo' 'ws' 'wt' 'wu' 'wv' 'x3' 'yl' - f | '1x' '2h' '6b' 'ah' 'av' 'ay' 'b9' 'bu' 'bv' 'c6' 'dv' 'e2' 'ea' 'ec' 'fh' 'gk' 'ia' 'j2' 'ji' 'k2' 'kc' 'kg' 'kq' 'kz' 'la' 'mq' 'nb' 'od' 'oe' 'ot' 'p8' 'pm' 'pp' 'qc' 'qi' 'qr' 'rg' 'rp' 'rw' 'tl' 'u5' 'ub' 'un' 'uv' 'vc' 'vi' 'wc' 'wi' 'wp' 'wv' 'xg' 'xq' 'yq' 'z3' 'zd' 'zv' 'zx' 'zy' - f | 'as' 'bb' 'bn' 'ce' 'd4' 'dp' 'ez' 'gu' 'gw' 'hd' 'hp' 'ia' 'ih' 'ij' 'j6' 'jm' 'jz' 'ku' 'kw' 'lh' 'mu' 'nl' 'nu' 'oc' 'pa' 'pm' 'q8' 'qd' 'qg' 'qi' 'qm' 'qn' 'qr' 'qs' 'qw' 'r9' 're' 'ro' 'ru' 'rv' 'rw' 't1' 't3' 'tm' 'u4' 'uf' 'uw' 'wa' 'wf' 'wk' 'xa' 'xs' 'yg' 'yp' 'ys' 'yu' 'yz' 'z4' - f | '3q' '5p' 'a2' 'be' 'bv' 'bw' 'cv' 'd8' 'df' 'dh' 'dk' 'e2' 'ec' 'eo' 'fc' 'g8' 'gq' 'h8' 'ig' 'io' 'ir' 'iv' 'je' 'kq' 'kx' 'lc' 'lr' 'lt' 'ok' 'pk' 'q1' 'q4' 'qe' 'qh' 'qw' 'qz' 'rj' 'rv' 't8' 'tf' 'tl' 'tq' 'uh' 'uz' 'wk' 'wp' 'ws' 'wt' 'wv' 'x3' 'yb' 'ye' 'yo' 'yp' 'yy' 'z6' 'z8' 'zb' 'zm' - f | 'a1' 'ag' 'ai' 'ap' 'bp' 'by' 'dc' 'dy' 'e5' 'eg' 'ei' 'el' 'em' 'fc' 'gl' 'h8' 'hr' 'i1' 'ib' 'ie' 'if' 'ij' 'j5' 'jj' 'kf' 'kx' 'lc' 'm3' 'mg' 'nb' 'ol' 'ph' 'py' 'q1' 'q5' 'qi' 'qk' 'ql' 'qp' 'qs' 'sv' 'td' 'te' 'tn' 'vd' 'vm' 'vq' 'wv' 'xp' 'xu' 'yb' 'yo' 'yq' 'yx' 'yy' 'zp' 'zr' 'zx' 'zz' - f | 'af' 'ag' 'ak' 'bb' 'cr' 'cy' 'd7' 'db' 'df' 'di' 'eh' 'ew' 'fl' 'fr' 'gd' 'gp' 'hf' 'hk' 'hu' 'ib' 'ik' 'io' 'ix' 'jg' 'k9' 'kc' 'ke' 'm4' 'ma' 'mx' 'mz' 'ob' 'oi' 'oo' 'or' 'ox' 'pg' 'pl' 'pu' 'qc' 'qe' 'qg' 'rl' 'ro' 'rv' 'rz' 'sj' 'sq' 'u4' 've' 'we' 'wi' 'wk' 'wy' 'xd' 'yh' 'yq' 'yv' 'yx' - f | 'ah' 'c3' 'd1' 'dh' 'dz' 'ei' 'em' 'ex' 'fe' 'fk' 'g7' 'gz' 'hi' 'hx' 'i3' 'iu' 'j1' 'jm' 'k8' 'kb' 'ku' 'lf' 'lv' 'lz' 'm3' 'mn' 'my' 'nc' 'oj' 'pk' 'qh' 'qn' 'qo' 'qq' 'rf' 'ru' 'ry' 's9' 'sa' 'sc' 'sd' 'se' 'sz' 'td' 'tg' 'tq' 'tx' 'tz' 'vr' 'vu' 'w3' 'wd' 'wl' 'wp' 'x9' 'yb' 'yd' 'yr' 'yt' - f | '0z' 'ae' 'br' 'cr' 'dd' 'di' 'du' 'e7' 'ea' 'eb' 'ee' 'ej' 'em' 'eo' 'fo' 'fs' 'gc' 'gf' 'gj' 'hu' 'iv' 'kc' 'lb' 'nw' 'o9' 'ov' 'oz' 'pq' 'qq' 'ro' 'rr' 'rt' 'ru' 'rw' 's4' 'te' 'tm' 'tq' 'um' 'v7' 'va' 'vi' 'vr' 'wb' 'wg' 'wo' 'wp' 'wr' 'ww' 'wy' 'xv' 'y1' 'y9' 'ya' 'ym' 'yt' 'yu' 'z5' 'zl' 'zs' - f | '3i' 'a3' 'af' 'cc' 'cs' 'cv' 'd8' 'ei' 'ej' 'ep' 'et' 'ex' 'fb' 'fe' 'fx' 'hc' 'ij' 'jf' 'jp' 'jr' 'js' 'kc' 'km' 'kz' 'lc' 'm7' 'nv' 'ob' 'oc' 'pt' 'q5' 'q7' 'q8' 'qc' 'qm' 'qn' 'qs' 'qy' 'ra' 're' 'rk' 'rx' 's0' 's4' 'se' 'sh' 'sm' 't7' 'tl' 'to' 'tz' 'ue' 'um' 'w3' 'wk' 'wp' 'ya' 'yl' 'yn' 'ys' - f | 'a5' 'al' 'b6' 'bu' 'co' 'd0' 'd4' 'db' 'e0' 'e2' 'eb' 'ei' 'ej' 'el' 'et' 'ez' 'g7' 'gu' 'j6' 'jl' 'k3' 'kf' 'km' 'kw' 'kx' 'lp' 'me' 'mw' 'my' 'n2' 'n5' 'n7' 'nr' 'ny' 'oj' 'q8' 'qb' 'qg' 'qn' 'qq' 'qz' 'ra' 'rk' 'rl' 'rn' 's3' 's6' 't2' 't8' 'tk' 'tm' 'ul' 'uq' 'wg' 'y1' 'yc' 'yn' 'yq' 'yy' 'zr' - f | 'af' 'am' 'az' 'ce' 'ci' 'dd' 'e5' 'eb' 'ee' 'eh' 'fe' 'fj' 'fv' 'ge' 'gl' 'hp' 'hx' 'i5' 'i8' 'ia' 'ig' 'jb' 'jm' 'jv' 'k6' 'kg' 'kv' 'li' 'ls' 'lx' 'm2' 'md' 'mz' 'o0' 'oe' 'oy' 'pv' 'q5' 'qh' 'qm' 'qo' 'qy' 'rf' 'ri' 'rp' 'rz' 'su' 'tj' 'tz' 'u2' 'uh' 'ur' 'vg' 'we' 'wi' 'xj' 'yb' 'yx' 'yz' 'z0' - f | 'b9' 'c9' 'cc' 'cx' 'di' 'ec' 'eo' 'f5' 'fn' 'gd' 'ge' 'gh' 'hc' 'hy' 'i8' 'if' 'iq' 'ir' 'ix' 'ja' 'jl' 'jx' 'km' 'l5' 'l8' 'le' 'mm' 'oc' 'pr' 'qg' 'qo' 'rm' 'ro' 'rv' 'sm' 'td' 'th' 'tm' 'tx' 'u7' 'uc' 'ue' 'uk' 'ux' 'vw' 'wa' 'wb' 'wd' 'wh' 'wr' 'ww' 'xa' 'xj' 'xz' 'y4' 'yd' 'yl' 'ym' 'zf' 'zv' - f | '1a' 'a0' 'ab' 'ah' 'ay' 'cd' 'db' 'di' 'eh' 'eo' 'eq' 'f4' 'f8' 'fs' 'gv' 'h7' 'he' 'hf' 'i0' 'id' 'il' 'io' 'ip' 'kc' 'l1' 'l7' 'lw' 'mp' 'na' 'nb' 'nj' 'oj' 'ou' 'pa' 'pn' 'ps' 'pu' 'qb' 'qf' 'ql' 'qn' 'qr' 'rn' 'rw' 'so' 'tf' 'tg' 'th' 'tr' 'us' 'w3' 'w6' 'wb' 'wc' 'wf' 'wg' 'wp' 'wr' 'yv' 'yw' 'zh' - f | '1n' 'am' 'b9' 'bc' 'bi' 'dl' 'dv' 'ea' 'eq' 'ey' 'fj' 'g1' 'g3' 'g8' 'ge' 'it' 'iu' 'jh' 'jz' 'kk' 'ln' 'mc' 'mw' 'nf' 'nj' 'o4' 'o9' 'ob' 'ox' 'pq' 'q4' 'qb' 'qk' 'qn' 'qs' 'qt' 'r4' 'ra' 'rg' 'rp' 'rx' 'sj' 'sq' 'ss' 't0' 'tg' 'ty' 'ue' 'ui' 'uj' 'uv' 'v6' 'vr' 'w1' 'w9' 'wj' 'wy' 'xt' 'ym' 'ys' 'yz' - f | '1v' '20' 'au' 'bo' 'br' 'c9' 'cv' 'dp' 'ep' 'fo' 'gj' 'hb' 'hx' 'iv' 'iw' 'jc' 'jm' 'jw' 'k8' 'kg' 'km' 'kn' 'nd' 'o8' 'oh' 'ok' 'op' 'oy' 'px' 'pz' 'qh' 'qo' 'qp' 'qs' 'qw' 're' 'rr' 'ry' 's3' 'sj' 't7' 't9' 'tt' 'tw' 'u9' 'ue' 'us' 'uu' 'v2' 'w3' 'wa' 'wf' 'wg' 'wt' 'wv' 'xc' 'yi' 'yu' 'yv' 'z4' 'zj' - f | '6g' 'ar' 'ce' 'cn' 'ds' 'dt' 'e9' 'eh' 'el' 'ew' 'gt' 'gw' 'gx' 'hb' 'ho' 'i8' 'j8' 'jp' 'jr' 'kb' 'la' 'lr' 'mg' 'mi' 'ml' 'nd' 'ng' 'oj' 'op' 'pb' 'pd' 'pn' 'py' 'qc' 'qe' 'qk' 'qr' 'qt' 'qv' 'qz' 'sm' 'tc' 'tg' 'ti' 'tp' 'ty' 'u8' 'uq' 'uw' 'uy' 've' 'w0' 'wb' 'wd' 'wp' 'x4' 'xm' 'ym' 'z2' 'zh' 'zz' - f | 'af' 'as' 'b2' 'bl' 'bz' 'ca' 'cd' 'co' 'de' 'dp' 'e4' 'ed' 'en' 'eo' 'eu' 'ft' 'g0' 'gj' 'ha' 'hh' 'hn' 'hy' 'ij' 'jb' 'jj' 'jn' 'l7' 'll' 'lp' 'oh' 'ot' 'pb' 'ph' 'pi' 'pn' 'qc' 'qx' 'r5' 'rb' 'ri' 'sb' 'sd' 'sn' 'sv' 'sw' 't7' 'tb' 'ti' 'ty' 'u7' 'un' 'uo' 'wb' 'we' 'wf' 'wh' 'wo' 'wp' 'yb' 'yc' 'ys' - f | '4a' 'a9' 'au' 'bn' 'bs' 'cg' 'd4' 'dx' 'fb' 'fk' 'gc' 'hh' 'ht' 'hy' 'iy' 'je' 'jg' 'jj' 'jp' 'ju' 'kz' 'la' 'm8' 'na' 'oa' 'oj' 'ol' 'or' 'ov' 'ox' 'p6' 'po' 'q0' 'q9' 'qc' 'qe' 'qi' 'qq' 'qt' 'qx' 'si' 'sn' 'su' 'sw' 't8' 'ta' 'tv' 'tz' 'uq' 'ut' 'w6' 'w7' 'we' 'wk' 'wl' 'wq' 'wy' 'y4' 'ya' 'ze' 'zq' 'zy' - f | 'b0' 'bg' 'bh' 'cu' 'd8' 'dv' 'er' 'fd' 'fm' 'fo' 'gg' 'ij' 'ir' 'iu' 'jc' 'jl' 'jn' 'jo' 'k4' 'kb' 'ku' 'lq' 'ly' 'mw' 'of' 'op' 'ph' 'pk' 'ps' 'px' 'q0' 'qd' 'qg' 'qz' 'rb' 'rp' 'rs' 'rv' 'su' 't9' 'tm' 'tp' 'tx' 'ty' 'ug' 'ul' 'uo' 'up' 'uv' 'v5' 'wh' 'wr' 'ww' 'xw' 'y1' 'yd' 'yf' 'yn' 'z4' 'z8' 'zf' 'zn' - f | '1i' 'ap' 'bh' 'ce' 'cp' 'di' 'dm' 'dt' 'es' 'eu' 'f2' 'f3' 'fw' 'fx' 'g5' 'gf' 'gy' 'h2' 'hl' 'i4' 'ii' 'iy' 'kp' 'lh' 'lr' 'me' 'of' 'og' 'ok' 'on' 'oo' 'pb' 'pd' 'pt' 'qf' 'qk' 'qz' 'r4' 'r7' 're' 'ri' 'rj' 'ro' 'rx' 's2' 'tk' 'tl' 'tq' 'tx' 'ub' 'ui' 'us' 'vm' 'w1' 'w7' 'wi' 'wj' 'wq' 'wx' 'xp' 'yg' 'yr' 'yx' - f | 'a2' 'a7' 'aq' 'bv' 'cy' 'd0' 'df' 'dg' 'do' 'ei' 'ek' 'ev' 'ey' 'fg' 'ge' 'gg' 'h4' 'hv' 'im' 'iq' 'ix' 'j4' 'j5' 'jt' 'kv' 'nc' 'o2' 'ou' 'ow' 'ph' 'pz' 'qf' 'qj' 'qm' 'qo' 'qq' 'qs' 'ra' 'rl' 'rz' 'te' 'tj' 'tp' 'tr' 'ts' 'tx' 'u5' 'ue' 'uj' 'uk' 'uo' 'us' 'v7' 'w2' 'wa' 'wu' 'wv' 'ww' 'wz' 'y2' 'y8' 'yy' 'zg' - f | 'a6' 'ao' 'az' 'by' 'db' 'dl' 'eg' 'ei' 'el' 'eo' 'fh' 'fv' 'gl' 'h0' 'hl' 'hx' 'i9' 'iq' 'j7' 'jx' 'kg' 'kh' 'l9' 'nz' 'o9' 'oi' 'om' 'on' 'oq' 'or' 'pf' 'pz' 'qf' 'qj' 'r5' 'rq' 'rw' 'sr' 'sx' 'tc' 'tg' 'tj' 'tl' 'to' 'uj' 'un' 'vw' 'w1' 'w5' 'w8' 'wn' 'ws' 'wv' 'x2' 'x3' 'xi' 'y4' 'yd' 'ym' 'ys' 'z7' 'zq' 'zv' - f | 'am' 'as' 'ay' 'bl' 'e0' 'e1' 'ea' 'eg' 'f6' 'fc' 'fx' 'ia' 'io' 'jq' 'jx' 'kd' 'ky' 'lb' 'll' 'lr' 'lv' 'me' 'nv' 'o4' 'o7' 'oe' 'ok' 'oq' 'pe' 'pr' 'py' 'q7' 'qg' 'qh' 'qj' 'qk' 'ql' 'qq' 'qr' 'qs' 'r1' 'rg' 'rl' 'rm' 'ro' 'sq' 'sr' 'sz' 'ti' 'ts' 'ue' 'ui' 'uu' 'uz' 'vk' 'y0' 'y2' 'y9' 'ym' 'yt' 'yx' 'z8' 'zd' - f | '1o' 'ah' 'ap' 'ba' 'bn' 'cs' 'cu' 'd2' 'd8' 'dg' 'dr' 'ed' 'ee' 'er' 'et' 'eu' 'ey' 'ff' 'g1' 'hj' 'i3' 'i5' 'il' 'in' 'jd' 'kd' 'ku' 'lm' 'lv' 'mu' 'nu' 'ok' 'ol' 'oo' 'ov' 'oy' 'p8' 'pu' 'qb' 'qq' 'qx' 'r5' 'rm' 'rp' 'rv' 'sh' 'sk' 'sl' 'sr' 'tx' 'uy' 'v3' 'vu' 'w3' 'wa' 'wb' 'wv' 'xh' 'xq' 'ys' 'yt' 'yx' 'z2' 'zi' - f | '2e' 'ak' 'bv' 'cb' 'ch' 'cy' 'd9' 'dq' 'dr' 'e8' 'ec' 'ef' 'ek' 'es' 'f1' 'fw' 'gj' 'gw' 'hh' 'hr' 'i3' 'i6' 'ic' 'ji' 'jr' 'jy' 'kr' 'md' 'mu' 'od' 'og' 'oo' 'p9' 'pd' 'q1' 'q3' 'qq' 'qw' 'qy' 'ra' 'rj' 'rl' 'rn' 'sf' 't4' 't5' 't7' 'tl' 'tm' 'ts' 'u4' 'ug' 'ui' 'uw' 'vo' 'ws' 'ww' 'wy' 'yd' 'yo' 'yq' 'zm' 'zp' 'zw' - f | '5y' 'af' 'av' 'az' 'cj' 'cp' 'cq' 'dk' 'e6' 'e7' 'ea' 'ec' 'ee' 'ei' 'ek' 'em' 'ga' 'gk' 'gw' 'hc' 'id' 'ie' 'kp' 'kv' 'lw' 'm0' 'mf' 'mn' 'mw' 'ny' 'ob' 'ol' 'p9' 'ph' 'pk' 'pp' 'pw' 'q0' 'qg' 'qi' 'ql' 'qv' 'qx' 'r3' 'rg' 'ry' 'se' 'sh' 'sq' 'sz' 't1' 'tu' 'u2' 'uh' 'uj' 'uk' 'ut' 'w2' 'wb' 'ww' 'wx' 'yf' 'yo' 'zr' - f | 'ab' 'an' 'bm' 'bn' 'bp' 'ca' 'd9' 'dc' 'e0' 'e4' 'e5' 'eh' 'er' 'fe' 'fk' 'fv' 'ga' 'ge' 'hy' 'ic' 'ie' 'io' 'ja' 'jb' 'je' 'kp' 'ks' 'ln' 'md' 'ng' 'nr' 'oj' 'oy' 'p5' 'p6' 'p7' 'pe' 'pg' 'pu' 'qa' 'qq' 'qv' 'qw' 'qy' 'rg' 'rj' 'rk' 'sk' 'tf' 'tw' 'ui' 'um' 'uu' 'v9' 'vu' 'wo' 'wp' 'wx' 'wy' 'xf' 'y0' 'yp' 'z6' 'zi' - f | 'ae' 'cn' 'ct' 'dz' 'eb' 'ee' 'ff' 'fi' 'fk' 'fo' 'ft' 'gj' 'gr' 'ie' 'il' 'iv' 'iw' 'iy' 'jb' 'jf' 'ji' 'ke' 'ku' 'kx' 'l3' 'la' 'of' 'ol' 'ox' 'pb' 'pi' 'pq' 'q8' 'qi' 'qj' 'qp' 'qq' 'qw' 'r0' 'r5' 'rk' 'rq' 'ru' 'rz' 'su' 't8' 'tb' 'u0' 'ue' 'um' 'w2' 'wc' 'wm' 'ws' 'wt' 'x4' 'xc' 'xd' 'xm' 'xn' 'y0' 'yb' 'zi' 'zp' - f | '3r' '6o' 'ab' 'ay' 'b3' 'bc' 'bh' 'd8' 'dd' 'df' 'eb' 'ee' 'eh' 'el' 'eu' 'ex' 'fn' 'g3' 'ge' 'gr' 'gz' 'hd' 'ib' 'ie' 'ih' 'il' 'it' 'iu' 'jd' 'jq' 'jt' 'jv' 'li' 'pc' 'pp' 'qc' 'ql' 'qp' 'qu' 'qx' 'qz' 'ro' 'rq' 'sj' 'sz' 'te' 'tt' 'tu' 'uh' 'uo' 'up' 'us' 'uu' 'ux' 'v7' 'w3' 'wl' 'wn' 'xf' 'xu' 'ya' 'yh' 'yk' 'za' 'zt' - f | '5o' 'ad' 'aw' 'az' 'bi' 'bo' 'd1' 'db' 'di' 'do' 'e7' 'eb' 'ei' 'em' 'ep' 'eq' 'eu' 'fo' 'gg' 'gw' 'i0' 'ig' 'ih' 'iu' 'j3' 'j4' 'jo' 'js' 'kq' 'lc' 'lo' 'lu' 'm9' 'mi' 'mk' 'mt' 'n4' 'ni' 'o7' 'od' 'ot' 'pc' 'pg' 'pp' 'qc' 'qr' 'qw' 'rd' 'rx' 'se' 'sq' 'sy' 't5' 'ts' 'ub' 'vz' 'wb' 'wl' 'wr' 'wt' 'xe' 'xt' 'yg' 'yr' 'zw' - f | '5t' 'ad' 'am' 'ed' 'ei' 'en' 'eo' 'ey' 'f0' 'fp' 'fr' 'gc' 'hp' 'hz' 'ic' 'ix' 'jt' 'kn' 'kr' 'lk' 'ls' 'm1' 'mt' 'nk' 'od' 'p3' 'pa' 'pe' 'pi' 'q4' 'qa' 'qi' 'qk' 'qq' 'qt' 'qv' 'rb' 'rr' 'rv' 's3' 'se' 'sr' 't0' 'tj' 'tk' 'tp' 'tu' 'u1' 'ud' 'uf' 'uv' 'ux' 'vd' 'vu' 'wh' 'wi' 'wp' 'wu' 'x9' 'xa' 'ye' 'yn' 'yw' 'zj' 'zs' - f | '6h' '7f' 'ab' 'aq' 'ax' 'bc' 'bl' 'ce' 'cm' 'dn' 'do' 'e1' 'ec' 'ed' 'en' 'fc' 'fl' 'g1' 'ga' 'ge' 'gn' 'h8' 'i0' 'id' 'iq' 'iw' 'jc' 'ji' 'lt' 'mj' 'nm' 'o0' 'o6' 'oo' 'pa' 'pb' 'pt' 'q6' 'qf' 'qg' 'qz' 'r1' 'r2' 'r8' 'rd' 'rf' 's9' 'se' 't8' 'tc' 'te' 'u3' 'u5' 'uc' 'ug' 'ul' 'us' 'uu' 'v2' 'vz' 'wp' 'x8' 'ye' 'yq' 'yw' - f | 'a5' 'ae' 'ah' 'as' 'b9' 'bh' 'c5' 'd0' 'dc' 'dd' 'do' 'dp' 'dz' 'eg' 'eh' 'fg' 'fu' 'g3' 'gh' 'gu' 'ha' 'hb' 'hd' 'hg' 'hw' 'i3' 'ib' 'jb' 'je' 'jm' 'js' 'm8' 'ma' 'n4' 'nu' 'nz' 'ob' 'oy' 'qu' 'qz' 'r5' 'rd' 're' 'rr' 'ru' 's5' 'sf' 'sp' 'st' 'tn' 'uz' 'vi' 'vo' 'w9' 'wj' 'wm' 'ws' 'wu' 'wv' 'wy' 'xa' 'xc' 'yl' 'zd' 'zp' - f | 'a6' 'ad' 'ak' 'ap' 'd1' 'de' 'dj' 'eb' 'eg' 'fi' 'fq' 'ft' 'gx' 'gy' 'hn' 'hs' 'i4' 'ia' 'im' 'is' 'kf' 'ko' 'kt' 'l0' 'lr' 'm8' 'mv' 'oi' 'on' 'pc' 'pl' 'pn' 'pp' 'q2' 'q4' 'qj' 'ql' 'qv' 'qy' 'r2' 'rc' 'rd' 're' 'rm' 'rt' 'sj' 'tb' 'tc' 'tf' 'tk' 'uf' 'uk' 'ul' 'um' 'uq' 'uy' 'vj' 'wl' 'wv' 'ww' 'x7' 'xj' 'y7' 'yx' 'zb' - f | 'ab' 'ct' 'cv' 'cw' 'dg' 'ds' 'e0' 'e5' 'f3' 'fj' 'fl' 'fn' 'gy' 'ha' 'ie' 'if' 'jf' 'ju' 'jx' 'kg' 'ki' 'kw' 'l0' 'ls' 'm9' 'mj' 'nj' 'of' 'om' 'oq' 'os' 'ov' 'pv' 'pz' 'q0' 'q5' 'q8' 'qf' 'qg' 'qi' 'qj' 'qm' 'qn' 'qw' 'rk' 'ru' 'sc' 'sn' 'so' 't1' 'tn' 'tz' 'un' 'uv' 'uw' 'vn' 'wh' 'wn' 'ww' 'xy' 'yd' 'yr' 'yv' 'zh' 'zy' - f | 'am' 'db' 'dj' 'dn' 'ec' 'eo' 'ev' 'ex' 'fn' 'fw' 'fz' 'gi' 'gn' 'gq' 'ha' 'ho' 'in' 'is' 'ja' 'jj' 'jk' 'js' 'kv' 'lc' 'lz' 'mj' 'o2' 'oa' 'of' 'oi' 'pe' 'pn' 'ps' 'pv' 'py' 'q3' 'qa' 'qb' 'qi' 'qn' 'qo' 'qq' 'qr' 'qv' 'rk' 'rl' 't8' 'tk' 'tv' 'tw' 'ug' 'uk' 'ux' 'uz' 'v7' 'vr' 'wd' 'wf' 'wk' 'wv' 'ya' 'yq' 'yu' 'zp' 'zx' - f | 'ao' 'as' 'bz' 'dc' 'dl' 'dn' 'du' 'dy' 'e3' 'ed' 'ee' 'ej' 'em' 'eo' 'ep' 'eq' 'er' 'fc' 'ft' 'g4' 'gc' 'gm' 'gq' 'gr' 'gy' 'hq' 'jg' 'k6' 'k9' 'ks' 'kz' 'l7' 'lo' 'lu' 'lw' 'ly' 'nb' 'oc' 'oo' 'q9' 'qc' 'qd' 'qk' 'qs' 'qv' 'ro' 'rx' 'ry' 'sk' 'sv' 'sy' 'ti' 'tk' 'ui' 'un' 'uq' 'vl' 'w4' 'wl' 'wm' 'yj' 'yo' 'yu' 'yw' 'zg' - f | '1i' '3z' 'b6' 'bh' 'bn' 'bu' 'cm' 'do' 'dt' 'ef' 'eg' 'ek' 'eo' 'et' 'ex' 'f9' 'g3' 'gj' 'gl' 'h7' 'hp' 'i8' 'ih' 'im' 'in' 'jn' 'k1' 'k7' 'kd' 'lq' 'ms' 'mv' 'n7' 'nj' 'nt' 'o4' 'o9' 'ov' 'q2' 'qa' 'qh' 'qk' 'ql' 'qp' 'qu' 'qv' 'rj' 's8' 'sf' 'sh' 't7' 't8' 'um' 'un' 'uo' 'ut' 'uu' 'w1' 'wa' 'wf' 'wi' 'wx' 'xj' 'yc' 'yo' 'yt' - f | '1w' '5i' 'a4' 'a6' 'bz' 'de' 'dg' 'dt' 'ed' 'ei' 'ej' 'ey' 'fa' 'ff' 'gg' 'hi' 'hj' 'ho' 'i2' 'ii' 'ij' 'jq' 'jy' 'ka' 'kr' 'kw' 'lv' 'm7' 'nd' 'ot' 'ov' 'oy' 'oz' 'pe' 'pj' 'qb' 'qj' 'qq' 'qt' 'qv' 'r0' 'r3' 'r4' 'ri' 'rj' 'si' 'ta' 'tc' 'ts' 'tx' 'u3' 'uj' 'ur' 'v6' 'vh' 'w3' 'w6' 'wc' 'wg' 'wq' 'x5' 'xv' 'yb' 'yt' 'yx' 'zl' - f | '10' '2p' '6r' 'a2' 'bb' 'c9' 'dq' 'dy' 'ec' 'eh' 'ej' 'ek' 'es' 'fl' 'g1' 'g9' 'gd' 'h1' 'h2' 'hj' 'hn' 'hw' 'ip' 'iz' 'jg' 'jl' 'l5' 'le' 'lk' 'me' 'mi' 'o0' 'o6' 'oa' 'oe' 'ox' 'pd' 'pm' 'pr' 'py' 'q1' 'qo' 'qq' 'qz' 'r3' 'rs' 'rw' 's7' 'sl' 'sw' 't2' 't4' 'td' 'tj' 'u3' 'ud' 'ur' 'uw' 'vy' 'wi' 'wj' 'wl' 'wq' 'ys' 'yu' 'z7' 'zp' - f | '19' 'a4' 'a7' 'ae' 'ar' 'as' 'bj' 'bp' 'bv' 'cp' 'd8' 'dp' 'e0' 'e8' 'ea' 'ee' 'ek' 'ep' 'es' 'et' 'ez' 'fp' 'gu' 'h2' 'h4' 'he' 'hp' 'ii' 'im' 'in' 'lc' 'lk' 'lu' 'lv' 'ma' 'od' 'oe' 'p7' 'pm' 'q7' 'qa' 'qe' 'qf' 'qi' 'qr' 'qu' 'rc' 'rd' 're' 'rj' 'rl' 'ro' 'tj' 'tw' 'v4' 'vb' 'w7' 'wc' 'wg' 'wi' 'wm' 'wu' 'y4' 'yj' 'yv' 'z1' 'zt' 'zu' - f | '2f' 'af' 'al' 'at' 'bc' 'bo' 'cd' 'd6' 'dk' 'dp' 'dy' 'ea' 'eu' 'ev' 'ey' 'fe' 'ft' 'gd' 'gi' 'ha' 'hm' 'hr' 'i6' 'im' 'is' 'iz' 'jb' 'jt' 'ju' 'li' 'm4' 'my' 'na' 'nm' 'nu' 'oh' 'p4' 'pa' 'pn' 'po' 'qk' 'qz' 'r4' 're' 'rf' 'rs' 'sm' 'tb' 'ti' 'to' 'tw' 'u7' 'ut' 'vz' 'w3' 'w5' 'w9' 'wc' 'wj' 'wq' 'wr' 'x7' 'xg' 'xz' 'ye' 'yx' 'ze' 'zo' - f | '2o' '4i' '93' 'a2' 'az' 'b5' 'bk' 'cd' 'do' 'ea' 'ed' 'ej' 'el' 'es' 'ez' 'fd' 'fk' 'fu' 'h7' 'hg' 'hr' 'hs' 'hv' 'iz' 'j0' 'j9' 'jb' 'jc' 'jt' 'ln' 'lu' 'lw' 'lz' 'mz' 'ns' 'nv' 'o8' 'oi' 'oq' 'ov' 'oz' 'pr' 'qi' 'qw' 'rb' 'rg' 'ro' 'rq' 'sb' 'sc' 't8' 't9' 'te' 'ti' 'tm' 'uo' 'uz' 'wd' 'wi' 'wn' 'wp' 'ww' 'wx' 'xt' 'xv' 'yb' 'yr' 'zs' - f | '2p' '3w' 'ah' 'at' 'bg' 'bv' 'bz' 'cu' 'd8' 'dw' 'eb' 'ec' 'ei' 'er' 'es' 'fn' 'gl' 'hd' 'hx' 'ij' 'ip' 'ki' 'lh' 'mx' 'my' 'nq' 'o3' 'o7' 'ok' 'or' 'os' 'pd' 'pu' 'q5' 'qa' 'qc' 'qd' 'qg' 'qh' 'ql' 'qs' 'qt' 'qu' 'qx' 'qy' 'rb' 'rd' 'rk' 'rs' 'ru' 'rv' 'rw' 'sn' 'tm' 'vw' 'w9' 'wa' 'wb' 'wm' 'ws' 'xe' 'xo' 'xu' 'y6' 'yh' 'yj' 'z4' 'zg' - f | '45' '85' 'an' 'bi' 'ca' 'cb' 'co' 'cq' 'cu' 'dt' 'e4' 'eb' 'ed' 'ef' 'em' 'eq' 'er' 'et' 'ex' 'fe' 'fk' 'fv' 'fw' 'gm' 'gq' 'hu' 'it' 'iw' 'j5' 'jj' 'jm' 'jr' 'lq' 'lz' 'mc' 'n0' 'nq' 'o7' 'ok' 'pd' 'ph' 'q6' 'qe' 'qh' 'qm' 'qy' 'qz' 'r2' 'r5' 'ra' 're' 's6' 'sb' 'sl' 'tb' 'tg' 'ur' 'vl' 'wa' 'wf' 'wt' 'wv' 'ww' 'xr' 'xz' 'yb' 'yf' 'zx' - f | 'a2' 'af' 'an' 'aq' 'ar' 'bj' 'bz' 'cx' 'dy' 'eh' 'ek' 'en' 'ex' 'fy' 'gg' 'gr' 'hh' 'if' 'ip' 'it' 'ix' 'j5' 'jf' 'jn' 'k0' 'kk' 'lq' 'nc' 'oc' 'od' 'og' 'oh' 'oo' 'or' 'pm' 'po' 'qa' 'qd' 'qe' 'qh' 'ql' 'qo' 'qt' 'qx' 'qz' 'rq' 'rr' 'ru' 'sj' 'sk' 'tl' 'tr' 'ug' 'wa' 'wb' 'wd' 'we' 'wk' 'wn' 'wq' 'wr' 'xl' 'xo' 'xw' 'yf' 'yq' 'ys' 'yw' - f | 'a6' 'ao' 'aq' 'ba' 'be' 'bg' 'cb' 'ci' 'cj' 'cq' 'cs' 'dc' 'e6' 'ea' 'ei' 'ex' 'fw' 'fy' 'g7' 'gg' 'gq' 'hg' 'ib' 'ig' 'im' 'jz' 'kv' 'me' 'mi' 'mj' 'mp' 'o6' 'oq' 'os' 'ov' 'pd' 'pl' 'pr' 'px' 'qf' 'qg' 'ql' 'qr' 'qz' 'r5' 'rl' 'ro' 'ru' 'rz' 'sy' 'sz' 't7' 'tt' 'u7' 'uf' 'ug' 'uo' 'vt' 'w3' 'w8' 'wb' 'wp' 'ww' 'wy' 'xl' 'xv' 'yc' 'z3' - f | 'a7' 'ab' 'ba' 'bv' 'e7' 'ea' 'eh' 'ep' 'er' 'es' 'f4' 'gq' 'hg' 'hi' 'hs' 'ip' 'iw' 'je' 'k0' 'kh' 'kn' 'ko' 'lo' 'ly' 'm6' 'n2' 'o1' 'oh' 'on' 'op' 'os' 'pi' 'q6' 'q9' 'qh' 'qj' 'qm' 'qn' 'qp' 'qs' 's7' 'sa' 'sb' 'sc' 'tn' 'tq' 'tt' 'u4' 'un' 'ux' 've' 'w1' 'wd' 'wf' 'wj' 'wl' 'wr' 'wu' 'wy' 'xf' 'xx' 'y3' 'y9' 'yk' 'zh' 'zn' 'zo' 'zr' - f | '1l' '2u' 'ao' 'av' 'bb' 'c7' 'c8' 'ca' 'cm' 'cp' 'dc' 'di' 'e2' 'e4' 'eo' 'er' 'et' 'ex' 'g1' 'gb' 'hi' 'hr' 'ht' 'i9' 'id' 'ie' 'jk' 'jq' 'ju' 'k3' 'k5' 'lb' 'lm' 'lv' 'mg' 'no' 'o8' 'oo' 'ot' 'p2' 'pn' 'pw' 'py' 'q6' 'qg' 'ql' 'qo' 'r2' 'rf' 'rk' 'rq' 'ry' 't2' 'tb' 'tn' 'tr' 'tw' 'ub' 'w1' 'wa' 'wb' 'we' 'wi' 'ww' 'xo' 'yk' 'ys' 'yx' 'zg' - f | '26' '4v' 'a1' 'ac' 'af' 'ah' 'au' 'cn' 'd3' 'dn' 'e4' 'ec' 'eg' 'ep' 'er' 'fa' 'fb' 'g6' 'gr' 'h3' 'hb' 'hf' 'hj' 'iu' 'iv' 'j1' 'jk' 'jy' 'k2' 'k8' 'kd' 'lc' 'lf' 'mb' 'nn' 'ot' 'p5' 'pb' 'pl' 'pw' 'py' 'q4' 'q9' 'qf' 'r6' 'ra' 'rl' 'rr' 'ru' 'rz' 'ta' 'te' 'ti' 'tp' 'u1' 'uy' 'w6' 'wb' 'wc' 'wd' 'wh' 'wv' 'wy' 'xo' 'xu' 'yd' 'yh' 'yo' 'yt' - f | 'a3' 'ac' 'af' 'ar' 'b4' 'cu' 'd6' 'dx' 'dz' 'eb' 'ej' 'ek' 'eo' 'es' 'eu' 'ff' 'gj' 'go' 'h6' 'ho' 'hx' 'i6' 'ih' 'ir' 'iy' 'jd' 'jg' 'jh' 'k5' 'n0' 'nn' 'oe' 'og' 'pj' 'pk' 'pq' 'px' 'q5' 'qc' 'qf' 'qg' 'qi' 'qm' 'qx' 'rb' 'rd' 're' 'rx' 'sn' 'sq' 'tp' 'uh' 'ul' 'um' 'uo' 'up' 'uq' 'uz' 'vt' 'wb' 'wj' 'wp' 'ws' 'wv' 'xk' 'xo' 'yv' 'yw' 'yx' - f | 'a9' 'ag' 'bh' 'dk' 'dq' 'e3' 'e7' 'ea' 'ee' 'ej' 'et' 'ez' 'f1' 'gh' 'gn' 'gr' 'hb' 'hf' 'hh' 'hz' 'ip' 'iw' 'j7' 'jh' 'ki' 'kp' 'kx' 'ml' 'nu' 'ov' 'ow' 'pg' 'ph' 'pn' 'po' 'pu' 'qd' 'qe' 'qr' 'qs' 'qv' 'r2' 'r3' 'rb' 'rd' 'ry' 's3' 'sd' 'sr' 'su' 'sz' 'tp' 'ty' 'uh' 'un' 'v0' 'v4' 'w0' 'wa' 'wk' 'wq' 'wx' 'xe' 'y6' 'yd' 'yf' 'yj' 'yl' 'zt' - f | 'ah' 'ai' 'aj' 'cb' 'cg' 'dd' 'dl' 'dp' 'eb' 'ee' 'ei' 'es' 'ey' 'f5' 'fm' 'fr' 'g0' 'gj' 'gp' 'gq' 'gw' 'hc' 'hf' 'ig' 'ij' 'iu' 'kg' 'ld' 'mr' 'nh' 'o2' 'pp' 'pz' 'qk' 'qr' 'qv' 'qz' 'r4' 'rb' 'rd' 'ro' 'rt' 'rw' 'rz' 'sr' 'sw' 'sy' 't6' 't9' 'tb' 'ts' 'tt' 'uo' 'vg' 'wd' 'wj' 'wl' 'wo' 'wp' 'wq' 'wt' 'ww' 'x8' 'yw' 'yx' 'z3' 'z9' 'zi' 'zz' - f | 'al' 'ar' 'ax' 'be' 'bu' 'dl' 'do' 'du' 'e5' 'es' 'ey' 'fb' 'fn' 'ga' 'he' 'hh' 'ho' 'i8' 'ic' 'in' 'iy' 'j1' 'j6' 'j9' 'jk' 'jm' 'ko' 'kv' 'kz' 'lk' 'ls' 'nb' 'oe' 'ou' 'pf' 'pj' 'pm' 'pu' 'py' 'q4' 'q7' 'qe' 'ql' 'qo' 'qr' 'qt' 'rh' 'rs' 'ry' 's3' 's6' 'sl' 'sq' 'tm' 'ud' 'uf' 'ur' 'vy' 'w5' 'w8' 'wp' 'wt' 'wx' 'xq' 'yc' 'yd' 'yi' 'yl' 'ym' - f | 'b0' 'b7' 'bh' 'bt' 'c0' 'cd' 'dv' 'e5' 'ed' 'ef' 'eq' 'ff' 'fj' 'fk' 'ga' 'gt' 'gx' 'hm' 'hx' 'i1' 'ih' 'il' 'j5' 'ja' 'jf' 'jp' 'jt' 'm2' 'nf' 'nt' 'of' 'oo' 'ou' 'p7' 'pa' 'pl' 'po' 'qa' 'qd' 'qr' 'qs' 'qt' 'qx' 'rb' 'rd' 're' 'rf' 'rv' 's0' 'sj' 'sw' 'tf' 'tu' 'tz' 'u2' 'ue' 'uq' 'ur' 'us' 'vw' 'w8' 'wc' 'wo' 'wt' 'x8' 'xo' 'yd' 'zi' 'zq' - f | '1i' '6c' 'ah' 'aq' 'ax' 'b4' 'cg' 'd5' 'da' 'do' 'eu' 'ex' 'ez' 'fa' 'go' 'gt' 'h5' 'h8' 'hi' 'i2' 'ib' 'il' 'in' 'is' 'iz' 'j0' 'j7' 'jn' 'jq' 'ku' 'kw' 'li' 'ls' 'n3' 'nc' 'nt' 'o6' 'oc' 'p4' 'p7' 'pc' 'qc' 'qi' 'qp' 'qs' 'qw' 'r3' 'rl' 'rq' 'ry' 's5' 'si' 'sm' 'ta' 'tr' 'ud' 'ut' 'uw' 'v0' 'w7' 'wg' 'wm' 'xi' 'yi' 'yl' 'yn' 'z1' 'z5' 'zk' 'zp' - f | '3y' 'a9' 'au' 'bp' 'ca' 'cf' 'cn' 'de' 'dh' 'dk' 'dw' 'ec' 'er' 'ey' 'fn' 'g1' 'hb' 'hd' 'hg' 'hi' 'hj' 'ib' 'if' 'iu' 'j7' 'jd' 'jg' 'jj' 'jx' 'k2' 'km' 'kv' 'ld' 'lo' 'mz' 'o3' 'ok' 'ot' 'pl' 'pn' 'pr' 'q0' 'q2' 'q7' 'qa' 'qc' 'qg' 'qm' 'qp' 'qx' 'rc' 'rq' 'rt' 'si' 'so' 'tp' 'tu' 'uj' 'vi' 'vx' 'w7' 'wb' 'wd' 'wm' 'ws' 'wt' 'wv' 'y9' 'yf' 'yq' - f | '7u' 'a4' 'ah' 'aj' 'al' 'cu' 'e1' 'fi' 'fq' 'fr' 'he' 'hi' 'hk' 'hn' 'hp' 'hs' 'ih' 'iw' 'je' 'k4' 'k6' 'kx' 'l1' 'lf' 'li' 'lj' 'lm' 'lp' 'ls' 'lu' 'ma' 'nr' 'o2' 'o4' 'oe' 'oh' 'os' 'ow' 'p7' 'pl' 'q3' 'qj' 'qt' 'qy' 'qz' 'r3' 'rc' 'rm' 'ro' 's0' 's8' 'so' 't7' 'th' 'ti' 'tm' 'tt' 'ut' 'v5' 'va' 've' 'w7' 'wc' 'wk' 'wl' 'wm' 'wq' 'wu' 'x0' 'zh' - f | '8l' 'au' 'ay' 'bn' 'bs' 'ch' 'co' 'cu' 'dq' 'dv' 'eq' 'ev' 'ff' 'fp' 'fr' 'fz' 'gb' 'gu' 'hb' 'he' 'hj' 'id' 'ih' 'jb' 'kg' 'lm' 'ls' 'nm' 'oe' 'ot' 'p6' 'pb' 'ps' 'q0' 'q8' 'qg' 'qh' 'qj' 'qo' 'qp' 'qr' 'qt' 'qz' 'r1' 're' 'rh' 'rp' 'ry' 's1' 's4' 'sc' 'sd' 'sn' 'tf' 'ty' 'u4' 'us' 'vt' 'vx' 'wc' 'wd' 'ws' 'wv' 'xp' 'y2' 'y5' 'y6' 'yy' 'zh' 'zx' - f | 'a2' 'al' 'av' 'b9' 'bd' 'bo' 'c8' 'cq' 'dz' 'ej' 'el' 'ep' 'ew' 'f3' 'f5' 'fr' 'ft' 'h2' 'i3' 'ic' 'id' 'iy' 'jd' 'ke' 'kf' 'kr' 'l3' 'lf' 'mg' 'mu' 'nj' 'o3' 'ob' 'ol' 'ov' 'pb' 'pj' 'pl' 'pp' 'qn' 'qz' 're' 'rg' 'rk' 'ru' 's3' 'sa' 'sh' 'sj' 'su' 'sw' 'tb' 'tk' 'tv' 'ue' 'uh' 'ul' 'un' 'vk' 'vu' 'w0' 'wa' 'wm' 'wo' 'wq' 'xa' 'xl' 'ya' 'yn' 'yo' - f | 'a3' 'a4' 'a5' 'bd' 'co' 'cq' 'd8' 'da' 'dn' 'do' 'du' 'dv' 'ed' 'ei' 'en' 'eo' 'es' 'et' 'f1' 'fa' 'ha' 'hr' 'i6' 'id' 'ie' 'if' 'ir' 'jx' 'kd' 'kh' 'mb' 'mq' 'mv' 'o6' 'oa' 'or' 'oy' 'pl' 'pr' 'q3' 'q8' 'qa' 'qb' 'qc' 'qd' 'qk' 'qs' 'ra' 'rc' 'rp' 'rz' 'se' 'tg' 'tj' 'u2' 'uq' 'uv' 'uy' 'vm' 'vz' 'wh' 'wu' 'xf' 'xs' 'yc' 'ye' 'yl' 'yn' 'z1' 'zf' - f | '18' 'at' 'c6' 'ca' 'dj' 'dl' 'dx' 'ec' 'ek' 'f4' 'fo' 'fs' 'fz' 'h8' 'hn' 'ik' 'il' 'j4' 'jn' 'ld' 'ln' 'ls' 'lx' 'nu' 'o6' 'os' 'ot' 'ox' 'pa' 'pe' 'pp' 'pw' 'q1' 'qc' 'qd' 'qh' 'qk' 'qq' 'qr' 'rq' 'rr' 'rt' 'rv' 'rz' 's5' 'sd' 'sh' 'sy' 't3' 'tu' 'ty' 'uj' 'uo' 'up' 'uu' 've' 'vl' 'vu' 'wa' 'wd' 'wo' 'wr' 'ws' 'ww' 'xk' 'y0' 'y6' 'yi' 'yq' 'yy' 'z3' - f | '1t' 'a7' 'aj' 'au' 'ca' 'cn' 'cw' 'dg' 'dp' 'ec' 'ei' 'en' 'ew' 'ez' 'f3' 'f8' 'hp' 'ht' 'hw' 'is' 'iv' 'jd' 'ji' 'kn' 'l4' 'lq' 'lz' 'm7' 'o6' 'oj' 'oz' 'p4' 'p7' 'po' 'pp' 'q2' 'qa' 'qj' 'qo' 'qt' 'qv' 'qw' 'qy' 'ra' 'rd' 'ri' 'rn' 'rr' 'ry' 's7' 'st' 'sz' 'tg' 'to' 'tu' 'tx' 'w2' 'w4' 'w5' 'wd' 'we' 'wg' 'wo' 'ws' 'xm' 'y5' 'yf' 'yl' 'ym' 'yr' 'yz' - f | '2e' '3u' 'aa' 'an' 'ap' 'bc' 'br' 'bx' 'cc' 'dt' 'ea' 'ei' 'ej' 'em' 'eo' 'ep' 'eq' 'es' 'et' 'ey' 'fb' 'fw' 'gh' 'gs' 'gv' 'hd' 'hg' 'hn' 'i7' 'it' 'jf' 'ka' 'kl' 'l8' 'la' 'm0' 'nu' 'o2' 'oc' 'oy' 'ph' 'po' 'pz' 'q2' 'qg' 'qh' 'qn' 'qp' 'qt' 'r7' 'r8' 'rd' 'rf' 'rj' 'rk' 'sm' 't1' 'tb' 'th' 'ub' 'ui' 'ul' 'um' 'uu' 've' 'w8' 'wj' 'wx' 'y8' 'zf' 'zn' - f | '2n' 'ar' 'b3' 'bc' 'bd' 'c0' 'c9' 'cb' 'cp' 'do' 'ee' 'eh' 'ep' 'f3' 'fb' 'fj' 'gg' 'gk' 'gm' 'h9' 'hk' 'hp' 'ht' 'i7' 'ij' 'iw' 'kx' 'm2' 'mt' 'mv' 'nj' 'ns' 'o7' 'oa' 'od' 'of' 'om' 'or' 'pg' 'pm' 'pu' 'qq' 'qw' 'qx' 'r0' 'rb' 'rg' 'rk' 'rv' 'se' 'sj' 'sp' 'su' 'tf' 'uu' 'v9' 've' 'vg' 'vm' 'w5' 'w6' 'w8' 'wa' 'wp' 'y5' 'y9' 'yk' 'yy' 'z2' 'zd' 'zw' - f | '4z' 'a8' 'ds' 'dv' 'dx' 'eq' 'f1' 'fs' 'gs' 'h9' 'hm' 'hp' 'hu' 'hz' 'i6' 'ip' 'is' 'j4' 'jf' 'k3' 'ku' 'lc' 'le' 'lj' 'nb' 'o6' 'ob' 'of' 'p6' 'pj' 'pm' 'ps' 'qc' 'qf' 'qh' 'ql' 'qr' 'qu' 'qx' 'r3' 'rf' 'ri' 's1' 's4' 'sr' 'st' 'sw' 'tb' 'tc' 'tg' 'tr' 'tz' 'ug' 'uq' 'uu' 'uv' 'uw' 'uz' 'vl' 'w2' 'w4' 'wq' 'wx' 'xe' 'xv' 'xx' 'y6' 'yg' 'yn' 'yp' 'yr' - f | '6x' 'a4' 'ae' 'as' 'd5' 'df' 'e9' 'ek' 'ew' 'ex' 'ez' 'fa' 'fe' 'fr' 'gk' 'hb' 'hg' 'hl' 'hp' 'id' 'it' 'ix' 'jc' 'jg' 'jk' 'jm' 'js' 'ju' 'ln' 'lq' 'mo' 'ms' 'o7' 'od' 'oi' 'oo' 'pn' 'qd' 'qt' 'qv' 'r0' 'rc' 'rj' 'rk' 'rn' 'rp' 'rx' 'rz' 'sc' 'sg' 'sk' 'so' 'ti' 'tn' 'to' 'tr' 'tz' 'uk' 'um' 'ut' 'v1' 'vr' 'wo' 'wr' 'wu' 'wz' 'xn' 'xu' 'y4' 'yg' 'z2' - f | '6y' 'aw' 'az' 'cn' 'cs' 'cx' 'd4' 'di' 'dl' 'e7' 'eg' 'eh' 'eo' 'ep' 'et' 'ew' 'ex' 'ey' 'fv' 'fz' 'gu' 'gv' 'hg' 'hl' 'hm' 'iv' 'jc' 'lb' 'me' 'nc' 'nz' 'o2' 'ox' 'pn' 'po' 'pw' 'q4' 'q5' 'qg' 'qq' 'qv' 'qz' 'r7' 're' 'rl' 'rq' 'rs' 'rx' 'sa' 'se' 'ti' 'tj' 'tn' 'tz' 'u6' 'uq' 'ur' 'us' 'v9' 'we' 'wn' 'wp' 'wr' 'ws' 'xo' 'ya' 'ye' 'yg' 'yx' 'zj' 'zl' - f | '8j' 'ao' 'bc' 'bh' 'co' 'cz' 'di' 'dq' 'dr' 'e1' 'ec' 'ei' 'el' 'et' 'eu' 'ex' 'f8' 'g7' 'gl' 'hq' 'hw' 'ib' 'kh' 'kn' 'kt' 'lc' 'md' 'n7' 'oe' 'p0' 'pg' 'pl' 'pm' 'po' 'pr' 'q0' 'q6' 'ql' 'qv' 'qy' 'r7' 'ra' 're' 'rq' 'ru' 'ry' 'sm' 'sn' 't4' 't5' 'tw' 'ty' 'u7' 'ud' 'uh' 'um' 'us' 'ux' 'v0' 'v7' 'vn' 'w6' 'we' 'wi' 'wm' 'x1' 'xo' 'xz' 'yn' 'yo' 'yz' - f | 'a9' 'b8' 'de' 'dl' 'eg' 'fb' 'fi' 'fm' 'gj' 'hp' 'hx' 'if' 'ig' 'ii' 'ik' 'io' 'iw' 'ix' 'j1' 'j3' 'j8' 'ji' 'ki' 'kt' 'ld' 'm8' 'mi' 'mj' 'mx' 'mz' 'n2' 'nk' 'oe' 'ok' 'oq' 'os' 'ot' 'pj' 'q4' 'qe' 'ql' 'qp' 'qq' 'r4' 'rl' 'rq' 'rx' 'sf' 'ss' 'td' 'ti' 'tl' 'u4' 'u5' 'uq' 'ux' 'v4' 'vl' 'vs' 'wb' 'wc' 'wg' 'wj' 'wn' 'ww' 'x9' 'xa' 'ye' 'yg' 'yl' 'yn' - f | 'ab' 'ap' 'ay' 'b6' 'bg' 'bm' 'bq' 'br' 'ce' 'co' 'dt' 'e4' 'ef' 'ej' 'ek' 'ep' 'fj' 'fq' 'fu' 'g3' 'gg' 'gp' 'hk' 'i3' 'i9' 'je' 'k7' 'ku' 'li' 'lq' 'lt' 'lx' 'mc' 'mz' 'n7' 'nl' 'o1' 'of' 'os' 'pm' 'qc' 'ql' 'qs' 'qw' 'r6' 'rf' 'rj' 'rp' 'ru' 'rx' 'rz' 'tl' 'tw' 'ty' 'u1' 'u3' 'ud' 'un' 'uw' 'vu' 'w6' 'wf' 'wl' 'wq' 'xh' 'xm' 'yc' 'yh' 'yr' 'yw' 'z9' - f | 'ad' 'af' 'ar' 'b0' 'bw' 'c4' 'cn' 'do' 'e0' 'e4' 'em' 'eo' 'fn' 'ga' 'gg' 'gy' 'hf' 'ht' 'id' 'ig' 'ik' 'iv' 'j6' 'mi' 'n5' 'ng' 'ob' 'og' 'ou' 'oy' 'p4' 'pd' 'pg' 'pk' 'po' 'pt' 'pw' 'q3' 'q5' 'qb' 'qr' 'qt' 'r3' 'rc' 'rd' 'rl' 's0' 'sy' 't9' 'tc' 'tm' 'tq' 'ub' 'up' 'uv' 'ux' 'vm' 'vv' 'vw' 'wc' 'wg' 'wk' 'wm' 'x0' 'xp' 'xr' 'xv' 'xx' 'yg' 'ym' 'yw' - f | 'at' 'bm' 'd0' 'd5' 'eg' 'ei' 'ek' 'eq' 'er' 'eu' 'ez' 'fs' 'gh' 'hc' 'ho' 'ix' 'ko' 'kq' 'l1' 'll' 'mz' 'ob' 'ou' 'p2' 'pi' 'pl' 'ps' 'pt' 'q0' 'q5' 'qa' 'qg' 'qj' 'qm' 'qq' 'qt' 'rf' 'ri' 'rm' 'ru' 'rv' 'rx' 'ry' 's4' 't4' 'td' 'tn' 'tq' 'tx' 'u3' 'up' 'uq' 'vn' 'wb' 'wf' 'wk' 'wr' 'wv' 'wy' 'xh' 'xx' 'y3' 'yc' 'ye' 'ys' 'za' 'zd' 'zo' 'zs' 'zv' 'zy' - f | '0p' 'ab' 'as' 'az' 'b5' 'bl' 'cn' 'cr' 'ct' 'cu' 'dq' 'dr' 'em' 'eq' 'fe' 'fj' 'fk' 'fy' 'gn' 'gx' 'h9' 'hg' 'hk' 'hr' 'io' 'iy' 'jh' 'la' 'lb' 'll' 'ln' 'lq' 'me' 'mp' 'mr' 'mv' 'ns' 'od' 'op' 'os' 'ov' 'po' 'pv' 'qa' 'qn' 'qp' 'qs' 'qt' 'r0' 'rc' 'rd' 'rl' 's5' 'si' 't7' 'tc' 'th' 'u0' 'um' 'uz' 'vg' 'vo' 'wa' 'wp' 'wu' 'xk' 'yg' 'yh' 'yi' 'yo' 'yy' 'zy' - f | '10' 'ac' 'as' 'av' 'b6' 'bb' 'cj' 'd3' 'd8' 'dt' 'eb' 'ey' 'ez' 'fm' 'g8' 'gf' 'gs' 'hn' 'hq' 'ib' 'ii' 'j0' 'jb' 'k4' 'l5' 'ld' 'mg' 'mu' 'nz' 'oa' 'ou' 'pn' 'q1' 'qa' 'qg' 'qj' 'qm' 'qn' 'qs' 'qx' 'qy' 'rj' 'rm' 'rr' 'ry' 's0' 's7' 't4' 't6' 'tb' 'td' 'u0' 'ua' 'ut' 'ux' 'uz' 'v1' 'v9' 'vd' 'vz' 'wc' 'wj' 'wo' 'ws' 'ww' 'x9' 'xu' 'y7' 'yq' 'yv' 'zw' 'zy' - f | '11' '3o' '7a' 'au' 'bc' 'bx' 'cg' 'dz' 'e5' 'ea' 'eb' 'ee' 'eg' 'eo' 'er' 'eu' 'g2' 'gq' 'gx' 'i4' 'in' 'ip' 'iv' 'k4' 'kd' 'kw' 'lf' 'ls' 'oq' 'ot' 'oz' 'p7' 'ph' 'pk' 'ps' 'qa' 'qd' 'qf' 'qi' 'qj' 'qr' 'qt' 'r4' 'rb' 'rd' 'rl' 'th' 'tl' 'tx' 'uc' 'uj' 'v6' 'vj' 'vz' 'we' 'wj' 'wl' 'wm' 'wp' 'wy' 'wz' 'xj' 'xk' 'xl' 'ya' 'yj' 'yl' 'yo' 'yw' 'zs' 'zv' 'zw' - f | '5h' 'ak' 'al' 'aq' 'cw' 'd7' 'dm' 'ec' 'ee' 'ef' 'el' 'f4' 'f5' 'f8' 'fh' 'fr' 'fu' 'gh' 'hk' 'ir' 'ix' 'k0' 'k2' 'ka' 'ku' 'lg' 'lr' 'm8' 'mf' 'nq' 'of' 'ph' 'pr' 'px' 'q2' 'qf' 'qh' 'qk' 'qn' 'qq' 'qs' 'qv' 'qx' 'qy' 'qz' 're' 'rh' 'ro' 'rx' 'sa' 'sh' 'sk' 'tb' 'u1' 'ud' 'uo' 'us' 'uw' 'vg' 'vp' 'w3' 'wb' 'wc' 'wf' 'wg' 'wi' 'wk' 'yr' 'ys' 'yw' 'zw' 'zz' - f | 'ae' 'ak' 'ax' 'cm' 'cw' 'cx' 'df' 'dm' 'dw' 'eb' 'ef' 'ei' 'el' 'f1' 'fn' 'gu' 'hf' 'hk' 'ik' 'iw' 'jd' 'ju' 'jz' 'k7' 'ku' 'lq' 'mf' 'mw' 'oa' 'od' 'oe' 'ou' 'ow' 'pc' 'ph' 'pw' 'q0' 'q2' 'qd' 'qq' 'qw' 'qx' 'rj' 'rk' 'rn' 'rx' 's2' 'sm' 'sx' 't9' 'ti' 'tu' 'tw' 'u3' 'ud' 'wf' 'wm' 'wt' 'xl' 'xo' 'xs' 'yh' 'yi' 'ym' 'yr' 'yu' 'yw' 'z2' 'za' 'zf' 'zl' 'zz' - f | 'ae' 'ap' 'bi' 'd7' 'ee' 'ej' 'ek' 'ev' 'ew' 'fb' 'gm' 'hf' 'ho' 'hz' 'i6' 'ib' 'id' 'il' 'im' 'io' 'ip' 'ir' 'iv' 'j2' 'jf' 'jl' 'jo' 'kh' 'kk' 'kt' 'lr' 'm4' 'mi' 'nm' 'ns' 'og' 'pv' 'pw' 'q4' 'qd' 'qi' 'r6' 'r8' 'rn' 'rp' 'si' 't7' 'ta' 'td' 'te' 'ti' 'tm' 'u6' 'ub' 'vu' 'w6' 'w8' 'wa' 'wb' 'wc' 'wd' 'wf' 'wh' 'wn' 'wt' 'wz' 'y5' 'ya' 'yg' 'yk' 'yn' 'z3' - f | 'as' 'b1' 'bc' 'br' 'cd' 'dw' 'e2' 'ec' 'ew' 'f1' 'f2' 'f6' 'g0' 'gi' 'gy' 'hf' 'hk' 'if' 'ii' 'is' 'iy' 'j2' 'jp' 'kl' 'ku' 'l4' 'lg' 'lp' 'lv' 'lw' 'nd' 'ng' 'oo' 'q4' 'q6' 'q9' 'qc' 'qh' 'ql' 'qm' 'qo' 'qx' 'qz' 're' 'ro' 'sm' 't5' 'th' 'tt' 'ul' 'um' 'v0' 'vb' 'vf' 'vx' 'w9' 'wc' 'we' 'wp' 'xi' 'xl' 'xt' 'xv' 'y3' 'y6' 'ye' 'yg' 'yq' 'yw' 'yx' 'zs' 'zu' - f | '3y' 'a1' 'ay' 'cn' 'd3' 'dc' 'dh' 'e9' 'ef' 'ew' 'f9' 'fd' 'fg' 'ft' 'h6' 'hs' 'hu' 'hz' 'i0' 'ib' 'ip' 'iu' 'jw' 'kf' 'kp' 'kw' 'li' 'lp' 'mg' 'mj' 'mz' 'ng' 'oc' 'od' 'om' 'ou' 'ov' 'p8' 'pi' 'q8' 'qe' 'qf' 'qh' 'qj' 'qo' 'qt' 'qv' 'qz' 'r2' 'r3' 'rc' 'rm' 't4' 'ty' 'tz' 'u6' 'ua' 'ut' 'v3' 'vj' 'w0' 'w6' 'wi' 'wj' 'wq' 'wt' 'wu' 'xe' 'xv' 'xy' 'y3' 'yv' 'zw' - f | '4a' '56' 'ae' 'ao' 'ay' 'bn' 'bx' 'c9' 'cl' 'd0' 'd7' 'en' 'et' 'fj' 'fk' 'fu' 'g4' 'ha' 'ht' 'hv' 'ih' 'ij' 'ir' 'iw' 'k1' 'k7' 'kq' 'kw' 'lg' 'm5' 'me' 'nw' 'oj' 'ou' 'p6' 'pl' 'pq' 'pt' 'qc' 'qg' 'qk' 'ql' 'qm' 'qo' 'qq' 'rj' 's1' 'sd' 'sq' 'sz' 'tb' 'td' 'tr' 'tw' 'ug' 'uj' 'uo' 'ut' 'uy' 'wj' 'wk' 'ws' 'wz' 'x2' 'xx' 'xy' 'y1' 'y4' 'yc' 'yk' 'yt' 'yx' 'zp' - f | 'a2' 'a4' 'ac' 'ag' 'ao' 'ay' 'ce' 'di' 'dm' 'dr' 'dz' 'e9' 'eg' 'ej' 'el' 'em' 'eq' 'et' 'ey' 'fa' 'fw' 'fz' 'gg' 'gh' 'gp' 'gr' 'h6' 'hj' 'hk' 'i7' 'id' 'ik' 'iu' 'j2' 'kc' 'l1' 'lh' 'm5' 'm9' 'mj' 'mr' 'mx' 'ok' 'ot' 'ov' 'oz' 'p5' 'q0' 'q1' 'qe' 'qg' 'r2' 'rj' 'rk' 'rw' 'sa' 't3' 't6' 't9' 'te' 'tf' 'tj' 'tk' 'u4' 'wa' 'wf' 'wu' 'wy' 'yg' 'yj' 'ys' 'zk' 'zy' - f | '2b' '2e' 'ao' 'ap' 'au' 'bo' 'by' 'cr' 'do' 'du' 'dy' 'e7' 'eb' 'eh' 'em' 'ey' 'f6' 'ff' 'fu' 'gc' 'gi' 'gk' 'h1' 'hp' 'hs' 'hy' 'ia' 'ic' 'ig' 'ik' 'im' 'je' 'jf' 'ji' 'jr' 'l5' 'lf' 'lp' 'mv' 'ne' 'nt' 'oa' 'os' 'pj' 'po' 'q9' 'qd' 'qe' 'qf' 'qw' 'qy' 'ra' 'rg' 'rk' 'rp' 'rq' 'rx' 'sb' 'si' 'sn' 'ta' 'ux' 'v1' 'vd' 'wa' 'wk' 'wr' 'wu' 'xo' 'yg' 'yl' 'yz' 'zi' 'zt' - f | '2l' 'a5' 'ah' 'ak' 'ar' 'be' 'e6' 'eh' 'ge' 'gj' 'gn' 'gt' 'gy' 'ia' 'ii' 'iw' 'ix' 'jb' 'k9' 'kd' 'ke' 'kh' 'kv' 'lm' 'ly' 'me' 'mt' 'nb' 'np' 'o5' 'oe' 'of' 'og' 'pd' 'pf' 'pm' 'pt' 'pw' 'q3' 'qc' 'qe' 'qg' 'qh' 'qk' 'ql' 'qs' 'qt' 'qx' 'qz' 'rr' 'rw' 'rx' 'ry' 'sk' 'sr' 'su' 'sv' 'sz' 'ug' 'uk' 'uq' 'vg' 'w7' 'wb' 'wn' 'wr' 'ws' 'wz' 'x6' 'yg' 'yj' 'yo' 'zb' 'zx' - f | '3h' '4h' '93' 'ak' 'ao' 'bq' 'cw' 'db' 'dx' 'eb' 'ef' 'el' 'eu' 'ex' 'fc' 'fg' 'fo' 'fr' 'fs' 'fx' 'g5' 'gl' 'go' 'hs' 'i0' 'ii' 'ix' 'j3' 'jc' 'ke' 'l2' 'lf' 'lo' 'm6' 'ms' 'ne' 'oi' 'ox' 'p6' 'pb' 'pr' 'q9' 'qa' 'qi' 'qj' 'qq' 'qs' 'qu' 'qw' 're' 'rq' 's0' 'sa' 'se' 'sk' 'sx' 'tj' 'tk' 'u2' 'ua' 'uh' 'un' 'vy' 'wf' 'wh' 'wj' 'wq' 'wv' 'xl' 'xq' 'yf' 'yi' 'yw' 'z3' - f | 'a6' 'ac' 'ao' 'au' 'cf' 'co' 'cr' 'd9' 'da' 'ds' 'du' 'e4' 'ea' 'ew' 'f1' 'fx' 'hr' 'hu' 'ic' 'id' 'ii' 'in' 'iq' 'iy' 'j3' 'jb' 'ji' 'jl' 'kf' 'mi' 'mp' 'o3' 'oe' 'oj' 'on' 'p5' 'ph' 'pk' 'q1' 'q9' 'qa' 'qs' 'qu' 'qv' 'r9' 'rc' 'rj' 'rv' 's1' 'se' 'sl' 'su' 't2' 't5' 'tk' 'u8' 'uv' 'v9' 'vd' 'vi' 'w0' 'w3' 'we' 'wh' 'wm' 'wp' 'xm' 'y0' 'y1' 'y8' 'yf' 'yo' 'yw' 'zv' - f | 'a0' 'ad' 'ak' 'ao' 'au' 'b0' 'dg' 'dt' 'e9' 'em' 'fg' 'fk' 'fn' 'gq' 'h7' 'hf' 'hm' 'ia' 'id' 'ig' 'iv' 'kv' 'l1' 'lm' 'lz' 'm1' 'mw' 'mz' 'na' 'nh' 'nl' 'nn' 'o1' 'o3' 'om' 'p2' 'p9' 'pj' 'pw' 'pz' 'qk' 'qm' 'qy' 'rs' 'ru' 'ry' 'sf' 'su' 'sw' 'sx' 'td' 'tl' 'tp' 'tw' 'u1' 'ug' 'un' 'uo' 'uq' 'ur' 'v5' 'vk' 'wd' 'wf' 'wj' 'wq' 'wy' 'xg' 'xk' 'xn' 'xq' 'yb' 'z0' 'zt' 'zu' - f | 'a2' 'ag' 'cz' 'd0' 'd3' 'da' 'di' 'ds' 'e5' 'e6' 'e7' 'ej' 'em' 'ex' 'ff' 'fq' 'gm' 'go' 'gt' 'gv' 'gx' 'ho' 'hv' 'i8' 'ic' 'ii' 'il' 'im' 'it' 'ix' 'j1' 'ja' 'jd' 'js' 'kw' 'l6' 'le' 'lk' 'ln' 'mt' 'my' 'ns' 'ol' 'op' 'os' 'p0' 'pu' 'pv' 'pz' 'q4' 'q5' 'qe' 'qh' 'ql' 'qx' 'qy' 'r1' 'rk' 'rr' 'sb' 'sn' 'te' 'tt' 'ui' 'v6' 'w6' 'we' 'ws' 'wy' 'xt' 'xu' 'yf' 'yq' 'yz' 'zy' - f | '1l' '2t' '2z' 'af' 'az' 'be' 'br' 'cm' 'cu' 'cy' 'd2' 'd4' 'dd' 'dx' 'ec' 'ed' 'g2' 'gs' 'gu' 'id' 'ig' 'in' 'it' 'jh' 'jl' 'l6' 'ld' 'lg' 'lr' 'ly' 'nf' 'nj' 'ob' 'ot' 'p4' 'p8' 'pe' 'ph' 'q5' 'qa' 'qd' 'qe' 'qi' 'qo' 'qv' 'qz' 'ra' 'ri' 'rl' 'rr' 's7' 'sj' 'sx' 't0' 'tj' 'to' 'u2' 'ui' 'uq' 'ut' 'uw' 'vg' 'vs' 'w2' 'wa' 'wi' 'wl' 'wr' 'wu' 'ww' 'x7' 'xm' 'ym' 'yn' 'yp' 'zh' - f | 'a0' 'a7' 'ad' 'ae' 'ah' 'ay' 'b8' 'bh' 'dc' 'di' 'do' 'e5' 'ea' 'eb' 'ep' 'ev' 'fn' 'gq' 'gr' 'gs' 'h8' 'hc' 'hj' 'i3' 'ih' 'it' 'iw' 'ja' 'jf' 'kc' 'l8' 'lp' 'lx' 'ly' 'm1' 'og' 'oy' 'p7' 'pp' 'q7' 'qa' 'qm' 'qq' 'qr' 'qu' 'r3' 'rd' 'rg' 'rj' 'rw' 'si' 'sq' 'ss' 't0' 'tb' 'tg' 'tl' 'to' 'tp' 'tx' 'u9' 'ub' 'um' 'up' 'ux' 'vc' 'w0' 'w2' 'w5' 'wl' 'wy' 'xg' 'yb' 'yg' 'yh' 'za' - f | 'af' 'as' 'at' 'aw' 'ax' 'ay' 'az' 'b2' 'bf' 'bl' 'ck' 'cs' 'df' 'dn' 'dv' 'ei' 'ek' 'ev' 'fg' 'fm' 'h0' 'hb' 'hk' 'i0' 'ib' 'if' 'ir' 'lk' 'm5' 'mr' 'np' 'om' 'p5' 'p7' 'pl' 'pq' 'q3' 'qh' 'qi' 'qj' 'qo' 'qp' 'qs' 'qt' 'qu' 'qv' 'qy' 'ra' 'sh' 'sm' 'so' 't2' 'ta' 'ti' 'tv' 'tz' 'u1' 'ug' 'um' 'v5' 'vd' 'w1' 'wn' 'wp' 'wr' 'ws' 'ww' 'xk' 'xx' 'y7' 'yf' 'yh' 'yk' 'yt' 'zr' 'zv' - f | 'ai' 'ak' 'as' 'ax' 'b8' 'bd' 'bq' 'bv' 'd1' 'd8' 'dl' 'e9' 'ew' 'ez' 'fz' 'gj' 'gu' 'hk' 'hq' 'i2' 'ie' 'ip' 'iq' 'is' 'iz' 'jf' 'k0' 'kk' 'l6' 'md' 'mx' 'na' 'nf' 'o5' 'ol' 'p3' 'pe' 'q2' 'qf' 'qj' 'qm' 'qn' 'qs' 'qv' 'r2' 'ra' 'rv' 'ry' 's1' 's5' 'si' 't0' 'tc' 'te' 'tn' 'tq' 'tz' 'u1' 'uj' 'ut' 'w3' 'wa' 'wd' 'wh' 'wj' 'wo' 'wu' 'wv' 'ww' 'xk' 'xo' 'yi' 'yk' 'yl' 'zb' 'zw' - f | '3b' '4p' 'ae' 'aj' 'ap' 'b3' 'bb' 'c0' 'cc' 'cf' 'cn' 'dz' 'e1' 'e9' 'eo' 'ew' 'ey' 'fk' 'fo' 'gd' 'gp' 'hb' 'i8' 'ia' 'ib' 'ie' 'ij' 'iq' 'ir' 'ix' 'jo' 'kp' 'lc' 'ld' 'lp' 'ml' 'on' 'p8' 'pd' 'pf' 'pi' 'pn' 'pr' 'pt' 'pw' 'qe' 'qi' 'qj' 'qp' 'qr' 'qw' 'qz' 'r0' 'rj' 'rn' 'ro' 'rq' 'rr' 's3' 'sg' 'sz' 'tn' 'tw' 'ty' 'ui' 'uj' 'vj' 'vr' 'w5' 'w9' 'wa' 'wp' 'xt' 'ya' 'ym' 'z0' 'zr' - f | 'a7' 'ag' 'aq' 'aw' 'az' 'bf' 'bg' 'ce' 'cp' 'cx' 'dc' 'ek' 'en' 'es' 'fj' 'gb' 'hr' 'hs' 'ie' 'ik' 'is' 'jl' 'jr' 'kc' 'ku' 'l5' 'lj' 'lq' 'lr' 'nu' 'og' 'oj' 'os' 'oy' 'p1' 'p6' 'pc' 'pk' 'pr' 'pu' 'px' 'py' 'q1' 'q4' 'qb' 'qc' 'ql' 'qo' 'qv' 'qz' 'r9' 'ra' 'rg' 'rp' 'sq' 'ts' 'tx' 'u8' 'ue' 'ui' 'uj' 'uk' 'up' 'v4' 'vg' 'vn' 'w2' 'w9' 'wa' 'wk' 'wt' 'y0' 'y9' 'yc' 'ym' 'ys' 'zh' - f | 'aq' 'bo' 'cx' 'dl' 'dm' 'ed' 'ee' 'ei' 'er' 'eu' 'f4' 'fe' 'fw' 'g2' 'gj' 'h7' 'hv' 'im' 'j8' 'jf' 'kl' 'la' 'lj' 'mo' 'oc' 'oh' 'oi' 'ol' 'pa' 'pb' 'pf' 'pk' 'po' 'q9' 'qf' 'qj' 'qq' 'qv' 'r8' 're' 'rg' 'rh' 'rj' 'rr' 'ru' 'ry' 's8' 'sd' 'sg' 'sj' 'sk' 'so' 'sv' 't3' 'tz' 'u5' 'ua' 'uk' 'um' 'vi' 'vt' 'wb' 'we' 'wk' 'wn' 'wt' 'wu' 'wz' 'xk' 'xz' 'yi' 'yl' 'yz' 'z9' 'zd' 'zu' 'zw' - f | '3w' 'aa' 'ad' 'cj' 'cu' 'cv' 'dv' 'ei' 'ej' 'ep' 'er' 'fc' 'fd' 'g5' 'ga' 'go' 'gr' 'gs' 'hq' 'hx' 'hy' 'i1' 'i5' 'ie' 'ip' 'jh' 'jn' 'jq' 'k7' 'ks' 'l0' 'l6' 'l9' 'lm' 'm5' 'mj' 'ng' 'nh' 'o8' 'od' 'on' 'pq' 'q3' 'q8' 'qb' 'qc' 'qf' 'qp' 'qs' 'r1' 'ra' 'rj' 'rw' 'si' 'sp' 't6' 'ta' 'tc' 'tk' 'tm' 'ty' 'ua' 'ud' 'ug' 'v7' 'vg' 'vm' 'w3' 'wc' 'wi' 'wp' 'wy' 'xk' 'xv' 'yi' 'ym' 'ys' 'zl' - f | '5c' 'ag' 'ak' 'ao' 'ap' 'at' 'bo' 'br' 'bs' 'bw' 'cv' 'e9' 'et' 'ex' 'ez' 'fj' 'fu' 'fz' 'gm' 'gq' 'gu' 'h8' 'hl' 'i7' 'ic' 'ik' 'il' 'is' 'j1' 'jc' 'k2' 'k3' 'k6' 'k7' 'kf' 'km' 'kr' 'lj' 'mb' 'md' 'nf' 'om' 'ow' 'p4' 'pk' 'pw' 'q2' 'qe' 'qh' 'qn' 'qq' 'qu' 'qz' 'r0' 'ra' 'rp' 'ru' 'rw' 'rz' 'sv' 'ta' 'ti' 'tq' 'ua' 'up' 'us' 'ut' 'uz' 'vd' 'wl' 'wq' 'xg' 'xk' 'y0' 'yd' 'yw' 'zd' 'zq' - f | 'a0' 'a8' 'b4' 'b9' 'bb' 'cb' 'cn' 'cq' 'ds' 'e2' 'eb' 'ex' 'ez' 'fa' 'fu' 'fz' 'ge' 'gy' 'h0' 'hj' 'ht' 'hu' 'ig' 'in' 'iq' 'is' 'iu' 'jg' 'le' 'ln' 'lr' 'nj' 'nu' 'oe' 'oo' 'ow' 'oz' 'pf' 'ph' 'pj' 'ps' 'pu' 'pv' 'q0' 'q4' 'qf' 'qm' 'qn' 'qo' 'qq' 'qs' 'qw' 'r2' 'r3' 'ra' 'rk' 's7' 'sa' 'sp' 'tl' 'ue' 'ui' 'vo' 'vs' 'wj' 'wk' 'wn' 'wv' 'ww' 'x0' 'xg' 'xh' 'xx' 'y0' 'yd' 'yr' 'zg' 'zn' - f | '18' '5j' '6y' 'ax' 'bw' 'c5' 'de' 'dh' 'dl' 'do' 'dx' 'ek' 'el' 'en' 'et' 'ez' 'f1' 'fe' 'fw' 'ge' 'h1' 'h9' 'ha' 'hb' 'hl' 'it' 'jy' 'kl' 'ky' 'lo' 'nr' 'o3' 'o9' 'p0' 'pe' 'pg' 'ph' 'q1' 'q5' 'qd' 'qg' 'qh' 'qi' 'qj' 'qp' 'qq' 'qr' 'qv' 'qx' 'r0' 'rd' 're' 'rj' 'rm' 'rn' 'rq' 'rv' 'se' 'sv' 'to' 'tz' 'uo' 'v1' 'vm' 'vr' 'wa' 'we' 'wf' 'wh' 'wp' 'wt' 'wy' 'xe' 'xh' 'xz' 'y6' 'yn' 'zm' 'zy' - f | '1s' '95' 'ac' 'aq' 'cb' 'ch' 'cq' 'ct' 'cz' 'dg' 'dj' 'eb' 'ed' 'ee' 'eg' 'en' 'eo' 'ep' 'es' 'fc' 'fl' 'fp' 'gu' 'gw' 'hx' 'i0' 'i2' 'ig' 'ih' 'il' 'in' 'iu' 'iy' 'iz' 'jc' 'k7' 'ka' 'kl' 'km' 'kn' 'lz' 'mx' 'n6' 'nc' 'og' 'pt' 'pw' 'q0' 'qa' 'qe' 'qf' 'ql' 'qm' 'qp' 'qt' 'r7' 'rp' 'ru' 'rw' 'sb' 'sd' 't0' 't7' 'ta' 'tl' 'tn' 'tv' 'ty' 'ui' 'vx' 'wa' 'wc' 'wm' 'wp' 'wy' 'xi' 'xj' 'xk' 'yz' - f | '2o' '2w' 'ac' 'an' 'bb' 'be' 'c3' 'db' 'dj' 'dm' 'dw' 'eb' 'ed' 'eh' 'ew' 'ex' 'fb' 'fi' 'g2' 'gh' 'gv' 'h6' 'hw' 'id' 'ie' 'iz' 'j8' 'jk' 'jv' 'kd' 'lk' 'm8' 'ml' 'mr' 'mx' 'np' 'oe' 'on' 'oz' 'pj' 'pk' 'pm' 'pu' 'qb' 'ql' 'qv' 'qx' 'r0' 're' 'rj' 'rq' 'rw' 't3' 'ta' 'tc' 'td' 'th' 'to' 'tu' 'tx' 'ty' 'tz' 'u3' 'uf' 'vp' 'vz' 'wd' 'wh' 'wk' 'wl' 'wx' 'wy' 'wz' 'xe' 'xm' 'xs' 'ye' 'zd' 'zk' - f | '2v' '7g' 'a1' 'ar' 'bw' 'cs' 'dt' 'ee' 'eg' 'f4' 'fd' 'fl' 'g0' 'ge' 'gx' 'hf' 'hk' 'ht' 'i7' 'il' 'jy' 'ka' 'kl' 'lb' 'lm' 'lv' 'mu' 'nk' 'ns' 'nw' 'oe' 'og' 'oj' 'ol' 'ou' 'pk' 'q2' 'q3' 'qi' 'qn' 'qo' 'qs' 'qy' 'r5' 'rh' 'rj' 'rm' 'rq' 'rr' 'rs' 'rt' 'ru' 'rv' 'ss' 'th' 'tj' 'uj' 'ul' 'um' 'un' 'uo' 'uv' 'w2' 'w6' 'wf' 'wh' 'wk' 'wo' 'wx' 'y4' 'y5' 'yb' 'yn' 'yo' 'ys' 'yz' 'zb' 'zt' 'zw' - f | 'ab' 'ah' 'ax' 'bd' 'ca' 'dh' 'e3' 'ea' 'ed' 'ef' 'en' 'eo' 'er' 'ev' 'ex' 'ez' 'f5' 'fh' 'fo' 'fv' 'ga' 'gb' 'gk' 'id' 'ik' 'in' 'ir' 'jp' 'js' 'jv' 'kf' 'kr' 'lx' 'mu' 'mz' 'n5' 'od' 'on' 'pr' 'pt' 'pv' 'qb' 'qe' 'qj' 'ql' 'qq' 'qu' 'qw' 'rd' 'rl' 'rz' 's4' 'sv' 'ta' 'tj' 'tk' 'u8' 'ui' 'uj' 'uk' 'um' 'ux' 'uz' 'v9' 'vh' 'vl' 'w7' 'wb' 'wi' 'wm' 'ws' 'xi' 'ye' 'yg' 'yr' 'yw' 'zj' 'zn' 'zs' - f | '17' 'bv' 'c5' 'cn' 'd0' 'di' 'dm' 'dz' 'ec' 'ef' 'et' 'ev' 'ew' 'fa' 'fb' 'fh' 'fw' 'fy' 'g8' 'he' 'hf' 'hp' 'hu' 'hz' 'i2' 'ig' 'ix' 'jy' 'lt' 'mi' 'nm' 'nq' 'o5' 'oa' 'od' 'oi' 'oo' 'ox' 'pb' 'po' 'qb' 'qc' 'qf' 'qr' 'qs' 'qt' 'qw' 'qx' 'r0' 'rb' 'rf' 'rh' 'rk' 'ry' 'sb' 'sf' 'sh' 'st' 'tb' 'tj' 'tn' 'tq' 'tu' 'ty' 'u9' 'ud' 'ut' 'uw' 'ux' 'w4' 'wi' 'xm' 'ya' 'yl' 'ys' 'yt' 'yv' 'yy' 'zb' 'zv' - f | '19' '1t' 'aa' 'ah' 'ak' 'an' 'aq' 'bx' 'cc' 'dd' 'ed' 'ee' 'ei' 'ej' 'en' 'er' 'es' 'eu' 'fj' 'fs' 'fy' 'gd' 'gs' 'hw' 'ie' 'ig' 'ix' 'jc' 'jj' 'jk' 'jq' 'kb' 'kv' 'li' 'mr' 'no' 'nq' 'o9' 'oo' 'os' 'oy' 'p2' 'pd' 'ph' 'pn' 'pp' 'ql' 'qr' 'qy' 'r1' 'rb' 'rd' 'rn' 'ru' 's9' 'sf' 'tk' 'to' 'u1' 'u5' 'ub' 'ud' 'uf' 'vh' 'vx' 'w1' 'w8' 'wg' 'wn' 'wq' 'wu' 'wy' 'xc' 'xm' 'xw' 'y8' 'yk' 'yr' 'z3' 'zm' - f | '1n' '2h' 'at' 'ax' 'c0' 'cn' 'dc' 'df' 'dg' 'e1' 'e5' 'ea' 'eq' 'ex' 'ez' 'f7' 'f8' 'fa' 'gt' 'gv' 'gy' 'hb' 'i3' 'i8' 'id' 'iw' 'ix' 'jc' 'jg' 'k0' 'kh' 'ky' 'kz' 'lj' 'lm' 'lq' 'mj' 'o8' 'og' 'op' 'ow' 'p5' 'p9' 'qc' 'qe' 'qf' 'qg' 'qo' 'qq' 'qv' 'qz' 'rq' 'rt' 'ru' 's2' 's5' 'sf' 'sl' 'sm' 'st' 'sw' 'tc' 'tl' 'ts' 'tz' 'ud' 'ur' 've' 'wd' 'wj' 'wn' 'wq' 'xa' 'xb' 'yf' 'yj' 'yn' 'yt' 'yv' 'zf' - f | '5h' 'a2' 'ad' 'ag' 'ar' 'cf' 'ch' 'dd' 'e6' 'ei' 'el' 'em' 'f3' 'fx' 'ga' 'gm' 'h8' 'hi' 'hl' 'hm' 'ix' 'jb' 'l5' 'm2' 'mh' 'mm' 'mu' 'n9' 'nf' 'nq' 'nw' 'o4' 'oe' 'pa' 'pl' 'q1' 'qb' 'qd' 'qi' 'qj' 'qk' 'qu' 'qy' 'r0' 'r3' 'r8' 'rg' 'rj' 'rt' 's1' 'sa' 'ss' 'sx' 'tb' 'tc' 'tj' 'uf' 'uh' 'um' 'uo' 'ut' 'vf' 'vo' 'w4' 'w7' 'wf' 'wk' 'wp' 'wq' 'wr' 'wt' 'wy' 'wz' 'xk' 'xt' 'ye' 'yv' 'zd' 'zp' 'zw' - f | 'a9' 'ad' 'az' 'bo' 'bq' 'by' 'c8' 'cb' 'cp' 'd9' 'de' 'dj' 'dp' 'e4' 'ef' 'ey' 'fn' 'gc' 'ge' 'gp' 'gs' 'gu' 'gx' 'hf' 'ic' 'ie' 'ir' 'kc' 'kp' 'ku' 'l2' 'lv' 'mx' 'n7' 'o3' 'o7' 'oe' 'pb' 'ps' 'q3' 'q4' 'qb' 'qn' 'qo' 'qq' 'qu' 'qw' 'r3' 'ra' 'rk' 'sg' 'si' 'sv' 'sw' 'tb' 'tg' 'tw' 'u2' 'uc' 'uf' 'uj' 'us' 'ut' 'uu' 'v3' 'va' 'wa' 'wd' 'ww' 'wy' 'wz' 'xk' 'y6' 'y8' 'ya' 'yc' 'ye' 'yo' 'yx' 'z3' - f | '2b' 'a4' 'aa' 'ay' 'br' 'cf' 'd3' 'dh' 'dw' 'e1' 'e8' 'eg' 'en' 'ep' 'ff' 'fj' 'g2' 'go' 'gq' 'i4' 'i8' 'if' 'jc' 'jj' 'jo' 'k1' 'kk' 'ks' 'la' 'ld' 'lm' 'm4' 'ml' 'o4' 'oe' 'og' 'os' 'oy' 'pc' 'pd' 'pr' 'px' 'q5' 'q6' 'qd' 'qh' 'qj' 'ql' 'qo' 'qt' 'qu' 'qw' 'rb' 're' 'rk' 'rn' 'rr' 'rw' 'sl' 'sm' 'te' 'tf' 'tk' 'u6' 'ui' 'ul' 'uo' 'ur' 'us' 'va' 'vt' 'w7' 'wf' 'wg' 'wm' 'wn' 'ws' 'xo' 'y8' 'yj' 'zh' - f | '3q' 'am' 'ar' 'az' 'bo' 'cb' 'cv' 'dd' 'ds' 'e1' 'e7' 'en' 'eq' 'er' 'eu' 'ew' 'fq' 'fx' 'g8' 'gm' 'h5' 'ic' 'if' 'jp' 'kw' 'kz' 'l4' 'lf' 'li' 'lm' 'lq' 'lu' 'lz' 'ml' 'nz' 'o4' 'o6' 'op' 'ow' 'po' 'py' 'qj' 'qk' 'qn' 'qp' 'qw' 'qz' 'r6' 'r8' 'rc' 'rl' 'rt' 's6' 'sh' 'sx' 'sz' 'tc' 'ti' 'tt' 'ty' 'uf' 'uh' 'uj' 'um' 'ut' 'uu' 'uv' 'vn' 'vt' 'we' 'wh' 'wi' 'wq' 'wu' 'wz' 'xn' 'y4' 'yu' 'yz' 'z9' 'ze' - f | 'a5' 'ao' 'av' 'b0' 'bh' 'bk' 'cj' 'd0' 'do' 'ds' 'e1' 'ee' 'ep' 'fa' 'fh' 'fv' 'hc' 'hh' 'hq' 'i1' 'if' 'iv' 'ix' 'iy' 'jq' 'jw' 'jz' 'ko' 'll' 'lr' 'lx' 'ns' 'nz' 'og' 'or' 'os' 'oz' 'p0' 'p8' 'pr' 'pv' 'q6' 'q9' 'qb' 'qd' 'qe' 'qh' 'qi' 'qq' 'qt' 'qu' 'qy' 'rd' 'ri' 'rq' 'rr' 'ry' 'sf' 'sg' 'sh' 'si' 'sw' 'sx' 'tc' 'tq' 'u3' 'uh' 'ul' 'us' 'wg' 'wn' 'wx' 'x3' 'xb' 'ya' 'yg' 'yn' 'yo' 'yp' 'yr' 'yw' - f | 'a7' 'ad' 'aq' 'ck' 'cu' 'd8' 'db' 'do' 'dt' 'e7' 'eg' 'em' 'eq' 'ex' 'ez' 'fl' 'gr' 'h4' 'hd' 'he' 'hg' 'id' 'ie' 'if' 'in' 'io' 'j4' 'j7' 'je' 'jm' 'jo' 'k5' 'kg' 'kj' 'kn' 'l9' 'lb' 'lc' 'ld' 'lf' 'li' 'lj' 'na' 'nz' 'oa' 'ok' 'oo' 'pj' 'px' 'q3' 'q4' 'q6' 'qd' 'qi' 'qm' 'qq' 'qt' 'qx' 'r1' 'rg' 'ri' 'rn' 'sm' 'so' 'su' 'sy' 'tq' 'u5' 'uc' 'ue' 'us' 'w3' 'wc' 'we' 'wj' 'wk' 'wt' 'x8' 'xj' 'yc' 'yy' - f | '2l' 'a4' 'ae' 'ag' 'cb' 'cs' 'cu' 'cy' 'dd' 'dj' 'ed' 'ee' 'ef' 'es' 'ex' 'ey' 'ft' 'fy' 'gs' 'h4' 'ho' 'ht' 'i2' 'i7' 'ia' 'iq' 'iz' 'jz' 'ku' 'kv' 'lq' 'mv' 'of' 'oi' 'op' 'pb' 'pd' 'pl' 'pn' 'pq' 'q0' 'q3' 'qe' 'qi' 'qp' 'qs' 'qy' 'qz' 'r3' 'ra' 'rh' 'rk' 'ry' 'sj' 'st' 'ta' 'tc' 'te' 'tf' 'th' 'ti' 'to' 'tt' 'u2' 'u5' 'vf' 'vx' 'w4' 'w7' 'wm' 'wt' 'ww' 'wx' 'x2' 'xi' 'y1' 'ye' 'yq' 'yv' 'za' 'zo' 'zy' - f | '4a' 'aj' 'an' 'aq' 'ax' 'bb' 'bh' 'ci' 'cn' 'd4' 'df' 'ea' 'ef' 'ek' 'en' 'eo' 'ex' 'fc' 'fj' 'fz' 'gb' 'gl' 'h7' 'hg' 'i1' 'i4' 'ia' 'im' 'j9' 'jg' 'ji' 'jj' 'kl' 'l2' 'lb' 'ld' 'lh' 'm1' 'mf' 'n1' 'nd' 'ob' 'od' 'ot' 'ph' 'pk' 'po' 'pv' 'q1' 'q2' 'q4' 'qb' 'qu' 'qz' 'ra' 'rh' 'ro' 'rp' 's1' 'si' 'sl' 'sn' 't7' 't8' 'ta' 'tc' 'ub' 'ue' 'ul' 'v9' 'w7' 'wd' 'xq' 'y5' 'yj' 'yl' 'yp' 'yw' 'z9' 'zb' 'zu' 'zy' - f | '8w' 'ao' 'aw' 'bk' 'by' 'c5' 'ch' 'cw' 'd0' 'dh' 'e2' 'eq' 'ev' 'ha' 'hk' 'ii' 'ir' 'iv' 'j8' 'ki' 'kp' 'lm' 'lx' 'nh' 'ns' 'nt' 'o3' 'on' 'ov' 'ow' 'ox' 'pl' 'q3' 'qc' 'qd' 'qe' 'qh' 'qm' 'qo' 'qr' 'qs' 'qt' 'qx' 'r2' 'r8' 'rc' 'rd' 'rh' 'ri' 'rk' 'rq' 'rt' 's3' 'sm' 'sq' 'sz' 't1' 't6' 'tx' 'u2' 'ue' 'up' 'uq' 'ut' 'ux' 'vg' 'vp' 'w3' 'wb' 'wc' 'wd' 'wr' 'xf' 'xp' 'y1' 'ya' 'yf' 'yg' 'yi' 'yn' 'yq' 'zn' - f | '5i' 'a4' 'a8' 'ae' 'af' 'am' 'ap' 'ax' 'bf' 'cr' 'cw' 'dk' 'dz' 'ea' 'eb' 'ec' 'ef' 'ep' 'er' 'et' 'ex' 'fp' 'fv' 'gh' 'hy' 'hz' 'i8' 'ig' 'io' 'iq' 'ji' 'jw' 'kt' 'le' 'lo' 'mi' 'nb' 'nq' 'o1' 'ol' 'oo' 'oq' 'oy' 'q3' 'q8' 'qi' 'qk' 'qo' 'qq' 'qs' 'r0' 'rg' 'rl' 'rt' 's6' 'sb' 'sk' 'sq' 't9' 'ta' 'tb' 'tg' 'tj' 'tu' 'ty' 'un' 'ur' 'uw' 'vi' 'wf' 'wk' 'wo' 'wt' 'wy' 'xj' 'xq' 'y0' 'y1' 'y9' 'yc' 'yn' 'yu' 'zs' - f | '6q' 'ac' 'ag' 'av' 'aw' 'az' 'bj' 'bq' 'bx' 'cj' 'dc' 'dd' 'dq' 'eg' 'ei' 'ek' 'em' 'f7' 'fg' 'fq' 'fx' 'gb' 'gp' 'hb' 'hk' 'i9' 'ii' 'im' 'ip' 'ir' 'iz' 'jx' 'le' 'lf' 'll' 'lx' 'mp' 'mv' 'of' 'oq' 'pb' 'pg' 'pj' 'py' 'pz' 'qi' 'qk' 'ql' 'qs' 'qu' 'qw' 'r8' 'ra' 'rc' 'rj' 'sj' 'tg' 'tk' 'tl' 'tm' 'tp' 'tw' 'u4' 'uf' 'ui' 'um' 'vu' 'w7' 'wd' 'wn' 'wt' 'wy' 'wz' 'y1' 'y3' 'y9' 'yl' 'yo' 'yq' 'yu' 'zb' 'zu' 'zv' - f | 'a1' 'a6' 'aq' 'bk' 'bu' 'ch' 'dd' 'dj' 'dx' 'e7' 'ef' 'ei' 'ek' 'el' 'ez' 'fp' 'ft' 'gb' 'go' 'hd' 'hh' 'hj' 'ho' 'hs' 'ic' 'il' 'ip' 'jh' 'jn' 'jq' 'jx' 'kq' 'kv' 'la' 'm8' 'mv' 'ng' 'oh' 'or' 'p7' 'p9' 'pe' 'pk' 'px' 'q7' 'qc' 'qd' 'qh' 'qj' 'qk' 'qr' 'qx' 'rd' 'rl' 'rq' 'sl' 'sq' 'st' 'sy' 'th' 'tn' 'u9' 'uc' 'ud' 'ug' 'uy' 'uz' 'vl' 'vn' 'wa' 'wb' 'wd' 'wt' 'xi' 'xs' 'xz' 'y5' 'yi' 'yk' 'yt' 'yw' 'z7' 'zg' - f | 'a2' 'a8' 'ae' 'b3' 'b5' 'bn' 'bq' 'd4' 'd7' 'dh' 'dl' 'dt' 'e6' 'es' 'fa' 'fb' 'ff' 'gd' 'ge' 'h8' 'hj' 'hm' 'hq' 'hw' 'hy' 'im' 'ip' 'kb' 'kh' 'ku' 'lm' 'ly' 'mf' 'nn' 'o0' 'oi' 'ok' 'or' 'pn' 'po' 'pq' 'pt' 'pv' 'q4' 'qc' 'qd' 'qu' 'qv' 'rd' 'rh' 'ri' 'rk' 'rp' 'rr' 'ru' 'si' 'sk' 'sq' 'ss' 'sx' 'sy' 'ta' 'tm' 'tq' 'tx' 'ul' 'um' 'uv' 'vj' 'vt' 'w7' 'wh' 'wi' 'wl' 'wn' 'wp' 'wq' 'ww' 'xb' 'y6' 'yq' 'z2' 'zn' - f | 'a3' 'b3' 'bv' 'ck' 'cl' 'cs' 'cv' 'cy' 'dc' 'dl' 'dq' 'dr' 'du' 'eg' 'el' 'en' 'ex' 'fv' 'fx' 'gd' 'gk' 'gu' 'h7' 'ic' 'jf' 'jz' 'lf' 'lq' 'nl' 'nm' 'o6' 'ob' 'ol' 'pe' 'po' 'q2' 'qa' 'qk' 'qo' 'qp' 'qr' 'qv' 'qz' 'r5' 're' 'rk' 'ss' 'sv' 't2' 'tf' 'ti' 'tj' 'ua' 'ud' 'v8' 'vb' 'vg' 'vh' 'vi' 'w1' 'w5' 'wb' 'wd' 'we' 'wf' 'wj' 'wr' 'ws' 'wv' 'xq' 'xs' 'y1' 'ye' 'yi' 'yp' 'yr' 'ys' 'yu' 'yw' 'z7' 'z8' 'zf' 'zq' - f | 'a7' 'a9' 'al' 'aq' 'ar' 'as' 'b2' 'cj' 'cl' 'co' 'cu' 'cv' 'dc' 'e3' 'e5' 'e7' 'ea' 'ee' 'eh' 'en' 'es' 'ev' 'ez' 'fl' 'fp' 'gm' 'hm' 'it' 'iu' 'iv' 'j8' 'jd' 'jo' 'kn' 'ko' 'ky' 'ln' 'mr' 'nc' 'o2' 'ok' 'ot' 'pc' 'pe' 'pz' 'q2' 'qe' 'qi' 'qq' 'qr' 'qs' 'r8' 'rm' 'rn' 'ro' 'rx' 'sz' 'te' 'tn' 'tq' 'tx' 'u1' 'ub' 'ul' 'up' 'uq' 'wf' 'wh' 'wk' 'wl' 'wo' 'wq' 'wt' 'wu' 'wv' 'xh' 'xz' 'y5' 'y9' 'yv' 'yx' 'yz' 'zj' - f | 'a8' 'am' 'as' 'bb' 'cn' 'co' 'dd' 'di' 'dx' 'dz' 'e3' 'e5' 'ea' 'ef' 'eh' 'el' 'en' 'eo' 'ew' 'fe' 'fg' 'gc' 'gi' 'gj' 'gp' 'ha' 'hl' 'hy' 'i3' 'id' 'ij' 'ir' 'is' 'k9' 'kc' 'kf' 'l9' 'ln' 'ls' 'lw' 'm0' 'm8' 'my' 'nn' 'on' 'p9' 'ph' 'pm' 'pw' 'q1' 'q3' 'qc' 'qm' 'qq' 'qv' 'rg' 'ro' 'se' 'sw' 'sx' 'ta' 'tl' 'tz' 'u4' 'uo' 'vg' 'vl' 'vm' 'vn' 'w3' 'wd' 'wm' 'wo' 'wp' 'wt' 'yg' 'yj' 'yv' 'yx' 'yz' 'zu' 'zx' 'zy' - f | 'ag' 'ao' 'ay' 'bk' 'bl' 'bw' 'cq' 'dp' 'dv' 'e5' 'ee' 'eu' 'fv' 'fx' 'gg' 'h8' 'ha' 'hk' 'ii' 'im' 'iq' 'it' 'je' 'jf' 'jr' 'js' 'km' 'ks' 'lo' 'lz' 'o8' 'ot' 'pg' 'pl' 'q3' 'q9' 'qa' 'qd' 'qe' 'qf' 'qh' 'qn' 'qq' 'qy' 'qz' 'r7' 're' 'ri' 'rl' 'ro' 'rr' 'rx' 'ry' 'sh' 'sl' 'ss' 'sw' 't5' 'ta' 'te' 'th' 'tr' 'tt' 'tu' 'tv' 'u7' 'uk' 'um' 'up' 'uu' 'vl' 'vw' 'w0' 'wl' 'ws' 'wt' 'ww' 'xe' 'ya' 'yb' 'ye' 'yf' 'za' - f | '2i' 'ap' 'aw' 'bd' 'bs' 'c9' 'db' 'di' 'dl' 'dq' 'dr' 'e5' 'ej' 'el' 'ez' 'f9' 'ga' 'gp' 'hm' 'if' 'im' 'j9' 'k9' 'ka' 'kd' 'kj' 'lc' 'lf' 'lk' 'mf' 'mq' 'mr' 'o3' 'oe' 'oj' 'op' 'p5' 'p7' 'p8' 'pb' 'pv' 'py' 'qc' 'qd' 'qf' 'qi' 'qk' 'qq' 'qu' 'qw' 'qz' 'r2' 'r8' 'r9' 'rj' 'rk' 'ry' 'rz' 'sd' 'sk' 'sm' 't2' 't6' 't7' 'tp' 'tq' 'tt' 'tw' 'u7' 'uh' 'uv' 'vh' 'w0' 'wc' 'we' 'wh' 'wk' 'wl' 'yf' 'yk' 'ys' 'zi' 'zq' 'zs' - f | '39' 'a9' 'ag' 'ap' 'ax' 'b9' 'c3' 'dn' 'e4' 'ea' 'f7' 'f9' 'g2' 'gi' 'h4' 'ht' 'ie' 'ij' 'ir' 'is' 'it' 'jd' 'jj' 'jv' 'kp' 'kt' 'kv' 'lh' 'ln' 'ls' 'mg' 'mh' 'nc' 'nh' 'o0' 'o2' 'od' 'ox' 'pb' 'pn' 'po' 'pz' 'q1' 'q8' 'qc' 'qd' 'qf' 'qh' 'qi' 'qk' 'qz' 'rd' 'rg' 'ro' 'rz' 's7' 'sa' 'sf' 'sn' 'sw' 'tk' 'tu' 'tw' 'u7' 'uu' 'vh' 'wa' 'wd' 'wk' 'wr' 'wu' 'wy' 'wz' 'xh' 'xm' 'xt' 'yb' 'yi' 'yj' 'yn' 'yr' 'z1' 'z8' 'zn' - f | '14' '1t' 'aa' 'ab' 'ag' 'aq' 'ax' 'bc' 'cb' 'cm' 'd1' 'db' 'ea' 'ek' 'en' 'ey' 'f0' 'g6' 'g7' 'gx' 'ha' 'ho' 'i1' 'i6' 'i8' 'it' 'iw' 'jl' 'jp' 'ko' 'kt' 'la' 'le' 'mb' 'mk' 'mt' 'n6' 'na' 'ob' 'oc' 'od' 'on' 'op' 'or' 'ot' 'q6' 'qd' 'qf' 'qk' 'qp' 'qq' 'qr' 'qw' 'qy' 'r5' 'rf' 'rk' 'se' 'sp' 'sx' 't0' 'tj' 'tk' 'tq' 'tv' 'tx' 'u0' 'ub' 'ue' 'uf' 'um' 'us' 'uu' 'v9' 'vi' 'wb' 'wo' 'wu' 'wy' 'x9' 'xs' 'xu' 'y0' 'yo' 'zi' - f | '1a' '3r' 'ai' 'b8' 'bp' 'd6' 'do' 'dp' 'du' 'e0' 'e1' 'ek' 'es' 'eu' 'ey' 'ez' 'fq' 'fs' 'fy' 'gd' 'gm' 'h1' 'hu' 'i0' 'is' 'iv' 'iz' 'jd' 'jn' 'jz' 'kc' 'lf' 'lp' 'lt' 'ly' 'm2' 'mb' 'mt' 'n1' 'nr' 'of' 'oi' 'oq' 'ow' 'pe' 'pm' 'pn' 'q0' 'qb' 'qg' 'qk' 'qo' 'qz' 'r4' 'r8' 'ra' 'rn' 'rs' 's7' 'sa' 'sj' 'so' 'su' 'sv' 'sx' 'ti' 'tl' 'ts' 'ty' 'u4' 'up' 'vr' 'w2' 'wg' 'wi' 'wk' 'wl' 'ws' 'xl' 'xx' 'yf' 'yk' 'yn' 'yq' 'yv' - f | '1r' '2z' '3d' '6d' 'ay' 'bb' 'bh' 'bq' 'bv' 'cn' 'cr' 'cs' 'd5' 'd9' 'dh' 'dq' 'dw' 'dz' 'e5' 'ea' 'eb' 'eh' 'er' 'fu' 'g0' 'ga' 'gc' 'h4' 'hf' 'hh' 'hx' 'ih' 'io' 'jz' 'kk' 'ko' 'li' 'lz' 'n1' 'n4' 'nn' 'nt' 'o8' 'oa' 'oe' 'oh' 'ov' 'oz' 'p2' 'p5' 'pg' 'pt' 'px' 'qa' 'qe' 'qg' 'qm' 'qt' 'qv' 'qx' 'ro' 'rp' 'rv' 's6' 'sh' 'sn' 'sx' 'sz' 't6' 'th' 'tj' 'tu' 'u5' 'uk' 'uq' 'wg' 'wp' 'wv' 'xe' 'xv' 'y4' 'yf' 'yo' 'yx' 'zr' - f | '27' '4g' 'a2' 'al' 'bp' 'ca' 'cp' 'da' 'dt' 'e8' 'ee' 'ef' 'eg' 'ej' 'eq' 'eu' 'ev' 'fe' 'gn' 'gq' 'gy' 'i5' 'ic' 'il' 'io' 'ir' 'iw' 'iz' 'j2' 'kz' 'l2' 'l8' 'lh' 'ln' 'lt' 'np' 'ns' 'oi' 'oj' 'or' 'ph' 'pr' 'pt' 'qa' 'qh' 'qi' 'qs' 'qt' 'qu' 'r1' 'rd' 'ry' 's8' 'sj' 'sk' 'sl' 'sq' 'td' 'te' 'tg' 'tj' 'tq' 'tx' 'u0' 'ub' 'ul' 'uu' 'ux' 'uy' 'v0' 've' 'vg' 'vk' 'wa' 'wj' 'ws' 'wu' 'yb' 'yd' 'yi' 'yk' 'yo' 'yr' 'ys' 'zp' - f | '2a' '3o' '6w' '9h' 'ag' 'ak' 'cu' 'db' 'e3' 'ei' 'ep' 'eq' 'f6' 'fm' 'fq' 'fz' 'g5' 'gi' 'gk' 'gn' 'gp' 'gx' 'hb' 'hw' 'ia' 'ic' 'id' 'ig' 'ih' 'im' 'jh' 'jy' 'k3' 'kh' 'kv' 'l4' 'lf' 'lh' 'lu' 'ni' 'o7' 'oe' 'oi' 'op' 'os' 'ow' 'p0' 'p1' 'pj' 'pp' 'qa' 'qe' 'qi' 'qm' 'qz' 'rb' 're' 'rh' 'sa' 'sn' 'te' 'th' 'u3' 'ui' 'uj' 'us' 'vh' 'w1' 'w7' 'wc' 'wg' 'wh' 'wo' 'wx' 'xr' 'xw' 'xz' 'y5' 'y6' 'y9' 'ye' 'yo' 'ze' 'zg' 'zp' - f | '2i' 'am' 'ar' 'bl' 'by' 'ci' 'da' 'db' 'dc' 'dg' 'ea' 'ed' 'ei' 'ek' 'em' 'en' 'er' 'f2' 'f7' 'fi' 'fj' 'fu' 'fy' 'g0' 'g8' 'gn' 'gr' 'hl' 'hr' 'i2' 'it' 'ix' 'jg' 'jr' 'ju' 'jx' 'lh' 'lj' 'm8' 'n7' 'o1' 'o5' 'ob' 'og' 'ok' 'oz' 'pg' 'pl' 'pz' 'q4' 'q9' 'qf' 'qh' 'qn' 'qt' 'qu' 'qw' 're' 'ri' 'rn' 'ro' 'rp' 'rz' 's7' 'st' 'sz' 't3' 'tk' 'tw' 'u1' 'u5' 'uh' 'uy' 've' 'vh' 'w1' 'x2' 'xi' 'y4' 'ya' 'yi' 'yk' 'yn' 'zb' 'zo' - f | '2v' '7j' '7r' 'a7' 'aj' 'av' 'br' 'cg' 'd8' 'ei' 'en' 'ez' 'f5' 'fb' 'go' 'h0' 'hf' 'hk' 'hm' 'i9' 'ia' 'ig' 'ik' 'im' 'iq' 'it' 'iv' 'ja' 'je' 'ji' 'ks' 'lo' 'mo' 'mq' 'nj' 'o5' 'of' 'on' 'ot' 'ox' 'p1' 'p6' 'pb' 'ph' 'pj' 'pn' 'pp' 'pq' 'pr' 'qa' 'qh' 'qj' 'qm' 'qn' 'qo' 'qu' 'r2' 'ro' 's1' 'sa' 'se' 'sp' 't6' 'ti' 'tu' 'u2' 'ug' 'uh' 'ui' 'ur' 'uy' 'v9' 'wl' 'wn' 'wt' 'wv' 'wy' 'wz' 'xm' 'xs' 'ya' 'yi' 'yu' 'z8' 'zl' - f | '68' 'af' 'as' 'at' 'cf' 'ci' 'cx' 'dl' 'dt' 'dv' 'e4' 'ea' 'eg' 'es' 'fd' 'fi' 'fo' 'g1' 'gd' 'gy' 'he' 'hu' 'hw' 'hz' 'i0' 'ia' 'if' 'io' 'it' 'iv' 'iz' 'j0' 'jc' 'jj' 'jm' 'kb' 'ki' 'kk' 'ku' 'ky' 'lr' 'nv' 'oi' 'om' 'p3' 'pa' 'pt' 'qe' 'qh' 'qj' 'qm' 'qq' 'qs' 'qt' 'qu' 'r3' 'rp' 'rr' 'rw' 'rx' 's2' 'sc' 'sp' 'ti' 'tn' 'tv' 'ty' 'ue' 'uk' 'ul' 'up' 'ut' 'uu' 'uw' 'vf' 'vp' 'w2' 'w7' 'wb' 'wl' 'wq' 'xg' 'yc' 'yh' 'z3' - f | 'a8' 'ad' 'ai' 'al' 'as' 'av' 'ay' 'az' 'bf' 'bg' 'c6' 'dc' 'dd' 'dz' 'ef' 'eh' 'eu' 'ft' 'g0' 'g4' 'gf' 'gm' 'hq' 'im' 'iw' 'ix' 'j5' 'jj' 'jn' 'jv' 'k1' 'ko' 'ma' 'n0' 'nw' 'o9' 'om' 'op' 'ox' 'p4' 'pa' 'pe' 'pm' 'ps' 'q2' 'qb' 'qc' 'qf' 'qi' 'ql' 'qu' 'qw' 'qy' 'qz' 'rl' 'rn' 'rs' 'ru' 'se' 'sf' 'sm' 't8' 'tc' 'tg' 'uq' 'uz' 'va' 'vj' 'wa' 'we' 'wg' 'wk' 'wq' 'wu' 'wy' 'xb' 'xo' 'y3' 'ye' 'ym' 'ys' 'yt' 'z8' 'zd' 'zo' - f | 'aa' 'af' 'bp' 'c2' 'cd' 'ci' 'dl' 'du' 'dz' 'es' 'fn' 'fo' 'g7' 'ga' 'gc' 'gj' 'gx' 'hc' 'ht' 'iu' 'jl' 'jm' 'ke' 'kk' 'kr' 'lc' 'le' 'lr' 'lw' 'ms' 'n2' 'nq' 'nw' 'nz' 'o1' 'op' 'oq' 'ot' 'ow' 'p0' 'pb' 'pp' 'pr' 'qc' 'qh' 'qp' 'qr' 'qu' 'qy' 'r3' 'r9' 'rc' 'rk' 'rr' 'ry' 'sb' 'sf' 'sk' 'sl' 't1' 'ta' 'tb' 'tk' 'tz' 'ud' 'ur' 've' 'vn' 'vt' 'vw' 'w6' 'w9' 'wg' 'wk' 'xg' 'yg' 'yh' 'yj' 'ys' 'yt' 'yv' 'yy' 'z3' 'zo' 'zq' - f | '1o' '1v' '4v' 'ab' 'at' 'b5' 'bw' 'bz' 'cm' 'dc' 'dh' 'dj' 'dk' 'dq' 'e1' 'e5' 'ee' 'el' 'em' 'eo' 'ep' 'ew' 'fi' 'fy' 'gd' 'gh' 'gw' 'h7' 'i6' 'ia' 'ii' 'ip' 'is' 'iu' 'jk' 'k5' 'kb' 'mf' 'mp' 'mw' 'mx' 'n1' 'na' 'nm' 'nq' 'ob' 'of' 'pa' 'pb' 'pd' 'pu' 'q4' 'qb' 'qe' 'qf' 'qj' 'qo' 'qr' 're' 'rj' 'ro' 'rt' 'rv' 'sb' 'sp' 'st' 'ub' 'ue' 'um' 'vz' 'w3' 'w7' 'w8' 'wh' 'wo' 'wt' 'x5' 'x9' 'xd' 'xj' 'xm' 'ya' 'yb' 'yg' 'zr' 'zv' - f | '2d' '2w' 'ag' 'aj' 'am' 'ce' 'd2' 'd4' 'dd' 'dn' 'e0' 'e6' 'ef' 'ej' 'ek' 'er' 'f9' 'fd' 'fe' 'fq' 'ft' 'fv' 'gq' 'gy' 'he' 'ij' 'iq' 'it' 'iy' 'jf' 'jl' 'jr' 'ju' 'kq' 'ku' 'lm' 'nj' 'nw' 'nx' 'oa' 'oe' 'oj' 'p2' 'pa' 'pm' 'pq' 'pv' 'q5' 'q9' 'qb' 'qd' 'qg' 'qj' 'qk' 'ql' 'qm' 'qu' 'qx' 'qz' 'rp' 'rq' 'rs' 's5' 'sk' 'ss' 'sy' 't2' 'ta' 'ts' 'tw' 'tx' 'u5' 'w3' 'w7' 'wa' 'wp' 'ws' 'wu' 'wy' 'wz' 'xz' 'y4' 'yn' 'yy' 'zt' 'zw' - f | '3h' 'aw' 'az' 'b2' 'bl' 'bq' 'bt' 'c0' 'cd' 'ck' 'cm' 'cw' 'cy' 'd3' 'e0' 'ef' 'eo' 'ew' 'fj' 'fk' 'gb' 'gc' 'gm' 'gt' 'gz' 'hv' 'in' 'ix' 'jb' 'jg' 'jl' 'jn' 'js' 'k7' 'kg' 'ku' 'kx' 'kz' 'ld' 'nb' 'ni' 'o3' 'o6' 'od' 'om' 'p3' 'p4' 'pn' 'pu' 'q7' 'qd' 'qh' 'qp' 'qq' 'qr' 'qv' 'qy' 'qz' 'rq' 'sb' 'se' 'sf' 'sh' 'sm' 't0' 'tg' 'tj' 'tl' 'tq' 'ua' 'uk' 'us' 'wd' 'we' 'wj' 'wn' 'wq' 'wv' 'wz' 'yd' 'yg' 'ym' 'yn' 'yr' 'zc' 'zz' - f | 'ac' 'al' 'am' 'ap' 'ar' 'av' 'c1' 'cl' 'cz' 'dm' 'dp' 'dt' 'du' 'e0' 'es' 'eu' 'ev' 'ez' 'fa' 'fc' 'fj' 'fw' 'fz' 'gm' 'gx' 'ha' 'i6' 'i7' 'if' 'iz' 'j0' 'jd' 'jx' 'k0' 'kr' 'mj' 'mk' 'mp' 'n4' 'nm' 'om' 'ot' 'pl' 'px' 'qa' 'qb' 'qg' 'qk' 'qn' 'qo' 'qr' 'qu' 'r7' 'rc' 'rk' 's3' 's4' 'se' 'ss' 'su' 't8' 'ta' 'te' 'tj' 'tk' 'ts' 'tz' 'ub' 'v2' 'wb' 'wd' 'we' 'wf' 'wj' 'wq' 'wr' 'ws' 'wv' 'wx' 'y6' 'ym' 'yn' 'yq' 'ys' 'yv' 'zt' - f | '20' 'ag' 'az' 'b9' 'bg' 'bh' 'c2' 'dd' 'di' 'do' 'dw' 'e1' 'e3' 'e8' 'eb' 'ev' 'fc' 'fj' 'fu' 'fw' 'fx' 'gb' 'gf' 'hu' 'hw' 'hz' 'ih' 'ik' 'iq' 'jc' 'jq' 'ka' 'kf' 'kh' 'kw' 'ky' 'ly' 'lz' 'mc' 'n8' 'o3' 'o7' 'oa' 'os' 'ou' 'pf' 'q5' 'q6' 'qg' 'ql' 'qo' 'qy' 'r2' 'rf' 'rp' 'ru' 'ry' 's1' 's5' 'se' 'si' 'sn' 'su' 'ta' 'tn' 'tu' 'tv' 'tw' 'u9' 'ua' 'uh' 'uu' 'vo' 'w8' 'wa' 'wc' 'we' 'wi' 'wu' 'ww' 'wy' 'x3' 'xl' 'yb' 'yg' 'yk' 'yv' - f | '5f' 'ac' 'ad' 'aj' 'av' 'bg' 'ch' 'ci' 'dg' 'di' 'dl' 'dx' 'ep' 'ew' 'f8' 'fp' 'fr' 'fs' 'g4' 'g6' 'gb' 'h5' 'he' 'hk' 'hx' 'i1' 'ic' 'im' 'ji' 'jm' 'js' 'k9' 'kq' 'lf' 'ln' 'mj' 'n2' 'ni' 'no' 'o5' 'oi' 'ot' 'oy' 'pa' 'pj' 'qk' 'qq' 'qt' 'qu' 'r4' 'r8' 'rb' 'rh' 'rj' 'rm' 'ro' 'rp' 'rq' 'rt' 'ru' 'sb' 'th' 'tu' 'tz' 'u9' 'un' 'uo' 'us' 've' 'vi' 'vq' 'vx' 'wf' 'wg' 'wi' 'wq' 'wr' 'wt' 'x5' 'xz' 'y6' 'yd' 'yo' 'yq' 'yx' 'z3' 'zl' - f | 'a5' 'av' 'dc' 'dm' 'dt' 'dw' 'e2' 'ea' 'en' 'et' 'ez' 'f2' 'fg' 'fn' 'fv' 'gn' 'gu' 'h5' 'ht' 'i2' 'ie' 'ik' 'il' 'in' 'it' 'iv' 'iy' 'ji' 'jj' 'ju' 'kf' 'kn' 'ko' 'ku' 'l6' 'ls' 'nz' 'o2' 'o4' 'of' 'on' 'op' 'p7' 'q0' 'q2' 'qa' 'qt' 'r1' 'r9' 'ri' 'rq' 'rv' 'se' 'sp' 'sx' 't0' 't2' 't9' 'te' 'tq' 'tu' 'u8' 'uc' 'ue' 'ug' 'ui' 'ut' 'uu' 'v0' 'v7' 'vs' 'w0' 'wc' 'wh' 'wn' 'wo' 'ws' 'y1' 'y3' 'y5' 'ya' 'yc' 'yi' 'ys' 'yt' 'zf' 'zq' - f | 'ab' 'ag' 'aw' 'b4' 'd4' 'ds' 'e1' 'ea' 'eb' 'ee' 'ef' 'eh' 'ek' 'el' 'en' 'eu' 'ex' 'fv' 'fx' 'gi' 'gp' 'gt' 'i3' 'ie' 'jd' 'jk' 'jn' 'kv' 'l7' 'n8' 'ns' 'nx' 'o2' 'o3' 'oh' 'os' 'ow' 'p2' 'pr' 'pu' 'q3' 'qd' 'qe' 'qk' 'qq' 'qz' 'r9' 'rb' 'ri' 'rm' 'rr' 'rw' 'ry' 'sc' 'sj' 'sl' 'sx' 'tk' 'tr' 'tw' 'u4' 'ub' 'ud' 'uf' 'uh' 'un' 'uv' 'v6' 'vc' 'vf' 'vi' 'wg' 'wr' 'ws' 'wv' 'x7' 'xf' 'xo' 'y0' 'yi' 'yo' 'yt' 'yy' 'za' 'zm' 'zu' 'zx' - f | 'ad' 'af' 'aj' 'am' 'aq' 'ba' 'bo' 'c0' 'c5' 'cx' 'da' 'dc' 'dk' 'ed' 'ek' 'en' 'eo' 'ep' 'ew' 'fb' 'g4' 'gd' 'h2' 'hm' 'ho' 'hy' 'ib' 'if' 'io' 'ir' 'iv' 'iz' 'jc' 'jp' 'jt' 'kr' 'lo' 'me' 'na' 'nc' 'nh' 'o6' 'ok' 'oq' 'or' 'ow' 'pn' 'ps' 'q6' 'qa' 'qj' 'qo' 'qx' 'r2' 'r6' 'rd' 're' 'rg' 'rw' 'ta' 'tk' 'uj' 'uo' 'vn' 'wc' 'wh' 'wj' 'wl' 'wu' 'wv' 'ww' 'wx' 'xe' 'xl' 'xn' 'xo' 'xs' 'yb' 'yl' 'yp' 'yw' 'zg' 'zq' 'zr' 'zu' 'zx' 'zy' - f | 'am' 'as' 'b1' 'd3' 'db' 'dl' 'ea' 'ed' 'ee' 'el' 'em' 'ep' 'er' 'ew' 'ez' 'f4' 'fm' 'go' 'h9' 'he' 'hl' 'i0' 'ie' 'ii' 'iz' 'ji' 'kl' 'kn' 'lc' 'lr' 'm7' 'mb' 'mt' 'my' 'no' 'nu' 'oo' 'or' 'ov' 'ox' 'pe' 'pq' 'q7' 'qc' 'qd' 'qi' 'qj' 'qo' 'qr' 'qs' 'qv' 'qw' 'r0' 'r8' 're' 'rm' 'rn' 'rp' 's0' 'so' 'sp' 'sw' 'sy' 'te' 'tg' 'tl' 'tr' 'uq' 'uz' 'vk' 'wk' 'wl' 'wp' 'wq' 'wr' 'wu' 'ww' 'xs' 'y0' 'yb' 'yn' 'yr' 'ys' 'yt' 'yy' 'zh' 'zr' - f | '1v' '44' 'aj' 'al' 'am' 'ba' 'bi' 'br' 'bt' 'c0' 'd6' 'dg' 'di' 'e1' 'e4' 'ei' 'ek' 'er' 'et' 'eu' 'ev' 'ex' 'fa' 'fc' 'fe' 'fh' 'fr' 'ga' 'gh' 'gu' 'hp' 'hq' 'ib' 'if' 'io' 'ix' 'jo' 'jv' 'kd' 'l1' 'me' 'mh' 'mn' 'mo' 'mt' 'n7' 'nf' 'nk' 'oe' 'oy' 'pa' 'pg' 'pj' 'pm' 'pn' 'pq' 'py' 'q1' 'qd' 'qe' 'qi' 'qj' 'qr' 'qs' 'qz' 'rb' 'rs' 'su' 'sw' 't5' 'ti' 'tx' 'uc' 'ug' 'ui' 'uq' 'uz' 'v6' 'vp' 'we' 'wf' 'wj' 'wm' 'wx' 'xe' 'y7' 'yt' 'yy' - f | '1x' 'a2' 'ah' 'az' 'bb' 'be' 'bz' 'd1' 'dd' 'du' 'ee' 'eh' 'en' 'eu' 'ey' 'ez' 'fl' 'fs' 'g4' 'gm' 'gr' 'ha' 'hf' 'hg' 'hr' 'hw' 'i6' 'id' 'ij' 'j2' 'jv' 'k9' 'lg' 'm9' 'md' 'me' 'mg' 'mp' 'nd' 'nf' 'ng' 'nj' 'ny' 'nz' 'oj' 'os' 'pi' 'pj' 'pt' 'q9' 'qa' 'qf' 'qh' 'qk' 'qn' 'qq' 'qs' 'rz' 'sb' 't7' 't8' 'tw' 'ty' 'u2' 'u3' 'ua' 'ub' 'uy' 'uz' 'w1' 'w3' 'w5' 'wa' 'wc' 'we' 'wh' 'wp' 'wr' 'xd' 'xs' 'y3' 'yd' 'yk' 'yl' 'yo' 'ze' 'zh' 'zo' - f | '4n' '6a' 'a3' 'a5' 'aa' 'ae' 'ag' 'b9' 'ca' 'cf' 'd1' 'da' 'dr' 'dz' 'ee' 'el' 'et' 'ey' 'fj' 'fs' 'gl' 'hk' 'hl' 'hn' 'ie' 'ih' 'im' 'ix' 'j1' 'jr' 'kf' 'kk' 'lc' 'lk' 'lp' 'lx' 'mh' 'mt' 'mx' 'my' 'nr' 'nu' 'o6' 'og' 'oo' 'p4' 'p7' 'pj' 'pr' 'q3' 'qc' 'qd' 'qj' 'qk' 'ql' 'qp' 'qt' 'qv' 'qx' 'r8' 're' 'rm' 'rs' 'ru' 'rv' 'sp' 'sw' 'td' 'tk' 'to' 'tw' 'tz' 'u8' 'uf' 'vf' 'vw' 'w7' 'wq' 'wr' 'xe' 'ym' 'yo' 'yr' 'ys' 'yz' 'zc' 'zn' 'zs' - f | 'a3' 'ag' 'ar' 'au' 'ax' 'be' 'cy' 'd7' 'dd' 'do' 'e3' 'eb' 'eo' 'er' 'ev' 'ey' 'fp' 'gj' 'hk' 'hw' 'hy' 'if' 'ig' 'ii' 'in' 'io' 'iq' 'is' 'kh' 'll' 'n8' 'nd' 'np' 'nz' 'og' 'ot' 'ox' 'oy' 'pe' 'px' 'qa' 'qb' 'qe' 'qf' 'qh' 'qj' 'qm' 'qn' 'qt' 'qu' 'qw' 'qx' 'r6' 'r9' 'rb' 'rc' 'rd' 'rn' 'rq' 'se' 't7' 'tb' 'ti' 'tq' 'u0' 'u6' 'ub' 'ud' 'vd' 'vj' 'vl' 'vo' 'wd' 'wg' 'wh' 'wi' 'wk' 'wo' 'wv' 'wz' 'xy' 'y9' 'yl' 'ym' 'yo' 'yp' 'ys' 'yu' - f | 'ad' 'av' 'be' 'bi' 'bk' 'bu' 'ce' 'cv' 'd8' 'df' 'dh' 'du' 'e1' 'em' 'ep' 'ex' 'ey' 'f1' 'fd' 'fh' 'fp' 'gn' 'gu' 'h8' 'i8' 'ii' 'il' 'iz' 'j0' 'ji' 'jv' 'jz' 'k2' 'k9' 'ky' 'l9' 'lo' 'm6' 'mc' 'md' 'ng' 'nz' 'ot' 'p2' 'pa' 'pj' 'ps' 'pv' 'q5' 'qd' 'qf' 'qm' 'qq' 'qr' 'qt' 'qv' 'qx' 'rc' 'rh' 'rp' 'rq' 'rs' 'sb' 'sc' 'te' 'to' 'ts' 'tw' 'up' 'vn' 'vw' 'wa' 'wg' 'wh' 'wn' 'wp' 'wz' 'xc' 'xf' 'xt' 'y5' 'yh' 'yn' 'yy' 'yz' 'za' 'zh' 'zy' - f | 'aj' 'ak' 'aq' 'ba' 'bd' 'bj' 'bk' 'bx' 'cr' 'cx' 'd0' 'dj' 'dl' 'ef' 'ei' 'ej' 'ek' 'em' 'eq' 'er' 'f3' 'f7' 'fi' 'fp' 'gv' 'h7' 'ha' 'hc' 'hh' 'hk' 'hn' 'ia' 'id' 'im' 'iq' 'is' 'iw' 'ji' 'jk' 'js' 'ju' 'jx' 'l0' 'm1' 'mq' 'ng' 'o8' 'ot' 'ov' 'oy' 'p1' 'pu' 'pv' 'pz' 'qc' 'qh' 'qm' 'qq' 'qs' 'qt' 'qw' 'rc' 'rq' 'rt' 'sd' 't5' 'ta' 'tb' 'tj' 'tp' 'uk' 'un' 'v9' 'vt' 'wa' 'wd' 'wf' 'wm' 'wn' 'wv' 'wz' 'xp' 'ya' 'yg' 'ym' 'yn' 'yr' 'zi' - f | 'aj' 'as' 'aw' 'bc' 'bj' 'bm' 'cd' 'd7' 'd9' 'di' 'ef' 'er' 'es' 'ew' 'fi' 'ft' 'g2' 'gq' 'gx' 'h9' 'he' 'hg' 'hu' 'i8' 'ie' 'ik' 'im' 'iq' 'ix' 'iy' 'jf' 'ji' 'ka' 'kl' 'kt' 'la' 'lf' 'm8' 'm9' 'nh' 'nw' 'o7' 'oi' 'pi' 'ps' 'q6' 'qa' 'qb' 'qf' 'qm' 'qo' 'qq' 'qs' 'r9' 'rb' 'rf' 'rk' 'rx' 'sa' 'sb' 'sp' 't1' 'tb' 'tl' 'tm' 'u6' 'uc' 'um' 'un' 'ur' 'w3' 'wj' 'wu' 'xm' 'xr' 'xy' 'ya' 'yd' 'ye' 'yf' 'yj' 'yo' 'ys' 'zc' 'zg' 'zl' 'zv' 'zz' - f | '1g' '3e' 'a5' 'ae' 'ar' 'bt' 'cb' 'ck' 'co' 'd5' 'dh' 'dm' 'dr' 'dt' 'e0' 'e9' 'eh' 'el' 'em' 'f2' 'f3' 'fb' 'ff' 'fg' 'gu' 'hb' 'he' 'hr' 'hx' 'i7' 'ib' 'if' 'ig' 'io' 'iu' 'jc' 'jo' 'jv' 'kh' 'kx' 'lb' 'lh' 'lw' 'lx' 'ly' 'mp' 'oa' 'oc' 'oz' 'pa' 'q9' 'qi' 'qp' 'qq' 'qw' 'r3' 'rb' 'rd' 're' 'rn' 'ry' 'rz' 's5' 'su' 'sz' 'td' 'tf' 'tt' 'u9' 'uh' 'um' 'un' 'va' 'vh' 'vt' 'w7' 'wb' 'wc' 'wg' 'wh' 'wx' 'xd' 'xz' 'y8' 'yf' 'yg' 'yh' 'ym' 'zy' - f | '1t' 'am' 'aw' 'b4' 'bi' 'bm' 'bx' 'cd' 'cj' 'cv' 'e5' 'ek' 'eo' 'er' 'ex' 'f5' 'f8' 'fp' 'fr' 'fw' 'ga' 'gy' 'hm' 'hs' 'ip' 'ir' 'is' 'it' 'iv' 'iz' 'jf' 'jm' 'jp' 'ju' 'k6' 'kk' 'kr' 'lb' 'le' 'lt' 'mj' 'nk' 'np' 'nr' 'oa' 'oj' 'pm' 'pn' 'q1' 'q3' 'qb' 'qc' 'qf' 'qh' 'qi' 'qj' 'qq' 'qt' 'qw' 'qy' 'r2' 'r8' 'rf' 'rh' 'rw' 's9' 't3' 'te' 'ti' 'tn' 'tq' 'uu' 'uv' 'uw' 'w0' 'w1' 'w3' 'w7' 'wc' 'wi' 'wk' 'wn' 'wr' 'wt' 'xm' 'y5' 'ya' 'z7' 'zu' - f | '1f' '2j' '2q' '5c' 'am' 'ap' 'aq' 'az' 'bu' 'bx' 'cr' 'e0' 'e7' 'ea' 'eb' 'ec' 'eg' 'ew' 'ey' 'fh' 'fk' 'g2' 'go' 'h4' 'h8' 'ha' 'hb' 'hm' 'ia' 'ic' 'ie' 'ik' 'iu' 'iv' 'j7' 'ja' 'k9' 'kw' 'lp' 'ly' 'mb' 'ns' 'ny' 'o0' 'of' 'ok' 'oz' 'pe' 'pr' 'qb' 'qd' 'qg' 'qt' 'qx' 'qy' 'rg' 'ro' 'rq' 'rz' 'sh' 'si' 'sl' 'sm' 'td' 'tg' 'tx' 'uh' 'um' 'up' 'uw' 've' 'vl' 'vp' 'vw' 'w2' 'w5' 'wc' 'wf' 'wi' 'wn' 'wq' 'ws' 'wv' 'wy' 'wz' 'x1' 'xr' 'y1' 'zs' 'zz' - f | '1q' '2n' '4p' '8n' 'a3' 'aa' 'bn' 'bq' 'bu' 'cg' 'db' 'dl' 'dx' 'dy' 'e2' 'e3' 'e4' 'ea' 'eq' 'ff' 'fk' 'fn' 'fv' 'gf' 'gh' 'h1' 'hs' 'hu' 'ij' 'in' 'iv' 'kc' 'ke' 'ln' 'm2' 'mc' 'mf' 'o2' 'og' 'oo' 'ov' 'p8' 'pl' 'pm' 'ps' 'pv' 'pz' 'qa' 'qc' 'qe' 'qh' 'qi' 'qj' 'qm' 'qo' 'qq' 'qv' 'qw' 'qy' 're' 'rz' 'sd' 'si' 'sj' 'sp' 'su' 'tc' 'tk' 'tn' 'tq' 'u7' 'ut' 'uv' 'v5' 'vr' 'wb' 'we' 'wm' 'ws' 'wv' 'xc' 'xy' 'y9' 'yj' 'yq' 'yv' 'yw' 'zb' 'zw' 'zz' - f | '2t' '4d' 'bb' 'bd' 'cg' 'co' 'd6' 'db' 'dg' 'dn' 'do' 'dy' 'e1' 'e3' 'e6' 'ec' 'em' 'en' 'ep' 'es' 'ev' 'ew' 'fu' 'fz' 'gc' 'gt' 'hg' 'hl' 'hy' 'id' 'in' 'io' 'ir' 'iu' 'iw' 'jl' 'jo' 'jp' 'jw' 'k4' 'ke' 'ku' 'ld' 'lg' 'li' 'lj' 'lr' 'ls' 'm7' 'n8' 'o6' 'oi' 'op' 'oy' 'pi' 'pq' 'qk' 'qm' 'qn' 'qp' 'qr' 'qu' 'qv' 'qz' 'r3' 're' 'rj' 'rk' 'rq' 'ru' 'rw' 'rz' 'sh' 'si' 'ta' 'to' 'uq' 'ux' 'vc' 'vr' 'wb' 'wh' 'wn' 'wo' 'wy' 'xg' 'y7' 'yb' 'yd' 'yo' - f | '4w' 'ad' 'ak' 'as' 'b3' 'bd' 'cy' 'dt' 'du' 'dy' 'e2' 'e4' 'en' 'es' 'et' 'ew' 'ex' 'f2' 'fl' 'fr' 'ft' 'gv' 'h1' 'ha' 'hd' 'hh' 'hs' 'hv' 'ic' 'io' 'ja' 'jm' 'k2' 'ku' 'kw' 'ld' 'ls' 'lx' 'ma' 'nu' 'ny' 'ov' 'pm' 'ps' 'q6' 'qa' 'qd' 'qo' 'qs' 'qv' 'qy' 'ra' 'rs' 'rt' 'rv' 'rw' 's8' 'sa' 'sw' 'tj' 'ug' 'ui' 'ur' 'ut' 'ux' 'v6' 'vt' 'w4' 'w7' 'wa' 'wb' 'wc' 'wg' 'wh' 'wi' 'wt' 'wu' 'wy' 'wz' 'x2' 'xb' 'xm' 'yg' 'yh' 'yi' 'yu' 'yy' 'z5' 'zg' 'zo' - f | '97' 'ac' 'ah' 'bn' 'c8' 'dl' 'ds' 'dw' 'e2' 'eb' 'eg' 'ej' 'ep' 'eu' 'f1' 'fe' 'g9' 'gs' 'h0' 'ha' 'he' 'hh' 'hy' 'i0' 'i8' 'i9' 'ia' 'ij' 'ip' 'jr' 'jt' 'jw' 'kq' 'lo' 'lq' 'm7' 'me' 'na' 'ns' 'o1' 'od' 'oe' 'oi' 'om' 'oz' 'pc' 'pj' 'pk' 'qh' 'qi' 'qj' 'ql' 'qo' 'qq' 'qr' 'qs' 'qt' 'qw' 'qz' 'rc' 're' 'rh' 'ri' 'rr' 'sz' 'tc' 'tf' 'tk' 'tl' 'ue' 'uh' 'uj' 'un' 'uz' 'vq' 'vr' 'vv' 'w3' 'w4' 'we' 'wk' 'wt' 'wx' 'xa' 'xh' 'xl' 'yg' 'yi' 'yj' 'ym' - f | 'ae' 'av' 'bj' 'bk' 'c3' 'd3' 'dj' 'eb' 'ed' 'ef' 'ei' 'ej' 'en' 'ep' 'fl' 'fp' 'fr' 'fu' 'fz' 'g8' 'gd' 'h6' 'ht' 'hu' 'i7' 'if' 'im' 'j0' 'j1' 'je' 'jx' 'ku' 'l6' 'l7' 'll' 'lp' 'mc' 'ns' 'o4' 'oi' 'op' 'oz' 'q4' 'qa' 'qf' 'qh' 'ql' 'qn' 'qv' 'r0' 'r1' 'r4' 'rh' 'rj' 'rw' 'sd' 'sn' 'so' 't6' 'ti' 'tw' 'uc' 'uf' 'uk' 'ul' 'uw' 'v3' 'v8' 'vd' 'vr' 'w7' 'w9' 'wa' 'wb' 'wg' 'wh' 'wk' 'wl' 'wn' 'wo' 'wz' 'xf' 'xg' 'xo' 'xv' 'y2' 'yl' 'zr' 'zs' 'zw' - f | '4k' 'af' 'ah' 'b7' 'bj' 'by' 'ci' 'df' 'ds' 'eh' 'em' 'eq' 'ey' 'ez' 'fu' 'fv' 'g1' 'ga' 'go' 'gs' 'gy' 'gz' 'ho' 'i0' 'ie' 'ir' 'iv' 'k5' 'kj' 'ks' 'kw' 'l4' 'li' 'm0' 'mo' 'o8' 'ol' 'oq' 'os' 'ox' 'pk' 'pl' 'pq' 'q3' 'q6' 'qa' 'qg' 'qj' 'qn' 'qq' 'qr' 'qu' 'r5' 'r9' 'rb' 'ri' 'rl' 'rs' 'ry' 's7' 's9' 'sa' 'sd' 'sx' 'ta' 'tc' 'td' 'tf' 'tg' 'th' 'ti' 'to' 'tq' 'tv' 'uo' 'ut' 've' 'vt' 'w8' 'wg' 'wm' 'ws' 'wy' 'xy' 'y8' 'ya' 'yc' 'yf' 'ys' 'yu' 'zy' - f | 'aa' 'av' 'ay' 'bn' 'by' 'cm' 'da' 'dd' 'dj' 'dk' 'dr' 'dz' 'eu' 'ev' 'ez' 'f1' 'f8' 'gr' 'he' 'hp' 'hs' 'hw' 'iz' 'k1' 'kc' 'km' 'ko' 'kt' 'ln' 'ls' 'mx' 'n3' 'nl' 'oe' 'oj' 'om' 'os' 'oy' 'pg' 'pr' 'pt' 'pv' 'qa' 'qc' 'qe' 'qi' 'qj' 'qm' 'qn' 'qq' 'qu' 'qx' 'qz' 'r0' 'r1' 'rf' 'rs' 'rx' 'ry' 's4' 'sg' 't2' 'tq' 'tt' 'tv' 'ty' 'ua' 'uj' 'uq' 'vi' 'vk' 'vx' 'wc' 'we' 'wi' 'wl' 'wo' 'wp' 'wv' 'ww' 'xi' 'xr' 'xs' 'y9' 'yg' 'ym' 'yr' 'yt' 'yz' 'zo' 'zw' - f | 'ag' 'bm' 'co' 'cr' 'd7' 'dk' 'do' 'e6' 'e9' 'eb' 'ed' 'ef' 'eh' 'ep' 'eq' 'ew' 'f4' 'fd' 'fr' 'gc' 'gg' 'gq' 'gt' 'gv' 'h0' 'h4' 'hi' 'hm' 'i4' 'ib' 'im' 'is' 'j0' 'jc' 'jd' 'jo' 'ka' 'kk' 'kx' 'm3' 'nj' 'nr' 'nu' 'o2' 'ob' 'oe' 'oi' 'om' 'ow' 'oz' 'p3' 'pd' 'pf' 'ph' 'qi' 'qj' 'qu' 'qw' 'qy' 'r2' 'ra' 'rg' 'rj' 'rm' 'rn' 'ro' 'rp' 'rr' 'ry' 'rz' 's3' 'sa' 'so' 't6' 't7' 'ta' 'tc' 'u3' 'ub' 'vj' 'vm' 'vn' 'w7' 'wb' 'wf' 'wk' 'wn' 'x2' 'yi' 'zf' 'zh' - f | 'av' 'aw' 'bl' 'bt' 'cj' 'cx' 'df' 'ea' 'ed' 'ee' 'ef' 'ew' 'f5' 'fq' 'ft' 'fu' 'g6' 'gl' 'gs' 'ha' 'hj' 'hr' 'i8' 'ia' 'ic' 'ir' 'iz' 'j0' 'j5' 'jp' 'ju' 'k6' 'ki' 'lk' 'lz' 'mh' 'nl' 'o4' 'ob' 'oo' 'op' 'pf' 'po' 'pq' 'pr' 'q2' 'q3' 'q6' 'qd' 'qj' 'qk' 'qn' 'qt' 'qw' 'ro' 'rr' 'ru' 'rv' 'sc' 'sw' 'sy' 'sz' 't2' 'tb' 'tg' 'tl' 'tp' 'tv' 'u4' 'u9' 'um' 'uu' 'vj' 'vt' 'vu' 'wg' 'wh' 'wj' 'wo' 'wq' 'wt' 'xd' 'y1' 'yc' 'ye' 'yl' 'yw' 'zb' 'zd' 'zm' 'zr' - f | '41' '7r' 'a2' 'ad' 'aj' 'ak' 'ao' 'as' 'b1' 'b2' 'cn' 'db' 'eb' 'ec' 'ee' 'em' 'ev' 'ex' 'f8' 'fa' 'fo' 'fs' 'fu' 'gh' 'gk' 'gr' 'gx' 'iq' 'iv' 'j9' 'jb' 'jc' 'jr' 'kf' 'lg' 'm1' 'mq' 'mt' 'ne' 'nv' 'o5' 'od' 'os' 'ox' 'pc' 'pj' 'pq' 'q1' 'q6' 'q7' 'q8' 'qk' 'qm' 'qn' 'qp' 'qs' 'rj' 'rk' 's5' 'sb' 'sk' 'sn' 'sv' 't4' 'tb' 'th' 'ti' 'uc' 'uj' 'ut' 'vh' 'vp' 'wg' 'wi' 'wk' 'wp' 'ws' 'wv' 'wx' 'wy' 'x6' 'xa' 'xg' 'xr' 'xy' 'y6' 'yj' 'yo' 'yv' 'yw' 'zt' 'zw' - f | '5z' 'ad' 'al' 'ax' 'b4' 'bx' 'd7' 'da' 'dp' 'dz' 'e3' 'ef' 'en' 'es' 'et' 'ev' 'ex' 'f6' 'fj' 'fr' 'ft' 'fv' 'h9' 'hn' 'hx' 'i0' 'ii' 'it' 'jf' 'jk' 'jl' 'ka' 'kr' 'l9' 'lf' 'm3' 'mm' 'nc' 'nd' 'nr' 'o8' 'oe' 'ok' 'om' 'pd' 'ph' 'pz' 'qd' 'qf' 'qo' 'qp' 'qw' 'qx' 'qy' 'r6' 'rc' 'rg' 'rw' 'rx' 's8' 'se' 't3' 'tb' 'tc' 'ti' 'tl' 'to' 'tw' 'ub' 'ue' 'uf' 'uy' 'vf' 'vh' 'vr' 'w0' 'w9' 'wd' 'wf' 'wh' 'wp' 'wu' 'x0' 'x8' 'y2' 'ye' 'yq' 'ys' 'yt' 'z6' 'zf' 'zp' - f | '7u' '7z' 'a0' 'a5' 'c6' 'cj' 'cx' 'do' 'e4' 'eg' 'eh' 'eq' 'ey' 'ez' 'fe' 'fu' 'gk' 'gy' 'h9' 'ih' 'ik' 'il' 'j0' 'jt' 'jy' 'k1' 'k5' 'ke' 'lp' 'lx' 'ly' 'ma' 'mj' 'mm' 'mt' 'nb' 'nm' 'o3' 'o5' 'of' 'oi' 'ov' 'p2' 'pf' 'ph' 'pt' 'q8' 'qj' 'qk' 'qp' 'qs' 'r1' 'r8' 'rl' 'rp' 'rt' 's5' 'sb' 'sh' 'sk' 'so' 'sr' 'su' 'tc' 'tn' 'tr' 'tx' 'u4' 'uh' 'ul' 'up' 'ur' 'uw' 'uy' 'vm' 'w5' 'wb' 'wj' 'wm' 'wq' 'wy' 'x6' 'xq' 'xs' 'y8' 'y9' 'yi' 'yj' 'yv' 'yx' 'zi' 'zy' - f | 'a7' 'a9' 'ab' 'af' 'ah' 'bc' 'bg' 'bi' 'c2' 'cj' 'cl' 'dj' 'dn' 'do' 'dv' 'dw' 'e5' 'ec' 'es' 'f4' 'fa' 'fk' 'fv' 'h9' 'hi' 'hu' 'i5' 'ic' 'ig' 'im' 'ir' 'ji' 'jt' 'k2' 'kc' 'kd' 'ki' 'km' 'kz' 'l3' 'lh' 'li' 'lv' 'ml' 'ne' 'ni' 'nt' 'nx' 'o9' 'pm' 'pn' 'pr' 'px' 'q0' 'qa' 'qe' 'qj' 'r6' 'ra' 'rj' 'rn' 'rq' 'ru' 'ry' 's0' 'sq' 'tb' 'to' 'tw' 'ua' 'ub' 'uf' 'ui' 'un' 'uu' 'vi' 'vo' 'vv' 'w5' 'w7' 'w8' 'wo' 'wv' 'wy' 'xy' 'y2' 'ya' 'yh' 'yj' 'yo' 'za' 'zh' - f | '0h' '42' 'ak' 'al' 'bf' 'bz' 'co' 'd3' 'dc' 'dt' 'dy' 'ed' 'ee' 'eg' 'ev' 'ew' 'fg' 'fr' 'fz' 'gi' 'gy' 'ha' 'hb' 'hd' 'hl' 'hn' 'hs' 'ht' 'ij' 'io' 'iv' 'jh' 'jl' 'jr' 'kc' 'kj' 'kt' 'ku' 'ky' 'ln' 'ml' 'mu' 'ng' 'nm' 'o0' 'o1' 'of' 'oh' 'or' 'p8' 'q8' 'qb' 'qp' 'qr' 'qt' 'qu' 'qv' 'r8' 'rj' 'rl' 'rp' 'rw' 'sk' 'ss' 'sw' 't9' 'th' 'tl' 'u5' 'uj' 'us' 'vg' 'vt' 'vz' 'w4' 'wb' 'we' 'wl' 'ww' 'wx' 'wy' 'wz' 'xj' 'yb' 'yg' 'yn' 'yp' 'ys' 'yw' 'yz' 'zk' 'zp' 'zu' - f | '2s' 'a7' 'ae' 'am' 'bx' 'd5' 'de' 'do' 'ds' 'dt' 'e1' 'e3' 'e7' 'ed' 'ee' 'eg' 'ek' 'em' 'es' 'ev' 'fi' 'fw' 'g2' 'gf' 'gs' 'gu' 'gy' 'h7' 'hh' 'hi' 'hm' 'hu' 'ih' 'in' 'io' 'jr' 'js' 'jw' 'k0' 'k5' 'kb' 'l4' 'lu' 'm6' 'm8' 'mc' 'nb' 'od' 'ox' 'pc' 'pg' 'pv' 'py' 'q5' 'qc' 'qe' 'qf' 'qh' 'ql' 'qm' 'qo' 'qq' 'ra' 'rk' 'ro' 'rp' 'rr' 'ru' 'rw' 'se' 'sh' 't9' 'to' 'tq' 'tt' 'tw' 'u1' 'u4' 'ui' 'un' 'uq' 'vr' 'vy' 'vz' 'wh' 'wp' 'ws' 'wt' 'wy' 'xt' 'y8' 'yd' 'zp' - f | '3g' 'af' 'aj' 'ak' 'ap' 'as' 'au' 'cp' 'cx' 'dh' 'dn' 'dr' 'ds' 'ej' 'en' 'eo' 'et' 'eu' 'ex' 'fq' 'fs' 'ft' 'gw' 'h5' 'i5' 'ix' 'j6' 'jc' 'jg' 'k1' 'kb' 'kh' 'kn' 'kv' 'lj' 'lu' 'mc' 'mi' 'na' 'nq' 'ns' 'o4' 'o7' 'of' 'q5' 'q7' 'qe' 'qh' 'qi' 'qk' 'qr' 'qu' 'qw' 'r9' 'rb' 'ri' 'rx' 's3' 'sf' 'sm' 'so' 'sq' 'ss' 'su' 'sy' 't7' 'ta' 'ti' 'tn' 'tr' 'tx' 'u1' 'u3' 'ue' 'uh' 'up' 'uw' 'uy' 'va' 'w6' 'wg' 'wm' 'wp' 'ws' 'wy' 'x1' 'y4' 'y6' 'yk' 'ys' 'yy' 'zf' 'zv' - f | 'a4' 'ae' 'ax' 'bb' 'bg' 'ca' 'ch' 'cq' 'cv' 'dm' 'dn' 'en' 'ep' 'eu' 'ev' 'f0' 'g3' 'gk' 'gm' 'hd' 'ho' 'hp' 'hy' 'ij' 'im' 'iy' 'jl' 'jr' 'jy' 'kj' 'kt' 'ku' 'lp' 'mo' 'mr' 'mz' 'n4' 'nk' 'oc' 'ol' 'oo' 'os' 'oy' 'oz' 'p8' 'p9' 'ps' 'qb' 'qd' 'qg' 'qi' 'qv' 'qx' 'r1' 'ra' 'rf' 'rg' 'rm' 'ro' 'rr' 'rv' 'rz' 's7' 'sm' 'ss' 'tl' 'tr' 'tu' 'ty' 'u5' 'ui' 'un' 'uq' 'uv' 'vn' 'w1' 'w2' 'w6' 'wd' 'we' 'wg' 'wn' 'wp' 'wy' 'y2' 'y6' 'yc' 'yd' 'yt' 'yw' 'z8' 'ze' 'zs' - f | 'ai' 'cg' 'cs' 'dc' 'dg' 'di' 'dj' 'dk' 'dp' 'du' 'eb' 'ec' 'ee' 'ei' 'ek' 'eu' 'f2' 'fh' 'fm' 'fy' 'hc' 'hm' 'i2' 'ia' 'jj' 'ke' 'kl' 'lb' 'lc' 'ln' 'me' 'nc' 'nf' 'o6' 'oc' 'ok' 'os' 'pc' 'po' 'px' 'q2' 'q8' 'qa' 'qb' 'qd' 'qe' 'qg' 'qi' 'qo' 'qs' 'qt' 'qv' 'qx' 'r4' 'r9' 'ri' 'rn' 'rq' 'rr' 'rz' 's9' 'sf' 'sr' 'su' 'sw' 'sy' 'sz' 't2' 'ti' 'tv' 'ud' 'uv' 'wa' 'wc' 'wi' 'wk' 'wm' 'ws' 'wu' 'wv' 'wz' 'x2' 'xa' 'xf' 'y8' 'yb' 'yd' 'yl' 'yp' 'yr' 'ys' 'z5' 'zh' - f | '1a' 'a0' 'ae' 'av' 'be' 'bj' 'bv' 'bx' 'bz' 'ck' 'd4' 'do' 'ds' 'du' 'ee' 'eu' 'fg' 'fm' 'fy' 'g1' 'gh' 'h8' 'h9' 'ha' 'he' 'hl' 'hy' 'i6' 'ic' 'io' 'jb' 'jk' 'jq' 'k1' 'kf' 'km' 'kv' 'l8' 'n0' 'n3' 'oh' 'oz' 'po' 'q9' 'qg' 'qh' 'qi' 'ql' 'qp' 'qr' 'qu' 'qw' 'qx' 'rb' 're' 'rf' 'ri' 'rj' 'rv' 'sj' 'sm' 'sz' 't1' 'tl' 'tm' 'tw' 'tz' 'ua' 'uc' 'ug' 'ut' 'uv' 'ux' 'v7' 'wa' 'wc' 'wf' 'wi' 'wl' 'wp' 'wq' 'wr' 'x3' 'x6' 'xk' 'xx' 'y4' 'yp' 'yr' 'yw' 'yy' 'ze' 'zk' 'zy' - f | '1z' 'aq' 'cf' 'cl' 'e1' 'e5' 'ee' 'eg' 'eo' 'er' 'ff' 'fh' 'fx' 'g5' 'ga' 'gd' 'gm' 'gn' 'hc' 'hf' 'hi' 'hk' 'ho' 'ib' 'ik' 'in' 'iw' 'ix' 'jd' 'kl' 'ky' 'lp' 'm3' 'm5' 'n4' 'ng' 'o0' 'oc' 'oj' 'ot' 'ou' 'p2' 'pa' 'pd' 'pg' 'ps' 'pw' 'q1' 'q8' 'qb' 'qc' 'qd' 'qi' 'qr' 'qs' 'qu' 'qv' 'ra' 'rg' 'rt' 'rz' 's7' 'sm' 'sn' 't0' 'tb' 'th' 'tx' 'tz' 'ub' 'ud' 'ue' 'un' 'ur' 'ut' 'vb' 'vj' 'wg' 'wh' 'wj' 'wl' 'wn' 'ww' 'wz' 'x0' 'xc' 'xq' 'xr' 'xw' 'y8' 'y9' 'yr' 'z7' 'zt' - f | '27' '3p' '6r' 'a8' 'an' 'ap' 'au' 'ay' 'bi' 'c6' 'cy' 'dh' 'ds' 'eg' 'eh' 'ej' 'es' 'eu' 'fm' 'fp' 'fq' 'fx' 'g2' 'gg' 'gv' 'hz' 'ij' 'il' 'iq' 'iw' 'j8' 'j9' 'k3' 'kr' 'lq' 'm7' 'm9' 'mj' 'n0' 'n6' 'nr' 'nx' 'ox' 'pq' 'qc' 'qd' 'qe' 'qg' 'qh' 'qj' 'qk' 'qm' 'qn' 'qr' 'qu' 'qv' 'qw' 'qx' 're' 'rg' 'rr' 'rz' 's1' 'sj' 'sl' 'sy' 't4' 't7' 'tb' 'tr' 'uc' 'un' 'uq' 'ut' 'vf' 'w7' 'w9' 'wg' 'wh' 'wp' 'wq' 'ws' 'wx' 'x8' 'xp' 'xy' 'y0' 'y1' 'ya' 'yu' 'yz' 'z2' 'z5' 'zz' - f | '3k' 'ag' 'ak' 'bi' 'bl' 'bw' 'by' 'ch' 'cm' 'dw' 'e1' 'e2' 'ed' 'ej' 'ek' 'er' 'eu' 'ez' 'f8' 'fd' 'fi' 'fl' 'gi' 'gm' 'gx' 'gy' 'h2' 'h8' 'hl' 'hn' 'ij' 'ip' 'iq' 'it' 'jb' 'jl' 'jn' 'k7' 'kh' 'kl' 'kn' 'kt' 'nh' 'nk' 'pa' 'pe' 'pg' 'pp' 'q5' 'q7' 'qi' 'qk' 'ql' 'qs' 'r8' 'ri' 'rj' 'rl' 'rw' 'rx' 'so' 'tb' 'tj' 'tm' 'to' 'tu' 'tv' 'tz' 'u4' 'ue' 'ul' 'uv' 'v1' 'vj' 'vy' 'wc' 'wr' 'wt' 'wx' 'wz' 'xh' 'xj' 'xp' 'xt' 'y4' 'yb' 'yf' 'ym' 'yo' 'yq' 'yy' 'zp' 'zq' 'zt' - f | '9a' 'aa' 'bo' 'br' 'bv' 'bz' 'c1' 'c7' 'cz' 'db' 'dh' 'dj' 'e4' 'e8' 'eh' 'ew' 'gd' 'gg' 'gp' 'gu' 'gx' 'hc' 'ho' 'ht' 'hv' 'ia' 'ii' 'ij' 'ir' 'iw' 'j5' 'jk' 'jv' 'la' 'lc' 'lp' 'lt' 'lw' 'na' 'nt' 'nv' 'nw' 'o8' 'o9' 'ou' 'oy' 'p0' 'pc' 'pq' 'py' 'q4' 'q8' 'qi' 'qk' 'qn' 'qr' 'qt' 'qw' 'r5' 'r8' 're' 'rj' 'rt' 'rv' 'ry' 'rz' 's8' 'sg' 'sv' 'ta' 'td' 'tl' 'tm' 'ul' 'up' 'ut' 'uz' 'vf' 'w1' 'wb' 'wc' 'wd' 'wf' 'wi' 'wl' 'wu' 'x8' 'xg' 'xm' 'y1' 'yl' 'yr' 'ys' 'z8' - f | 'a3' 'a5' 'ai' 'av' 'ay' 'c3' 'cp' 'd3' 'dn' 'du' 'dz' 'e9' 'ed' 'ei' 'ek' 'em' 'eo' 'ev' 'f2' 'gh' 'gl' 'gy' 'h6' 'h8' 'hb' 'he' 'hg' 'hm' 'hp' 'hy' 'hz' 'id' 'ie' 'it' 'ix' 'j2' 'ja' 'jc' 'jf' 'k5' 'ki' 'kk' 'kv' 'l4' 'l6' 'ls' 'm9' 'mg' 'mt' 'nb' 'ng' 'oh' 'ot' 'oz' 'pw' 'py' 'pz' 'q0' 'q3' 'q8' 'qb' 'qh' 'qj' 'qk' 'ql' 'qp' 'qq' 'qr' 'qt' 'qw' 'rb' 'rz' 's3' 'sl' 'tb' 'u0' 'u5' 'uo' 'us' 'vc' 'wg' 'wh' 'wj' 'wr' 'wt' 'wu' 'wy' 'x1' 'y1' 'yh' 'z7' 'zf' 'zs' 'zu' - f | 'af' 'aq' 'at' 'bh' 'cc' 'd3' 'dd' 'dg' 'dq' 'e1' 'e6' 'ec' 'ee' 'ex' 'ey' 'go' 'gt' 'h3' 'h8' 'hd' 'he' 'hm' 'i7' 'ii' 'ik' 'io' 'ip' 'it' 'iz' 'jg' 'k0' 'k5' 'k7' 'kb' 'ks' 'kw' 'ln' 'lp' 'lx' 'm3' 'nf' 'nh' 'of' 'og' 'oj' 'ok' 'ow' 'p7' 'pd' 'pj' 'pm' 'q1' 'q7' 'qg' 'qh' 'qk' 'qq' 'qr' 'qt' 'qw' 'rr' 'rs' 'ry' 's4' 's7' 'sd' 'si' 'sl' 'sp' 'sw' 'sz' 't6' 't8' 'tc' 'u2' 'um' 'uo' 'ux' 'vb' 'w2' 'wb' 'wi' 'wj' 'ws' 'wt' 'wx' 'x3' 'xf' 'xt' 'yb' 'ym' 'zb' 'ze' 'zm' - f | '1s' 'a0' 'ac' 'aj' 'am' 'ao' 'aw' 'bi' 'bm' 'by' 'ca' 'cu' 'dc' 'di' 'dp' 'e0' 'e9' 'eg' 'eq' 'fh' 'fi' 'gc' 'gi' 'gq' 'gx' 'h4' 'he' 'hk' 'i2' 'ix' 'jc' 'jl' 'jm' 'k1' 'kf' 'kg' 'kn' 'kq' 'la' 'nj' 'nw' 'o9' 'og' 'p0' 'p6' 'pj' 'pn' 'pp' 'q4' 'qf' 'ql' 'qm' 'qs' 'qt' 'qu' 'qz' 'r5' 'r6' 'ri' 'ro' 'rw' 'sv' 'sx' 't5' 'th' 'tl' 'tp' 'u0' 'ue' 'uf' 'ug' 'un' 'uq' 'vx' 'wd' 'we' 'wg' 'wj' 'wk' 'wp' 'wr' 'ws' 'wt' 'x2' 'xq' 'xt' 'xw' 'xx' 'ya' 'yk' 'yl' 'yr' 'yt' 'za' 'zh' - f | '2o' 'af' 'ah' 'aj' 'al' 'ap' 'as' 'bc' 'd2' 'di' 'dm' 'do' 'ds' 'dt' 'dy' 'eb' 'ed' 'ee' 'ej' 'es' 'ev' 'ex' 'ey' 'gs' 'hk' 'hr' 'hw' 'hz' 'ig' 'is' 'jp' 'jv' 'jx' 'k4' 'kh' 'kv' 'lb' 'll' 'lw' 'na' 'no' 'o1' 'o8' 'oh' 'oo' 'op' 'pb' 'po' 'q2' 'q4' 'q7' 'qa' 'qc' 'qe' 'qg' 'qm' 'qo' 'qt' 'qw' 'qy' 'qz' 'r4' 'r7' 'r8' 'rp' 'rs' 's2' 'sb' 'sg' 'sl' 't1' 'tj' 'to' 'ts' 'tx' 'u5' 'uz' 'v6' 'w4' 'w5' 'we' 'wh' 'wn' 'wr' 'wu' 'wv' 'x1' 'y1' 'y8' 'ya' 'yk' 'ym' 'yw' 'z5' 'zx' - f | '2s' '4q' '8x' 'aa' 'ac' 'ah' 'av' 'aw' 'c4' 'c5' 'ce' 'd1' 'dj' 'dq' 'e7' 'e9' 'ea' 'ef' 'fc' 'fs' 'fz' 'gb' 'ge' 'gx' 'hf' 'hl' 'hm' 'i5' 'i7' 'ie' 'ii' 'iw' 'kf' 'ko' 'kx' 'lb' 'm6' 'mh' 'ob' 'od' 'oe' 'og' 'oq' 'or' 'pn' 'ps' 'pu' 'q4' 'qf' 'qg' 'qj' 'ql' 'qn' 'qt' 'qy' 'r3' 'ra' 'ri' 'rj' 'rv' 'sr' 'tg' 'th' 'tl' 'tx' 'u7' 'ub' 'uh' 'uq' 'uu' 'uy' 'vn' 'vt' 'wa' 'we' 'wh' 'wn' 'wp' 'wr' 'ww' 'xg' 'xk' 'xs' 'ya' 'yc' 'yd' 'yf' 'yl' 'ym' 'ys' 'z6' 'zj' 'zm' 'zv' 'zw' - f | '4d' '5a' 'ab' 'ae' 'ah' 'ai' 'be' 'cb' 'd6' 'dw' 'ea' 'eu' 'fb' 'fd' 'fe' 'fj' 'fk' 'g0' 'g9' 'gf' 'hc' 'hh' 'hk' 'i4' 'ik' 'iv' 'iz' 'j1' 'j3' 'j5' 'ju' 'jz' 'kc' 'md' 'ng' 'nk' 'o1' 'o9' 'oi' 'om' 'p4' 'pl' 'pn' 'ps' 'q8' 'qa' 'qb' 'qh' 'qj' 'qm' 'qn' 'qo' 'qq' 'qr' 'qt' 'qu' 'qy' 'qz' 'ro' 'rs' 's2' 'sl' 'sm' 'sp' 'ti' 'tn' 'tu' 'tw' 'u7' 'ug' 'ui' 'ul' 'us' 'ut' 'vc' 've' 'vj' 'vk' 'w0' 'w2' 'w8' 'wi' 'wk' 'wl' 'wm' 'wt' 'x6' 'xh' 'xy' 'yr' 'ys' 'yt' 'yy' 'yz' 'zr' - f | 'a1' 'ab' 'ad' 'ag' 'bd' 'bf' 'bo' 'bt' 'cl' 'cn' 'cq' 'cz' 'd4' 'db' 'dc' 'dk' 'dn' 'dq' 'ea' 'el' 'em' 'ev' 'ew' 'ex' 'fr' 'ft' 'ga' 'gc' 'gd' 'gg' 'gl' 'gp' 'hp' 'hu' 'id' 'ij' 'jn' 'kl' 'kt' 'lh' 'lk' 'lm' 'mi' 'mw' 'n4' 'nk' 'oj' 'ok' 'on' 'ph' 'pk' 'pt' 'q0' 'q8' 'qa' 'qe' 'qf' 'qg' 'qh' 'qi' 'qr' 'qt' 'qv' 'qw' 'qx' 'rd' 're' 'rg' 'rq' 'rr' 'sb' 'sg' 'te' 'tj' 'us' 'w5' 'w9' 'wb' 'wf' 'wh' 'wp' 'wq' 'ws' 'wt' 'wu' 'wv' 'y7' 'yb' 'ye' 'yf' 'yq' 'yu' 'yy' 'yz' 'zx' - f | 'ah' 'ao' 'aq' 'aw' 'az' 'b5' 'bd' 'bg' 'bj' 'bq' 'bu' 'cc' 'cv' 'dt' 'e0' 'e2' 'e4' 'ec' 'eu' 'fd' 'fi' 'gg' 'gu' 'ha' 'hb' 'he' 'hj' 'hy' 'ih' 'in' 'iv' 'ji' 'js' 'ks' 'l1' 'la' 'lg' 'mh' 'mi' 'mk' 'o7' 'oh' 'oj' 'om' 'on' 'op' 'oq' 'or' 'os' 'p1' 'pe' 'pq' 'pv' 'q8' 'qe' 'qg' 'qj' 'ql' 'qm' 'qn' 'qo' 'qr' 'qs' 'qt' 'qv' 'qy' 'r1' 'r9' 'rb' 'rl' 'ro' 'ru' 'rw' 'ry' 's0' 's6' 'sn' 't0' 't1' 'tr' 'ty' 'u0' 'u8' 'up' 'uv' 'vn' 'wb' 'wg' 'ww' 'x1' 'yb' 'yj' 'ym' 'yx' 'zz' - f | '2k' '2v' '4h' '7c' 'a3' 'aa' 'al' 'an' 'aq' 'aw' 'b7' 'bb' 'bl' 'bn' 'by' 'ca' 'cf' 'cu' 'dd' 'dn' 'e6' 'ej' 'en' 'et' 'eu' 'ey' 'g8' 'gg' 'go' 'gw' 'hj' 'ho' 'i3' 'ii' 'iy' 'ke' 'kh' 'le' 'lf' 'lu' 'ml' 'ny' 'oa' 'oc' 'og' 'oh' 'os' 'pf' 'pl' 'qb' 'qd' 'qf' 'qj' 'qn' 'qu' 'qw' 'r8' 'rd' 're' 'rh' 'sc' 'sn' 'ss' 't0' 't7' 'tl' 'tt' 'tx' 'tz' 'u9' 'uc' 'ud' 'ul' 'us' 'ux' 'vb' 'vf' 'vg' 'vp' 'w5' 'w6' 'wk' 'wt' 'wy' 'xd' 'xk' 'xm' 'xn' 'xr' 'xx' 'y0' 'yf' 'yl' 'yo' 'yw' 'zv' - f | '3k' '3v' 'a0' 'ah' 'am' 'an' 'ay' 'bd' 'cs' 'cu' 'cw' 'db' 'dp' 'e3' 'et' 'ey' 'fi' 'gl' 'gq' 'hh' 'hk' 'hx' 'i8' 'ih' 'ii' 'iv' 'iz' 'j5' 'jf' 'jo' 'jr' 'kd' 'km' 'lg' 'li' 'lt' 'm4' 'mo' 'mv' 'mw' 'n3' 'nh' 'nn' 'o9' 'od' 'of' 'oh' 'ok' 'or' 'pc' 'pg' 'pm' 'pn' 'q6' 'qj' 'qn' 'qr' 'qs' 'qw' 'r7' 'r9' 're' 'rm' 'rr' 'rt' 'rz' 'sb' 'sf' 'td' 'tu' 'uc' 'ug' 'uj' 'uu' 'w3' 'wa' 'wc' 'wg' 'wi' 'wm' 'wp' 'ww' 'wx' 'wz' 'xb' 'xi' 'y0' 'y9' 'ya' 'yd' 'yg' 'yh' 'yv' 'yy' 'zo' 'zz' - f | '3z' 'ah' 'ai' 'aq' 'bn' 'ck' 'cm' 'cq' 'ct' 'cy' 'd1' 'db' 'dn' 'e2' 'e7' 'ed' 'ee' 'eh' 'eq' 'er' 'ew' 'fc' 'fn' 'fp' 'fs' 'fw' 'fx' 'gl' 'gp' 'gw' 'ha' 'hq' 'hw' 'hx' 'i2' 'ir' 'j9' 'jb' 'jn' 'jr' 'jx' 'jy' 'kk' 'kl' 'kx' 'kz' 'li' 'm2' 'me' 'mj' 'mr' 'na' 'nu' 'oe' 'ol' 'on' 'po' 'pv' 'q7' 'qa' 'qb' 'qd' 'qh' 'qp' 'qv' 'rh' 'rz' 'sf' 'sp' 't6' 'tl' 'to' 'tx' 'ty' 'ue' 'uf' 'un' 'uu' 'uw' 'vb' 'vq' 'wg' 'wp' 'wt' 'wu' 'xb' 'xp' 'y1' 'y9' 'yi' 'yj' 'ys' 'yu' 'z7' 'zf' 'zt' - f | '4d' '9f' 'aa' 'ad' 'av' 'b1' 'bb' 'bd' 'bk' 'd2' 'd6' 'd7' 'de' 'do' 'ds' 'dx' 'e4' 'eh' 'en' 'ep' 'ew' 'fd' 'fg' 'fo' 'fp' 'ga' 'gw' 'gz' 'h2' 'h4' 'hc' 'hk' 'ic' 'ih' 'io' 'iv' 'iy' 'jj' 'jt' 'jz' 'kb' 'ke' 'kl' 'lh' 'lm' 'nc' 'ni' 'nl' 'o9' 'oi' 'oo' 'pd' 'pj' 'po' 'pr' 'qa' 'qf' 'qi' 'qm' 'qn' 'qp' 'qt' 'qu' 'rb' 're' 'rf' 'rn' 'rz' 'sz' 't0' 'tg' 'ti' 'ut' 'v9' 'vg' 'wb' 'wc' 'wf' 'wx' 'x0' 'xb' 'xv' 'y6' 'yb' 'yg' 'yh' 'yk' 'ym' 'yn' 'yw' 'yx' 'yz' 'z8' 'zp' 'zs' 'zw' - f | '5t' 'al' 'av' 'ax' 'by' 'cr' 'cx' 'df' 'dh' 'dp' 'dq' 'e4' 'e7' 'en' 'ff' 'fg' 'fo' 'g4' 'ge' 'gg' 'gm' 'gr' 'gt' 'hc' 'hn' 'hq' 'hs' 'i0' 'i1' 'id' 'ig' 'im' 'jb' 'jv' 'k9' 'kl' 'km' 'lh' 'lp' 'lq' 'mm' 'ne' 'nk' 'nu' 'od' 'os' 'pj' 'pw' 'pz' 'q0' 'q1' 'qa' 'qd' 'qe' 'qf' 'qk' 'ql' 'qn' 'qp' 'qt' 'r0' 'rx' 'sx' 'sy' 't0' 't1' 't8' 'th' 'ti' 'tp' 'tv' 'tz' 'ub' 'uc' 'ul' 'v5' 'vp' 'vu' 'w8' 'wd' 'we' 'wf' 'wh' 'wm' 'wq' 'wr' 'ws' 'wy' 'wz' 'xg' 'y9' 'yg' 'yh' 'yq' 'yz' 'z0' - f | '6w' 'a1' 'aa' 'ab' 'af' 'ao' 'aq' 'ay' 'cd' 'cg' 'dn' 'dp' 'dy' 'e0' 'e6' 'eb' 'ej' 'fh' 'fi' 'fs' 'g0' 'gc' 'gi' 'gs' 'gv' 'gw' 'hd' 'ho' 'i8' 'i9' 'ia' 'ic' 'ie' 'ik' 'ja' 'jd' 'ji' 'jm' 'k0' 'kj' 'lj' 'm8' 'n0' 'nh' 'nl' 'nn' 'o8' 'of' 'ou' 'oz' 'ph' 'po' 'q0' 'q3' 'q6' 'q7' 'qa' 'qc' 'qd' 'qn' 'qp' 'qq' 'qu' 'qw' 'qz' 'rd' 'rm' 'rn' 'rp' 'rs' 'sj' 'tg' 'tj' 'tr' 'tv' 'u0' 'uf' 'uh' 'uk' 'vv' 'wa' 'wc' 'wf' 'wg' 'wn' 'wo' 'wp' 'wr' 'ww' 'xt' 'y3' 'y7' 'yc' 'yf' 'yp' 'yy' - f | '9y' 'a0' 'a6' 'ad' 'aj' 'az' 'bw' 'by' 'cg' 'ci' 'dc' 'dk' 'dm' 'dw' 'e0' 'e4' 'ee' 'ef' 'eg' 'en' 'eu' 'fc' 'fg' 'fm' 'fx' 'g7' 'gm' 'go' 'hw' 'hy' 'i4' 'i7' 'ip' 'iq' 'ir' 'jr' 'ju' 'jx' 'kr' 'ky' 'la' 'lk' 'lq' 'm9' 'mg' 'mp' 'my' 'n6' 'nv' 'nz' 'o1' 'o3' 'oe' 'oy' 'pj' 'pv' 'pz' 'qg' 'ql' 'qp' 'qt' 'qy' 'r4' 'rf' 'rg' 'rk' 'ro' 'rw' 'ry' 's3' 'sd' 'sf' 'sm' 'tf' 'tg' 'tq' 'tu' 'ty' 'tz' 'ub' 'uc' 'uf' 'um' 'vi' 'vn' 'wa' 'wc' 'we' 'xo' 'xr' 'xs' 'yb' 'yi' 'yw' 'zn' 'zo' - f | 'ag' 'ai' 'az' 'br' 'c2' 'cd' 'ck' 'db' 'du' 'e0' 'e7' 'eb' 'ee' 'em' 'ep' 'eq' 'es' 'eu' 'ex' 'fh' 'fi' 'ga' 'gm' 'gn' 'hj' 'hq' 'if' 'ig' 'ii' 'ix' 'jk' 'kd' 'kg' 'kk' 'kr' 'kt' 'ku' 'lx' 'mp' 'mq' 'nx' 'o9' 'oa' 'om' 'oq' 'p5' 'pd' 'pr' 'pu' 'pw' 'q3' 'qa' 'qd' 'qe' 'qf' 'qi' 'qj' 'ql' 'qn' 'qo' 'qr' 'qt' 'qu' 'qv' 'qx' 'rc' 'rf' 'rl' 'rm' 'rn' 'rp' 'rr' 's7' 'se' 'st' 'sx' 't8' 'to' 'u1' 'ua' 'uq' 'ux' 'w6' 'w8' 'wf' 'wt' 'xb' 'xf' 'xk' 'xn' 'y3' 'ym' 'yp' 'yz' 'zi' 'zk' - f | '1k' '1p' 'a6' 'ah' 'ap' 'ay' 'az' 'bi' 'bj' 'cv' 'd1' 'd2' 'd5' 'db' 'dm' 'dn' 'e7' 'eg' 'eh' 'el' 'en' 'eo' 'er' 'f4' 'fy' 'gf' 'gp' 'hd' 'hj' 'hp' 'i2' 'i7' 'ij' 'ik' 'jq' 'jy' 'kg' 'kh' 'kw' 'lr' 'ls' 'n5' 'ne' 'o7' 'od' 'oi' 'oo' 'os' 'oy' 'pd' 'ph' 'pm' 'pw' 'px' 'qa' 'qb' 'qc' 'qk' 'ql' 'qm' 'qn' 'qr' 'qs' 'qu' 'qx' 'r5' 'rh' 'ri' 'rk' 'rn' 'ry' 's0' 'sa' 'si' 'sr' 'st' 'ub' 'uc' 'uf' 'uq' 'ur' 'v9' 'vn' 'w9' 'wd' 'we' 'wk' 'wt' 'wv' 'ww' 'xj' 'xk' 'yh' 'yk' 'zd' 'zw' 'zy' - f | '2u' '3q' '7p' 'b4' 'b8' 'bb' 'bq' 'bu' 'ce' 'dk' 'dn' 'e0' 'ea' 'ed' 'ef' 'eg' 'eh' 'ej' 'ek' 'em' 'en' 'eo' 'et' 'fh' 'fr' 'fw' 'gj' 'gx' 'ho' 'i7' 'i9' 'if' 'ii' 'il' 'in' 'iq' 'iw' 'jy' 'k0' 'k1' 'km' 'kr' 'lh' 'lq' 'lw' 'ma' 'mb' 'md' 'mj' 'nh' 'ni' 'nj' 'ob' 'p5' 'p7' 'pc' 'pk' 'pl' 'pu' 'q2' 'qa' 'qc' 'qe' 'qi' 'qm' 'qn' 'qt' 'rb' 'rp' 'rx' 'sd' 't6' 'tb' 'tl' 'tw' 'u5' 'u7' 'ug' 'uh' 'ut' 'vs' 'wi' 'wj' 'wp' 'ws' 'wu' 'wv' 'xm' 'xs' 'y2' 'y6' 'yd' 'yh' 'yl' 'yr' 'yx' 'yz' - f | '2u' 'au' 'bz' 'cd' 'cj' 'cm' 'cq' 'ct' 'cw' 'd1' 'ds' 'dw' 'dz' 'ec' 'ei' 'eo' 'fk' 'fq' 'fx' 'g6' 'gl' 'gs' 'i5' 'if' 'im' 'iq' 'jd' 'k0' 'k5' 'kr' 'lv' 'lx' 'n5' 'na' 'ny' 'ob' 'ot' 'ox' 'pa' 'pi' 'ps' 'qa' 'qc' 'qg' 'qh' 'qj' 'ql' 'qm' 'qo' 'qr' 'qs' 'r2' 'rh' 'rl' 'rr' 'rw' 'rx' 's0' 's8' 'sb' 'sc' 'sg' 'si' 'sl' 'so' 'sv' 't7' 't9' 'tc' 'te' 'tl' 'tn' 'to' 'tr' 'tx' 'ty' 'un' 'uz' 'vg' 'vw' 'ws' 'wt' 'wu' 'xj' 'xy' 'y0' 'y1' 'ya' 'ye' 'yl' 'yn' 'yr' 'ys' 'yt' 'z3' 'z6' 'zw' - f | '3a' '5k' 'a2' 'ah' 'au' 'ba' 'bb' 'bh' 'bu' 'cb' 'cj' 'cv' 'cx' 'df' 'dy' 'e4' 'e6' 'ed' 'ep' 'et' 'ev' 'ez' 'f1' 'fb' 'fl' 'fx' 'fz' 'gg' 'h5' 'hj' 'io' 'iz' 'ja' 'k7' 'kf' 'lu' 'lv' 'md' 'ne' 'nh' 'oh' 'on' 'ow' 'p0' 'p8' 'pc' 'px' 'q3' 'qa' 'qf' 'qg' 'qj' 'qr' 'qs' 'qt' 'qv' 'qx' 'qz' 'r3' 'rm' 'rq' 'rt' 'rv' 'sa' 'sf' 'so' 't1' 't7' 'tb' 'tn' 'tq' 'tr' 'ts' 'tu' 'tz' 'u7' 'uf' 'uk' 'um' 'ut' 'va' 'vj' 'vm' 'vx' 'vz' 'wa' 'we' 'wf' 'xe' 'xg' 'ya' 'yb' 'yu' 'zg' 'zo' 'zt' 'zz' - f | '3t' '5u' 'aa' 'ab' 'b9' 'd8' 'di' 'dj' 'dq' 'dx' 'dy' 'ea' 'ek' 'el' 'es' 'ev' 'ey' 'ez' 'fk' 'fp' 'g3' 'gb' 'gd' 'gg' 'gi' 'go' 'hj' 'hz' 'i3' 'i5' 'in' 'io' 'is' 'jv' 'kb' 'kr' 'lu' 'md' 'nd' 'ny' 'o6' 'oe' 'ok' 'ow' 'ox' 'p4' 'p7' 'p8' 'pb' 'pu' 'q1' 'q3' 'q4' 'qd' 'qj' 'qk' 'qq' 'qx' 'qy' 'r6' 'ro' 'rw' 'rx' 'ry' 'se' 'sp' 't0' 't1' 'th' 'tl' 'tn' 'tp' 'tr' 'tx' 'u5' 'uf' 'uo' 'ux' 'vc' 'vz' 'w2' 'w5' 'wa' 'wb' 'we' 'wi' 'wj' 'ws' 'wt' 'xh' 'y1' 'yb' 'yg' 'yi' 'zd' 'zm' 'zt' - f | '4g' '8w' 'ab' 'aq' 'at' 'bc' 'bi' 'c7' 'cb' 'cj' 'cs' 'd2' 'd3' 'di' 'dm' 'dx' 'dz' 'ed' 'ex' 'fj' 'gs' 'h1' 'h6' 'he' 'hj' 'hr' 'i1' 'ia' 'ie' 'il' 'ix' 'iy' 'j2' 'jd' 'jo' 'jy' 'kx' 'la' 'lv' 'ma' 'mh' 'mp' 'mt' 'n9' 'na' 'nf' 'ng' 'np' 'o7' 'ob' 'on' 'ou' 'ov' 'p9' 'pg' 'po' 'pq' 'q0' 'q4' 'q5' 'qc' 'qj' 'qp' 'qq' 'qt' 'ra' 'rb' 'rq' 'ru' 'sl' 'sp' 't8' 'ta' 'te' 'tl' 'tz' 'u1' 'ud' 'ui' 'uv' 'uw' 'vf' 'vt' 'vu' 'vz' 'w0' 'w7' 'wc' 'wg' 'wh' 'wq' 'wr' 'wz' 'y6' 'y7' 'ye' 'yh' - f | '6u' 'a5' 'ai' 'au' 'b1' 'be' 'bg' 'by' 'ce' 'co' 'cw' 'db' 'dw' 'e8' 'ec' 'em' 'en' 'er' 'f7' 'fh' 'fu' 'gb' 'gq' 'h4' 'hf' 'hy' 'hz' 'ig' 'iq' 'kj' 'kk' 'kp' 'ky' 'ld' 'lr' 'na' 'nd' 'ny' 'o8' 'o9' 'og' 'oh' 'ok' 'ot' 'ou' 'ow' 'ox' 'p8' 'pl' 'pp' 'ps' 'px' 'q0' 'q1' 'qa' 'qm' 'qr' 'qs' 'qx' 'r9' 'rd' 're' 'rf' 'rl' 'rn' 'rr' 'ru' 'rz' 'sc' 'sn' 'so' 't1' 'tl' 'tr' 'ts' 'tt' 'tx' 'ub' 'um' 'un' 'uo' 'ut' 'vr' 'wa' 'wb' 'wc' 'wj' 'wl' 'wp' 'wq' 'ws' 'wx' 'wz' 'yp' 'yt' 'yy' 'zc' - f | '7h' '7k' 'bi' 'c8' 'cc' 'cj' 'cs' 'd7' 'dh' 'dl' 'dp' 'dt' 'e9' 'ea' 'eh' 'ei' 'ej' 'el' 'ew' 'fo' 'fp' 'ge' 'gg' 'gi' 'gk' 'h2' 'h7' 'hk' 'hs' 'hy' 'ii' 'j4' 'kd' 'kh' 'kp' 'ks' 'm2' 'n1' 'n3' 'nk' 'nr' 'od' 'ok' 'om' 'oy' 'pb' 'ph' 'pm' 'pp' 'pt' 'q2' 'q8' 'q9' 'qc' 'qf' 'qg' 'qh' 'qj' 'qk' 'qn' 'qo' 'qq' 'qv' 'qx' 'r4' 'rc' 'rg' 'rj' 's9' 'sb' 'sg' 'sj' 'ss' 't6' 'ta' 'tc' 'tm' 'tv' 'us' 'uu' 'uy' 'w7' 'wf' 'wh' 'wk' 'wz' 'x2' 'xr' 'ya' 'yc' 'yk' 'yp' 'ys' 'yz' 'z4' 'zg' 'zn' - f | '15' '4o' '7h' 'aa' 'av' 'b0' 'cb' 'da' 'dh' 'di' 'dr' 'e0' 'ee' 'eo' 'ep' 'ey' 'fi' 'fo' 'fq' 'fx' 'fz' 'g9' 'ge' 'hd' 'hh' 'hs' 'i4' 'i9' 'iq' 'it' 'iw' 'ix' 'iy' 'j8' 'jr' 'ld' 'm1' 'mo' 'nx' 'ob' 'ol' 'ot' 'pj' 'qf' 'qj' 'qk' 'qp' 'qv' 'qy' 'r4' 'r5' 'rl' 'rm' 'rq' 'rz' 's8' 'sc' 'sd' 'sf' 'sh' 'sn' 'ss' 't5' 't7' 'tj' 'to' 'tw' 'u6' 'uc' 'ud' 'ug' 'ui' 'uk' 'ut' 'uy' 'uz' 'vi' 'w0' 'w9' 'wb' 'wg' 'wl' 'ww' 'wx' 'wy' 'xa' 'xb' 'xo' 'ya' 'yi' 'yu' 'yv' 'yz' 'zm' 'zv' 'zx' 'zy' 'zz' - f | '1g' '6b' 'az' 'be' 'c5' 'dp' 'dt' 'e6' 'eg' 'en' 'es' 'et' 'f1' 'fi' 'fn' 'ft' 'fz' 'g0' 'gj' 'gv' 'h8' 'hp' 'hs' 'hu' 'hw' 'hz' 'ia' 'im' 'is' 'iv' 'iw' 'iy' 'jd' 'kw' 'ky' 'l4' 'l7' 'mn' 'nn' 'nr' 'ny' 'ot' 'p2' 'p8' 'pt' 'q8' 'qa' 'qb' 'qf' 'qh' 'qi' 'qm' 'qt' 'qu' 'qv' 'qy' 'ra' 'rl' 'ro' 'rw' 'rx' 's8' 's9' 'sk' 'sn' 'st' 'sv' 'th' 'tl' 'to' 'tp' 'tu' 'ua' 'uk' 'un' 'uv' 'v8' 've' 'vt' 'vu' 'vv' 'w4' 'wc' 'wh' 'wo' 'wq' 'wy' 'xe' 'xm' 'xp' 'xu' 'yc' 'yn' 'yq' 'zf' 'zj' 'zs' 'zt' - f | '1t' 'a0' 'ah' 'ar' 'at' 'be' 'bs' 'bt' 'co' 'd9' 'e9' 'ea' 'ec' 'ei' 'eo' 'er' 'ez' 'fa' 'fz' 'gl' 'gt' 'h8' 'h9' 'hb' 'hv' 'ia' 'ic' 'if' 'im' 'io' 'iq' 'ix' 'k9' 'kq' 'lo' 'm4' 'md' 'mo' 'mz' 'ni' 'nr' 'nz' 'o8' 'ox' 'pk' 'pr' 'q1' 'q3' 'q8' 'qa' 'qb' 'qf' 'qg' 'qi' 'ql' 'qr' 'r3' 'rc' 'rf' 'rg' 'rr' 's0' 'sf' 'tg' 'tw' 'u2' 'uh' 'un' 'ur' 'ux' 'vb' 'vr' 'w7' 'w9' 'wd' 'wh' 'wm' 'wo' 'wr' 'ws' 'wv' 'x4' 'xj' 'xx' 'y3' 'y8' 'yd' 'yl' 'yo' 'yq' 'yr' 'yw' 'z8' 'za' 'zb' 'zg' 'zo' 'zs' - f | '2n' 'aa' 'ab' 'ae' 'ah' 'aj' 'as' 'av' 'ax' 'bc' 'be' 'bi' 'by' 'cg' 'ck' 'cm' 'cx' 'dq' 'dr' 'e5' 'ed' 'ef' 'ei' 'em' 'eu' 'fd' 'fq' 'fu' 'gd' 'gl' 'gs' 'he' 'ia' 'iz' 'jc' 'je' 'jt' 'k7' 'km' 'ko' 'l4' 'lh' 'mk' 'nl' 'ny' 'oa' 'oh' 'op' 'p1' 'pj' 'pm' 'ps' 'q1' 'q7' 'qc' 'qg' 'qj' 'qo' 'qr' 'qt' 'qu' 'qv' 'qw' 'rf' 'ri' 'rl' 'rw' 'sf' 'su' 't4' 'tc' 'tn' 'to' 'tq' 'tr' 'tt' 'tv' 'tz' 'u0' 'u6' 'ub' 'ug' 'up' 'uv' 'ux' 'uy' 'vv' 'w2' 'wx' 'xi' 'xu' 'xw' 'yj' 'yt' 'yw' 'z3' 'z7' 'zb' - f | '2y' '4v' 'ac' 'at' 'av' 'bd' 'bs' 'c3' 'ca' 'cf' 'cg' 'cq' 'cw' 'cz' 'db' 'dx' 'e7' 'eg' 'ei' 'el' 'et' 'ey' 'fo' 'fq' 'fw' 'fx' 'gd' 'gl' 'gw' 'h6' 'hd' 'hp' 'hy' 'il' 'ir' 'is' 'j5' 'k4' 'k8' 'kc' 'kp' 'kz' 'l0' 'l1' 'm4' 'm6' 'mn' 'mr' 'nx' 'ov' 'ox' 'pn' 'pq' 'q3' 'qd' 'qj' 'qk' 'qo' 'qw' 'qx' 'rd' 're' 'rg' 'rq' 'rr' 'rx' 'rz' 'sb' 't0' 't3' 't4' 'tc' 'tk' 'tp' 'tr' 'tv' 'u7' 'uf' 'um' 'uo' 'uq' 'va' 'vc' 'vi' 'vy' 'vz' 'w1' 'w6' 'wo' 'wq' 'xh' 'xn' 'y5' 'yo' 'ys' 'yt' 'zs' 'zu' - f | '4y' '6h' 'a0' 'a6' 'bo' 'bq' 'co' 'cv' 'dv' 'ec' 'ee' 'eh' 'ei' 'en' 'er' 'ew' 'f1' 'fk' 'fq' 'fy' 'ga' 'gj' 'gp' 'gv' 'gx' 'hv' 'i0' 'i5' 'ij' 'ik' 'in' 'kb' 'ks' 'kw' 'kz' 'la' 'lh' 'lq' 'ls' 'mu' 'nl' 'og' 'oi' 'om' 'pf' 'pu' 'pv' 'q6' 'q9' 'qe' 'qk' 'ql' 'qo' 'qq' 'qu' 'qw' 'r5' 'rb' 'rn' 'rr' 'rt' 's4' 'sc' 'sg' 'si' 'sm' 'sn' 'sp' 'ss' 'tb' 'tc' 'tg' 'tk' 'tm' 'tr' 'tt' 'tu' 'tv' 'u0' 'u3' 'uj' 'un' 'uz' 'vp' 'w6' 'w8' 'wc' 'we' 'wi' 'wt' 'wx' 'xp' 'xz' 'y0' 'y4' 'z0' 'zj' 'zy' - f | '5e' 'a1' 'ak' 'at' 'av' 'bi' 'bj' 'c7' 'dl' 'do' 'e0' 'ee' 'el' 'em' 'es' 'fl' 'fy' 'g2' 'g6' 'g7' 'gr' 'gv' 'h3' 'hg' 'hr' 'ht' 'ii' 'il' 'is' 'j8' 'jm' 'jq' 'jv' 'k0' 'ka' 'kk' 'l3' 'la' 'lh' 'ms' 'mz' 'no' 'oa' 'os' 'ox' 'pa' 'pc' 'pl' 'pq' 'px' 'q1' 'q3' 'q5' 'q8' 'qb' 'qi' 'ql' 'qw' 'qy' 'qz' 're' 'ri' 'rp' 'rx' 's1' 's3' 'sh' 'sq' 't1' 't5' 'ta' 'td' 'tj' 'to' 'tt' 'ub' 'uc' 'ur' 'uv' 'v1' 'vs' 'w7' 'wb' 'wd' 'wj' 'wl' 'wm' 'wq' 'xr' 'xt' 'ym' 'yu' 'yx' 'yz' 'z8' 'zp' 'zr' 'zs' - f | '5o' 'ar' 'at' 'c1' 'ch' 'cr' 'dp' 'dy' 'ed' 'el' 'er' 'f0' 'f7' 'fc' 'fh' 'fm' 'fx' 'g8' 'gd' 'gf' 'gh' 'gl' 'gp' 'gv' 'gy' 'hs' 'ht' 'hv' 'hy' 'i2' 'ia' 'lc' 'lu' 'lv' 'ly' 'mb' 'mq' 'nn' 'nz' 'oa' 'oq' 'ot' 'ox' 'oz' 'p8' 'pc' 'pn' 'py' 'q2' 'q7' 'qe' 'qj' 'qn' 'qs' 'qv' 'qw' 'r1' 'r4' 'rh' 'rn' 'rq' 'rr' 's1' 'sa' 'sd' 'se' 'sr' 't6' 'ta' 'tf' 'ts' 'tw' 'tx' 'uk' 'ul' 'uw' 'v7' 'vu' 'vz' 'w7' 'wc' 'wd' 'wk' 'wl' 'wo' 'wr' 'wv' 'x9' 'xe' 'xj' 'xl' 'xu' 'yi' 'ym' 'yq' 'z1' 'z5' 'zm' - f | '8d' 'a2' 'af' 'ap' 'as' 'cg' 'cr' 'd4' 'dg' 'du' 'dv' 'eg' 'ei' 'el' 'em' 'fg' 'ft' 'g1' 'gt' 'h1' 'hg' 'i5' 'i8' 'ih' 'im' 'ir' 'iw' 'jd' 'jf' 'js' 'jw' 'jz' 'k8' 'ko' 'ky' 'la' 'lr' 'mq' 'no' 'ox' 'p8' 'p9' 'pb' 'pv' 'pw' 'px' 'q0' 'q1' 'q5' 'q7' 'qd' 'qh' 'qj' 'ql' 'qn' 'qo' 'qq' 'qx' 'qy' 'rc' 'rd' 'rf' 'rh' 'rr' 'rs' 'sd' 'sw' 'sz' 't3' 'tf' 'tn' 'to' 'tv' 'tx' 'ty' 'ua' 'ub' 'ud' 'uk' 'ul' 'us' 'uu' 'ux' 'vl' 'vs' 'wf' 'wg' 'wl' 'wq' 'wt' 'wu' 'wx' 'x6' 'xi' 'yg' 'yh' 'z7' 'ze' - f | 'a3' 'ai' 'ap' 'ar' 'at' 'be' 'br' 'bz' 'cw' 'd2' 'd6' 'df' 'dk' 'do' 'dp' 'dr' 'dw' 'e2' 'ef' 'eg' 'ej' 'eq' 'fb' 'fd' 'fq' 'ge' 'gr' 'h0' 'hp' 'i8' 'ih' 'ir' 'jb' 'jd' 'kj' 'kz' 'l4' 'lm' 'lt' 'mj' 'mz' 'nc' 'ni' 'nw' 'of' 'oh' 'ol' 'ot' 'ov' 'p5' 'pf' 'pn' 'pp' 'pv' 'py' 'q2' 'q3' 'q7' 'qb' 'qc' 'qj' 'qo' 'qp' 'qr' 'qs' 'r6' 'ra' 'rc' 'rd' 'rx' 'se' 'sn' 'sr' 'sx' 't2' 't9' 'tm' 'tr' 'uj' 'vh' 'vn' 'vs' 'w0' 'w2' 'w3' 'wd' 'we' 'wj' 'wq' 'wr' 'wv' 'xe' 'xo' 'ya' 'ye' 'yq' 'yt' 'yw' - f | '1h' '4r' 'a9' 'ag' 'ah' 'ak' 'as' 'at' 'b2' 'be' 'cs' 'd6' 'd7' 'da' 'dg' 'dl' 'dr' 'dy' 'dz' 'e8' 'e9' 'eg' 'eh' 'ek' 'eq' 'es' 'f3' 'f9' 'fs' 'gh' 'go' 'gq' 'gz' 'ha' 'hc' 'hi' 'hp' 'if' 'ig' 'im' 'iv' 'jd' 'jt' 'kp' 'kt' 'l6' 'le' 'lg' 'lo' 'mz' 'ns' 'oc' 'ok' 'p6' 'pa' 'pt' 'pv' 'px' 'q1' 'q5' 'qa' 'qe' 'qg' 'qh' 'qi' 'qn' 'qp' 'qs' 'qu' 'qv' 'qy' 'rh' 'rl' 'rp' 'rv' 'rx' 'rz' 's8' 'sc' 'sr' 'su' 't6' 'tb' 'tq' 'tw' 'u9' 'vr' 'w7' 'wb' 'wj' 'wq' 'ww' 'xr' 'xx' 'yb' 'yl' 'yn' 'yr' 'zw' - f | '1r' '2q' 'aa' 'ae' 'ah' 'aq' 'at' 'bx' 'c6' 'ca' 'cl' 'da' 'dp' 'ds' 'e0' 'e6' 'ea' 'eb' 'eg' 'er' 'ev' 'ew' 'fs' 'fw' 'gm' 'gx' 'hl' 'hv' 'hw' 'ib' 'iw' 'jc' 'jn' 'jr' 'ju' 'k0' 'k5' 'k8' 'kf' 'kn' 'l1' 'ln' 'lp' 'ly' 'mz' 'n3' 'nc' 'ng' 'nk' 'o8' 'oe' 'oi' 'ol' 'ot' 'pb' 'pe' 'pk' 'q0' 'qa' 'qe' 'qg' 'qi' 'ql' 'qo' 'qv' 'r0' 'r2' 'r4' 'rg' 'rj' 'rm' 'sv' 'tk' 'to' 'tt' 'u7' 'ud' 'uo' 'ur' 'us' 'uv' 'vf' 'vm' 'vn' 'w6' 'w7' 'wa' 'wb' 'wf' 'wg' 'wi' 'wv' 'ww' 'wx' 'xk' 'xy' 'yg' 'yh' 'ym' - f | '6i' 'a3' 'ac' 'ax' 'br' 'ck' 'dc' 'dj' 'dn' 'dq' 'dt' 'dv' 'eb' 'ed' 'ei' 'en' 'eq' 'ey' 'f4' 'fk' 'fm' 'fp' 'fw' 'gn' 'gw' 'he' 'ho' 'io' 'ja' 'jj' 'jn' 'ju' 'jy' 'kc' 'kk' 'l1' 'l4' 'lt' 'lx' 'm1' 'm7' 'mc' 'o6' 'ol' 'p3' 'pc' 'pe' 'pp' 'pv' 'px' 'q0' 'qb' 'qe' 'qr' 'qs' 'qt' 'qu' 'qv' 'qy' 'rg' 'rq' 's3' 'sm' 'so' 't5' 't9' 'tb' 'tp' 'ty' 'tz' 'u6' 'ua' 'ui' 'uv' 'vm' 'vw' 'w2' 'wa' 'wf' 'wi' 'wj' 'wt' 'ww' 'wz' 'xg' 'y1' 'ya' 'yb' 'yd' 'yg' 'yh' 'yi' 'yk' 'yp' 'yz' 'zb' 'zk' 'zm' 'zo' - f | '0e' 'a0' 'a1' 'a5' 'ad' 'ao' 'bp' 'bw' 'c0' 'ca' 'cw' 'cx' 'cy' 'dg' 'e8' 'eb' 'ef' 'ek' 'fd' 'fk' 'fv' 'g3' 'gj' 'gn' 'gw' 'hr' 'if' 'ij' 'is' 'ix' 'j7' 'km' 'kp' 'kq' 'ks' 'kt' 'kv' 'lk' 'mj' 'mn' 'mv' 'mz' 'nn' 'o5' 'oa' 'ol' 'on' 'os' 'pa' 'pb' 'pf' 'po' 'pq' 'pr' 'pv' 'py' 'q1' 'q6' 'qf' 'qh' 'qj' 'qn' 'qt' 'qu' 'qw' 'rf' 'rk' 'rt' 's5' 'sq' 'ss' 't5' 'ta' 'th' 'tj' 'to' 'ts' 'tx' 'tz' 'u0' 'ua' 'ug' 'ui' 'uw' 'ux' 'vh' 'vp' 'we' 'wg' 'wi' 'wj' 'wp' 'wq' 'xm' 'y6' 'yr' 'yt' 'yu' 'z8' 'zs' - f | '1l' '24' '2o' 'ad' 'am' 'ao' 'bf' 'bl' 'ca' 'ce' 'cn' 'cw' 'cy' 'd4' 'dm' 'e9' 'ed' 'ee' 'ei' 'ep' 'f0' 'fk' 'fu' 'fw' 'g3' 'g4' 'gm' 'gn' 'gu' 'ha' 'hh' 'id' 'iq' 'it' 'iw' 'ix' 'iy' 'j4' 'j6' 'jo' 'jp' 'js' 'jv' 'k6' 'kb' 'ke' 'kh' 'l9' 'lh' 'lr' 'mr' 'n7' 'n8' 'nd' 'o6' 'of' 'oi' 'op' 'ox' 'p6' 'q2' 'qb' 'qd' 'qi' 'qk' 'qn' 'qq' 'qt' 'qy' 'r2' 're' 'rf' 'rk' 's4' 'sb' 'se' 'sh' 't4' 'tb' 'tn' 'tq' 'ty' 'u4' 'u5' 'ub' 'ue' 'uf' 'uk' 'uo' 'vc' 'vs' 'vu' 'w7' 'wd' 'wh' 'xm' 'yk' 'yv' 'zl' 'zz' - f | '1m' '37' 'a8' 'ab' 'at' 'ce' 'cx' 'd6' 'dk' 'e9' 'eh' 'ei' 'el' 'eo' 'eu' 'ew' 'ex' 'f4' 'fh' 'fr' 'fs' 'fy' 'g6' 'gf' 'gl' 'gm' 'gp' 'h8' 'ha' 'hf' 'hi' 'hl' 'hr' 'ie' 'ir' 'j6' 'jd' 'jr' 'jv' 'kz' 'l1' 'lg' 'ln' 'lp' 'ls' 'm0' 'ma' 'mi' 'mo' 'mu' 'na' 'np' 'o8' 'oc' 'oe' 'oh' 'ot' 'oy' 'ps' 'pw' 'q5' 'qa' 'qe' 'qg' 'qh' 'qi' 'qq' 'qz' 'rd' 'rg' 'ru' 'rv' 's9' 'sr' 'sv' 'sy' 'sz' 'ts' 'ty' 'uc' 'uh' 'uj' 'uk' 'up' 'v9' 'vc' 'vg' 'vt' 'vy' 'wl' 'wm' 'wv' 'wy' 'wz' 'xg' 'yg' 'yv' 'yw' 'yy' 'z0' - f | '2s' '3k' '4b' '6s' 'a1' 'b2' 'b9' 'bi' 'bz' 'c0' 'c3' 'ck' 'cl' 'cu' 'de' 'dl' 'do' 'dp' 'e8' 'ec' 'ee' 'ei' 'ek' 'eu' 'ez' 'fi' 'fo' 'fr' 'fu' 'fx' 'gh' 'gk' 'go' 'gq' 'h4' 'hd' 'hm' 'hz' 'ia' 'id' 'iv' 'jb' 'jh' 'km' 'kp' 'l4' 'l7' 'l8' 'ld' 'lj' 'nb' 'o7' 'oc' 'oh' 'os' 'p4' 'p9' 'pd' 'q6' 'q7' 'q8' 'qc' 'qh' 'qj' 'qk' 'qw' 'rg' 'rj' 'rm' 'rn' 'rp' 'ru' 'rz' 's5' 'si' 'sv' 'sy' 'tc' 'tg' 'tk' 'tv' 'ue' 'uf' 'ux' 'uz' 'vl' 'w2' 'w6' 'wf' 'wm' 'wu' 'wx' 'xh' 'ya' 'yc' 'ye' 'z7' 'zi' 'zo' 'zq' - f | '3s' '6q' 'ad' 'am' 'as' 'ay' 'cd' 'ci' 'cl' 'dw' 'eb' 'en' 'ep' 'ew' 'ey' 'fh' 'g6' 'gb' 'gk' 'h5' 'hk' 'hp' 'hy' 'i8' 'ia' 'ic' 'ih' 'in' 'is' 'iw' 'jd' 'je' 'kh' 'kp' 'ks' 'lg' 'lz' 'mx' 'my' 'nf' 'nh' 'no' 'nv' 'o4' 'oa' 'oc' 'op' 'p2' 'p5' 'pa' 'pb' 'pt' 'pw' 'q2' 'q4' 'qb' 'qg' 'qh' 'qq' 'qs' 'qt' 'qx' 'qy' 'qz' 'r7' 'rc' 'rk' 'rt' 'sr' 'sx' 'sy' 'tc' 'tn' 'tr' 'tv' 'u1' 'u7' 'ua' 'uh' 'uz' 'vi' 'wd' 'wr' 'x3' 'x5' 'xa' 'xe' 'y5' 'y7' 'yb' 'yg' 'yk' 'ym' 'yr' 'yt' 'z7' 'zc' 'zf' 'zj' 'zp' - f | '5k' 'a1' 'ab' 'an' 'ar' 'as' 'av' 'ax' 'br' 'c2' 'c7' 'd5' 'da' 'dl' 'dr' 'dz' 'e3' 'ec' 'ed' 'ek' 'el' 'em' 'eu' 'ew' 'fd' 'ff' 'fw' 'g8' 'gb' 'gl' 'hh' 'hs' 'hz' 'i6' 'ia' 'ig' 'ii' 'ik' 'iq' 'ix' 'j0' 'j9' 'jf' 'jl' 'jo' 'jw' 'ko' 'kt' 'lm' 'nl' 'nm' 'ov' 'p3' 'p6' 'p7' 'pg' 'pl' 'pn' 'pp' 'qd' 'qe' 'qf' 'qn' 'qo' 'qq' 'qs' 'qt' 'qv' 'r9' 'rf' 'rj' 'rt' 'rw' 'sa' 'sl' 't2' 'tg' 'tk' 'tq' 'ty' 'ua' 'ud' 'vi' 'vm' 'w2' 'w6' 'wb' 'wd' 'wf' 'wi' 'wl' 'wq' 'wr' 'wy' 'x5' 'x8' 'y0' 'y1' 'ys' 'yx' - f | '6f' 'a1' 'ag' 'ak' 'ap' 'au' 'b1' 'b5' 'bi' 'c1' 'cu' 'd5' 'dc' 'dr' 'dv' 'eg' 'ej' 'ek' 'em' 'et' 'fe' 'fr' 'fz' 'ga' 'gb' 'gk' 'gu' 'gv' 'h5' 'hh' 'ho' 'hy' 'ii' 'ik' 'ip' 'iv' 'ja' 'jg' 'jz' 'k0' 'kt' 'm6' 'mj' 'nd' 'o0' 'o1' 'oj' 'or' 'ot' 'ov' 'oz' 'ph' 'pm' 'pv' 'qa' 'qe' 'qf' 'qg' 'qh' 'qj' 'qn' 'qt' 'qy' 'r5' 'rd' 'rg' 'rs' 'ru' 'rz' 's7' 'sf' 'si' 'sl' 'sw' 'sy' 't0' 't3' 'th' 'tn' 'tq' 'tu' 'ub' 'us' 'ux' 'vb' 'vo' 'wa' 'wd' 'wn' 'wq' 'wt' 'ww' 'wx' 'y1' 'yh' 'yo' 'yq' 'yz' 'z7' 'ze' - f | 'an' 'as' 'cm' 'dh' 'dk' 'do' 'ds' 'dv' 'e1' 'eh' 'ek' 'el' 'er' 'ew' 'ff' 'fo' 'fq' 'g2' 'gz' 'h0' 'hi' 'hk' 'hm' 'hs' 'i4' 'ij' 'iy' 'j5' 'jj' 'jk' 'jw' 'kq' 'kx' 'ky' 'lo' 'lp' 'lw' 'ly' 'm2' 'm6' 'md' 'mv' 'ng' 'of' 'om' 'oy' 'p7' 'pr' 'q7' 'qc' 'ql' 'qq' 'qs' 'qy' 'qz' 'r2' 'r9' 'ra' 'rn' 'ro' 'rq' 'rv' 'rx' 'ry' 'rz' 's0' 'si' 'sy' 'sz' 't6' 't7' 'to' 'tt' 'tv' 'tx' 'ub' 'ur' 'uv' 've' 'vj' 'w3' 'w8' 'w9' 'wa' 'wb' 'wc' 'we' 'wm' 'wt' 'wu' 'wx' 'wy' 'y9' 'yd' 'yg' 'ym' 'yp' 'yt' 'yu' 'yy' - f | '1h' '1j' '1o' '2d' 'ac' 'ak' 'b6' 'cx' 'd3' 'ds' 'dv' 'e7' 'es' 'ev' 'ez' 'fs' 'fx' 'fy' 'gc' 'gh' 'gs' 'gt' 'hk' 'ho' 'i8' 'id' 'ig' 'ii' 'iq' 'j5' 'jd' 'je' 'jg' 'jk' 'jl' 'jo' 'jr' 'kf' 'kl' 'kq' 'lf' 'lh' 'lz' 'mb' 'mu' 'ni' 'nz' 'o4' 'ol' 'p7' 'pl' 'pm' 'pv' 'q5' 'qa' 'qe' 'qh' 'qi' 'ql' 'qq' 'qw' 'ra' 'rb' 'rn' 's5' 'sf' 'sh' 'so' 'sp' 'sq' 'sw' 'tj' 'tu' 'ty' 'u3' 'ue' 'uo' 'ux' 'v8' 'vo' 'vr' 'vz' 'w4' 'w8' 'wa' 'wk' 'wl' 'wo' 'wr' 'wu' 'ww' 'xs' 'xx' 'yb' 'yf' 'yn' 'yt' 'yw' 'zf' 'zg' 'zs' - f | '1l' '2l' 'ag' 'aj' 'al' 'an' 'ay' 'bo' 'cg' 'cs' 'cw' 'cx' 'db' 'dd' 'e1' 'e8' 'ee' 'ef' 'ej' 'eu' 'ew' 'fc' 'ff' 'fh' 'fo' 'fv' 'fz' 'g1' 'gj' 'gk' 'gw' 'ha' 'i3' 'ib' 'iu' 'jv' 'k9' 'kq' 'ku' 'kw' 'lv' 'lw' 'ly' 'mp' 'my' 'nf' 'ng' 'nw' 'o6' 'oe' 'or' 'ou' 'oz' 'p4' 'pc' 'ph' 'pn' 'py' 'q0' 'qd' 'qe' 'qp' 'qs' 'qu' 'qv' 'qz' 'r6' 'rg' 'rj' 'rt' 'ru' 'rv' 'rw' 'sx' 't2' 'tl' 'tn' 'tq' 'tx' 'tz' 'ue' 'ui' 'ul' 'uo' 'uu' 'w0' 'w1' 'w4' 'w6' 'w8' 'w9' 'wh' 'wi' 'wp' 'ws' 'wt' 'wx' 'yd' 'zd' 'zf' 'zx' - f | '1x' '3m' 'a1' 'a5' 'a7' 'al' 'aq' 'ar' 'c8' 'cc' 'cd' 'd0' 'dt' 'e6' 'ei' 'em' 'ez' 'f6' 'fc' 'ff' 'fg' 'fp' 'gm' 'h3' 'ha' 'hg' 'ho' 'hs' 'ib' 'ie' 'il' 'it' 'ix' 'j3' 'jl' 'jt' 'jv' 'jw' 'kd' 'ki' 'l1' 'lk' 'lr' 'lv' 'm0' 'mx' 'my' 'n6' 'ni' 'o2' 'o4' 'o9' 'om' 'p0' 'p6' 'pi' 'pj' 'q5' 'qa' 'qc' 'qg' 'qp' 'qs' 'qu' 'qw' 'rg' 'rt' 'rz' 'se' 'sj' 'sp' 'su' 'sw' 'te' 'tp' 'tq' 'tt' 'tu' 'tx' 'u3' 'un' 'uo' 'up' 'uq' 'vc' 'vj' 'vu' 'w2' 'wh' 'wj' 'ws' 'wv' 'ww' 'xg' 'yc' 'yf' 'yv' 'z2' 'zl' 'zw' 'zy' - f | '5q' '7c' 'a1' 'ac' 'ao' 'az' 'bw' 'cz' 'd8' 'dr' 'dy' 'ec' 'eg' 'ej' 'el' 'es' 'et' 'fa' 'fh' 'g2' 'gm' 'go' 'gp' 'gy' 'h6' 'hd' 'he' 'ho' 'ij' 'ik' 'it' 'jc' 'ji' 'k8' 'ku' 'l8' 'lf' 'mw' 'n8' 'nb' 'nd' 'o3' 'ok' 'ol' 'ot' 'p8' 'pi' 'pl' 'pn' 'ps' 'qd' 'qe' 'qk' 'ql' 'qt' 'qz' 'r0' 'r7' 'rd' 'rg' 'rh' 'rm' 'ro' 'rp' 'ru' 'rz' 'sj' 'sm' 'sr' 'su' 'sv' 'sx' 't1' 'tc' 'tl' 'tq' 'uj' 'um' 'uv' 'uw' 'wa' 'wb' 'wi' 'wo' 'wr' 'ws' 'wv' 'wz' 'xb' 'xg' 'ya' 'yb' 'yh' 'yi' 'ym' 'yn' 'yr' 'yv' 'z6' 'zf' 'zz' - f | 'ab' 'ad' 'al' 'cm' 'cw' 'dh' 'dn' 'dy' 'e8' 'ea' 'ed' 'ej' 'eq' 'er' 'eu' 'ev' 'f5' 'fb' 'fj' 'fr' 'gc' 'gp' 'h2' 'h6' 'hc' 'hw' 'i3' 'i5' 'id' 'ir' 'ix' 'ka' 'kj' 'ko' 'lv' 'lx' 'mj' 'mv' 'nq' 'ns' 'oa' 'od' 'ok' 'om' 'os' 'p1' 'p5' 'pb' 'pg' 'pj' 'pl' 'ps' 'pu' 'q1' 'qb' 'qd' 'qe' 'qj' 'qk' 'ql' 'qr' 'qs' 'rd' 'rl' 'ro' 'rs' 'rx' 's1' 'sf' 'sg' 't0' 'tb' 'te' 'tf' 'tg' 'tl' 'tp' 'tq' 'u3' 'uf' 'ug' 'up' 'uq' 'vx' 'vy' 'w5' 'wa' 'wc' 'wr' 'ws' 'wu' 'wx' 'wy' 'wz' 'yf' 'ym' 'yz' 'ze' 'zs' 'zy' 'zz' - f | '13' '6k' 'ae' 'ah' 'an' 'at' 'aw' 'cc' 'cn' 'du' 'dx' 'ek' 'el' 'em' 'en' 'es' 'ey' 'f2' 'fe' 'fh' 'fk' 'fv' 'g6' 'g9' 'gw' 'hj' 'hn' 'hs' 'hu' 'hv' 'ia' 'im' 'iq' 'ix' 'jh' 'jm' 'ki' 'lj' 'lo' 'lt' 'lw' 'm1' 'nv' 'nw' 'ny' 'oj' 'oo' 'ot' 'ov' 'ox' 'pd' 'pv' 'q1' 'q7' 'qc' 'qd' 'qj' 'ql' 'qp' 'qq' 'qv' 'qw' 'qx' 'r7' 'ry' 'so' 'st' 'su' 'sx' 't9' 'tf' 'th' 'ty' 'uh' 'uo' 'ut' 'uv' 'uy' 'vj' 'vp' 'vu' 'vw' 'w3' 'w5' 'w8' 'wc' 'we' 'wg' 'wi' 'wl' 'wv' 'xh' 'xx' 'yb' 'yd' 'yj' 'yn' 'yo' 'yr' 'yy' 'zk' 'zx' - f | '4m' 'a3' 'ac' 'ag' 'ai' 'au' 'av' 'bd' 'bu' 'cl' 'd0' 'dc' 'dy' 'ej' 'el' 'eo' 'es' 'eu' 'ex' 'fr' 'fx' 'g6' 'g9' 'gk' 'gq' 'gr' 'gw' 'gx' 'gz' 'hv' 'ii' 'ix' 'jj' 'jy' 'k0' 'kl' 'kn' 'kw' 'l5' 'lo' 'lz' 'm1' 'n5' 'n9' 'nf' 'nm' 'nz' 'ol' 'os' 'ot' 'oy' 'p1' 'p9' 'pa' 'pj' 'pl' 'pp' 'qc' 'qh' 'qj' 'qr' 'qs' 'qw' 'qz' 'rg' 'ri' 'rl' 'rn' 'rp' 'rt' 'rx' 'rz' 'se' 'sl' 'sv' 'sy' 't8' 'td' 'th' 'tr' 'tx' 'u3' 'u7' 'uc' 'ud' 'ul' 'un' 'up' 'uv' 've' 'vz' 'w7' 'wr' 'y0' 'y6' 'yh' 'yo' 'yu' 'yy' 'yz' 'z6' 'zm' - f | '6p' 'an' 'aq' 'au' 'br' 'bz' 'c3' 'ca' 'cg' 'cn' 'db' 'dk' 'dq' 'e0' 'e8' 'ek' 'eo' 'er' 'ez' 'fd' 'ft' 'g0' 'gd' 'gh' 'gk' 'gn' 'gr' 'gv' 'gy' 'hb' 'hc' 'he' 'ht' 'ii' 'ip' 'iu' 'j9' 'jn' 'jo' 'jq' 'jz' 'kh' 'kn' 'ko' 'l3' 'ls' 'lz' 'nh' 'nk' 'ok' 'oy' 'p7' 'pd' 'ph' 'pu' 'pw' 'py' 'q7' 'qa' 'qi' 'qk' 'ql' 'qn' 'qq' 'qr' 'qs' 'qv' 'qx' 'qy' 'rg' 'rs' 'ru' 'sg' 'sl' 'sq' 'sr' 'su' 'ts' 'tt' 'ui' 'um' 'ut' 'uu' 'v0' 'v5' 'w7' 'wb' 'wc' 'wf' 'wi' 'wm' 'xd' 'xs' 'xz' 'y3' 'y4' 'y9' 'yi' 'yp' 'yx' 'z0' 'zf' - f | '1f' '3z' '43' 'am' 'b9' 'bg' 'cc' 'ct' 'cx' 'd0' 'de' 'dm' 'dr' 'e0' 'e8' 'ef' 'en' 'ev' 'fd' 'ff' 'fx' 'ga' 'gm' 'gp' 'gr' 'gs' 'gy' 'h1' 'hi' 'hl' 'hs' 'i4' 'i5' 'ic' 'jb' 'jj' 'kj' 'lh' 'ng' 'ni' 'nn' 'ns' 'nx' 'o1' 'oa' 'oe' 'og' 'p4' 'pd' 'ph' 'pj' 'pl' 'pw' 'q9' 'qa' 'qd' 'qh' 'ql' 'qr' 'qs' 'qw' 'qx' 'ro' 'rs' 'rw' 'ry' 'rz' 'sb' 'sj' 'sm' 'so' 't0' 't6' 'tc' 'ti' 'tk' 'tn' 'uk' 'um' 'uw' 'uy' 'v9' 'vd' 'vg' 'w3' 'wf' 'wg' 'wi' 'wk' 'wm' 'wx' 'xe' 'xm' 'xn' 'y5' 'ye' 'yk' 'yq' 'z3' 'zj' 'zk' 'zt' 'zz' - f | '1t' 'ai' 'cu' 'cw' 'cx' 'dd' 'de' 'ds' 'e0' 'e2' 'e6' 'eb' 'ei' 'eq' 'eu' 'ev' 'ez' 'f5' 'f8' 'fc' 'g2' 'gd' 'gs' 'gv' 'hu' 'hy' 'id' 'ig' 'ij' 'ir' 'iv' 'ju' 'ka' 'kj' 'kl' 'ks' 'kv' 'kw' 'kx' 'la' 'lh' 'lm' 'ls' 'lv' 'lz' 'mg' 'mh' 'mp' 'ns' 'nt' 'nu' 'nx' 'o6' 'o9' 'oc' 'oj' 'pa' 'pj' 'pl' 'pv' 'q3' 'q5' 'qb' 'qh' 'ql' 'qn' 'qr' 'qs' 'qz' 'rb' 'rf' 'rh' 'rm' 'sm' 'sn' 'sw' 't5' 't9' 'tq' 'ty' 'uj' 'v2' 'vz' 'w6' 'wc' 'wg' 'wi' 'wj' 'wk' 'wm' 'wn' 'wt' 'wv' 'ww' 'wz' 'x0' 'xb' 'xc' 'yb' 'yt' 'yv' 'zp' 'zy' - f | 'a3' 'ad' 'ar' 'at' 'bb' 'bf' 'bt' 'cg' 'cx' 'd6' 'de' 'df' 'e4' 'e6' 'eg' 'et' 'ex' 'f0' 'fe' 'fg' 'fj' 'fo' 'gh' 'hb' 'hj' 'hq' 'hr' 'hv' 'ia' 'id' 'is' 'it' 'iy' 'ja' 'jj' 'jq' 'jw' 'l2' 'l7' 'lc' 'lu' 'nc' 'no' 'np' 'nt' 'ob' 'od' 'og' 'oo' 'os' 'pe' 'pj' 'pl' 'po' 'pq' 'pu' 'q2' 'qa' 'qc' 'qf' 'qr' 'qt' 'qx' 're' 'rk' 'rn' 'ro' 'ru' 'rw' 'rx' 's7' 's8' 'sy' 'tc' 'tf' 'tg' 'th' 'tm' 'to' 'tv' 'tx' 'tz' 'va' 'vp' 'w0' 'w1' 'wh' 'wl' 'wq' 'wr' 'wt' 'ww' 'wy' 'x7' 'xl' 'xy' 'y0' 'ye' 'yr' 'yy' 'z3' 'zf' 'zo' - f | 'ad' 'ar' 'az' 'b7' 'cf' 'cm' 'ct' 'cw' 'cy' 'dh' 'dn' 'ds' 'ef' 'en' 'eo' 'er' 'fh' 'fi' 'fq' 'fr' 'fx' 'gp' 'gq' 'gu' 'gx' 'h8' 'hf' 'hj' 'hk' 'ho' 'hw' 'hy' 'i3' 'i4' 'ik' 'iu' 'iy' 'jj' 'kn' 'l8' 'lb' 'lg' 'lo' 'm7' 'mx' 'nj' 'nt' 'o6' 'ob' 'oh' 'ok' 'ot' 'pr' 'pz' 'q7' 'q8' 'qa' 'qd' 'qg' 'qh' 'qi' 'qn' 'qz' 'r7' 're' 'ri' 'rk' 'ry' 's4' 'sa' 'sd' 'sm' 'sn' 'sp' 'sw' 'sy' 'tf' 'th' 'to' 'tr' 'tv' 'tz' 'u0' 'u1' 'u5' 'ue' 'uk' 'uq' 'vb' 'vp' 'vr' 'vu' 'wa' 'wb' 'wg' 'wi' 'wk' 'wm' 'wt' 'ya' 'yj' 'yl' 'z3' - f | '12' 'ac' 'ay' 'bc' 'bj' 'bm' 'bo' 'ce' 'cf' 'ck' 'cr' 'db' 'do' 'du' 'dy' 'ea' 'ej' 'ek' 'eo' 'ep' 'et' 'f2' 'fc' 'fl' 'fs' 'fy' 'g9' 'gf' 'hj' 'hk' 'hp' 'i1' 'i5' 'ih' 'ii' 'im' 'jp' 'jx' 'k9' 'kf' 'ky' 'mb' 'mj' 'mk' 'nb' 'nc' 'o0' 'o9' 'oc' 'oj' 'oq' 'pm' 'ps' 'pt' 'pu' 'pv' 'py' 'qd' 'qi' 'qj' 'qk' 'ql' 'qm' 'qs' 'qz' 'ra' 'rc' 'rd' 'rh' 'ri' 'ro' 's0' 's3' 's7' 's9' 'sv' 't2' 't7' 'tm' 'tp' 'tw' 'tx' 'ty' 'u3' 'u6' 'uf' 'ug' 'ui' 'uk' 'ut' 'ux' 'v5' 'w3' 'wk' 'wt' 'xo' 'xq' 'xr' 'xu' 'ye' 'yl' 'yn' 'yt' 'yv' 'zm' - f | '1o' '7o' 'a1' 'aq' 'b4' 'bi' 'bp' 'c9' 'cb' 'cd' 'cf' 'co' 'cp' 'd3' 'd8' 'ds' 'dv' 'dy' 'eb' 'ee' 'ef' 'eh' 'em' 'eo' 'es' 'ez' 'fi' 'fk' 'fl' 'gj' 'gn' 'gt' 'h1' 'hn' 'ho' 'hp' 'hu' 'ic' 'ik' 'il' 'im' 'ir' 'iw' 'ji' 'jp' 'k4' 'ks' 'm0' 'ml' 'n0' 'ns' 'oj' 'on' 'or' 'os' 'ov' 'pr' 'pv' 'px' 'py' 'q6' 'qa' 'qc' 'qg' 'qj' 'qm' 'qn' 'qp' 'qq' 'qs' 'qv' 'qz' 'r0' 'ra' 's0' 'te' 'tg' 'tm' 'to' 'tw' 'u1' 'u7' 'ug' 'um' 'uw' 'ux' 'uz' 'vm' 'vu' 'w4' 'wg' 'wh' 'wj' 'wk' 'wm' 'wo' 'wq' 'ws' 'wt' 'wz' 'x0' 'x5' 'yg' 'yn' 'z6' - f | '2l' '9f' 'a2' 'ak' 'as' 'av' 'bi' 'c1' 'cf' 'ct' 'cu' 'db' 'dp' 'du' 'dv' 'e3' 'e9' 'ee' 'eg' 'el' 'fm' 'gu' 'hc' 'he' 'i3' 'i9' 'ib' 'ik' 'im' 'ir' 'j7' 'jp' 'jv' 'ki' 'kl' 'l6' 'lj' 'lo' 'lw' 'md' 'mj' 'mk' 'ms' 'mw' 'na' 'nq' 'o2' 'od' 'ox' 'p3' 'pj' 'pp' 'q6' 'q7' 'q9' 'qb' 'qg' 'qr' 'qs' 'r7' 'r8' 'rd' 're' 'rf' 'rg' 'rp' 'rv' 'rw' 's6' 'sc' 'sq' 't6' 'tb' 'tc' 'te' 'tj' 'tn' 'tx' 'tz' 'uh' 'uq' 'uu' 'v4' 'vw' 'w3' 'w8' 'wa' 'wj' 'wk' 'wp' 'x3' 'xg' 'xy' 'y1' 'y6' 'yc' 'yi' 'yn' 'yo' 'yw' 'yz' 'z6' 'z8' 'zk' 'zz' - f | '80' 'ak' 'al' 'an' 'aq' 'as' 'at' 'bg' 'bn' 'bq' 'bx' 'd4' 'db' 'dg' 'dq' 'dv' 'ef' 'ej' 'en' 'eu' 'ex' 'f9' 'fu' 'g1' 'g2' 'g3' 'gj' 'gn' 'gs' 'gt' 'gx' 'h4' 'h8' 'hb' 'hn' 'hx' 'hy' 'i5' 'im' 'ji' 'jo' 'jy' 'k1' 'kb' 'kh' 'kp' 'kv' 'l4' 'lf' 'lt' 'ml' 'mv' 'na' 'ny' 'o2' 'oj' 'oq' 'or' 'os' 'pp' 'q3' 'q8' 'qc' 'qf' 'qp' 'qt' 'qv' 'rc' 'rg' 'rm' 's4' 'sa' 'sk' 'sp' 'su' 'sv' 'sy' 't5' 'te' 'tm' 'tn' 'to' 'tt' 'tw' 'tx' 'tz' 'ue' 'ug' 'ul' 'un' 'uq' 'us' 'v3' 'wd' 'wr' 'wu' 'wy' 'x3' 'x8' 'xk' 'yf' 'yj' 'yk' 'yp' 'z0' - f | '1b' '42' 'a7' 'ab' 'ak' 'ap' 'at' 'av' 'ay' 'b0' 'b9' 'bb' 'bp' 'bu' 'bz' 'cq' 'da' 'de' 'dn' 'e0' 'eb' 'ef' 'eg' 'ek' 'eq' 'er' 'eu' 'ey' 'fn' 'ft' 'gg' 'h4' 'hk' 'hl' 'i7' 'ig' 'ik' 'ip' 'ir' 'iu' 'iw' 'jr' 'jw' 'jx' 'kg' 'lc' 'lg' 'm0' 'na' 'np' 'om' 'on' 'oz' 'pg' 'pn' 'ps' 'pt' 'pz' 'q3' 'q6' 'qa' 'qb' 'ql' 'qq' 'qt' 'qv' 'qw' 'qy' 'r8' 'rf' 'ri' 'rk' 'rl' 'rw' 'sg' 'si' 'sp' 'sw' 'ta' 'th' 'ua' 'uj' 'uu' 'uv' 'uz' 'vj' 'vk' 'vm' 'wc' 'wf' 'wh' 'wn' 'wo' 'ww' 'xb' 'xk' 'xt' 'xw' 'y7' 'ye' 'yl' 'yt' 'yw' 'z4' 'z7' 'zc' 'zw' - f | '1h' '3s' 'ab' 'ae' 'ax' 'b1' 'bz' 'cy' 'dk' 'dq' 'ds' 'du' 'e8' 'ef' 'ej' 'ek' 'ex' 'f1' 'fe' 'ff' 'fn' 'fo' 'ft' 'fx' 'ge' 'go' 'gz' 'h6' 'hz' 'i2' 'iv' 'iy' 'j5' 'j6' 'ke' 'kf' 'lh' 'lr' 'mc' 'mj' 'na' 'ng' 'oh' 'om' 'oy' 'p2' 'pi' 'pk' 'py' 'q3' 'qb' 'qc' 'qg' 'qn' 'qo' 'qq' 'qu' 'qw' 'qx' 'qy' 'qz' 'r1' 'rk' 'rl' 'rq' 'rs' 'rt' 'ry' 'rz' 'sk' 'sl' 'so' 't9' 'td' 'te' 'tn' 'tw' 'tz' 'ud' 'uk' 'uo' 'uq' 'uw' 'ux' 'uy' 'v1' 'vg' 'vq' 'w4' 'w9' 'wa' 'wg' 'wj' 'wm' 'wo' 'wr' 'ww' 'wy' 'xf' 'xg' 'y9' 'yh' 'yi' 'yk' 'ym' 'yq' 'yv' 'zm' - t | -(514 rows) - -drop index wowidx; -create index wowidx on test_tsvector using gin (a); -set enable_seqscan=off; -SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh'; - count -------- - 158 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh'; - count -------- - 17 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt'; - count -------- - 6 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt'; - count -------- - 98 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)'; - count -------- - 23 -(1 row) - -SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)'; - count -------- - 39 -(1 row) - diff --git a/contrib/tsearch2/sql/tsearch2.sql b/contrib/tsearch2/sql/tsearch2.sql index 665882ff88..53e3073af4 100644 --- a/contrib/tsearch2/sql/tsearch2.sql +++ b/contrib/tsearch2/sql/tsearch2.sql @@ -230,14 +230,14 @@ select rank(' a:1 s:2 d g'::tsvector, 'a & s'); insert into test_tsvector (t) values ('foo bar foo the over foo qq bar'); drop trigger tsvectorupdate on test_tsvector; -select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word collate "C"; insert into test_tsvector values ('1', 'a:1a,2,3b b:5a,6a,7c,8'); insert into test_tsvector values ('1', 'a:1a,2,3c b:5a,6b,7c,8b'); -select * from stat('select a from test_tsvector','a') order by ndoc desc, nentry desc, word; -select * from stat('select a from test_tsvector','b') order by ndoc desc, nentry desc, word; -select * from stat('select a from test_tsvector','c') order by ndoc desc, nentry desc, word; -select * from stat('select a from test_tsvector','d') order by ndoc desc, nentry desc, word; -select * from stat('select a from test_tsvector','ad') order by ndoc desc, nentry desc, word; +select * from stat('select a from test_tsvector','a') order by ndoc desc, nentry desc, word collate "C"; +select * from stat('select a from test_tsvector','b') order by ndoc desc, nentry desc, word collate "C"; +select * from stat('select a from test_tsvector','c') order by ndoc desc, nentry desc, word collate "C"; +select * from stat('select a from test_tsvector','d') order by ndoc desc, nentry desc, word collate "C"; +select * from stat('select a from test_tsvector','ad') order by ndoc desc, nentry desc, word collate "C"; select to_tsquery('english', 'skies & books'); diff --git a/doc/bug.template b/doc/bug.template index 3fcae9d970..275634390c 100644 --- a/doc/bug.template +++ b/doc/bug.template @@ -23,7 +23,7 @@ System Configuration: Operating System (example: Ubuntu Linux 16.04) : - PostgreSQL version (example: PostgresPro 9.5.3.1): PostgrePro 9.5.3.1 + PostgreSQL version (example: PostgresPro 9.5.4.1): PostgrePro 9.5.4.1 Compiler used (example: gcc 3.3.5) : diff --git a/doc/src/sgml/adminpack.sgml b/doc/src/sgml/adminpack.sgml index 9b72f34ead..98736cb7c4 100644 --- a/doc/src/sgml/adminpack.sgml +++ b/doc/src/sgml/adminpack.sgml @@ -12,29 +12,151 @@ pgAdmin and other administration and management tools can use to provide additional functionality, such as remote management of server log files. + Use of all these functions is restricted to superusers. - - Functions Implemented + + The functions shown in provide + write access to files on the machine hosting the server. (See also the + functions in , which + provide read-only access.) + Only files within the database cluster directory can be accessed, but + either a relative or absolute path is allowable. + + + + <filename>adminpack</> Functions + + + Name Return Type Description + + - - The functions implemented by adminpack can only be run by a - superuser. Here's a list of these functions: + + + pg_catalog.pg_file_write(filename text, data text, append boolean) + bigint + + Write, or append to, a text file + + + + pg_catalog.pg_file_rename(oldname text, newname text , archivename text) + boolean + + Rename a file + + + + pg_catalog.pg_file_unlink(filename text) + boolean + + Remove a file + + + + pg_catalog.pg_logdir_ls() + setof record + + List the log files in the log_directory directory + + + + +
+ + + pg_file_write + + + pg_file_write writes the specified data into + the file named by filename. If append is + false, the file must not already exist. If append is true, + the file can already exist, and will be appended to if so. + Returns the number of bytes written. + + + + pg_file_rename + + + pg_file_rename renames a file. If archivename + is omitted or NULL, it simply renames oldname + to newname (which must not already exist). + If archivename is provided, it first + renames newname to archivename (which must + not already exist), and then renames oldname + to newname. In event of failure of the second rename step, + it will try to rename archivename back + to newname before reporting the error. + Returns true on success, false if the source file(s) are not present or + not writable; other cases throw errors. + - -int8 pg_catalog.pg_file_write(fname text, data text, append bool) -bool pg_catalog.pg_file_rename(oldname text, newname text, archivename text) -bool pg_catalog.pg_file_rename(oldname text, newname text) -bool pg_catalog.pg_file_unlink(fname text) -setof record pg_catalog.pg_logdir_ls() + + pg_file_unlink + + + pg_file_unlink removes the specified file. + Returns true on success, false if the specified file is not present + or the unlink() call fails; other cases throw errors. + + + + pg_logdir_ls + + + pg_logdir_ls returns the start timestamps and path + names of all the log files in the + directory. The parameter must have its + default setting (postgresql-%Y-%m-%d_%H%M%S.log) to use this + function. + + + + The functions shown + in are deprecated + and should not be used in new applications; instead use those shown + in + and . These functions are + provided in adminpack only for compatibility with old + versions of pgAdmin. + -/* Renaming of existing backend functions for pgAdmin compatibility */ -int8 pg_catalog.pg_file_read(fname text, data text, append bool) -bigint pg_catalog.pg_file_length(text) -int4 pg_catalog.pg_logfile_rotate() - - + + Deprecated <filename>adminpack</> Functions + + + Name Return Type Description + + - + + + pg_catalog.pg_file_read(filename text, offset bigint, nbytes bigint) + text + + Alternate name for pg_read_file() + + + + pg_catalog.pg_file_length(filename text) + bigint + + Same as size column returned + by pg_stat_file() + + + + pg_catalog.pg_logfile_rotate() + integer + + Alternate name for pg_rotate_logfile(), but note that it + returns integer 0 or 1 rather than boolean + + + + +
diff --git a/doc/src/sgml/array.sgml b/doc/src/sgml/array.sgml index d7669628d1..a9dd67c9fb 100644 --- a/doc/src/sgml/array.sgml +++ b/doc/src/sgml/array.sgml @@ -728,7 +728,7 @@ SELECT f1[1][-2][3] AS e1, f1[1][-1][5] AS e2 variant), the element is taken to be NULL. The presence of any quotes or backslashes disables this and allows the literal string value NULL to be entered. Also, for backward compatibility with - pre-8.2 versions of &productname;, the PostgreSQL, the configuration parameter can be turned off to suppress recognition of NULL as a NULL. diff --git a/doc/src/sgml/btree-gist.sgml b/doc/src/sgml/btree-gist.sgml index f4afc09546..e8a5622704 100644 --- a/doc/src/sgml/btree-gist.sgml +++ b/doc/src/sgml/btree-gist.sgml @@ -98,7 +98,7 @@ INSERT 0 1 Authors - Teodor Sigaev (teodor@stack.net) , + Teodor Sigaev (teodor@stack.net), Oleg Bartunov (oleg@sai.msu.su), and Janko Richter (jankorichter@yahoo.de). See diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index a9deb16994..e34883d59f 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -5905,9 +5905,9 @@ The number of distinct nonnull data values in the column. A value greater than zero is the actual number of distinct values. A value less than zero is the negative of a multiplier for the number - of rows in the table; for example, a column in which values appear about - twice on the average could be represented by - stadistinct = -0.5. + of rows in the table; for example, a column in which about 80% of the + values are nonnull and each nonnull value appears about twice on + average could be represented by stadistinct = -0.4. A zero value means the number of distinct values is unknown. @@ -7845,7 +7845,7 @@ The view pg_group exists for backwards compatibility: it emulates a catalog that existed in - &productname; before version 8.1. + PostgreSQL before version 8.1. It shows the names and members of all roles that are marked as not rolcanlogin, which is an approximation to the set of roles that are being used as groups. @@ -9349,7 +9349,7 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx The view pg_shadow exists for backwards compatibility: it emulates a catalog that existed in - &productname; before version 8.1. + PostgreSQL before version 8.1. It shows properties of all roles that are marked as rolcanlogin in pg_authid. @@ -9770,6 +9770,13 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx + + While most timezone abbreviations represent fixed offsets from UTC, + there are some that have historically varied in value + (see for more information). + In such cases this view presents their current meaning. + + diff --git a/doc/src/sgml/citext.sgml b/doc/src/sgml/citext.sgml index b2c93f26a6..cf5731b2e2 100644 --- a/doc/src/sgml/citext.sgml +++ b/doc/src/sgml/citext.sgml @@ -196,7 +196,7 @@ SELECT * FROM users WHERE nick = 'Larry'; - As of &productname; 9.1, you can attach a + As of PostgreSQL 9.1, you can attach a COLLATE specification to citext columns or data values. Currently, citext operators will honor a non-default COLLATE specification while comparing case-folded strings, diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 5239b7e49a..f22bb62e9e 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -2363,11 +2363,11 @@ include_dir 'conf.d' Only superusers can change this setting. - In &productname; releases prior to 9.3, + In PostgreSQL releases prior to 9.3, commit_delay behaved differently and was much less effective: it affected only commits, rather than all WAL flushes, and waited for the entire configured delay even if the WAL flush - was completed sooner. Beginning in &productname; 9.3, + was completed sooner. Beginning in PostgreSQL 9.3, the first process that becomes ready to flush waits for the configured interval, while subsequent processes wait only until the leader completes the flush operation. @@ -3926,7 +3926,7 @@ local0.* /var/log/postgresql use a log rotation utility to avoid eventually filling the entire disk. In releases prior to 8.4, if no % escapes were - present, &productname; would append + present, PostgreSQL would append the epoch of the new log file's creation time, but this is no longer the case. @@ -6088,11 +6088,11 @@ SET XML OPTION { DOCUMENT | CONTENT }; The value sql_standard will produce output matching SQL standard interval literals. The value postgres (which is the default) will produce - output matching &productname; releases prior to 8.4 + output matching PostgreSQL releases prior to 8.4 when the parameter was set to ISO. The value postgres_verbose will produce output - matching &productname; releases prior to 8.4 + matching PostgreSQL releases prior to 8.4 when the DateStyle parameter was set to non-ISO output. The value iso_8601 will produce output matching the time @@ -6687,7 +6687,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' This controls whether the array input parser recognizes unquoted NULL as specifying a null array element. By default, this is on, allowing array values containing - null values to be entered. However, &productname; versions + null values to be entered. However, PostgreSQL versions before 8.2 did not support null values in arrays, and therefore would treat NULL as specifying a normal array element with the string value NULL. For backward compatibility with @@ -6753,7 +6753,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' nor WITHOUT OIDS is specified. It also determines whether OIDs will be included in tables created by SELECT INTO. The parameter is off - by default; in &productname; 8.0 and earlier, it + by default; in PostgreSQL 8.0 and earlier, it was on by default. @@ -6800,7 +6800,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' - In &productname; releases prior to 9.0, large objects + In PostgreSQL releases prior to 9.0, large objects did not have access privileges and were, therefore, always readable and writable by all users. Setting this variable to on disables the new privilege checks, for compatibility with prior @@ -6810,7 +6810,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' Setting this variable does not disable all security checks related to large objects — only those for which the default behavior has - changed in &productname; 9.0. + changed in PostgreSQL 9.0. For example, lo_import() and lo_export() need superuser privileges regardless of this setting. @@ -6827,7 +6827,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' When on, the parser will emit a warning for any construct that might - have changed meanings since &productname; 9.4 as a result + have changed meanings since PostgreSQL 9.4 as a result of changes in operator precedence. This is useful for auditing applications to see if precedence changes have broken anything; but it is not meant to be kept turned on in production, since it will warn @@ -6876,7 +6876,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' ONLY prefix is assumed). The SQL standard requires child tables to be included, so the off setting is not spec-compliant, but it is provided for compatibility with - &productname; releases prior to 7.1. + PostgreSQL releases prior to 7.1. See for more information. @@ -6901,7 +6901,7 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir' This controls whether ordinary string literals ('...') treat backslashes literally, as specified in the SQL standard. - Beginning in &productname; 9.1, the default is + Beginning in PostgreSQL 9.1, the default is on (prior releases defaulted to off). Applications can check this parameter to determine how string literals will be processed. diff --git a/doc/src/sgml/contrib.sgml b/doc/src/sgml/contrib.sgml index 537f4f4c28..fab8ce1f39 100644 --- a/doc/src/sgml/contrib.sgml +++ b/doc/src/sgml/contrib.sgml @@ -54,9 +54,9 @@ Many modules supply new user-defined functions, operators, or types. To make use of one of these modules, after you have installed the code you need to register the new SQL objects in the database system. - In &productname; 9.1 and later, this is done by executing - a command. In a fresh database, - you can simply do + In &productname;, and PostgreSQL 9.1 and later, + this is done by executing a command. + In a fresh database, you can simply do CREATE EXTENSION module_name; @@ -80,7 +80,7 @@ CREATE EXTENSION module_name; If your database was brought forward by dump and reload from a pre-9.1 - version of &productname;, and you had been using the pre-9.1 + version of PostgreSQL, and you had been using the pre-9.1 version of the module in it, you should instead do diff --git a/doc/src/sgml/cube.sgml b/doc/src/sgml/cube.sgml index f5da703620..0a226ca542 100644 --- a/doc/src/sgml/cube.sgml +++ b/doc/src/sgml/cube.sgml @@ -136,7 +136,7 @@ - (Before &productname; 8.2, the containment operators @> and <@ were + (Before PostgreSQL 8.2, the containment operators @> and <@ were respectively called @ and ~. These names are still available, but are deprecated and will eventually be retired. Notice that the old names are reversed from the convention formerly followed by the core geometric diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 153403c6aa..76b49d45c7 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1272,7 +1272,7 @@ SELECT b, char_length(b) FROM test2; of these are always accepted on input. The output format depends on the configuration parameter ; the default is hex. (Note that the hex format was introduced in - &productname; 9.0; earlier versions and some + PostgreSQL 9.0; earlier versions and some tools don't understand it.) @@ -2478,7 +2478,7 @@ January 8 04:05:06 1999 PST In all cases, timezone names and abbreviations are recognized - case-insensitively. (This is a change from &productname; + case-insensitively. (This is a change from PostgreSQL versions prior to 8.2, which were case-sensitive in some contexts but not others.) @@ -2756,13 +2756,13 @@ P years-months-days < The output of the postgres style matches the output of - &productname; releases prior to 8.4 when the + PostgreSQL releases prior to 8.4 when the parameter was set to ISO. The output of the postgres_verbose style matches the output of - &productname; releases prior to 8.4 when the + PostgreSQL releases prior to 8.4 when the DateStyle parameter was set to non-ISO output. diff --git a/doc/src/sgml/datetime.sgml b/doc/src/sgml/datetime.sgml index 3df62e89ef..a30a3b7f91 100644 --- a/doc/src/sgml/datetime.sgml +++ b/doc/src/sgml/datetime.sgml @@ -384,19 +384,38 @@ A zone_abbreviation is just the abbreviation - being defined. The offset is the equivalent - offset in seconds from UTC, positive being east from Greenwich and - negative being west. For example, -18000 would be five hours west - of Greenwich, or North American east coast standard time. D - indicates that the zone name represents local daylight-savings time rather - than standard time. Alternatively, a time_zone_name can - be given, in which case that time zone definition is consulted, and the - abbreviation's meaning in that zone is used. This alternative is - recommended only for abbreviations whose meaning has historically varied, - as looking up the meaning is noticeably more expensive than just using - a fixed integer value. + being defined. An offset is an integer giving + the equivalent offset in seconds from UTC, positive being east from + Greenwich and negative being west. For example, -18000 would be five + hours west of Greenwich, or North American east coast standard time. + D indicates that the zone name represents local + daylight-savings time rather than standard time. + + Alternatively, a time_zone_name can be given, referencing + a zone name defined in the IANA timezone database. The zone's definition + is consulted to see whether the abbreviation is or has been in use in + that zone, and if so, the appropriate meaning is used — that is, + the meaning that was currently in use at the timestamp whose value is + being determined, or the meaning in use immediately before that if it + wasn't current at that time, or the oldest meaning if it was used only + after that time. This behavior is essential for dealing with + abbreviations whose meaning has historically varied. It is also allowed + to define an abbreviation in terms of a zone name in which that + abbreviation does not appear; then using the abbreviation is just + equivalent to writing out the zone name. + + + + + Using a simple integer offset is preferred + when defining an abbreviation whose offset from UTC has never changed, + as such abbreviations are much cheaper to process than those that + require consulting a time zone definition. + + + The @INCLUDE syntax allows inclusion of another file in the .../share/timezonesets/ directory. Inclusion can be nested, diff --git a/doc/src/sgml/dblink.sgml b/doc/src/sgml/dblink.sgml index 60a4b2fca0..5fdcbc0478 100644 --- a/doc/src/sgml/dblink.sgml +++ b/doc/src/sgml/dblink.sgml @@ -1828,7 +1828,7 @@ dblink_build_sql_insert(text relname, Notes - As of &productname; 9.0, the attribute numbers in + As of PostgreSQL 9.0, the attribute numbers in primary_key_attnums are interpreted as logical column numbers, corresponding to the column's position in SELECT * FROM relname. Previous versions interpreted the @@ -1946,7 +1946,7 @@ dblink_build_sql_delete(text relname, Notes - As of &productname; 9.0, the attribute numbers in + As of PostgreSQL 9.0, the attribute numbers in primary_key_attnums are interpreted as logical column numbers, corresponding to the column's position in SELECT * FROM relname. Previous versions interpreted the @@ -2083,7 +2083,7 @@ dblink_build_sql_update(text relname, Notes - As of &productname; 9.0, the attribute numbers in + As of PostgreSQL 9.0, the attribute numbers in primary_key_attnums are interpreted as logical column numbers, corresponding to the column's position in SELECT * FROM relname. Previous versions interpreted the diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index 9127c0bd26..b28d2776d0 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1088,7 +1088,7 @@ CREATE TABLE circles ( Of course, the tables in question must be created WITH - OIDS. As of &productname; 8.1, + OIDS. As of PostgreSQL 8.1, WITHOUT OIDS is the default. @@ -1629,7 +1629,7 @@ CREATE POLICY account_managers ON accounts TO managers CREATE POLICY user_policy ON users - USING (user = current_user); + USING (user_name = current_user); @@ -1642,7 +1642,7 @@ CREATE POLICY user_policy ON users CREATE POLICY user_policy ON users USING (true) - WITH CHECK (user = current_user); + WITH CHECK (user_name = current_user); @@ -1662,7 +1662,7 @@ CREATE POLICY user_policy ON users -- Simple passwd-file based example CREATE TABLE passwd ( - username text UNIQUE NOT NULL, + user_name text UNIQUE NOT NULL, pwhash text, uid int PRIMARY KEY, gid int NOT NULL, @@ -1696,9 +1696,9 @@ CREATE POLICY all_view ON passwd FOR SELECT USING (true); -- Normal users can update their own records, but -- limit which shells a normal user is allowed to set CREATE POLICY user_mod ON passwd FOR UPDATE - USING (current_user = username) + USING (current_user = user_name) WITH CHECK ( - current_user = username AND + current_user = user_name AND shell IN ('/bin/bash','/bin/sh','/bin/dash','/bin/zsh','/bin/tcsh') ); @@ -1706,7 +1706,7 @@ CREATE POLICY user_mod ON passwd FOR UPDATE GRANT SELECT, INSERT, UPDATE, DELETE ON passwd TO admin; -- Users only get select access on public columns GRANT SELECT - (username, uid, gid, real_name, home_phone, extra_info, home_dir, shell) + (user_name, uid, gid, real_name, home_phone, extra_info, home_dir, shell) ON passwd TO public; -- Allow users to update certain columns GRANT UPDATE @@ -1725,11 +1725,11 @@ GRANT UPDATE postgres=> set role admin; SET postgres=> table passwd; - username | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell -----------+--------+-----+-----+-----------+--------------+------------+-------------+----------- - admin | xxx | 0 | 0 | Admin | 111-222-3333 | | /root | /bin/dash - bob | xxx | 1 | 1 | Bob | 123-456-7890 | | /home/bob | /bin/zsh - alice | xxx | 2 | 1 | Alice | 098-765-4321 | | /home/alice | /bin/zsh + user_name | pwhash | uid | gid | real_name | home_phone | extra_info | home_dir | shell +-----------+--------+-----+-----+-----------+--------------+------------+-------------+----------- + admin | xxx | 0 | 0 | Admin | 111-222-3333 | | /root | /bin/dash + bob | xxx | 1 | 1 | Bob | 123-456-7890 | | /home/bob | /bin/zsh + alice | xxx | 2 | 1 | Alice | 098-765-4321 | | /home/alice | /bin/zsh (3 rows) -- Test what Alice is able to do @@ -1737,26 +1737,26 @@ postgres=> set role alice; SET postgres=> table passwd; ERROR: permission denied for relation passwd -postgres=> select username,real_name,home_phone,extra_info,home_dir,shell from passwd; - username | real_name | home_phone | extra_info | home_dir | shell -----------+-----------+--------------+------------+-------------+----------- - admin | Admin | 111-222-3333 | | /root | /bin/dash - bob | Bob | 123-456-7890 | | /home/bob | /bin/zsh - alice | Alice | 098-765-4321 | | /home/alice | /bin/zsh +postgres=> select user_name,real_name,home_phone,extra_info,home_dir,shell from passwd; + user_name | real_name | home_phone | extra_info | home_dir | shell +-----------+-----------+--------------+------------+-------------+----------- + admin | Admin | 111-222-3333 | | /root | /bin/dash + bob | Bob | 123-456-7890 | | /home/bob | /bin/zsh + alice | Alice | 098-765-4321 | | /home/alice | /bin/zsh (3 rows) -postgres=> update passwd set username = 'joe'; +postgres=> update passwd set user_name = 'joe'; ERROR: permission denied for relation passwd -- Alice is allowed to change her own real_name, but no others postgres=> update passwd set real_name = 'Alice Doe'; UPDATE 1 -postgres=> update passwd set real_name = 'John Doe' where username = 'admin'; +postgres=> update passwd set real_name = 'John Doe' where user_name = 'admin'; UPDATE 0 postgres=> update passwd set shell = '/bin/xx'; ERROR: new row violates WITH CHECK OPTION for "passwd" postgres=> delete from passwd; ERROR: permission denied for relation passwd -postgres=> insert into passwd (username) values ('xxx'); +postgres=> insert into passwd (user_name) values ('xxx'); ERROR: permission denied for relation passwd -- Alice can change her own password; RLS silently prevents updating other rows postgres=> update passwd set pwhash = 'abc'; @@ -2055,7 +2055,7 @@ DROP SCHEMA myschema CASCADE; (since this is one of the ways to restrict the activities of your users to well-defined namespaces). The syntax for that is: -CREATE SCHEMA schemaname AUTHORIZATION username; +CREATE SCHEMA schema_name AUTHORIZATION user_name; You can even omit the schema name, in which case the schema name will be the same as the user name. See username.tablename. + user_name.table_name. This is how &productname; will effectively behave if you create a per-user schema for every user. diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml index 172425b285..824befd32e 100644 --- a/doc/src/sgml/ecpg.sgml +++ b/doc/src/sgml/ecpg.sgml @@ -3597,7 +3597,7 @@ EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc; - Before &productname; 9.0, the SQL keyword was optional, + Before PostgreSQL 9.0, the SQL keyword was optional, so using DESCRIPTOR and SQL DESCRIPTOR produced named SQL Descriptor Areas. Now it is mandatory, omitting the SQL keyword produces SQLDA Descriptor Areas, diff --git a/doc/src/sgml/errcodes.sgml b/doc/src/sgml/errcodes.sgml index 1e13cf96e5..92f1c46d42 100644 --- a/doc/src/sgml/errcodes.sgml +++ b/doc/src/sgml/errcodes.sgml @@ -56,7 +56,7 @@ unique_violation error. Such names are supplied in separate fields of the error report message so that applications need not try to extract them from the possibly-localized human-readable text of the message. - As of &productname; 9.3, complete coverage for this feature + As of PostgreSQL 9.3, complete coverage for this feature exists only for errors in SQLSTATE class 23 (integrity constraint violation), but this is likely to be expanded in future. diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml index 7265a34b6a..67fa0ff53c 100644 --- a/doc/src/sgml/extend.sgml +++ b/doc/src/sgml/extend.sgml @@ -772,7 +772,7 @@ SELECT pg_catalog.pg_extension_config_dump('my_config', 'WHERE NOT standard_entr The update mechanism can be used to solve an important special case: converting a loose collection of objects into an extension. Before the extension mechanism was added to - &productname; (in 9.1), many people wrote + PostgreSQL (in 9.1), many people wrote extension modules that simply created assorted unpackaged objects. Given an existing database containing such objects, how can we convert the objects into a properly packaged extension? Dropping them and then diff --git a/doc/src/sgml/external-projects.sgml b/doc/src/sgml/external-projects.sgml index 6922cb6841..e58f38cde1 100644 --- a/doc/src/sgml/external-projects.sgml +++ b/doc/src/sgml/external-projects.sgml @@ -178,7 +178,7 @@ PL/PHP PHP - http://www.commandprompt.com/community/plphp/ + https://public.commandprompt.com/projects/plphp diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index f463878b2b..9866a345b3 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -289,6 +289,32 @@ a nonempty range is always implied. + + + IS DISTINCT FROM + + + IS NOT DISTINCT FROM + + Ordinary comparison operators yield null (signifying unknown), + not true or false, when either input is null. For example, + 7 = NULL yields null, as does 7 <> NULL. When + this behavior is not suitable, use the + IS NOT DISTINCT FROM constructs: + +a IS DISTINCT FROM b +a IS NOT DISTINCT FROM b + + For non-null inputs, IS DISTINCT FROM is + the same as the <> operator. However, if both + inputs are null it returns false, and if only one input is + null it returns true. Similarly, IS NOT DISTINCT + FROM is identical to = for non-null + inputs, but it returns true when both inputs are null, and false when only + one input is null. Thus, these constructs effectively act as though null + were a normal data value, rather than unknown. + + IS NULL @@ -320,8 +346,7 @@ expression = NULL because NULL is not equal to NULL. (The null value represents an unknown value, - and it is not known whether two unknown values are equal.) This - behavior conforms to the SQL standard. + and it is not known whether two unknown values are equal.) @@ -338,7 +363,6 @@ - If the expression is row-valued, then IS NULL is true when the row expression itself is null @@ -346,39 +370,13 @@ IS NOT NULL is true when the row expression itself is non-null and all the row's fields are non-null. Because of this behavior, IS NULL and IS NOT NULL do not always return - inverse results for row-valued expressions, i.e., a row-valued - expression that contains both NULL and non-null values will return false - for both tests. - This definition conforms to the SQL standard, and is a change from the - inconsistent behavior exhibited by PostgreSQL - versions prior to 8.2. - - - - - - IS DISTINCT FROM - - - IS NOT DISTINCT FROM - - Ordinary comparison operators yield null (signifying unknown), - not true or false, when either input is null. For example, - 7 = NULL yields null, as does 7 <> NULL. When - this behavior is not suitable, use the - IS NOT DISTINCT FROM constructs: - -expression IS DISTINCT FROM expression -expression IS NOT DISTINCT FROM expression - - For non-null inputs, IS DISTINCT FROM is - the same as the <> operator. However, if both - inputs are null it returns false, and if only one input is - null it returns true. Similarly, IS NOT DISTINCT - FROM is identical to = for non-null - inputs, but it returns true when both inputs are null, and false when only - one input is null. Thus, these constructs effectively act as though null - were a normal data value, rather than unknown. + inverse results for row-valued expressions; in particular, a row-valued + expression that contains both null and non-null fields will return false + for both tests. In some cases, it may be preferable to + write row IS DISTINCT FROM NULL + or row IS NOT DISTINCT FROM NULL, + which will simply check whether the overall row value is null without any + additional tests on the row fields. @@ -1125,7 +1123,7 @@ - Before &productname; 8.3, these functions would + Before PostgreSQL 8.3, these functions would silently accept values of several non-string data types as well, due to the presence of implicit coercions from those data types to text. Those coercions have been removed because they frequently @@ -5352,7 +5350,7 @@ SELECT regexp_matches('abc01234xyz', '(?:(.*?)(\d+)(.*)){1,1}'); Two significant incompatibilities exist between AREs and the ERE syntax - recognized by pre-7.4 releases of &productname;: + recognized by pre-7.4 releases of PostgreSQL: @@ -7294,7 +7292,7 @@ SELECT EXTRACT(ISOYEAR FROM DATE '2006-01-02'); field for more information. - This field is not available in &productname; releases prior to 8.3. + This field is not available in PostgreSQL releases prior to 8.3. @@ -8039,12 +8037,12 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple # Point or box of intersection - '((1,-1),(-1,1))' # '((1,1),(-1,-1))' + box '((1,-1),(-1,1))' # box '((1,1),(-2,-2))' # Number of points in path or polygon - # '((1,0),(0,1),(-1,0))' + # path '((1,0),(0,1),(-1,0))' @-@ @@ -8177,7 +8175,7 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple - Before &productname; 8.2, the containment + Before PostgreSQL 8.2, the containment operators @> and <@ were respectively called ~ and @. These names are still available, but are deprecated and will eventually be removed. @@ -11176,7 +11174,7 @@ nextval('foo') searches search path for fo - Before &productname; 8.1, the arguments of the + Before PostgreSQL 8.1, the arguments of the sequence functions were of type text, not regclass, and the above-described conversion from a text string to an OID value would happen at run time during each call. For backward compatibility, this @@ -11199,7 +11197,7 @@ nextval('foo') searches search path for fo nextval('foo'::text) foo is looked up at runtime Note that late binding was the only behavior supported in - &productname; releases before 8.1, so you + PostgreSQL releases before 8.1, so you might need to do this to preserve the semantics of old applications. @@ -11703,7 +11701,7 @@ SELECT NULLIF(value, '(none)') ... If the contents of two arrays are equal but the dimensionality is different, the first difference in the dimensionality information determines the sort order. (This is a change from versions of - &productname; prior to 8.2: older versions would claim + PostgreSQL prior to 8.2: older versions would claim that two arrays with the same contents were equal, even if the number of dimensions or subscript ranges were different.) @@ -12038,7 +12036,7 @@ NULL baz(3 rows) There are two differences in the behavior of string_to_array - from pre-9.1 versions of &productname;. + from pre-9.1 versions of PostgreSQL. First, it will return an empty (zero-element) array rather than NULL when the input string is of zero length. Second, if the delimiter string is NULL, the function splits the input into individual characters, rather @@ -15349,6 +15347,21 @@ SET search_path TO schema , schema, .. boolean does current user have privilege for tablespace + + has_type_privilege(user, + type, + privilege) + + boolean + does user have privilege for type + + + has_type_privilege(type, + privilege) + + boolean + does current user have privilege for type + pg_has_role(user, role, @@ -15407,6 +15420,9 @@ SET search_path TO schema , schema, .. has_tablespace_privilege + + has_type_privilege + pg_has_role @@ -15561,6 +15577,18 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); CREATE. + + has_type_privilege checks whether a user + can access a type in a particular way. + Its argument possibilities + are analogous to has_table_privilege. + When specifying a type by a text string rather than by OID, + the allowed input is the same as for the regtype data type + (see ). + The desired access privilege type must evaluate to + USAGE. + + pg_has_role checks whether a user can access a role in a particular way. @@ -17575,7 +17603,7 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); pg_replication_origin_xact_reset - pg_replication_origin_xact_reset() + pg_replication_origin_xact_reset(origin_lsn pg_lsn, origin_timestamp timestamptz) void @@ -17583,6 +17611,12 @@ postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup()); Cancel the effects of pg_replication_origin_xact_setup(). + Note that two arguments were introduced by mistake + during the PostgreSQL 9.5 development cycle while + pg_replication_origin_xact_reset() actually + doesn't use them at all. Therefore, any dummy values except + NULL can be safely specified as the arguments. + This mistake will be fixed in a future release. diff --git a/doc/src/sgml/gin.sgml b/doc/src/sgml/gin.sgml index 4ee7283b44..4ac071b648 100644 --- a/doc/src/sgml/gin.sgml +++ b/doc/src/sgml/gin.sgml @@ -705,7 +705,7 @@ - As of &productname; 9.1, null key values can be + As of PostgreSQL 9.1, null key values can be included in the index. Also, placeholder nulls are included in the index for indexed items that are null or contain no keys according to extractValue. This allows searches that should find empty @@ -725,7 +725,7 @@ Updating a GIN index tends to be slow because of the intrinsic nature of inverted indexes: inserting or updating one heap row can cause many inserts into the index (one for each key extracted - from the indexed item). As of &productname; 8.4, + from the indexed item). As of PostgreSQL 8.4, GIN is capable of postponing much of this work by inserting new tuples into a temporary, unsorted list of pending entries. When the table is vacuumed, or if the pending list becomes larger than @@ -792,7 +792,7 @@ - As of &productname; 8.4, this advice is less + As of PostgreSQL 8.4, this advice is less necessary since delayed indexing is used (see for details). But for very large updates it may still be best to drop and recreate the index. diff --git a/doc/src/sgml/gist.sgml b/doc/src/sgml/gist.sgml index 6820f2ae5a..0c8d2ca96a 100644 --- a/doc/src/sgml/gist.sgml +++ b/doc/src/sgml/gist.sgml @@ -912,7 +912,7 @@ my_fetch(PG_FUNCTION_ARGS) Building large GiST indexes by simply inserting all the tuples tends to be slow, because if the index tuples are scattered across the index and the index is large enough to not fit in cache, the insertions need to perform - a lot of random I/O. Beginning in version 9.2, &productname; supports a more + a lot of random I/O. Beginning in version 9.2, PostgreSQL supports a more efficient method to build GiST indexes based on buffering, which can dramatically reduce the number of random I/Os needed for non-ordered data sets. For well-ordered data sets the benefit is smaller or non-existent, diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 566a9e447f..4c37706749 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -1523,7 +1523,7 @@ if (!triggered) - Starting with &productname; version 9.0, you can use + Starting with PostgreSQL version 9.0, you can use streaming replication (see ) to achieve the same benefits with less effort. diff --git a/doc/src/sgml/hstore.sgml b/doc/src/sgml/hstore.sgml index 88e870f473..5aee21291a 100644 --- a/doc/src/sgml/hstore.sgml +++ b/doc/src/sgml/hstore.sgml @@ -588,7 +588,7 @@ SELECT key, count(*) FROM Compatibility - As of &productname; 9.0, hstore uses a different internal + As of PostgreSQL 9.0, hstore uses a different internal representation than previous versions. This presents no obstacle for dump/restore upgrades since the text representation (used in the dump) is unchanged. diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index 1e87ca0685..44fdcd6e23 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -262,7 +262,7 @@ amvacuumcleanup (IndexVacuumInfo *info, - As of &productname; 8.4, + As of PostgreSQL 8.4, amvacuumcleanup will also be called at completion of an ANALYZE operation. In this case stats is always NULL and any return value will be ignored. This case can be distinguished diff --git a/doc/src/sgml/information_schema.sgml b/doc/src/sgml/information_schema.sgml index 4de8cd9cca..ae42fdea67 100644 --- a/doc/src/sgml/information_schema.sgml +++ b/doc/src/sgml/information_schema.sgml @@ -2897,18 +2897,6 @@ ORDER BY c.ordinal_position; Name of the foreign table - - foreign_server_catalog - sql_identifier - Name of the database that the foreign server is defined in (always the current database) - - - - foreign_server_name - sql_identifier - Name of the foreign server - - option_name sql_identifier @@ -5881,7 +5869,7 @@ ORDER BY c.ordinal_position; The view udt_privileges identifies USAGE privileges granted on user-defined types to a currently enabled role or by a currently enabled role. There is one row for - each combination of column, grantor, and grantee. This view shows only + each combination of type, grantor, and grantee. This view shows only composite types (see under for why); see for domain privileges. diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml index 2b3f1713f4..88a93d0953 100644 --- a/doc/src/sgml/installation.sgml +++ b/doc/src/sgml/installation.sgml @@ -930,14 +930,14 @@ su - postgres Disable support for 64-bit integer storage for timestamps and intervals, and store datetime values as floating-point numbers instead. Floating-point datetime storage was the - default in &productname; releases + default in PostgreSQL releases prior to 8.4, but it is now deprecated, because it does not support microsecond precision for the full range of timestamp values. However, integer-based datetime storage requires a 64-bit integer type. Therefore, this option can be used when no such type is available, or for compatibility with applications written for prior - versions of &productname;. See + versions of PostgreSQL. See ]]> for more information. @@ -1474,7 +1474,7 @@ su - postgres will take a few minutes depending on your hardware. The last line displayed should be: -All of &productname; is successfully made. Ready to install. +All of &productname; successfully made. Ready to install. @@ -1487,7 +1487,7 @@ All of &productname; is successfully made. Ready to install. The last line displayed should be: -&productname;, contrib and HTML documentation successfully made. Ready to install. +&productname;, contrib, and documentation successfully made. Ready to install. @@ -2137,7 +2137,7 @@ kill `cat /usr/local/pgsql/data/postmaster.pid` - When implementing &productname; version 8.1 on AIX 5.3, we + When implementing PostgreSQL version 8.1 on AIX 5.3, we periodically ran into problems where the statistics collector would mysteriously not come up successfully. This appears to be the result of unexpected behavior in the IPv6 @@ -2455,7 +2455,7 @@ make MAX_CONNECTIONS=5 check - &productname; 7.3+ should work on Series 700/800 PA-RISC machines + PostgreSQL 7.3+ and &productname; should work on Series 700/800 PA-RISC machines running HP-UX 10.X or 11.X, given appropriate system patch levels and build tools. At least one developer routinely tests on HP-UX 10.20, and we have reports of successful installations on HP-UX diff --git a/doc/src/sgml/intarray.sgml b/doc/src/sgml/intarray.sgml index 3440124a0c..69b9fb525f 100644 --- a/doc/src/sgml/intarray.sgml +++ b/doc/src/sgml/intarray.sgml @@ -220,7 +220,7 @@ - (Before &productname; 8.2, the containment operators @> and + (Before PostgreSQL 8.2, the containment operators @> and <@ were respectively called @ and ~. These names are still available, but are deprecated and will eventually be retired. Notice that the old names are reversed from the convention diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml index 837983d039..0cef457372 100644 --- a/doc/src/sgml/json.sgml +++ b/doc/src/sgml/json.sgml @@ -280,7 +280,7 @@ SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb; -- The object with a single pair on the right side is contained -- within the object on the left side: -SELECT '{"product": "&productname;", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb; +SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb; -- The array on the right side is not considered contained within the -- array on the left, even though a similar array is nested within it: diff --git a/doc/src/sgml/legal.sgml b/doc/src/sgml/legal.sgml index 035c50d12d..dcc6edcd51 100644 --- a/doc/src/sgml/legal.sgml +++ b/doc/src/sgml/legal.sgml @@ -1,6 +1,10 @@ 2016 + + 1996-2016 +The PostgreSQL Global Development Group + 2016 diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index e82775beef..8cb6f7636b 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1702,7 +1702,7 @@ int PQprotocolVersion(const PGconn *conn); not change after connection startup is complete, but it could theoretically change during a connection reset. The 3.0 protocol will normally be used when communicating with - &productname; 7.4 or later servers; pre-7.4 servers + PostgreSQL 7.4 or later servers; pre-7.4 servers support only protocol 2.0. (Protocol 1.0 is obsolete and not supported by libpq.) @@ -5955,7 +5955,7 @@ int PQlibVersion(void); loaded version of libpq. The function can be used, for example, to determine which connection options are available for PQconnectdb or if the hex bytea - output added in &productname; 9.0 is supported. + output added in PostgreSQL 9.0 is supported. @@ -5967,7 +5967,7 @@ int PQlibVersion(void); - This function appeared in &productname; version 9.1, so + This function appeared in PostgreSQL version 9.1, so it cannot be used to detect required functionality in earlier versions, since linking to it will create a link dependency on version 9.1. @@ -7643,8 +7643,8 @@ void PQinitSSL(int do_ssl); PQinitSSL has been present since - &productname; 8.0, while PQinitOpenSSL - was added in &productname; 8.4, so PQinitSSL + PostgreSQL 8.0, while PQinitOpenSSL + was added in PostgreSQL 8.4, so PQinitSSL might be preferable for applications that need to work with older versions of libpq. diff --git a/doc/src/sgml/lobj.sgml b/doc/src/sgml/lobj.sgml index 37576ac21e..e85c8f1d6a 100644 --- a/doc/src/sgml/lobj.sgml +++ b/doc/src/sgml/lobj.sgml @@ -81,7 +81,7 @@ - As of &productname; 9.0, large objects have an owner + As of PostgreSQL 9.0, large objects have an owner and a set of access permissions, which can be managed using and . @@ -144,7 +144,7 @@ Oid lo_creat(PGconn *conn, int mode); or InvalidOid (zero) on failure. mode is unused and - ignored as of &productname; 8.1; however, for + ignored as of PostgreSQL 8.1; however, for backward compatibility with earlier releases it is best to set it to INV_READ, INV_WRITE, or INV_READ | INV_WRITE. @@ -176,7 +176,7 @@ Oid lo_create(PGconn *conn, Oid lobjId); - lo_create is new as of &productname; + lo_create is new as of PostgreSQL 8.1; if this function is run against an older server version, it will fail and return InvalidOid. @@ -225,7 +225,7 @@ Oid lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId); - lo_import_with_oid is new as of &productname; + lo_import_with_oid is new as of PostgreSQL 8.4 and uses lo_create internally which is new in 8.1; if this function is run against 8.0 or before, it will fail and return InvalidOid. @@ -389,7 +389,7 @@ pg_int64 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence); - lo_lseek64 is new as of &productname; + lo_lseek64 is new as of PostgreSQL 9.3. If this function is run against an older server version, it will fail and return -1. @@ -424,7 +424,7 @@ pg_int64 lo_tell64(PGconn *conn, int fd); - lo_tell64 is new as of &productname; + lo_tell64 is new as of PostgreSQL 9.3. If this function is run against an older server version, it will fail and return -1. @@ -473,13 +473,13 @@ int lo_truncate64(PGcon *conn, int fd, pg_int64 len); - lo_truncate is new as of &productname; + lo_truncate is new as of PostgreSQL 8.3; if this function is run against an older server version, it will fail and return -1. - lo_truncate64 is new as of &productname; + lo_truncate64 is new as of PostgreSQL 9.3; if this function is run against an older server version, it will fail and return -1. diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml index 535d3f97db..bdfe856a6f 100644 --- a/doc/src/sgml/logicaldecoding.sgml +++ b/doc/src/sgml/logicaldecoding.sgml @@ -192,7 +192,7 @@ $ pg_recvlogical -d postgres --slot test --drop-slot
- + Replication Slots diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index 5e16f67529..5dffb67399 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -386,7 +386,8 @@ - &productname;'s MVCC transaction semantics + &productname;'s + MVCC transaction semantics depend on being able to compare transaction ID (XID) numbers: a row version with an insertion XID greater than the current transaction's XID is in the future and should not be visible @@ -404,13 +405,10 @@ The reason that periodic vacuuming solves the problem is that VACUUM will mark rows as frozen, indicating that - they were inserted by a transaction which committed sufficiently far in - the past that the effects of the inserting transaction is certain to be - visible, from an MVCC perspective, to all current and future transactions. - &productname; reserves a special XID, - FrozenTransactionId, which does not follow the normal XID - comparison rules and is always considered older - than every normal XID. Normal XIDs are + they were inserted by a transaction that committed sufficiently far in + the past that the effects of the inserting transaction are certain to be + visible to all current and future transactions. + Normal XIDs are compared using modulo-232 arithmetic. This means that for every normal XID, there are two billion XIDs that are older and two billion that are newer; another @@ -420,16 +418,40 @@ the next two billion transactions, no matter which normal XID we are talking about. If the row version still exists after more than two billion transactions, it will suddenly appear to be in the future. To - prevent this, frozen row versions are treated as if the inserting XID were + prevent this, PostgreSQL reserves a special XID, + FrozenTransactionId, which does not follow the normal XID + comparison rules and is always considered older + than every normal XID. + Frozen row versions are treated as if the inserting XID were FrozenTransactionId, so that they will appear to be in the past to all normal transactions regardless of wraparound issues, and so such row versions will be valid until deleted, no matter how long that is. + + + In PostgreSQL versions before 9.4, freezing was + implemented by actually replacing a row's insertion XID + with FrozenTransactionId, which was visible in the + row's xmin system column. Newer versions just set a flag + bit, preserving the row's original xmin for possible + forensic use. However, rows with xmin equal + to FrozenTransactionId (2) may still be found + in databases pg_upgrade'd from pre-9.4 versions. + + + Also, system catalogs may contain rows with xmin equal + to BootstrapTransactionId (1), indicating that they were + inserted during the first phase of initdb. + Like FrozenTransactionId, this special XID is treated as + older than every normal XID. + + + - controls how old an XID value has to be before its row version will be + controls how old an XID value has to be before rows bearing that XID will be frozen. Increasing this setting may avoid unnecessary work if the rows that would otherwise be frozen will soon be modified again, but decreasing this setting increases diff --git a/doc/src/sgml/manage-ag.sgml b/doc/src/sgml/manage-ag.sgml index 45b8be109a..a193911ce8 100644 --- a/doc/src/sgml/manage-ag.sgml +++ b/doc/src/sgml/manage-ag.sgml @@ -517,7 +517,7 @@ SELECT spcname FROM pg_tablespace; point to each of the non-built-in tablespaces defined in the cluster. Although not recommended, it is possible to adjust the tablespace layout by hand by redefining these links. Under no circumstances perform - this operation while the server is running. Note that in &productname; 9.1 + this operation while the server is running. Note that in PostgreSQL 9.1 and earlier you will also need to update the pg_tablespace catalog with the new locations. (If you do not, pg_dump will continue to output the old tablespace locations.) diff --git a/doc/src/sgml/pg_variables.sgml b/doc/src/sgml/pg_variables.sgml index 05cb5f5473..1103483924 100644 --- a/doc/src/sgml/pg_variables.sgml +++ b/doc/src/sgml/pg_variables.sgml @@ -7,9 +7,69 @@ provides functions to work with variables of various types. Created variables live only in the current user session. + + + Note that the module does not support transactions and savepoints. For + example: + + +SELECT pgv_set_int('vars', 'int1', 101); +BEGIN; +SELECT pgv_set_int('vars', 'int2', 102); +ROLLBACK; + +SELECT * FROM pgv_list() order by package, name; + package | name +---------+------ + vars | int1 + vars | int2 +(2 rows) + + Module functions + + + The functions provided by the pg_variables module are + shown in the tables below. The module supports the following scalar and + record types. + + + + To use pgv_get_() functions required package and variable + must exists. It is necessary to set variable with pgv_set_() + functions to use pgv_get_() functions. + + + + If a package does not exists you will get the following error: + + + +SELECT pgv_get_int('vars', 'int1'); +ERROR: unrecognized package "vars" + + + + If a variable does not exists you will get the following error: + + + +SELECT pgv_get_int('vars', 'int1'); +ERROR: unrecognized variable "int1" + + + + pgv_get_() functions check the variable type. If the variable + type does not match with the function type the error will be raised: + + + +SELECT pgv_get_text('vars', 'int1'); +ERROR: variable "int1" requires "integer" value + + Integer variables @@ -257,6 +317,25 @@ Records + + + The following functions are provided by the module to work with + collections of record types. + + + + To use pgv_update(), pgv_delete() and + pgv_select() functions required package and variable must + exists. Otherwise the error will be raised. It is necessary to set + variable with pgv_insert() function to use these functions. + + + + pgv_update(), pgv_delete() and + pgv_select() functions check the variable type. If the + variable type does not record type the error will be raised. + + @@ -267,6 +346,9 @@ Returns + + Description + @@ -277,6 +359,13 @@ void + + Inserts a record to the variable collection. If package and + variable do not exists they will be created. The first column + of r will be a primary key. If exists a record with the same + primary key the error will be raised. If this variable + collection has other structure the error will be raised. + @@ -285,6 +374,12 @@ boolean + + Updates a record with the corresponding primary key (the first + column of r is a primary key). Returns + true if a record was found. If this variable + collection has other structure the error will be raised. + @@ -293,6 +388,11 @@ boolean + + Deletes a record with the corresponding primary key (the first + column of r is a primary key). Returns + true if a record was found. + @@ -301,6 +401,9 @@ set of record + + Returns the variable collection records. + @@ -309,6 +412,10 @@ record + + Returns the record with the corresponding primary key (the first + column of r is a primary key). + @@ -317,6 +424,11 @@ set of record + + Returns the variable collection records with the corresponding + primary keys (the first column of r is a primary + key). + @@ -334,6 +446,9 @@ Returns + + Description + @@ -344,6 +459,9 @@ bool + + Returns true if package and variable exists. + @@ -352,6 +470,11 @@ void + + Removes the variable with the corresponding name. Required + package and variable must exists, otherwise the error will be + raised. + @@ -360,6 +483,11 @@ void + + Removes the package and all package variables with the + corresponding name. Required package must exists, otherwise the + error will be raised. + @@ -368,6 +496,9 @@ void + + Removes all packages and variables. + @@ -376,6 +507,9 @@ table(package text, name text) + + Returns set of records of assigned packages and variables. + @@ -384,6 +518,9 @@ table(package text, used_memory bigint) + + Returns list of assigned packages and used memory in bytes. + @@ -399,7 +536,7 @@ It is easy to use functions to work with scalar variables: - + SELECT pgv_set_int('vars', 'int1', 101); SELECT pgv_set_int('vars', 'int2', 102); @@ -418,14 +555,14 @@ SELECT pgv_get_int('vars', 'int2'); Let's assume we have a tab table: - + CREATE TABLE tab (id int, t varchar); INSERT INTO tab VALUES (0, 'str00'), (1, 'str11'); Then you can use functions to work with record variables: - + SELECT pgv_insert('vars', 'r1', tab) FROM tab; SELECT pgv_select('vars', 'r1'); @@ -465,7 +602,7 @@ SELECT pgv_select('vars', 'r1'); You can list packages and variables: - + SELECT * FROM pgv_list() order by package, name; package | name ---------+------ @@ -477,7 +614,7 @@ SELECT * FROM pgv_list() order by package, name; And get used memory in bytes: - + SELECT * FROM pgv_stats() order by package; package | used_memory ---------+------------- @@ -487,14 +624,14 @@ SELECT * FROM pgv_stats() order by package; You can delete variables or whole packages: - + SELECT pgv_remove('vars', 'int1'); SELECT pgv_remove('vars'); You can delete all packages and variables: - + SELECT pgv_free(); diff --git a/doc/src/sgml/pgbuffercache.sgml b/doc/src/sgml/pgbuffercache.sgml index f379be225f..b261a4dbe0 100644 --- a/doc/src/sgml/pgbuffercache.sgml +++ b/doc/src/sgml/pgbuffercache.sgml @@ -82,7 +82,7 @@ smallint Fork number within the relation; see - include/storage/relfilenode.h + include/common/relpath.h diff --git a/doc/src/sgml/pgpathman.sgml b/doc/src/sgml/pgpathman.sgml index 36f93c9a6d..78f4c689c8 100644 --- a/doc/src/sgml/pgpathman.sgml +++ b/doc/src/sgml/pgpathman.sgml @@ -94,12 +94,12 @@ WHERE id = 150 - LIST-patitioning; + LIST-partitioning; - HASH-patitioning by non integer attribtes. + HASH-partitioning by non-integer attributes. diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml index 5d87ca6b97..e4bdc1e803 100644 --- a/doc/src/sgml/pgstandby.sgml +++ b/doc/src/sgml/pgstandby.sgml @@ -148,7 +148,7 @@ restore_command = 'pg_standby archiveDir %f %p %r' specification method is more accurate in determining the correct archive cut-off point. Use of this parameter is deprecated as of - &productname; 8.3; it is safer and more efficient to + PostgreSQL 8.3; it is safer and more efficient to specify a restartwalfile parameter. A too small setting could result in removal of files that are still needed for a restart of the standby server, while a too large setting wastes @@ -241,17 +241,17 @@ restore_command = 'pg_standby archiveDir %f %p %r' pg_standby is designed to work with - &productname; 8.2 and later. + PostgreSQL 8.2 and later. - &productname; 8.3 provides the %r macro, + PostgreSQL 8.3 provides the %r macro, which is designed to let pg_standby know the - last file it needs to keep. With &productname; 8.2, the + last file it needs to keep. With PostgreSQL 8.2, the -k option must be used if archive cleanup is required. This option remains available in 8.3, but its use is deprecated. - &productname; 8.4 provides the + PostgreSQL 8.4 provides the recovery_end_command option. Without this option a leftover trigger file can be hazardous. diff --git a/doc/src/sgml/plperl.sgml b/doc/src/sgml/plperl.sgml index 3186451d77..f1968e4ff5 100644 --- a/doc/src/sgml/plperl.sgml +++ b/doc/src/sgml/plperl.sgml @@ -201,9 +201,9 @@ select returns_array(); Perl passes &productname; arrays as a blessed - &productname;::InServer::ARRAY object. This object may be treated as an array + PostgreSQL::InServer::ARRAY object. This object may be treated as an array reference or a string, allowing for backward compatibility with Perl - code written for &productname; versions below 9.1 to + code written for PostgreSQL versions below 9.1 to run. For example: diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml index d754891583..466b7a6a9a 100644 --- a/doc/src/sgml/plpgsql.sgml +++ b/doc/src/sgml/plpgsql.sgml @@ -59,7 +59,7 @@ - In &productname; 9.0 and later, + In PostgreSQL 9.0 and later, PL/pgSQL is installed by default. However it is still a loadable module, so especially security-conscious administrators could choose to remove it. @@ -1441,28 +1441,56 @@ EXECUTE format('UPDATE tbl SET %I = $1 WHERE key = $2', colname) GET CURRENT DIAGNOSTICS variable { = | := } item , ... ; - This command allows retrieval of system status indicators. Each - item is a key word identifying a status - value to be assigned to the specified variable (which should be - of the right data type to receive it). The currently available - status items are ROW_COUNT, the number of rows - processed by the last SQL command sent to - the SQL engine, and RESULT_OID, - the OID of the last row inserted by the most recent - SQL command. Note that RESULT_OID - is only useful after an INSERT command into a - table containing OIDs. - Colon-equal (:=) can be used instead of SQL-standard - = for GET DIAGNOSTICS. - - - - An example: + This command allows retrieval of system status indicators. + CURRENT is a noise word (but see also GET STACKED + DIAGNOSTICS in ). + Each item is a key word identifying a status + value to be assigned to the specified variable + (which should be of the right data type to receive it). The currently + available status items are shown + in . Colon-equal + (:=) can be used instead of the SQL-standard = + token. An example: GET DIAGNOSTICS integer_var = ROW_COUNT; + + Available Diagnostics Items + + + + Name + Type + Description + + + + + ROW_COUNT + integer + the number of rows processed by the most + recent SQL command + + + RESULT_OID + oid + the OID of the last row inserted by the most + recent SQL command (only useful after + an INSERT command into a table having + OIDs) + + + PG_CONTEXT + text + line(s) of text describing the current call stack + (see ) + + + +
+ The second method to determine the effects of a command is to check the special variable named FOUND, which is of @@ -1828,13 +1856,13 @@ SELECT * FROM get_available_flightid(CURRENT_DATE); PL/pgSQL has three forms of IF: - IF ... THEN + IF ... THEN ... END IF - IF ... THEN ... ELSE + IF ... THEN ... ELSE ... END IF - IF ... THEN ... ELSIF ... THEN ... ELSE + IF ... THEN ... ELSIF ... THEN ... ELSE ... END IF @@ -2163,7 +2191,7 @@ EXIT label WHEN EXIT is never considered to match a BEGIN block. (This is a change from - pre-8.4 releases of &productname;, which + pre-8.4 releases of PostgreSQL, which would allow an unlabeled EXIT to match a BEGIN block.) @@ -2699,13 +2727,14 @@ GET STACKED DIAGNOSTICS variable { = | := } Each item is a key word identifying a status - value to be assigned to the specified variable (which should be - of the right data type to receive it). The currently available - status items are shown in . + value to be assigned to the specified variable + (which should be of the right data type to receive it). The currently + available status items are shown + in . - Error Diagnostics Values + Error Diagnostics Items @@ -2717,53 +2746,54 @@ GET STACKED DIAGNOSTICS variable { = | := } RETURNED_SQLSTATE - text + text the SQLSTATE error code of the exception COLUMN_NAME - text + text the name of the column related to exception CONSTRAINT_NAME - text + text the name of the constraint related to exception PG_DATATYPE_NAME - text + text the name of the data type related to exception MESSAGE_TEXT - text + text the text of the exception's primary message TABLE_NAME - text + text the name of the table related to exception SCHEMA_NAME - text + text the name of the schema related to exception PG_EXCEPTION_DETAIL - text + text the text of the exception's detail message, if any PG_EXCEPTION_HINT - text + text the text of the exception's hint message, if any PG_EXCEPTION_CONTEXT - text - line(s) of text describing the call stack + text + line(s) of text describing the call stack at the time of the + exception (see ) @@ -2794,26 +2824,19 @@ END; - - Obtaining Current Execution Information + + Obtaining Execution Location Information - The GET CURRENT DIAGNOSTICS - command retrieves information about current execution state (whereas - the GET STACKED DIAGNOSTICS command discussed above - reports information about the execution state as of a previous error). - This command has the form: - - - -GET CURRENT DIAGNOSTICS variable { = | := } item , ... ; - - - - Currently only one information item is supported. Status - item PG_CONTEXT will return a text string with line(s) of - text describing the call stack. The first line refers to the - current function and currently executing GET DIAGNOSTICS + The GET DIAGNOSTICS command, previously described + in , retrieves information + about current execution state (whereas the GET STACKED + DIAGNOSTICS command discussed above reports information about + the execution state as of a previous error). Its PG_CONTEXT + status item is useful for identifying the current execution + location. PG_CONTEXT returns a text string with line(s) + of text describing the call stack. The first line refers to the current + function and currently executing GET DIAGNOSTICS command. The second and any subsequent lines refer to calling functions further up the call stack. For example: @@ -2847,6 +2870,12 @@ CONTEXT: PL/pgSQL function outer_func() line 3 at RETURN + + + GET STACKED DIAGNOSTICS ... PG_EXCEPTION_CONTEXT + returns the same sort of stack trace, but describing the location + at which an error was detected, rather than the current location. + @@ -3559,7 +3588,7 @@ RAISE unique_violation USING MESSAGE = 'Duplicate user ID: ' || user_id; - Before &productname; 9.1, RAISE without + Before PostgreSQL 9.1, RAISE without parameters was interpreted as re-throwing the error from the block containing the active exception handler. Thus an EXCEPTION clause nested within that handler could not catch it, even if the @@ -4225,7 +4254,7 @@ SELECT * FROM sales_summary_bytime; - When a PL/pgSQL function is called as a + When a PL/pgSQL function is called as an event trigger, several special variables are created automatically in the top-level block. They are: @@ -4253,7 +4282,7 @@ SELECT * FROM sales_summary_bytime; - shows an example of a + shows an example of an event trigger procedure in PL/pgSQL. @@ -4310,7 +4339,7 @@ INSERT INTO foo (foo) VALUES (foo); - &productname; versions before 9.0 would try + PostgreSQL versions before 9.0 would try to substitute the variable in all three cases, leading to syntax errors. @@ -4373,7 +4402,7 @@ BEGIN large body of PL/pgSQL code. In such cases you can specify that PL/pgSQL should resolve ambiguous references as the variable (which is compatible with PL/pgSQL's - behavior before &productname; 9.0), or as the + behavior before PostgreSQL 9.0), or as the table column (which is compatible with some other systems such as Oracle). diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index fd798a7f22..b5ac632ab0 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -477,7 +477,7 @@ postgres_fdw can be used with remote servers dating back - to &productname; 8.3. Read-only capability is available + to PostgreSQL 8.3. Read-only capability is available back to 8.1. A limitation however is that postgres_fdw generally assumes that immutable built-in functions and operators are safe to send to the remote server for execution, if they appear in a diff --git a/doc/src/sgml/problems.sgml b/doc/src/sgml/problems.sgml index 02d509956b..60b41f3ff2 100644 --- a/doc/src/sgml/problems.sgml +++ b/doc/src/sgml/problems.sgml @@ -295,15 +295,24 @@ Where to Report Bugs - In general, send bug reports to the bug report our support email - address at + In general, send bug reports to our support email address at bugs@postgrespro.ru. You are requested to use a descriptive subject for your email message, perhaps parts of the error message. - Do not send bug reports to any of the user mailing lists, such as + Do not send bug reports specific to Postgres Pro + to the PostgreSQL support email address, + as Postgres Pro is not supported by + the PostgreSQL community. + But you can send reports to bugs@postgresql.org + for any bugs related to PostgreSQL. + + + + Even if your bug is not specific to Postgres Pro, + do not send bug reports to any of the user mailing lists, such as pgsql-sql@postgresql.org or pgsql-general@postgresql.org. These mailing lists are for answering @@ -316,9 +325,10 @@ the developers' mailing list pgsql-hackers@postgresql.org. This list is for discussing the development of PostgreSQL, and it would be nice - if we could keep the bug reports separate. We might choose to take up a + if the community could keep the bug reports separate. + The community might choose to take up a discussion about your bug report on pgsql-hackers, - if the problem needs more review. + if the PostgreSQL-related problem needs more review. diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml index 6c9d14cdd8..5e465c64a7 100644 --- a/doc/src/sgml/protocol.sgml +++ b/doc/src/sgml/protocol.sgml @@ -19,9 +19,9 @@ This document describes version 3.0 of the protocol, implemented in - &productname; 7.4 and later. For descriptions + PostgreSQL 7.4 and later. For descriptions of the earlier protocol versions, see previous releases of the - &productname; documentation. A single server + PostgreSQL documentation. A single server can support multiple protocol versions. The initial startup-request message tells the server which protocol version the client is attempting to use, and then the server follows that protocol @@ -164,7 +164,7 @@ Data of a particular data type might be transmitted in any of several - different formats. As of &productname; 7.4 + different formats. As of PostgreSQL 7.4 the only supported formats are text and binary, but the protocol makes provision for future extensions. The desired format for any value is specified by a format code. @@ -3054,7 +3054,7 @@ CommandComplete (B) COPY rows where rows is the number of rows copied. (Note: the row count appears only in - &productname; 8.2 and later.) + PostgreSQL 8.2 and later.) diff --git a/doc/src/sgml/ref/alter_function.sgml b/doc/src/sgml/ref/alter_function.sgml index 1440c04a4e..3824c88eeb 100644 --- a/doc/src/sgml/ref/alter_function.sgml +++ b/doc/src/sgml/ref/alter_function.sgml @@ -236,8 +236,9 @@ ALTER FUNCTION name ( [ [ - Before &productname; 8.4, the OPERATOR + Before PostgreSQL 8.4, the OPERATOR clause could include a RECHECK option. This is no longer supported because whether an index operator is lossy is now determined on-the-fly at run time. This allows efficient handling of diff --git a/doc/src/sgml/ref/alter_sequence.sgml b/doc/src/sgml/ref/alter_sequence.sgml index b32805b26e..32da5aacd0 100644 --- a/doc/src/sgml/ref/alter_sequence.sgml +++ b/doc/src/sgml/ref/alter_sequence.sgml @@ -274,7 +274,7 @@ ALTER SEQUENCE [ IF EXISTS ] name S ALTER SEQUENCE does not affect the currval - status for the sequence. (Before &productname; + status for the sequence. (Before PostgreSQL 8.3, it sometimes did.) diff --git a/doc/src/sgml/ref/alter_user_mapping.sgml b/doc/src/sgml/ref/alter_user_mapping.sgml index d6b520fea3..ca6e6717ba 100644 --- a/doc/src/sgml/ref/alter_user_mapping.sgml +++ b/doc/src/sgml/ref/alter_user_mapping.sgml @@ -89,9 +89,9 @@ ALTER USER MAPPING FOR { user_name Examples - Change the password for user mapping bob, server foo: + Change the password for user mapping bob, server foo: -ALTER USER MAPPING FOR bob SERVER foo OPTIONS (user 'bob', password 'public'); +ALTER USER MAPPING FOR bob SERVER foo OPTIONS (SET password 'public'); diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml index b35025aba3..fafffa9d9b 100644 --- a/doc/src/sgml/ref/cluster.sgml +++ b/doc/src/sgml/ref/cluster.sgml @@ -212,7 +212,7 @@ CLUSTER; CLUSTER index_name ON table_name - is also supported for compatibility with pre-8.3 &productname; + is also supported for compatibility with pre-8.3 PostgreSQL versions. diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index add48125b8..cdfb3f2150 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -744,7 +744,7 @@ COPY count - &productname; releases before 7.4 used a + PostgreSQL releases before 7.4 used a different binary file format. @@ -957,7 +957,7 @@ ZW ZIMBABWE - The following syntax was used before &productname; + The following syntax was used before PostgreSQL version 9.0 and is still supported: @@ -992,7 +992,7 @@ COPY { table_name [ ( - The following syntax was used before &productname; + The following syntax was used before PostgreSQL version 7.3 and is still supported: diff --git a/doc/src/sgml/ref/create_domain.sgml b/doc/src/sgml/ref/create_domain.sgml index 3a9a414fab..aeb8fb91e1 100644 --- a/doc/src/sgml/ref/create_domain.sgml +++ b/doc/src/sgml/ref/create_domain.sgml @@ -181,7 +181,7 @@ CREATE DOMAIN name [ AS ] When a domain has multiple CHECK constraints, they will be tested in alphabetical order by name. - (&productname; versions before 9.5 did not honor any + (PostgreSQL versions before 9.5 did not honor any particular firing order for CHECK constraints.) diff --git a/doc/src/sgml/ref/create_extension.sgml b/doc/src/sgml/ref/create_extension.sgml index f7c57d8a2a..700bd3a163 100644 --- a/doc/src/sgml/ref/create_extension.sgml +++ b/doc/src/sgml/ref/create_extension.sgml @@ -133,7 +133,7 @@ CREATE EXTENSION [ IF NOT EXISTS ] extension_name extension's author, and might vary if there is more than one version of the old-style module that can be upgraded into an extension. For the standard additional modules supplied with pre-9.1 - &productname;, use unpackaged + PostgreSQL, use unpackaged for old_version when updating a module to extension style. diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index fb83abc4b2..4804f8c5e7 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -448,8 +448,9 @@ CREATE [ OR REPLACE ] FUNCTION The SET clause causes the specified configuration parameter to be set to the specified value when the function is entered, and then restored to its prior value when the function exits. - SET FROM CURRENT saves the session's current value of - the parameter as the value to be applied when the function is entered. + SET FROM CURRENT saves the value of the parameter that + is current when CREATE FUNCTION is executed as the value + to be applied when the function is entered. @@ -739,7 +740,7 @@ $$ LANGUAGE plpgsql - Before &productname; version 8.3, the + Before PostgreSQL version 8.3, the SET option was not available, and so older functions may contain rather complicated logic to save, set, and restore search_path. The SET option is far easier diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml index 4d8553ad8c..e2f9ab5996 100644 --- a/doc/src/sgml/ref/create_language.sgml +++ b/doc/src/sgml/ref/create_language.sgml @@ -39,7 +39,7 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE not CREATE LANGUAGE. Direct use of @@ -274,7 +274,7 @@ CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name [ DEFAUL - Before &productname; 8.4, the OPERATOR + Before PostgreSQL 8.4, the OPERATOR clause could include a RECHECK option. This is no longer supported because whether an index operator is lossy is now determined on-the-fly at run time. This allows efficient handling of diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index a686ffcb92..50471c5f4c 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -329,26 +329,33 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI table. - Default expressions for the copied column definitions will only be - copied if INCLUDING DEFAULTS is specified. - Defaults that call database-modification functions, like - nextval, create a linkage between the original and - new tables. The + Default expressions for the copied column definitions will be copied + only if INCLUDING DEFAULTS is specified. The default behavior is to exclude default expressions, resulting in the copied columns in the new table having null defaults. + Note that copying defaults that call database-modification functions, + such as nextval, may create a functional linkage between + the original and new tables. Not-null constraints are always copied to the new table. CHECK constraints will be copied only if INCLUDING CONSTRAINTS is specified. - Indexes, PRIMARY KEY, and UNIQUE constraints - on the original table will be created on the new table only if the - INCLUDING INDEXES clause is specified. No distinction is made between column constraints and table constraints. - STORAGE settings for the copied column definitions will only - be copied if INCLUDING STORAGE is specified. The + + Indexes, PRIMARY KEY, UNIQUE, + and EXCLUDE constraints on the original table will be + created on the new table only if INCLUDING INDEXES + is specified. Names for the new indexes and constraints are + chosen according to the default rules, regardless of how the originals + were named. (This behavior avoids possible duplicate-name failures for + the new indexes.) + + + STORAGE settings for the copied column definitions will be + copied only if INCLUDING STORAGE is specified. The default behavior is to exclude STORAGE settings, resulting in the copied columns in the new table having type-specific default settings. For more on STORAGE settings, see @@ -356,24 +363,26 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI Comments for the copied columns, constraints, and indexes - will only be copied if INCLUDING COMMENTS + will be copied only if INCLUDING COMMENTS is specified. The default behavior is to exclude comments, resulting in the copied columns and constraints in the new table having no comments. - INCLUDING ALL is an abbreviated form of + + INCLUDING ALL is an abbreviated form of INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS. - Note also that unlike INHERITS, columns and + Note that unlike INHERITS, columns and constraints copied by LIKE are not merged with similarly named columns and constraints. If the same name is specified explicitly or in another LIKE clause, an error is signaled. - The LIKE clause can also be used to copy columns from - views, foreign tables, or composite types. Inapplicable options (e.g., INCLUDING - INDEXES from a view) are ignored. + The LIKE clause can also be used to copy column + definitions from views, foreign tables, or composite types. + Inapplicable options (e.g., INCLUDING INDEXES from + a view) are ignored. @@ -447,7 +456,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI When a table has multiple CHECK constraints, they will be tested for each row in alphabetical order by name, after checking NOT NULL constraints. - (&productname; versions before 9.5 did not honor any + (PostgreSQL versions before 9.5 did not honor any particular firing order for CHECK constraints.) @@ -1514,6 +1523,17 @@ CREATE TABLE employees OF employee_type ( + + <literal>LIKE</> Clause + + + While a LIKE clause exists in the SQL standard, many of the + options that PostgreSQL accepts for it are not + in the standard, and some of the standard's options are not implemented + by PostgreSQL. + + + <literal>WITH</> Clause diff --git a/doc/src/sgml/ref/create_trigger.sgml b/doc/src/sgml/ref/create_trigger.sgml index 1bb892b649..a0c9cf2e4a 100644 --- a/doc/src/sgml/ref/create_trigger.sgml +++ b/doc/src/sgml/ref/create_trigger.sgml @@ -410,7 +410,7 @@ UPDATE OF column_name1 [, column_name2 - In &productname; versions before 7.3, it was + In PostgreSQL versions before 7.3, it was necessary to declare trigger functions as returning the placeholder type opaque, rather than trigger. To support loading of old dump files, CREATE TRIGGER will accept a function diff --git a/doc/src/sgml/ref/create_type.sgml b/doc/src/sgml/ref/create_type.sgml index 820e2ebb2c..86d3c59f57 100644 --- a/doc/src/sgml/ref/create_type.sgml +++ b/doc/src/sgml/ref/create_type.sgml @@ -784,7 +784,7 @@ CREATE TYPE name - Before &productname; version 8.3, the name of + Before PostgreSQL version 8.3, the name of a generated array type was always exactly the element type's name with one underscore character (_) prepended. (Type names were therefore restricted in length to one less character than other names.) @@ -805,11 +805,11 @@ CREATE TYPE name - Before &productname; version 8.2, the shell-type + Before PostgreSQL version 8.2, the shell-type creation syntax CREATE TYPE name did not exist. The way to create a new base type was to create its input function first. - In this approach, &productname; will first see + In this approach, PostgreSQL will first see the name of the new data type as the return type of the input function. The shell type is implicitly created in this situation, and then it can be referenced in the definitions of the remaining I/O functions. @@ -821,7 +821,7 @@ CREATE TYPE name - In &productname; versions before 7.3, it + In PostgreSQL versions before 7.3, it was customary to avoid creating a shell type at all, by replacing the functions' forward references to the type name with the placeholder pseudotype opaque. The cstring arguments and diff --git a/doc/src/sgml/ref/createuser.sgml b/doc/src/sgml/ref/createuser.sgml index f9f0539603..c223d62cb6 100644 --- a/doc/src/sgml/ref/createuser.sgml +++ b/doc/src/sgml/ref/createuser.sgml @@ -175,7 +175,7 @@ doc/src/sgml/ref/createuser.sgml /, /, / is not specified on the command - line. (This was the default behavior up to &productname; 9.1.) + line. (This was the default behavior up to PostgreSQL 9.1.) diff --git a/doc/src/sgml/ref/drop_language.sgml b/doc/src/sgml/ref/drop_language.sgml index 1a2a01df35..98a8fb9dbc 100644 --- a/doc/src/sgml/ref/drop_language.sgml +++ b/doc/src/sgml/ref/drop_language.sgml @@ -36,7 +36,7 @@ DROP [ PROCEDURAL ] LANGUAGE [ IF EXISTS ] name - As of &productname; 9.1, most procedural + As of PostgreSQL 9.1, most procedural languages have been made into extensions, and should therefore be removed with not DROP LANGUAGE. diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index 445d3d84c7..07ad116590 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -429,7 +429,7 @@ GRANT role_name [, ...] TO - Since &productname; 8.1, the concepts of users and + Since PostgreSQL 8.1, the concepts of users and groups have been unified into a single kind of entity called a role. It is therefore no longer necessary to use the keyword GROUP to identify whether a grantee is a user or a group. GROUP diff --git a/doc/src/sgml/ref/insert.sgml b/doc/src/sgml/ref/insert.sgml index 68a30785a9..97148be7c4 100644 --- a/doc/src/sgml/ref/insert.sgml +++ b/doc/src/sgml/ref/insert.sgml @@ -194,8 +194,8 @@ INSERT INTO table_name [ AS ON CONFLICT DO UPDATE, do not include the table's name in the specification of a target column. For - example, INSERT ... ON CONFLICT DO UPDATE tab SET - table_name.col = 1 is invalid (this follows the general + example, INSERT INTO table_name ... ON CONFLICT DO UPDATE + SET table_name.col = 1 is invalid (this follows the general behavior for UPDATE). @@ -295,8 +295,7 @@ INSERT INTO table_name [ AS index_column_name columns and/or index_expression - expressions, and an optional - index_predicate. All index_predicate. All table_name unique indexes that, without regard to order, contain exactly the conflict_target-specified diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml index 915aa88a2b..9903daa6dd 100644 --- a/doc/src/sgml/ref/pg_basebackup.sgml +++ b/doc/src/sgml/ref/pg_basebackup.sgml @@ -364,7 +364,7 @@ doc/src/sgml/ref/pg_basebackup.sgml Enables gzip compression of tar file output, and specifies the - compression level (1 through 9, 9 being best + compression level (0 through 9, 0 being no compression and 9 being best compression). Compression is only available when using the tar format. diff --git a/doc/src/sgml/ref/pg_config-ref.sgml b/doc/src/sgml/ref/pg_config-ref.sgml index 3473c3b10a..91eb54120b 100644 --- a/doc/src/sgml/ref/pg_config-ref.sgml +++ b/doc/src/sgml/ref/pg_config-ref.sgml @@ -303,9 +303,9 @@ , , , , , , - and were added in &productname; 8.1. - The option was added in &productname; 8.4. - The option was added in &productname; 9.0. + and were added in PostgreSQL 8.1. + The option was added in PostgreSQL 8.4. + The option was added in PostgreSQL 9.0. diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 7c6fe1933d..49d9e11a77 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -319,7 +319,7 @@ doc/src/sgml/ref/pg_dump.sgml For a consistent backup, the database server needs to support synchronized snapshots, - a feature that was introduced in &productname; 9.2. With this + a feature that was introduced in PostgreSQL 9.2. With this feature, database clients can ensure they see the same data set even though they use different connections. pg_dump -j uses multiple database connections; it connects to the database once with the master process and @@ -334,7 +334,7 @@ doc/src/sgml/ref/pg_dump.sgml do this is to halt any data modifying processes (DDL and DML) accessing the database before starting the backup. You also need to specify the parameter when running - pg_dump -j against a pre-9.2 &productname; + pg_dump -j against a pre-9.2 PostgreSQL server. @@ -530,7 +530,7 @@ doc/src/sgml/ref/pg_dump.sgml The behavior of the - NonC and and non-POSIX locales rely on the + Non-C and and non-POSIX locales rely on the operating system's collation library for character set ordering. This controls the ordering of keys stored in indexes. For this reason, a cluster cannot switch to an incompatible collation library version, - either through snapshot restore, binary streaming replication, or - pg_upgrade run. + either through snapshot restore, binary streaming replication, a + different operating system, or an operating system upgrade. diff --git a/doc/src/sgml/seg.sgml b/doc/src/sgml/seg.sgml index af1c702fb6..00bd71dcb6 100644 --- a/doc/src/sgml/seg.sgml +++ b/doc/src/sgml/seg.sgml @@ -304,7 +304,7 @@ test=> select '6.25 .. 6.50'::seg as "pH";
- (Before &productname; 8.2, the containment operators @> and <@ were + (Before PostgreSQL 8.2, the containment operators @> and <@ were respectively called @ and ~. These names are still available, but are deprecated and will eventually be retired. Notice that the old names are reversed from the convention formerly followed by the core geometric diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml index cdfca520b6..c1221c56d6 100644 --- a/doc/src/sgml/sepgsql.sgml +++ b/doc/src/sgml/sepgsql.sgml @@ -675,13 +675,13 @@ ERROR: SELinux: security policy violation
sepgsql_mcstrans_in(text) returns text - Translates the given qualifies MLS/MCS range into raw format if + Translates the given qualified MLS/MCS range into raw format if the mcstrans daemon is running. sepgsql_mcstrans_out(text) returns text - Translates the given raw MCS/MCS range into qualified format if + Translates the given raw MLS/MCS range into qualified format if the mcstrans daemon is running. @@ -753,7 +753,7 @@ ERROR: SELinux: security policy violation External Resources - SE-&productname; Introduction + SE-PostgreSQL Introduction This wiki page provides a brief overview, security design, architecture, diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml index 8260df8ce8..eeaef82d0e 100644 --- a/doc/src/sgml/sources.sgml +++ b/doc/src/sgml/sources.sgml @@ -367,7 +367,7 @@ ereport(ERROR, potentially-localized error message text. These functions should be used in error reports for which it's likely that applications would wish to have automatic error handling. As of - &productname; 9.3, complete coverage exists only for + PostgreSQL 9.3, complete coverage exists only for errors in SQLSTATE class 23 (integrity constraint violation), but this is likely to be expanded in future. diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index a4737346fe..3afeb63653 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -992,7 +992,7 @@ SPIPlanPtr SPI_prepare(const char * command, int changes from one use to the next, the statement will be re-parsed using the new search_path. (This latter behavior is new as of - &productname; 9.3.) See PostgreSQL 9.3.) See for more information about the behavior of prepared statements. @@ -3950,7 +3950,7 @@ void SPI_freetuptable(SPITupleTable * tuptable) - Beginning in &productname; 9.3, + Beginning in PostgreSQL 9.3, SPI_freetuptable contains guard logic to protect against duplicate deletion requests for the same row set. In previous releases, duplicate deletions would lead to crashes. diff --git a/doc/src/sgml/sr_plan.sgml b/doc/src/sgml/sr_plan.sgml index 34136d18b2..7437da5d4d 100644 --- a/doc/src/sgml/sr_plan.sgml +++ b/doc/src/sgml/sr_plan.sgml @@ -10,7 +10,7 @@ sr_plan is an extension which allows to save query execution plans and use these plans for all repetitions of same query, instead of - optimizing identical query again and again/ + optimizing identical query again and again. sr_plan looks like Oracle Outline system. It can be used to lock diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml index f934586f35..6dce4ca503 100644 --- a/doc/src/sgml/storage.sgml +++ b/doc/src/sgml/storage.sgml @@ -770,10 +770,10 @@ data. Empty in ordinary tables. unallocated space, and to the start of the special space. The next 2 bytes of the page header, pd_pagesize_version, store both the page size and a version indicator. Beginning with - &productname; 8.3 the version number is 4; - &productname; 8.1 and 8.2 used version number 3; - &productname; 8.0 used version number 2; - &productname; 7.3 and 7.4 used version number 1; + PostgreSQL 8.3 the version number is 4; + PostgreSQL 8.1 and 8.2 used version number 3; + PostgreSQL 8.0 used version number 2; + PostgreSQL 7.3 and 7.4 used version number 1; prior releases used version number 0. (The basic page layout and header format has not changed in most of these versions, but the layout of heap row headers has.) The page size diff --git a/doc/src/sgml/syntax.sgml b/doc/src/sgml/syntax.sgml index 3b47b7f2aa..ff3e8c05e5 100644 --- a/doc/src/sgml/syntax.sgml +++ b/doc/src/sgml/syntax.sgml @@ -454,7 +454,7 @@ SELECT 'foo' 'bar'; is off, then &productname; recognizes backslash escapes in both regular and escape string constants. However, as of - &productname; 9.1, the default is on, meaning + PostgreSQL 9.1, the default is on, meaning that backslash escapes are recognized only in escape string constants. This behavior is more standards-compliant, but might break applications which rely on the historical behavior, where backslash escapes @@ -1133,7 +1133,7 @@ SELECT 3 OPERATOR(pg_catalog.+) 4; - &productname; versions before 9.5 used slightly different + PostgreSQL versions before 9.5 used slightly different operator precedence rules. In particular, <= >= and <> used to be treated as generic operators; IS tests used to have higher priority; @@ -2301,7 +2301,7 @@ SELECT ROW(t.f1, t.f2, 42) FROM t; - Before &productname; 8.2, the + Before PostgreSQL 8.2, the .* syntax was not expanded, so that writing ROW(t.*, 42) created a two-field row whose first field was another row value. The new behavior is usually more useful. diff --git a/doc/src/sgml/textsearch.sgml b/doc/src/sgml/textsearch.sgml index a22056e9b5..2324a109d3 100644 --- a/doc/src/sgml/textsearch.sgml +++ b/doc/src/sgml/textsearch.sgml @@ -294,35 +294,6 @@ SELECT 'fat cats ate fat rats'::tsvector @@ to_tsquery('fat & rat'); already normalized, so rats does not match rat. - - Phrase search is made possible with the help of the <-> - (FOLLOWED BY) operator, which enforces lexeme order. This allows you - to discard strings not containing the desired phrase, for example: - - -SELECT q @@ to_tsquery('fatal <-> error') -FROM unnest(array[to_tsvector('fatal error'), - to_tsvector('error is not fatal')]) AS q; - ?column? ----------- - t - f - - - A more generic version of the FOLLOWED BY operator takes form of - <N>, where N stands for the greatest allowed distance - between the specified lexemes. The phraseto_tsquery - function makes use of this behavior in order to construct a - tsquery capable of matching the provided phrase: - - -SELECT phraseto_tsquery('cat ate some rats'); - phraseto_tsquery -------------------------------- - ( 'cat' <-> 'ate' ) <2> 'rat' - - - The @@ operator also supports text input, allowing explicit conversion of a text @@ -3899,7 +3870,7 @@ Parser: "pg_catalog.default" - For comparison, the &productname; 8.1 documentation + For comparison, the PostgreSQL 8.1 documentation contained 10,441 unique words, a total of 335,420 words, and the most frequent word postgresql was mentioned 6,127 times in 655 documents. @@ -3907,7 +3878,7 @@ Parser: "pg_catalog.default" - Another example — the &productname; mailing + Another example — the PostgreSQL mailing list archives contained 910,989 unique words with 57,491,343 lexemes in 461,020 messages. diff --git a/doc/src/sgml/tsearch2.sgml b/doc/src/sgml/tsearch2.sgml index b786cc8977..192eccd732 100644 --- a/doc/src/sgml/tsearch2.sgml +++ b/doc/src/sgml/tsearch2.sgml @@ -11,7 +11,7 @@ The tsearch2 module provides backwards-compatible text search functionality for applications that used tsearch2 before text searching was integrated - into core &productname; in release 8.3. + into core PostgreSQL in release 8.3. @@ -99,7 +99,7 @@ The replacement tsearch2 module offers a little bit of support for this by making it possible to load an old set of tsearch2 configuration tables into - &productname; 8.3. (Without the module, + PostgreSQL 8.3. (Without the module, it is not possible to load the configuration data because values in the regprocedure columns cannot be resolved to functions.) While those configuration tables won't actually do diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml index 68a322f570..69d8c0ae8b 100644 --- a/doc/src/sgml/user-manag.sgml +++ b/doc/src/sgml/user-manag.sgml @@ -16,7 +16,7 @@ The concept of roles subsumes the concepts of users and - groups. In &productname; versions + groups. In PostgreSQL versions before 8.1, users and groups were distinct kinds of entities, but now there are only roles. Any role can act as a user, a group, or both. @@ -380,8 +380,8 @@ RESET ROLE; giving roles being used as SQL users the NOINHERIT attribute. However, &productname; defaults to giving all roles the INHERIT attribute, for backward compatibility with pre-8.1 - releases in which users always had use of permissions granted to groups - they were members of. + releases of PostgreSQL in which users always + had use of permissions granted to groups they were members of. diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index 7521bbdb74..5d53a0ed79 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -225,7 +225,7 @@ INSERT INTO $1 VALUES (42); The ability to use names to reference SQL function arguments was added - in &productname; 9.2. Functions to be used in + in PostgreSQL 9.2. Functions to be used in older servers must use the $n notation. @@ -1706,7 +1706,7 @@ CREATE FUNCTION square_root(double precision) RETURNS double precision This allows the server to detect obvious incompatibilities, such as code compiled for a different major version of &productname;. A magic block is required as of - &productname; 8.2. To include a magic block, + PostgreSQL 8.2. To include a magic block, write this in one (and only one) of the module source files, after having included the header fmgr.h: @@ -1717,7 +1717,7 @@ PG_MODULE_MAGIC; The #ifdef test can be omitted if the code doesn't - need to compile against pre-8.2 &productname; + need to compile against pre-8.2 PostgreSQL releases. diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index 03823b6139..b8080de67c 100644 --- a/doc/src/sgml/xindex.sgml +++ b/doc/src/sgml/xindex.sgml @@ -1151,7 +1151,7 @@ ALTER OPERATOR FAMILY integer_ops USING btree ADD - In &productname; versions before 7.4, + In PostgreSQL versions before 7.4, sorting and grouping operations would implicitly use operators named =, <, and >. The new behavior of relying on default operator classes avoids having to make diff --git a/doc/src/sgml/xml2.sgml b/doc/src/sgml/xml2.sgml index 88c2f0e2bd..232c190571 100644 --- a/doc/src/sgml/xml2.sgml +++ b/doc/src/sgml/xml2.sgml @@ -16,7 +16,7 @@ Deprecation Notice - From &productname; 8.3 on, there is XML-related + From PostgreSQL 8.3 on, there is XML-related functionality based on the SQL/XML standard in the core server. That functionality covers XML syntax checking and XPath queries, which is what this module does, and more, but the API is @@ -62,7 +62,7 @@ This parses the document text in its parameter and returns true if the - document is well-formed XML. (Note: before &productname; 8.2, this + document is well-formed XML. (Note: before PostgreSQL 8.2, this function was called xml_valid(). That is the wrong name since validity and well-formedness have different meanings in XML. The old name is still available, but is deprecated.) diff --git a/src/Makefile b/src/Makefile index d66a55b110..1108f33ca8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -26,6 +26,7 @@ SUBDIRS = \ pl \ makefiles \ test/regress \ + test/perl \ pgpro-upgrade # There are too many interdependencies between the subdirectories, so diff --git a/src/Makefile.shlib b/src/Makefile.shlib index 86db52fe5e..924d21f443 100644 --- a/src/Makefile.shlib +++ b/src/Makefile.shlib @@ -338,7 +338,16 @@ endif else # PORTNAME == aix # AIX case -$(shlib) $(stlib): $(OBJS) | $(SHLIB_PREREQS) + +# There is no correct way to write a rule that generates two files. +# Rules with two targets don't have that meaning, they are merely +# shorthand for two otherwise separate rules. To be safe for parallel +# make, we must chain the dependencies like this. The semicolon is +# important, otherwise make will choose some built-in rule. + +$(stlib): $(shlib) ; + +$(shlib): $(OBJS) | $(SHLIB_PREREQS) rm -f $(stlib) $(LINK.static) $(stlib) $^ $(RANLIB) $(stlib) diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index feac59d9e0..93f2d8f350 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -86,7 +86,7 @@ typedef struct char action; ItemPointerData *modifieditems; - int nmodifieditems; + uint16 nmodifieditems; /* * The following fields represent the items in this segment. If 'items' is diff --git a/src/backend/access/gist/gistproc.c b/src/backend/access/gist/gistproc.c index 22ae31c0f8..e68d989023 100644 --- a/src/backend/access/gist/gistproc.c +++ b/src/backend/access/gist/gistproc.c @@ -17,20 +17,31 @@ */ #include "postgres.h" +#include + #include "access/gist.h" #include "access/stratnum.h" +#include "utils/builtins.h" #include "utils/geo_decls.h" static bool gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy); -static double size_box(BOX *box); static bool rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy); /* Minimum accepted ratio of split */ #define LIMIT_RATIO 0.3 +/* Convenience macros for NaN-aware comparisons */ +#define FLOAT8_EQ(a,b) (float8_cmp_internal(a, b) == 0) +#define FLOAT8_LT(a,b) (float8_cmp_internal(a, b) < 0) +#define FLOAT8_LE(a,b) (float8_cmp_internal(a, b) <= 0) +#define FLOAT8_GT(a,b) (float8_cmp_internal(a, b) > 0) +#define FLOAT8_GE(a,b) (float8_cmp_internal(a, b) >= 0) +#define FLOAT8_MAX(a,b) (FLOAT8_GT(a, b) ? (a) : (b)) +#define FLOAT8_MIN(a,b) (FLOAT8_LT(a, b) ? (a) : (b)) + /************************************************** * Box ops @@ -40,12 +51,53 @@ static bool rtree_internal_consistent(BOX *key, BOX *query, * Calculates union of two boxes, a and b. The result is stored in *n. */ static void -rt_box_union(BOX *n, BOX *a, BOX *b) +rt_box_union(BOX *n, const BOX *a, const BOX *b) +{ + n->high.x = FLOAT8_MAX(a->high.x, b->high.x); + n->high.y = FLOAT8_MAX(a->high.y, b->high.y); + n->low.x = FLOAT8_MIN(a->low.x, b->low.x); + n->low.y = FLOAT8_MIN(a->low.y, b->low.y); +} + +/* + * Size of a BOX for penalty-calculation purposes. + * The result can be +Infinity, but not NaN. + */ +static double +size_box(const BOX *box) +{ + /* + * Check for zero-width cases. Note that we define the size of a zero- + * by-infinity box as zero. It's important to special-case this somehow, + * as naively multiplying infinity by zero will produce NaN. + * + * The less-than cases should not happen, but if they do, say "zero". + */ + if (FLOAT8_LE(box->high.x, box->low.x) || + FLOAT8_LE(box->high.y, box->low.y)) + return 0.0; + + /* + * We treat NaN as larger than +Infinity, so any distance involving a NaN + * and a non-NaN is infinite. Note the previous check eliminated the + * possibility that the low fields are NaNs. + */ + if (isnan(box->high.x) || isnan(box->high.y)) + return get_float8_infinity(); + return (box->high.x - box->low.x) * (box->high.y - box->low.y); +} + +/* + * Return amount by which the union of the two boxes is larger than + * the original BOX's area. The result can be +Infinity, but not NaN. + */ +static double +box_penalty(const BOX *original, const BOX *new) { - n->high.x = Max(a->high.x, b->high.x); - n->high.y = Max(a->high.y, b->high.y); - n->low.x = Min(a->low.x, b->low.x); - n->low.y = Min(a->low.y, b->low.y); + BOX unionbox; + + rt_box_union(&unionbox, original, new); + return size_box(&unionbox) - size_box(original); } /* @@ -85,16 +137,19 @@ gist_box_consistent(PG_FUNCTION_ARGS) strategy)); } +/* + * Increase BOX b to include addon. + */ static void -adjustBox(BOX *b, BOX *addon) +adjustBox(BOX *b, const BOX *addon) { - if (b->high.x < addon->high.x) + if (FLOAT8_LT(b->high.x, addon->high.x)) b->high.x = addon->high.x; - if (b->low.x > addon->low.x) + if (FLOAT8_GT(b->low.x, addon->low.x)) b->low.x = addon->low.x; - if (b->high.y < addon->high.y) + if (FLOAT8_LT(b->high.y, addon->high.y)) b->high.y = addon->high.y; - if (b->low.y > addon->low.y) + if (FLOAT8_GT(b->low.y, addon->low.y)) b->low.y = addon->low.y; } @@ -174,10 +229,8 @@ gist_box_penalty(PG_FUNCTION_ARGS) float *result = (float *) PG_GETARG_POINTER(2); BOX *origbox = DatumGetBoxP(origentry->key); BOX *newbox = DatumGetBoxP(newentry->key); - BOX unionbox; - rt_box_union(&unionbox, origbox, newbox); - *result = (float) (size_box(&unionbox) - size_box(origbox)); + *result = (float) box_penalty(origbox, newbox); PG_RETURN_POINTER(result); } @@ -290,12 +343,7 @@ interval_cmp_lower(const void *i1, const void *i2) double lower1 = ((const SplitInterval *) i1)->lower, lower2 = ((const SplitInterval *) i2)->lower; - if (lower1 < lower2) - return -1; - else if (lower1 > lower2) - return 1; - else - return 0; + return float8_cmp_internal(lower1, lower2); } /* @@ -307,16 +355,11 @@ interval_cmp_upper(const void *i1, const void *i2) double upper1 = ((const SplitInterval *) i1)->upper, upper2 = ((const SplitInterval *) i2)->upper; - if (upper1 < upper2) - return -1; - else if (upper1 > upper2) - return 1; - else - return 0; + return float8_cmp_internal(upper1, upper2); } /* - * Replace negative value with zero. + * Replace negative (or NaN) value with zero. */ static inline float non_negative(float val) @@ -435,25 +478,9 @@ g_box_consider_split(ConsiderSplitContext *context, int dimNum, } } -/* - * Return increase of original BOX area by new BOX area insertion. - */ -static double -box_penalty(BOX *original, BOX *new) -{ - double union_width, - union_height; - - union_width = Max(original->high.x, new->high.x) - - Min(original->low.x, new->low.x); - union_height = Max(original->high.y, new->high.y) - - Min(original->low.y, new->low.y); - return union_width * union_height - (original->high.x - original->low.x) * - (original->high.y - original->low.y); -} - /* * Compare common entries by their deltas. + * (We assume the deltas can't be NaN.) */ static int common_entry_cmp(const void *i1, const void *i2) @@ -615,9 +642,11 @@ gist_box_picksplit(PG_FUNCTION_ARGS) /* * Find next lower bound of right group. */ - while (i1 < nentries && rightLower == intervalsLower[i1].lower) + while (i1 < nentries && + FLOAT8_EQ(rightLower, intervalsLower[i1].lower)) { - leftUpper = Max(leftUpper, intervalsLower[i1].upper); + if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper)) + leftUpper = intervalsLower[i1].upper; i1++; } if (i1 >= nentries) @@ -628,7 +657,8 @@ gist_box_picksplit(PG_FUNCTION_ARGS) * Find count of intervals which anyway should be placed to the * left group. */ - while (i2 < nentries && intervalsUpper[i2].upper <= leftUpper) + while (i2 < nentries && + FLOAT8_LE(intervalsUpper[i2].upper, leftUpper)) i2++; /* @@ -650,9 +680,10 @@ gist_box_picksplit(PG_FUNCTION_ARGS) /* * Find next upper bound of left group. */ - while (i2 >= 0 && leftUpper == intervalsUpper[i2].upper) + while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper)) { - rightLower = Min(rightLower, intervalsUpper[i2].lower); + if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower)) + rightLower = intervalsUpper[i2].lower; i2--; } if (i2 < 0) @@ -663,7 +694,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS) * Find count of intervals which anyway should be placed to the * right group. */ - while (i1 >= 0 && intervalsLower[i1].lower >= rightLower) + while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower)) i1--; /* @@ -751,10 +782,10 @@ gist_box_picksplit(PG_FUNCTION_ARGS) upper = box->high.y; } - if (upper <= context.leftUpper) + if (FLOAT8_LE(upper, context.leftUpper)) { /* Fits to the left group */ - if (lower >= context.rightLower) + if (FLOAT8_GE(lower, context.rightLower)) { /* Fits also to the right group, so "common entry" */ commonEntries[commonEntriesCount++].index = i; @@ -772,7 +803,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS) * entry didn't fit on the left group, it better fit in the right * group. */ - Assert(lower >= context.rightLower); + Assert(FLOAT8_GE(lower, context.rightLower)); /* Doesn't fit to the left group, so join to the right group */ PLACE_RIGHT(box, i); @@ -856,8 +887,10 @@ gist_box_same(PG_FUNCTION_ARGS) bool *result = (bool *) PG_GETARG_POINTER(2); if (b1 && b2) - *result = (b1->low.x == b2->low.x && b1->low.y == b2->low.y && - b1->high.x == b2->high.x && b1->high.y == b2->high.y); + *result = (FLOAT8_EQ(b1->low.x, b2->low.x) && + FLOAT8_EQ(b1->low.y, b2->low.y) && + FLOAT8_EQ(b1->high.x, b2->high.x) && + FLOAT8_EQ(b1->high.y, b2->high.y)); else *result = (b1 == NULL && b2 == NULL); PG_RETURN_POINTER(result); @@ -943,14 +976,6 @@ gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy) return retval; } -static double -size_box(BOX *box) -{ - if (box->high.x <= box->low.x || box->high.y <= box->low.y) - return 0.0; - return (box->high.x - box->low.x) * (box->high.y - box->low.y); -} - /***************************************** * Common rtree functions (for boxes, polygons, and circles) *****************************************/ diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index ee3289ae8e..62f1fdd8da 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -126,7 +126,7 @@ gistrescan(PG_FUNCTION_ARGS) * which is created on the second call and reset on later calls. Thus, in * the common case where a scan is only rescan'd once, we just put the * queue in scanCxt and don't pay the overhead of making a second memory - * context. If we do rescan more than once, the first RBTree is just left + * context. If we do rescan more than once, the first queue is just left * for dead until end of scan; this small wastage seems worth the savings * in the common case. */ @@ -186,7 +186,7 @@ gistrescan(PG_FUNCTION_ARGS) ALLOCSET_DEFAULT_MAXSIZE); } - /* create new, empty RBTree for search queue */ + /* create new, empty pairing heap for search queue */ oldCxt = MemoryContextSwitchTo(so->queueCxt); so->queue = pairingheap_allocate(pairingheap_GISTSearchItem_cmp, scan); MemoryContextSwitchTo(oldCxt); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 540c7ec060..0e268f16af 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -3112,7 +3112,7 @@ heap_delete(Relation relation, ItemPointer tid, Assert(!HeapTupleHasExternal(&tp)); } else if (HeapTupleHasExternal(&tp)) - toast_delete(relation, &tp); + toast_delete(relation, &tp, false); /* * Mark tuple for invalidation from system caches at next command @@ -3232,8 +3232,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, newbuf, vmbuffer = InvalidBuffer, vmbuffer_new = InvalidBuffer; - bool need_toast, - already_marked; + bool need_toast; Size newtupsize, pagefree; bool have_tuple_lock = false; @@ -3580,6 +3579,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, ReleaseBuffer(vmbuffer); bms_free(hot_attrs); bms_free(key_attrs); + bms_free(id_attrs); return result; } @@ -3675,8 +3675,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, * on the same page as the old, then we need to release the content lock * (but not the pin!) on the old tuple's buffer while we are off doing * TOAST and/or table-file-extension work. We must mark the old tuple to - * show that it's already being updated, else other processes may try to - * update it themselves. + * show that it's locked, else other processes may try to update it + * themselves. * * We need to invoke the toaster if there are already any out-of-line * toasted values present, or if the new tuple is over-threshold. @@ -3700,19 +3700,73 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, if (need_toast || newtupsize > pagefree) { + TransactionId xmax_lock_old_tuple; + uint16 infomask_lock_old_tuple, + infomask2_lock_old_tuple; + + /* + * To prevent concurrent sessions from updating the tuple, we have to + * temporarily mark it locked, while we release the lock. + * + * To satisfy the rule that any xid potentially appearing in a buffer + * written out to disk, we unfortunately have to WAL log this + * temporary modification. We can reuse xl_heap_lock for this + * purpose. If we crash/error before following through with the + * actual update, xmax will be of an aborted transaction, allowing + * other sessions to proceed. + */ + + /* + * Compute xmax / infomask appropriate for locking the tuple. This has + * to be done separately from the lock, because the potentially + * created multixact would otherwise be wrong. + */ + compute_new_xmax_infomask(HeapTupleHeaderGetRawXmax(oldtup.t_data), + oldtup.t_data->t_infomask, + oldtup.t_data->t_infomask2, + xid, *lockmode, false, + &xmax_lock_old_tuple, &infomask_lock_old_tuple, + &infomask2_lock_old_tuple); + + Assert(HEAP_XMAX_IS_LOCKED_ONLY(infomask_lock_old_tuple)); + + START_CRIT_SECTION(); + /* Clear obsolete visibility flags ... */ oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; HeapTupleClearHotUpdated(&oldtup); /* ... and store info about transaction updating this tuple */ - Assert(TransactionIdIsValid(xmax_old_tuple)); - HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple); - oldtup.t_data->t_infomask |= infomask_old_tuple; - oldtup.t_data->t_infomask2 |= infomask2_old_tuple; + Assert(TransactionIdIsValid(xmax_lock_old_tuple)); + HeapTupleHeaderSetXmax(oldtup.t_data, xmax_lock_old_tuple); + oldtup.t_data->t_infomask |= infomask_lock_old_tuple; + oldtup.t_data->t_infomask2 |= infomask2_lock_old_tuple; HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); - /* temporarily make it look not-updated */ + + /* temporarily make it look not-updated, but locked */ oldtup.t_data->t_ctid = oldtup.t_self; - already_marked = true; + + MarkBufferDirty(buffer); + + if (RelationNeedsWAL(relation)) + { + xl_heap_lock xlrec; + XLogRecPtr recptr; + + XLogBeginInsert(); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + + xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self); + xlrec.locking_xid = xmax_lock_old_tuple; + xlrec.infobits_set = compute_infobits(oldtup.t_data->t_infomask, + oldtup.t_data->t_infomask2); + XLogRegisterData((char *) &xlrec, SizeOfHeapLock); + recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK); + PageSetLSN(page, recptr); + } + + END_CRIT_SECTION(); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); /* @@ -3783,7 +3837,6 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, else { /* No TOAST work needed, and it'll fit on same page */ - already_marked = false; newbuf = buffer; heaptup = newtup; } @@ -3870,18 +3923,16 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, RelationPutHeapTuple(relation, newbuf, heaptup, false); /* insert new tuple */ - if (!already_marked) - { - /* Clear obsolete visibility flags ... */ - oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); - oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; - /* ... and store info about transaction updating this tuple */ - Assert(TransactionIdIsValid(xmax_old_tuple)); - HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple); - oldtup.t_data->t_infomask |= infomask_old_tuple; - oldtup.t_data->t_infomask2 |= infomask2_old_tuple; - HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); - } + + /* Clear obsolete visibility flags, possibly set by ourselves above... */ + oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); + oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED; + /* ... and store info about transaction updating this tuple */ + Assert(TransactionIdIsValid(xmax_old_tuple)); + HeapTupleHeaderSetXmax(oldtup.t_data, xmax_old_tuple); + oldtup.t_data->t_infomask |= infomask_old_tuple; + oldtup.t_data->t_infomask2 |= infomask2_old_tuple; + HeapTupleHeaderSetCmax(oldtup.t_data, cid, iscombo); /* record address of new tuple in t_ctid of old one */ oldtup.t_data->t_ctid = heaptup->t_self; @@ -3981,6 +4032,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, bms_free(hot_attrs); bms_free(key_attrs); + bms_free(id_attrs); return HeapTupleMayBeUpdated; } @@ -4317,7 +4369,7 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, */ return HeapTupleInvisible; } - else if (result == HeapTupleBeingUpdated) + else if (result == HeapTupleBeingUpdated || result == HeapTupleUpdated) { TransactionId xwait; uint16 infomask; @@ -4577,12 +4629,22 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, } /* + * Time to sleep on the other transaction/multixact, if necessary. + * + * If the other transaction is an update that's already committed, + * then sleeping cannot possibly do any good: if we're required to + * sleep, get out to raise an error instead. + * * By here, we either have already acquired the buffer exclusive lock, * or we must wait for the locking transaction or multixact; so below * we ensure that we grab buffer lock after the sleep. */ - - if (require_sleep) + if (require_sleep && result == HeapTupleUpdated) + { + LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); + goto failed; + } + else if (require_sleep) { /* * Acquire tuple lock to establish our priority for the tuple, or @@ -5341,6 +5403,17 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, return HeapTupleMayBeUpdated; } + /* + * Also check Xmin: if this tuple was created by an aborted + * (sub)transaction, then we already locked the last live one in the + * chain, thus we're done, so return success. + */ + if (TransactionIdDidAbort(HeapTupleHeaderGetXmin(mytup.t_data))) + { + UnlockReleaseBuffer(buf); + return HeapTupleMayBeUpdated; + } + old_infomask = mytup.t_data->t_infomask; old_infomask2 = mytup.t_data->t_infomask2; xmax = HeapTupleHeaderGetRawXmax(mytup.t_data); @@ -5663,7 +5736,8 @@ heap_finish_speculative(Relation relation, HeapTuple tuple) * could deadlock with each other, which would not be acceptable. * * This is somewhat redundant with heap_delete, but we prefer to have a - * dedicated routine with stripped down requirements. + * dedicated routine with stripped down requirements. Note that this is also + * used to delete the TOAST tuples created during speculative insertion. * * This routine does not affect logical decoding as it only looks at * confirmation records. @@ -5707,7 +5781,7 @@ heap_abort_speculative(Relation relation, HeapTuple tuple) */ if (tp.t_data->t_choice.t_heap.t_xmin != xid) elog(ERROR, "attempted to kill a tuple inserted by another transaction"); - if (!HeapTupleHeaderIsSpeculative(tp.t_data)) + if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data))) elog(ERROR, "attempted to kill a non-speculative tuple"); Assert(!HeapTupleHeaderIsHeapOnly(tp.t_data)); @@ -5777,7 +5851,10 @@ heap_abort_speculative(Relation relation, HeapTuple tuple) LockBuffer(buffer, BUFFER_LOCK_UNLOCK); if (HeapTupleHasExternal(&tp)) - toast_delete(relation, &tp); + { + Assert(!IsToastRelation(relation)); + toast_delete(relation, &tp, true); + } /* * Never need to mark tuple for invalidation, since catalogs don't support @@ -8383,6 +8460,8 @@ heap_xlog_lock(XLogReaderState *record) htup = (HeapTupleHeader) PageGetItem(page, lp); + htup->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); + htup->t_infomask2 &= ~HEAP_KEYS_UPDATED; fix_infomask_from_infobits(xlrec->infobits_set, &htup->t_infomask, &htup->t_infomask2); @@ -8433,6 +8512,8 @@ heap_xlog_lock_updated(XLogReaderState *record) htup = (HeapTupleHeader) PageGetItem(page, lp); + htup->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); + htup->t_infomask2 &= ~HEAP_KEYS_UPDATED; fix_infomask_from_infobits(xlrec->infobits_set, &htup->t_infomask, &htup->t_infomask2); HeapTupleHeaderSetXmax(htup, xlrec->xmax); diff --git a/src/backend/access/heap/ptrack.c b/src/backend/access/heap/ptrack.c index 63c82ba822..2e26622212 100644 --- a/src/backend/access/heap/ptrack.c +++ b/src/backend/access/heap/ptrack.c @@ -355,7 +355,7 @@ SetPtrackClearLSN(bool set_invalid) ptr = InvalidXLogRecPtr; else ptr = GetXLogInsertRecPtr(); - //LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); + /* LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); */ fd = BasicOpenFile("global/ptrack_control", O_RDWR | O_CREAT | PG_BINARY, S_IRUSR | S_IWUSR); @@ -385,7 +385,7 @@ SetPtrackClearLSN(bool set_invalid) ereport(PANIC, (errcode_for_file_access(), errmsg("could not close ptrack control file: %m"))); - //LWLockRelease(ControlFileLock); + /* LWLockRelease(ControlFileLock); */ } /* Test ptrack file */ diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index b9691a57be..f989f9577d 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -66,7 +66,7 @@ typedef struct toast_compress_header #define TOAST_COMPRESS_SET_RAWSIZE(ptr, len) \ (((toast_compress_header *) (ptr))->rawsize = (len)) -static void toast_delete_datum(Relation rel, Datum value); +static void toast_delete_datum(Relation rel, Datum value, bool is_speculative); static Datum toast_save_datum(Relation rel, Datum value, struct varlena * oldexternal, int options); static bool toastrel_valueid_exists(Relation toastrel, Oid valueid); @@ -459,7 +459,7 @@ toast_datum_size(Datum value) * ---------- */ void -toast_delete(Relation rel, HeapTuple oldtup) +toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative) { TupleDesc tupleDesc; Form_pg_attribute *att; @@ -506,7 +506,7 @@ toast_delete(Relation rel, HeapTuple oldtup) if (toast_isnull[i]) continue; else if (VARATT_IS_EXTERNAL_ONDISK(PointerGetDatum(value))) - toast_delete_datum(rel, value); + toast_delete_datum(rel, value, is_speculative); } } } @@ -1062,7 +1062,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, if (need_delold) for (i = 0; i < numAttrs; i++) if (toast_delold[i]) - toast_delete_datum(rel, toast_oldvalues[i]); + toast_delete_datum(rel, toast_oldvalues[i], false); return result_tuple; } @@ -1654,7 +1654,7 @@ toast_save_datum(Relation rel, Datum value, * ---------- */ static void -toast_delete_datum(Relation rel, Datum value) +toast_delete_datum(Relation rel, Datum value, bool is_speculative) { struct varlena *attr = (struct varlena *) DatumGetPointer(value); struct varatt_external toast_pointer; @@ -1703,7 +1703,10 @@ toast_delete_datum(Relation rel, Datum value) /* * Have a chunk, delete it */ - simple_heap_delete(toastrel, &toasttup->t_self); + if (is_speculative) + heap_abort_speculative(toastrel, toasttup); + else + simple_heap_delete(toastrel, &toasttup->t_self); } /* diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index a053ac997e..af6cfa1772 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -157,7 +157,8 @@ IndexScanEnd(IndexScanDesc scan) * * Construct a string describing the contents of an index entry, in the * form "(key_name, ...)=(key_value, ...)". This is currently used - * for building unique-constraint and exclusion-constraint error messages. + * for building unique-constraint and exclusion-constraint error messages, + * so only key columns of index are checked and printed. * * Note that if the user does not have permissions to view all of the * columns involved then a NULL is returned. Returning a partial key seems @@ -183,7 +184,6 @@ BuildIndexValueDescription(Relation indexRelation, AclResult aclresult; indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation); - /* * Check permissions- if the user does not have access to view all of the * key columns then return NULL to avoid leaking data. diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 5e9b9753ac..d1cfd012f5 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -1982,7 +1982,6 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf) itemid = PageGetItemId(lpage, P_HIKEY); right_item_sz = ItemIdGetLength(itemid); item = (IndexTuple) PageGetItem(lpage, itemid); - right_item = CopyIndexTuple(item); ItemPointerSet(&(right_item->t_tid), rbkno, P_HIKEY); diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index a4e5818579..750ead2875 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -1286,7 +1286,7 @@ _bt_pagedel(Relation rel, Buffer buf) { if (!_bt_unlink_halfdead_page(rel, buf, &rightsib_empty)) { - _bt_relbuf(rel, buf); + /* _bt_unlink_halfdead_page already released buffer */ return ndeleted; } ndeleted++; @@ -1503,6 +1503,11 @@ _bt_mark_page_halfdead(Relation rel, Buffer leafbuf, BTStack stack) * Returns 'false' if the page could not be unlinked (shouldn't happen). * If the (new) right sibling of the page is empty, *rightsib_empty is set * to true. + * + * Must hold pin and lock on leafbuf at entry (read or write doesn't matter). + * On success exit, we'll be holding pin and write lock. On failure exit, + * we'll release both pin and lock before returning (we define it that way + * to avoid having to reacquire a lock we already released). */ static bool _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty) @@ -1545,11 +1550,13 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty) /* * If the leaf page still has a parent pointing to it (or a chain of * parents), we don't unlink the leaf page yet, but the topmost remaining - * parent in the branch. + * parent in the branch. Set 'target' and 'buf' to reference the page + * actually being unlinked. */ if (ItemPointerIsValid(leafhikey)) { target = ItemPointerGetBlockNumber(leafhikey); + Assert(target != leafblkno); /* fetch the block number of the topmost parent's left sibling */ buf = _bt_getbuf(rel, target, BT_READ); @@ -1569,7 +1576,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty) target = leafblkno; buf = leafbuf; - leftsib = opaque->btpo_prev; + leftsib = leafleftsib; targetlevel = 0; } @@ -1600,8 +1607,20 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, bool *rightsib_empty) _bt_relbuf(rel, lbuf); if (leftsib == P_NONE) { - elog(LOG, "no left sibling (concurrent deletion?) in \"%s\"", + elog(LOG, "no left sibling (concurrent deletion?) of block %u in \"%s\"", + target, RelationGetRelationName(rel)); + if (target != leafblkno) + { + /* we have only a pin on target, but pin+lock on leafbuf */ + ReleaseBuffer(buf); + _bt_relbuf(rel, leafbuf); + } + else + { + /* we have only a pin on leafbuf */ + ReleaseBuffer(leafbuf); + } return false; } lbuf = _bt_getbuf(rel, leftsib, BT_WRITE); diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index e7fa33575d..3bdbe757ae 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -431,8 +431,6 @@ _bt_compare(Relation rel, itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum)); - Assert (keysz <= rel->rd_index->indnkeyatts); - /* * The scan key is set up with the attribute number associated with each * term in the key. It is important that, if the index is multi-key, the diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 61bac2cd22..7ca74974ed 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -580,15 +580,12 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, IndexTuple itup) * Save a copy of the minimum key for the new page. We have to copy * it off the old page, not the new one, in case we are not at leaf * level. - * If tuple contains non-key attributes, truncate them. - * We perform truncation only for leaf pages, - * beacuse all tuples at inner pages will be already - * truncated by the time we handle them. + * Despite oitup is already initialized, it's important to get high + * key from the page, since we could have replaced it with truncated + * copy. See comment above. */ - if (indnkeyatts != indnatts && P_ISLEAF(opageop)) - state->btps_minkey = index_truncate_tuple(wstate->index, oitup); - else - state->btps_minkey = CopyIndexTuple(oitup); + oitup = (IndexTuple) PageGetItem(opage,PageGetItemId(opage, P_HIKEY)); + state->btps_minkey = CopyIndexTuple(oitup); /* * Set the sibling links for both pages. diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index ca1d849483..88e30c1aad 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -64,7 +64,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup) { ScanKey skey; TupleDesc itupdesc; - int indnatts, + int indnatts, indnkeyatts; int16 *indoption; int i; @@ -125,7 +125,7 @@ ScanKey _bt_mkscankey_nodata(Relation rel) { ScanKey skey; - int indnkeyatts; + int indnkeyatts; int16 *indoption; int i; diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c index 1e0eb10c86..3a6047f76a 100644 --- a/src/backend/access/transam/parallel.c +++ b/src/backend/access/transam/parallel.c @@ -14,9 +14,9 @@ #include "postgres.h" +#include "access/parallel.h" #include "access/xact.h" #include "access/xlog.h" -#include "access/parallel.h" #include "commands/async.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" @@ -33,6 +33,7 @@ #include "utils/resowner.h" #include "utils/snapmgr.h" + /* * We don't want to waste a lot of memory on an error queue which, most of * the time, will process only a handful of small messages. However, it is @@ -90,7 +91,7 @@ typedef struct FixedParallelState int ParallelWorkerNumber = -1; /* Is there a parallel message pending which we need to receive? */ -bool ParallelMessagePending = false; +volatile bool ParallelMessagePending = false; /* Are we initializing a parallel worker? */ bool InitializingParallelWorker = false; @@ -102,11 +103,12 @@ static FixedParallelState *MyFixedParallelState; static dlist_head pcxt_list = DLIST_STATIC_INIT(pcxt_list); /* Private functions. */ -static void HandleParallelMessage(ParallelContext *, int, StringInfo msg); +static void HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg); static void ParallelErrorContext(void *arg); static void ParallelExtensionTrampoline(dsm_segment *seg, shm_toc *toc); static void ParallelWorkerMain(Datum main_arg); + /* * Establish a new parallel context. This should be done after entering * parallel mode, and (unless there is an error) the context should be @@ -178,8 +180,8 @@ CreateParallelContextForExternalFunction(char *library_name, /* * Establish the dynamic shared memory segment for a parallel context and - * copied state and other bookkeeping information that will need by parallel - * workers into it. + * copy state and other bookkeeping information that will be needed by + * parallel workers into it. */ void InitializeParallelDSM(ParallelContext *pcxt) @@ -231,7 +233,8 @@ InitializeParallelDSM(ParallelContext *pcxt) PARALLEL_ERROR_QUEUE_SIZE, "parallel error queue size not buffer-aligned"); shm_toc_estimate_chunk(&pcxt->estimator, - PARALLEL_ERROR_QUEUE_SIZE * pcxt->nworkers); + mul_size(PARALLEL_ERROR_QUEUE_SIZE, + pcxt->nworkers)); shm_toc_estimate_keys(&pcxt->estimator, 1); /* Estimate how much we'll need for extension entrypoint info. */ @@ -257,7 +260,7 @@ InitializeParallelDSM(ParallelContext *pcxt) * parallelism than to fail outright. */ segsize = shm_toc_estimate(&pcxt->estimator); - if (pcxt->nworkers != 0) + if (pcxt->nworkers > 0) pcxt->seg = dsm_create(segsize, DSM_CREATE_NULL_IF_MAXSEGMENTS); if (pcxt->seg != NULL) pcxt->toc = shm_toc_create(PARALLEL_MAGIC, @@ -337,7 +340,8 @@ InitializeParallelDSM(ParallelContext *pcxt) */ error_queue_space = shm_toc_allocate(pcxt->toc, - PARALLEL_ERROR_QUEUE_SIZE * pcxt->nworkers); + mul_size(PARALLEL_ERROR_QUEUE_SIZE, + pcxt->nworkers)); for (i = 0; i < pcxt->nworkers; ++i) { char *start; @@ -603,17 +607,17 @@ ParallelContextActive(void) /* * Handle receipt of an interrupt indicating a parallel worker message. + * + * Note: this is called within a signal handler! All we can do is set + * a flag that will cause the next CHECK_FOR_INTERRUPTS() to invoke + * HandleParallelMessages(). */ void HandleParallelMessageInterrupt(void) { - int save_errno = errno; - InterruptPending = true; ParallelMessagePending = true; SetLatch(MyLatch); - - errno = save_errno; } /* @@ -623,15 +627,42 @@ void HandleParallelMessages(void) { dlist_iter iter; + MemoryContext oldcontext; + static MemoryContext hpm_context = NULL; + + /* + * This is invoked from ProcessInterrupts(), and since some of the + * functions it calls contain CHECK_FOR_INTERRUPTS(), there is a potential + * for recursive calls if more signals are received while this runs. It's + * unclear that recursive entry would be safe, and it doesn't seem useful + * even if it is safe, so let's block interrupts until done. + */ + HOLD_INTERRUPTS(); + + /* + * Moreover, CurrentMemoryContext might be pointing almost anywhere. We + * don't want to risk leaking data into long-lived contexts, so let's do + * our work here in a private context that we can reset on each use. + */ + if (hpm_context == NULL) /* first time through? */ + hpm_context = AllocSetContextCreate(TopMemoryContext, + "HandleParallelMessages context", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + else + MemoryContextReset(hpm_context); + + oldcontext = MemoryContextSwitchTo(hpm_context); + + /* OK to process messages. Reset the flag saying there are more to do. */ ParallelMessagePending = false; dlist_foreach(iter, &pcxt_list) { ParallelContext *pcxt; int i; - Size nbytes; - void *data; pcxt = dlist_container(ParallelContext, node, iter.cur); if (pcxt->worker == NULL) @@ -641,13 +672,15 @@ HandleParallelMessages(void) { /* * Read as many messages as we can from each worker, but stop when - * either (1) the error queue goes away, which can happen if we - * receive a Terminate message from the worker; or (2) no more - * messages can be read from the worker without blocking. + * either (1) the worker's error queue goes away, which can happen + * if we receive a Terminate message from the worker; or (2) no + * more messages can be read from the worker without blocking. */ while (pcxt->worker[i].error_mqh != NULL) { shm_mq_result res; + Size nbytes; + void *data; res = shm_mq_receive(pcxt->worker[i].error_mqh, &nbytes, &data, true); @@ -664,14 +697,18 @@ HandleParallelMessages(void) } else ereport(ERROR, - (errcode(ERRCODE_INTERNAL_ERROR), /* XXX: wrong errcode? */ - errmsg("lost connection to parallel worker"))); - - /* This might make the error queue go away. */ - CHECK_FOR_INTERRUPTS(); + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("lost connection to parallel worker"))); } } } + + MemoryContextSwitchTo(oldcontext); + + /* Might as well clear the context on our way out */ + MemoryContextReset(hpm_context); + + RESUME_INTERRUPTS(); } /* @@ -714,7 +751,7 @@ HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg) errctx.previous = pcxt->error_context_stack; error_context_stack = &errctx; - /* Parse ErrorReponse or NoticeResponse. */ + /* Parse ErrorResponse or NoticeResponse. */ pq_parse_errornotice(msg, &edata); /* Death of a worker isn't enough justification for suicide. */ @@ -747,7 +784,7 @@ HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg) default: { - elog(ERROR, "unknown message type: %c (%d bytes)", + elog(ERROR, "unrecognized message type received from parallel worker: %c (message length %d bytes)", msgtype, msg->len); } } @@ -847,7 +884,7 @@ ParallelWorkerMain(Datum main_arg) if (toc == NULL) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("invalid magic number in dynamic shared memory segment"))); + errmsg("invalid magic number in dynamic shared memory segment"))); /* Look up fixed parallel state. */ fps = shm_toc_lookup(toc, PARALLEL_KEY_FIXED); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index af06fcda65..c29689fbcd 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4980,7 +4980,8 @@ readRecoveryCommandFile(void) rtli = (TimeLineID) strtoul(item->value, NULL, 0); if (errno == EINVAL || errno == ERANGE) ereport(FATAL, - (errmsg("recovery_target_timeline is not a valid number: \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery_target_timeline is not a valid number: \"%s\"", item->value))); } if (rtli) @@ -4996,7 +4997,8 @@ readRecoveryCommandFile(void) recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0); if (errno == EINVAL || errno == ERANGE) ereport(FATAL, - (errmsg("recovery_target_xid is not a valid number: \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery_target_xid is not a valid number: \"%s\"", item->value))); ereport(DEBUG2, (errmsg_internal("recovery_target_xid = %u", @@ -5111,7 +5113,8 @@ readRecoveryCommandFile(void) } else ereport(FATAL, - (errmsg("unrecognized recovery parameter \"%s\"", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized recovery parameter \"%s\"", item->name))); } @@ -5130,7 +5133,8 @@ readRecoveryCommandFile(void) { if (recoveryRestoreCommand == NULL) ereport(FATAL, - (errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled", RECOVERY_COMMAND_FILE))); } @@ -5144,6 +5148,15 @@ readRecoveryCommandFile(void) !EnableHotStandby) recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN; + /* + * We don't support standby_mode in standalone backends; that requires + * other processes such as the WAL receiver to be alive. + */ + if (StandbyModeRequested && !IsUnderPostmaster) + ereport(FATAL, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("standby mode is not supported by single-user servers"))); + /* Enable fetching from archive recovery area */ ArchiveRecoveryRequested = true; @@ -5160,7 +5173,8 @@ readRecoveryCommandFile(void) /* Timeline 1 does not have a history file, all else should */ if (rtli != 1 && !existsTimeLineHistory(rtli)) ereport(FATAL, - (errmsg("recovery target timeline %u does not exist", + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("recovery target timeline %u does not exist", rtli))); recoveryTargetTLI = rtli; recoveryTargetIsLatest = false; diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index 37cf9dee80..0973d778ac 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -844,46 +844,83 @@ XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr) { XLogReaderState saved_state = *state; - XLogRecPtr targetPagePtr; XLogRecPtr tmpRecPtr; - int targetRecOff; XLogRecPtr found = InvalidXLogRecPtr; - uint32 pageHeaderSize; XLogPageHeader header; - int readLen; char *errormsg; Assert(!XLogRecPtrIsInvalid(RecPtr)); - targetRecOff = RecPtr % XLOG_BLCKSZ; + /* + * skip over potential continuation data, keeping in mind that it may span + * multiple pages + */ + tmpRecPtr = RecPtr; + while (true) + { + XLogRecPtr targetPagePtr; + int targetRecOff; + uint32 pageHeaderSize; + int readLen; - /* scroll back to page boundary */ - targetPagePtr = RecPtr - targetRecOff; + /* + * Compute targetRecOff. It should typically be equal or greater than + * short page-header since a valid record can't start anywhere before + * that, except when caller has explicitly specified the offset that + * falls somewhere there or when we are skipping multi-page + * continuation record. It doesn't matter though because + * ReadPageInternal() is prepared to handle that and will read at least + * short page-header worth of data + */ + targetRecOff = tmpRecPtr % XLOG_BLCKSZ; - /* Read the page containing the record */ - readLen = ReadPageInternal(state, targetPagePtr, targetRecOff); - if (readLen < 0) - goto err; + /* scroll back to page boundary */ + targetPagePtr = tmpRecPtr - targetRecOff; - header = (XLogPageHeader) state->readBuf; + /* Read the page containing the record */ + readLen = ReadPageInternal(state, targetPagePtr, targetRecOff); + if (readLen < 0) + goto err; - pageHeaderSize = XLogPageHeaderSize(header); + header = (XLogPageHeader) state->readBuf; - /* make sure we have enough data for the page header */ - readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize); - if (readLen < 0) - goto err; + pageHeaderSize = XLogPageHeaderSize(header); - /* skip over potential continuation data */ - if (header->xlp_info & XLP_FIRST_IS_CONTRECORD) - { - /* record headers are MAXALIGN'ed */ - tmpRecPtr = targetPagePtr + pageHeaderSize - + MAXALIGN(header->xlp_rem_len); - } - else - { - tmpRecPtr = targetPagePtr + pageHeaderSize; + /* make sure we have enough data for the page header */ + readLen = ReadPageInternal(state, targetPagePtr, pageHeaderSize); + if (readLen < 0) + goto err; + + /* skip over potential continuation data */ + if (header->xlp_info & XLP_FIRST_IS_CONTRECORD) + { + /* + * If the length of the remaining continuation data is more than + * what can fit in this page, the continuation record crosses over + * this page. Read the next page and try again. xlp_rem_len in the + * next page header will contain the remaining length of the + * continuation data + * + * Note that record headers are MAXALIGN'ed + */ + if (MAXALIGN(header->xlp_rem_len) > (XLOG_BLCKSZ - pageHeaderSize)) + tmpRecPtr = targetPagePtr + XLOG_BLCKSZ; + else + { + /* + * The previous continuation record ends in this page. Set + * tmpRecPtr to point to the first valid record + */ + tmpRecPtr = targetPagePtr + pageHeaderSize + + MAXALIGN(header->xlp_rem_len); + break; + } + } + else + { + tmpRecPtr = targetPagePtr + pageHeaderSize; + break; + } } /* diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index e44d7d09e1..179bf125c5 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -2237,23 +2237,18 @@ get_object_namespace(const ObjectAddress *address) int read_objtype_from_string(const char *objtype) { - ObjectType type; int i; for (i = 0; i < lengthof(ObjectTypeMap); i++) { if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0) - { - type = ObjectTypeMap[i].tm_type; - break; - } + return ObjectTypeMap[i].tm_type; } - if (i >= lengthof(ObjectTypeMap)) - ereport(ERROR, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized object type \"%s\"", objtype))); + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized object type \"%s\"", objtype))); - return type; + return -1; /* keep compiler quiet */ } /* diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 04b08b6377..ef0ed93ece 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -2043,8 +2043,11 @@ compute_distinct_stats(VacAttrStatsP stats, if (nmultiple == 0) { - /* If we found no repeated values, assume it's a unique column */ - stats->stadistinct = -1.0; + /* + * If we found no repeated non-null values, assume it's a unique + * column; but be sure to discount for any nulls we found. + */ + stats->stadistinct = -1.0 * (1.0 - stats->stanullfrac); } else if (track_cnt < track_max && toowide_cnt == 0 && nmultiple == track_cnt) @@ -2398,8 +2401,11 @@ compute_scalar_stats(VacAttrStatsP stats, if (nmultiple == 0) { - /* If we found no repeated values, assume it's a unique column */ - stats->stadistinct = -1.0; + /* + * If we found no repeated non-null values, assume it's a unique + * column; but be sure to discount for any nulls we found. + */ + stats->stadistinct = -1.0 * (1.0 - stats->stanullfrac); } else if (toowide_cnt == 0 && nmultiple == ndistinct) { @@ -2703,7 +2709,7 @@ compute_scalar_stats(VacAttrStatsP stats, else stats->stawidth = stats->attrtype->typlen; /* Assume all too-wide values are distinct, so it's a unique column */ - stats->stadistinct = -1.0; + stats->stadistinct = -1.0 * (1.0 - stats->stanullfrac); } else if (null_cnt > 0) { diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 5d06fa4ea6..3f5c638bb0 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -25,6 +25,7 @@ #include "optimizer/clauses.h" #include "parser/parsetree.h" #include "rewrite/rewriteHandler.h" +#include "storage/bufmgr.h" #include "tcop/tcopprot.h" #include "utils/builtins.h" #include "utils/json.h" @@ -652,15 +653,35 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es) Instrumentation *instr = rInfo->ri_TrigInstrument + nt; char *relname; char *conname = NULL; + instr_time starttimespan; + double total; + double ntuples; + double ncalls; - /* Must clean up instrumentation state */ - InstrEndLoop(instr); + if (!es->runtime) + { + /* Must clean up instrumentation state */ + InstrEndLoop(instr); + } + + /* Collect statistic variables */ + if (!INSTR_TIME_IS_ZERO(instr->starttime)) + { + INSTR_TIME_SET_CURRENT(starttimespan); + INSTR_TIME_SUBTRACT(starttimespan, instr->starttime); + } + else + INSTR_TIME_SET_ZERO(starttimespan); + total = instr->total + INSTR_TIME_GET_DOUBLE(instr->counter) + + INSTR_TIME_GET_DOUBLE(starttimespan); + ntuples = instr->ntuples + instr->tuplecount; + ncalls = ntuples + !INSTR_TIME_IS_ZERO(starttimespan); /* * We ignore triggers that were never invoked; they likely aren't * relevant to the current query type. */ - if (instr->ntuples == 0) + if (ncalls == 0) continue; ExplainOpenGroup("Trigger", NULL, true, es); @@ -684,8 +705,11 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es) appendStringInfo(es->str, " for constraint %s", conname); if (show_relname) appendStringInfo(es->str, " on %s", relname); - appendStringInfo(es->str, ": time=%.3f calls=%.0f\n", - 1000.0 * instr->total, instr->ntuples); + if (es->timing) + appendStringInfo(es->str, ": time=%.3f calls=%.0f\n", + 1000.0 * total, ncalls); + else + appendStringInfo(es->str, ": calls=%.0f\n", ncalls); } else { @@ -693,8 +717,9 @@ report_triggers(ResultRelInfo *rInfo, bool show_relname, ExplainState *es) if (conname) ExplainPropertyText("Constraint Name", conname, es); ExplainPropertyText("Relation", relname, es); - ExplainPropertyFloat("Time", 1000.0 * instr->total, 3, es); - ExplainPropertyFloat("Calls", instr->ntuples, 0, es); + if (es->timing) + ExplainPropertyFloat("Time", 1000.0 * total, 3, es); + ExplainPropertyFloat("Calls", ncalls, 0, es); } if (conname) @@ -1242,8 +1267,11 @@ ExplainNode(PlanState *planstate, List *ancestors, * instrumentation results the user didn't ask for. But we do the * InstrEndLoop call anyway, if possible, to reduce the number of cases * auto_explain has to contend with. + * + * if flag es->stateinfo is set i.e. when printing the current execution state + * this step of cleaning up is miss */ - if (planstate->instrument) + if (planstate->instrument && !es->runtime) InstrEndLoop(planstate->instrument); if (es->analyze && @@ -1276,7 +1304,7 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainPropertyFloat("Actual Loops", nloops, 0, es); } } - else if (es->analyze) + else if (es->analyze && !es->runtime) { if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoString(es->str, " (never executed)"); @@ -1292,6 +1320,75 @@ ExplainNode(PlanState *planstate, List *ancestors, } } + /* + * print the progress of node execution at current loop + */ + if (planstate->instrument && es->analyze && es->runtime) + { + instr_time starttimespan; + double startup_sec; + double total_sec; + double rows; + double loop_num; + bool finished; + + if (!INSTR_TIME_IS_ZERO(planstate->instrument->starttime)) + { + INSTR_TIME_SET_CURRENT(starttimespan); + INSTR_TIME_SUBTRACT(starttimespan, planstate->instrument->starttime); + } + else + INSTR_TIME_SET_ZERO(starttimespan); + startup_sec = 1000.0 * planstate->instrument->firsttuple; + total_sec = 1000.0 * (INSTR_TIME_GET_DOUBLE(planstate->instrument->counter) + + INSTR_TIME_GET_DOUBLE(starttimespan)); + rows = planstate->instrument->tuplecount; + loop_num = planstate->instrument->nloops + 1; + + finished = planstate->instrument->nloops > 0 + && !planstate->instrument->running + && INSTR_TIME_IS_ZERO(starttimespan); + + if (!finished) + { + ExplainOpenGroup("Current loop", "Current loop", true, es); + if (es->format == EXPLAIN_FORMAT_TEXT) + { + if (es->timing) + { + if (planstate->instrument->running) + appendStringInfo(es->str, + " (Current loop: actual time=%.3f..%.3f rows=%.0f, loop number=%.0f)", + startup_sec, total_sec, rows, loop_num); + else + appendStringInfo(es->str, + " (Current loop: running time=%.3f actual rows=0, loop number=%.0f)", + total_sec, loop_num); + } + else + appendStringInfo(es->str, + " (Current loop: actual rows=%.0f, loop number=%.0f)", + rows, loop_num); + } + else + { + ExplainPropertyFloat("Actual Loop Number", loop_num, 0, es); + if (es->timing) + { + if (planstate->instrument->running) + { + ExplainPropertyFloat("Actual Startup Time", startup_sec, 3, es); + ExplainPropertyFloat("Actual Total Time", total_sec, 3, es); + } + else + ExplainPropertyFloat("Running Time", total_sec, 3, es); + } + ExplainPropertyFloat("Actual Rows", rows, 0, es); + } + ExplainCloseGroup("Current loop", "Current loop", true, es); + } + } + /* in text format, first line ends here */ if (es->format == EXPLAIN_FORMAT_TEXT) appendStringInfoChar(es->str, '\n'); @@ -1600,8 +1697,11 @@ ExplainNode(PlanState *planstate, List *ancestors, ExplainPropertyLong("Local Written Blocks", usage->local_blks_written, es); ExplainPropertyLong("Temp Read Blocks", usage->temp_blks_read, es); ExplainPropertyLong("Temp Written Blocks", usage->temp_blks_written, es); - ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es); - ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es); + if (track_io_timing) + { + ExplainPropertyFloat("I/O Read Time", INSTR_TIME_GET_MILLISEC(usage->blk_read_time), 3, es); + ExplainPropertyFloat("I/O Write Time", INSTR_TIME_GET_MILLISEC(usage->blk_write_time), 3, es); + } } } @@ -2285,20 +2385,17 @@ show_instrumentation_count(const char *qlabel, int which, if (!es->analyze || !planstate->instrument) return; + nloops = planstate->instrument->nloops; if (which == 2) - nfiltered = planstate->instrument->nfiltered2; + nfiltered = ((nloops > 0) ? planstate->instrument->accum_nfiltered2 / nloops : 0) + + planstate->instrument->nfiltered2; else - nfiltered = planstate->instrument->nfiltered1; - nloops = planstate->instrument->nloops; + nfiltered = ((nloops > 0) ? planstate->instrument->accum_nfiltered1 / nloops : 0) + + planstate->instrument->nfiltered1; /* In text mode, suppress zero counts; they're not interesting enough */ if (nfiltered > 0 || es->format != EXPLAIN_FORMAT_TEXT) - { - if (nloops > 0) - ExplainPropertyFloat(qlabel, nfiltered / nloops, 0, es); - else - ExplainPropertyFloat(qlabel, 0.0, 0, es); - } + ExplainPropertyFloat(qlabel, nfiltered, 0, es); } /* @@ -2650,14 +2747,28 @@ show_modifytable_info(ModifyTableState *mtstate, List *ancestors, double insert_path; double other_path; - InstrEndLoop(mtstate->mt_plans[0]->instrument); + if (!es->runtime) + InstrEndLoop(mtstate->mt_plans[0]->instrument); /* count the number of source rows */ - total = mtstate->mt_plans[0]->instrument->ntuples; - other_path = mtstate->ps.instrument->nfiltered2; - insert_path = total - other_path; + other_path = mtstate->ps.instrument->accum_nfiltered2 + + mtstate->ps.instrument->nfiltered2; + + /* + * Insert occurs after extracting row from subplan and in runtime mode + * we can appear between these two operations - situation when + * total > insert_path + other_path. Therefore we don't know exactly + * whether last row from subplan is inserted. + * We don't print inserted tuples in runtime mode in order to not print + * inconsistent data + */ + if (!es->runtime) + { + total = mtstate->mt_plans[0]->instrument->ntuples; + insert_path = total - other_path; + ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es); + } - ExplainPropertyFloat("Tuples Inserted", insert_path, 0, es); ExplainPropertyFloat("Conflicting Tuples", other_path, 0, es); } } diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 24298894fa..64626edf70 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -1484,7 +1484,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) return; } - pg_usleep(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL); + pg_usleep(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL * 1000L); } /* diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c index 03c2febc3e..a33e645ceb 100644 --- a/src/backend/executor/execProcnode.c +++ b/src/backend/executor/execProcnode.c @@ -115,7 +115,6 @@ #include "executor/nodeWorktablescan.h" #include "miscadmin.h" - /* ------------------------------------------------------------------------ * ExecInitNode * @@ -356,6 +355,9 @@ ExecInitNode(Plan *node, EState *estate, int eflags) return result; } +/* Hooks for plugins to pre/post process ExecProcNode */ +PreExecProcNode_hook_type preExecProcNode_hook = NULL; +PostExecProcNode_hook_type postExecProcNode_hook = NULL; /* ---------------------------------------------------------------- * ExecProcNode @@ -374,7 +376,12 @@ ExecProcNode(PlanState *node) ExecReScan(node); /* let ReScan handle this */ if (node->instrument) + { + if (preExecProcNode_hook) + preExecProcNode_hook(node); + InstrStartNode(node->instrument); + } switch (nodeTag(node)) { @@ -527,8 +534,13 @@ ExecProcNode(PlanState *node) } if (node->instrument) + { InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0); + if (postExecProcNode_hook) + postExecProcNode_hook(node, result); + } + return result; } diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index f2e8ee2f77..a6c9b6a66b 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -2943,19 +2943,30 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, /* * If there's a test expression, we have to evaluate it and save the value - * where the CaseTestExpr placeholders can find it. We must save and + * where the CaseTestExpr placeholders can find it. We must save and * restore prior setting of econtext's caseValue fields, in case this node - * is itself within a larger CASE. + * is itself within a larger CASE. Furthermore, don't assign to the + * econtext fields until after returning from evaluation of the test + * expression. We used to pass &econtext->caseValue_isNull to the + * recursive call, but that leads to aliasing that variable within said + * call, which can (and did) produce bugs when the test expression itself + * contains a CASE. + * + * If there's no test expression, we don't actually need to save and + * restore these fields; but it's less code to just do so unconditionally. */ save_datum = econtext->caseValue_datum; save_isNull = econtext->caseValue_isNull; if (caseExpr->arg) { + bool arg_isNull; + econtext->caseValue_datum = ExecEvalExpr(caseExpr->arg, econtext, - &econtext->caseValue_isNull, + &arg_isNull, NULL); + econtext->caseValue_isNull = arg_isNull; } /* @@ -2967,10 +2978,11 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, { CaseWhenState *wclause = lfirst(clause); Datum clause_value; + bool clause_isNull; clause_value = ExecEvalExpr(wclause->expr, econtext, - isNull, + &clause_isNull, NULL); /* @@ -2978,7 +2990,7 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, * statement is satisfied. A NULL result from the test is not * considered true. */ - if (DatumGetBool(clause_value) && !*isNull) + if (DatumGetBool(clause_value) && !clause_isNull) { econtext->caseValue_datum = save_datum; econtext->caseValue_isNull = save_isNull; @@ -3793,6 +3805,21 @@ ExecEvalNullTest(NullTestState *nstate, if (ntest->argisrow && !(*isNull)) { + /* + * The SQL standard defines IS [NOT] NULL for a non-null rowtype + * argument as: + * + * "R IS NULL" is true if every field is the null value. + * + * "R IS NOT NULL" is true if no field is the null value. + * + * This definition is (apparently intentionally) not recursive; so our + * tests on the fields are primitive attisnull tests, not recursive + * checks to see if they are all-nulls or no-nulls rowtypes. + * + * The standard does not consider the possibility of zero-field rows, + * but here we consider them to vacuously satisfy both predicates. + */ HeapTupleHeader tuple; Oid tupType; int32 tupTypmod; diff --git a/src/backend/executor/instrument.c b/src/backend/executor/instrument.c index f5351eb397..591ea0f4da 100644 --- a/src/backend/executor/instrument.c +++ b/src/backend/executor/instrument.c @@ -118,6 +118,8 @@ InstrEndLoop(Instrumentation *instr) instr->total += totaltime; instr->ntuples += instr->tuplecount; instr->nloops += 1; + instr->accum_nfiltered1 += instr->nfiltered1; + instr->accum_nfiltered2 += instr->nfiltered2; /* Reset for next cycle (if any) */ instr->running = false; @@ -125,6 +127,8 @@ InstrEndLoop(Instrumentation *instr) INSTR_TIME_SET_ZERO(instr->counter); instr->firsttuple = 0; instr->tuplecount = 0; + instr->nfiltered1 = 0; + instr->nfiltered2 = 0; } /* dst += add - sub */ diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 2bf48c54e3..4c82176671 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -2666,11 +2666,13 @@ ExecReScanAgg(AggState *node) return; /* - * If we do have the hash table and the subplan does not have any - * parameter changes, then we can just rescan the existing hash table; - * no need to build it again. + * If we do have the hash table, and the subplan does not have any + * parameter changes, and none of our own parameter changes affect + * input expressions of the aggregated functions, then we can just + * rescan the existing hash table; no need to build it again. */ - if (outerPlan->chgParam == NULL) + if (outerPlan->chgParam == NULL && + !bms_overlap(node->ss.ps.chgParam, aggnode->aggParams)) { ResetTupleHashIterator(node->hashtable, &node->hashiter); return; diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index 75c1ab3e8a..56f141c587 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -224,9 +224,13 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) { /* Not the leader */ Assert(IsA(scanstate->leader, CteScanState)); + /* Create my own read pointer, and ensure it is at start */ scanstate->readptr = tuplestore_alloc_read_pointer(scanstate->leader->cte_table, scanstate->eflags); + tuplestore_select_read_pointer(scanstate->leader->cte_table, + scanstate->readptr); + tuplestore_rescan(scanstate->leader->cte_table); } /* diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index dc039f4174..0eba31d0d0 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -2224,8 +2224,12 @@ _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, strtoul(completionTag + 7, NULL, 10); else { - /* Must be an IF NOT EXISTS that did nothing */ - Assert(ctastmt->if_not_exists); + /* + * Must be an IF NOT EXISTS that did nothing, or a + * CREATE ... WITH NO DATA. + */ + Assert(ctastmt->if_not_exists || + ctastmt->into->skipData); _SPI_current->processed = 0; } diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index dd8d2e9ff3..936a7ccae5 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -20,6 +20,9 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif #include "libpq/auth.h" #include "libpq/crypt.h" diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index f3965226d0..4901a169de 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -53,7 +53,7 @@ #include #include -#if SSLEAY_VERSION_NUMBER >= 0x0907000L +#if OPENSSL_VERSION_NUMBER >= 0x0907000L #include #endif #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH) @@ -74,6 +74,7 @@ static int my_SSL_set_fd(Port *port, int fd); static DH *load_dh_file(int keylength); static DH *load_dh_buffer(const char *, size_t); +static DH *generate_dh_parameters(int prime_len, int generator); static DH *tmp_dh_cb(SSL *s, int is_export, int keylength); static int verify_cb(int, X509_STORE_CTX *); static void info_cb(const SSL *ssl, int type, int args); @@ -166,11 +167,15 @@ be_tls_init(void) if (!SSL_context) { -#if SSLEAY_VERSION_NUMBER >= 0x0907000L +#ifdef HAVE_OPENSSL_INIT_SSL + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL); +#else +#if OPENSSL_VERSION_NUMBER >= 0x0907000L OPENSSL_config(NULL); #endif SSL_library_init(); SSL_load_error_strings(); +#endif /* * We use SSLv23_method() because it can negotiate use of the highest @@ -650,8 +655,12 @@ be_tls_write(Port *port, void *ptr, size_t len, int *waitfor) * to retry; do we need to adopt their logic for that? */ -static bool my_bio_initialized = false; -static BIO_METHOD my_bio_methods; +#ifndef HAVE_BIO_GET_DATA +#define BIO_get_data(bio) (bio->ptr) +#define BIO_set_data(bio, data) (bio->ptr = data) +#endif + +static BIO_METHOD *my_bio_methods = NULL; static int my_sock_read(BIO *h, char *buf, int size) @@ -660,7 +669,7 @@ my_sock_read(BIO *h, char *buf, int size) if (buf != NULL) { - res = secure_raw_read(((Port *) h->ptr), buf, size); + res = secure_raw_read(((Port *) BIO_get_data(h)), buf, size); BIO_clear_retry_flags(h); if (res <= 0) { @@ -680,7 +689,7 @@ my_sock_write(BIO *h, const char *buf, int size) { int res = 0; - res = secure_raw_write(((Port *) h->ptr), buf, size); + res = secure_raw_write(((Port *) BIO_get_data(h)), buf, size); BIO_clear_retry_flags(h); if (res <= 0) { @@ -697,14 +706,41 @@ my_sock_write(BIO *h, const char *buf, int size) static BIO_METHOD * my_BIO_s_socket(void) { - if (!my_bio_initialized) + if (!my_bio_methods) { - memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD)); - my_bio_methods.bread = my_sock_read; - my_bio_methods.bwrite = my_sock_write; - my_bio_initialized = true; + BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket(); +#ifdef HAVE_BIO_METH_NEW + int my_bio_index; + + my_bio_index = BIO_get_new_index(); + if (my_bio_index == -1) + return NULL; + my_bio_methods = BIO_meth_new(my_bio_index, "PostgreSQL backend socket"); + if (!my_bio_methods) + return NULL; + if (!BIO_meth_set_write(my_bio_methods, my_sock_write) || + !BIO_meth_set_read(my_bio_methods, my_sock_read) || + !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) || + !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) || + !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) || + !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) || + !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) || + !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom))) + { + BIO_meth_free(my_bio_methods); + my_bio_methods = NULL; + return NULL; + } +#else + my_bio_methods = malloc(sizeof(BIO_METHOD)); + if (!my_bio_methods) + return NULL; + memcpy(my_bio_methods, biom, sizeof(BIO_METHOD)); + my_bio_methods->bread = my_sock_read; + my_bio_methods->bwrite = my_sock_write; +#endif } - return &my_bio_methods; + return my_bio_methods; } /* This should exactly match openssl's SSL_set_fd except for using my BIO */ @@ -712,17 +748,23 @@ static int my_SSL_set_fd(Port *port, int fd) { int ret = 0; - BIO *bio = NULL; + BIO *bio; + BIO_METHOD *bio_method; - bio = BIO_new(my_BIO_s_socket()); + bio_method = my_BIO_s_socket(); + if (bio_method == NULL) + { + SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); + goto err; + } + bio = BIO_new(bio_method); if (bio == NULL) { SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB); goto err; } - /* Use 'ptr' to store pointer to PGconn */ - bio->ptr = port; + BIO_set_data(bio, port); BIO_set_fd(bio, fd, BIO_NOCLOSE); SSL_set_bio(port->ssl, bio, bio); @@ -816,6 +858,31 @@ load_dh_buffer(const char *buffer, size_t len) return dh; } +/* + * Generate DH parameters. + * + * Last resort if we can't load precomputed nor hardcoded + * parameters. + */ +static DH * +generate_dh_parameters(int prime_len, int generator) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) + DH *dh; + + if ((dh = DH_new()) == NULL) + return NULL; + + if (DH_generate_parameters_ex(dh, prime_len, generator, NULL)) + return dh; + + DH_free(dh); + return NULL; +#else + return DH_generate_parameters(prime_len, generator, NULL, NULL); +#endif +} + /* * Generate an ephemeral DH key. Because this can take a long * time to compute, we can use precomputed parameters of the @@ -885,7 +952,7 @@ tmp_dh_cb(SSL *s, int is_export, int keylength) ereport(DEBUG2, (errmsg_internal("DH: generating parameters (%d bits)", keylength))); - r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL); + r = generate_dh_parameters(keylength, DH_GENERATOR_2); } return r; diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c index 0a3c2b70cb..549e76dfa0 100644 --- a/src/backend/libpq/pqmq.c +++ b/src/backend/libpq/pqmq.c @@ -172,8 +172,8 @@ mq_putmessage(char msgtype, const char *s, size_t len) break; WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0); - CHECK_FOR_INTERRUPTS(); ResetLatch(&MyProc->procLatch); + CHECK_FOR_INTERRUPTS(); } pq_mq_busy = false; diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 34332bbfc4..3d9e29beb2 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -847,6 +847,7 @@ _copyAgg(const Agg *from) COPY_POINTER_FIELD(grpOperators, from->numCols * sizeof(Oid)); } COPY_SCALAR_FIELD(numGroups); + COPY_BITMAPSET_FIELD(aggParams); COPY_NODE_FIELD(groupingSets); COPY_NODE_FIELD(chain); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 26d70584ea..9762d00320 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -684,7 +684,7 @@ _outAgg(StringInfo str, const Agg *node) appendStringInfo(str, " %u", node->grpOperators[i]); WRITE_LONG_FIELD(numGroups); - + WRITE_BITMAPSET_FIELD(aggParams); WRITE_NODE_FIELD(groupingSets); WRITE_NODE_FIELD(chain); } diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 40f801e41c..6af68b08d2 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -4535,6 +4535,7 @@ make_agg(PlannerInfo *root, List *tlist, List *qual, node->grpColIdx = grpColIdx; node->grpOperators = grpOperators; node->numGroups = numGroups; + node->aggParams = NULL; /* SS_finalize_plan() will fill this */ copy_plan_costsize(plan, lefttree); /* only care about copying size */ cost_agg(&agg_path, root, diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 979802f70d..e400ea983c 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -81,6 +81,7 @@ static Bitmapset *finalize_plan(PlannerInfo *root, Bitmapset *valid_params, Bitmapset *scan_params); static bool finalize_primnode(Node *node, finalize_primnode_context *context); +static bool finalize_agg_primnode(Node *node, finalize_primnode_context *context); /* @@ -2558,6 +2559,29 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, locally_added_param); break; + case T_Agg: + { + Agg *agg = (Agg *) plan; + + /* + * AGG_HASHED plans need to know which Params are referenced + * in aggregate calls. Do a separate scan to identify them. + */ + if (agg->aggstrategy == AGG_HASHED) + { + finalize_primnode_context aggcontext; + + aggcontext.root = root; + aggcontext.paramids = NULL; + finalize_agg_primnode((Node *) agg->plan.targetlist, + &aggcontext); + finalize_agg_primnode((Node *) agg->plan.qual, + &aggcontext); + agg->aggParams = aggcontext.paramids; + } + } + break; + case T_WindowAgg: finalize_primnode(((WindowAgg *) plan)->startOffset, &context); @@ -2566,7 +2590,6 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, break; case T_Hash: - case T_Agg: case T_Material: case T_Sort: case T_Unique: @@ -2710,6 +2733,29 @@ finalize_primnode(Node *node, finalize_primnode_context *context) (void *) context); } +/* + * finalize_agg_primnode: find all Aggref nodes in the given expression tree, + * and add IDs of all PARAM_EXEC params appearing within their aggregated + * arguments to the result set. + */ +static bool +finalize_agg_primnode(Node *node, finalize_primnode_context *context) +{ + if (node == NULL) + return false; + if (IsA(node, Aggref)) + { + Aggref *agg = (Aggref *) node; + + /* we should not consider the direct arguments, if any */ + finalize_primnode((Node *) agg->args, context); + finalize_primnode((Node *) agg->aggfilter, context); + return false; /* there can't be any Aggrefs below here */ + } + return expression_tree_walker(node, finalize_agg_primnode, + (void *) context); +} + /* * SS_make_initplan_from_plan - given a plan tree, make it an InitPlan * diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index e6d83d4fd9..18a2b10c70 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -97,6 +97,8 @@ static bool contain_mutable_functions_walker(Node *node, void *context); static bool contain_volatile_functions_walker(Node *node, void *context); static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context); static bool contain_nonstrict_functions_walker(Node *node, void *context); +static bool contain_context_dependent_node(Node *clause); +static bool contain_context_dependent_node_walker(Node *node, int *flags); static bool contain_leaked_vars_walker(Node *node, void *context); static Relids find_nonnullable_rels_walker(Node *node, bool top_level); static List *find_nonnullable_vars_walker(Node *node, bool top_level); @@ -1322,6 +1324,76 @@ contain_nonstrict_functions_walker(Node *node, void *context) context); } +/***************************************************************************** + * Check clauses for context-dependent nodes + *****************************************************************************/ + +/* + * contain_context_dependent_node + * Recursively search for context-dependent nodes within a clause. + * + * CaseTestExpr nodes must appear directly within the corresponding CaseExpr, + * not nested within another one, or they'll see the wrong test value. If one + * appears "bare" in the arguments of a SQL function, then we can't inline the + * SQL function for fear of creating such a situation. + * + * CoerceToDomainValue would have the same issue if domain CHECK expressions + * could get inlined into larger expressions, but presently that's impossible. + * Still, it might be allowed in future, or other node types with similar + * issues might get invented. So give this function a generic name, and set + * up the recursion state to allow multiple flag bits. + */ +static bool +contain_context_dependent_node(Node *clause) +{ + int flags = 0; + + return contain_context_dependent_node_walker(clause, &flags); +} + +#define CCDN_IN_CASEEXPR 0x0001 /* CaseTestExpr okay here? */ + +static bool +contain_context_dependent_node_walker(Node *node, int *flags) +{ + if (node == NULL) + return false; + if (IsA(node, CaseTestExpr)) + return !(*flags & CCDN_IN_CASEEXPR); + if (IsA(node, CaseExpr)) + { + CaseExpr *caseexpr = (CaseExpr *) node; + + /* + * If this CASE doesn't have a test expression, then it doesn't create + * a context in which CaseTestExprs should appear, so just fall + * through and treat it as a generic expression node. + */ + if (caseexpr->arg) + { + int save_flags = *flags; + bool res; + + /* + * Note: in principle, we could distinguish the various sub-parts + * of a CASE construct and set the flag bit only for some of them, + * since we are only expecting CaseTestExprs to appear in the + * "expr" subtree of the CaseWhen nodes. But it doesn't really + * seem worth any extra code. If there are any bare CaseTestExprs + * elsewhere in the CASE, something's wrong already. + */ + *flags |= CCDN_IN_CASEEXPR; + res = expression_tree_walker(node, + contain_context_dependent_node_walker, + (void *) flags); + *flags = save_flags; + return res; + } + } + return expression_tree_walker(node, contain_context_dependent_node_walker, + (void *) flags); +} + /***************************************************************************** * Check clauses for Vars passed to non-leakproof functions *****************************************************************************/ @@ -3330,7 +3402,7 @@ eval_const_expressions_mutator(Node *node, arg = eval_const_expressions_mutator((Node *) ntest->arg, context); - if (arg && IsA(arg, RowExpr)) + if (ntest->argisrow && arg && IsA(arg, RowExpr)) { /* * We break ROW(...) IS [NOT] NULL into separate tests on @@ -3342,8 +3414,6 @@ eval_const_expressions_mutator(Node *node, List *newargs = NIL; ListCell *l; - Assert(ntest->argisrow); - foreach(l, rarg->args) { Node *relem = (Node *) lfirst(l); @@ -3362,10 +3432,17 @@ eval_const_expressions_mutator(Node *node, return makeBoolConst(false, false); continue; } + + /* + * Else, make a scalar (argisrow == false) NullTest + * for this field. Scalar semantics are required + * because IS [NOT] NULL doesn't recurse; see comments + * in ExecEvalNullTest(). + */ newntest = makeNode(NullTest); newntest->arg = (Expr *) relem; newntest->nulltesttype = ntest->nulltesttype; - newntest->argisrow = type_is_rowtype(exprType(relem)); + newntest->argisrow = false; newntest->location = ntest->location; newargs = lappend(newargs, newntest); } @@ -4230,6 +4307,8 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, * doesn't work in the general case because it discards information such * as OUT-parameter declarations. * + * Also, context-dependent expression nodes in the argument list are trouble. + * * Returns a simplified expression if successful, or NULL if cannot * simplify the function. */ @@ -4424,6 +4503,13 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, contain_nonstrict_functions(newexpr)) goto fail; + /* + * If any parameter expression contains a context-dependent node, we can't + * inline, for fear of putting such a node into the wrong context. + */ + if (contain_context_dependent_node((Node *) args)) + goto fail; + /* * We may be able to do it; there are still checks on parameter usage to * make, but those are most easily done in combination with the actual diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 5e74677947..f919d8491f 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -586,7 +586,7 @@ infer_arbiter_indexes(PlannerInfo *root) /* Build BMS representation of plain (non expression) index attrs */ indexedAttrs = NULL; - for (natt = 0; natt < idxForm->indnatts; natt++) + for (natt = 0; natt < idxForm->indnkeyatts; natt++) { int attno = idxRel->rd_index->indkey.values[natt]; @@ -1097,7 +1097,13 @@ get_relation_constraints(PlannerInfo *root, att->attcollation, 0); ntest->nulltesttype = IS_NOT_NULL; - ntest->argisrow = type_is_rowtype(att->atttypid); + + /* + * argisrow=false is correct even for a composite column, + * because attnotnull does not represent a SQL-spec IS NOT + * NULL test in such a case, just IS DISTINCT FROM NULL. + */ + ntest->argisrow = false; ntest->location = -1; result = lappend(result, ntest); } diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 86c0e84266..692dc9432b 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -1095,7 +1095,9 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx, /* * We don't try to preserve the name of the source index; instead, just - * let DefineIndex() choose a reasonable name. + * let DefineIndex() choose a reasonable name. (If we tried to preserve + * the name, we'd get duplicate-relation-name failures unless the source + * table was in a different schema.) */ index->idxname = NULL; diff --git a/src/backend/po/de.po b/src/backend/po/de.po index 1e4e2e84f7..626ce70b86 100644 --- a/src/backend/po/de.po +++ b/src/backend/po/de.po @@ -1,14 +1,14 @@ # German message translation file for PostgreSQL server # Peter Eisentraut , 2001 - 2016. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" "Project-Id-Version: PostgreSQL 9.5\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" -"POT-Creation-Date: 2016-04-28 16:16+0000\n" -"PO-Revision-Date: 2016-04-28 16:25-0400\n" +"POT-Creation-Date: 2016-08-07 17:46+0000\n" +"PO-Revision-Date: 2016-08-07 18:22-0400\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -25,27 +25,27 @@ msgstr "konnte aktuelles Verzeichnis nicht ermitteln: %s" #: ../common/exec.c:146 #, c-format msgid "invalid binary \"%s\"" -msgstr "ungültige Programmdatei „%s“" +msgstr "ungültige Programmdatei »%s«" #: ../common/exec.c:195 #, c-format msgid "could not read binary \"%s\"" -msgstr "konnte Programmdatei „%s“ nicht lesen" +msgstr "konnte Programmdatei »%s« nicht lesen" #: ../common/exec.c:202 #, c-format msgid "could not find a \"%s\" to execute" -msgstr "konnte kein „%s“ zum Ausführen finden" +msgstr "konnte kein »%s« zum Ausführen finden" #: ../common/exec.c:257 ../common/exec.c:293 #, c-format msgid "could not change directory to \"%s\": %s" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %s" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %s" #: ../common/exec.c:272 #, c-format msgid "could not read symbolic link \"%s\"" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen" #: ../common/exec.c:523 #, c-format @@ -67,32 +67,32 @@ msgstr "kann NULL-Zeiger nicht kopieren (interner Fehler)\n" #: ../common/pgfnames.c:45 #, c-format msgid "could not open directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht öffnen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht öffnen: %s\n" #: ../common/pgfnames.c:72 #, c-format msgid "could not read directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht lesen: %s\n" #: ../common/pgfnames.c:84 #, c-format msgid "could not close directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht schließen: %s\n" #: ../common/psprintf.c:179 ../port/path.c:596 ../port/path.c:634 #: ../port/path.c:651 access/transam/xlog.c:6023 lib/stringinfo.c:258 #: libpq/auth.c:820 libpq/auth.c:1183 libpq/auth.c:1251 libpq/auth.c:1662 #: postmaster/bgworker.c:289 postmaster/bgworker.c:797 -#: postmaster/postmaster.c:2317 postmaster/postmaster.c:2348 -#: postmaster/postmaster.c:3867 postmaster/postmaster.c:4557 -#: postmaster/postmaster.c:4625 postmaster/postmaster.c:5315 -#: postmaster/postmaster.c:5568 replication/logical/logical.c:167 +#: postmaster/postmaster.c:2321 postmaster/postmaster.c:2352 +#: postmaster/postmaster.c:3871 postmaster/postmaster.c:4561 +#: postmaster/postmaster.c:4629 postmaster/postmaster.c:5319 +#: postmaster/postmaster.c:5572 replication/logical/logical.c:167 #: storage/buffer/localbuf.c:396 storage/file/fd.c:588 storage/file/fd.c:985 #: storage/file/fd.c:1103 storage/file/fd.c:1716 storage/ipc/procarray.c:907 #: storage/ipc/procarray.c:1393 storage/ipc/procarray.c:1400 #: storage/ipc/procarray.c:1793 storage/ipc/procarray.c:2377 -#: utils/adt/formatting.c:1523 utils/adt/formatting.c:1643 -#: utils/adt/formatting.c:1764 utils/adt/regexp.c:219 utils/adt/varlena.c:4212 +#: utils/adt/formatting.c:1522 utils/adt/formatting.c:1642 +#: utils/adt/formatting.c:1763 utils/adt/regexp.c:219 utils/adt/varlena.c:4212 #: utils/adt/varlena.c:4233 utils/fmgr/dfmgr.c:216 utils/hash/dynahash.c:411 #: utils/hash/dynahash.c:488 utils/hash/dynahash.c:1002 utils/mb/mbutils.c:376 #: utils/mb/mbutils.c:709 utils/misc/guc.c:3723 utils/misc/guc.c:3739 @@ -113,7 +113,7 @@ msgstr "ungültiger Fork-Name" #: ../common/relpath.c:60 #, c-format msgid "Valid fork names are \"main\", \"fsm\", \"vm\", and \"init\"." -msgstr "Gültige Fork-Namen sind „main“, „fsm“, „vm“ und „init“." +msgstr "Gültige Fork-Namen sind »main«, »fsm«, »vm« und »init«." #: ../common/restricted_token.c:68 #, c-format @@ -138,7 +138,7 @@ msgstr "%s: konnte beschränktes Token nicht erzeugen: Fehlercode %lu\n" #: ../common/restricted_token.c:132 #, c-format msgid "%s: could not start process for command \"%s\": error code %lu\n" -msgstr "%s: konnte Prozess für Befehl „%s“ nicht starten: Fehlercode %lu\n" +msgstr "%s: konnte Prozess für Befehl »%s« nicht starten: Fehlercode %lu\n" #: ../common/restricted_token.c:170 #, c-format @@ -153,12 +153,12 @@ msgstr "%s: konnte Statuscode des Subprozesses nicht ermitteln: Fehlercode %lu\n #: ../common/rmtree.c:77 #, c-format msgid "could not stat file or directory \"%s\": %s\n" -msgstr "konnte „stat“ für Datei oder Verzeichnis „%s“ nicht ausführen: %s\n" +msgstr "konnte »stat« für Datei oder Verzeichnis »%s« nicht ausführen: %s\n" #: ../common/rmtree.c:104 ../common/rmtree.c:121 #, c-format msgid "could not remove file or directory \"%s\": %s\n" -msgstr "konnte Datei oder Verzeichnis „%s“ nicht entfernen: %s\n" +msgstr "konnte Datei oder Verzeichnis »%s« nicht entfernen: %s\n" #: ../common/username.c:45 #, c-format @@ -209,46 +209,46 @@ msgstr "Kindprozess wurde von Signal %d beendet" msgid "child process exited with unrecognized status %d" msgstr "Kindprozess hat mit unbekanntem Status %d beendet" -#: ../port/chklocale.c:259 +#: ../port/chklocale.c:294 #, c-format msgid "could not determine encoding for codeset \"%s\"" -msgstr "konnte Kodierung für Codeset „%s“ nicht bestimmen" +msgstr "konnte Kodierung für Codeset »%s« nicht bestimmen" -#: ../port/chklocale.c:260 ../port/chklocale.c:389 -#: postmaster/postmaster.c:4857 +#: ../port/chklocale.c:295 ../port/chklocale.c:424 +#: postmaster/postmaster.c:4861 #, c-format msgid "Please report this to ." msgstr "Bitte berichten Sie das an ." -#: ../port/chklocale.c:381 ../port/chklocale.c:387 +#: ../port/chklocale.c:416 ../port/chklocale.c:422 #, c-format msgid "could not determine encoding for locale \"%s\": codeset is \"%s\"" -msgstr "konnte Kodierung für Locale „%s“ nicht bestimmen: Codeset ist „%s“" +msgstr "konnte Kodierung für Locale »%s« nicht bestimmen: Codeset ist »%s«" #: ../port/dirmod.c:218 #, c-format msgid "could not set junction for \"%s\": %s" -msgstr "konnte Junction für „%s“ nicht erzeugen: %s" +msgstr "konnte Junction für »%s« nicht erzeugen: %s" #: ../port/dirmod.c:221 #, c-format msgid "could not set junction for \"%s\": %s\n" -msgstr "konnte Junction für „%s“ nicht erzeugen: %s\n" +msgstr "konnte Junction für »%s« nicht erzeugen: %s\n" #: ../port/dirmod.c:295 #, c-format msgid "could not get junction for \"%s\": %s" -msgstr "konnte Junction für „%s“ nicht ermitteln: %s" +msgstr "konnte Junction für »%s« nicht ermitteln: %s" #: ../port/dirmod.c:298 #, c-format msgid "could not get junction for \"%s\": %s\n" -msgstr "konnte Junction für „%s“ nicht ermitteln: %s\n" +msgstr "konnte Junction für »%s« nicht ermitteln: %s\n" #: ../port/open.c:112 #, c-format msgid "could not open file \"%s\": %s" -msgstr "konnte Datei „%s“ nicht öffnen: %s" +msgstr "konnte Datei »%s« nicht öffnen: %s" #: ../port/open.c:113 msgid "lock violation" @@ -281,7 +281,7 @@ msgstr "unbekannter Fehler %d" #: access/brin/brin.c:814 #, c-format msgid "\"%s\" is not a BRIN index" -msgstr "„%s“ ist kein BRIN-Index" +msgstr "»%s« ist kein BRIN-Index" #: access/brin/brin.c:830 #, c-format @@ -292,12 +292,12 @@ msgstr "konnte Basistabelle von Index %s nicht öffnen" #: access/brin/brin_pageops.c:828 #, c-format msgid "index row size %lu exceeds maximum %lu for index \"%s\"" -msgstr "Größe %lu der Indexzeile überschreitet Maximum %lu für Index „%s“" +msgstr "Größe %lu der Indexzeile überschreitet Maximum %lu für Index »%s«" -#: access/brin/brin_revmap.c:449 +#: access/brin/brin_revmap.c:453 #, c-format msgid "unexpected page type 0x%04X in BRIN index \"%s\" block %u" -msgstr "unerwarteter Seitentyp 0x%04X in BRIN-Index „%s“ Block %u" +msgstr "unerwarteter Seitentyp 0x%04X in BRIN-Index »%s« Block %u" #: access/common/heaptuple.c:708 access/common/heaptuple.c:1450 #, c-format @@ -333,47 +333,47 @@ msgstr "RESET darf keinen Parameterwert enthalten" #: access/common/reloptions.c:734 #, c-format msgid "unrecognized parameter namespace \"%s\"" -msgstr "unbekannter Parameter-Namensraum „%s“" +msgstr "unbekannter Parameter-Namensraum »%s«" #: access/common/reloptions.c:974 parser/parse_clause.c:279 #, c-format msgid "unrecognized parameter \"%s\"" -msgstr "unbekannter Parameter „%s“" +msgstr "unbekannter Parameter »%s«" #: access/common/reloptions.c:1004 #, c-format msgid "parameter \"%s\" specified more than once" -msgstr "Parameter „%s“ mehrmals angegeben" +msgstr "Parameter »%s« mehrmals angegeben" #: access/common/reloptions.c:1020 #, c-format msgid "invalid value for boolean option \"%s\": %s" -msgstr "ungültiger Wert für Boole’sche Option „%s“: „%s“" +msgstr "ungültiger Wert für Boole’sche Option »%s«: »%s«" #: access/common/reloptions.c:1032 #, c-format msgid "invalid value for integer option \"%s\": %s" -msgstr "ungültiger Wert für ganzzahlige Option „%s“: „%s“" +msgstr "ungültiger Wert für ganzzahlige Option »%s«: »%s«" #: access/common/reloptions.c:1038 access/common/reloptions.c:1058 #, c-format msgid "value %s out of bounds for option \"%s\"" -msgstr "Wert %s ist außerhalb des gültigen Bereichs für Option „%s“" +msgstr "Wert %s ist außerhalb des gültigen Bereichs für Option »%s«" #: access/common/reloptions.c:1040 #, c-format msgid "Valid values are between \"%d\" and \"%d\"." -msgstr "Gültige Werte sind zwischen „%d“ und „%d“." +msgstr "Gültige Werte sind zwischen »%d« und »%d«." #: access/common/reloptions.c:1052 #, c-format msgid "invalid value for floating point option \"%s\": %s" -msgstr "ungültiger Wert für Gleitkommaoption „%s“: „%s“" +msgstr "ungültiger Wert für Gleitkommaoption »%s«: »%s«" #: access/common/reloptions.c:1060 #, c-format msgid "Valid values are between \"%f\" and \"%f\"." -msgstr "Gültige Werte sind zwischen „%f“ und „%f“." +msgstr "Gültige Werte sind zwischen »%f« und »%f«." #: access/common/tupconvert.c:108 #, c-format @@ -388,24 +388,24 @@ msgstr "Anzahl der zurückgegebenen Spalten (%d) entspricht nicht der erwarteten #: access/common/tupconvert.c:241 #, c-format msgid "Attribute \"%s\" of type %s does not match corresponding attribute of type %s." -msgstr "Attribut „%s“ von Typ %s stimmt nicht mit dem entsprechenden Attribut von Typ %s überein." +msgstr "Attribut »%s« von Typ %s stimmt nicht mit dem entsprechenden Attribut von Typ %s überein." #: access/common/tupconvert.c:253 #, c-format msgid "Attribute \"%s\" of type %s does not exist in type %s." -msgstr "Attribut „%s“ von Typ %s existiert nicht in Typ %s." +msgstr "Attribut »%s« von Typ %s existiert nicht in Typ %s." #: access/common/tupdesc.c:635 parser/parse_relation.c:1517 #, c-format msgid "column \"%s\" cannot be declared SETOF" -msgstr "Spalte „%s“ kann nicht als SETOF deklariert werden" +msgstr "Spalte »%s« kann nicht als SETOF deklariert werden" #: access/gin/ginentrypage.c:109 access/gist/gist.c:1289 #: access/nbtree/nbtinsert.c:567 access/nbtree/nbtsort.c:488 #: access/spgist/spgdoinsert.c:1907 #, c-format msgid "index row size %zu exceeds maximum %zu for index \"%s\"" -msgstr "Größe %zu der Indexzeile überschreitet Maximum %zu für Index „%s“" +msgstr "Größe %zu der Indexzeile überschreitet Maximum %zu für Index »%s«" #: access/gin/ginscan.c:412 #, c-format @@ -420,7 +420,7 @@ msgstr "Um das zu reparieren, führen Sie REINDEX INDEX \"%s\" aus." #: access/gist/gist.c:632 access/gist/gistvacuum.c:266 #, c-format msgid "index \"%s\" contains an inner tuple marked as invalid" -msgstr "Index „%s“ enthält ein inneres Tupel, das als ungültig markiert ist" +msgstr "Index »%s« enthält ein inneres Tupel, das als ungültig markiert ist" #: access/gist/gist.c:634 access/gist/gistvacuum.c:268 #, c-format @@ -439,12 +439,12 @@ msgstr "Bitte führen Sie REINDEX für den Index aus." #: access/gist/gistbuild.c:252 #, c-format msgid "invalid value for \"buffering\" option" -msgstr "ungültiger Wert für Option „buffering“" +msgstr "ungültiger Wert für Option »buffering«" #: access/gist/gistbuild.c:253 #, c-format msgid "Valid values are \"on\", \"off\", and \"auto\"." -msgstr "Gültige Werte sind „on“, „off“ und „auto“." +msgstr "Gültige Werte sind »on«, »off« und »auto«." #: access/gist/gistbuildbuffers.c:778 utils/sort/logtape.c:209 #, c-format @@ -454,7 +454,7 @@ msgstr "konnte Block %ld von temporärer Datei nicht schreiben: %m" #: access/gist/gistsplit.c:446 #, c-format msgid "picksplit method for column %d of index \"%s\" failed" -msgstr "Picksplit-Methode für Spalte %d von Index „%s“ fehlgeschlagen" +msgstr "Picksplit-Methode für Spalte %d von Index »%s« fehlgeschlagen" #: access/gist/gistsplit.c:448 #, c-format @@ -465,13 +465,13 @@ msgstr "Der Index ist nicht optimal. Um ihn zu optimieren, kontaktieren Sie eine #: access/nbtree/nbtpage.c:515 #, c-format msgid "index \"%s\" contains unexpected zero page at block %u" -msgstr "Index „%s“ enthält unerwartete Nullseite bei Block %u" +msgstr "Index »%s« enthält unerwartete Nullseite bei Block %u" #: access/gist/gistutil.c:743 access/hash/hashutil.c:180 #: access/hash/hashutil.c:192 access/nbtree/nbtpage.c:526 #, c-format msgid "index \"%s\" contains corrupted page at block %u" -msgstr "Index „%s“ enthält korrupte Seite bei Block %u" +msgstr "Index »%s« enthält korrupte Seite bei Block %u" #: access/hash/hashinsert.c:68 #, c-format @@ -487,7 +487,7 @@ msgstr "Werte, die größer sind als eine Pufferseite, können nicht indiziert w #: access/hash/hashovfl.c:546 #, c-format msgid "out of overflow pages in hash index \"%s\"" -msgstr "keine Überlaufseiten in Hash-Index „%s“ mehr" +msgstr "keine Überlaufseiten in Hash-Index »%s« mehr" #: access/hash/hashsearch.c:153 #, c-format @@ -497,12 +497,12 @@ msgstr "Hash-Indexe unterstützen keine Scans des ganzen Index" #: access/hash/hashutil.c:208 #, c-format msgid "index \"%s\" is not a hash index" -msgstr "Index „%s“ ist kein Hash-Index" +msgstr "Index »%s« ist kein Hash-Index" #: access/hash/hashutil.c:214 #, c-format msgid "index \"%s\" has wrong hash version" -msgstr "Index „%s“ hat falsche Hash-Version" +msgstr "Index »%s« hat falsche Hash-Version" #: access/heap/heapam.c:1074 access/heap/heapam.c:1126 #, c-format @@ -513,14 +513,14 @@ msgstr "während einer parallelen Operation kann nicht auf temporäre Tabellen z #: access/heap/heapam.c:1303 catalog/aclchk.c:1733 #, c-format msgid "\"%s\" is an index" -msgstr "„%s“ ist ein Index" +msgstr "»%s« ist ein Index" #: access/heap/heapam.c:1248 access/heap/heapam.c:1276 #: access/heap/heapam.c:1308 catalog/aclchk.c:1740 commands/tablecmds.c:8954 #: commands/tablecmds.c:12005 #, c-format msgid "\"%s\" is a composite type" -msgstr "„%s“ ist ein zusammengesetzter Typ" +msgstr "»%s« ist ein zusammengesetzter Typ" #: access/heap/heapam.c:2344 #, c-format @@ -537,21 +537,21 @@ msgstr "während einer parallelen Operation können keine Tupel gelöscht werden msgid "attempted to delete invisible tuple" msgstr "Versuch ein unsichtbares Tupel zu löschen" -#: access/heap/heapam.c:3267 access/heap/heapam.c:5818 +#: access/heap/heapam.c:3266 access/heap/heapam.c:5889 #, c-format msgid "cannot update tuples during a parallel operation" msgstr "während einer parallelen Operation können keine Tupel aktualisiert werden" -#: access/heap/heapam.c:3389 +#: access/heap/heapam.c:3388 #, c-format msgid "attempted to update invisible tuple" msgstr "Versuch ein unsichtbares Tupel zu aktualisieren" -#: access/heap/heapam.c:4640 access/heap/heapam.c:4678 -#: access/heap/heapam.c:4901 executor/execMain.c:2279 +#: access/heap/heapam.c:4701 access/heap/heapam.c:4739 +#: access/heap/heapam.c:4962 executor/execMain.c:2279 #, c-format msgid "could not obtain lock on row in relation \"%s\"" -msgstr "konnte Sperre für Zeile in Relation „%s“ nicht setzen" +msgstr "konnte Sperre für Zeile in Relation »%s« nicht setzen" #: access/heap/hio.c:253 access/heap/rewriteheap.c:666 #, c-format @@ -561,7 +561,7 @@ msgstr "Zeile ist zu groß: Größe ist %zu, Maximalgröße ist %zu" #: access/heap/rewriteheap.c:925 #, c-format msgid "could not write to file \"%s\", wrote %d of %d: %m" -msgstr "konnte nicht in Datei „%s“ schreiben, %d von %d geschrieben: %m" +msgstr "konnte nicht in Datei »%s« schreiben, %d von %d geschrieben: %m" #: access/heap/rewriteheap.c:965 access/heap/rewriteheap.c:1177 #: access/heap/rewriteheap.c:1274 access/transam/timeline.c:407 @@ -572,34 +572,34 @@ msgstr "konnte nicht in Datei „%s“ schreiben, %d von %d geschrieben: %m" #: storage/smgr/md.c:1386 utils/misc/guc.c:6708 #, c-format msgid "could not fsync file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht fsyncen: %m" +msgstr "konnte Datei »%s« nicht fsyncen: %m" #: access/heap/rewriteheap.c:1020 access/heap/rewriteheap.c:1140 #: access/transam/timeline.c:315 access/transam/timeline.c:461 #: access/transam/xlog.c:2967 access/transam/xlog.c:3116 #: access/transam/xlog.c:10075 access/transam/xlog.c:10111 -#: access/transam/xlog.c:10433 postmaster/postmaster.c:4332 +#: access/transam/xlog.c:10433 postmaster/postmaster.c:4336 #: replication/logical/origin.c:542 replication/slot.c:983 #: storage/file/copydir.c:162 storage/smgr/md.c:320 utils/time/snapmgr.c:1071 #, c-format msgid "could not create file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht erstellen: %m" +msgstr "konnte Datei »%s« nicht erstellen: %m" #: access/heap/rewriteheap.c:1149 #, c-format msgid "could not truncate file \"%s\" to %u: %m" -msgstr "konnte Datei „%s“ nicht auf %u kürzen: %m" +msgstr "konnte Datei »%s« nicht auf %u kürzen: %m" #: access/heap/rewriteheap.c:1156 replication/walsender.c:479 #: storage/smgr/md.c:1798 #, c-format msgid "could not seek to end of file \"%s\": %m" -msgstr "konnte Positionszeiger nicht ans Ende der Datei „%s“ setzen: %m" +msgstr "konnte Positionszeiger nicht ans Ende der Datei »%s« setzen: %m" #: access/heap/rewriteheap.c:1167 access/transam/timeline.c:367 #: access/transam/timeline.c:401 access/transam/timeline.c:477 #: access/transam/xlog.c:3002 access/transam/xlog.c:3166 -#: postmaster/postmaster.c:4342 postmaster/postmaster.c:4352 +#: postmaster/postmaster.c:4346 postmaster/postmaster.c:4356 #: replication/logical/origin.c:551 replication/logical/origin.c:587 #: replication/logical/origin.c:603 replication/logical/snapbuild.c:1572 #: replication/slot.c:1012 storage/file/copydir.c:187 @@ -609,18 +609,18 @@ msgstr "konnte Positionszeiger nicht ans Ende der Datei „%s“ setzen: %m" #: utils/time/snapmgr.c:1083 #, c-format msgid "could not write to file \"%s\": %m" -msgstr "konnte nicht in Datei „%s“ schreiben: %m" +msgstr "konnte nicht in Datei »%s« schreiben: %m" #: access/heap/rewriteheap.c:1250 access/transam/xlog.c:10300 #: access/transam/xlogarchive.c:114 access/transam/xlogarchive.c:468 -#: replication/logical/origin.c:529 replication/logical/reorderbuffer.c:2490 -#: replication/logical/reorderbuffer.c:2547 +#: replication/logical/origin.c:529 replication/logical/reorderbuffer.c:2491 +#: replication/logical/reorderbuffer.c:2548 #: replication/logical/snapbuild.c:1516 replication/logical/snapbuild.c:1891 #: replication/slot.c:1089 storage/ipc/dsm.c:326 storage/smgr/md.c:420 #: storage/smgr/md.c:469 storage/smgr/md.c:1333 #, c-format msgid "could not remove file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht löschen: %m" +msgstr "konnte Datei »%s« nicht löschen: %m" #: access/heap/rewriteheap.c:1264 access/transam/timeline.c:111 #: access/transam/timeline.c:236 access/transam/timeline.c:334 @@ -628,9 +628,9 @@ msgstr "konnte Datei „%s“ nicht löschen: %m" #: access/transam/xlog.c:3101 access/transam/xlog.c:3374 #: access/transam/xlog.c:3452 replication/basebackup.c:398 #: replication/basebackup.c:1159 replication/logical/logicalfuncs.c:154 -#: replication/logical/origin.c:658 replication/logical/reorderbuffer.c:2071 -#: replication/logical/reorderbuffer.c:2284 -#: replication/logical/reorderbuffer.c:2938 +#: replication/logical/origin.c:658 replication/logical/reorderbuffer.c:2072 +#: replication/logical/reorderbuffer.c:2285 +#: replication/logical/reorderbuffer.c:2939 #: replication/logical/snapbuild.c:1565 replication/logical/snapbuild.c:1649 #: replication/slot.c:1104 replication/walsender.c:472 #: replication/walsender.c:2100 storage/file/copydir.c:155 @@ -640,34 +640,34 @@ msgstr "konnte Datei „%s“ nicht löschen: %m" #: utils/init/miscinit.c:1343 utils/misc/guc.c:6928 utils/misc/guc.c:6961 #, c-format msgid "could not open file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht öffnen: %m" +msgstr "konnte Datei »%s« nicht öffnen: %m" #: access/index/indexam.c:172 catalog/objectaddress.c:1144 #: commands/indexcmds.c:1754 commands/tablecmds.c:239 #: commands/tablecmds.c:11996 #, c-format msgid "\"%s\" is not an index" -msgstr "„%s“ ist kein Index" +msgstr "»%s« ist kein Index" #: access/nbtree/nbtinsert.c:419 #, c-format msgid "duplicate key value violates unique constraint \"%s\"" -msgstr "doppelter Schlüsselwert verletzt Unique-Constraint „%s“" +msgstr "doppelter Schlüsselwert verletzt Unique-Constraint »%s«" #: access/nbtree/nbtinsert.c:421 #, c-format msgid "Key %s already exists." -msgstr "Schlüssel „%s“ existiert bereits." +msgstr "Schlüssel »%s« existiert bereits." #: access/nbtree/nbtinsert.c:488 #, c-format msgid "failed to re-find tuple within index \"%s\"" -msgstr "konnte Tupel mit Index „%s“ nicht erneut finden" +msgstr "konnte Tupel mit Index »%s« nicht erneut finden" #: access/nbtree/nbtinsert.c:490 #, c-format msgid "This may be because of a non-immutable index expression." -msgstr "Das kann daran liegen, dass der Indexausdruck nicht „immutable“ ist." +msgstr "Das kann daran liegen, dass der Indexausdruck nicht »immutable« ist." #: access/nbtree/nbtinsert.c:570 access/nbtree/nbtsort.c:491 #, c-format @@ -679,21 +679,21 @@ msgstr "" "Erstellen Sie eventuell einen Funktionsindex auf einen MD5-Hash oder verwenden Sie Volltextindizierung." #: access/nbtree/nbtpage.c:168 access/nbtree/nbtpage.c:371 -#: access/nbtree/nbtpage.c:458 parser/parse_utilcmd.c:1665 +#: access/nbtree/nbtpage.c:458 parser/parse_utilcmd.c:1667 #, c-format msgid "index \"%s\" is not a btree" -msgstr "Index „%s“ ist kein B-Tree" +msgstr "Index »%s« ist kein B-Tree" #: access/nbtree/nbtpage.c:174 access/nbtree/nbtpage.c:377 #: access/nbtree/nbtpage.c:464 #, c-format msgid "version mismatch in index \"%s\": file version %d, code version %d" -msgstr "keine Versionsübereinstimmung in Index „%s“: Dateiversion %d, Code-Version %d" +msgstr "keine Versionsübereinstimmung in Index »%s«: Dateiversion %d, Code-Version %d" #: access/nbtree/nbtpage.c:1152 #, c-format msgid "index \"%s\" contains a half-dead internal page" -msgstr "Index „%s“ enthält eine halbtote interne Seite" +msgstr "Index »%s« enthält eine halbtote interne Seite" #: access/nbtree/nbtpage.c:1154 #, c-format @@ -723,17 +723,17 @@ msgstr "konnte Commit-Timestamp-Daten nicht auslesen" #: access/transam/commit_ts.c:387 #, c-format msgid "Make sure the configuration parameter \"%s\" is set on the master server." -msgstr "Stellen Sie sicher, dass der Konfigurationsparameter „%s“ auf dem Masterserver gesetzt ist." +msgstr "Stellen Sie sicher, dass der Konfigurationsparameter »%s« auf dem Masterserver gesetzt ist." #: access/transam/commit_ts.c:389 libpq/hba.c:1424 #, c-format msgid "Make sure the configuration parameter \"%s\" is set." -msgstr "Stellen Sie sicher, dass der Konfigurationsparameter „%s“ gesetzt ist." +msgstr "Stellen Sie sicher, dass der Konfigurationsparameter »%s« gesetzt ist." #: access/transam/multixact.c:1008 #, c-format msgid "database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database \"%s\"" -msgstr "Datenbank nimmt keine Befehle an, die neue MultiXactIds erzeugen, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank „%s“ zu vermeiden" +msgstr "Datenbank nimmt keine Befehle an, die neue MultiXactIds erzeugen, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank »%s« zu vermeiden" #: access/transam/multixact.c:1010 access/transam/multixact.c:1017 #: access/transam/multixact.c:1041 access/transam/multixact.c:1050 @@ -750,14 +750,14 @@ msgstr "" msgid "database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database with OID %u" msgstr "Datenbank nimmt keine Befehle an, die neue MultiXactIds erzeugen, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank mit OID %u zu vermeiden" -#: access/transam/multixact.c:1036 access/transam/multixact.c:2319 +#: access/transam/multixact.c:1036 access/transam/multixact.c:2318 #, 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" +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:1045 access/transam/multixact.c:2328 +#: access/transam/multixact.c:1045 access/transam/multixact.c:2327 #, 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" @@ -767,7 +767,7 @@ msgstr[1] "Datenbank mit OID %u muss gevacuumt werden, bevor %u weitere MultiXac #: access/transam/multixact.c:1106 #, c-format msgid "multixact \"members\" limit exceeded" -msgstr "Grenzwert für Multixact-„Members“ überschritten" +msgstr "Grenzwert für Multixact-»Members« überschritten" #: access/transam/multixact.c:1107 #, c-format @@ -793,22 +793,22 @@ msgstr[1] "Datenbank mit OID %u muss gevacuumt werden, bevor %d weitere Multixac 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:1286 +#: access/transam/multixact.c:1285 #, c-format msgid "MultiXactId %u does no longer exist -- apparent wraparound" msgstr "MultiXactId %u existiert nicht mehr -- anscheinender Überlauf" -#: access/transam/multixact.c:1294 +#: access/transam/multixact.c:1293 #, 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:2269 +#: access/transam/multixact.c:2268 #, c-format msgid "MultiXactId wrap limit is %u, limited by database with OID %u" msgstr "Grenze für MultiXactId-Überlauf ist %u, begrenzt durch Datenbank mit OID %u" -#: access/transam/multixact.c:2324 access/transam/multixact.c:2333 +#: access/transam/multixact.c:2323 access/transam/multixact.c:2332 #: access/transam/varsup.c:146 access/transam/varsup.c:153 #: access/transam/varsup.c:384 access/transam/varsup.c:391 #, c-format @@ -819,62 +819,62 @@ msgstr "" "Um ein Abschalten der Datenbank 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." -#: access/transam/multixact.c:2603 +#: access/transam/multixact.c:2602 #, c-format msgid "oldest MultiXactId member is at offset %u" msgstr "ältestes MultiXactId-Mitglied ist bei Offset %u" -#: access/transam/multixact.c:2607 +#: access/transam/multixact.c:2606 #, 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:2629 +#: access/transam/multixact.c:2628 #, c-format msgid "MultiXact member wraparound protections are now enabled" msgstr "MultiXact-Member-Wraparound-Schutz ist jetzt aktiviert" -#: access/transam/multixact.c:2631 +#: access/transam/multixact.c:2630 #, c-format msgid "MultiXact member stop limit is now %u based on MultiXact %u" msgstr "MultiXact-Member-Stopp-Limit ist jetzt %u, basierend auf MultiXact %u" -#: access/transam/multixact.c:3011 +#: access/transam/multixact.c:3010 #, 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:3029 +#: access/transam/multixact.c:3028 #, 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:3355 +#: access/transam/multixact.c:3354 #, c-format msgid "invalid MultiXactId: %u" msgstr "ungültige MultiXactId: %u" -#: access/transam/parallel.c:577 +#: access/transam/parallel.c:581 #, c-format msgid "postmaster exited during a parallel transaction" msgstr "Postmaster beendete während einer parallelen Transaktion" -#: access/transam/parallel.c:668 +#: access/transam/parallel.c:681 #, c-format msgid "lost connection to parallel worker" msgstr "Verbindung mit parallelem Arbeitsprozess verloren" -#: access/transam/parallel.c:845 +#: access/transam/parallel.c:857 #, c-format msgid "could not map dynamic shared memory segment" msgstr "konnte dynamisches Shared-Memory-Segment nicht mappen" -#: access/transam/parallel.c:850 +#: access/transam/parallel.c:862 #, c-format msgid "invalid magic number in dynamic shared memory segment" msgstr "ungültige magische Zahl in dynamischem Shared-Memory-Segment" -#: access/transam/parallel.c:1001 +#: access/transam/parallel.c:1013 #, c-format msgid "parallel worker, PID %d" msgstr "paralleler Arbeitsprozess, PID %d" @@ -882,7 +882,7 @@ msgstr "paralleler Arbeitsprozess, PID %d" #: access/transam/slru.c:652 #, c-format msgid "file \"%s\" doesn't exist, reading as zeroes" -msgstr "Datei „%s“ existiert nicht, wird als Nullen eingelesen" +msgstr "Datei »%s« existiert nicht, wird als Nullen eingelesen" #: access/transam/slru.c:882 access/transam/slru.c:888 #: access/transam/slru.c:895 access/transam/slru.c:902 @@ -894,42 +894,42 @@ msgstr "konnte auf den Status von Transaktion %u nicht zugreifen" #: access/transam/slru.c:883 #, c-format msgid "Could not open file \"%s\": %m." -msgstr "Konnte Datei „%s“ nicht öffnen: %m." +msgstr "Konnte Datei »%s« nicht öffnen: %m." #: access/transam/slru.c:889 #, c-format msgid "Could not seek in file \"%s\" to offset %u: %m." -msgstr "Konnte Positionszeiger in Datei „%s“ nicht auf %u setzen: %m." +msgstr "Konnte Positionszeiger in Datei »%s« nicht auf %u setzen: %m." #: access/transam/slru.c:896 #, c-format msgid "Could not read from file \"%s\" at offset %u: %m." -msgstr "Konnte nicht aus Datei „%s“ bei Position %u lesen: %m." +msgstr "Konnte nicht aus Datei »%s« bei Position %u lesen: %m." #: access/transam/slru.c:903 #, c-format msgid "Could not write to file \"%s\" at offset %u: %m." -msgstr "Konnte nicht in Datei „%s“ bei Position %u schreiben: %m." +msgstr "Konnte nicht in Datei »%s« bei Position %u schreiben: %m." #: access/transam/slru.c:910 #, c-format msgid "Could not fsync file \"%s\": %m." -msgstr "Konnte Datei „%s“ nicht fsyncen: %m." +msgstr "Konnte Datei »%s« nicht fsyncen: %m." #: access/transam/slru.c:917 #, c-format msgid "Could not close file \"%s\": %m." -msgstr "Konnte Datei „%s“ nicht schließen: %m." +msgstr "Konnte Datei »%s« nicht schließen: %m." #: access/transam/slru.c:1172 #, c-format msgid "could not truncate directory \"%s\": apparent wraparound" -msgstr "konnte Verzeichnis „%s“ nicht leeren: anscheinender Überlauf" +msgstr "konnte Verzeichnis »%s« nicht leeren: anscheinender Überlauf" #: access/transam/slru.c:1227 access/transam/slru.c:1283 #, c-format msgid "removing file \"%s\"" -msgstr "entferne Datei „%s“" +msgstr "entferne Datei »%s«" #: access/transam/timeline.c:148 access/transam/timeline.c:153 #, c-format @@ -959,7 +959,7 @@ msgstr "Zeitleisten-IDs müssen in aufsteigender Folge sein." #: access/transam/timeline.c:179 #, c-format msgid "invalid data in history file \"%s\"" -msgstr "ungültige Daten in History-Datei „%s“" +msgstr "ungültige Daten in History-Datei »%s«" #: access/transam/timeline.c:180 #, c-format @@ -972,12 +972,12 @@ msgstr "Zeitleisten-IDs müssen kleiner als die Zeitleisten-ID des Kindes sein." #: access/transam/xlog.c:10740 access/transam/xlog.c:10783 #: access/transam/xlogfuncs.c:478 access/transam/xlogfuncs.c:497 #: commands/extension.c:3047 replication/logical/origin.c:665 -#: replication/logical/origin.c:695 replication/logical/reorderbuffer.c:2956 +#: replication/logical/origin.c:695 replication/logical/reorderbuffer.c:2957 #: replication/walsender.c:497 storage/file/copydir.c:176 #: utils/adt/genfile.c:151 #, c-format msgid "could not read file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht lesen: %m" +msgstr "konnte Datei »%s« nicht lesen: %m" #: access/transam/timeline.c:412 access/transam/timeline.c:488 #: access/transam/xlog.c:3017 access/transam/xlog.c:3178 @@ -985,7 +985,7 @@ msgstr "konnte Datei „%s“ nicht lesen: %m" #: storage/file/copydir.c:201 #, c-format msgid "could not close file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht schließen: %m" +msgstr "konnte Datei »%s« nicht schließen: %m" #: access/transam/timeline.c:570 #, c-format @@ -995,7 +995,7 @@ msgstr "angeforderte Zeitleiste %u ist nicht in der History dieses Servers" #: access/transam/twophase.c:330 #, c-format msgid "transaction identifier \"%s\" is too long" -msgstr "Transaktionsbezeichner „%s“ ist zu lang" +msgstr "Transaktionsbezeichner »%s« ist zu lang" #: access/transam/twophase.c:337 #, c-format @@ -1010,7 +1010,7 @@ msgstr "Setzen Sie max_prepared_transactions auf einen Wert höher als null." #: access/transam/twophase.c:357 #, c-format msgid "transaction identifier \"%s\" is already in use" -msgstr "Transaktionsbezeichner „%s“ wird bereits verwendet" +msgstr "Transaktionsbezeichner »%s« wird bereits verwendet" #: access/transam/twophase.c:366 #, c-format @@ -1025,7 +1025,7 @@ msgstr "Erhöhen Sie max_prepared_transactions (aktuell %d)." #: access/transam/twophase.c:504 #, c-format msgid "prepared transaction with identifier \"%s\" is busy" -msgstr "vorbereitete Transaktion mit Bezeichner „%s“ ist beschäftigt" +msgstr "vorbereitete Transaktion mit Bezeichner »%s« ist beschäftigt" #: access/transam/twophase.c:510 #, c-format @@ -1050,7 +1050,7 @@ msgstr "Verbinden Sie sich mit der Datenbank, wo die Transaktion vorbereitet wur #: access/transam/twophase.c:538 #, c-format msgid "prepared transaction with identifier \"%s\" does not exist" -msgstr "vorbereitete Transaktion mit Bezeichner „%s“ existiert nicht" +msgstr "vorbereitete Transaktion mit Bezeichner »%s« existiert nicht" #: access/transam/twophase.c:1048 #, c-format @@ -1060,7 +1060,7 @@ msgstr "maximale Länge der Zweiphasen-Statusdatei überschritten" #: access/transam/twophase.c:1061 #, c-format msgid "could not create two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statusdatei „%s“ nicht erstellen: %m" +msgstr "konnte Zweiphasen-Statusdatei »%s« nicht erstellen: %m" #: access/transam/twophase.c:1075 access/transam/twophase.c:1092 #: access/transam/twophase.c:1145 access/transam/twophase.c:1575 @@ -1082,17 +1082,17 @@ msgstr "konnte Zweiphasen-Statusdatei nicht schließen: %m" #: access/transam/twophase.c:1239 access/transam/twophase.c:1681 #, c-format msgid "could not open two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statusdatei „%s“ nicht öffnen: %m" +msgstr "konnte Zweiphasen-Statusdatei »%s« nicht öffnen: %m" #: access/transam/twophase.c:1256 #, c-format msgid "could not stat two-phase state file \"%s\": %m" -msgstr "konnte „stat“ für Zweiphasen-Statusdatei „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Zweiphasen-Statusdatei »%s« nicht ausführen: %m" #: access/transam/twophase.c:1288 #, c-format msgid "could not read two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statusdatei „%s“ nicht lesen: %m" +msgstr "konnte Zweiphasen-Statusdatei »%s« nicht lesen: %m" #: access/transam/twophase.c:1384 #, c-format @@ -1102,12 +1102,12 @@ msgstr "Zweiphasen-Statusdatei für Transaktion %u ist verfälscht" #: access/transam/twophase.c:1537 #, c-format msgid "could not remove two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statusdatei „%s“ nicht löschen: %m" +msgstr "konnte Zweiphasen-Statusdatei »%s« nicht löschen: %m" #: access/transam/twophase.c:1566 #, c-format msgid "could not recreate two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statusdatei „%s“ nicht wieder erstellen: %m" +msgstr "konnte Zweiphasen-Statusdatei »%s« nicht wieder erstellen: %m" #: access/transam/twophase.c:1594 #, c-format @@ -1117,29 +1117,29 @@ msgstr "konnte Zweiphasen-Statusdatei nicht fsyncen: %m" #: access/transam/twophase.c:1690 #, c-format msgid "could not fsync two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statusdatei „%s“ nicht fsyncen: %m" +msgstr "konnte Zweiphasen-Statusdatei »%s« nicht fsyncen: %m" #: access/transam/twophase.c:1697 #, c-format msgid "could not close two-phase state file \"%s\": %m" -msgstr "konnte Zweiphasen-Statistikdatei „%s“ nicht schließen: %m" +msgstr "konnte Zweiphasen-Statistikdatei »%s« nicht schließen: %m" #: access/transam/twophase.c:1762 #, c-format msgid "removing future two-phase state file \"%s\"" -msgstr "entferne Zweiphasen-Statusdatei aus der Zukunft „%s“" +msgstr "entferne Zweiphasen-Statusdatei aus der Zukunft »%s«" #: access/transam/twophase.c:1778 access/transam/twophase.c:1789 #: access/transam/twophase.c:1908 access/transam/twophase.c:1919 #: access/transam/twophase.c:1992 #, c-format msgid "removing corrupt two-phase state file \"%s\"" -msgstr "entferne verfälschte Zweiphasen-Statusdatei „%s“" +msgstr "entferne verfälschte Zweiphasen-Statusdatei »%s«" #: access/transam/twophase.c:1897 access/transam/twophase.c:1981 #, c-format msgid "removing stale two-phase state file \"%s\"" -msgstr "entferne abgelaufene Zweiphasen-Statusdatei „%s“" +msgstr "entferne abgelaufene Zweiphasen-Statusdatei »%s«" #: access/transam/twophase.c:1999 #, c-format @@ -1149,7 +1149,7 @@ msgstr "Wiederherstellung der vorbereiteten Transaktion %u" #: access/transam/varsup.c:124 #, c-format msgid "database is not accepting commands to avoid wraparound data loss in database \"%s\"" -msgstr "Datenbank nimmt keine Befehle an, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank „%s“ zu vermeiden" +msgstr "Datenbank nimmt keine Befehle an, um Datenverlust wegen Transaktionsnummernüberlauf in Datenbank »%s« zu vermeiden" #: access/transam/varsup.c:126 access/transam/varsup.c:133 #, c-format @@ -1168,7 +1168,7 @@ msgstr "Datenbank nimmt keine Befehle an, um Datenverlust wegen Transaktionsnumm #: access/transam/varsup.c:143 access/transam/varsup.c:381 #, c-format msgid "database \"%s\" must be vacuumed within %u transactions" -msgstr "Datenbank „%s“ muss innerhalb von %u Transaktionen gevacuumt werden" +msgstr "Datenbank »%s« muss innerhalb von %u Transaktionen gevacuumt werden" #: access/transam/varsup.c:150 access/transam/varsup.c:388 #, c-format @@ -1188,7 +1188,7 @@ msgstr "kann nicht mehr als 2^32-2 Befehle in einer Transaktion ausführen" #: access/transam/xact.c:1453 #, c-format msgid "maximum number of committed subtransactions (%d) exceeded" -msgstr "maximale Anzahl committeter Subtransaktionen (%d) erreicht" +msgstr "maximale Anzahl committeter Subtransaktionen (%d) überschritten" #: access/transam/xact.c:2249 #, c-format @@ -1299,12 +1299,12 @@ msgstr "minimaler Recovery-Punkt auf %X/%X auf Zeitleiste %u aktualisiert" #: access/transam/xlog.c:3148 #, c-format msgid "not enough data in file \"%s\"" -msgstr "nicht genug Daten in Datei „%s“" +msgstr "nicht genug Daten in Datei »%s«" #: access/transam/xlog.c:3289 #, c-format msgid "could not open transaction log file \"%s\": %m" -msgstr "konnte Transaktionslogdatei „%s“ nicht öffnen: %m" +msgstr "konnte Transaktionslogdatei »%s« nicht öffnen: %m" #: access/transam/xlog.c:3478 access/transam/xlog.c:5254 #, c-format @@ -1321,47 +1321,47 @@ msgstr "das angeforderte WAL-Segment %s wurde schon entfernt" #: access/transam/xlog.c:3868 #, c-format msgid "could not open transaction log directory \"%s\": %m" -msgstr "konnte Transaktionslog-Verzeichnis „%s“ nicht öffnen: %m" +msgstr "konnte Transaktionslog-Verzeichnis »%s« nicht öffnen: %m" #: access/transam/xlog.c:3751 #, c-format msgid "recycled transaction log file \"%s\"" -msgstr "Transaktionslogdatei „%s“ wird wiederverwendet" +msgstr "Transaktionslogdatei »%s« wird wiederverwendet" #: access/transam/xlog.c:3763 #, c-format msgid "removing transaction log file \"%s\"" -msgstr "entferne Transaktionslogdatei „%s“" +msgstr "entferne Transaktionslogdatei »%s«" #: access/transam/xlog.c:3783 #, c-format msgid "could not rename old transaction log file \"%s\": %m" -msgstr "konnte alte Transaktionslogdatei „%s“ nicht umbenennen: %m" +msgstr "konnte alte Transaktionslogdatei »%s« nicht umbenennen: %m" #: access/transam/xlog.c:3795 #, c-format msgid "could not remove old transaction log file \"%s\": %m" -msgstr "konnte alte Transaktionslogdatei „%s“ nicht löschen: %m" +msgstr "konnte alte Transaktionslogdatei »%s« nicht löschen: %m" #: access/transam/xlog.c:3828 access/transam/xlog.c:3838 #, c-format msgid "required WAL directory \"%s\" does not exist" -msgstr "benötigtes WAL-Verzeichnis „%s“ existiert nicht" +msgstr "benötigtes WAL-Verzeichnis »%s« existiert nicht" #: access/transam/xlog.c:3844 #, c-format msgid "creating missing WAL directory \"%s\"" -msgstr "erzeuge fehlendes WAL-Verzeichnis „%s“" +msgstr "erzeuge fehlendes WAL-Verzeichnis »%s«" #: access/transam/xlog.c:3847 #, c-format msgid "could not create missing directory \"%s\": %m" -msgstr "konnte fehlendes Verzeichnis „%s“ nicht erzeugen: %m" +msgstr "konnte fehlendes Verzeichnis »%s« nicht erzeugen: %m" #: access/transam/xlog.c:3878 #, c-format msgid "removing transaction log backup history file \"%s\"" -msgstr "entferne Transaktionslog-Backup-History-Datei „%s“" +msgstr "entferne Transaktionslog-Backup-History-Datei »%s«" #: access/transam/xlog.c:3959 #, c-format @@ -1386,7 +1386,7 @@ msgstr "neue Zielzeitleiste ist %u" #: access/transam/xlog.c:4194 #, c-format msgid "could not create control file \"%s\": %m" -msgstr "konnte Kontrolldatei „%s“ nicht erzeugen: %m" +msgstr "konnte Kontrolldatei »%s« nicht erzeugen: %m" #: access/transam/xlog.c:4205 access/transam/xlog.c:4441 #, c-format @@ -1406,7 +1406,7 @@ msgstr "konnte Kontrolldatei nicht schließen: %m" #: access/transam/xlog.c:4234 access/transam/xlog.c:4430 #, c-format msgid "could not open control file \"%s\": %m" -msgstr "konnte Kontrolldatei „%s“ nicht öffnen: %m" +msgstr "konnte Kontrolldatei »%s« nicht öffnen: %m" #: access/transam/xlog.c:4240 #, c-format @@ -1567,27 +1567,27 @@ msgstr "konnte Bootstrap-Transaktionslogdatei nicht schließen: %m" #: access/transam/xlog.c:4915 #, c-format msgid "could not open recovery command file \"%s\": %m" -msgstr "konnte Recovery-Kommandodatei „%s“ nicht öffnen: %m" +msgstr "konnte Recovery-Kommandodatei »%s« nicht öffnen: %m" #: access/transam/xlog.c:4961 access/transam/xlog.c:5044 #, c-format msgid "invalid value for recovery parameter \"%s\": \"%s\"" -msgstr "ungültiger Wert für Recovery-Parameter „%s“: „%s“" +msgstr "ungültiger Wert für Recovery-Parameter »%s«: »%s«" #: access/transam/xlog.c:4964 #, c-format msgid "Valid values are \"pause\", \"promote\", and \"shutdown\"." -msgstr "Gültige Werte sind „pause“, „promote“ und „shutdown“." +msgstr "Gültige Werte sind »pause«, »promote« und »shutdown«." #: access/transam/xlog.c:4983 #, c-format msgid "recovery_target_timeline is not a valid number: \"%s\"" -msgstr "recovery_target_timeline ist keine gültige Zahl: „%s“" +msgstr "recovery_target_timeline ist keine gültige Zahl: »%s«" #: access/transam/xlog.c:4999 #, c-format msgid "recovery_target_xid is not a valid number: \"%s\"" -msgstr "recovery_target_xid ist keine gültige Zahl: „%s“" +msgstr "recovery_target_xid ist keine gültige Zahl: »%s«" #: access/transam/xlog.c:5030 #, c-format @@ -1597,24 +1597,24 @@ msgstr "recovery_target_name ist zu lang (maximal %d Zeichen)" #: access/transam/xlog.c:5047 #, c-format msgid "The only allowed value is \"immediate\"." -msgstr "Der einzige erlaubte Wert ist „immediate“." +msgstr "Der einzige erlaubte Wert ist »immediate«." #: access/transam/xlog.c:5060 access/transam/xlog.c:5071 #: commands/extension.c:531 commands/extension.c:539 utils/misc/guc.c:5464 #, c-format msgid "parameter \"%s\" requires a Boolean value" -msgstr "Parameter „%s“ erfordert einen Boole’schen Wert" +msgstr "Parameter »%s« erfordert einen Boole’schen Wert" #: access/transam/xlog.c:5106 #, c-format msgid "parameter \"%s\" requires a temporal value" -msgstr "Parameter „%s“ erfordert einen Zeitwert" +msgstr "Parameter »%s« erfordert einen Zeitwert" #: access/transam/xlog.c:5108 catalog/dependency.c:984 #: catalog/dependency.c:985 catalog/dependency.c:991 catalog/dependency.c:992 #: catalog/dependency.c:1003 catalog/dependency.c:1004 #: catalog/objectaddress.c:1053 commands/tablecmds.c:791 -#: commands/tablecmds.c:9415 commands/user.c:1027 commands/view.c:482 +#: commands/tablecmds.c:9415 commands/user.c:1027 commands/view.c:470 #: libpq/auth.c:285 port/win32/security.c:51 storage/lmgr/deadlock.c:955 #: storage/lmgr/proc.c:1177 utils/misc/guc.c:5486 utils/misc/guc.c:5579 #: utils/misc/guc.c:9482 utils/misc/guc.c:9516 utils/misc/guc.c:9550 @@ -1626,12 +1626,12 @@ msgstr "%s" #: access/transam/xlog.c:5114 #, c-format msgid "unrecognized recovery parameter \"%s\"" -msgstr "unbekannter Recovery-Parameter „%s“" +msgstr "unbekannter Recovery-Parameter »%s«" #: access/transam/xlog.c:5125 #, c-format msgid "recovery command file \"%s\" specified neither primary_conninfo nor restore_command" -msgstr "Recovery-Kommandodatei „%s“ hat weder primary_conninfo noch restore_command angegeben" +msgstr "Recovery-Kommandodatei »%s« hat weder primary_conninfo noch restore_command angegeben" #: access/transam/xlog.c:5127 #, c-format @@ -1641,7 +1641,7 @@ msgstr "Der Datenbankserver prüft das Unterverzeichnis pg_xlog regelmäßig auf #: access/transam/xlog.c:5133 #, c-format msgid "recovery command file \"%s\" must specify restore_command when standby mode is not enabled" -msgstr "Recovery-Kommandodatei „%s“ muss restore_command angeben, wenn der Standby-Modus nicht eingeschaltet ist" +msgstr "Recovery-Kommandodatei »%s« muss restore_command angeben, wenn der Standby-Modus nicht eingeschaltet ist" #: access/transam/xlog.c:5163 #, c-format @@ -1671,7 +1671,7 @@ msgstr "Wiederherstellung beendet vor Abbruch der Transaktion %u, Zeit %s" #: access/transam/xlog.c:5483 #, c-format msgid "recovery stopping at restore point \"%s\", time %s" -msgstr "Wiederherstellung beendet bei Restore-Punkt „%s“, Zeit %s" +msgstr "Wiederherstellung beendet bei Restore-Punkt »%s«, Zeit %s" #: access/transam/xlog.c:5551 #, c-format @@ -1711,12 +1711,12 @@ msgstr "Das passiert, wenn vorübergehend wal_level=minimal gesetzt wurde, ohne #: access/transam/xlog.c:5844 #, c-format msgid "hot standby is not possible because wal_level was not set to \"hot_standby\" or higher on the master server" -msgstr "Hot Standby ist nicht möglich, weil wal_level auf dem Masterserver nicht auf „hot_standby“ oder höher gesetzt wurde" +msgstr "Hot Standby ist nicht möglich, weil wal_level auf dem Masterserver nicht auf »hot_standby« oder höher gesetzt wurde" #: access/transam/xlog.c:5845 #, c-format msgid "Either set wal_level to \"hot_standby\" on the master, or turn off hot_standby here." -msgstr "Setzen Sie entweder wal_level auf „hot_standby“ auf dem Master oder schalten Sie hot_standby hier aus." +msgstr "Setzen Sie entweder wal_level auf »hot_standby« auf dem Master oder schalten Sie hot_standby hier aus." #: access/transam/xlog.c:5902 #, c-format @@ -1781,7 +1781,7 @@ msgstr "starte Point-in-Time-Recovery bis %s" #: access/transam/xlog.c:6000 #, c-format msgid "starting point-in-time recovery to \"%s\"" -msgstr "starte Point-in-Time-Recovery bis „%s“" +msgstr "starte Point-in-Time-Recovery bis »%s«" #: access/transam/xlog.c:6004 #, c-format @@ -1811,7 +1811,7 @@ msgstr "konnte die vom Checkpoint-Datensatz referenzierte Redo-Position nicht fi #: access/transam/xlog.c:6066 access/transam/xlog.c:6073 #, c-format msgid "If you are not restoring from a backup, try removing the file \"%s/backup_label\"." -msgstr "Wenn Sie gerade keine Sicherung wiederherstellen, versuchen Sie, die Datei „%s/backup_label“ zu löschen." +msgstr "Wenn Sie gerade keine Sicherung wiederherstellen, versuchen Sie, die Datei »%s/backup_label« zu löschen." #: access/transam/xlog.c:6072 #, c-format @@ -1821,27 +1821,27 @@ msgstr "konnte den nötigen Checkpoint-Datensatz nicht finden" #: access/transam/xlog.c:6098 commands/tablespace.c:641 #, c-format msgid "could not create symbolic link \"%s\": %m" -msgstr "konnte symbolische Verknüpfung „%s“ nicht erstellen: %m" +msgstr "konnte symbolische Verknüpfung »%s« nicht erstellen: %m" #: access/transam/xlog.c:6130 #, c-format msgid "ignoring file \"%s\" because no file \"%s\" exists" -msgstr "ignoriere Datei „%s“, weil keine Datei „%s“ existiert" +msgstr "ignoriere Datei »%s«, weil keine Datei »%s« existiert" #: access/transam/xlog.c:6132 access/transam/xlog.c:10858 #, c-format msgid "File \"%s\" was renamed to \"%s\"." -msgstr "Datei „%s“ wurde in „%s“ umbenannt." +msgstr "Datei »%s« wurde in »%s« umbenannt." #: access/transam/xlog.c:6136 #, c-format msgid "ignoring \"%s\" file because no \"%s\" file exists" -msgstr "ignoriere Datei „%s“, weil keine Datei „%s“ existiert" +msgstr "ignoriere Datei »%s«, weil keine Datei »%s« existiert" #: access/transam/xlog.c:6138 #, c-format msgid "Could not rename file \"%s\" to \"%s\": %m." -msgstr "Konnte Datei „%s“ nicht in „%s“ umbenennen: %m." +msgstr "Konnte Datei »%s« nicht in »%s« umbenennen: %m." #: access/transam/xlog.c:6189 access/transam/xlog.c:6204 #, c-format @@ -2071,7 +2071,7 @@ msgstr "Recovery-Restart-Punkt bei %X/%X" #: access/transam/xlog.c:8986 #, c-format msgid "restore point \"%s\" created at %X/%X" -msgstr "Restore-Punkt „%s“ erzeugt bei %X/%X" +msgstr "Restore-Punkt »%s« erzeugt bei %X/%X" #: access/transam/xlog.c:9116 #, c-format @@ -2143,7 +2143,7 @@ msgstr "WAL-Level nicht ausreichend, um Online-Sicherung durchzuführen" #: access/transam/xlogfuncs.c:157 #, c-format msgid "wal_level must be set to \"archive\", \"hot_standby\", or \"logical\" at server start." -msgstr "wal_level muss beim Serverstart auf „archive“, „hot_standby“ oder „logical“ gesetzt werden." +msgstr "wal_level muss beim Serverstart auf »archive«, »hot_standby« oder »logical« gesetzt werden." #: access/transam/xlog.c:9764 #, c-format @@ -2175,13 +2175,13 @@ msgstr "Das bedeutet, dass die aktuelle Datensicherung auf dem Standby-Server ve #: utils/adt/misc.c:378 #, c-format msgid "could not read symbolic link \"%s\": %m" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen: %m" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen: %m" #: access/transam/xlog.c:9967 replication/basebackup.c:1040 #: utils/adt/misc.c:383 #, c-format msgid "symbolic link \"%s\" target is too long" -msgstr "Ziel für symbolische Verknüpfung „%s“ ist zu lang" +msgstr "Ziel für symbolische Verknüpfung »%s« ist zu lang" #: access/transam/xlog.c:10020 commands/tablespace.c:391 #: commands/tablespace.c:553 replication/basebackup.c:1056 @@ -2201,18 +2201,18 @@ msgstr "Tablespaces werden auf dieser Plattform nicht unterstützt" #: utils/adt/dbsize.c:298 utils/adt/genfile.c:114 utils/adt/genfile.c:333 #, c-format msgid "could not stat file \"%s\": %m" -msgstr "konnte „stat“ für Datei „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Datei »%s« nicht ausführen: %m" #: access/transam/xlog.c:10067 access/transam/xlog.c:10103 #, c-format msgid "If you're sure there is no backup in progress, remove file \"%s\" and try again." -msgstr "Wenn Sie sicher sind, dass noch kein Backup läuft, entfernen Sie die Datei „%s“ und versuchen Sie es noch einmal." +msgstr "Wenn Sie sicher sind, dass noch kein Backup läuft, entfernen Sie die Datei »%s« und versuchen Sie es noch einmal." #: access/transam/xlog.c:10084 access/transam/xlog.c:10120 #: access/transam/xlog.c:10445 #, c-format msgid "could not write file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht schreiben: %m" +msgstr "konnte Datei »%s« nicht schreiben: %m" #: access/transam/xlog.c:10274 #, c-format @@ -2224,7 +2224,7 @@ msgstr "es läuft kein Backup" #: access/transam/xlog.c:10762 access/transam/xlogfuncs.c:508 #, c-format msgid "invalid data in file \"%s\"" -msgstr "ungültige Daten in Datei „%s“" +msgstr "ungültige Daten in Datei »%s«" #: access/transam/xlog.c:10336 replication/basebackup.c:933 #, c-format @@ -2279,7 +2279,7 @@ msgstr "Online-Sicherungsmodus wurde nicht storniert" #: access/transam/xlog.c:10848 #, c-format msgid "File \"%s\" could not be renamed to \"%s\": %m." -msgstr "Konnte Datei „%s“ nicht in „%s“ umbenennen: %m." +msgstr "Konnte Datei »%s« nicht in »%s« umbenennen: %m." #: access/transam/xlog.c:10857 access/transam/xlog.c:10869 #: access/transam/xlog.c:10879 @@ -2290,12 +2290,12 @@ msgstr "Online-Sicherungsmodus storniert" #: access/transam/xlog.c:10870 #, c-format msgid "Files \"%s\" and \"%s\" were renamed to \"%s\" and \"%s\", respectively." -msgstr "Dateien „%s“ und „%s“ wurden in „%s“ und „%s“ umbenannt." +msgstr "Dateien »%s« und »%s« wurden in »%s« und »%s« umbenannt." #: access/transam/xlog.c:10880 #, c-format msgid "File \"%s\" was renamed to \"%s\", but file \"%s\" could not be renamed to \"%s\": %m." -msgstr "Datei „%s“ wurde in „%s“ umbenannt, aber Datei „%s“ konnte nicht in „%s“ umbenannt werden: %m." +msgstr "Datei »%s« wurde in »%s« umbenannt, aber Datei »%s« konnte nicht in »%s« umbenannt werden: %m." #: access/transam/xlog.c:11002 replication/logical/logicalfuncs.c:171 #: replication/walreceiver.c:932 replication/walsender.c:2112 @@ -2321,22 +2321,22 @@ msgstr "Triggerdatei gefunden: %s" #: access/transam/xlog.c:11510 #, c-format msgid "could not stat trigger file \"%s\": %m" -msgstr "konnte „stat“ für Trigger-Datei „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Trigger-Datei »%s« nicht ausführen: %m" #: access/transam/xlogarchive.c:244 #, c-format msgid "archive file \"%s\" has wrong size: %lu instead of %lu" -msgstr "Archivdatei „%s“ hat falsche Größe: %lu statt %lu" +msgstr "Archivdatei »%s« hat falsche Größe: %lu statt %lu" #: access/transam/xlogarchive.c:253 #, c-format msgid "restored log file \"%s\" from archive" -msgstr "Logdatei „%s“ aus Archiv wiederhergestellt" +msgstr "Logdatei »%s« aus Archiv wiederhergestellt" #: access/transam/xlogarchive.c:303 #, c-format msgid "could not restore file \"%s\" from archive: %s" -msgstr "konnte Datei „%s“ nicht aus Archiv wiederherstellen: %s" +msgstr "konnte Datei »%s« nicht aus Archiv wiederherstellen: %s" #. translator: First %s represents a recovery.conf parameter name like #. "recovery_end_command", the 2nd is the value of that parameter, the @@ -2344,24 +2344,24 @@ msgstr "konnte Datei „%s“ nicht aus Archiv wiederherstellen: %s" #: access/transam/xlogarchive.c:415 #, c-format msgid "%s \"%s\": %s" -msgstr "%s „%s“: %s" +msgstr "%s »%s«: %s" #: access/transam/xlogarchive.c:458 replication/logical/snapbuild.c:1602 #: replication/slot.c:470 replication/slot.c:926 replication/slot.c:1038 #: storage/file/fd.c:494 storage/file/fd.c:552 utils/time/snapmgr.c:1094 #, c-format msgid "could not rename file \"%s\" to \"%s\": %m" -msgstr "konnte Datei „%s“ nicht in „%s“ umbenennen: %m" +msgstr "konnte Datei »%s« nicht in »%s« umbenennen: %m" #: access/transam/xlogarchive.c:525 access/transam/xlogarchive.c:589 #, c-format msgid "could not create archive status file \"%s\": %m" -msgstr "konnte Archivstatusdatei „%s“ nicht erstellen: %m" +msgstr "konnte Archivstatusdatei »%s« nicht erstellen: %m" #: access/transam/xlogarchive.c:533 access/transam/xlogarchive.c:597 #, c-format msgid "could not write archive status file \"%s\": %m" -msgstr "konnte Archivstatusdatei „%s“ nicht schreiben: %m" +msgstr "konnte Archivstatusdatei »%s« nicht schreiben: %m" #: access/transam/xlogfuncs.c:61 access/transam/xlogfuncs.c:98 #, c-format @@ -2369,14 +2369,14 @@ msgid "must be superuser or replication role to run a backup" msgstr "nur Superuser und Replikationsrollen können ein Backup ausführen" #: access/transam/xlogfuncs.c:67 commands/tablespace.c:705 -#: commands/tablespace.c:715 postmaster/postmaster.c:1389 +#: commands/tablespace.c:715 postmaster/postmaster.c:1393 #: replication/basebackup.c:292 replication/basebackup.c:632 #: storage/file/copydir.c:53 storage/file/copydir.c:96 storage/file/fd.c:2092 #: storage/file/fd.c:2691 storage/ipc/dsm.c:300 utils/adt/genfile.c:439 #: utils/adt/misc.c:291 utils/misc/tzparser.c:339 #, c-format msgid "could not open directory \"%s\": %m" -msgstr "konnte Verzeichnis „%s“ nicht öffnen: %m" +msgstr "konnte Verzeichnis »%s« nicht öffnen: %m" #: access/transam/xlogfuncs.c:116 #, c-format @@ -2560,12 +2560,12 @@ msgstr "Datensatz mit ungültiger Länge bei %X/%X" msgid "invalid compressed image at %X/%X, block %d" msgstr "ungültiges komprimiertes Image bei %X/%X, Block %d" -#: bootstrap/bootstrap.c:268 postmaster/postmaster.c:779 tcop/postgres.c:3485 +#: bootstrap/bootstrap.c:268 postmaster/postmaster.c:779 tcop/postgres.c:3500 #, c-format msgid "--%s requires a value" msgstr "--%s benötigt einen Wert" -#: bootstrap/bootstrap.c:273 postmaster/postmaster.c:784 tcop/postgres.c:3490 +#: bootstrap/bootstrap.c:273 postmaster/postmaster.c:784 tcop/postgres.c:3505 #, c-format msgid "-c %s requires a value" msgstr "-c %s benötigt einen Wert" @@ -2574,7 +2574,7 @@ msgstr "-c %s benötigt einen Wert" #: postmaster/postmaster.c:809 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: bootstrap/bootstrap.c:293 #, c-format @@ -2589,42 +2589,42 @@ msgstr "Grant-Optionen können nur Rollen gewährt werden" #: catalog/aclchk.c:305 #, c-format msgid "no privileges were granted for column \"%s\" of relation \"%s\"" -msgstr "es wurden keine Privilegien für Spalte „%s“ von Relation „%s“ gewährt" +msgstr "es wurden keine Privilegien für Spalte »%s« von Relation »%s« gewährt" #: catalog/aclchk.c:310 #, c-format msgid "no privileges were granted for \"%s\"" -msgstr "es wurden keine Privilegien für „%s“ gewährt" +msgstr "es wurden keine Privilegien für »%s« gewährt" #: catalog/aclchk.c:318 #, c-format msgid "not all privileges were granted for column \"%s\" of relation \"%s\"" -msgstr "es wurden nicht alle Priviligien für Spalte „%s“ von Relation „%s“ gewährt" +msgstr "es wurden nicht alle Priviligien für Spalte »%s« von Relation »%s« gewährt" #: catalog/aclchk.c:323 #, c-format msgid "not all privileges were granted for \"%s\"" -msgstr "es wurden nicht alle Priviligien für „%s“ gewährt" +msgstr "es wurden nicht alle Priviligien für »%s« gewährt" #: catalog/aclchk.c:334 #, c-format msgid "no privileges could be revoked for column \"%s\" of relation \"%s\"" -msgstr "es konnten keine Privilegien für Spalte „%s“ von Relation „%s“ entzogen werden" +msgstr "es konnten keine Privilegien für Spalte »%s« von Relation »%s« entzogen werden" #: catalog/aclchk.c:339 #, c-format msgid "no privileges could be revoked for \"%s\"" -msgstr "es konnten keine Privilegien für „%s“ entzogen werden" +msgstr "es konnten keine Privilegien für »%s« entzogen werden" #: catalog/aclchk.c:347 #, c-format msgid "not all privileges could be revoked for column \"%s\" of relation \"%s\"" -msgstr "es konnten nicht alle Privilegien für Spalte „%s“ von Relation „%s“ entzogen werden" +msgstr "es konnten nicht alle Privilegien für Spalte »%s« von Relation »%s« entzogen werden" #: catalog/aclchk.c:352 #, c-format msgid "not all privileges could be revoked for \"%s\"" -msgstr "es konnten nicht alle Privilegien für „%s“ entzogen werden" +msgstr "es konnten nicht alle Privilegien für »%s« entzogen werden" #: catalog/aclchk.c:434 catalog/aclchk.c:924 #, c-format @@ -2691,7 +2691,7 @@ msgstr "ungültiger Privilegtyp %s für Fremdserver" msgid "column privileges are only valid for relations" msgstr "Spaltenprivilegien sind nur für Relation gültig" -#: catalog/aclchk.c:676 catalog/aclchk.c:3874 catalog/aclchk.c:4651 +#: catalog/aclchk.c:676 catalog/aclchk.c:3874 catalog/aclchk.c:4656 #: catalog/objectaddress.c:854 catalog/pg_largeobject.c:113 #: storage/large_object/inv_api.c:291 #, c-format @@ -2750,7 +2750,7 @@ msgstr "Vorgabeprivilegien können nicht für Spalten gesetzt werden" #: utils/adt/ruleutils.c:1856 #, c-format msgid "column \"%s\" of relation \"%s\" does not exist" -msgstr "Spalte „%s“ von Relation „%s“ existiert nicht" +msgstr "Spalte »%s« von Relation »%s« existiert nicht" #: catalog/aclchk.c:1748 catalog/objectaddress.c:1151 commands/sequence.c:1078 #: commands/tablecmds.c:221 commands/tablecmds.c:11970 utils/adt/acl.c:2075 @@ -2758,12 +2758,12 @@ msgstr "Spalte „%s“ von Relation „%s“ existiert nicht" #: utils/adt/acl.c:2197 utils/adt/acl.c:2227 #, c-format msgid "\"%s\" is not a sequence" -msgstr "„%s“ ist keine Sequenz" +msgstr "»%s« ist keine Sequenz" #: catalog/aclchk.c:1786 #, c-format msgid "sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges" -msgstr "Sequenz „%s“ unterstützt nur die Privilegien USAGE, SELECT und UPDATE" +msgstr "Sequenz »%s« unterstützt nur die Privilegien USAGE, SELECT und UPDATE" #: catalog/aclchk.c:1803 #, c-format @@ -2778,12 +2778,12 @@ msgstr "ungültiger Privilegtyp %s für Spalte" #: catalog/aclchk.c:1981 #, c-format msgid "sequence \"%s\" only supports SELECT column privileges" -msgstr "Sequenz „%s“ unterstützt nur den Spaltenprivilegientyp SELECT" +msgstr "Sequenz »%s« unterstützt nur den Spaltenprivilegientyp SELECT" #: catalog/aclchk.c:2565 #, c-format msgid "language \"%s\" is not trusted" -msgstr "Sprache „%s“ ist nicht „trusted“" +msgstr "Sprache »%s« ist nicht »trusted«" #: catalog/aclchk.c:2567 #, c-format @@ -2803,12 +2803,12 @@ msgstr "Setzen Sie stattdessen die Privilegien des Elementtyps." #: catalog/aclchk.c:3091 catalog/objectaddress.c:1471 commands/typecmds.c:3142 #, c-format msgid "\"%s\" is not a domain" -msgstr "„%s“ ist keine Domäne" +msgstr "»%s« ist keine Domäne" #: catalog/aclchk.c:3211 #, c-format msgid "unrecognized privilege type \"%s\"" -msgstr "unbekannter Privilegtyp „%s“" +msgstr "unbekannter Privilegtyp »%s«" #: catalog/aclchk.c:3260 #, c-format @@ -3019,99 +3019,99 @@ msgstr "Berechtigung nur für Eigentümer der Erweiterung %s" #: catalog/aclchk.c:3388 #, c-format msgid "permission denied for column \"%s\" of relation \"%s\"" -msgstr "keine Berechtigung für Spalte „%s“ von Relation „%s“" +msgstr "keine Berechtigung für Spalte »%s« von Relation »%s«" #: catalog/aclchk.c:3507 catalog/aclchk.c:3515 #, c-format msgid "attribute %d of relation with OID %u does not exist" msgstr "Attribut %d der Relation mit OID %u existiert nicht" -#: catalog/aclchk.c:3588 catalog/aclchk.c:4502 +#: catalog/aclchk.c:3588 catalog/aclchk.c:4507 #, c-format msgid "relation with OID %u does not exist" msgstr "Relation mit OID %u existiert nicht" -#: catalog/aclchk.c:3687 catalog/aclchk.c:4920 +#: catalog/aclchk.c:3687 catalog/aclchk.c:4925 #, c-format msgid "database with OID %u does not exist" msgstr "Datenbank mit OID %u existiert nicht" -#: catalog/aclchk.c:3741 catalog/aclchk.c:4580 tcop/fastpath.c:223 +#: catalog/aclchk.c:3741 catalog/aclchk.c:4585 tcop/fastpath.c:223 #, c-format msgid "function with OID %u does not exist" msgstr "Funktion mit OID %u existiert nicht" -#: catalog/aclchk.c:3795 catalog/aclchk.c:4606 +#: catalog/aclchk.c:3795 catalog/aclchk.c:4611 #, c-format msgid "language with OID %u does not exist" msgstr "Sprache mit OID %u existiert nicht" -#: catalog/aclchk.c:3959 catalog/aclchk.c:4678 +#: catalog/aclchk.c:3959 catalog/aclchk.c:4683 #, c-format msgid "schema with OID %u does not exist" msgstr "Schema mit OID %u existiert nicht" -#: catalog/aclchk.c:4013 catalog/aclchk.c:4705 +#: catalog/aclchk.c:4013 catalog/aclchk.c:4710 #, c-format msgid "tablespace with OID %u does not exist" msgstr "Tablespace mit OID %u existiert nicht" -#: catalog/aclchk.c:4071 catalog/aclchk.c:4839 commands/foreigncmds.c:325 +#: catalog/aclchk.c:4072 catalog/aclchk.c:4844 commands/foreigncmds.c:325 #, c-format msgid "foreign-data wrapper with OID %u does not exist" msgstr "Fremddaten-Wrapper mit OID %u existiert nicht" -#: catalog/aclchk.c:4132 catalog/aclchk.c:4866 commands/foreigncmds.c:461 +#: catalog/aclchk.c:4134 catalog/aclchk.c:4871 commands/foreigncmds.c:461 #, c-format msgid "foreign server with OID %u does not exist" msgstr "Fremdserver mit OID %u existiert nicht" -#: catalog/aclchk.c:4191 catalog/aclchk.c:4205 catalog/aclchk.c:4528 +#: catalog/aclchk.c:4194 catalog/aclchk.c:4533 #, c-format msgid "type with OID %u does not exist" msgstr "Typ mit OID %u existiert nicht" -#: catalog/aclchk.c:4554 +#: catalog/aclchk.c:4559 #, c-format msgid "operator with OID %u does not exist" msgstr "Operator mit OID %u existiert nicht" -#: catalog/aclchk.c:4731 +#: catalog/aclchk.c:4736 #, c-format msgid "operator class with OID %u does not exist" msgstr "Operatorklasse mit OID %u existiert nicht" -#: catalog/aclchk.c:4758 +#: catalog/aclchk.c:4763 #, c-format msgid "operator family with OID %u does not exist" msgstr "Operatorfamilie mit OID %u existiert nicht" -#: catalog/aclchk.c:4785 +#: catalog/aclchk.c:4790 #, c-format msgid "text search dictionary with OID %u does not exist" msgstr "Textsuchewörterbuch mit OID %u existiert nicht" -#: catalog/aclchk.c:4812 +#: catalog/aclchk.c:4817 #, c-format msgid "text search configuration with OID %u does not exist" msgstr "Textsuchekonfiguration mit OID %u existiert nicht" -#: catalog/aclchk.c:4893 commands/event_trigger.c:586 +#: catalog/aclchk.c:4898 commands/event_trigger.c:586 #, c-format msgid "event trigger with OID %u does not exist" msgstr "Ereignistrigger mit OID %u existiert nicht" -#: catalog/aclchk.c:4946 +#: catalog/aclchk.c:4951 #, c-format msgid "collation with OID %u does not exist" msgstr "Sortierfolge mit OID %u existiert nicht" -#: catalog/aclchk.c:4972 +#: catalog/aclchk.c:4977 #, c-format msgid "conversion with OID %u does not exist" msgstr "Konversion mit OID %u existiert nicht" -#: catalog/aclchk.c:5013 +#: catalog/aclchk.c:5018 #, c-format msgid "extension with OID %u does not exist" msgstr "Erweiterung mit OID %u existiert nicht" @@ -3187,12 +3187,12 @@ msgstr[1] "Löschvorgang löscht ebenfalls %d weitere Objekte" #: catalog/dependency.c:1622 #, c-format msgid "constant of the type \"regrole\" cannot be used here" -msgstr "Konstante vom Typ „regrole“ kann hier nicht verwendet werden" +msgstr "Konstante vom Typ »regrole« kann hier nicht verwendet werden" #: catalog/heap.c:276 #, c-format msgid "permission denied to create \"%s.%s\"" -msgstr "keine Berechtigung, um „%s.%s“ zu erzeugen" +msgstr "keine Berechtigung, um »%s.%s« zu erzeugen" #: catalog/heap.c:278 #, c-format @@ -3208,17 +3208,17 @@ msgstr "Tabellen können höchstens %d Spalten haben" #: catalog/heap.c:430 commands/tablecmds.c:5063 #, c-format msgid "column name \"%s\" conflicts with a system column name" -msgstr "Spaltenname „%s“ steht im Konflikt mit dem Namen einer Systemspalte" +msgstr "Spaltenname »%s« steht im Konflikt mit dem Namen einer Systemspalte" #: catalog/heap.c:446 #, c-format msgid "column name \"%s\" specified more than once" -msgstr "Spaltenname „%s“ mehrmals angegeben" +msgstr "Spaltenname »%s« mehrmals angegeben" #: catalog/heap.c:496 #, c-format msgid "column \"%s\" has type \"unknown\"" -msgstr "Spalte „%s“ hat Typ „unknown“" +msgstr "Spalte »%s« hat Typ »unknown«" #: catalog/heap.c:497 #, c-format @@ -3228,24 +3228,25 @@ msgstr "Relation wird trotzdem erzeugt." #: catalog/heap.c:510 #, c-format msgid "column \"%s\" has pseudo-type %s" -msgstr "Spalte „%s“ hat Pseudotyp %s" +msgstr "Spalte »%s« hat Pseudotyp %s" #: catalog/heap.c:540 #, 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:582 commands/createas.c:373 +#: catalog/heap.c:582 commands/createas.c:201 commands/createas.c:497 #, 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" +msgstr "für Spalte »%s« mit sortierbarem Typ %s wurde keine Sortierfolge abgeleitet" -#: catalog/heap.c:584 commands/createas.c:375 commands/indexcmds.c:1087 -#: commands/view.c:116 regex/regc_pg_locale.c:262 utils/adt/formatting.c:1514 -#: utils/adt/formatting.c:1566 utils/adt/formatting.c:1634 -#: utils/adt/formatting.c:1686 utils/adt/formatting.c:1755 -#: utils/adt/formatting.c:1819 utils/adt/like.c:213 utils/adt/selfuncs.c:5276 -#: utils/adt/varlena.c:1411 utils/adt/varlena.c:1800 +#: catalog/heap.c:584 commands/createas.c:204 commands/createas.c:500 +#: commands/indexcmds.c:1087 commands/view.c:105 regex/regc_pg_locale.c:262 +#: utils/adt/formatting.c:1513 utils/adt/formatting.c:1565 +#: utils/adt/formatting.c:1633 utils/adt/formatting.c:1685 +#: utils/adt/formatting.c:1754 utils/adt/formatting.c:1818 +#: utils/adt/like.c:213 utils/adt/selfuncs.c:5276 utils/adt/varlena.c:1411 +#: utils/adt/varlena.c:1800 #, c-format msgid "Use the COLLATE clause to set the collation explicitly." msgstr "Verwenden Sie die COLLATE-Klausel, um die Sortierfolge explizit zu setzen." @@ -3253,14 +3254,14 @@ msgstr "Verwenden Sie die COLLATE-Klausel, um die Sortierfolge explizit zu setze #: catalog/heap.c:1065 catalog/index.c:793 commands/tablecmds.c:2614 #, c-format msgid "relation \"%s\" already exists" -msgstr "Relation „%s“ existiert bereits" +msgstr "Relation »%s« existiert bereits" #: catalog/heap.c:1081 catalog/pg_type.c:412 catalog/pg_type.c:722 #: commands/typecmds.c:235 commands/typecmds.c:782 commands/typecmds.c:1133 #: commands/typecmds.c:1355 commands/typecmds.c:2109 #, c-format msgid "type \"%s\" already exists" -msgstr "Typ „%s“ existiert bereits" +msgstr "Typ »%s« existiert bereits" #: catalog/heap.c:1082 #, c-format @@ -3275,22 +3276,22 @@ msgstr "Heap-OID-Wert für pg_class ist im Binary-Upgrade-Modus nicht gesetzt" #: catalog/heap.c:2290 #, c-format msgid "check constraint \"%s\" already exists" -msgstr "Check-Constraint „%s“ existiert bereits" +msgstr "Check-Constraint »%s« existiert bereits" #: catalog/heap.c:2445 catalog/pg_constraint.c:652 commands/tablecmds.c:6038 #, c-format msgid "constraint \"%s\" for relation \"%s\" already exists" -msgstr "Constraint „%s“ existiert bereits für Relation „%s“" +msgstr "Constraint »%s« existiert bereits für Relation »%s«" #: catalog/heap.c:2455 #, 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“" +msgstr "Constraint »%s« kollidiert mit nicht vererbtem Constraint für Relation »%s«" #: catalog/heap.c:2469 #, c-format msgid "merging constraint \"%s\" with inherited definition" -msgstr "Constraint „%s“ wird mit geerbter Definition zusammengeführt" +msgstr "Constraint »%s« wird mit geerbter Definition zusammengeführt" #: catalog/heap.c:2562 #, c-format @@ -3305,7 +3306,7 @@ msgstr "Vorgabeausdruck kann keine Ergebnismenge zurückgeben" #: catalog/heap.c:2592 rewrite/rewriteHandler.c:1077 #, 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" +msgstr "Spalte »%s« hat Typ %s, aber der Vorgabeausdruck hat Typ %s" #: catalog/heap.c:2597 commands/prepare.c:374 parser/parse_node.c:411 #: parser/parse_target.c:528 parser/parse_target.c:778 @@ -3317,7 +3318,7 @@ msgstr "Sie müssen den Ausdruck umschreiben oder eine Typumwandlung vornehmen." #: catalog/heap.c:2644 #, c-format msgid "only table \"%s\" can be referenced in check constraint" -msgstr "nur Verweise auf Tabelle „%s“ sind im Check-Constraint zugelassen" +msgstr "nur Verweise auf Tabelle »%s« sind im Check-Constraint zugelassen" #: catalog/heap.c:2884 #, c-format @@ -3327,7 +3328,7 @@ msgstr "nicht unterstützte Kombination aus ON COMMIT und Fremdschlüssel" #: catalog/heap.c:2885 #, 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." +msgstr "Tabelle »%s« verweist auf »%s«, aber sie haben nicht die gleiche ON-COMMIT-Einstellung." #: catalog/heap.c:2890 #, c-format @@ -3337,17 +3338,17 @@ msgstr "kann eine Tabelle, die in einen Fremdschlüssel-Constraint eingebunden i #: catalog/heap.c:2891 #, c-format msgid "Table \"%s\" references \"%s\"." -msgstr "Tabelle „%s“ verweist auf „%s“." +msgstr "Tabelle »%s« verweist auf »%s«." #: catalog/heap.c:2893 #, 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." +msgstr "Leeren Sie die Tabelle »%s« gleichzeitig oder verwenden Sie TRUNCATE ... CASCADE." -#: catalog/index.c:205 parser/parse_utilcmd.c:1436 parser/parse_utilcmd.c:1522 +#: catalog/index.c:205 parser/parse_utilcmd.c:1438 parser/parse_utilcmd.c:1524 #, c-format msgid "multiple primary keys for table \"%s\" are not allowed" -msgstr "mehrere Primärschlüssel für Tabelle „%s“ nicht erlaubt" +msgstr "mehrere Primärschlüssel für Tabelle »%s« nicht erlaubt" #: catalog/index.c:223 #, c-format @@ -3369,11 +3370,11 @@ msgstr "nebenläufige Indexerzeugung für Systemkatalogtabellen wird nicht unter msgid "shared indexes cannot be created after initdb" msgstr "Cluster-globale Indexe können nicht nach initdb erzeugt werden" -#: catalog/index.c:785 commands/createas.c:100 commands/sequence.c:141 +#: catalog/index.c:785 commands/createas.c:249 commands/sequence.c:141 #: parser/parse_utilcmd.c:185 #, c-format msgid "relation \"%s\" already exists, skipping" -msgstr "Relation „%s“ existiert bereits, wird übersprungen" +msgstr "Relation »%s« existiert bereits, wird übersprungen" #: catalog/index.c:821 #, c-format @@ -3388,7 +3389,7 @@ msgstr "DROP INDEX CONCURRENTLY muss die erste Aktion in einer Transaktion sein" #: catalog/index.c:2007 #, c-format msgid "building index \"%s\" on table \"%s\"" -msgstr "baue Index „%s“ von Tabelle „%s“" +msgstr "baue Index »%s« von Tabelle »%s«" #: catalog/index.c:3262 #, c-format @@ -3398,7 +3399,7 @@ msgstr "kann temporäre Tabellen anderer Sitzungen nicht reindizieren" #: catalog/index.c:3387 #, c-format msgid "index \"%s\" was reindexed" -msgstr "Index „%s“ wurde neu indiziert" +msgstr "Index »%s« wurde neu indiziert" #: catalog/index.c:3389 commands/vacuumlazy.c:1135 commands/vacuumlazy.c:1211 #: commands/vacuumlazy.c:1378 commands/vacuumlazy.c:1550 @@ -3410,7 +3411,7 @@ msgstr "%s." #: commands/trigger.c:4528 #, c-format msgid "cross-database references are not implemented: \"%s.%s.%s\"" -msgstr "Verweise auf andere Datenbanken sind nicht implementiert: „%s.%s.%s“" +msgstr "Verweise auf andere Datenbanken sind nicht implementiert: »%s.%s.%s«" #: catalog/namespace.c:306 #, c-format @@ -3420,23 +3421,23 @@ msgstr "temporäre Tabellen können keinen Schemanamen angeben" #: catalog/namespace.c:385 #, c-format msgid "could not obtain lock on relation \"%s.%s\"" -msgstr "konnte Sperre für Relation „%s.%s“ nicht setzen" +msgstr "konnte Sperre für Relation »%s.%s« nicht setzen" #: catalog/namespace.c:390 commands/lockcmds.c:146 #, c-format msgid "could not obtain lock on relation \"%s\"" -msgstr "konnte Sperre für Relation „%s“ nicht setzen" +msgstr "konnte Sperre für Relation »%s« nicht setzen" #: catalog/namespace.c:414 parser/parse_relation.c:1137 #, c-format msgid "relation \"%s.%s\" does not exist" -msgstr "Relation „%s.%s“ existiert nicht" +msgstr "Relation »%s.%s« existiert nicht" #: catalog/namespace.c:419 parser/parse_relation.c:1150 #: parser/parse_relation.c:1158 utils/adt/regproc.c:1034 #, c-format msgid "relation \"%s\" does not exist" -msgstr "Relation „%s“ existiert nicht" +msgstr "Relation »%s« existiert nicht" #: catalog/namespace.c:487 catalog/namespace.c:2852 commands/extension.c:1394 #: commands/extension.c:1400 @@ -3462,30 +3463,30 @@ msgstr "nur temporäre Relationen können in temporären Schemas erzeugt werden" #: catalog/namespace.c:2154 #, c-format msgid "text search parser \"%s\" does not exist" -msgstr "Textsucheparser „%s“ existiert nicht" +msgstr "Textsucheparser »%s« existiert nicht" #: catalog/namespace.c:2280 #, c-format msgid "text search dictionary \"%s\" does not exist" -msgstr "Textsuchewörterbuch „%s“ existiert nicht" +msgstr "Textsuchewörterbuch »%s« existiert nicht" #: catalog/namespace.c:2407 #, c-format msgid "text search template \"%s\" does not exist" -msgstr "Textsuchevorlage „%s“ existiert nicht" +msgstr "Textsuchevorlage »%s« existiert nicht" #: catalog/namespace.c:2533 commands/tsearchcmds.c:1197 #: utils/cache/ts_cache.c:613 #, c-format msgid "text search configuration \"%s\" does not exist" -msgstr "Textsuchekonfiguration „%s“ existiert nicht" +msgstr "Textsuchekonfiguration »%s« existiert nicht" #: catalog/namespace.c:2646 parser/parse_expr.c:789 parser/parse_target.c:1130 #, c-format msgid "cross-database references are not implemented: %s" msgstr "Verweise auf andere Datenbanken sind nicht implementiert: %s" -#: catalog/namespace.c:2652 gram.y:13305 gram.y:14659 parser/parse_expr.c:796 +#: catalog/namespace.c:2652 gram.y:13305 gram.y:14671 parser/parse_expr.c:796 #: parser/parse_target.c:1137 #, c-format msgid "improper qualified name (too many dotted names): %s" @@ -3494,7 +3495,7 @@ msgstr "falscher qualifizierter Name (zu viele Namensteile): %s" #: catalog/namespace.c:2786 #, c-format msgid "%s is already in schema \"%s\"" -msgstr "%s ist bereits in Schema „%s“" +msgstr "%s ist bereits in Schema »%s«" #: catalog/namespace.c:2794 #, c-format @@ -3510,7 +3511,7 @@ msgstr "Objekte können nicht in oder aus TOAST-Schemas verschoben werden" #: commands/schemacmds.c:317 commands/tablecmds.c:736 #, c-format msgid "schema \"%s\" does not exist" -msgstr "Schema „%s“ existiert nicht" +msgstr "Schema »%s« existiert nicht" #: catalog/namespace.c:2904 #, c-format @@ -3520,17 +3521,17 @@ msgstr "falscher Relationsname (zu viele Namensteile): %s" #: catalog/namespace.c:3369 #, c-format msgid "collation \"%s\" for encoding \"%s\" does not exist" -msgstr "Sortierfolge „%s“ für Kodierung „%s“ existiert nicht" +msgstr "Sortierfolge »%s« für Kodierung »%s« existiert nicht" #: catalog/namespace.c:3424 #, c-format msgid "conversion \"%s\" does not exist" -msgstr "Konversion „%s“ existiert nicht" +msgstr "Konversion »%s« existiert nicht" #: catalog/namespace.c:3632 #, c-format msgid "permission denied to create temporary tables in database \"%s\"" -msgstr "keine Berechtigung, um temporäre Tabellen in Datenbank „%s“ zu erzeugen" +msgstr "keine Berechtigung, um temporäre Tabellen in Datenbank »%s« zu erzeugen" #: catalog/namespace.c:3648 #, c-format @@ -3591,25 +3592,25 @@ msgstr "Ereignistriggername kann nicht qualifiziert werden" #: commands/tablecmds.c:7947 #, c-format msgid "\"%s\" is not a table" -msgstr "„%s“ ist keine Tabelle" +msgstr "»%s« ist keine Tabelle" #: catalog/objectaddress.c:1165 commands/tablecmds.c:227 -#: commands/tablecmds.c:4368 commands/tablecmds.c:11975 commands/view.c:155 +#: commands/tablecmds.c:4368 commands/tablecmds.c:11975 commands/view.c:143 #, c-format msgid "\"%s\" is not a view" -msgstr "„%s“ ist keine Sicht" +msgstr "»%s« ist keine Sicht" #: catalog/objectaddress.c:1172 commands/matview.c:174 #: commands/tablecmds.c:233 commands/tablecmds.c:11980 #, c-format msgid "\"%s\" is not a materialized view" -msgstr "„%s“ ist keine materialisierte Sicht" +msgstr "»%s« ist keine materialisierte Sicht" #: catalog/objectaddress.c:1179 commands/tablecmds.c:251 #: commands/tablecmds.c:4371 commands/tablecmds.c:11985 #, c-format msgid "\"%s\" is not a foreign table" -msgstr "„%s“ ist keine Fremdtabelle" +msgstr "»%s« ist keine Fremdtabelle" #: catalog/objectaddress.c:1324 catalog/objectaddress.c:1377 #, c-format @@ -3619,7 +3620,7 @@ msgstr "Spaltenname muss qualifiziert werden" #: catalog/objectaddress.c:1420 #, c-format msgid "default value for column \"%s\" of relation \"%s\" does not exist" -msgstr "Vorgabewert für Spalte „%s“ von Relation „%s“ existiert nicht" +msgstr "Vorgabewert für Spalte »%s« von Relation »%s« existiert nicht" #: catalog/objectaddress.c:1460 commands/functioncmds.c:128 #: commands/tablecmds.c:243 commands/typecmds.c:3210 parser/parse_type.c:226 @@ -3627,7 +3628,7 @@ msgstr "Vorgabewert für Spalte „%s“ von Relation „%s“ existiert nicht" #: utils/adt/regproc.c:1225 #, c-format msgid "type \"%s\" does not exist" -msgstr "Typ „%s“ existiert nicht" +msgstr "Typ »%s« existiert nicht" #: catalog/objectaddress.c:1577 #, c-format @@ -3642,14 +3643,14 @@ msgstr "Funktion %d (%s, %s) von %s existiert nicht" #: catalog/objectaddress.c:1655 catalog/objectaddress.c:1681 #, c-format msgid "user mapping for user \"%s\" on server \"%s\" does not exist" -msgstr "Benutzerabbildung für Benutzer „%s“ auf Server „%s“ existiert nicht" +msgstr "Benutzerabbildung für Benutzer »%s« auf Server »%s« existiert nicht" #: catalog/objectaddress.c:1670 commands/foreigncmds.c:430 #: commands/foreigncmds.c:997 commands/foreigncmds.c:1359 #: foreign/foreign.c:691 #, c-format msgid "server \"%s\" does not exist" -msgstr "Server „%s“ existiert nicht" +msgstr "Server »%s« existiert nicht" #: catalog/objectaddress.c:1742 #, c-format @@ -3659,17 +3660,17 @@ msgstr "unbekannter Standard-ACL-Objekttyp %c" #: catalog/objectaddress.c:1743 #, c-format msgid "Valid object types are \"r\", \"S\", \"f\", and \"T\"." -msgstr "Gültige Objekttypen sind „r“, „S“, „f“ und „T“." +msgstr "Gültige Objekttypen sind »r«, »S«, »f« und »T«." #: catalog/objectaddress.c:1789 #, c-format msgid "default ACL for user \"%s\" in schema \"%s\" on %s does not exist" -msgstr "Standard-ACL für Benutzer „%s“ in Schema „%s“ für %s existiert nicht" +msgstr "Standard-ACL für Benutzer »%s« in Schema »%s« für %s existiert nicht" #: catalog/objectaddress.c:1794 #, c-format msgid "default ACL for user \"%s\" on %s does not exist" -msgstr "Standard-ACL für Benutzer „%s“ für %s existiert nicht" +msgstr "Standard-ACL für Benutzer »%s« für %s existiert nicht" #: catalog/objectaddress.c:1821 catalog/objectaddress.c:1877 #: catalog/objectaddress.c:1932 @@ -3680,7 +3681,7 @@ msgstr "Namens- oder Argumentlisten dürfen keine NULL-Werte enthalten" #: catalog/objectaddress.c:1853 #, c-format msgid "unsupported object type \"%s\"" -msgstr "nicht unterstützter Objekttyp „%s“" +msgstr "nicht unterstützter Objekttyp »%s«" #: catalog/objectaddress.c:1873 catalog/objectaddress.c:1891 #, c-format @@ -3726,7 +3727,7 @@ msgstr "Berechtigung nur mit CREATEROLE-Privileg" #: catalog/objectaddress.c:2254 #, c-format msgid "unrecognized object type \"%s\"" -msgstr "unbekannter Objekttyp „%s“" +msgstr "unbekannter Objekttyp »%s«" #: catalog/objectaddress.c:2449 #, c-format @@ -4041,12 +4042,12 @@ msgstr "Eine Aggregatfunktion, die einen polymorphischen Typ zurückgibt, muss m #: catalog/pg_aggregate.c:423 catalog/pg_proc.c:258 #, c-format msgid "unsafe use of pseudo-type \"internal\"" -msgstr "unsichere Verwendung des Pseudotyps „internal“" +msgstr "unsichere Verwendung des Pseudotyps »internal«" #: catalog/pg_aggregate.c:424 catalog/pg_proc.c:259 #, c-format msgid "A function returning \"internal\" must have at least one \"internal\" argument." -msgstr "Eine Funktion, die „internal“ zurückgibt, muss mindestens ein Argument vom Typ „internal“ haben." +msgstr "Eine Funktion, die »internal« zurückgibt, muss mindestens ein Argument vom Typ »internal« haben." #: catalog/pg_aggregate.c:477 #, c-format @@ -4086,42 +4087,42 @@ msgstr "Funktion %s erfordert Typumwandlung zur Laufzeit" #: catalog/pg_collation.c:77 #, c-format msgid "collation \"%s\" for encoding \"%s\" already exists" -msgstr "Sortierfolge „%s“ für Kodierung „%s“ existiert bereits" +msgstr "Sortierfolge »%s« für Kodierung »%s« existiert bereits" #: catalog/pg_collation.c:91 #, c-format msgid "collation \"%s\" already exists" -msgstr "Sortierfolge „%s“ existiert bereits" +msgstr "Sortierfolge »%s« existiert bereits" #: catalog/pg_constraint.c:661 #, c-format msgid "constraint \"%s\" for domain %s already exists" -msgstr "Constraint „%s“ für Domäne %s existiert bereits" +msgstr "Constraint »%s« für Domäne %s existiert bereits" #: catalog/pg_constraint.c:794 #, c-format msgid "table \"%s\" has multiple constraints named \"%s\"" -msgstr "Tabelle „%s“ hat mehrere Constraints namens „%s“" +msgstr "Tabelle »%s« hat mehrere Constraints namens »%s«" #: catalog/pg_constraint.c:806 #, c-format msgid "constraint \"%s\" for table \"%s\" does not exist" -msgstr "Constraint „%s“ für Tabelle „%s“ existiert nicht" +msgstr "Constraint »%s« für Tabelle »%s« existiert nicht" #: catalog/pg_constraint.c:852 #, c-format msgid "domain \"%s\" has multiple constraints named \"%s\"" -msgstr "Domäne „%s“ hat mehrere Constraints namens „%s“" +msgstr "Domäne »%s« hat mehrere Constraints namens »%s«" #: catalog/pg_constraint.c:864 #, c-format msgid "constraint \"%s\" for domain \"%s\" does not exist" -msgstr "Constraint „%s“ für Domäne „%s“ existiert nicht" +msgstr "Constraint »%s« für Domäne »%s« existiert nicht" #: catalog/pg_conversion.c:66 #, c-format msgid "conversion \"%s\" already exists" -msgstr "Konversion „%s“ existiert bereits" +msgstr "Konversion »%s« existiert bereits" #: catalog/pg_conversion.c:79 #, c-format @@ -4131,7 +4132,7 @@ msgstr "Standardumwandlung von %s nach %s existiert bereits" #: catalog/pg_depend.c:165 commands/extension.c:2945 #, c-format msgid "%s is already a member of extension \"%s\"" -msgstr "%s ist schon Mitglied der Erweiterung „%s“" +msgstr "%s ist schon Mitglied der Erweiterung »%s«" #: catalog/pg_depend.c:324 #, c-format @@ -4141,7 +4142,7 @@ msgstr "kann Abhängigkeit von %s nicht entfernen, weil es ein Systemobjekt ist" #: catalog/pg_enum.c:115 catalog/pg_enum.c:202 #, c-format msgid "invalid enum label \"%s\"" -msgstr "ungültiges Enum-Label „%s“" +msgstr "ungültiges Enum-Label »%s«" #: catalog/pg_enum.c:116 catalog/pg_enum.c:203 #, c-format @@ -4151,17 +4152,17 @@ msgstr "Labels müssen %d oder weniger Zeichen haben." #: catalog/pg_enum.c:231 #, c-format msgid "enum label \"%s\" already exists, skipping" -msgstr "Enum-Label „%s“ existiert bereits, wird übersprungen" +msgstr "Enum-Label »%s« existiert bereits, wird übersprungen" #: catalog/pg_enum.c:238 #, c-format msgid "enum label \"%s\" already exists" -msgstr "Enum-Label „%s“ existiert bereits" +msgstr "Enum-Label »%s« existiert bereits" #: catalog/pg_enum.c:293 #, c-format msgid "\"%s\" is not an existing enum label" -msgstr "„%s“ ist kein existierendes Enum-Label" +msgstr "»%s« ist kein existierendes Enum-Label" #: catalog/pg_enum.c:349 #, c-format @@ -4176,12 +4177,12 @@ msgstr "ALTER TYPE ADD BEFORE/AFTER ist mit Binary Upgrade inkompatibel" #: catalog/pg_namespace.c:61 commands/schemacmds.c:246 #, c-format msgid "schema \"%s\" already exists" -msgstr "Schema „%s“ existiert bereits" +msgstr "Schema »%s« existiert bereits" #: catalog/pg_operator.c:223 catalog/pg_operator.c:364 #, c-format msgid "\"%s\" is not a valid operator name" -msgstr "„%s“ ist kein gültiger Operatorname" +msgstr "»%s« ist kein gültiger Operatorname" #: catalog/pg_operator.c:373 #, c-format @@ -4253,17 +4254,17 @@ msgstr "Eine Funktion, die einen polymorphischen Typ zurückgibt, muss mindesten #: catalog/pg_proc.c:253 #, c-format msgid "A function returning \"anyrange\" must have at least one \"anyrange\" argument." -msgstr "Eine Funktion, die „anyrange“ zurückgibt, muss mindestens ein Argument vom Typ „anyrange“ haben." +msgstr "Eine Funktion, die »anyrange« zurückgibt, muss mindestens ein Argument vom Typ »anyrange« haben." #: catalog/pg_proc.c:271 #, c-format msgid "\"%s\" is already an attribute of type %s" -msgstr "„%s“ ist schon ein Attribut von Typ %s" +msgstr "»%s« ist schon ein Attribut von Typ %s" #: catalog/pg_proc.c:401 #, c-format msgid "function \"%s\" already exists with same argument types" -msgstr "Funktion „%s“ existiert bereits mit den selben Argumenttypen" +msgstr "Funktion »%s« existiert bereits mit den selben Argumenttypen" #: catalog/pg_proc.c:415 catalog/pg_proc.c:438 #, c-format @@ -4284,7 +4285,7 @@ msgstr "Der von OUT-Parametern bestimmte Zeilentyp ist verschieden." #: catalog/pg_proc.c:481 #, c-format msgid "cannot change name of input parameter \"%s\"" -msgstr "kann Name des Eingabeparameters „%s“ nicht ändern" +msgstr "kann Name des Eingabeparameters »%s« nicht ändern" #: catalog/pg_proc.c:506 #, c-format @@ -4299,12 +4300,12 @@ msgstr "kann Datentyp eines bestehenden Parametervorgabewerts nicht ändern" #: catalog/pg_proc.c:546 #, c-format msgid "function \"%s\" is an aggregate function" -msgstr "Funktion „%s“ ist eine Aggregatfunktion" +msgstr "Funktion »%s« ist eine Aggregatfunktion" #: catalog/pg_proc.c:551 #, c-format msgid "function \"%s\" is not an aggregate function" -msgstr "Funktion „%s“ ist keine Aggregatfunktion" +msgstr "Funktion »%s« ist keine Aggregatfunktion" #: catalog/pg_proc.c:559 #, c-format @@ -4314,7 +4315,7 @@ msgstr "Funktion %s ist eine Fensterfunktion" #: catalog/pg_proc.c:564 #, c-format msgid "function \"%s\" is not a window function" -msgstr "Funktion „%s“ ist keine Fensterfunktion" +msgstr "Funktion »%s« ist keine Fensterfunktion" #: catalog/pg_proc.c:772 #, c-format @@ -4324,17 +4325,17 @@ msgstr "es gibt keine eingebaute Funktion namens %s" #: catalog/pg_proc.c:870 #, c-format msgid "SQL functions cannot return type %s" -msgstr "SQL-Funktionen können keinen Rückgabetyp „%s“ haben" +msgstr "SQL-Funktionen können keinen Rückgabetyp »%s« haben" #: catalog/pg_proc.c:885 #, c-format msgid "SQL functions cannot have arguments of type %s" -msgstr "SQL-Funktionen können keine Argumente vom Typ „%s“ haben" +msgstr "SQL-Funktionen können keine Argumente vom Typ »%s« haben" #: catalog/pg_proc.c:971 executor/functions.c:1421 #, c-format msgid "SQL function \"%s\"" -msgstr "SQL-Funktion „%s“" +msgstr "SQL-Funktion »%s«" #: catalog/pg_shdepend.c:694 #, c-format @@ -4413,7 +4414,7 @@ msgstr "ungültige interne Typgröße %d" #: catalog/pg_type.c:294 #, c-format msgid "alignment \"%c\" is invalid for passed-by-value type of size %d" -msgstr "Ausrichtung „%c“ ist ungültig für Typen mit Wertübergabe mit Größe %d" +msgstr "Ausrichtung »%c« ist ungültig für Typen mit Wertübergabe mit Größe %d" #: catalog/pg_type.c:301 #, c-format @@ -4423,7 +4424,7 @@ msgstr "interne Größe %d ist ungültig für Typen mit Wertübergabe" #: catalog/pg_type.c:310 catalog/pg_type.c:316 #, c-format msgid "alignment \"%c\" is invalid for variable-length type" -msgstr "Ausrichtung „%c“ ist ungültig für Typen variabler Länge" +msgstr "Ausrichtung »%c« ist ungültig für Typen variabler Länge" #: catalog/pg_type.c:324 #, c-format @@ -4433,13 +4434,13 @@ msgstr "Typen mit fester Größe müssen Storage-Typ PLAIN haben" #: catalog/pg_type.c:789 #, c-format msgid "could not form array type name for type \"%s\"" -msgstr "konnte keinen Arraytypnamen für Datentyp „%s“ erzeugen" +msgstr "konnte keinen Arraytypnamen für Datentyp »%s« erzeugen" #: catalog/toasting.c:104 commands/indexcmds.c:381 commands/tablecmds.c:4350 #: commands/tablecmds.c:11863 #, c-format msgid "\"%s\" is not a table or materialized view" -msgstr "„%s“ ist keine Tabelle oder materialisierte Sicht" +msgstr "»%s« ist keine Tabelle oder materialisierte Sicht" #: catalog/toasting.c:157 #, c-format @@ -4454,52 +4455,52 @@ msgstr "nur Ordered-Set-Aggregatfunktionen können Hypothetical-Set-Aggregatfunk #: commands/aggregatecmds.c:171 #, c-format msgid "aggregate attribute \"%s\" not recognized" -msgstr "Attribut „%s“ für Aggregatfunktion unbekannt" +msgstr "Attribut »%s« für Aggregatfunktion unbekannt" #: commands/aggregatecmds.c:181 #, c-format msgid "aggregate stype must be specified" -msgstr "„stype“ für Aggregatfunktion muss angegeben werden" +msgstr "»stype« für Aggregatfunktion muss angegeben werden" #: commands/aggregatecmds.c:185 #, c-format msgid "aggregate sfunc must be specified" -msgstr "„sfunc“ für Aggregatfunktion muss angegeben werden" +msgstr "»sfunc« für Aggregatfunktion muss angegeben werden" #: commands/aggregatecmds.c:197 #, c-format msgid "aggregate msfunc must be specified when mstype is specified" -msgstr "„msfunc“ für Aggregatfunktion muss angegeben werden, wenn „mstype“ angegeben ist" +msgstr "»msfunc« für Aggregatfunktion muss angegeben werden, wenn »mstype« angegeben ist" #: commands/aggregatecmds.c:201 #, c-format msgid "aggregate minvfunc must be specified when mstype is specified" -msgstr "„minvfunc“ für Aggregatfunktion muss angegeben werden, wenn „mstype“ angegeben ist" +msgstr "»minvfunc« für Aggregatfunktion muss angegeben werden, wenn »mstype« angegeben ist" #: commands/aggregatecmds.c:208 #, c-format msgid "aggregate msfunc must not be specified without mstype" -msgstr "„msfunc“ für Aggregatfunktion darf nicht angegeben werden, wenn „mstype“ nicht angegeben ist" +msgstr "»msfunc« für Aggregatfunktion darf nicht angegeben werden, wenn »mstype« nicht angegeben ist" #: commands/aggregatecmds.c:212 #, c-format msgid "aggregate minvfunc must not be specified without mstype" -msgstr "„minvfunc“ für Aggregatfunktion darf nicht angegeben werden, wenn „mstype“ nicht angegeben ist" +msgstr "»minvfunc« für Aggregatfunktion darf nicht angegeben werden, wenn »mstype« nicht angegeben ist" #: commands/aggregatecmds.c:216 #, c-format msgid "aggregate mfinalfunc must not be specified without mstype" -msgstr "„mfinalfunc“ für Aggregatfunktion darf nicht angegeben werden, wenn „mstype“ nicht angegeben ist" +msgstr "»mfinalfunc« für Aggregatfunktion darf nicht angegeben werden, wenn »mstype« nicht angegeben ist" #: commands/aggregatecmds.c:220 #, c-format msgid "aggregate msspace must not be specified without mstype" -msgstr "„msspace“ für Aggregatfunktion darf nicht angegeben werden, wenn „mstype“ nicht angegeben ist" +msgstr "»msspace« für Aggregatfunktion darf nicht angegeben werden, wenn »mstype« nicht angegeben ist" #: commands/aggregatecmds.c:224 #, c-format msgid "aggregate minitcond must not be specified without mstype" -msgstr "„minitcond“ für Aggregatfunktion darf nicht angegeben werden, wenn „mstype“ nicht angegeben ist" +msgstr "»minitcond« für Aggregatfunktion darf nicht angegeben werden, wenn »mstype« nicht angegeben ist" #: commands/aggregatecmds.c:244 #, c-format @@ -4509,7 +4510,7 @@ msgstr "Eingabetyp für Aggregatfunktion muss angegeben werden" #: commands/aggregatecmds.c:274 #, c-format msgid "basetype is redundant with aggregate input type specification" -msgstr "Angabe „basetype“ ist überflüssig bei Angabe des Eingabetyps der Aggregatfunktion" +msgstr "Angabe »basetype« ist überflüssig bei Angabe des Eingabetyps der Aggregatfunktion" #: commands/aggregatecmds.c:315 commands/aggregatecmds.c:335 #, c-format @@ -4519,47 +4520,47 @@ msgstr "Übergangsdatentyp von Aggregatfunktion kann nicht %s sein" #: commands/alter.c:80 commands/event_trigger.c:230 #, c-format msgid "event trigger \"%s\" already exists" -msgstr "Ereignistrigger „%s“ existiert bereits" +msgstr "Ereignistrigger »%s« existiert bereits" #: commands/alter.c:83 commands/foreigncmds.c:597 #, c-format msgid "foreign-data wrapper \"%s\" already exists" -msgstr "Fremddaten-Wrapper „%s“ existiert bereits" +msgstr "Fremddaten-Wrapper »%s« existiert bereits" #: commands/alter.c:86 commands/foreigncmds.c:890 #, c-format msgid "server \"%s\" already exists" -msgstr "Server „%s“ existiert bereits" +msgstr "Server »%s« existiert bereits" #: commands/alter.c:89 commands/proclang.c:363 #, c-format msgid "language \"%s\" already exists" -msgstr "Sprache „%s“ existiert bereits" +msgstr "Sprache »%s« existiert bereits" #: commands/alter.c:112 #, c-format msgid "conversion \"%s\" already exists in schema \"%s\"" -msgstr "Konversion „%s“ existiert bereits in Schema „%s“" +msgstr "Konversion »%s« existiert bereits in Schema »%s«" #: commands/alter.c:116 #, c-format msgid "text search parser \"%s\" already exists in schema \"%s\"" -msgstr "Textsucheparser „%s“ existiert bereits in Schema „%s“" +msgstr "Textsucheparser »%s« existiert bereits in Schema »%s«" #: commands/alter.c:120 #, c-format msgid "text search dictionary \"%s\" already exists in schema \"%s\"" -msgstr "Textsuchewörterbuch „%s“ existiert bereits in Schema „%s“" +msgstr "Textsuchewörterbuch »%s« existiert bereits in Schema »%s«" #: commands/alter.c:124 #, c-format msgid "text search template \"%s\" already exists in schema \"%s\"" -msgstr "Textsuchevorlage „%s“ existiert bereits in Schema „%s“" +msgstr "Textsuchevorlage »%s« existiert bereits in Schema »%s«" #: commands/alter.c:128 #, c-format msgid "text search configuration \"%s\" already exists in schema \"%s\"" -msgstr "Textsuchekonfiguration „%s“ existiert bereits in Schema „%s“" +msgstr "Textsuchekonfiguration »%s« existiert bereits in Schema »%s«" #: commands/alter.c:202 #, c-format @@ -4574,64 +4575,64 @@ msgstr "nur Superuser können Schema von %s setzen" #: commands/analyze.c:145 #, c-format msgid "skipping analyze of \"%s\" --- lock not available" -msgstr "überspringe Analyze von „%s“ --- Sperre nicht verfügbar" +msgstr "überspringe Analyze von »%s« --- Sperre nicht verfügbar" #: commands/analyze.c:162 #, c-format msgid "skipping \"%s\" --- only superuser can analyze it" -msgstr "überspringe „%s“ --- nur Superuser kann sie analysieren" +msgstr "überspringe »%s« --- nur Superuser kann sie analysieren" #: commands/analyze.c:166 #, c-format msgid "skipping \"%s\" --- only superuser or database owner can analyze it" -msgstr "überspringe „%s“ --- nur Superuser oder Eigentümer der Datenbank kann sie analysieren" +msgstr "überspringe »%s« --- nur Superuser oder Eigentümer der Datenbank kann sie analysieren" #: commands/analyze.c:170 #, c-format msgid "skipping \"%s\" --- only table or database owner can analyze it" -msgstr "überspringe „%s“ --- nur Eigentümer der Tabelle oder der Datenbank kann sie analysieren" +msgstr "überspringe »%s« --- nur Eigentümer der Tabelle oder der Datenbank kann sie analysieren" #: commands/analyze.c:230 #, c-format msgid "skipping \"%s\" --- cannot analyze this foreign table" -msgstr "überspringe „%s“ --- kann diese Fremdtabelle nicht analysieren" +msgstr "überspringe »%s« --- kann diese Fremdtabelle nicht analysieren" #: commands/analyze.c:241 #, c-format msgid "skipping \"%s\" --- cannot analyze non-tables or special system tables" -msgstr "überspringe „%s“ --- kann Nicht-Tabellen oder besondere Systemtabellen nicht analysieren" +msgstr "überspringe »%s« --- kann Nicht-Tabellen oder besondere Systemtabellen nicht analysieren" #: commands/analyze.c:320 #, c-format msgid "analyzing \"%s.%s\" inheritance tree" -msgstr "analysiere Vererbungsbaum von „%s.%s“" +msgstr "analysiere Vererbungsbaum von »%s.%s«" #: commands/analyze.c:325 #, c-format msgid "analyzing \"%s.%s\"" -msgstr "analysiere „%s.%s“" +msgstr "analysiere »%s.%s«" -#: commands/analyze.c:645 +#: commands/analyze.c:648 #, c-format msgid "automatic analyze of table \"%s.%s.%s\" system usage: %s" -msgstr "automatisches Analysieren von Tabelle „%s.%s.%s“ Systembenutzung: %s" +msgstr "automatisches Analysieren von Tabelle »%s.%s.%s« Systembenutzung: %s" -#: commands/analyze.c:1201 +#: commands/analyze.c:1204 #, c-format msgid "\"%s\": scanned %d of %u pages, containing %.0f live rows and %.0f dead rows; %d rows in sample, %.0f estimated total rows" -msgstr "„%s“: %d von %u Seiten gelesen, enthalten %.0f lebende Zeilen und %.0f tote Zeilen; %d Zeilen in Stichprobe, schätzungsweise %.0f Zeilen insgesamt" +msgstr "»%s«: %d von %u Seiten gelesen, enthalten %.0f lebende Zeilen und %.0f tote Zeilen; %d Zeilen in Stichprobe, schätzungsweise %.0f Zeilen insgesamt" -#: commands/analyze.c:1280 +#: commands/analyze.c:1283 #, c-format msgid "skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no child tables" -msgstr "überspringe Analysieren des Vererbungsbaums „%s.%s“ --- dieser Vererbungsbaum enthält keine abgeleiteten Tabellen" +msgstr "überspringe Analysieren des Vererbungsbaums »%s.%s« --- dieser Vererbungsbaum enthält keine abgeleiteten Tabellen" -#: commands/analyze.c:1369 +#: commands/analyze.c:1372 #, c-format msgid "skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables" -msgstr "überspringe Analysieren des Vererbungsbaums „%s.%s“ --- dieser Vererbungsbaum enthält keine analysierbaren abgeleiteten Tabellen" +msgstr "überspringe Analysieren des Vererbungsbaums »%s.%s« --- dieser Vererbungsbaum enthält keine analysierbaren abgeleiteten Tabellen" -#: commands/analyze.c:1417 executor/execQual.c:2900 +#: commands/analyze.c:1420 executor/execQual.c:2900 msgid "could not convert row type" msgstr "konnte Zeilentyp nicht umwandeln" @@ -4683,12 +4684,12 @@ msgstr "kann temporäre Tabellen anderer Sitzungen nicht clustern" #: commands/cluster.c:157 #, c-format msgid "there is no previously clustered index for table \"%s\"" -msgstr "es gibt keinen bereits geclusterten Index für Tabelle „%s“" +msgstr "es gibt keinen bereits geclusterten Index für Tabelle »%s«" #: commands/cluster.c:171 commands/tablecmds.c:9256 commands/tablecmds.c:10972 #, c-format msgid "index \"%s\" for table \"%s\" does not exist" -msgstr "Index „%s“ für Tabelle „%s“ existiert nicht" +msgstr "Index »%s« für Tabelle »%s« existiert nicht" #: commands/cluster.c:353 #, c-format @@ -4703,42 +4704,42 @@ msgstr "temporäre Tabellen anderer Sitzungen können nicht gevacuumt werden" #: commands/cluster.c:431 commands/tablecmds.c:10982 #, c-format msgid "\"%s\" is not an index for table \"%s\"" -msgstr "„%s“ ist kein Index für Tabelle „%s“" +msgstr "»%s« ist kein Index für Tabelle »%s«" #: commands/cluster.c:439 #, c-format msgid "cannot cluster on index \"%s\" because access method does not support clustering" -msgstr "kann nicht anhand des Index „%s“ clustern, weil die Indexmethode Clustern nicht unterstützt" +msgstr "kann nicht anhand des Index »%s« clustern, weil die Indexmethode Clustern nicht unterstützt" #: commands/cluster.c:451 #, c-format msgid "cannot cluster on partial index \"%s\"" -msgstr "kann nicht anhand des partiellen Index „%s“ clustern" +msgstr "kann nicht anhand des partiellen Index »%s« clustern" #: commands/cluster.c:465 #, c-format msgid "cannot cluster on invalid index \"%s\"" -msgstr "kann nicht anhand des ungültigen Index „%s“ clustern" +msgstr "kann nicht anhand des ungültigen Index »%s« clustern" #: commands/cluster.c:918 #, c-format msgid "clustering \"%s.%s\" using index scan on \"%s\"" -msgstr "clustere „%s.%s“ durch Index-Scan von „%s“" +msgstr "clustere »%s.%s« durch Index-Scan von »%s«" #: commands/cluster.c:924 #, c-format msgid "clustering \"%s.%s\" using sequential scan and sort" -msgstr "clustere „%s.%s“ durch sequenziellen Scan und Sortieren" +msgstr "clustere »%s.%s« durch sequenziellen Scan und Sortieren" #: commands/cluster.c:929 commands/vacuumlazy.c:464 #, c-format msgid "vacuuming \"%s.%s\"" -msgstr "vacuume „%s.%s“" +msgstr "vacuume »%s.%s«" #: commands/cluster.c:1088 #, c-format msgid "\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages" -msgstr "„%s“: %.0f entfernbare, %.0f nicht entfernbare Zeilenversionen in %u Seiten gefunden" +msgstr "»%s«: %.0f entfernbare, %.0f nicht entfernbare Zeilenversionen in %u Seiten gefunden" #: commands/cluster.c:1092 #, c-format @@ -4752,27 +4753,27 @@ msgstr "" #: commands/collationcmds.c:80 #, c-format msgid "collation attribute \"%s\" not recognized" -msgstr "Attribut „%s“ für Sortierfolge unbekannt" +msgstr "Attribut »%s« für Sortierfolge unbekannt" #: commands/collationcmds.c:125 #, c-format msgid "parameter \"lc_collate\" must be specified" -msgstr "Parameter „lc_collate“ muss angegeben werden" +msgstr "Parameter »lc_collate« muss angegeben werden" #: commands/collationcmds.c:130 #, c-format msgid "parameter \"lc_ctype\" must be specified" -msgstr "Parameter „lc_ctype“ muss angegeben werden" +msgstr "Parameter »lc_ctype« muss angegeben werden" #: commands/collationcmds.c:166 #, c-format msgid "collation \"%s\" for encoding \"%s\" already exists in schema \"%s\"" -msgstr "Sortierfolge „%s“ für Kodierung „%s“ existiert bereits in Schema „%s“" +msgstr "Sortierfolge »%s« für Kodierung »%s« existiert bereits in Schema »%s«" #: commands/collationcmds.c:177 #, c-format msgid "collation \"%s\" already exists in schema \"%s\"" -msgstr "Sortierfolge „%s“ existiert bereits in Schema „%s“" +msgstr "Sortierfolge »%s« existiert bereits in Schema »%s«" #: commands/comment.c:62 commands/dbcommands.c:797 commands/dbcommands.c:962 #: commands/dbcommands.c:1067 commands/dbcommands.c:1257 @@ -4781,42 +4782,42 @@ msgstr "Sortierfolge „%s“ existiert bereits in Schema „%s“" #: utils/init/postinit.c:928 utils/init/postinit.c:945 #, c-format msgid "database \"%s\" does not exist" -msgstr "Datenbank „%s“ existiert nicht" +msgstr "Datenbank »%s« existiert nicht" #: commands/comment.c:101 commands/seclabel.c:116 parser/parse_utilcmd.c:727 #, c-format msgid "\"%s\" is not a table, view, materialized view, composite type, or foreign table" -msgstr "„%s“ ist weder Tabelle, Sicht, materialisierte Sicht, zusammengesetzter Typ noch Fremdtabelle" +msgstr "»%s« ist weder Tabelle, Sicht, materialisierte Sicht, zusammengesetzter Typ noch Fremdtabelle" #: commands/constraint.c:60 utils/adt/ri_triggers.c:2717 #, c-format msgid "function \"%s\" was not called by trigger manager" -msgstr "Funktion „%s“ wurde nicht von Triggermanager aufgerufen" +msgstr "Funktion »%s« wurde nicht von Triggermanager aufgerufen" #: commands/constraint.c:67 utils/adt/ri_triggers.c:2726 #, c-format msgid "function \"%s\" must be fired AFTER ROW" -msgstr "Funktion „%s“ muss AFTER ROW ausgelöst werden" +msgstr "Funktion »%s« muss AFTER ROW ausgelöst werden" #: commands/constraint.c:81 #, c-format msgid "function \"%s\" must be fired for INSERT or UPDATE" -msgstr "Funktion „%s“ muss von INSERT oder UPDATE ausgelöst werden" +msgstr "Funktion »%s« muss von INSERT oder UPDATE ausgelöst werden" #: commands/conversioncmds.c:67 #, c-format msgid "source encoding \"%s\" does not exist" -msgstr "Quellkodierung „%s“ existiert nicht" +msgstr "Quellkodierung »%s« existiert nicht" #: commands/conversioncmds.c:74 #, c-format msgid "destination encoding \"%s\" does not exist" -msgstr "Zielkodierung „%s“ existiert nicht" +msgstr "Zielkodierung »%s« existiert nicht" #: commands/conversioncmds.c:88 #, c-format msgid "encoding conversion function %s must return type \"void\"" -msgstr "Kodierungskonversionsfunktion %s muss Typ „void“ zurückgeben" +msgstr "Kodierungskonversionsfunktion %s muss Typ »void« zurückgeben" #: commands/copy.c:365 commands/copy.c:377 commands/copy.c:411 #: commands/copy.c:423 @@ -4888,23 +4889,23 @@ msgstr "Verwenden Sie stattdessen INSERT-Anweisungen." #: commands/copy.c:1021 #, c-format msgid "COPY format \"%s\" not recognized" -msgstr "COPY-Format „%s“ nicht erkannt" +msgstr "COPY-Format »%s« nicht erkannt" #: commands/copy.c:1092 commands/copy.c:1106 commands/copy.c:1120 #: commands/copy.c:1140 #, 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" +msgstr "Argument von Option »%s« muss eine Liste aus Spaltennamen sein" #: commands/copy.c:1153 #, c-format msgid "argument to option \"%s\" must be a valid encoding name" -msgstr "Argument von Option „%s“ muss ein gültiger Kodierungsname sein" +msgstr "Argument von Option »%s« muss ein gültiger Kodierungsname sein" #: commands/copy.c:1159 commands/dbcommands.c:232 commands/dbcommands.c:1427 #, c-format msgid "option \"%s\" not recognized" -msgstr "Option „%s“ nicht erkannt" +msgstr "Option »%s« nicht erkannt" #: commands/copy.c:1170 #, c-format @@ -4934,7 +4935,7 @@ msgstr "COPY NULL-Darstellung kann nicht Newline oder Carriage Return enthalten" #: commands/copy.c:1227 #, c-format msgid "COPY delimiter cannot be \"%s\"" -msgstr "DELIMITER für COPY darf nicht „%s“ sein" +msgstr "DELIMITER für COPY darf nicht »%s« sein" #: commands/copy.c:1233 #, c-format @@ -5009,7 +5010,7 @@ msgstr "CSV-Quote-Zeichen darf nicht in der NULL-Darstellung erscheinen" #: commands/copy.c:1367 #, c-format msgid "table \"%s\" does not have OIDs" -msgstr "Tabelle „%s“ hat keine OIDs" +msgstr "Tabelle »%s« hat keine OIDs" #: commands/copy.c:1384 #, c-format @@ -5029,17 +5030,17 @@ msgstr "die von der COPY-Anweisung verwendete Relation hat sich geändert" #: commands/copy.c:1498 #, c-format msgid "FORCE QUOTE column \"%s\" not referenced by COPY" -msgstr "FORCE-QUOTE-Spalte „%s“ wird von COPY nicht verwendet" +msgstr "FORCE-QUOTE-Spalte »%s« wird von COPY nicht verwendet" #: commands/copy.c:1520 #, c-format msgid "FORCE NOT NULL column \"%s\" not referenced by COPY" -msgstr "Spalte „%s“ mit FORCE NOT NULL wird von COPY nicht verwendet" +msgstr "Spalte »%s« mit FORCE NOT NULL wird von COPY nicht verwendet" #: commands/copy.c:1542 #, c-format msgid "FORCE NULL column \"%s\" not referenced by COPY" -msgstr "Spalte „%s“ mit FORCE NULL wird von COPY nicht verwendet" +msgstr "Spalte »%s« mit FORCE NULL wird von COPY nicht verwendet" #: commands/copy.c:1607 #, c-format @@ -5049,12 +5050,12 @@ msgstr "konnte Pipe zu externem Programm nicht schließen: %m" #: commands/copy.c:1611 #, c-format msgid "program \"%s\" failed" -msgstr "Programm „%s“ fehlgeschlagen" +msgstr "Programm »%s« fehlgeschlagen" #: commands/copy.c:1661 #, c-format msgid "cannot copy from view \"%s\"" -msgstr "kann nicht aus Sicht „%s“ kopieren" +msgstr "kann nicht aus Sicht »%s« kopieren" #: commands/copy.c:1663 commands/copy.c:1669 commands/copy.c:1675 #, c-format @@ -5064,27 +5065,27 @@ msgstr "Versuchen Sie die Variante COPY (SELECT ...) TO." #: commands/copy.c:1667 #, c-format msgid "cannot copy from materialized view \"%s\"" -msgstr "kann nicht aus materialisierter Sicht „%s“ kopieren" +msgstr "kann nicht aus materialisierter Sicht »%s« kopieren" #: commands/copy.c:1673 #, c-format msgid "cannot copy from foreign table \"%s\"" -msgstr "kann nicht aus Fremdtabelle „%s“ kopieren" +msgstr "kann nicht aus Fremdtabelle »%s« kopieren" #: commands/copy.c:1679 #, c-format msgid "cannot copy from sequence \"%s\"" -msgstr "kann nicht aus Sequenz „%s“ kopieren" +msgstr "kann nicht aus Sequenz »%s« kopieren" #: commands/copy.c:1684 #, c-format msgid "cannot copy from non-table relation \"%s\"" -msgstr "kann nicht aus Relation „%s“, die keine Tabelle ist, kopieren" +msgstr "kann nicht aus Relation »%s«, die keine Tabelle ist, kopieren" #: commands/copy.c:1709 commands/copy.c:2747 #, c-format msgid "could not execute command \"%s\": %m" -msgstr "konnte Befehl „%s“ nicht ausführen: %m" +msgstr "konnte Befehl »%s« nicht ausführen: %m" #: commands/copy.c:1724 #, c-format @@ -5094,12 +5095,12 @@ msgstr "relativer Pfad bei COPY in Datei nicht erlaubt" #: commands/copy.c:1732 #, c-format msgid "could not open file \"%s\" for writing: %m" -msgstr "konnte Datei „%s“ nicht zum Schreiben öffnen: %m" +msgstr "konnte Datei »%s« nicht zum Schreiben öffnen: %m" #: commands/copy.c:1744 commands/copy.c:2770 #, c-format msgid "\"%s\" is a directory" -msgstr "„%s“ ist ein Verzeichnis" +msgstr "»%s« ist ein Verzeichnis" #: commands/copy.c:2069 #, c-format @@ -5114,7 +5115,7 @@ msgstr "COPY %s, Zeile %d" #: commands/copy.c:2084 #, c-format msgid "COPY %s, line %d, column %s: \"%s\"" -msgstr "COPY %s, Zeile %d, Spalte %s: „%s“" +msgstr "COPY %s, Zeile %d, Spalte %s: »%s«" #: commands/copy.c:2092 #, c-format @@ -5124,32 +5125,32 @@ msgstr "COPY %s, Zeile %d, Spalte %s: NULL Eingabe" #: commands/copy.c:2114 #, c-format msgid "COPY %s, line %d: \"%s\"" -msgstr "COPY %s, Zeile %d: „%s“" +msgstr "COPY %s, Zeile %d: »%s«" #: commands/copy.c:2198 #, c-format msgid "cannot copy to view \"%s\"" -msgstr "kann nicht in Sicht „%s“ kopieren" +msgstr "kann nicht in Sicht »%s« kopieren" #: commands/copy.c:2203 #, c-format msgid "cannot copy to materialized view \"%s\"" -msgstr "kann nicht in materialisierte Sicht „%s“ kopieren" +msgstr "kann nicht in materialisierte Sicht »%s« kopieren" #: commands/copy.c:2208 #, c-format msgid "cannot copy to foreign table \"%s\"" -msgstr "kann nicht in Fremdtabelle „%s“ kopieren" +msgstr "kann nicht in Fremdtabelle »%s« kopieren" #: commands/copy.c:2213 #, c-format msgid "cannot copy to sequence \"%s\"" -msgstr "kann nicht in Sequenz „%s“ kopieren" +msgstr "kann nicht in Sequenz »%s« kopieren" #: commands/copy.c:2218 #, c-format msgid "cannot copy to non-table relation \"%s\"" -msgstr "kann nicht in Relation „%s“ kopieren, die keine Tabelle ist" +msgstr "kann nicht in Relation »%s« kopieren, die keine Tabelle ist" #: commands/copy.c:2281 #, c-format @@ -5164,7 +5165,7 @@ msgstr "FREEZE kann nicht durchgeführt werden, weil die Tabelle nicht in der ak #: commands/copy.c:2758 commands/extension.c:3037 utils/adt/genfile.c:134 #, c-format msgid "could not open file \"%s\" for reading: %m" -msgstr "konnte Datei „%s“ nicht zum Lesen öffnen: %m" +msgstr "konnte Datei »%s« nicht zum Lesen öffnen: %m" #: commands/copy.c:2790 #, c-format @@ -5214,7 +5215,7 @@ msgstr "ungültige OID in COPY-Daten" #: commands/copy.c:2988 #, c-format msgid "missing data for column \"%s\"" -msgstr "fehlende Daten für Spalte „%s“" +msgstr "fehlende Daten für Spalte »%s«" #: commands/copy.c:3071 #, c-format @@ -5239,7 +5240,7 @@ msgstr "ungequotetes Carriage-Return-Zeichen in Daten gefunden" #: commands/copy.c:3421 commands/copy.c:3438 #, c-format msgid "Use \"\\r\" to represent carriage return." -msgstr "Verwenden Sie „\\r“, um ein Carriage-Return-Zeichen darzustellen." +msgstr "Verwenden Sie »\\r«, um ein Carriage-Return-Zeichen darzustellen." #: commands/copy.c:3422 commands/copy.c:3439 #, c-format @@ -5259,7 +5260,7 @@ msgstr "ungequotetes Newline-Zeichen in Daten gefunden" #: commands/copy.c:3454 #, c-format msgid "Use \"\\n\" to represent newline." -msgstr "Verwenden Sie „\\n“, um ein Newline-Zeichen darzustellen." +msgstr "Verwenden Sie »\\n«, um ein Newline-Zeichen darzustellen." #: commands/copy.c:3455 #, c-format @@ -5301,20 +5302,20 @@ msgstr "falsches Binärdatenformat" #: parser/parse_relation.c:3104 utils/adt/tsvector_op.c:1417 #, c-format msgid "column \"%s\" does not exist" -msgstr "Spalte „%s“ existiert nicht" +msgstr "Spalte »%s« existiert nicht" #: commands/copy.c:4395 commands/tablecmds.c:1485 commands/trigger.c:652 #: parser/parse_target.c:956 parser/parse_target.c:967 #, c-format msgid "column \"%s\" specified more than once" -msgstr "Spalte „%s“ mehrmals angegeben" +msgstr "Spalte »%s« mehrmals angegeben" -#: commands/createas.c:383 +#: commands/createas.c:213 commands/createas.c:508 #, c-format msgid "too many column names were specified" msgstr "zu viele Spaltennamen wurden angegeben" -#: commands/createas.c:452 +#: commands/createas.c:549 #, c-format msgid "policies not yet implemented for this command" msgstr "Policys sind für diesen Befehl noch nicht implementiert" @@ -5353,12 +5354,12 @@ msgstr "keine Berechtigung, um Datenbank zu erzeugen" #: commands/dbcommands.c:321 #, c-format msgid "template database \"%s\" does not exist" -msgstr "Template-Datenbank „%s“ existiert nicht" +msgstr "Template-Datenbank »%s« existiert nicht" #: commands/dbcommands.c:333 #, c-format msgid "permission denied to copy database \"%s\"" -msgstr "keine Berechtigung, um Datenbank „%s“ zu kopieren" +msgstr "keine Berechtigung, um Datenbank »%s« zu kopieren" #: commands/dbcommands.c:349 #, c-format @@ -5368,7 +5369,7 @@ msgstr "ungültige Serverkodierung %d" #: commands/dbcommands.c:355 commands/dbcommands.c:360 #, c-format msgid "invalid locale name: \"%s\"" -msgstr "ungültiger Locale-Name: „%s“" +msgstr "ungültiger Locale-Name: »%s«" #: commands/dbcommands.c:380 #, c-format @@ -5408,42 +5409,42 @@ msgstr "pg_global kann nicht als Standard-Tablespace verwendet werden" #: commands/dbcommands.c:445 #, c-format msgid "cannot assign new default tablespace \"%s\"" -msgstr "kann neuen Standard-Tablespace „%s“ nicht setzen" +msgstr "kann neuen Standard-Tablespace »%s« nicht setzen" #: commands/dbcommands.c:447 #, c-format msgid "There is a conflict because database \"%s\" already has some tables in this tablespace." -msgstr "Es gibt einen Konflikt, weil Datenbank „%s“ schon einige Tabellen in diesem Tablespace hat." +msgstr "Es gibt einen Konflikt, weil Datenbank »%s« schon einige Tabellen in diesem Tablespace hat." #: commands/dbcommands.c:467 commands/dbcommands.c:982 #, c-format msgid "database \"%s\" already exists" -msgstr "Datenbank „%s“ existiert bereits" +msgstr "Datenbank »%s« existiert bereits" #: commands/dbcommands.c:481 #, c-format msgid "source database \"%s\" is being accessed by other users" -msgstr "auf Quelldatenbank „%s“ wird gerade von anderen Benutzern zugegriffen" +msgstr "auf Quelldatenbank »%s« wird gerade von anderen Benutzern zugegriffen" #: commands/dbcommands.c:726 commands/dbcommands.c:741 #, c-format msgid "encoding \"%s\" does not match locale \"%s\"" -msgstr "Kodierung „%s“ stimmt nicht mit Locale „%s“ überein" +msgstr "Kodierung »%s« stimmt nicht mit Locale »%s« überein" #: commands/dbcommands.c:729 #, c-format msgid "The chosen LC_CTYPE setting requires encoding \"%s\"." -msgstr "Die gewählte LC_CTYPE-Einstellung verlangt die Kodierung „%s“." +msgstr "Die gewählte LC_CTYPE-Einstellung verlangt die Kodierung »%s«." #: commands/dbcommands.c:744 #, c-format msgid "The chosen LC_COLLATE setting requires encoding \"%s\"." -msgstr "Die gewählte LC_COLLATE-Einstellung verlangt die Kodierung „%s“." +msgstr "Die gewählte LC_COLLATE-Einstellung verlangt die Kodierung »%s«." #: commands/dbcommands.c:804 #, c-format msgid "database \"%s\" does not exist, skipping" -msgstr "Datenbank „%s“ existiert nicht, wird übersprungen" +msgstr "Datenbank »%s« existiert nicht, wird übersprungen" #: commands/dbcommands.c:828 #, c-format @@ -5458,7 +5459,7 @@ msgstr "kann aktuell geöffnete Datenbank nicht löschen" #: commands/dbcommands.c:844 #, c-format msgid "database \"%s\" is used by a logical replication slot" -msgstr "Datenbank „%s“ wird von einem logischen Replikations-Slot verwendet" +msgstr "Datenbank »%s« wird von einem logischen Replikations-Slot verwendet" #: commands/dbcommands.c:846 #, c-format @@ -5471,7 +5472,7 @@ msgstr[1] "%d Slots sind vorhanden, %d davon aktiv." #: commands/dbcommands.c:1135 #, c-format msgid "database \"%s\" is being accessed by other users" -msgstr "auf Datenbank „%s“ wird von anderen Benutzern zugegriffen" +msgstr "auf Datenbank »%s« wird von anderen Benutzern zugegriffen" #: commands/dbcommands.c:973 #, c-format @@ -5491,7 +5492,7 @@ msgstr "kann den Tablespace der aktuell geöffneten Datenbank nicht ändern" #: commands/dbcommands.c:1194 #, c-format msgid "some relations of database \"%s\" are already in tablespace \"%s\"" -msgstr "einige Relationen von Datenbank „%s“ ist bereits in Tablespace „%s“" +msgstr "einige Relationen von Datenbank »%s« ist bereits in Tablespace »%s«" #: commands/dbcommands.c:1196 #, c-format @@ -5503,12 +5504,12 @@ msgstr "Sie müssen sie zurück in den Standard-Tablespace der Datenbank verschi #: commands/tablespace.c:606 #, c-format msgid "some useless files may be left behind in old database directory \"%s\"" -msgstr "einige nutzlose Dateien wurde möglicherweise im alten Datenbankverzeichnis „%s“ zurückgelassen" +msgstr "einige nutzlose Dateien wurde möglicherweise im alten Datenbankverzeichnis »%s« zurückgelassen" #: commands/dbcommands.c:1440 #, c-format msgid "option \"%s\" cannot be specified with other options" -msgstr "Option „%s“ kann nicht mit anderen Optionen angegeben werden" +msgstr "Option »%s« kann nicht mit anderen Optionen angegeben werden" #: commands/dbcommands.c:1494 #, c-format @@ -5574,13 +5575,13 @@ msgstr "Argument von %s muss ein Typname sein" #: commands/define.c:318 #, c-format msgid "invalid argument for %s: \"%s\"" -msgstr "ungültiges Argument für %s: „%s“" +msgstr "ungültiges Argument für %s: »%s«" #: commands/dropcmds.c:112 commands/functioncmds.c:1166 #: utils/adt/ruleutils.c:1951 #, c-format msgid "\"%s\" is an aggregate function" -msgstr "„%s“ ist eine Aggregatfunktion" +msgstr "»%s« ist eine Aggregatfunktion" #: commands/dropcmds.c:114 #, c-format @@ -5592,52 +5593,52 @@ msgstr "Verwenden Sie DROP AGGREGATE, um Aggregatfunktionen zu löschen." #: commands/tablecmds.c:11346 tcop/utility.c:1104 #, c-format msgid "relation \"%s\" does not exist, skipping" -msgstr "Relation „%s“ existiert nicht, wird übersprungen" +msgstr "Relation »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:195 commands/dropcmds.c:292 commands/tablecmds.c:741 #, c-format msgid "schema \"%s\" does not exist, skipping" -msgstr "Schema „%s“ existiert nicht, wird übersprungen" +msgstr "Schema »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:237 commands/dropcmds.c:272 commands/tablecmds.c:244 #, c-format msgid "type \"%s\" does not exist, skipping" -msgstr "Typ „%s“ existiert nicht, wird übersprungen" +msgstr "Typ »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:280 #, c-format msgid "collation \"%s\" does not exist, skipping" -msgstr "Sortierfolge „%s“ existiert nicht, wird übersprungen" +msgstr "Sortierfolge »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:287 #, c-format msgid "conversion \"%s\" does not exist, skipping" -msgstr "Konversion „%s“ existiert nicht, wird übersprungen" +msgstr "Konversion »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:298 #, c-format msgid "text search parser \"%s\" does not exist, skipping" -msgstr "Textsucheparser „%s“ existiert nicht, wird übersprungen" +msgstr "Textsucheparser »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:305 #, c-format msgid "text search dictionary \"%s\" does not exist, skipping" -msgstr "Textsuchewörterbuch „%s“ existiert nicht, wird übersprungen" +msgstr "Textsuchewörterbuch »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:312 #, c-format msgid "text search template \"%s\" does not exist, skipping" -msgstr "Textsuchevorlage „%s“ existiert nicht, wird übersprungen" +msgstr "Textsuchevorlage »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:319 #, c-format msgid "text search configuration \"%s\" does not exist, skipping" -msgstr "Textsuchekonfiguration „%s“ existiert nicht, wird übersprungen" +msgstr "Textsuchekonfiguration »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:324 #, c-format msgid "extension \"%s\" does not exist, skipping" -msgstr "Erweiterung „%s“ existiert nicht, wird übersprungen" +msgstr "Erweiterung »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:331 #, c-format @@ -5657,7 +5658,7 @@ msgstr "Operator %s existiert nicht, wird übersprungen" #: commands/dropcmds.c:354 #, c-format msgid "language \"%s\" does not exist, skipping" -msgstr "Sprache „%s“ existiert nicht, wird übersprungen" +msgstr "Sprache »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:363 #, c-format @@ -5667,52 +5668,52 @@ msgstr "Typumwandlung von Typ %s in Typ %s existiert nicht, wird übersprungen" #: commands/dropcmds.c:372 #, c-format msgid "transform for type %s language \"%s\" does not exist, skipping" -msgstr "Transformation für Typ %s Sprache „%s“ existiert nicht, wird übersprungen" +msgstr "Transformation für Typ %s Sprache »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:380 #, c-format msgid "trigger \"%s\" for relation \"%s\" does not exist, skipping" -msgstr "Trigger „%s“ für Relation „%s“ existiert nicht, wird übersprungen" +msgstr "Trigger »%s« für Relation »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:389 #, c-format msgid "policy \"%s\" for relation \"%s\" does not exist, skipping" -msgstr "Policy „%s“ für Relation „%s“ existiert nicht, wird übersprungen" +msgstr "Policy »%s« für Relation »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:396 #, c-format msgid "event trigger \"%s\" does not exist, skipping" -msgstr "Ereignistrigger „%s“ existiert nicht, wird übersprungen" +msgstr "Ereignistrigger »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:402 #, c-format msgid "rule \"%s\" for relation \"%s\" does not exist, skipping" -msgstr "Regel „%s“ für Relation „%s“ existiert nicht, wird übersprungen" +msgstr "Regel »%s« für Relation »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:409 #, c-format msgid "foreign-data wrapper \"%s\" does not exist, skipping" -msgstr "Fremddaten-Wrapper „%s“ existiert nicht, wird übersprungen" +msgstr "Fremddaten-Wrapper »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:413 #, c-format msgid "server \"%s\" does not exist, skipping" -msgstr "Server „%s“ existiert nicht, wird übersprungen" +msgstr "Server »%s« existiert nicht, wird übersprungen" #: commands/dropcmds.c:422 #, c-format msgid "operator class \"%s\" does not exist for access method \"%s\", skipping" -msgstr "Operatorklasse „%s“ existiert nicht für Zugriffsmethode „%s“, wird übersprungen" +msgstr "Operatorklasse »%s« existiert nicht für Zugriffsmethode »%s«, wird übersprungen" #: commands/dropcmds.c:434 #, c-format msgid "operator family \"%s\" does not exist for access method \"%s\", skipping" -msgstr "Operatorfamilie „%s“ existiert nicht für Zugriffsmethode „%s“, wird übersprungen" +msgstr "Operatorfamilie »%s« existiert nicht für Zugriffsmethode »%s«, wird übersprungen" #: commands/event_trigger.c:181 #, c-format msgid "permission denied to create event trigger \"%s\"" -msgstr "keine Berechtigung, um Ereignistrigger „%s“ zu erzeugen" +msgstr "keine Berechtigung, um Ereignistrigger »%s« zu erzeugen" #: commands/event_trigger.c:183 #, c-format @@ -5722,22 +5723,22 @@ msgstr "Nur Superuser können Ereignistrigger anlegen." #: commands/event_trigger.c:192 #, c-format msgid "unrecognized event name \"%s\"" -msgstr "unbekannter Ereignisname „%s“" +msgstr "unbekannter Ereignisname »%s«" #: commands/event_trigger.c:209 #, c-format msgid "unrecognized filter variable \"%s\"" -msgstr "unbekannte Filtervariable „%s“" +msgstr "unbekannte Filtervariable »%s«" #: commands/event_trigger.c:239 #, c-format msgid "function \"%s\" must return type \"event_trigger\"" -msgstr "Funktion „%s“ muss Typ „event_trigger“ zurückgeben" +msgstr "Funktion »%s« muss Typ »event_trigger« zurückgeben" #: commands/event_trigger.c:264 #, c-format msgid "filter value \"%s\" not recognized for filter variable \"%s\"" -msgstr "Filterwert „%s“ nicht erkannt für Filtervariable „%s“" +msgstr "Filterwert »%s« nicht erkannt für Filtervariable »%s«" #. translator: %s represents an SQL statement name #: commands/event_trigger.c:270 commands/event_trigger.c:340 @@ -5748,18 +5749,18 @@ msgstr "Ereignistrigger für %s werden nicht unterstützt" #: commands/event_trigger.c:363 #, c-format msgid "filter variable \"%s\" specified more than once" -msgstr "Filtervariable „%s“ mehrmals angegeben" +msgstr "Filtervariable »%s« mehrmals angegeben" #: commands/event_trigger.c:511 commands/event_trigger.c:555 #: commands/event_trigger.c:648 #, c-format msgid "event trigger \"%s\" does not exist" -msgstr "Ereignistrigger „%s“ existiert nicht" +msgstr "Ereignistrigger »%s« existiert nicht" #: commands/event_trigger.c:616 #, c-format msgid "permission denied to change owner of event trigger \"%s\"" -msgstr "keine Berechtigung, um Eigentümer des Ereignistriggers „%s“ zu ändern" +msgstr "keine Berechtigung, um Eigentümer des Ereignistriggers »%s« zu ändern" #: commands/event_trigger.c:618 #, c-format @@ -5774,10 +5775,10 @@ msgstr "%s kann nur in einer sql_drop-Ereignistriggerfunktion aufgerufen werden" #: commands/event_trigger.c:1446 commands/event_trigger.c:1997 #: commands/extension.c:1645 commands/extension.c:1754 #: commands/extension.c:1947 commands/prepare.c:701 executor/execQual.c:1735 -#: executor/execQual.c:1760 executor/execQual.c:2135 executor/execQual.c:5376 +#: executor/execQual.c:1760 executor/execQual.c:2135 executor/execQual.c:5404 #: executor/functions.c:1021 foreign/foreign.c:491 #: replication/logical/logicalfuncs.c:324 replication/logical/origin.c:1391 -#: replication/slotfuncs.c:173 replication/walsender.c:2762 +#: replication/slotfuncs.c:173 replication/walsender.c:2766 #: utils/adt/jsonfuncs.c:1474 utils/adt/jsonfuncs.c:1606 #: utils/adt/jsonfuncs.c:1796 utils/adt/jsonfuncs.c:1925 #: utils/adt/jsonfuncs.c:2693 utils/adt/pgstatfuncs.c:547 @@ -5790,7 +5791,7 @@ msgstr "Funktion mit Mengenergebnis in einem Zusammenhang aufgerufen, der keine #: commands/extension.c:1649 commands/extension.c:1758 #: commands/extension.c:1951 commands/prepare.c:705 foreign/foreign.c:496 #: replication/logical/logicalfuncs.c:328 replication/logical/origin.c:1395 -#: replication/slotfuncs.c:177 replication/walsender.c:2766 +#: replication/slotfuncs.c:177 replication/walsender.c:2770 #: utils/adt/pgstatfuncs.c:551 utils/misc/guc.c:8224 #: utils/mmgr/portalmem.c:1056 #, c-format @@ -5810,12 +5811,12 @@ msgstr "%s kann nur in einer Ereignistriggerfunktion aufgerufen werden" #: commands/explain.c:184 #, c-format msgid "unrecognized value for EXPLAIN option \"%s\": \"%s\"" -msgstr "unbekannter Wert für EXPLAIN-Option „%s“: „%s“" +msgstr "unbekannter Wert für EXPLAIN-Option »%s«: »%s«" #: commands/explain.c:190 #, c-format msgid "unrecognized EXPLAIN option \"%s\"" -msgstr "unbekannte EXPLAIN-Option „%s“" +msgstr "unbekannte EXPLAIN-Option »%s«" #: commands/explain.c:197 #, c-format @@ -5830,13 +5831,13 @@ msgstr "EXPLAIN-Option TIMING erfordert ANALYZE" #: commands/extension.c:152 commands/extension.c:2635 #, c-format msgid "extension \"%s\" does not exist" -msgstr "Erweiterung „%s“ existiert nicht" +msgstr "Erweiterung »%s« existiert nicht" #: commands/extension.c:251 commands/extension.c:260 commands/extension.c:272 #: commands/extension.c:282 #, c-format msgid "invalid extension name: \"%s\"" -msgstr "ungültiger Erweiterungsname: „%s“" +msgstr "ungültiger Erweiterungsname: »%s«" #: commands/extension.c:252 #, c-format @@ -5846,12 +5847,12 @@ msgstr "Erweiterungsnamen dürfen nicht leer sein." #: commands/extension.c:261 #, c-format msgid "Extension names must not contain \"--\"." -msgstr "Erweiterungsnamen dürfen nicht „--“ enthalten." +msgstr "Erweiterungsnamen dürfen nicht »--« enthalten." #: commands/extension.c:273 #, c-format msgid "Extension names must not begin or end with \"-\"." -msgstr "Erweiterungsnamen dürfen nicht mit „-“ anfangen oder aufhören." +msgstr "Erweiterungsnamen dürfen nicht mit »-« anfangen oder aufhören." #: commands/extension.c:283 #, c-format @@ -5862,7 +5863,7 @@ msgstr "Erweiterungsnamen dürfen keine Verzeichnistrennzeichen enthalten." #: commands/extension.c:326 #, c-format msgid "invalid extension version name: \"%s\"" -msgstr "ungültiger Erweiterungsversionsname: „%s“" +msgstr "ungültiger Erweiterungsversionsname: »%s«" #: commands/extension.c:299 #, c-format @@ -5872,12 +5873,12 @@ msgstr "Versionsnamen dürfen nicht leer sein." #: commands/extension.c:308 #, c-format msgid "Version names must not contain \"--\"." -msgstr "Versionsnamen dürfen nicht „--“ enthalten." +msgstr "Versionsnamen dürfen nicht »--« enthalten." #: commands/extension.c:317 #, c-format msgid "Version names must not begin or end with \"-\"." -msgstr "Versionsnamen dürfen nicht mit „-“ anfangen oder aufhören." +msgstr "Versionsnamen dürfen nicht mit »-« anfangen oder aufhören." #: commands/extension.c:327 #, c-format @@ -5887,32 +5888,32 @@ msgstr "Versionsnamen dürfen keine Verzeichnistrennzeichen enthalten." #: commands/extension.c:477 #, c-format msgid "could not open extension control file \"%s\": %m" -msgstr "konnte Erweiterungskontrolldatei „%s“ nicht öffnen: %m" +msgstr "konnte Erweiterungskontrolldatei »%s« nicht öffnen: %m" #: commands/extension.c:499 commands/extension.c:509 #, c-format msgid "parameter \"%s\" cannot be set in a secondary extension control file" -msgstr "Parameter „%s“ kann nicht in einer sekundären Erweitungskontrolldatei gesetzt werden" +msgstr "Parameter »%s« kann nicht in einer sekundären Erweitungskontrolldatei gesetzt werden" #: commands/extension.c:548 #, c-format msgid "\"%s\" is not a valid encoding name" -msgstr "„%s“ ist kein gültiger Kodierungsname" +msgstr "»%s« ist kein gültiger Kodierungsname" #: commands/extension.c:562 #, c-format msgid "parameter \"%s\" must be a list of extension names" -msgstr "Parameter „%s“ muss eine Liste von Erweiterungsnamen sein" +msgstr "Parameter »%s« muss eine Liste von Erweiterungsnamen sein" #: commands/extension.c:569 #, c-format msgid "unrecognized parameter \"%s\" in file \"%s\"" -msgstr "unbekannter Parameter „%s“ in Datei „%s“" +msgstr "unbekannter Parameter »%s« in Datei »%s«" #: commands/extension.c:578 #, c-format msgid "parameter \"schema\" cannot be specified when \"relocatable\" is true" -msgstr "Parameter „schema“ kann nicht angegeben werden, wenn „relocatable“ an ist" +msgstr "Parameter »schema« kann nicht angegeben werden, wenn »relocatable« an ist" #: commands/extension.c:719 #, c-format @@ -5922,7 +5923,7 @@ msgstr "Transaktionskontrollanweisungen sind nicht in einem Erweiterungsskript e #: commands/extension.c:787 #, c-format msgid "permission denied to create extension \"%s\"" -msgstr "keine Berechtigung, um Erweiterung „%s“ zu erzeugen" +msgstr "keine Berechtigung, um Erweiterung »%s« zu erzeugen" #: commands/extension.c:789 #, c-format @@ -5932,7 +5933,7 @@ msgstr "Nur Superuser können diese Erweiterung anlegen." #: commands/extension.c:793 #, c-format msgid "permission denied to update extension \"%s\"" -msgstr "keine Berechtigung, um Erweiterung „%s“ zu aktualisieren" +msgstr "keine Berechtigung, um Erweiterung »%s« zu aktualisieren" #: commands/extension.c:795 #, c-format @@ -5942,17 +5943,17 @@ msgstr "Nur Superuser können diese Erweiterung aktualisieren." #: commands/extension.c:1077 #, c-format msgid "extension \"%s\" has no update path from version \"%s\" to version \"%s\"" -msgstr "Erweiterung „%s“ hat keinen Aktualisierungspfad von Version „%s“ auf Version „%s“" +msgstr "Erweiterung »%s« hat keinen Aktualisierungspfad von Version »%s« auf Version »%s«" #: commands/extension.c:1205 #, c-format msgid "extension \"%s\" already exists, skipping" -msgstr "Erweiterung „%s“ existiert bereits, wird übersprungen" +msgstr "Erweiterung »%s« existiert bereits, wird übersprungen" #: commands/extension.c:1212 #, c-format msgid "extension \"%s\" already exists" -msgstr "Erweiterung „%s“ existiert bereits" +msgstr "Erweiterung »%s« existiert bereits" #: commands/extension.c:1223 #, c-format @@ -5967,22 +5968,22 @@ msgstr "die zu installierende Version muss angegeben werden" #: commands/extension.c:1295 #, c-format msgid "FROM version must be different from installation target version \"%s\"" -msgstr "FROM-Version muss verschieden von der zu installierenden Version „%s“ sein" +msgstr "FROM-Version muss verschieden von der zu installierenden Version »%s« sein" #: commands/extension.c:1350 #, c-format msgid "extension \"%s\" must be installed in schema \"%s\"" -msgstr "Erweiterung „%s“ muss in Schema „%s“ installiert werden" +msgstr "Erweiterung »%s« muss in Schema »%s« installiert werden" #: commands/extension.c:1434 commands/extension.c:2840 #, c-format msgid "required extension \"%s\" is not installed" -msgstr "benötigte Erweiterung „%s“ ist nicht installiert" +msgstr "benötigte Erweiterung »%s« ist nicht installiert" #: commands/extension.c:1597 #, c-format msgid "cannot drop extension \"%s\" because it is being modified" -msgstr "Erweiterung „%s“ kann nicht gelöscht werden, weil sie gerade geändert wird" +msgstr "Erweiterung »%s« kann nicht gelöscht werden, weil sie gerade geändert wird" #: commands/extension.c:2068 #, c-format @@ -5997,22 +5998,22 @@ msgstr "OID %u bezieht sich nicht auf eine Tabelle" #: commands/extension.c:2085 #, c-format msgid "table \"%s\" is not a member of the extension being created" -msgstr "Tabelle „%s“ ist kein Mitglied der anzulegenden Erweiterung" +msgstr "Tabelle »%s« ist kein Mitglied der anzulegenden Erweiterung" #: commands/extension.c:2450 #, c-format msgid "cannot move extension \"%s\" into schema \"%s\" because the extension contains the schema" -msgstr "kann Erweiterung „%s“ nicht in Schema „%s“ verschieben, weil die Erweiterung das Schema enthält" +msgstr "kann Erweiterung »%s« nicht in Schema »%s« verschieben, weil die Erweiterung das Schema enthält" #: commands/extension.c:2490 commands/extension.c:2553 #, c-format msgid "extension \"%s\" does not support SET SCHEMA" -msgstr "Erweiterung „%s“ unterstützt SET SCHEMA nicht" +msgstr "Erweiterung »%s« unterstützt SET SCHEMA nicht" #: commands/extension.c:2555 #, c-format msgid "%s is not in the extension's schema \"%s\"" -msgstr "%s ist nicht im Schema der Erweiterung („%s“)" +msgstr "%s ist nicht im Schema der Erweiterung (»%s«)" #: commands/extension.c:2615 #, c-format @@ -6022,37 +6023,37 @@ msgstr "geschachteltes ALTER EXTENSION wird nicht unterstützt" #: commands/extension.c:2706 #, c-format msgid "version \"%s\" of extension \"%s\" is already installed" -msgstr "Version „%s“ von Erweiterung „%s“ ist bereits installiert" +msgstr "Version »%s« von Erweiterung »%s« ist bereits installiert" #: commands/extension.c:2957 #, c-format msgid "cannot add schema \"%s\" to extension \"%s\" because the schema contains the extension" -msgstr "kann Schema „%s“ nicht zu Erweiterung „%s“ hinzufügen, weil das Schema die Erweiterung enthält" +msgstr "kann Schema »%s« nicht zu Erweiterung »%s« hinzufügen, weil das Schema die Erweiterung enthält" #: commands/extension.c:2975 #, c-format msgid "%s is not a member of extension \"%s\"" -msgstr "%s ist kein Mitglied der Erweiterung „%s“" +msgstr "%s ist kein Mitglied der Erweiterung »%s«" #: commands/extension.c:3031 #, c-format msgid "file \"%s\" is too large" -msgstr "Datei „%s“ ist zu groß" +msgstr "Datei »%s« ist zu groß" #: commands/foreigncmds.c:150 commands/foreigncmds.c:159 #, c-format msgid "option \"%s\" not found" -msgstr "Option „%s“ nicht gefunden" +msgstr "Option »%s« nicht gefunden" #: commands/foreigncmds.c:169 #, c-format msgid "option \"%s\" provided more than once" -msgstr "Option „%s“ mehrmals angegeben" +msgstr "Option »%s« mehrmals angegeben" #: commands/foreigncmds.c:223 commands/foreigncmds.c:231 #, c-format msgid "permission denied to change owner of foreign-data wrapper \"%s\"" -msgstr "keine Berechtigung, um Eigentümer des Fremddaten-Wrappers „%s“ zu ändern" +msgstr "keine Berechtigung, um Eigentümer des Fremddaten-Wrappers »%s« zu ändern" #: commands/foreigncmds.c:225 #, c-format @@ -6067,17 +6068,17 @@ msgstr "Der Eigentümer eines Fremddaten-Wrappers muss ein Superuser sein." #: commands/foreigncmds.c:292 commands/foreigncmds.c:709 foreign/foreign.c:670 #, c-format msgid "foreign-data wrapper \"%s\" does not exist" -msgstr "Fremddaten-Wrapper „%s“ existiert nicht" +msgstr "Fremddaten-Wrapper »%s« existiert nicht" #: commands/foreigncmds.c:489 #, c-format msgid "function %s must return type \"fdw_handler\"" -msgstr "Funktion %s muss Typ „fdw_handler“ zurückgeben" +msgstr "Funktion %s muss Typ »fdw_handler« zurückgeben" #: commands/foreigncmds.c:584 #, c-format msgid "permission denied to create foreign-data wrapper \"%s\"" -msgstr "keine Berechtigung, um Fremddaten-Wrapper „%s“ zu erzeugen" +msgstr "keine Berechtigung, um Fremddaten-Wrapper »%s« zu erzeugen" #: commands/foreigncmds.c:586 #, c-format @@ -6087,7 +6088,7 @@ msgstr "Nur Superuser können Fremddaten-Wrapper anlegen." #: commands/foreigncmds.c:699 #, c-format msgid "permission denied to alter foreign-data wrapper \"%s\"" -msgstr "keine Berechtigung, um Fremddaten-Wrapper „%s“ zu ändern" +msgstr "keine Berechtigung, um Fremddaten-Wrapper »%s« zu ändern" #: commands/foreigncmds.c:701 #, c-format @@ -6107,12 +6108,12 @@ msgstr "durch Ändern des Validators des Fremddaten-Wrappers können die Optione #: commands/foreigncmds.c:1165 #, c-format msgid "user mapping \"%s\" already exists for server %s" -msgstr "Benutzerabbildung „%s“ existiert bereits für Server „%s“" +msgstr "Benutzerabbildung »%s« existiert bereits für Server »%s«" #: commands/foreigncmds.c:1259 commands/foreigncmds.c:1375 #, c-format msgid "user mapping \"%s\" does not exist for the server" -msgstr "Benutzerabbildung „%s“ existiert für den Server nicht" +msgstr "Benutzerabbildung »%s« existiert für den Server nicht" #: commands/foreigncmds.c:1362 #, c-format @@ -6122,22 +6123,22 @@ msgstr "Server existiert nicht, wird übersprungen" #: commands/foreigncmds.c:1380 #, c-format msgid "user mapping \"%s\" does not exist for the server, skipping" -msgstr "Benutzerabbildung „%s“ existiert nicht für den Server, wird übersprungen" +msgstr "Benutzerabbildung »%s« existiert nicht für den Server, wird übersprungen" #: commands/foreigncmds.c:1532 foreign/foreign.c:360 #, c-format msgid "foreign-data wrapper \"%s\" has no handler" -msgstr "Fremddaten-Wrapper „%s“ hat keinen Handler" +msgstr "Fremddaten-Wrapper »%s« hat keinen Handler" #: commands/foreigncmds.c:1538 #, c-format msgid "foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA" -msgstr "Fremddaten-Wrapper „%s“ unterstützt IMPORT FOREIGN SCHEMA nicht" +msgstr "Fremddaten-Wrapper »%s« unterstützt IMPORT FOREIGN SCHEMA nicht" #: commands/foreigncmds.c:1631 #, c-format msgid "importing foreign table \"%s\"" -msgstr "importiere Fremdtabelle „%s“" +msgstr "importiere Fremdtabelle »%s«" #: commands/functioncmds.c:99 #, c-format @@ -6152,12 +6153,12 @@ msgstr "Rückgabetyp %s ist nur eine Hülle" #: commands/functioncmds.c:134 parser/parse_type.c:337 #, c-format msgid "type modifier cannot be specified for shell type \"%s\"" -msgstr "Typmodifikator kann für Hüllentyp „%s“ nicht angegeben werden" +msgstr "Typmodifikator kann für Hüllentyp »%s« nicht angegeben werden" #: commands/functioncmds.c:140 #, c-format msgid "type \"%s\" is not yet defined" -msgstr "Typ „%s“ ist noch nicht definiert" +msgstr "Typ »%s« ist noch nicht definiert" #: commands/functioncmds.c:141 #, c-format @@ -6207,7 +6208,7 @@ msgstr "VARIADIC-Parameter muss ein Array sein" #: commands/functioncmds.c:356 #, c-format msgid "parameter name \"%s\" used more than once" -msgstr "Parametername „%s“ mehrmals angegeben" +msgstr "Parametername »%s« mehrmals angegeben" #: commands/functioncmds.c:371 #, c-format @@ -6247,18 +6248,18 @@ msgstr "ROWS muss positiv sein" #: commands/functioncmds.c:752 #, c-format msgid "unrecognized function attribute \"%s\" ignored" -msgstr "unbekanntes Funktionsattribut „%s“ ignoriert" +msgstr "unbekanntes Funktionsattribut »%s« ignoriert" #: commands/functioncmds.c:803 #, c-format msgid "only one AS item needed for language \"%s\"" -msgstr "nur ein AS-Element benötigt für Sprache „%s“" +msgstr "nur ein AS-Element benötigt für Sprache »%s«" #: commands/functioncmds.c:894 commands/functioncmds.c:2079 #: commands/proclang.c:560 #, c-format msgid "language \"%s\" does not exist" -msgstr "Sprache „%s“ existiert nicht" +msgstr "Sprache »%s« existiert nicht" #: commands/functioncmds.c:896 commands/functioncmds.c:2081 #, c-format @@ -6268,7 +6269,7 @@ msgstr "Sie müssen CREATE LANGUAGE verwenden, um die Sprache in die Datenbank z #: commands/functioncmds.c:931 commands/functioncmds.c:1197 #, c-format msgid "only superuser can define a leakproof function" -msgstr "nur Superuser können eine „leakproof“-Funktion definieren" +msgstr "nur Superuser können eine »leakproof«-Funktion definieren" #: commands/functioncmds.c:975 #, c-format @@ -6423,7 +6424,7 @@ msgstr "Transformationsfunktion muss ein Argument haben" #: commands/functioncmds.c:1736 #, c-format msgid "first argument of transform function must be type \"internal\"" -msgstr "erstes Argument der Transformationsfunktion muss Typ „internal“ haben" +msgstr "erstes Argument der Transformationsfunktion muss Typ »internal« haben" #: commands/functioncmds.c:1773 #, c-format @@ -6438,7 +6439,7 @@ msgstr "Datentyp %s ist eine Domäne" #: commands/functioncmds.c:1819 #, c-format msgid "return data type of FROM SQL function must be \"internal\"" -msgstr "Rückgabetyp der FROM-SQL-Funktion muss „internal“ sein" +msgstr "Rückgabetyp der FROM-SQL-Funktion muss »internal« sein" #: commands/functioncmds.c:1844 #, c-format @@ -6448,17 +6449,17 @@ msgstr "Rückgabetyp der TO-SQL-Funktion muss der zu transformierende Datentyp s #: commands/functioncmds.c:1871 #, c-format msgid "transform for type %s language \"%s\" already exists" -msgstr "Transformation für Typ %s Sprache „%s“ existiert bereits" +msgstr "Transformation für Typ %s Sprache »%s« existiert bereits" #: commands/functioncmds.c:1962 #, c-format msgid "transform for type %s language \"%s\" does not exist" -msgstr "Transformation für Typ %s Sprache „%s“ existiert nicht" +msgstr "Transformation für Typ %s Sprache »%s« existiert nicht" #: commands/functioncmds.c:2013 #, c-format msgid "function %s already exists in schema \"%s\"" -msgstr "Funktion %s existiert bereits in Schema „%s“" +msgstr "Funktion %s existiert bereits in Schema »%s«" #: commands/functioncmds.c:2066 #, c-format @@ -6468,14 +6469,14 @@ msgstr "kein Inline-Code angegeben" #: commands/functioncmds.c:2111 #, c-format msgid "language \"%s\" does not support inline code execution" -msgstr "Sprache „%s“ unterstützt das Ausführen von Inline-Code nicht" +msgstr "Sprache »%s« unterstützt das Ausführen von Inline-Code nicht" #: commands/indexcmds.c:159 commands/indexcmds.c:487 #: commands/opclasscmds.c:360 commands/opclasscmds.c:786 #: commands/opclasscmds.c:1749 #, c-format msgid "access method \"%s\" does not exist" -msgstr "Zugriffsmethode „%s“ existiert nicht" +msgstr "Zugriffsmethode »%s« existiert nicht" #: commands/indexcmds.c:341 #, c-format @@ -6490,7 +6491,7 @@ msgstr "Index kann nicht mehr als %d Spalten enthalten" #: commands/indexcmds.c:376 #, c-format msgid "cannot create index on foreign table \"%s\"" -msgstr "kann keinen Index für Fremdtabelle „%s“ erzeugen" +msgstr "kann keinen Index für Fremdtabelle »%s« erzeugen" #: commands/indexcmds.c:391 #, c-format @@ -6500,12 +6501,12 @@ msgstr "kann keine Indexe für temporäre Tabellen anderer Sitzungen erzeugen" #: commands/indexcmds.c:446 commands/tablecmds.c:541 commands/tablecmds.c:9567 #, 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" +msgstr "nur geteilte Relationen können in den Tablespace »pg_global« gelegt werden" #: commands/indexcmds.c:479 #, c-format msgid "substituting access method \"gist\" for obsolete method \"rtree\"" -msgstr "ersetze Zugriffsmethode „gist“ für obsolete Methode „rtree“" +msgstr "ersetze Zugriffsmethode »gist« für obsolete Methode »rtree«" #: commands/indexcmds.c:496 #, c-format @@ -6515,32 +6516,32 @@ msgstr "Hash-Indexe werden nicht im WAL geloggt und von ihrer Verwendung wird ab #: commands/indexcmds.c:501 #, c-format msgid "access method \"%s\" does not support unique indexes" -msgstr "Zugriffsmethode „%s“ unterstützt keine Unique Indexe" +msgstr "Zugriffsmethode »%s« unterstützt keine Unique Indexe" #: commands/indexcmds.c:506 #, c-format msgid "access method \"%s\" does not support multicolumn indexes" -msgstr "Zugriffsmethode „%s“ unterstützt keine mehrspaltigen Indexe" +msgstr "Zugriffsmethode »%s« unterstützt keine mehrspaltigen Indexe" #: commands/indexcmds.c:511 #, c-format msgid "access method \"%s\" does not support exclusion constraints" -msgstr "Zugriffsmethode „%s“ unterstützt keine Exclusion-Constraints" +msgstr "Zugriffsmethode »%s« unterstützt keine Exclusion-Constraints" #: commands/indexcmds.c:590 #, c-format msgid "%s %s will create implicit index \"%s\" for table \"%s\"" -msgstr "%s %s erstellt implizit einen Index „%s“ für Tabelle „%s“" +msgstr "%s %s erstellt implizit einen Index »%s« für Tabelle »%s«" #: commands/indexcmds.c:937 #, 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:1003 parser/parse_utilcmd.c:1844 +#: commands/indexcmds.c:1003 parser/parse_utilcmd.c:1846 #, c-format msgid "column \"%s\" named in key does not exist" -msgstr "Spalte „%s“, die im Schlüssel verwendet wird, existiert nicht" +msgstr "Spalte »%s«, die im Schlüssel verwendet wird, existiert nicht" #: commands/indexcmds.c:1063 #, c-format @@ -6553,7 +6554,7 @@ 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:1094 commands/typecmds.c:825 parser/parse_expr.c:2583 -#: parser/parse_type.c:550 parser/parse_utilcmd.c:2736 utils/adt/misc.c:546 +#: parser/parse_type.c:550 parser/parse_utilcmd.c:2738 utils/adt/misc.c:546 #, c-format msgid "collations are not supported by type %s" msgstr "Sortierfolgen werden von Typ %s nicht unterstützt" @@ -6571,7 +6572,7 @@ msgstr "In Exclusion-Constraints können nur kommutative Operatoren verwendet we #: commands/indexcmds.c:1160 #, c-format msgid "operator %s is not a member of operator family \"%s\"" -msgstr "Operator %s ist kein Mitglied der Operatorfamilie „%s“" +msgstr "Operator %s ist kein Mitglied der Operatorfamilie »%s«" #: commands/indexcmds.c:1163 #, c-format @@ -6581,17 +6582,17 @@ msgstr "Der Exklusionsoperator muss in Beziehung zur Indexoperatorklasse des Con #: commands/indexcmds.c:1198 #, c-format msgid "access method \"%s\" does not support ASC/DESC options" -msgstr "Zugriffsmethode „%s“ unterstützt die Optionen ASC/DESC nicht" +msgstr "Zugriffsmethode »%s« unterstützt die Optionen ASC/DESC nicht" #: commands/indexcmds.c:1203 #, c-format msgid "access method \"%s\" does not support NULLS FIRST/LAST options" -msgstr "Zugriffsmethode „%s“ unterstützt die Optionen NULLS FIRST/LAST nicht" +msgstr "Zugriffsmethode »%s« unterstützt die Optionen NULLS FIRST/LAST nicht" #: commands/indexcmds.c:1259 commands/typecmds.c:1932 #, 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“" +msgstr "Datentyp %s hat keine Standardoperatorklasse für Zugriffsmethode »%s«" #: commands/indexcmds.c:1261 #, c-format @@ -6602,12 +6603,12 @@ msgstr "Sie müssen für den Index eine Operatorklasse angeben oder eine Standar #: commands/opclasscmds.c:204 #, c-format msgid "operator class \"%s\" does not exist for access method \"%s\"" -msgstr "Operatorklasse „%s“ existiert nicht für Zugriffsmethode „%s“" +msgstr "Operatorklasse »%s« existiert nicht für Zugriffsmethode »%s«" #: commands/indexcmds.c:1311 commands/typecmds.c:1920 #, c-format msgid "operator class \"%s\" does not accept data type %s" -msgstr "Operatorklasse „%s“ akzeptiert Datentyp %s nicht" +msgstr "Operatorklasse »%s« akzeptiert Datentyp %s nicht" #: commands/indexcmds.c:1401 #, c-format @@ -6617,7 +6618,7 @@ msgstr "es gibt mehrere Standardoperatorklassen für Datentyp %s" #: commands/indexcmds.c:1792 #, c-format msgid "table \"%s\" has no indexes" -msgstr "Tabelle „%s“ hat keine Indexe" +msgstr "Tabelle »%s« hat keine Indexe" #: commands/indexcmds.c:1847 #, c-format @@ -6627,7 +6628,7 @@ msgstr "aktuell geöffnete Datenbank kann nicht reindiziert werden" #: commands/indexcmds.c:1949 #, c-format msgid "table \"%s.%s\" was reindexed" -msgstr "Tabelle „%s.%s“ wurde neu indiziert" +msgstr "Tabelle »%s.%s« wurde neu indiziert" #: commands/matview.c:181 #, c-format @@ -6642,7 +6643,7 @@ msgstr "Optionen CONCURRENTLY und WITH NO DATA können nicht zusammen verwendet #: commands/matview.c:611 #, c-format msgid "new data for materialized view \"%s\" contains duplicate rows without any null columns" -msgstr "neue Daten für materialisierte Sicht „%s“ enthalten doppelte Zeilen ohne Spalten mit NULL-Werten" +msgstr "neue Daten für materialisierte Sicht »%s« enthalten doppelte Zeilen ohne Spalten mit NULL-Werten" #: commands/matview.c:613 #, c-format @@ -6652,7 +6653,7 @@ msgstr "Zeile: %s" #: commands/matview.c:701 #, c-format msgid "cannot refresh materialized view \"%s\" concurrently" -msgstr "kann materialisierte Sicht „%s“ nicht nebenläufig auffrischen" +msgstr "kann materialisierte Sicht »%s« nicht nebenläufig auffrischen" #: commands/matview.c:703 #, c-format @@ -6662,12 +6663,12 @@ msgstr "Erzeugen Sie einen Unique Index ohne WHERE-Klausel für eine oder mehrer #: commands/opclasscmds.c:125 #, c-format msgid "operator family \"%s\" does not exist for access method \"%s\"" -msgstr "Operatorfamilie „%s“ existiert nicht für Zugriffsmethode „%s“" +msgstr "Operatorfamilie »%s« existiert nicht für Zugriffsmethode »%s«" #: commands/opclasscmds.c:263 #, c-format msgid "operator family \"%s\" for access method \"%s\" already exists" -msgstr "Operatorfamilie „%s“ für Zugriffsmethode „%s“ existiert bereits" +msgstr "Operatorfamilie »%s« für Zugriffsmethode »%s« existiert bereits" #: commands/opclasscmds.c:399 #, c-format @@ -6694,22 +6695,22 @@ msgstr "Storage-Typ mehrmals angegeben" #: commands/opclasscmds.c:581 #, c-format msgid "storage type cannot be different from data type for access method \"%s\"" -msgstr "Storage-Typ kann nicht vom Datentyp der Zugriffsmethode „%s“ verschieden sein" +msgstr "Storage-Typ kann nicht vom Datentyp der Zugriffsmethode »%s« verschieden sein" #: commands/opclasscmds.c:597 #, c-format msgid "operator class \"%s\" for access method \"%s\" already exists" -msgstr "Operatorklasse „%s“ für Zugriffsmethode „%s“ existiert bereits" +msgstr "Operatorklasse »%s« für Zugriffsmethode »%s« existiert bereits" #: commands/opclasscmds.c:625 #, c-format msgid "could not make operator class \"%s\" be default for type %s" -msgstr "konnte Operatorklasse „%s“ nicht zum Standard für Typ %s machen" +msgstr "konnte Operatorklasse »%s« nicht zum Standard für Typ %s machen" #: commands/opclasscmds.c:628 #, c-format msgid "Operator class \"%s\" already is the default." -msgstr "Operatorklasse „%s“ ist bereits der Standard." +msgstr "Operatorklasse »%s« ist bereits der Standard." #: commands/opclasscmds.c:756 #, c-format @@ -6744,7 +6745,7 @@ msgstr "Indexoperatoren müssen binär sein" #: commands/opclasscmds.c:1113 #, c-format msgid "access method \"%s\" does not support ordering operators" -msgstr "Zugriffsmethode „%s“ unterstützt keine Sortieroperatoren" +msgstr "Zugriffsmethode »%s« unterstützt keine Sortieroperatoren" #: commands/opclasscmds.c:1126 #, c-format @@ -6764,7 +6765,7 @@ msgstr "btree-Vergleichsprozeduren müssen Typ integer zurückgeben" #: commands/opclasscmds.c:1189 #, c-format msgid "btree sort support procedures must accept type \"internal\"" -msgstr "btree-Sortierunterstützungsprozeduren müssen Typ „internal“ akzeptieren" +msgstr "btree-Sortierunterstützungsprozeduren müssen Typ »internal« akzeptieren" #: commands/opclasscmds.c:1193 #, c-format @@ -6799,32 +6800,32 @@ msgstr "Operatornummer %d für (%s,%s) einscheint mehrmals" #: commands/opclasscmds.c:1314 #, c-format msgid "operator %d(%s,%s) already exists in operator family \"%s\"" -msgstr "Operator %d(%s,%s) existiert bereits in Operatorfamilie „%s“" +msgstr "Operator %d(%s,%s) existiert bereits in Operatorfamilie »%s«" #: commands/opclasscmds.c:1430 #, c-format msgid "function %d(%s,%s) already exists in operator family \"%s\"" -msgstr "Funktion %d(%s,%s) existiert bereits in Operatorfamilie „%s“" +msgstr "Funktion %d(%s,%s) existiert bereits in Operatorfamilie »%s«" #: commands/opclasscmds.c:1520 #, c-format msgid "operator %d(%s,%s) does not exist in operator family \"%s\"" -msgstr "Operator %d(%s,%s) existiert nicht in Operatorfamilie „%s“" +msgstr "Operator %d(%s,%s) existiert nicht in Operatorfamilie »%s«" #: commands/opclasscmds.c:1560 #, c-format msgid "function %d(%s,%s) does not exist in operator family \"%s\"" -msgstr "Funktion %d(%s,%s) existiert nicht in Operatorfamilie „%s“" +msgstr "Funktion %d(%s,%s) existiert nicht in Operatorfamilie »%s«" #: commands/opclasscmds.c:1705 #, c-format msgid "operator class \"%s\" for access method \"%s\" already exists in schema \"%s\"" -msgstr "Operatorklasse „%s“ für Zugriffsmethode „%s“ existiert bereits in Schema „%s“" +msgstr "Operatorklasse »%s« für Zugriffsmethode »%s« existiert bereits in Schema »%s«" #: commands/opclasscmds.c:1728 #, c-format msgid "operator family \"%s\" for access method \"%s\" already exists in schema \"%s\"" -msgstr "Operatorfamilie „%s“ für Zugriffsmethode „%s“ existiert bereits in Schema „%s“" +msgstr "Operatorfamilie »%s« für Zugriffsmethode »%s« existiert bereits in Schema »%s«" #: commands/operatorcmds.c:110 commands/operatorcmds.c:118 #, c-format @@ -6834,7 +6835,7 @@ msgstr "SETOF-Typ nicht als Operatorargument erlaubt" #: commands/operatorcmds.c:146 #, c-format msgid "operator attribute \"%s\" not recognized" -msgstr "Attribut „%s“ für Operator unbekannt" +msgstr "Attribut »%s« für Operator unbekannt" #: commands/operatorcmds.c:156 #, c-format @@ -6849,12 +6850,12 @@ msgstr "entweder leftarg oder rightarg (oder beides) muss angegeben werden" #: commands/operatorcmds.c:235 #, c-format msgid "restriction estimator function %s must return type \"float8\"" -msgstr "Restriktionsschätzfunktion %s muss Typ „float8“ zurückgeben" +msgstr "Restriktionsschätzfunktion %s muss Typ »float8« zurückgeben" #: commands/operatorcmds.c:274 #, c-format msgid "join estimator function %s must return type \"float8\"" -msgstr "Join-Schätzfunktion %s muss Typ „float8“ zurückgeben" +msgstr "Join-Schätzfunktion %s muss Typ »float8« zurückgeben" #: commands/policy.c:87 commands/policy.c:390 commands/policy.c:479 #: commands/tablecmds.c:966 commands/tablecmds.c:1308 @@ -6865,7 +6866,7 @@ msgstr "Join-Schätzfunktion %s muss Typ „float8“ zurückgeben" #: rewrite/rewriteDefine.c:917 #, c-format msgid "permission denied: \"%s\" is a system catalog" -msgstr "keine Berechtigung: „%s“ ist ein Systemkatalog" +msgstr "keine Berechtigung: »%s« ist ein Systemkatalog" #: commands/policy.c:170 #, c-format @@ -6880,7 +6881,7 @@ msgstr "Alle Rollen sind Mitglieder der Rolle PUBLIC." #: commands/policy.c:503 #, c-format msgid "role \"%s\" could not be removed from policy \"%s\" on \"%s\"" -msgstr "Rolle „%s“ konnte nicht aus Policy „%s“ für „%s“ entfernt werden" +msgstr "Rolle »%s« konnte nicht aus Policy »%s« für »%s« entfernt werden" #: commands/policy.c:712 #, c-format @@ -6895,12 +6896,12 @@ msgstr "für INSERT sind nur WITH-CHECK-Ausdrücke erlaubt" #: commands/policy.c:794 commands/policy.c:1244 #, c-format msgid "policy \"%s\" for table \"%s\" already exists" -msgstr "Policy „%s“ für Tabelle „%s“ existiert bereits" +msgstr "Policy »%s« für Tabelle »%s« existiert bereits" #: commands/policy.c:993 commands/policy.c:1272 commands/policy.c:1347 #, c-format msgid "policy \"%s\" for table \"%s\" does not exist" -msgstr "Policy „%s“ für Tabelle „%s“ existiert nicht" +msgstr "Policy »%s« für Tabelle »%s« existiert nicht" #: commands/policy.c:1011 #, c-format @@ -6917,7 +6918,7 @@ msgstr "ungültiger Cursorname: darf nicht leer sein" #: executor/execCurrent.c:67 utils/adt/xml.c:2391 utils/adt/xml.c:2558 #, c-format msgid "cursor \"%s\" does not exist" -msgstr "Cursor „%s“ existiert nicht" +msgstr "Cursor »%s« existiert nicht" #: commands/portalcmds.c:407 #, c-format @@ -6947,7 +6948,7 @@ msgstr "vorbereitete Anweisung ist kein SELECT" #: commands/prepare.c:332 #, c-format msgid "wrong number of parameters for prepared statement \"%s\"" -msgstr "falsche Anzahl Parameter für vorbereitete Anweisung „%s“" +msgstr "falsche Anzahl Parameter für vorbereitete Anweisung »%s«" #: commands/prepare.c:334 #, c-format @@ -6962,12 +6963,12 @@ msgstr "Parameter $%d mit Typ %s kann nicht in erwarteten Typ %s umgewandelt wer #: commands/prepare.c:464 #, c-format msgid "prepared statement \"%s\" already exists" -msgstr "vorbereitete Anweisung „%s“ existiert bereits" +msgstr "vorbereitete Anweisung »%s« existiert bereits" #: commands/prepare.c:503 #, c-format msgid "prepared statement \"%s\" does not exist" -msgstr "vorbereitete Anweisung „%s“ existiert nicht" +msgstr "vorbereitete Anweisung »%s« existiert nicht" #: commands/proclang.c:87 #, c-format @@ -6977,17 +6978,17 @@ msgstr "verwende Informationen aus pg_pltemplate statt der CREATE-LANGUAGE-Param #: commands/proclang.c:97 #, c-format msgid "must be superuser to create procedural language \"%s\"" -msgstr "nur Superuser können prozedurale Sprache „%s“ erzeugen" +msgstr "nur Superuser können prozedurale Sprache »%s« erzeugen" #: commands/proclang.c:117 commands/proclang.c:285 #, c-format msgid "function %s must return type \"language_handler\"" -msgstr "Funktion %s muss Typ „language_handler“ zurückgeben" +msgstr "Funktion %s muss Typ »language_handler« zurückgeben" #: commands/proclang.c:249 #, c-format msgid "unsupported language \"%s\"" -msgstr "nicht unterstützte Sprache „%s“" +msgstr "nicht unterstützte Sprache »%s«" #: commands/proclang.c:251 #, c-format @@ -7002,22 +7003,22 @@ msgstr "nur Superuser können maßgeschneiderte prozedurale Sprachen erzeugen" #: commands/proclang.c:278 #, c-format msgid "changing return type of function %s from \"opaque\" to \"language_handler\"" -msgstr "ändere Rückgabetyp von Funktion %s von „opaque“ in „language_handler“" +msgstr "ändere Rückgabetyp von Funktion %s von »opaque« in »language_handler«" #: commands/schemacmds.c:99 commands/schemacmds.c:262 #, c-format msgid "unacceptable schema name \"%s\"" -msgstr "inakzeptabler Schemaname „%s“" +msgstr "inakzeptabler Schemaname »%s«" #: commands/schemacmds.c:100 commands/schemacmds.c:263 #, c-format msgid "The prefix \"pg_\" is reserved for system schemas." -msgstr "Der Präfix „pg_“ ist für Systemschemas reserviert." +msgstr "Der Präfix »pg_« ist für Systemschemas reserviert." #: commands/schemacmds.c:114 #, c-format msgid "schema \"%s\" already exists, skipping" -msgstr "Schema „%s“ existiert bereits, wird übersprungen" +msgstr "Schema »%s« existiert bereits, wird übersprungen" #: commands/seclabel.c:60 #, c-format @@ -7032,7 +7033,7 @@ msgstr "Provider muss angegeben werden, wenn mehrere Security-Label-Provider gel #: commands/seclabel.c:82 #, c-format msgid "security label provider \"%s\" is not loaded" -msgstr "Security-Label-Provider „%s“ ist nicht geladen" +msgstr "Security-Label-Provider »%s« ist nicht geladen" #: commands/sequence.c:127 #, c-format @@ -7042,17 +7043,17 @@ msgstr "ungeloggte Sequenzen werden nicht unterstützt" #: commands/sequence.c:651 #, c-format msgid "nextval: reached maximum value of sequence \"%s\" (%s)" -msgstr "nextval: Maximalwert von Sequenz „%s“ erreicht (%s)" +msgstr "nextval: Maximalwert von Sequenz »%s« erreicht (%s)" #: commands/sequence.c:674 #, c-format msgid "nextval: reached minimum value of sequence \"%s\" (%s)" -msgstr "nextval: Minimalwert von Sequenz „%s“ erreicht (%s)" +msgstr "nextval: Minimalwert von Sequenz »%s« erreicht (%s)" #: commands/sequence.c:792 #, c-format msgid "currval of sequence \"%s\" is not yet defined in this session" -msgstr "currval von Sequenz „%s“ ist in dieser Sitzung noch nicht definiert" +msgstr "currval von Sequenz »%s« ist in dieser Sitzung noch nicht definiert" #: commands/sequence.c:811 commands/sequence.c:817 #, c-format @@ -7062,7 +7063,7 @@ msgstr "lastval ist in dieser Sitzung noch nicht definiert" #: commands/sequence.c:893 #, c-format msgid "setval: value %s is out of bounds for sequence \"%s\" (%s..%s)" -msgstr "setval: Wert %s ist außerhalb des gültigen Bereichs von Sequenz „%s“ (%s..%s)" +msgstr "setval: Wert %s ist außerhalb des gültigen Bereichs von Sequenz »%s« (%s..%s)" #: commands/sequence.c:1267 #, c-format @@ -7112,7 +7113,7 @@ msgstr "Geben Sie OWNED BY tabelle.spalte oder OWNED BY NONE an." #: commands/sequence.c:1473 #, c-format msgid "referenced relation \"%s\" is not a table or foreign table" -msgstr "Relation „%s“, auf die verwiesen wird, ist keine Tabelle oder Fremdtabelle" +msgstr "Relation »%s«, auf die verwiesen wird, ist keine Tabelle oder Fremdtabelle" #: commands/sequence.c:1480 #, c-format @@ -7127,12 +7128,12 @@ msgstr "Sequenz muss im selben Schema wie die verknüpfte Tabelle sein" #: commands/tablecmds.c:213 #, c-format msgid "table \"%s\" does not exist" -msgstr "Tabelle „%s“ existiert nicht" +msgstr "Tabelle »%s« existiert nicht" #: commands/tablecmds.c:214 #, c-format msgid "table \"%s\" does not exist, skipping" -msgstr "Tabelle „%s“ existiert nicht, wird übersprungen" +msgstr "Tabelle »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:216 msgid "Use DROP TABLE to remove a table." @@ -7141,12 +7142,12 @@ msgstr "Verwenden Sie DROP TABLE, um eine Tabelle zu löschen." #: commands/tablecmds.c:219 #, c-format msgid "sequence \"%s\" does not exist" -msgstr "Sequenz „%s“ existiert nicht" +msgstr "Sequenz »%s« existiert nicht" #: commands/tablecmds.c:220 #, c-format msgid "sequence \"%s\" does not exist, skipping" -msgstr "Sequenz „%s“ existiert nicht, wird übersprungen" +msgstr "Sequenz »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:222 msgid "Use DROP SEQUENCE to remove a sequence." @@ -7155,12 +7156,12 @@ msgstr "Verwenden Sie DROP SEQUENCE, um eine Sequenz zu löschen." #: commands/tablecmds.c:225 #, c-format msgid "view \"%s\" does not exist" -msgstr "Sicht „%s“ existiert nicht" +msgstr "Sicht »%s« existiert nicht" #: commands/tablecmds.c:226 #, c-format msgid "view \"%s\" does not exist, skipping" -msgstr "Sicht „%s“ existiert nicht, wird übersprungen" +msgstr "Sicht »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:228 msgid "Use DROP VIEW to remove a view." @@ -7169,26 +7170,26 @@ msgstr "Verwenden Sie DROP VIEW, um eine Sicht zu löschen." #: commands/tablecmds.c:231 #, c-format msgid "materialized view \"%s\" does not exist" -msgstr "materialisierte Sicht „%s“ existiert nicht" +msgstr "materialisierte Sicht »%s« existiert nicht" #: commands/tablecmds.c:232 #, c-format msgid "materialized view \"%s\" does not exist, skipping" -msgstr "materialisierte Sicht „%s“ existiert nicht, wird übersprungen" +msgstr "materialisierte Sicht »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:234 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:237 parser/parse_utilcmd.c:1593 +#: commands/tablecmds.c:237 parser/parse_utilcmd.c:1595 #, c-format msgid "index \"%s\" does not exist" -msgstr "Index „%s“ existiert nicht" +msgstr "Index »%s« existiert nicht" #: commands/tablecmds.c:238 #, c-format msgid "index \"%s\" does not exist, skipping" -msgstr "Index „%s“ existiert nicht, wird übersprungen" +msgstr "Index »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:240 msgid "Use DROP INDEX to remove an index." @@ -7197,7 +7198,7 @@ msgstr "Verwenden Sie DROP INDEX, um einen Index zu löschen." #: commands/tablecmds.c:245 #, c-format msgid "\"%s\" is not a type" -msgstr "„%s“ ist kein Typ" +msgstr "»%s« ist kein Typ" #: commands/tablecmds.c:246 msgid "Use DROP TYPE to remove a type." @@ -7207,12 +7208,12 @@ msgstr "Verwenden Sie DROP TYPE, um einen Typen zu löschen." #: commands/tablecmds.c:11163 #, c-format msgid "foreign table \"%s\" does not exist" -msgstr "Fremdtabelle „%s“ existiert nicht" +msgstr "Fremdtabelle »%s« existiert nicht" #: commands/tablecmds.c:250 #, c-format msgid "foreign table \"%s\" does not exist, skipping" -msgstr "Fremdtabelle „%s“ existiert nicht, wird übersprungen" +msgstr "Fremdtabelle »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:252 msgid "Use DROP FOREIGN TABLE to remove a foreign table." @@ -7241,22 +7242,22 @@ msgstr "DROP INDEX CONCURRENTLY unterstützt kein CASCADE" #: commands/tablecmds.c:1080 #, c-format msgid "truncate cascades to table \"%s\"" -msgstr "Truncate-Vorgang leert ebenfalls Tabelle „%s“" +msgstr "Truncate-Vorgang leert ebenfalls Tabelle »%s«" #: commands/tablecmds.c:1318 #, c-format msgid "cannot truncate temporary tables of other sessions" msgstr "kann temporäre Tabellen anderer Sitzungen nicht leeren" -#: commands/tablecmds.c:1524 parser/parse_utilcmd.c:1807 +#: commands/tablecmds.c:1524 parser/parse_utilcmd.c:1809 #, c-format msgid "inherited relation \"%s\" is not a table or foreign table" -msgstr "geerbte Relation „%s“ ist keine Tabelle oder Fremdtabelle" +msgstr "geerbte Relation »%s« ist keine Tabelle oder Fremdtabelle" #: commands/tablecmds.c:1531 commands/tablecmds.c:10023 #, c-format msgid "cannot inherit from temporary relation \"%s\"" -msgstr "von temporärer Relation „%s“ kann nicht geerbt werden" +msgstr "von temporärer Relation »%s« kann nicht geerbt werden" #: commands/tablecmds.c:1539 commands/tablecmds.c:10031 #, c-format @@ -7266,17 +7267,17 @@ msgstr "von temporärer Relation einer anderen Sitzung kann nicht geerbt werden" #: commands/tablecmds.c:1555 commands/tablecmds.c:10065 #, c-format msgid "relation \"%s\" would be inherited from more than once" -msgstr "von der Relation „%s“ würde mehrmals geerbt werden" +msgstr "von der Relation »%s« würde mehrmals geerbt werden" #: commands/tablecmds.c:1603 #, c-format msgid "merging multiple inherited definitions of column \"%s\"" -msgstr "geerbte Definitionen von Spalte „%s“ werden zusammengeführt" +msgstr "geerbte Definitionen von Spalte »%s« werden zusammengeführt" #: commands/tablecmds.c:1611 #, c-format msgid "inherited column \"%s\" has a type conflict" -msgstr "geerbte Spalte „%s“ hat Typkonflikt" +msgstr "geerbte Spalte »%s« hat Typkonflikt" #: commands/tablecmds.c:1613 commands/tablecmds.c:1634 #: commands/tablecmds.c:1832 commands/tablecmds.c:1854 @@ -7290,21 +7291,21 @@ msgstr "%s gegen %s" #: commands/tablecmds.c:1620 #, c-format msgid "inherited column \"%s\" has a collation conflict" -msgstr "geerbte Spalte „%s“ hat Sortierfolgenkonflikt" +msgstr "geerbte Spalte »%s« hat Sortierfolgenkonflikt" #: commands/tablecmds.c:1622 commands/tablecmds.c:1842 #: commands/tablecmds.c:4757 #, c-format msgid "\"%s\" versus \"%s\"" -msgstr "„%s“ gegen „%s“" +msgstr "»%s« gegen »%s«" #: commands/tablecmds.c:1632 #, c-format msgid "inherited column \"%s\" has a storage parameter conflict" -msgstr "geerbte Spalte „%s“ hat einen Konflikt bei einem Storage-Parameter" +msgstr "geerbte Spalte »%s« hat einen Konflikt bei einem Storage-Parameter" #: commands/tablecmds.c:1745 parser/parse_utilcmd.c:894 -#: parser/parse_utilcmd.c:1238 parser/parse_utilcmd.c:1314 +#: parser/parse_utilcmd.c:1240 parser/parse_utilcmd.c:1316 #, c-format msgid "cannot convert whole-row table reference" msgstr "kann Verweis auf ganze Zeile der Tabelle nicht umwandeln" @@ -7312,17 +7313,17 @@ msgstr "kann Verweis auf ganze Zeile der Tabelle nicht umwandeln" #: commands/tablecmds.c:1746 parser/parse_utilcmd.c:895 #, 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“." +msgstr "Constraint »%s« enthält einen Verweis auf die ganze Zeile der Tabelle »%s«." #: commands/tablecmds.c:1818 #, c-format msgid "merging column \"%s\" with inherited definition" -msgstr "Spalte „%s“ wird mit geerbter Definition zusammengeführt" +msgstr "Spalte »%s« wird mit geerbter Definition zusammengeführt" #: commands/tablecmds.c:1822 #, c-format msgid "moving and merging column \"%s\" with inherited definition" -msgstr "Spalte „%s“ wird verschoben und mit geerbter Definition zusammengeführt" +msgstr "Spalte »%s« wird verschoben und mit geerbter Definition zusammengeführt" #: commands/tablecmds.c:1823 #, c-format @@ -7332,22 +7333,22 @@ msgstr "Benutzerdefinierte Spalte wurde auf die Position der geerbten Spalte ver #: commands/tablecmds.c:1830 #, c-format msgid "column \"%s\" has a type conflict" -msgstr "für Spalte „%s“ besteht ein Typkonflikt" +msgstr "für Spalte »%s« besteht ein Typkonflikt" #: commands/tablecmds.c:1840 #, c-format msgid "column \"%s\" has a collation conflict" -msgstr "für Spalte „%s“ besteht ein Sortierfolgenkonflikt" +msgstr "für Spalte »%s« besteht ein Sortierfolgenkonflikt" #: commands/tablecmds.c:1852 #, c-format msgid "column \"%s\" has a storage parameter conflict" -msgstr "für Spalte „%s“ besteht ein Konflikt bei einem Storage-Parameter" +msgstr "für Spalte »%s« besteht ein Konflikt bei einem Storage-Parameter" #: commands/tablecmds.c:1904 #, c-format msgid "column \"%s\" inherits conflicting default values" -msgstr "Spalte „%s“ erbt widersprüchliche Vorgabewerte" +msgstr "Spalte »%s« erbt widersprüchliche Vorgabewerte" #: commands/tablecmds.c:1906 #, c-format @@ -7357,7 +7358,7 @@ msgstr "Um den Konflikt zu lösen, geben Sie einen Vorgabewert ausdrücklich an. #: commands/tablecmds.c:1953 #, 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" +msgstr "Check-Constraint-Name »%s« erscheint mehrmals, aber mit unterschiedlichen Ausdrücken" #: commands/tablecmds.c:2147 #, c-format @@ -7367,54 +7368,54 @@ msgstr "Spalte einer getypten Tabelle kann nicht umbenannt werden" #: commands/tablecmds.c:2164 #, c-format msgid "\"%s\" is not a table, view, materialized view, composite type, index, or foreign table" -msgstr "„%s“ ist weder Tabelle, Sicht, materialisierte Sicht, zusammengesetzter Typ, Index noch Fremdtabelle" +msgstr "»%s« ist weder Tabelle, Sicht, materialisierte Sicht, zusammengesetzter Typ, Index noch Fremdtabelle" #: commands/tablecmds.c:2258 #, 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" +msgstr "vererbte Spalte »%s« muss ebenso in den abgeleiteten Tabellen umbenannt werden" #: commands/tablecmds.c:2290 #, c-format msgid "cannot rename system column \"%s\"" -msgstr "Systemspalte „%s“ kann nicht umbenannt werden" +msgstr "Systemspalte »%s« kann nicht umbenannt werden" #: commands/tablecmds.c:2305 #, c-format msgid "cannot rename inherited column \"%s\"" -msgstr "kann vererbte Spalte „%s“ nicht umbenennen" +msgstr "kann vererbte Spalte »%s« nicht umbenennen" #: commands/tablecmds.c:2460 #, 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" +msgstr "vererbter Constraint »%s« muss ebenso in den abgeleiteten Tabellen umbenannt werden" #: commands/tablecmds.c:2467 #, c-format msgid "cannot rename inherited constraint \"%s\"" -msgstr "kann vererbten Constraint „%s“ nicht umbenennen" +msgstr "kann vererbten Constraint »%s« nicht umbenennen" #. translator: first %s is a SQL command, eg ALTER TABLE #: commands/tablecmds.c:2693 #, 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" +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:2702 #, 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" +msgstr "%s mit Relation »%s« nicht möglich, weil es anstehende Trigger-Ereignisse dafür gibt" #: commands/tablecmds.c:3776 #, c-format msgid "cannot rewrite system relation \"%s\"" -msgstr "Systemrelation „%s“ kann nicht neu geschrieben werden" +msgstr "Systemrelation »%s« kann nicht neu geschrieben werden" #: commands/tablecmds.c:3782 #, 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" +msgstr "Tabelle »%s«, die als Katalogtabelle verwendet wird, kann nicht neu geschrieben werden" #: commands/tablecmds.c:3792 #, c-format @@ -7424,88 +7425,88 @@ msgstr "kann temporäre Tabellen anderer Sitzungen nicht neu schreiben" #: commands/tablecmds.c:4060 #, c-format msgid "rewriting table \"%s\"" -msgstr "schreibe Tabelle „%s“ neu" +msgstr "schreibe Tabelle »%s« neu" #: commands/tablecmds.c:4064 #, c-format msgid "verifying table \"%s\"" -msgstr "überprüfe Tabelle „%s“" +msgstr "überprüfe Tabelle »%s«" #: commands/tablecmds.c:4178 #, c-format msgid "column \"%s\" contains null values" -msgstr "Spalte „%s“ enthält NULL-Werte" +msgstr "Spalte »%s« enthält NULL-Werte" #: commands/tablecmds.c:4193 commands/tablecmds.c:7336 #, c-format msgid "check constraint \"%s\" is violated by some row" -msgstr "Check-Constraint „%s“ wird von irgendeiner Zeile verletzt" +msgstr "Check-Constraint »%s« wird von irgendeiner Zeile verletzt" #: commands/tablecmds.c:4341 commands/trigger.c:234 #: rewrite/rewriteDefine.c:267 rewrite/rewriteDefine.c:912 #, c-format msgid "\"%s\" is not a table or view" -msgstr "„%s“ ist keine Tabelle oder Sicht" +msgstr "»%s« ist keine Tabelle oder Sicht" #: commands/tablecmds.c:4344 commands/trigger.c:1120 commands/trigger.c:1225 #, c-format msgid "\"%s\" is not a table, view, or foreign table" -msgstr "„%s“ ist keine Tabelle, Sicht oder Fremdtabelle" +msgstr "»%s« ist keine Tabelle, Sicht oder Fremdtabelle" #: commands/tablecmds.c:4347 #, c-format msgid "\"%s\" is not a table, view, materialized view, or index" -msgstr "„%s“ ist weder Tabelle, Sicht, materialisierte Sicht noch Index" +msgstr "»%s« ist weder Tabelle, Sicht, materialisierte Sicht noch Index" #: commands/tablecmds.c:4353 #, c-format msgid "\"%s\" is not a table, materialized view, or index" -msgstr "„%s“ ist weder Tabelle, materialisierte Sicht noch Index" +msgstr "»%s« ist weder Tabelle, materialisierte Sicht noch Index" #: commands/tablecmds.c:4356 #, c-format msgid "\"%s\" is not a table, materialized view, or foreign table" -msgstr "„%s“ ist weder Tabelle, materialisierte Sicht noch Fremdtabelle" +msgstr "»%s« ist weder Tabelle, materialisierte Sicht noch Fremdtabelle" #: commands/tablecmds.c:4359 #, c-format msgid "\"%s\" is not a table or foreign table" -msgstr "„%s“ ist keine Tabelle oder Fremdtabelle" +msgstr "»%s« ist keine Tabelle oder Fremdtabelle" #: commands/tablecmds.c:4362 #, c-format msgid "\"%s\" is not a table, composite type, or foreign table" -msgstr "„%s“ ist weder Tabelle, Sicht, zusammengesetzter Typ noch Fremdtabelle" +msgstr "»%s« ist weder Tabelle, Sicht, zusammengesetzter Typ noch Fremdtabelle" #: commands/tablecmds.c:4365 commands/tablecmds.c:5395 #, c-format msgid "\"%s\" is not a table, materialized view, index, or foreign table" -msgstr "„%s“ ist weder Tabelle, materialisierte Sicht, Index noch Fremdtabelle" +msgstr "»%s« ist weder Tabelle, materialisierte Sicht, Index noch Fremdtabelle" #: commands/tablecmds.c:4375 #, c-format msgid "\"%s\" is of the wrong type" -msgstr "„%s“ hat den falschen Typ" +msgstr "»%s« hat den falschen Typ" #: commands/tablecmds.c:4527 commands/tablecmds.c:4534 #, 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" +msgstr "kann Typ »%s« nicht ändern, weil Spalte »%s.%s« ihn verwendet" #: commands/tablecmds.c:4541 #, 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" +msgstr "kann Fremdtabelle »%s« nicht ändern, weil Spalte »%s.%s« ihren Zeilentyp verwendet" #: commands/tablecmds.c:4548 #, 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" +msgstr "kann Tabelle »%s« nicht ändern, weil Spalte »%s.%s« ihren Zeilentyp verwendet" #: commands/tablecmds.c:4610 #, 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" +msgstr "kann Typ »%s« nicht ändern, weil er der Typ einer getypten Tabelle ist" #: commands/tablecmds.c:4612 #, c-format @@ -7525,22 +7526,22 @@ msgstr "zu einer getypten Tabelle kann keine Spalte hinzugefügt werden" #: commands/tablecmds.c:4749 commands/tablecmds.c:10224 #, c-format msgid "child table \"%s\" has different type for column \"%s\"" -msgstr "abgeleitete Tabelle „%s“ hat unterschiedlichen Typ für Spalte „%s“" +msgstr "abgeleitete Tabelle »%s« hat unterschiedlichen Typ für Spalte »%s«" #: commands/tablecmds.c:4755 commands/tablecmds.c:10231 #, c-format msgid "child table \"%s\" has different collation for column \"%s\"" -msgstr "abgeleitete Tabelle „%s“ hat unterschiedliche Sortierfolge für Spalte „%s“" +msgstr "abgeleitete Tabelle »%s« hat unterschiedliche Sortierfolge für Spalte »%s«" #: commands/tablecmds.c:4765 #, c-format msgid "child table \"%s\" has a conflicting \"%s\" column" -msgstr "abgeleitete Tabelle „%s“ hat eine widersprüchliche Spalte „%s“" +msgstr "abgeleitete Tabelle »%s« hat eine widersprüchliche Spalte »%s«" #: commands/tablecmds.c:4777 #, c-format msgid "merging definition of column \"%s\" for child \"%s\"" -msgstr "Definition von Spalte „%s“ für abgeleitete Tabelle „%s“ wird zusammengeführt" +msgstr "Definition von Spalte »%s« für abgeleitete Tabelle »%s« wird zusammengeführt" #: commands/tablecmds.c:4998 #, c-format @@ -7550,7 +7551,7 @@ msgstr "Spalte muss ebenso in den abgeleiteten Tabellen hinzugefügt werden" #: commands/tablecmds.c:5068 #, c-format msgid "column \"%s\" of relation \"%s\" already exists" -msgstr "Spalte „%s“ von Relation „%s“ existiert bereits" +msgstr "Spalte »%s« von Relation »%s« existiert bereits" #: commands/tablecmds.c:5176 commands/tablecmds.c:5282 #: commands/tablecmds.c:5340 commands/tablecmds.c:5454 @@ -7558,12 +7559,12 @@ msgstr "Spalte „%s“ von Relation „%s“ existiert bereits" #: commands/tablecmds.c:7854 commands/tablecmds.c:8479 #, c-format msgid "cannot alter system column \"%s\"" -msgstr "Systemspalte „%s“ kann nicht geändert werden" +msgstr "Systemspalte »%s« kann nicht geändert werden" #: commands/tablecmds.c:5212 #, c-format msgid "column \"%s\" is in a primary key" -msgstr "Spalte „%s“ ist in einem Primärschlüssel" +msgstr "Spalte »%s« ist in einem Primärschlüssel" #: commands/tablecmds.c:5427 #, c-format @@ -7578,7 +7579,7 @@ msgstr "setze Statistikziel auf %d herab" #: commands/tablecmds.c:5585 #, c-format msgid "invalid storage type \"%s\"" -msgstr "ungültiger Storage-Typ „%s“" +msgstr "ungültiger Storage-Typ »%s«" #: commands/tablecmds.c:5617 #, c-format @@ -7593,22 +7594,22 @@ msgstr "aus einer getypten Tabelle können keine Spalten gelöscht werden" #: commands/tablecmds.c:5699 #, c-format msgid "column \"%s\" of relation \"%s\" does not exist, skipping" -msgstr "Spalte „%s“ von Relation „%s“ existiert nicht, wird übersprungen" +msgstr "Spalte »%s« von Relation »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:5712 #, c-format msgid "cannot drop system column \"%s\"" -msgstr "Systemspalte „%s“ kann nicht gelöscht werden" +msgstr "Systemspalte »%s« kann nicht gelöscht werden" #: commands/tablecmds.c:5719 #, c-format msgid "cannot drop inherited column \"%s\"" -msgstr "geerbte Spalte „%s“ kann nicht gelöscht werden" +msgstr "geerbte Spalte »%s« kann nicht gelöscht werden" #: commands/tablecmds.c:5959 #, 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“" +msgstr "ALTER TABLE / ADD CONSTRAINT USING INDEX benennt Index »%s« um in »%s«" #: commands/tablecmds.c:6172 #, c-format @@ -7618,7 +7619,7 @@ msgstr "Constraint muss ebenso in den abgeleiteten Tabellen hinzugefügt werden" #: commands/tablecmds.c:6243 #, c-format msgid "referenced relation \"%s\" is not a table" -msgstr "Relation „%s“, auf die verwiesen wird, ist keine Tabelle" +msgstr "Relation »%s«, auf die verwiesen wird, ist keine Tabelle" #: commands/tablecmds.c:6266 #, c-format @@ -7648,28 +7649,28 @@ msgstr "Anzahl der Quell- und Zielspalten im Fremdschlüssel stimmt nicht übere #: commands/tablecmds.c:6451 #, c-format msgid "foreign key constraint \"%s\" cannot be implemented" -msgstr "Fremdschlüssel-Constraint „%s“ kann nicht implementiert werden" +msgstr "Fremdschlüssel-Constraint »%s« kann nicht implementiert werden" #: commands/tablecmds.c:6454 #, c-format msgid "Key columns \"%s\" and \"%s\" are of incompatible types: %s and %s." -msgstr "Schlüsselspalten „%s“ und „%s“ haben inkompatible Typen: %s und %s." +msgstr "Schlüsselspalten »%s« und »%s« haben inkompatible Typen: %s und %s." #: commands/tablecmds.c:6661 commands/tablecmds.c:6811 #: commands/tablecmds.c:7693 commands/tablecmds.c:7749 #, c-format msgid "constraint \"%s\" of relation \"%s\" does not exist" -msgstr "Constraint „%s“ von Relation „%s“ existiert nicht" +msgstr "Constraint »%s« von Relation »%s« existiert nicht" #: commands/tablecmds.c:6667 #, 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" +msgstr "Constraint »%s« von Relation »%s« ist kein Fremdschlüssel-Constraint" #: commands/tablecmds.c:6818 #, c-format msgid "constraint \"%s\" of relation \"%s\" is not a foreign key or check constraint" -msgstr "Constraint „%s“ von Relation „%s“ ist kein Fremdschlüssel- oder Check-Constraint" +msgstr "Constraint »%s« von Relation »%s« ist kein Fremdschlüssel- oder Check-Constraint" #: commands/tablecmds.c:6886 #, c-format @@ -7679,7 +7680,7 @@ msgstr "Constraint muss ebenso in den abgeleiteten Tabellen validiert werden" #: commands/tablecmds.c:6955 #, c-format msgid "column \"%s\" referenced in foreign key constraint does not exist" -msgstr "Spalte „%s“, die im Fremdschlüssel verwendet wird, existiert nicht" +msgstr "Spalte »%s«, die im Fremdschlüssel verwendet wird, existiert nicht" #: commands/tablecmds.c:6960 #, c-format @@ -7689,12 +7690,12 @@ msgstr "Fremdschlüssel kann nicht mehr als %d Schlüssel haben" #: commands/tablecmds.c:7025 #, 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" +msgstr "aufschiebbarer Primärschlüssel kann nicht für Tabelle »%s«, auf die verwiesen wird, verwendet werden" #: commands/tablecmds.c:7042 #, 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" +msgstr "in Tabelle »%s«, auf die verwiesen wird, gibt es keinen Primärschlüssel" #: commands/tablecmds.c:7107 #, c-format @@ -7704,27 +7705,27 @@ msgstr "die Liste der Spalten, auf die ein Fremdschlüssel verweist, darf keine #: commands/tablecmds.c:7201 #, 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" +msgstr "aufschiebbarer Unique-Constraint kann nicht für Tabelle »%s«, auf die verwiesen wird, verwendet werden" #: commands/tablecmds.c:7206 #, 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" +msgstr "in Tabelle »%s«, auf die verwiesen wird, gibt es keinen Unique-Constraint, der auf die angegebenen Schlüssel passt" #: commands/tablecmds.c:7369 #, c-format msgid "validating foreign key constraint \"%s\"" -msgstr "validiere Fremdschlüssel-Constraint „%s“" +msgstr "validiere Fremdschlüssel-Constraint »%s«" #: commands/tablecmds.c:7665 #, c-format msgid "cannot drop inherited constraint \"%s\" of relation \"%s\"" -msgstr "geerbter Constraint „%s“ von Relation „%s“ kann nicht gelöscht werden" +msgstr "geerbter Constraint »%s« von Relation »%s« kann nicht gelöscht werden" #: commands/tablecmds.c:7699 #, c-format msgid "constraint \"%s\" of relation \"%s\" does not exist, skipping" -msgstr "Constraint „%s“ von Relation „%s“ existiert nicht, wird übersprungen" +msgstr "Constraint »%s« von Relation »%s« existiert nicht, wird übersprungen" #: commands/tablecmds.c:7838 #, c-format @@ -7734,12 +7735,12 @@ msgstr "Spaltentyp einer getypten Tabelle kann nicht geändert werden" #: commands/tablecmds.c:7861 #, c-format msgid "cannot alter inherited column \"%s\"" -msgstr "kann vererbte Spalte „%s“ nicht ändern" +msgstr "kann vererbte Spalte »%s« nicht ändern" #: commands/tablecmds.c:7910 #, 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" +msgstr "Ergebnis der USING-Klausel für Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" #: commands/tablecmds.c:7913 #, c-format @@ -7749,28 +7750,28 @@ msgstr "Sie müssen möglicherweise eine ausdrückliche Typumwandlung hinzufüge #: commands/tablecmds.c:7917 #, c-format msgid "column \"%s\" cannot be cast automatically to type %s" -msgstr "Spalte „%s“ kann nicht automatisch in Typ %s umgewandelt werden" +msgstr "Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" #. translator: USING is SQL, don't translate it #: commands/tablecmds.c:7920 #, c-format msgid "You might need to specify \"USING %s::%s\"." -msgstr "Sie müssen möglicherweise „USING %s::%s“ angeben." +msgstr "Sie müssen möglicherweise »USING %s::%s« angeben." #: commands/tablecmds.c:7973 #, 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" +msgstr "Typ der vererbten Spalte »%s« muss ebenso in den abgeleiteten Tabellen geändert werden" #: commands/tablecmds.c:8060 #, c-format msgid "cannot alter type of column \"%s\" twice" -msgstr "Typ der Spalte „%s“ kann nicht zweimal geändert werden" +msgstr "Typ der Spalte »%s« kann nicht zweimal geändert werden" #: commands/tablecmds.c:8096 #, 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" +msgstr "Vorgabewert der Spalte »%s« kann nicht automatisch in Typ %s umgewandelt werden" #: commands/tablecmds.c:8222 #, c-format @@ -7781,7 +7782,7 @@ msgstr "Typ einer Spalte, die von einer Sicht oder Regel verwendet wird, kann ni #: commands/tablecmds.c:8260 #, c-format msgid "%s depends on column \"%s\"" -msgstr "%s hängt von Spalte „%s“ ab" +msgstr "%s hängt von Spalte »%s« ab" #: commands/tablecmds.c:8241 #, c-format @@ -7796,7 +7797,7 @@ msgstr "Typ einer Spalte, die in einer Policy-Definition verwendet wird, kann ni #: commands/tablecmds.c:8924 #, c-format msgid "cannot change owner of index \"%s\"" -msgstr "kann Eigentümer des Index „%s“ nicht ändern" +msgstr "kann Eigentümer des Index »%s« nicht ändern" #: commands/tablecmds.c:8926 #, c-format @@ -7806,12 +7807,12 @@ msgstr "Ändern Sie stattdessen den Eigentümer der Tabelle des Index." #: commands/tablecmds.c:8942 #, c-format msgid "cannot change owner of sequence \"%s\"" -msgstr "kann Eigentümer der Sequenz „%s“ nicht ändern" +msgstr "kann Eigentümer der Sequenz »%s« nicht ändern" #: commands/tablecmds.c:8944 commands/tablecmds.c:11365 #, c-format msgid "Sequence \"%s\" is linked to table \"%s\"." -msgstr "Sequenz „%s“ ist mit Tabelle „%s“ verknüpft." +msgstr "Sequenz »%s« ist mit Tabelle »%s« verknüpft." #: commands/tablecmds.c:8956 commands/tablecmds.c:12006 #, c-format @@ -7821,7 +7822,7 @@ msgstr "Verwenden Sie stattdessen ALTER TYPE." #: commands/tablecmds.c:8965 #, c-format msgid "\"%s\" is not a table, view, sequence, or foreign table" -msgstr "„%s“ ist keine Tabelle, Sicht, Sequenz oder Fremdtabelle" +msgstr "»%s« ist keine Tabelle, Sicht, Sequenz oder Fremdtabelle" #: commands/tablecmds.c:9308 #, c-format @@ -7831,9 +7832,9 @@ msgstr "mehrere SET TABLESPACE Unterbefehle sind ungültig" #: commands/tablecmds.c:9381 #, c-format msgid "\"%s\" is not a table, view, materialized view, index, or TOAST table" -msgstr "„%s“ ist weder Tabelle, Sicht, materialisierte Sicht, Index noch TOAST-Tabelle" +msgstr "»%s« ist weder Tabelle, Sicht, materialisierte Sicht, Index noch TOAST-Tabelle" -#: commands/tablecmds.c:9414 commands/view.c:481 +#: commands/tablecmds.c:9414 commands/view.c:469 #, 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" @@ -7841,7 +7842,7 @@ msgstr "WITH CHECK OPTION wird nur für automatisch aktualisierbare Sichten unte #: commands/tablecmds.c:9560 #, c-format msgid "cannot move system relation \"%s\"" -msgstr "Systemrelation „%s“ kann nicht verschoben werden" +msgstr "Systemrelation »%s« kann nicht verschoben werden" #: commands/tablecmds.c:9576 #, c-format @@ -7856,17 +7857,17 @@ msgstr "nur Tabellen, Indexe und materialisierte Sichten existieren in Tablespac #: commands/tablecmds.c:9725 #, 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" +msgstr "Relationen können nicht in den oder aus dem Tablespace »pg_global« verschoben werden" #: commands/tablecmds.c:9816 #, 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" +msgstr "Abbruch weil Sperre für Relation »%s.%s« nicht verfügbar ist" #: commands/tablecmds.c:9832 #, c-format msgid "no matching relations in tablespace \"%s\" found" -msgstr "keine passenden Relationen in Tablespace „%s“ gefunden" +msgstr "keine passenden Relationen in Tablespace »%s« gefunden" #: commands/tablecmds.c:9906 storage/buffer/bufmgr.c:801 #, c-format @@ -7891,42 +7892,42 @@ msgstr "zirkuläre Vererbung ist nicht erlaubt" #: commands/tablecmds.c:10093 #, c-format msgid "\"%s\" is already a child of \"%s\"." -msgstr "„%s“ ist schon von „%s“ abgeleitet." +msgstr "»%s« ist schon von »%s« abgeleitet." #: commands/tablecmds.c:10101 #, c-format msgid "table \"%s\" without OIDs cannot inherit from table \"%s\" with OIDs" -msgstr "Tabelle „%s“ ohne OIDs kann nicht von Tabelle „%s“ mit OIDs erben" +msgstr "Tabelle »%s« ohne OIDs kann nicht von Tabelle »%s« mit OIDs erben" #: commands/tablecmds.c:10242 #, c-format msgid "column \"%s\" in child table must be marked NOT NULL" -msgstr "Spalte „%s“ in abgeleiteter Tabelle muss als NOT NULL markiert sein" +msgstr "Spalte »%s« in abgeleiteter Tabelle muss als NOT NULL markiert sein" #: commands/tablecmds.c:10258 #, c-format msgid "child table is missing column \"%s\"" -msgstr "Spalte „%s“ fehlt in abgeleiteter Tabelle" +msgstr "Spalte »%s« fehlt in abgeleiteter Tabelle" #: commands/tablecmds.c:10341 #, 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“" +msgstr "abgeleitete Tabelle »%s« hat unterschiedliche Definition für Check-Constraint »%s«" #: commands/tablecmds.c:10349 #, 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“" +msgstr "Constraint »%s« kollidiert mit nicht vererbtem Constraint für abgeleitete Tabelle »%s«" #: commands/tablecmds.c:10373 #, c-format msgid "child table is missing constraint \"%s\"" -msgstr "Constraint „%s“ fehlt in abgeleiteter Tabelle" +msgstr "Constraint »%s« fehlt in abgeleiteter Tabelle" #: commands/tablecmds.c:10457 #, c-format msgid "relation \"%s\" is not a parent of relation \"%s\"" -msgstr "Relation „%s“ ist keine Basisrelation von Relation „%s“" +msgstr "Relation »%s« ist keine Basisrelation von Relation »%s«" #: commands/tablecmds.c:10691 #, c-format @@ -7936,77 +7937,77 @@ msgstr "getypte Tabellen können nicht erben" #: commands/tablecmds.c:10722 #, c-format msgid "table is missing column \"%s\"" -msgstr "Spalte „%s“ fehlt in Tabelle" +msgstr "Spalte »%s« fehlt in Tabelle" #: commands/tablecmds.c:10732 #, c-format msgid "table has column \"%s\" where type requires \"%s\"" -msgstr "Tabelle hat Spalte „%s“, aber Typ benötigt „%s“" +msgstr "Tabelle hat Spalte »%s«, aber Typ benötigt »%s«" #: commands/tablecmds.c:10741 #, c-format msgid "table \"%s\" has different type for column \"%s\"" -msgstr "Tabelle „%s“ hat unterschiedlichen Typ für Spalte „%s“" +msgstr "Tabelle »%s« hat unterschiedlichen Typ für Spalte »%s«" #: commands/tablecmds.c:10754 #, c-format msgid "table has extra column \"%s\"" -msgstr "Tabelle hat zusätzliche Spalte „%s“" +msgstr "Tabelle hat zusätzliche Spalte »%s«" #: commands/tablecmds.c:10806 #, c-format msgid "\"%s\" is not a typed table" -msgstr "„%s“ ist keine getypte Tabelle" +msgstr "»%s« ist keine getypte Tabelle" #: commands/tablecmds.c:10989 #, 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" +msgstr "nicht eindeutiger Index »%s« kann nicht als Replik-Identität verwendet werden" #: commands/tablecmds.c:10995 #, 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" +msgstr "Index »%s« kann nicht als Replik-Identität verwendet werden, weil er nicht IMMEDIATE ist" #: commands/tablecmds.c:11001 #, c-format msgid "cannot use expression index \"%s\" as replica identity" -msgstr "Ausdrucksindex „%s“ kann nicht als Replik-Identität verwendet werden" +msgstr "Ausdrucksindex »%s« kann nicht als Replik-Identität verwendet werden" #: commands/tablecmds.c:11007 #, c-format msgid "cannot use partial index \"%s\" as replica identity" -msgstr "partieller Index „%s“ kann nicht als Replik-Identität verwendet werden" +msgstr "partieller Index »%s« kann nicht als Replik-Identität verwendet werden" #: commands/tablecmds.c:11013 #, c-format msgid "cannot use invalid index \"%s\" as replica identity" -msgstr "ungültiger Index „%s“ kann nicht als Replik-Identität verwendet werden" +msgstr "ungültiger Index »%s« kann nicht als Replik-Identität verwendet werden" #: commands/tablecmds.c:11034 #, 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" +msgstr "Index »%s« kann nicht als Replik-Identität verwendet werden, weil Spalte %d eine Systemspalte ist" #: commands/tablecmds.c:11041 #, 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" +msgstr "Index »%s« kann nicht als Replik-Identität verwendet werden, weil Spalte »%s« NULL-Werte akzeptiert" #: commands/tablecmds.c:11238 #, 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" +msgstr "kann den geloggten Status der Tabelle »%s« nicht ändern, weil sie temporär ist" #: commands/tablecmds.c:11297 #, 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" +msgstr "konnte Tabelle »%s« nicht in geloggt ändern, weil sie auf die ungeloggte Tabelle »%s« verweist" #: commands/tablecmds.c:11307 #, 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" +msgstr "konnte Tabelle »%s« nicht in ungeloggt ändern, weil sie auf die geloggte Tabelle »%s« verweist" #: commands/tablecmds.c:11364 #, c-format @@ -8016,39 +8017,39 @@ msgstr "einer Tabelle zugeordnete Sequenz kann nicht in ein anderes Schema versc #: commands/tablecmds.c:11465 #, c-format msgid "relation \"%s\" already exists in schema \"%s\"" -msgstr "Relation „%s“ existiert bereits in Schema „%s“" +msgstr "Relation »%s« existiert bereits in Schema »%s«" #: commands/tablecmds.c:11990 #, c-format msgid "\"%s\" is not a composite type" -msgstr "„%s“ ist kein zusammengesetzter Typ" +msgstr "»%s« ist kein zusammengesetzter Typ" #: commands/tablecmds.c:12020 #, c-format msgid "\"%s\" is not a table, view, materialized view, sequence, or foreign table" -msgstr "„%s“ ist weder Tabelle, Sicht, materialisierte Sicht, Sequenz noch Fremdtabelle" +msgstr "»%s« ist weder Tabelle, Sicht, materialisierte Sicht, Sequenz noch Fremdtabelle" #: commands/tablespace.c:162 commands/tablespace.c:179 #: commands/tablespace.c:190 commands/tablespace.c:198 #: commands/tablespace.c:625 replication/slot.c:914 storage/file/copydir.c:47 #, c-format msgid "could not create directory \"%s\": %m" -msgstr "konnte Verzeichnis „%s“ nicht erzeugen: %m" +msgstr "konnte Verzeichnis »%s« nicht erzeugen: %m" #: commands/tablespace.c:209 #, c-format msgid "could not stat directory \"%s\": %m" -msgstr "konnte „stat“ für Verzeichnis „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Verzeichnis »%s« nicht ausführen: %m" #: commands/tablespace.c:218 #, c-format msgid "\"%s\" exists but is not a directory" -msgstr "„%s“ existiert, ist aber kein Verzeichnis" +msgstr "»%s« existiert, ist aber kein Verzeichnis" #: commands/tablespace.c:249 #, c-format msgid "permission denied to create tablespace \"%s\"" -msgstr "keine Berechtigung, um Tablespace „%s“ zu erzeugen" +msgstr "keine Berechtigung, um Tablespace »%s« zu erzeugen" #: commands/tablespace.c:251 #, c-format @@ -8068,7 +8069,7 @@ msgstr "Tablespace-Pfad muss ein absoluter Pfad sein" #: commands/tablespace.c:288 #, c-format msgid "tablespace location \"%s\" is too long" -msgstr "Tablespace-Pfad „%s“ ist zu lang" +msgstr "Tablespace-Pfad »%s« ist zu lang" #: commands/tablespace.c:295 #, c-format @@ -8078,39 +8079,39 @@ msgstr "Tablespace-Pfad sollte nicht innerhalb des Datenverzeichnisses sein" #: commands/tablespace.c:304 commands/tablespace.c:952 #, c-format msgid "unacceptable tablespace name \"%s\"" -msgstr "inakzeptabler Tablespace-Name „%s“" +msgstr "inakzeptabler Tablespace-Name »%s«" #: commands/tablespace.c:306 commands/tablespace.c:953 #, c-format msgid "The prefix \"pg_\" is reserved for system tablespaces." -msgstr "Der Präfix „pg_“ ist für System-Tablespaces reserviert." +msgstr "Der Präfix »pg_« ist für System-Tablespaces reserviert." #: commands/tablespace.c:316 commands/tablespace.c:965 #, c-format msgid "tablespace \"%s\" already exists" -msgstr "Tablespace „%s“ existiert bereits" +msgstr "Tablespace »%s« existiert bereits" #: commands/tablespace.c:430 commands/tablespace.c:935 #: commands/tablespace.c:1016 commands/tablespace.c:1085 #: commands/tablespace.c:1218 commands/tablespace.c:1418 #, c-format msgid "tablespace \"%s\" does not exist" -msgstr "Tablespace „%s“ existiert nicht" +msgstr "Tablespace »%s« existiert nicht" #: commands/tablespace.c:436 #, c-format msgid "tablespace \"%s\" does not exist, skipping" -msgstr "Tablespace „%s“ existiert nicht, wird übersprungen" +msgstr "Tablespace »%s« existiert nicht, wird übersprungen" #: commands/tablespace.c:512 #, c-format msgid "tablespace \"%s\" is not empty" -msgstr "Tablespace „%s“ ist nicht leer" +msgstr "Tablespace »%s« ist nicht leer" #: commands/tablespace.c:584 #, c-format msgid "directory \"%s\" does not exist" -msgstr "Verzeichnis „%s“ existiert nicht" +msgstr "Verzeichnis »%s« existiert nicht" #: commands/tablespace.c:585 #, c-format @@ -8120,33 +8121,33 @@ msgstr "Erzeugen Sie dieses Verzeichnis für den Tablespace bevor Sie den Server #: commands/tablespace.c:590 #, c-format msgid "could not set permissions on directory \"%s\": %m" -msgstr "konnte Zugriffsrechte für Verzeichnis „%s“ nicht setzen: %m" +msgstr "konnte Zugriffsrechte für Verzeichnis »%s« nicht setzen: %m" #: commands/tablespace.c:620 #, c-format msgid "directory \"%s\" already in use as a tablespace" -msgstr "Verzeichnis „%s“ ist bereits als Tablespace in Verwendung" +msgstr "Verzeichnis »%s« ist bereits als Tablespace in Verwendung" #: commands/tablespace.c:744 commands/tablespace.c:757 #: commands/tablespace.c:793 commands/tablespace.c:885 #, c-format msgid "could not remove directory \"%s\": %m" -msgstr "konnte Verzeichnis „%s“ nicht löschen: %m" +msgstr "konnte Verzeichnis »%s« nicht löschen: %m" #: commands/tablespace.c:806 commands/tablespace.c:894 #, c-format msgid "could not remove symbolic link \"%s\": %m" -msgstr "konnte symbolische Verknüpfung „%s“ nicht löschen: %m" +msgstr "konnte symbolische Verknüpfung »%s« nicht löschen: %m" #: commands/tablespace.c:816 commands/tablespace.c:903 #, c-format msgid "\"%s\" is not a directory or symbolic link" -msgstr "„%s“ ist kein Verzeichnis oder symbolische Verknüpfung" +msgstr "»%s« ist kein Verzeichnis oder symbolische Verknüpfung" #: commands/tablespace.c:1090 #, c-format msgid "Tablespace \"%s\" does not exist." -msgstr "Tablespace „%s“ existiert nicht." +msgstr "Tablespace »%s« existiert nicht." #: commands/tablespace.c:1517 #, c-format @@ -8161,7 +8162,7 @@ msgstr "Sie können die Verzeichnisse falls nötig manuell entfernen." #: commands/trigger.c:183 #, c-format msgid "\"%s\" is a table" -msgstr "„%s“ ist eine Tabelle" +msgstr "»%s« ist eine Tabelle" #: commands/trigger.c:185 #, c-format @@ -8171,7 +8172,7 @@ msgstr "Tabellen können keine INSTEAD OF-Trigger haben." #: commands/trigger.c:196 commands/trigger.c:203 #, c-format msgid "\"%s\" is a view" -msgstr "„%s“ ist eine Sicht" +msgstr "»%s« ist eine Sicht" #: commands/trigger.c:198 #, c-format @@ -8186,7 +8187,7 @@ msgstr "Sichten können keine TRUNCATE-Trigger haben." #: commands/trigger.c:213 commands/trigger.c:220 commands/trigger.c:227 #, c-format msgid "\"%s\" is a foreign table" -msgstr "„%s“ ist eine Fremdtabelle" +msgstr "»%s« ist eine Fremdtabelle" #: commands/trigger.c:215 #, c-format @@ -8246,17 +8247,17 @@ msgstr "WHEN-Bedingung eines BEFORE-Triggers kann keine Verweise auf Systemspalt #: commands/trigger.c:435 #, c-format msgid "changing return type of function %s from \"opaque\" to \"trigger\"" -msgstr "ändere Rückgabetyp von Funktion %s von „opaque“ in „trigger“" +msgstr "ändere Rückgabetyp von Funktion %s von »opaque« in »trigger«" #: commands/trigger.c:442 #, c-format msgid "function %s must return type \"trigger\"" -msgstr "Funktion %s muss Typ „trigger“ zurückgeben" +msgstr "Funktion %s muss Typ »trigger« zurückgeben" #: commands/trigger.c:554 commands/trigger.c:1304 #, c-format msgid "trigger \"%s\" for relation \"%s\" already exists" -msgstr "Trigger „%s“ für Relation „%s“ existiert bereits" +msgstr "Trigger »%s« für Relation »%s« existiert bereits" #: commands/trigger.c:839 msgid "Found referenced table's UPDATE trigger." @@ -8283,12 +8284,12 @@ msgstr "Triggergruppe wird in Constraint \"%s\" %s umgewandelt" #: commands/trigger.c:1191 commands/trigger.c:1352 commands/trigger.c:1470 #, c-format msgid "trigger \"%s\" for table \"%s\" does not exist" -msgstr "Trigger „%s“ für Tabelle „%s“ existiert nicht" +msgstr "Trigger »%s« für Tabelle »%s« existiert nicht" #: commands/trigger.c:1435 #, c-format msgid "permission denied: \"%s\" is a system trigger" -msgstr "keine Berechtigung: „%s“ ist ein Systemtrigger" +msgstr "keine Berechtigung: »%s« ist ein Systemtrigger" #: commands/trigger.c:1931 #, c-format @@ -8324,12 +8325,12 @@ msgstr "kann Zugriff nicht serialisieren wegen gleichzeitiger Aktualisierung" #: commands/trigger.c:4580 #, c-format msgid "constraint \"%s\" is not deferrable" -msgstr "Constraint „%s“ ist nicht aufschiebbar" +msgstr "Constraint »%s« ist nicht aufschiebbar" #: commands/trigger.c:4603 #, c-format msgid "constraint \"%s\" does not exist" -msgstr "Constraint „%s“ existiert nicht" +msgstr "Constraint »%s« existiert nicht" #: commands/tsearchcmds.c:115 commands/tsearchcmds.c:685 #, c-format @@ -8344,7 +8345,7 @@ msgstr "nur Superuser können Textsucheparser anlegen" #: commands/tsearchcmds.c:240 #, c-format msgid "text search parser parameter \"%s\" not recognized" -msgstr "Textsucheparserparameter „%s“ nicht erkannt" +msgstr "Textsucheparserparameter »%s« nicht erkannt" #: commands/tsearchcmds.c:250 #, c-format @@ -8369,7 +8370,7 @@ msgstr "Lextypes-Methode für Textsucheparser muss angegeben werden" #: commands/tsearchcmds.c:386 #, c-format msgid "text search template \"%s\" does not accept options" -msgstr "Textsuchevorlage „%s“ akzeptiert keine Optionen" +msgstr "Textsuchevorlage »%s« akzeptiert keine Optionen" #: commands/tsearchcmds.c:460 #, c-format @@ -8384,7 +8385,7 @@ msgstr "nur Superuser können Textsuchevorlagen erzeugen" #: commands/tsearchcmds.c:789 #, c-format msgid "text search template parameter \"%s\" not recognized" -msgstr "Textsuchevorlageparameter „%s“ nicht erkannt" +msgstr "Textsuchevorlageparameter »%s« nicht erkannt" #: commands/tsearchcmds.c:799 #, c-format @@ -8394,7 +8395,7 @@ msgstr "Lexize-Methode für Textsuchevorlage muss angegeben werden" #: commands/tsearchcmds.c:1008 #, c-format msgid "text search configuration parameter \"%s\" not recognized" -msgstr "Textsuchekonfigurationsparameter „%s“ nicht erkannt" +msgstr "Textsuchekonfigurationsparameter »%s« nicht erkannt" #: commands/tsearchcmds.c:1015 #, c-format @@ -8409,22 +8410,22 @@ msgstr "Textsucheparser muss angegeben werden" #: commands/tsearchcmds.c:1278 #, c-format msgid "token type \"%s\" does not exist" -msgstr "Tokentyp „%s“ existiert nicht" +msgstr "Tokentyp »%s« existiert nicht" #: commands/tsearchcmds.c:1502 #, c-format msgid "mapping for token type \"%s\" does not exist" -msgstr "Mapping für Tokentyp „%s“ existiert nicht" +msgstr "Mapping für Tokentyp »%s« existiert nicht" #: commands/tsearchcmds.c:1508 #, c-format msgid "mapping for token type \"%s\" does not exist, skipping" -msgstr "Mapping für Tokentyp „%s“ existiert nicht, wird übersprungen" +msgstr "Mapping für Tokentyp »%s« existiert nicht, wird übersprungen" #: commands/tsearchcmds.c:1663 commands/tsearchcmds.c:1774 #, c-format msgid "invalid parameter list format: \"%s\"" -msgstr "ungültiges Parameterlistenformat: „%s“" +msgstr "ungültiges Parameterlistenformat: »%s«" #: commands/typecmds.c:179 #, c-format @@ -8434,12 +8435,12 @@ msgstr "nur Superuser können Basistypen anlegen" #: commands/typecmds.c:286 commands/typecmds.c:1419 #, c-format msgid "type attribute \"%s\" not recognized" -msgstr "Typ-Attribut „%s“ nicht erkannt" +msgstr "Typ-Attribut »%s« nicht erkannt" #: commands/typecmds.c:340 #, c-format msgid "invalid type category \"%s\": must be simple ASCII" -msgstr "ungültige Typenkategorie „%s“: muss einfacher ASCII-Wert sein" +msgstr "ungültige Typenkategorie »%s«: muss einfacher ASCII-Wert sein" #: commands/typecmds.c:359 #, c-format @@ -8449,12 +8450,12 @@ msgstr "Arrayelementtyp kann nicht %s sein" #: commands/typecmds.c:391 #, c-format msgid "alignment \"%s\" not recognized" -msgstr "Ausrichtung „%s“ nicht erkannt" +msgstr "Ausrichtung »%s« nicht erkannt" #: commands/typecmds.c:408 #, c-format msgid "storage \"%s\" not recognized" -msgstr "Storage-Typ „%s“ nicht erkannt" +msgstr "Storage-Typ »%s« nicht erkannt" #: commands/typecmds.c:419 #, c-format @@ -8474,7 +8475,7 @@ msgstr "Typmodifikatorausgabefunktion ist nutzlos ohne Typmodifikatoreingabefunk #: commands/typecmds.c:451 #, c-format msgid "changing return type of function %s from \"opaque\" to %s" -msgstr "ändere Rückgabetyp von Funktion %s von „opaque“ in %s" +msgstr "ändere Rückgabetyp von Funktion %s von »opaque« in %s" #: commands/typecmds.c:458 #, c-format @@ -8484,12 +8485,12 @@ msgstr "Typeingabefunktion %s muss Typ %s zurückgeben" #: commands/typecmds.c:468 #, c-format msgid "changing return type of function %s from \"opaque\" to \"cstring\"" -msgstr "ändere Rückgabetyp von Funktion %s von „opaque“ in „cstring“" +msgstr "ändere Rückgabetyp von Funktion %s von »opaque« in »cstring«" #: commands/typecmds.c:475 #, c-format msgid "type output function %s must return type \"cstring\"" -msgstr "Typeausgabefunktion %s muss Typ „cstring“ zurückgeben" +msgstr "Typeausgabefunktion %s muss Typ »cstring« zurückgeben" #: commands/typecmds.c:484 #, c-format @@ -8499,7 +8500,7 @@ msgstr "Typempfangsfunktion %s muss Typ %s zurückgeben" #: commands/typecmds.c:493 #, c-format msgid "type send function %s must return type \"bytea\"" -msgstr "Typsendefunktion %s muss Typ „bytea“ zurückgeben" +msgstr "Typsendefunktion %s muss Typ »bytea« zurückgeben" #: commands/typecmds.c:558 #, c-format @@ -8534,7 +8535,7 @@ msgstr "Typmodifikatorausgabefunktion %s sollte nicht VOLATILE sein" #: commands/typecmds.c:805 #, c-format msgid "\"%s\" is not a valid base type for a domain" -msgstr "„%s“ ist kein gültiger Basistyp für eine Domäne" +msgstr "»%s« ist kein gültiger Basistyp für eine Domäne" #: commands/typecmds.c:891 #, c-format @@ -8579,12 +8580,12 @@ msgstr "Setzen des Constraint-Modus wird für Domänen nicht unterstützt" #: commands/typecmds.c:1289 utils/cache/typcache.c:1633 #, c-format msgid "%s is not an enum" -msgstr "„%s“ ist kein Enum" +msgstr "»%s« ist kein Enum" #: commands/typecmds.c:1427 #, c-format msgid "type attribute \"subtype\" is required" -msgstr "Typ-Attribut „subtype“ muss angegeben werden" +msgstr "Typ-Attribut »subtype« muss angegeben werden" #: commands/typecmds.c:1432 #, c-format @@ -8599,27 +8600,27 @@ msgstr "Sortierfolge für Bereichstyp angegeben, aber Untertyp unterstützt kein #: commands/typecmds.c:1684 #, c-format msgid "changing argument type of function %s from \"opaque\" to \"cstring\"" -msgstr "ändere Argumenttyp von Funktion %s von „opaque“ in „cstring“" +msgstr "ändere Argumenttyp von Funktion %s von »opaque« in »cstring«" #: commands/typecmds.c:1735 #, c-format msgid "changing argument type of function %s from \"opaque\" to %s" -msgstr "ändere Argumenttyp von Funktion %s von „opaque“ in %s" +msgstr "ändere Argumenttyp von Funktion %s von »opaque« in %s" #: commands/typecmds.c:1834 #, c-format msgid "typmod_in function %s must return type \"integer\"" -msgstr "typmod_in-Funktion %s muss Typ „integer“ zurückgeben" +msgstr "typmod_in-Funktion %s muss Typ »integer« zurückgeben" #: commands/typecmds.c:1861 #, c-format msgid "typmod_out function %s must return type \"cstring\"" -msgstr "typmod_out-Funktion %s muss Typ „cstring“ zurückgeben" +msgstr "typmod_out-Funktion %s muss Typ »cstring« zurückgeben" #: commands/typecmds.c:1888 #, c-format msgid "type analyze function %s must return type \"boolean\"" -msgstr "Typanalysefunktion %s muss Typ „boolean“ zurückgeben" +msgstr "Typanalysefunktion %s muss Typ »boolean« zurückgeben" #: commands/typecmds.c:1934 #, c-format @@ -8634,7 +8635,7 @@ msgstr "Bereichstyp-Canonical-Funktion %s muss Bereichstyp zurückgeben" #: commands/typecmds.c:1971 #, c-format msgid "range canonical function %s must be immutable" -msgstr "Bereichstyp-Canonical-Funktion %s muss „immutable“ sein" +msgstr "Bereichstyp-Canonical-Funktion %s muss »immutable« sein" #: commands/typecmds.c:2007 #, c-format @@ -8644,7 +8645,7 @@ msgstr "Bereichstyp-Untertyp-Diff-Funktion %s muss Typ double precision zurückg #: commands/typecmds.c:2013 #, c-format msgid "range subtype diff function %s must be immutable" -msgstr "Bereichstyp-Untertyp-Diff-Funktion %s muss „immutable“ sein" +msgstr "Bereichstyp-Untertyp-Diff-Funktion %s muss »immutable« sein" #: commands/typecmds.c:2040 #, c-format @@ -8654,27 +8655,27 @@ msgstr "Array-OID-Wert für pg_type ist im Binary-Upgrade-Modus nicht gesetzt" #: commands/typecmds.c:2344 #, c-format msgid "column \"%s\" of table \"%s\" contains null values" -msgstr "Spalte „%s“ von Tabelle „%s“ enthält NULL-Werte" +msgstr "Spalte »%s« von Tabelle »%s« enthält NULL-Werte" #: commands/typecmds.c:2459 commands/typecmds.c:2642 #, c-format msgid "constraint \"%s\" of domain \"%s\" does not exist" -msgstr "Constraint „%s“ von Domäne „%s“ existiert nicht" +msgstr "Constraint »%s« von Domäne »%s« existiert nicht" #: commands/typecmds.c:2463 #, c-format msgid "constraint \"%s\" of domain \"%s\" does not exist, skipping" -msgstr "Constraint „%s“ von Domäne „%s“ existiert nicht, wird übersprungen" +msgstr "Constraint »%s« von Domäne »%s« existiert nicht, wird übersprungen" #: commands/typecmds.c:2648 #, c-format msgid "constraint \"%s\" of domain \"%s\" is not a check constraint" -msgstr "Constraint „%s“ von Domäne „%s“ ist kein Check-Constraint" +msgstr "Constraint »%s« von Domäne »%s« ist kein Check-Constraint" #: commands/typecmds.c:2754 #, c-format msgid "column \"%s\" of table \"%s\" contains values that violate the new constraint" -msgstr "Spalte „%s“ von Tabelle „%s“ enthält Werte, die den neuen Constraint verletzen" +msgstr "Spalte »%s« von Tabelle »%s« enthält Werte, die den neuen Constraint verletzen" #: commands/typecmds.c:2967 commands/typecmds.c:3224 commands/typecmds.c:3413 #, c-format @@ -8684,7 +8685,7 @@ msgstr "%s ist keine Domäne" #: commands/typecmds.c:3001 #, c-format msgid "constraint \"%s\" for domain \"%s\" already exists" -msgstr "Constraint „%s“ für Domäne „%s“ existiert bereits" +msgstr "Constraint »%s« für Domäne »%s« existiert bereits" #: commands/typecmds.c:3051 #, c-format @@ -8714,7 +8715,7 @@ msgstr "Sie können den Typ %s ändern, wodurch der Array-Typ ebenfalls geänder #: commands/typecmds.c:3512 #, c-format msgid "type \"%s\" already exists in schema \"%s\"" -msgstr "Typ %s existiert bereits in Schema „%s“" +msgstr "Typ %s existiert bereits in Schema »%s«" #: commands/user.c:148 #, c-format @@ -8734,7 +8735,7 @@ msgstr "nur Superuser können Replikationsbenutzer anlegen" #: commands/user.c:304 commands/user.c:678 #, c-format msgid "must be superuser to change bypassrls attribute" -msgstr "nur Superuser können das Attribut „bypassrls“ ändern" +msgstr "nur Superuser können das Attribut »bypassrls« ändern" #: commands/user.c:311 #, c-format @@ -8744,7 +8745,7 @@ msgstr "keine Berechtigung, um Rolle zu erzeugen" #: commands/user.c:324 commands/user.c:1153 #, c-format msgid "role \"%s\" already exists" -msgstr "Rolle „%s“ existiert bereits" +msgstr "Rolle »%s« existiert bereits" #: commands/user.c:402 #, c-format @@ -8787,12 +8788,12 @@ msgstr "in DROP ROLE kann kein Rollenplatzhalter verwendet werden" #: utils/adt/acl.c:5205 utils/adt/acl.c:5223 utils/init/miscinit.c:494 #, c-format msgid "role \"%s\" does not exist" -msgstr "Rolle „%s“ existiert nicht" +msgstr "Rolle »%s« existiert nicht" #: commands/user.c:977 #, c-format msgid "role \"%s\" does not exist, skipping" -msgstr "Rolle „%s“ existiert nicht, wird übersprungen" +msgstr "Rolle »%s« existiert nicht, wird übersprungen" #: commands/user.c:989 commands/user.c:993 #, c-format @@ -8812,7 +8813,7 @@ msgstr "nur Superuser können Superuser löschen" #: commands/user.c:1024 #, c-format msgid "role \"%s\" cannot be dropped because some objects depend on it" -msgstr "kann Rolle „%s“ nicht löschen, weil andere Objekte davon abhängen" +msgstr "kann Rolle »%s« nicht löschen, weil andere Objekte davon abhängen" #: commands/user.c:1143 #, c-format @@ -8857,7 +8858,7 @@ msgstr "keine Berechtigung, um Objekte neu zuzuordnen" #: commands/user.c:1402 commands/user.c:1548 #, c-format msgid "must have admin option on role \"%s\"" -msgstr "Admin-Option für Rolle „%s“ wird benötigt" +msgstr "Admin-Option für Rolle »%s« wird benötigt" #: commands/user.c:1419 #, c-format @@ -8867,17 +8868,17 @@ msgstr "nur Superuser können Grantor setzen" #: commands/user.c:1444 #, c-format msgid "role \"%s\" is a member of role \"%s\"" -msgstr "Rolle „%s“ ist ein Mitglied der Rolle „%s“" +msgstr "Rolle »%s« ist ein Mitglied der Rolle »%s«" #: commands/user.c:1459 #, c-format msgid "role \"%s\" is already a member of role \"%s\"" -msgstr "Rolle „%s“ ist schon Mitglied der Rolle „%s“" +msgstr "Rolle »%s« ist schon Mitglied der Rolle »%s«" #: commands/user.c:1570 #, c-format msgid "role \"%s\" is not a member of role \"%s\"" -msgstr "Rolle „%s“ ist kein Mitglied der Rolle „%s“" +msgstr "Rolle »%s« ist kein Mitglied der Rolle »%s«" #: commands/vacuum.c:185 #, c-format @@ -8904,45 +8905,45 @@ msgstr "älteste Multixact ist weit in der Vergangenheit" msgid "Close open transactions with multixacts soon to avoid wraparound problems." msgstr "Schließen Sie bald alle offenen Transaktionen mit Multixacts, um Überlaufprobleme zu vermeiden." -#: commands/vacuum.c:1130 +#: commands/vacuum.c:1138 #, c-format msgid "some databases have not been vacuumed in over 2 billion transactions" msgstr "einige Datenbanken sind seit über 2 Milliarden Transaktionen nicht gevacuumt worden" -#: commands/vacuum.c:1131 +#: commands/vacuum.c:1139 #, c-format msgid "You might have already suffered transaction-wraparound data loss." msgstr "Sie haben möglicherweise bereits Daten wegen Transaktionsnummernüberlauf verloren." -#: commands/vacuum.c:1252 +#: commands/vacuum.c:1260 #, c-format msgid "skipping vacuum of \"%s\" --- lock not available" -msgstr "überspringe Vacuum von „%s“ --- Sperre nicht verfügbar" +msgstr "überspringe Vacuum von »%s« --- Sperre nicht verfügbar" -#: commands/vacuum.c:1278 +#: commands/vacuum.c:1286 #, c-format msgid "skipping \"%s\" --- only superuser can vacuum it" -msgstr "überspringe „%s“ --- nur Superuser kann sie vacuumen" +msgstr "überspringe »%s« --- nur Superuser kann sie vacuumen" -#: commands/vacuum.c:1282 +#: commands/vacuum.c:1290 #, c-format msgid "skipping \"%s\" --- only superuser or database owner can vacuum it" -msgstr "überspringe „%s“ --- nur Superuser oder Eigentümer der Datenbank kann sie vacuumen" +msgstr "überspringe »%s« --- nur Superuser oder Eigentümer der Datenbank kann sie vacuumen" -#: commands/vacuum.c:1286 +#: commands/vacuum.c:1294 #, c-format msgid "skipping \"%s\" --- only table or database owner can vacuum it" -msgstr "überspringe „%s“ --- nur Eigentümer der Tabelle oder der Datenbank kann sie vacuumen" +msgstr "überspringe »%s« --- nur Eigentümer der Tabelle oder der Datenbank kann sie vacuumen" -#: commands/vacuum.c:1304 +#: commands/vacuum.c:1312 #, c-format msgid "skipping \"%s\" --- cannot vacuum non-tables or special system tables" -msgstr "überspringe „%s“ --- kann Nicht-Tabellen oder besondere Systemtabellen nicht vacuumen" +msgstr "überspringe »%s« --- kann Nicht-Tabellen oder besondere Systemtabellen nicht vacuumen" #: commands/vacuumlazy.c:358 #, c-format msgid "automatic vacuum of table \"%s.%s.%s\": index scans: %d\n" -msgstr "automatisches Vacuum der Tabelle „%s.%s.%s“: Index-Scans: %d\n" +msgstr "automatisches Vacuum der Tabelle »%s.%s.%s«: Index-Scans: %d\n" #: commands/vacuumlazy.c:363 #, c-format @@ -8972,12 +8973,12 @@ msgstr "Systembenutzung: %s" #: commands/vacuumlazy.c:701 #, c-format msgid "relation \"%s\" page %u is uninitialized --- fixing" -msgstr "Seite %2$u in Relation „%1$s“ ist nicht initialisiert --- wird repariert" +msgstr "Seite %2$u in Relation »%1$s« ist nicht initialisiert --- wird repariert" #: commands/vacuumlazy.c:1113 #, c-format msgid "\"%s\": removed %.0f row versions in %u pages" -msgstr "„%s“: %.0f Zeilenversionen in %u Seiten entfernt" +msgstr "»%s«: %.0f Zeilenversionen in %u Seiten entfernt" #: commands/vacuumlazy.c:1123 #, c-format @@ -9006,22 +9007,22 @@ msgstr[1] "%u Seiten sind vollkommen leer.\n" #: commands/vacuumlazy.c:1139 #, c-format msgid "\"%s\": found %.0f removable, %.0f nonremovable row versions in %u out of %u pages" -msgstr "„%s“: %.0f entfernbare, %.0f nicht entfernbare Zeilenversionen in %u von %u Seiten gefunden" +msgstr "»%s«: %.0f entfernbare, %.0f nicht entfernbare Zeilenversionen in %u von %u Seiten gefunden" #: commands/vacuumlazy.c:1208 #, c-format msgid "\"%s\": removed %d row versions in %d pages" -msgstr "„%s“: %d Zeilenversionen in %d Seiten entfernt" +msgstr "»%s«: %d Zeilenversionen in %d Seiten entfernt" #: commands/vacuumlazy.c:1375 #, c-format msgid "scanned index \"%s\" to remove %d row versions" -msgstr "Index „%s“ gelesen und %d Zeilenversionen entfernt" +msgstr "Index »%s« gelesen und %d Zeilenversionen entfernt" #: commands/vacuumlazy.c:1421 #, c-format msgid "index \"%s\" now contains %.0f row versions in %u pages" -msgstr "Index „%s“ enthält %.0f Zeilenversionen in %u Seiten" +msgstr "Index »%s« enthält %.0f Zeilenversionen in %u Seiten" #: commands/vacuumlazy.c:1425 #, c-format @@ -9037,27 +9038,27 @@ msgstr "" #: commands/vacuumlazy.c:1482 #, c-format msgid "\"%s\": stopping truncate due to conflicting lock request" -msgstr "„%s“: Truncate wird gestoppt wegen Sperrkonflikt" +msgstr "»%s«: Truncate wird gestoppt wegen Sperrkonflikt" #: commands/vacuumlazy.c:1547 #, c-format msgid "\"%s\": truncated %u to %u pages" -msgstr "„%s“: von %u auf %u Seiten verkürzt" +msgstr "»%s«: von %u auf %u Seiten verkürzt" #: commands/vacuumlazy.c:1603 #, c-format msgid "\"%s\": suspending truncate due to conflicting lock request" -msgstr "„%s“: Truncate wird ausgesetzt wegen Sperrkonflikt" +msgstr "»%s«: Truncate wird ausgesetzt wegen Sperrkonflikt" #: commands/variable.c:164 utils/misc/guc.c:9673 #, c-format msgid "Unrecognized key word: \"%s\"." -msgstr "Unbekanntes Schlüsselwort: „%s“." +msgstr "Unbekanntes Schlüsselwort: »%s«." #: commands/variable.c:176 #, c-format msgid "Conflicting \"datestyle\" specifications." -msgstr "Widersprüchliche „datestyle“-Angaben." +msgstr "Widersprüchliche »datestyle«-Angaben." #: commands/variable.c:298 #, c-format @@ -9072,7 +9073,7 @@ msgstr "Im Zeitzonenintervall können keine Tage angegeben werden." #: commands/variable.c:346 commands/variable.c:428 #, c-format msgid "time zone \"%s\" appears to use leap seconds" -msgstr "Zeitzone „%s“ verwendet anscheinend Schaltsekunden" +msgstr "Zeitzone »%s« verwendet anscheinend Schaltsekunden" #: commands/variable.c:348 commands/variable.c:430 #, c-format @@ -9137,102 +9138,102 @@ msgstr "Umwandlung zwischen %s und %s wird nicht unterstützt." #: commands/variable.c:716 #, c-format msgid "Cannot change \"client_encoding\" now." -msgstr "„client_encoding“ kann jetzt nicht geändert werden." +msgstr "»client_encoding« kann jetzt nicht geändert werden." #: commands/variable.c:889 #, c-format msgid "permission denied to set role \"%s\"" -msgstr "keine Berechtigung, um Rolle „%s“ zu setzen" +msgstr "keine Berechtigung, um Rolle »%s« zu setzen" #: commands/view.c:54 #, c-format msgid "invalid value for \"check_option\" option" -msgstr "ungültiger Wert für Option „check_option“" +msgstr "ungültiger Wert für Option »check_option«" #: commands/view.c:55 #, c-format msgid "Valid values are \"local\" and \"cascaded\"." -msgstr "Gültige Werte sind „local“ und „cascaded“." +msgstr "Gültige Werte sind »local« und »cascaded«." -#: commands/view.c:114 +#: commands/view.c:103 #, c-format msgid "could not determine which collation to use for view column \"%s\"" -msgstr "konnte die für die Sichtspalte „%s“ zu verwendende Sortierfolge nicht bestimmen" +msgstr "konnte die für die Sichtspalte »%s« zu verwendende Sortierfolge nicht bestimmen" -#: commands/view.c:129 +#: commands/view.c:117 #, c-format msgid "view must have at least one column" msgstr "Sicht muss mindestens eine Spalte haben" -#: commands/view.c:263 commands/view.c:275 +#: commands/view.c:251 commands/view.c:263 #, c-format msgid "cannot drop columns from view" msgstr "aus einer Sicht können keine Spalten gelöscht werden" -#: commands/view.c:280 +#: commands/view.c:268 #, c-format msgid "cannot change name of view column \"%s\" to \"%s\"" -msgstr "kann Namen der Sichtspalte „%s“ nicht in „%s“ ändern" +msgstr "kann Namen der Sichtspalte »%s« nicht in »%s« ändern" -#: commands/view.c:288 +#: commands/view.c:276 #, c-format msgid "cannot change data type of view column \"%s\" from %s to %s" -msgstr "kann Datentyp der Sichtspalte „%s“ nicht von %s in %s ändern" +msgstr "kann Datentyp der Sichtspalte »%s« nicht von %s in %s ändern" -#: commands/view.c:427 +#: commands/view.c:415 #, c-format msgid "views must not contain SELECT INTO" msgstr "Sichten dürfen kein SELECT INTO enthalten" -#: commands/view.c:440 +#: commands/view.c:428 #, c-format msgid "views must not contain data-modifying statements in WITH" msgstr "Sichten dürfen keine datenmodifizierenden Anweisungen in WITH enthalten" -#: commands/view.c:511 +#: commands/view.c:499 #, c-format msgid "CREATE VIEW specifies more column names than columns" msgstr "CREATE VIEW gibt mehr Spaltennamen als Spalten an" -#: commands/view.c:519 +#: commands/view.c:507 #, c-format msgid "views cannot be unlogged because they do not have storage" msgstr "Sichten können nicht ungeloggt sein, weil sie keinen Speicherplatz verwenden" -#: commands/view.c:533 +#: commands/view.c:521 #, c-format msgid "view \"%s\" will be a temporary view" -msgstr "Sicht „%s“ wird eine temporäre Sicht" +msgstr "Sicht »%s« wird eine temporäre Sicht" #: executor/execCurrent.c:76 #, c-format msgid "cursor \"%s\" is not a SELECT query" -msgstr "Cursor „%s“ ist keine SELECT-Anfrage" +msgstr "Cursor »%s« ist keine SELECT-Anfrage" #: executor/execCurrent.c:82 #, c-format msgid "cursor \"%s\" is held from a previous transaction" -msgstr "Cursor „%s“ wurde aus einer vorherigen Transaktion beibehalten" +msgstr "Cursor »%s« wurde aus einer vorherigen Transaktion beibehalten" #: executor/execCurrent.c:114 #, c-format msgid "cursor \"%s\" has multiple FOR UPDATE/SHARE references to table \"%s\"" -msgstr "Cursor „%s“ hat mehrere FOR UPDATE/SHARE-Verweise auf Tabelle „%s“" +msgstr "Cursor »%s« hat mehrere FOR UPDATE/SHARE-Verweise auf Tabelle »%s«" #: executor/execCurrent.c:123 #, c-format msgid "cursor \"%s\" does not have a FOR UPDATE/SHARE reference to table \"%s\"" -msgstr "Cursor „%s“ hat keinen FOR UPDATE/SHARE-Verweis auf Tabelle „%s“" +msgstr "Cursor »%s« hat keinen FOR UPDATE/SHARE-Verweis auf Tabelle »%s«" #: executor/execCurrent.c:133 executor/execCurrent.c:179 #, c-format msgid "cursor \"%s\" is not positioned on a row" -msgstr "Cursor „%s“ ist nicht auf eine Zeile positioniert" +msgstr "Cursor »%s« ist nicht auf eine Zeile positioniert" #: executor/execCurrent.c:166 #, c-format msgid "cursor \"%s\" is not a simply updatable scan of table \"%s\"" -msgstr "Cursor „%s“ ist kein einfach aktualisierbarer Scan der Tabelle „%s“" +msgstr "Cursor »%s« ist kein einfach aktualisierbarer Scan der Tabelle »%s«" #: executor/execCurrent.c:231 executor/execQual.c:1156 #, c-format @@ -9244,37 +9245,37 @@ msgstr "Typ von Parameter %d (%s) stimmt nicht mit dem überein, als der Plan vo msgid "no value found for parameter %d" msgstr "kein Wert für Parameter %d gefunden" -#: executor/execIndexing.c:539 +#: executor/execIndexing.c:544 #, 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:816 +#: executor/execIndexing.c:821 #, c-format msgid "could not create exclusion constraint \"%s\"" -msgstr "konnte Exclusion-Constraint „%s“ nicht erzeugen" +msgstr "konnte Exclusion-Constraint »%s« nicht erzeugen" -#: executor/execIndexing.c:819 +#: executor/execIndexing.c:824 #, c-format msgid "Key %s conflicts with key %s." msgstr "Schlüssel %s kollidiert mit Schlüssel %s." -#: executor/execIndexing.c:821 +#: executor/execIndexing.c:826 #, c-format msgid "Key conflicts exist." msgstr "Es bestehen Schlüsselkonflikte." -#: executor/execIndexing.c:827 +#: executor/execIndexing.c:832 #, c-format msgid "conflicting key value violates exclusion constraint \"%s\"" -msgstr "kollidierender Schlüsselwert verletzt Exclusion-Constraint „%s“" +msgstr "kollidierender Schlüsselwert verletzt Exclusion-Constraint »%s«" -#: executor/execIndexing.c:830 +#: executor/execIndexing.c:835 #, c-format msgid "Key %s conflicts with existing key %s." msgstr "Schlüssel %s kollidiert mit vorhandenem Schlüssel %s." -#: executor/execIndexing.c:832 +#: executor/execIndexing.c:837 #, c-format msgid "Key conflicts with existing key." msgstr "Der Schlüssel kollidiert mit einem vorhandenen Schlüssel." @@ -9282,17 +9283,17 @@ msgstr "Der Schlüssel kollidiert mit einem vorhandenen Schlüssel." #: executor/execMain.c:1025 #, c-format msgid "cannot change sequence \"%s\"" -msgstr "kann Sequenz „%s“ nicht ändern" +msgstr "kann Sequenz »%s« nicht ändern" #: executor/execMain.c:1031 #, c-format msgid "cannot change TOAST relation \"%s\"" -msgstr "kann TOAST-Relation „%s“ nicht ändern" +msgstr "kann TOAST-Relation »%s« nicht ändern" #: executor/execMain.c:1049 rewrite/rewriteHandler.c:2641 #, c-format msgid "cannot insert into view \"%s\"" -msgstr "kann nicht in Sicht „%s“ einfügen" +msgstr "kann nicht in Sicht »%s« einfügen" #: executor/execMain.c:1051 rewrite/rewriteHandler.c:2644 #, c-format @@ -9302,7 +9303,7 @@ msgstr "Um Einfügen in die Sicht zu ermöglichen, richten Sie einen INSTEAD OF #: executor/execMain.c:1057 rewrite/rewriteHandler.c:2649 #, c-format msgid "cannot update view \"%s\"" -msgstr "kann Sicht „%s“ nicht aktualisieren" +msgstr "kann Sicht »%s« nicht aktualisieren" #: executor/execMain.c:1059 rewrite/rewriteHandler.c:2652 #, c-format @@ -9312,7 +9313,7 @@ msgstr "Um Aktualisieren der Sicht zu ermöglichen, richten Sie einen INSTEAD OF #: executor/execMain.c:1065 rewrite/rewriteHandler.c:2657 #, c-format msgid "cannot delete from view \"%s\"" -msgstr "kann nicht aus Sicht „%s“ löschen" +msgstr "kann nicht aus Sicht »%s« löschen" #: executor/execMain.c:1067 rewrite/rewriteHandler.c:2660 #, c-format @@ -9322,78 +9323,78 @@ msgstr "Um Löschen aus der Sicht zu ermöglichen, richten Sie einen INSTEAD OF #: executor/execMain.c:1078 #, c-format msgid "cannot change materialized view \"%s\"" -msgstr "kann materialisierte Sicht „%s“ nicht ändern" +msgstr "kann materialisierte Sicht »%s« nicht ändern" #: executor/execMain.c:1090 #, c-format msgid "cannot insert into foreign table \"%s\"" -msgstr "kann nicht in Fremdtabelle „%s“ einfügen" +msgstr "kann nicht in Fremdtabelle »%s« einfügen" #: executor/execMain.c:1096 #, c-format msgid "foreign table \"%s\" does not allow inserts" -msgstr "Fremdtabelle „%s“ erlaubt kein Einfügen" +msgstr "Fremdtabelle »%s« erlaubt kein Einfügen" #: executor/execMain.c:1103 #, c-format msgid "cannot update foreign table \"%s\"" -msgstr "kann Fremdtabelle „%s“ nicht aktualisieren" +msgstr "kann Fremdtabelle »%s« nicht aktualisieren" #: executor/execMain.c:1109 #, c-format msgid "foreign table \"%s\" does not allow updates" -msgstr "Fremdtabelle „%s“ erlaubt kein Aktualisieren" +msgstr "Fremdtabelle »%s« erlaubt kein Aktualisieren" #: executor/execMain.c:1116 #, c-format msgid "cannot delete from foreign table \"%s\"" -msgstr "kann nicht aus Fremdtabelle „%s“ löschen" +msgstr "kann nicht aus Fremdtabelle »%s« löschen" #: executor/execMain.c:1122 #, c-format msgid "foreign table \"%s\" does not allow deletes" -msgstr "Fremdtabelle „%s“ erlaubt kein Löschen" +msgstr "Fremdtabelle »%s« erlaubt kein Löschen" #: executor/execMain.c:1133 #, c-format msgid "cannot change relation \"%s\"" -msgstr "kann Relation „%s“ nicht ändern" +msgstr "kann Relation »%s« nicht ändern" #: executor/execMain.c:1159 #, c-format msgid "cannot lock rows in sequence \"%s\"" -msgstr "kann Zeilen in Sequenz „%s“ nicht sperren" +msgstr "kann Zeilen in Sequenz »%s« nicht sperren" #: executor/execMain.c:1166 #, c-format msgid "cannot lock rows in TOAST relation \"%s\"" -msgstr "kann Zeilen in TOAST-Relation „%s“ nicht sperren" +msgstr "kann Zeilen in TOAST-Relation »%s« nicht sperren" #: executor/execMain.c:1173 #, c-format msgid "cannot lock rows in view \"%s\"" -msgstr "kann Zeilen in Sicht „%s“ nicht sperren" +msgstr "kann Zeilen in Sicht »%s« nicht sperren" #: executor/execMain.c:1181 #, c-format msgid "cannot lock rows in materialized view \"%s\"" -msgstr "kann Zeilen in materialisierter Sicht „%s“ nicht sperren" +msgstr "kann Zeilen in materialisierter Sicht »%s« nicht sperren" #: executor/execMain.c:1190 executor/execMain.c:2578 #: executor/nodeLockRows.c:132 #, c-format msgid "cannot lock rows in foreign table \"%s\"" -msgstr "kann Zeilen in Fremdtabelle „%s“ nicht sperren" +msgstr "kann Zeilen in Fremdtabelle »%s« nicht sperren" #: executor/execMain.c:1196 #, c-format msgid "cannot lock rows in relation \"%s\"" -msgstr "kann Zeilen in Relation „%s“ nicht sperren" +msgstr "kann Zeilen in Relation »%s« nicht sperren" #: executor/execMain.c:1696 #, c-format msgid "null value in column \"%s\" violates not-null constraint" -msgstr "NULL-Wert in Spalte „%s“ verletzt Not-Null-Constraint" +msgstr "NULL-Wert in Spalte »%s« verletzt Not-Null-Constraint" #: executor/execMain.c:1698 executor/execMain.c:1724 executor/execMain.c:1813 #, c-format @@ -9403,32 +9404,32 @@ msgstr "Fehlgeschlagene Zeile enthält %s." #: executor/execMain.c:1722 #, c-format msgid "new row for relation \"%s\" violates check constraint \"%s\"" -msgstr "neue Zeile für Relation „%s“ verletzt Check-Constraint „%s“" +msgstr "neue Zeile für Relation »%s« verletzt Check-Constraint »%s«" #: executor/execMain.c:1811 #, c-format msgid "new row violates check option for view \"%s\"" -msgstr "neue Zeile verletzt Check-Option für Sicht „%s“" +msgstr "neue Zeile verletzt Check-Option für Sicht »%s«" #: executor/execMain.c:1821 #, c-format msgid "new row violates row-level security policy \"%s\" for table \"%s\"" -msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene „%s“ für Tabelle „%s“" +msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene »%s« für Tabelle »%s«" #: executor/execMain.c:1826 #, c-format msgid "new row violates row-level security policy for table \"%s\"" -msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene für Tabelle „%s“" +msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene für Tabelle »%s«" #: executor/execMain.c:1833 #, c-format msgid "new row violates row-level security policy \"%s\" (USING expression) for table \"%s\"" -msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene „%s“ (USING-Ausdruck) für Tabelle „%s“" +msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene »%s« (USING-Ausdruck) für Tabelle »%s«" #: executor/execMain.c:1838 #, c-format msgid "new row violates row-level security policy (USING expression) for table \"%s\"" -msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene (USING-Ausdruck) für Tabelle „%s“" +msgstr "neue Zeile verletzt Policy für Sicherheit auf Zeilenebene (USING-Ausdruck) für Tabelle »%s«" #: executor/execQual.c:300 executor/execQual.c:328 executor/execQual.c:3191 #: utils/adt/array_userfuncs.c:472 utils/adt/arrayfuncs.c:263 @@ -9444,12 +9445,12 @@ msgstr "Anzahl der Arraydimensionen (%d) überschreitet erlaubtes Maximum (%d)" msgid "array subscript in assignment must not be null" msgstr "Arrayindex in Zuweisung darf nicht NULL sein" -#: executor/execQual.c:635 executor/execQual.c:4116 +#: executor/execQual.c:635 executor/execQual.c:4131 #, c-format msgid "attribute %d has wrong type" msgstr "Attribut %d hat falschen Typ" -#: executor/execQual.c:636 executor/execQual.c:4117 +#: executor/execQual.c:636 executor/execQual.c:4132 #, c-format msgid "Table has type %s, but query expects %s." msgstr "Tabelle hat Typ %s, aber Anfrage erwartet %s." @@ -9563,42 +9564,42 @@ msgstr "mehrdimensionale Arrays müssen Arraysausdrücke mit gleicher Anzahl Dim msgid "NULLIF does not support set arguments" msgstr "NULLIF unterstützt keine Mengenargumente" -#: executor/execQual.c:3986 utils/adt/domains.c:136 +#: executor/execQual.c:4001 utils/adt/domains.c:136 #, c-format msgid "domain %s does not allow null values" msgstr "Domäne %s erlaubt keine NULL-Werte" -#: executor/execQual.c:4016 utils/adt/domains.c:173 +#: executor/execQual.c:4031 utils/adt/domains.c:173 #, c-format msgid "value for domain %s violates check constraint \"%s\"" -msgstr "Wert für Domäne %s verletzt Check-Constraint „%s“" +msgstr "Wert für Domäne %s verletzt Check-Constraint »%s«" -#: executor/execQual.c:4371 +#: executor/execQual.c:4386 #, 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/execQual.c:4518 parser/parse_agg.c:596 parser/parse_agg.c:626 +#: executor/execQual.c:4533 parser/parse_agg.c:596 parser/parse_agg.c:626 #, c-format msgid "aggregate function calls cannot be nested" msgstr "Aufrufe von Aggregatfunktionen können nicht geschachtelt werden" -#: executor/execQual.c:4580 parser/parse_agg.c:742 +#: executor/execQual.c:4595 parser/parse_agg.c:742 #, c-format msgid "window function calls cannot be nested" msgstr "Aufrufe von Fensterfunktionen können nicht geschachtelt werden" -#: executor/execQual.c:4792 +#: executor/execQual.c:4807 #, c-format msgid "target type is not an array" msgstr "Zieltyp ist kein Array" -#: executor/execQual.c:4907 +#: executor/execQual.c:4922 #, c-format msgid "ROW() column has type %s instead of type %s" msgstr "ROW()-Spalte hat Typ %s statt Typ %s" -#: executor/execQual.c:5042 utils/adt/arrayfuncs.c:3777 +#: executor/execQual.c:5057 utils/adt/arrayfuncs.c:3777 #: utils/adt/arrayfuncs.c:6315 utils/adt/rowtypes.c:927 #, c-format msgid "could not identify a comparison function for type %s" @@ -9607,7 +9608,7 @@ msgstr "konnte keine Vergleichsfunktion für Typ %s ermitteln" #: executor/execUtils.c:831 #, c-format msgid "materialized view \"%s\" has not been populated" -msgstr "materialisierte Sicht „%s“ wurde noch nicht befüllt" +msgstr "materialisierte Sicht »%s« wurde noch nicht befüllt" #: executor/execUtils.c:833 #, c-format @@ -9629,7 +9630,7 @@ msgstr "%s ist in SQL-Funktionen nicht erlaubt" #: executor/functions.c:513 executor/spi.c:1368 executor/spi.c:2158 #, c-format msgid "%s is not allowed in a non-volatile function" -msgstr "%s ist in als nicht „volatile“ markierten Funktionen nicht erlaubt" +msgstr "%s ist in als nicht »volatile« markierten Funktionen nicht erlaubt" #: executor/functions.c:641 #, c-format @@ -9639,12 +9640,12 @@ msgstr "konnte tatsächlichen Ergebnistyp von Funktion mit deklarierten Rückgab #: executor/functions.c:1405 #, c-format msgid "SQL function \"%s\" statement %d" -msgstr "SQL-Funktion „%s“ Anweisung %d" +msgstr "SQL-Funktion »%s« Anweisung %d" #: executor/functions.c:1431 #, c-format msgid "SQL function \"%s\" during startup" -msgstr "SQL-Funktion „%s“ beim Start" +msgstr "SQL-Funktion »%s« beim Start" #: executor/functions.c:1590 executor/functions.c:1627 #: executor/functions.c:1639 executor/functions.c:1752 @@ -9696,7 +9697,7 @@ msgstr "Aggregatfunktion %u muss kompatiblen Eingabe- und Übergangstyp haben" #: executor/nodeCustom.c:147 executor/nodeCustom.c:158 #, c-format msgid "custom scan \"%s\" does not support MarkPos" -msgstr "Custom-Scan „%s“ unterstützt MarkPos nicht" +msgstr "Custom-Scan »%s« unterstützt MarkPos nicht" #: executor/nodeHashjoin.c:823 executor/nodeHashjoin.c:853 #, c-format @@ -9812,7 +9813,7 @@ msgstr "Transaktion ließ nicht-leeren SPI-Stack zurück" #: executor/spi.c:215 executor/spi.c:279 #, c-format msgid "Check for missing \"SPI_finish\" calls." -msgstr "Prüfen Sie, ob Aufrufe von „SPI_finish“ fehlen." +msgstr "Prüfen Sie, ob Aufrufe von »SPI_finish« fehlen." #: executor/spi.c:278 #, c-format @@ -9843,17 +9844,17 @@ msgstr "Scrollbare Cursor müssen READ ONLY sein." #: executor/spi.c:2458 #, c-format msgid "SQL statement \"%s\"" -msgstr "SQL-Anweisung „%s“" +msgstr "SQL-Anweisung »%s«" #: foreign/foreign.c:192 #, c-format msgid "user mapping not found for \"%s\"" -msgstr "Benutzerabbildung für „%s“ nicht gefunden" +msgstr "Benutzerabbildung für »%s« nicht gefunden" #: foreign/foreign.c:643 #, c-format msgid "invalid option \"%s\"" -msgstr "ungültige Option „%s“" +msgstr "ungültige Option »%s«" #: foreign/foreign.c:644 #, c-format @@ -9863,7 +9864,7 @@ msgstr "Gültige Optionen in diesem Zusammenhang sind: %s" #: gram.y:1009 #, c-format msgid "unrecognized role option \"%s\"" -msgstr "unbekannte Rollenoption „%s“" +msgstr "unbekannte Rollenoption »%s«" #: gram.y:1285 gram.y:1300 #, c-format @@ -9905,7 +9906,7 @@ msgstr "MATCH PARTIAL ist noch nicht implementiert" msgid "duplicate trigger events specified" msgstr "mehrere Trigger-Ereignisse angegeben" -#: gram.y:4852 parser/parse_utilcmd.c:2657 parser/parse_utilcmd.c:2683 +#: gram.y:4852 parser/parse_utilcmd.c:2659 parser/parse_utilcmd.c:2685 #, c-format msgid "constraint declared INITIALLY DEFERRED must be DEFERRABLE" msgstr "Constraint, der als INITIALLY DEFERRED deklariert wurde, muss DEFERRABLE sein" @@ -10078,7 +10079,7 @@ msgstr "Typmodifikator kann kein ORDER BY haben" #: gram.y:13470 gram.y:13505 #, c-format msgid "role name \"%s\" is reserved" -msgstr "Rollenname „%s“ ist reserviert" +msgstr "Rollenname »%s« ist reserviert" #: gram.y:13476 gram.y:13482 #, c-format @@ -10087,7 +10088,7 @@ msgstr "%s kann hier nicht als Rollenname verwendet werden" #: gram.y:14101 gram.y:14290 msgid "improper use of \"*\"" -msgstr "unzulässige Verwendung von „*“" +msgstr "unzulässige Verwendung von »*«" #: gram.y:14253 gram.y:14270 tsearch/spell.c:667 tsearch/spell.c:684 #: tsearch/spell.c:701 tsearch/spell.c:718 tsearch/spell.c:740 @@ -10120,30 +10121,30 @@ msgstr "mehrere LIMIT-Klauseln sind nicht erlaubt" msgid "multiple WITH clauses not allowed" msgstr "mehrere WITH-Klauseln sind nicht erlaubt" -#: gram.y:14600 +#: gram.y:14612 #, c-format msgid "OUT and INOUT arguments aren't allowed in TABLE functions" msgstr "OUT- und INOUT-Argumente sind in TABLE-Funktionen nicht erlaubt" -#: gram.y:14701 +#: gram.y:14713 #, c-format msgid "multiple COLLATE clauses not allowed" msgstr "mehrere COLLATE-Klauseln sind nicht erlaubt" #. translator: %s is CHECK, UNIQUE, or similar -#: gram.y:14739 gram.y:14752 +#: gram.y:14751 gram.y:14764 #, c-format msgid "%s constraints cannot be marked DEFERRABLE" msgstr "%s-Constraints können nicht als DEFERRABLE markiert werden" #. translator: %s is CHECK, UNIQUE, or similar -#: gram.y:14765 +#: gram.y:14777 #, c-format msgid "%s constraints cannot be marked NOT VALID" msgstr "%s-Constraints können nicht als NOT VALID markiert werden" #. translator: %s is CHECK, UNIQUE, or similar -#: gram.y:14778 +#: gram.y:14790 #, c-format msgid "%s constraints cannot be marked NO INHERIT" msgstr "%s-Constraints können nicht als NO INHERIT markiert werden" @@ -10151,74 +10152,74 @@ msgstr "%s-Constraints können nicht als NO INHERIT markiert werden" #: guc-file.l:315 #, c-format msgid "unrecognized configuration parameter \"%s\" in file \"%s\" line %u" -msgstr "unbekannter Konfigurationsparameter „%s“ in Datei „%s“ Zeile %u" +msgstr "unbekannter Konfigurationsparameter »%s« in Datei »%s« Zeile %u" #: guc-file.l:352 utils/misc/guc.c:5720 utils/misc/guc.c:5912 #: utils/misc/guc.c:6002 utils/misc/guc.c:6092 utils/misc/guc.c:6200 #: utils/misc/guc.c:6295 #, c-format msgid "parameter \"%s\" cannot be changed without restarting the server" -msgstr "Parameter „%s“ kann nicht geändert werden, ohne den Server neu zu starten" +msgstr "Parameter »%s« kann nicht geändert werden, ohne den Server neu zu starten" #: guc-file.l:388 #, c-format msgid "parameter \"%s\" removed from configuration file, reset to default" -msgstr "Parameter „%s“ wurde aus Konfigurationsdatei entfernt, wird auf Standardwert zurückgesetzt" +msgstr "Parameter »%s« wurde aus Konfigurationsdatei entfernt, wird auf Standardwert zurückgesetzt" #: guc-file.l:454 #, c-format msgid "parameter \"%s\" changed to \"%s\"" -msgstr "Parameter „%s“ auf „%s“ gesetzt" +msgstr "Parameter »%s« auf »%s« gesetzt" #: guc-file.l:496 #, c-format msgid "configuration file \"%s\" contains errors" -msgstr "Konfigurationsdatei „%s“ enthält Fehler" +msgstr "Konfigurationsdatei »%s« enthält Fehler" #: guc-file.l:501 #, c-format msgid "configuration file \"%s\" contains errors; unaffected changes were applied" -msgstr "Konfigurationsdatei „%s“ enthält Fehler; nicht betroffene Änderungen wurden durchgeführt" +msgstr "Konfigurationsdatei »%s« enthält Fehler; nicht betroffene Änderungen wurden durchgeführt" #: guc-file.l:506 #, c-format msgid "configuration file \"%s\" contains errors; no changes were applied" -msgstr "Konfigurationsdatei „%s“ enthält Fehler; keine Änderungen wurden durchgeführt" +msgstr "Konfigurationsdatei »%s« enthält Fehler; keine Änderungen wurden durchgeführt" #: guc-file.l:579 #, c-format msgid "could not open configuration file \"%s\": maximum nesting depth exceeded" -msgstr "konnte Konfigurationsdatei „%s“ nicht öffnen: maximale Verschachtelungstiefe überschritten" +msgstr "konnte Konfigurationsdatei »%s« nicht öffnen: maximale Verschachtelungstiefe überschritten" #: guc-file.l:595 libpq/hba.c:1764 #, c-format msgid "could not open configuration file \"%s\": %m" -msgstr "konnte Konfigurationsdatei „%s“ nicht öffnen: %m" +msgstr "konnte Konfigurationsdatei »%s« nicht öffnen: %m" #: guc-file.l:606 #, c-format msgid "skipping missing configuration file \"%s\"" -msgstr "fehlende Konfigurationsdatei „%s“ wird übersprungen" +msgstr "fehlende Konfigurationsdatei »%s« wird übersprungen" #: guc-file.l:860 #, c-format msgid "syntax error in file \"%s\" line %u, near end of line" -msgstr "Syntaxfehler in Datei „%s“, Zeile %u, am Ende der Zeile" +msgstr "Syntaxfehler in Datei »%s«, Zeile %u, am Ende der Zeile" #: guc-file.l:870 #, c-format msgid "syntax error in file \"%s\" line %u, near token \"%s\"" -msgstr "Syntaxfehler in Datei „%s“, Zeile %u, bei „%s“" +msgstr "Syntaxfehler in Datei »%s«, Zeile %u, bei »%s«" #: guc-file.l:890 #, c-format msgid "too many syntax errors found, abandoning file \"%s\"" -msgstr "zu viele Syntaxfehler gefunden, Datei „%s“ wird aufgegeben" +msgstr "zu viele Syntaxfehler gefunden, Datei »%s« wird aufgegeben" #: guc-file.l:942 #, c-format msgid "could not open configuration directory \"%s\": %m" -msgstr "konnte Konfigurationsverzeichnis „%s“ nicht öffnen: %m" +msgstr "konnte Konfigurationsverzeichnis »%s« nicht öffnen: %m" #: lib/stringinfo.c:259 #, c-format @@ -10228,67 +10229,67 @@ msgstr "Kann Zeichenkettenpuffer mit %d Bytes nicht um %d Bytes vergrößern." #: libpq/auth.c:235 #, c-format msgid "authentication failed for user \"%s\": host rejected" -msgstr "Authentifizierung für Benutzer „%s“ fehlgeschlagen: Host abgelehnt" +msgstr "Authentifizierung für Benutzer »%s« fehlgeschlagen: Host abgelehnt" #: libpq/auth.c:238 #, c-format msgid "\"trust\" authentication failed for user \"%s\"" -msgstr "„trust“-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "»trust«-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:241 #, c-format msgid "Ident authentication failed for user \"%s\"" -msgstr "Ident-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "Ident-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:244 #, c-format msgid "Peer authentication failed for user \"%s\"" -msgstr "Peer-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "Peer-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:248 #, c-format msgid "password authentication failed for user \"%s\"" -msgstr "Passwort-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "Passwort-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:253 #, c-format msgid "GSSAPI authentication failed for user \"%s\"" -msgstr "GSSAPI-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "GSSAPI-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:256 #, c-format msgid "SSPI authentication failed for user \"%s\"" -msgstr "SSPI-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "SSPI-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:259 #, c-format msgid "PAM authentication failed for user \"%s\"" -msgstr "PAM-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "PAM-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:262 #, c-format msgid "LDAP authentication failed for user \"%s\"" -msgstr "LDAP-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "LDAP-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:265 #, c-format msgid "certificate authentication failed for user \"%s\"" -msgstr "Zertifikatauthentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "Zertifikatauthentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:268 #, c-format msgid "RADIUS authentication failed for user \"%s\"" -msgstr "RADIUS-Authentifizierung für Benutzer „%s“ fehlgeschlagen" +msgstr "RADIUS-Authentifizierung für Benutzer »%s« fehlgeschlagen" #: libpq/auth.c:271 #, c-format msgid "authentication failed for user \"%s\": invalid authentication method" -msgstr "Authentifizierung für Benutzer „%s“ fehlgeschlagen: ungültige Authentifizierungsmethode" +msgstr "Authentifizierung für Benutzer »%s« fehlgeschlagen: ungültige Authentifizierungsmethode" #: libpq/auth.c:275 #, c-format msgid "Connection matched pg_hba.conf line %d: \"%s\"" -msgstr "Verbindung stimmte mit pg_hba.conf-Zeile %d überein: „%s“" +msgstr "Verbindung stimmte mit pg_hba.conf-Zeile %d überein: »%s«" #: libpq/auth.c:330 #, c-format @@ -10298,7 +10299,7 @@ msgstr "Verbindung erfordert ein gültiges Client-Zertifikat" #: libpq/auth.c:372 #, c-format msgid "pg_hba.conf rejects replication connection for host \"%s\", user \"%s\", %s" -msgstr "pg_hba.conf lehnt Replikationsverbindung ab für Host „%s“, Benutzer „%s“, %s" +msgstr "pg_hba.conf lehnt Replikationsverbindung ab für Host »%s«, Benutzer »%s«, %s" #: libpq/auth.c:374 libpq/auth.c:390 libpq/auth.c:448 libpq/auth.c:466 msgid "SSL off" @@ -10311,37 +10312,37 @@ msgstr "SSL an" #: libpq/auth.c:378 #, c-format msgid "pg_hba.conf rejects replication connection for host \"%s\", user \"%s\"" -msgstr "pg_hba.conf lehnt Replikationsverbindung ab für Host „%s“, Benutzer „%s“" +msgstr "pg_hba.conf lehnt Replikationsverbindung ab für Host »%s«, Benutzer »%s«" #: libpq/auth.c:387 #, c-format msgid "pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\", %s" -msgstr "pg_hba.conf lehnt Verbindung ab für Host „%s“, Benutzer „%s“, Datenbank „%s“, %s" +msgstr "pg_hba.conf lehnt Verbindung ab für Host »%s«, Benutzer »%s«, Datenbank »%s«, %s" #: libpq/auth.c:394 #, c-format msgid "pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\"" -msgstr "pg_hba.conf lehnt Verbindung ab für Host „%s“, Benutzer „%s“, Datenbank „%s“" +msgstr "pg_hba.conf lehnt Verbindung ab für Host »%s«, Benutzer »%s«, Datenbank »%s«" #: libpq/auth.c:423 #, c-format msgid "Client IP address resolved to \"%s\", forward lookup matches." -msgstr "Auflösung der Client-IP-Adresse ergab „%s“, Vorwärtsauflösung stimmt überein." +msgstr "Auflösung der Client-IP-Adresse ergab »%s«, Vorwärtsauflösung stimmt überein." #: libpq/auth.c:426 #, c-format msgid "Client IP address resolved to \"%s\", forward lookup not checked." -msgstr "Auflösung der Client-IP-Adresse ergab „%s“, Vorwärtsauflösung nicht geprüft." +msgstr "Auflösung der Client-IP-Adresse ergab »%s«, Vorwärtsauflösung nicht geprüft." #: libpq/auth.c:429 #, c-format msgid "Client IP address resolved to \"%s\", forward lookup does not match." -msgstr "Auflösung der Client-IP-Adresse ergab „%s“, Vorwärtsauflösung stimmt nicht überein." +msgstr "Auflösung der Client-IP-Adresse ergab »%s«, Vorwärtsauflösung stimmt nicht überein." #: libpq/auth.c:432 #, c-format msgid "Could not translate client host name \"%s\" to IP address: %s." -msgstr "Konnte Client-Hostnamen „%s“ nicht in IP-Adresse übersetzen: %s." +msgstr "Konnte Client-Hostnamen »%s« nicht in IP-Adresse übersetzen: %s." #: libpq/auth.c:437 #, c-format @@ -10351,27 +10352,27 @@ msgstr "Konnte Client-IP-Adresse nicht in einen Hostnamen auflösen: %s." #: libpq/auth.c:446 #, c-format msgid "no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\", %s" -msgstr "kein pg_hba.conf-Eintrag für Replikationsverbindung von Host „%s“, Benutzer „%s“, %s" +msgstr "kein pg_hba.conf-Eintrag für Replikationsverbindung von Host »%s«, Benutzer »%s«, %s" #: libpq/auth.c:453 #, c-format msgid "no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\"" -msgstr "kein pg_hba.conf-Eintrag für Replikationsverbindung von Host „%s“, Benutzer „%s“" +msgstr "kein pg_hba.conf-Eintrag für Replikationsverbindung von Host »%s«, Benutzer »%s«" #: libpq/auth.c:463 #, c-format msgid "no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s" -msgstr "kein pg_hba.conf-Eintrag für Host „%s“, Benutzer „%s“, Datenbank „%s“, %s" +msgstr "kein pg_hba.conf-Eintrag für Host »%s«, Benutzer »%s«, Datenbank »%s«, %s" #: libpq/auth.c:471 #, c-format msgid "no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"" -msgstr "kein pg_hba.conf-Eintrag für Host „%s“, Benutzer „%s“, Datenbank „%s“" +msgstr "kein pg_hba.conf-Eintrag für Host »%s«, Benutzer »%s«, Datenbank »%s«" #: libpq/auth.c:514 libpq/hba.c:1180 #, c-format msgid "MD5 authentication is not supported when \"db_user_namespace\" is enabled" -msgstr "MD5-Authentifizierung wird nicht unterstützt, wenn „db_user_namespace“ angeschaltet ist" +msgstr "MD5-Authentifizierung wird nicht unterstützt, wenn »db_user_namespace« angeschaltet ist" #: libpq/auth.c:640 #, c-format @@ -10431,27 +10432,27 @@ msgstr "konnte Socket für Ident-Verbindung nicht erzeugen: %m" #: libpq/auth.c:1493 #, c-format msgid "could not bind to local address \"%s\": %m" -msgstr "konnte nicht mit lokaler Adresse „%s“ verbinden: %m" +msgstr "konnte nicht mit lokaler Adresse »%s« verbinden: %m" #: libpq/auth.c:1505 #, c-format msgid "could not connect to Ident server at address \"%s\", port %s: %m" -msgstr "konnte nicht mit Ident-Server auf Adresse „%s“, Port %s verbinden: %m" +msgstr "konnte nicht mit Ident-Server auf Adresse »%s«, Port %s verbinden: %m" #: libpq/auth.c:1527 #, c-format msgid "could not send query to Ident server at address \"%s\", port %s: %m" -msgstr "konnte Anfrage an Ident-Server auf Adresse „%s“, Port %s nicht senden: %m" +msgstr "konnte Anfrage an Ident-Server auf Adresse »%s«, Port %s nicht senden: %m" #: libpq/auth.c:1544 #, c-format msgid "could not receive response from Ident server at address \"%s\", port %s: %m" -msgstr "konnte Antwort von Ident-Server auf Adresse „%s“, Port %s nicht empfangen: %m" +msgstr "konnte Antwort von Ident-Server auf Adresse »%s«, Port %s nicht empfangen: %m" #: libpq/auth.c:1554 #, c-format msgid "invalidly formatted response from Ident server: \"%s\"" -msgstr "ungültig formatierte Antwort vom Ident-Server: „%s“" +msgstr "ungültig formatierte Antwort vom Ident-Server: »%s«" #: libpq/auth.c:1594 #, c-format @@ -10556,54 +10557,54 @@ msgstr "ungültiges Zeichen im Benutzernamen für LDAP-Authentifizierung" #: libpq/auth.c:2014 #, c-format msgid "could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": %s" -msgstr "erstes LDAP-Binden für ldapbinddn „%s“ auf Server „%s“ fehlgeschlagen: %s" +msgstr "erstes LDAP-Binden für ldapbinddn »%s« auf Server »%s« fehlgeschlagen: %s" #: libpq/auth.c:2038 #, c-format msgid "could not search LDAP for filter \"%s\" on server \"%s\": %s" -msgstr "konnte LDAP nicht mit Filter „%s“ auf Server „%s“ durchsuchen: %s" +msgstr "konnte LDAP nicht mit Filter »%s« auf Server »%s« durchsuchen: %s" #: libpq/auth.c:2049 #, c-format msgid "LDAP user \"%s\" does not exist" -msgstr "LDAP-Benutzer „%s“ existiert nicht" +msgstr "LDAP-Benutzer »%s« existiert nicht" #: libpq/auth.c:2050 #, c-format msgid "LDAP search for filter \"%s\" on server \"%s\" returned no entries." -msgstr "LDAP-Suche nach Filter „%s“ auf Server „%s“ gab keine Einträge zurück." +msgstr "LDAP-Suche nach Filter »%s« auf Server »%s« gab keine Einträge zurück." #: libpq/auth.c:2054 #, c-format msgid "LDAP user \"%s\" is not unique" -msgstr "LDAP-Benutzer „%s“ ist nicht eindeutig" +msgstr "LDAP-Benutzer »%s« ist nicht eindeutig" #: libpq/auth.c:2055 #, c-format msgid "LDAP search for filter \"%s\" on server \"%s\" returned %d entry." msgid_plural "LDAP search for filter \"%s\" on server \"%s\" returned %d entries." -msgstr[0] "LDAP-Suche nach Filter „%s“ auf Server „%s“ gab %d Eintrag zurück." -msgstr[1] "LDAP-Suche nach Filter „%s“ auf Server „%s“ gab %d Einträge zurück." +msgstr[0] "LDAP-Suche nach Filter »%s« auf Server »%s« gab %d Eintrag zurück." +msgstr[1] "LDAP-Suche nach Filter »%s« auf Server »%s« gab %d Einträge zurück." #: libpq/auth.c:2073 #, c-format msgid "could not get dn for the first entry matching \"%s\" on server \"%s\": %s" -msgstr "konnte DN fÅ©r den ersten Treffer für „%s“ auf Server „%s“ nicht lesen: %s" +msgstr "konnte DN fÅ©r den ersten Treffer für »%s« auf Server »%s« nicht lesen: %s" #: libpq/auth.c:2093 #, c-format msgid "could not unbind after searching for user \"%s\" on server \"%s\": %s" -msgstr "Losbinden fehlgeschlagen nach Suche nach Benutzer „%s“ auf Server „%s“: %s" +msgstr "Losbinden fehlgeschlagen nach Suche nach Benutzer »%s« auf Server »%s«: %s" #: libpq/auth.c:2123 #, c-format msgid "LDAP login failed for user \"%s\" on server \"%s\": %s" -msgstr "LDAP-Login fehlgeschlagen für Benutzer „%s“ auf Server „%s“: %s" +msgstr "LDAP-Login fehlgeschlagen für Benutzer »%s« auf Server »%s«: %s" #: libpq/auth.c:2151 #, c-format msgid "certificate authentication failed for user \"%s\": client certificate contains no user name" -msgstr "Zertifikatauthentifizierung für Benutzer „%s“ fehlgeschlagen: Client-Zertifikat enthält keinen Benutzernamen" +msgstr "Zertifikatauthentifizierung für Benutzer »%s« fehlgeschlagen: Client-Zertifikat enthält keinen Benutzernamen" #: libpq/auth.c:2274 #, c-format @@ -10618,7 +10619,7 @@ msgstr "RADIUS-Geheimnis nicht angegeben" #: libpq/auth.c:2297 libpq/hba.c:1590 #, c-format msgid "could not translate RADIUS server name \"%s\" to address: %s" -msgstr "konnte RADIUS-Servername „%s“ nicht in Adresse übersetzen: %s" +msgstr "konnte RADIUS-Servername »%s« nicht in Adresse übersetzen: %s" #: libpq/auth.c:2325 #, c-format @@ -10698,7 +10699,7 @@ msgstr "RADIUS-Antwort hat falsche MD5-Signatur" #: libpq/auth.c:2583 #, c-format msgid "RADIUS response has invalid code (%d) for user \"%s\"" -msgstr "RADIUS-Antwort hat ungültigen Code (%d) für Benutzer „%s“" +msgstr "RADIUS-Antwort hat ungültigen Code (%d) für Benutzer »%s«" #: libpq/be-fsstubs.c:134 libpq/be-fsstubs.c:165 libpq/be-fsstubs.c:199 #: libpq/be-fsstubs.c:239 libpq/be-fsstubs.c:264 libpq/be-fsstubs.c:312 @@ -10741,12 +10742,12 @@ msgstr "Jeder kann das clientseitige lo_import() von libpq verwenden." #: libpq/be-fsstubs.c:471 #, c-format msgid "could not open server file \"%s\": %m" -msgstr "konnte Serverdatei „%s“ nicht öffnen: %m" +msgstr "konnte Serverdatei »%s« nicht öffnen: %m" #: libpq/be-fsstubs.c:493 #, c-format msgid "could not read server file \"%s\": %m" -msgstr "konnte Serverdatei „%s“ nicht lesen: %m" +msgstr "konnte Serverdatei »%s« nicht lesen: %m" #: libpq/be-fsstubs.c:523 #, c-format @@ -10761,12 +10762,12 @@ msgstr "Jeder kann das clientseitige lo_export() von libpq verwenden." #: libpq/be-fsstubs.c:549 #, c-format msgid "could not create server file \"%s\": %m" -msgstr "konnte Serverdatei „%s“ nicht erstellen: %m" +msgstr "konnte Serverdatei »%s« nicht erstellen: %m" #: libpq/be-fsstubs.c:561 #, c-format msgid "could not write server file \"%s\": %m" -msgstr "konnte Serverdatei „%s“ nicht schreiben: %m" +msgstr "konnte Serverdatei »%s« nicht schreiben: %m" #: libpq/be-fsstubs.c:815 #, c-format @@ -10786,17 +10787,17 @@ msgstr "konnte SSL-Kontext nicht erzeugen: %s" #: libpq/be-secure-openssl.c:200 #, c-format msgid "could not load server certificate file \"%s\": %s" -msgstr "konnte Serverzertifikatsdatei „%s“ nicht laden: %s" +msgstr "konnte Serverzertifikatsdatei »%s« nicht laden: %s" #: libpq/be-secure-openssl.c:206 #, c-format msgid "could not access private key file \"%s\": %m" -msgstr "konnte auf private Schlüsseldatei „%s“ nicht zugreifen: %m" +msgstr "konnte auf private Schlüsseldatei »%s« nicht zugreifen: %m" #: libpq/be-secure-openssl.c:221 #, c-format msgid "private key file \"%s\" has group or world access" -msgstr "private Schlüsseldatei „%s“ erlaubt Zugriff von Gruppe oder Welt" +msgstr "private Schlüsseldatei »%s« erlaubt Zugriff von Gruppe oder Welt" #: libpq/be-secure-openssl.c:223 #, c-format @@ -10806,7 +10807,7 @@ msgstr "Rechte sollten u=rw (0600) oder weniger sein." #: libpq/be-secure-openssl.c:230 #, c-format msgid "could not load private key file \"%s\": %s" -msgstr "konnte private Schlüsseldatei „%s“ nicht laden: %s" +msgstr "konnte private Schlüsseldatei »%s« nicht laden: %s" #: libpq/be-secure-openssl.c:235 #, c-format @@ -10816,12 +10817,12 @@ msgstr "Überprüfung des privaten Schlüssels fehlgeschlagen: %s" #: libpq/be-secure-openssl.c:264 #, c-format msgid "could not load root certificate file \"%s\": %s" -msgstr "konnte Root-Zertifikat-Datei „%s“ nicht laden: %s" +msgstr "konnte Root-Zertifikat-Datei »%s« nicht laden: %s" #: libpq/be-secure-openssl.c:288 #, c-format msgid "SSL certificate revocation list file \"%s\" ignored" -msgstr "SSL-Certificate-Revocation-List-Datei „%s“ ignoriert" +msgstr "SSL-Certificate-Revocation-List-Datei »%s« ignoriert" #: libpq/be-secure-openssl.c:290 #, c-format @@ -10831,69 +10832,69 @@ msgstr "SSL-Bibliothek unterstützt keine Certificate-Revocation-Lists." #: libpq/be-secure-openssl.c:295 #, c-format msgid "could not load SSL certificate revocation list file \"%s\": %s" -msgstr "konnte SSL-Certificate-Revocation-List-Datei „%s“ nicht laden: %s" +msgstr "konnte SSL-Certificate-Revocation-List-Datei »%s« nicht laden: %s" -#: libpq/be-secure-openssl.c:341 +#: libpq/be-secure-openssl.c:342 #, c-format msgid "could not initialize SSL connection: %s" msgstr "konnte SSL-Verbindung nicht initialisieren: %s" -#: libpq/be-secure-openssl.c:349 +#: libpq/be-secure-openssl.c:350 #, c-format msgid "could not set SSL socket: %s" msgstr "konnte SSL-Socket nicht setzen: %s" -#: libpq/be-secure-openssl.c:383 +#: libpq/be-secure-openssl.c:404 #, c-format msgid "could not accept SSL connection: %m" msgstr "konnte SSL-Verbindung nicht annehmen: %m" -#: libpq/be-secure-openssl.c:387 libpq/be-secure-openssl.c:398 +#: libpq/be-secure-openssl.c:408 libpq/be-secure-openssl.c:419 #, c-format msgid "could not accept SSL connection: EOF detected" msgstr "konnte SSL-Verbindung nicht annehmen: EOF entdeckt" -#: libpq/be-secure-openssl.c:392 +#: libpq/be-secure-openssl.c:413 #, c-format msgid "could not accept SSL connection: %s" msgstr "konnte SSL-Verbindung nicht annehmen: %s" -#: libpq/be-secure-openssl.c:403 libpq/be-secure-openssl.c:541 -#: libpq/be-secure-openssl.c:598 +#: libpq/be-secure-openssl.c:424 libpq/be-secure-openssl.c:565 +#: libpq/be-secure-openssl.c:625 #, c-format msgid "unrecognized SSL error code: %d" msgstr "unbekannter SSL-Fehlercode: %d" -#: libpq/be-secure-openssl.c:447 +#: libpq/be-secure-openssl.c:468 #, c-format msgid "SSL certificate's common name contains embedded null" msgstr "Common-Name im SSL-Zertifikat enthält Null-Byte" -#: libpq/be-secure-openssl.c:458 +#: libpq/be-secure-openssl.c:479 #, c-format msgid "SSL connection from \"%s\"" -msgstr "SSL-Verbindung von „%s“" +msgstr "SSL-Verbindung von »%s«" -#: libpq/be-secure-openssl.c:532 libpq/be-secure-openssl.c:589 +#: libpq/be-secure-openssl.c:556 libpq/be-secure-openssl.c:616 #, c-format msgid "SSL error: %s" msgstr "SSL-Fehler: %s" -#: libpq/be-secure-openssl.c:937 +#: libpq/be-secure-openssl.c:965 #, c-format msgid "ECDH: unrecognized curve name: %s" msgstr "ECDH: unbekannter Kurvenname: %s" -#: libpq/be-secure-openssl.c:942 +#: libpq/be-secure-openssl.c:970 #, c-format msgid "ECDH: could not create key" msgstr "ECDH: konnte Schlüssel nicht erzeugen" -#: libpq/be-secure-openssl.c:966 +#: libpq/be-secure-openssl.c:994 msgid "no SSL error reported" msgstr "kein SSL-Fehler berichtet" -#: libpq/be-secure-openssl.c:970 +#: libpq/be-secure-openssl.c:998 #, c-format msgid "SSL error code %lu" msgstr "SSL-Fehlercode %lu" @@ -10901,22 +10902,22 @@ msgstr "SSL-Fehlercode %lu" #: libpq/crypt.c:60 #, c-format msgid "User \"%s\" has no password assigned." -msgstr "Benutzer „%s“ hat kein Passwort zugewiesen." +msgstr "Benutzer »%s« hat kein Passwort zugewiesen." #: libpq/crypt.c:150 #, c-format msgid "User \"%s\" has an expired password." -msgstr "Benutzer „%s“ hat ein abgelaufenes Passwort." +msgstr "Benutzer »%s« hat ein abgelaufenes Passwort." #: libpq/hba.c:188 #, c-format msgid "authentication file token too long, skipping: \"%s\"" -msgstr "Token in Authentifizierungsdatei zu lang, wird übersprungen: „%s“" +msgstr "Token in Authentifizierungsdatei zu lang, wird übersprungen: »%s«" #: libpq/hba.c:332 #, c-format msgid "could not open secondary authentication file \"@%s\" as \"%s\": %m" -msgstr "konnte sekundäre Authentifizierungsdatei „@%s“ nicht als „%s“ öffnen: %m" +msgstr "konnte sekundäre Authentifizierungsdatei »@%s« nicht als »%s« öffnen: %m" #: libpq/hba.c:409 #, c-format @@ -10935,23 +10936,23 @@ msgstr "Zeile in Authentifizierungsdatei zu lang" #: libpq/hba.c:1610 libpq/hba.c:1631 tsearch/ts_locale.c:182 #, c-format msgid "line %d of configuration file \"%s\"" -msgstr "Zeile %d in Konfigurationsdatei „%s“" +msgstr "Zeile %d in Konfigurationsdatei »%s«" #. translator: the second %s is a list of auth methods #: libpq/hba.c:755 #, c-format msgid "authentication option \"%s\" is only valid for authentication methods %s" -msgstr "Authentifizierungsoption „%s“ ist nur gültig für Authentifizierungsmethoden %s" +msgstr "Authentifizierungsoption »%s« ist nur gültig für Authentifizierungsmethoden %s" #: libpq/hba.c:771 #, c-format msgid "authentication method \"%s\" requires argument \"%s\" to be set" -msgstr "Authentifizierungsmethode „%s“ benötigt Argument „%s“" +msgstr "Authentifizierungsmethode »%s« benötigt Argument »%s«" #: libpq/hba.c:792 #, c-format msgid "missing entry in file \"%s\" at end of line %d" -msgstr "fehlender Eintrag in Datei „%s“ am Ende von Zeile %d" +msgstr "fehlender Eintrag in Datei »%s« am Ende von Zeile %d" #: libpq/hba.c:802 #, c-format @@ -10996,7 +10997,7 @@ msgstr "Kompilieren Sie mit --with-openssl, um SSL-Verbindungen zu verwenden." #: libpq/hba.c:912 #, c-format msgid "invalid connection type \"%s\"" -msgstr "ungültiger Verbindungstyp „%s“" +msgstr "ungültiger Verbindungstyp »%s«" #: libpq/hba.c:925 #, c-format @@ -11026,17 +11027,17 @@ msgstr "Geben Sie einen Adressbereich pro Zeile an." #: libpq/hba.c:1030 #, c-format msgid "invalid IP address \"%s\": %s" -msgstr "ungültige IP-Adresse „%s“: %s" +msgstr "ungültige IP-Adresse »%s«: %s" #: libpq/hba.c:1048 #, c-format msgid "specifying both host name and CIDR mask is invalid: \"%s\"" -msgstr "Angabe von sowohl Hostname als auch CIDR-Maske ist ungültig: „%s“" +msgstr "Angabe von sowohl Hostname als auch CIDR-Maske ist ungültig: »%s«" #: libpq/hba.c:1060 #, c-format msgid "invalid CIDR mask in address \"%s\"" -msgstr "ungültige CIDR-Maske in Adresse „%s“" +msgstr "ungültige CIDR-Maske in Adresse »%s«" #: libpq/hba.c:1077 #, c-format @@ -11056,7 +11057,7 @@ msgstr "mehrere Werte für Netzmaske angegeben" #: libpq/hba.c:1101 #, c-format msgid "invalid IP mask \"%s\": %s" -msgstr "ungültige IP-Maske „%s“: %s" +msgstr "ungültige IP-Maske »%s«: %s" #: libpq/hba.c:1118 #, c-format @@ -11081,12 +11082,12 @@ msgstr "Geben Sie genau einen Authentifizierungstyp pro Zeile an." #: libpq/hba.c:1211 #, c-format msgid "invalid authentication method \"%s\"" -msgstr "ungültige Authentifizierungsmethode „%s“" +msgstr "ungültige Authentifizierungsmethode »%s«" #: libpq/hba.c:1222 #, c-format msgid "invalid authentication method \"%s\": not supported by this build" -msgstr "ungültige Authentifizierungsmethode „%s“: von dieser Installation nicht unterstützt" +msgstr "ungültige Authentifizierungsmethode »%s«: von dieser Installation nicht unterstützt" #: libpq/hba.c:1243 #, c-format @@ -11101,7 +11102,7 @@ msgstr "peer-Authentifizierung wird nur auf lokalen Sockets unterstützt" #: libpq/hba.c:1271 #, c-format msgid "cert authentication is only supported on hostssl connections" -msgstr "cert-Authentifizierung wird nur auf „hostssl“-Verbindungen unterstützt" +msgstr "cert-Authentifizierung wird nur auf »hostssl«-Verbindungen unterstützt" #: libpq/hba.c:1309 #, c-format @@ -11116,7 +11117,7 @@ msgstr "ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute oder ldapurl #: libpq/hba.c:1356 #, c-format msgid "authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set" -msgstr "Authentifizierungsmethode „ldap“ benötigt Argument „ldapbasedn“, „ldapprefix“ oder „ldapsuffix“" +msgstr "Authentifizierungsmethode »ldap« benötigt Argument »ldapbasedn«, »ldapprefix« oder »ldapsuffix«" #: libpq/hba.c:1399 msgid "ident, peer, gssapi, sspi, and cert" @@ -11125,7 +11126,7 @@ msgstr "ident, peer, gssapi, sspi und cert" #: libpq/hba.c:1412 #, c-format msgid "clientcert can only be configured for \"hostssl\" rows" -msgstr "clientcert kann nur für „hostssl“-Zeilen konfiguriert werden" +msgstr "clientcert kann nur für »hostssl«-Zeilen konfiguriert werden" #: libpq/hba.c:1423 #, c-format @@ -11135,12 +11136,12 @@ msgstr "Client-Zertifikate können nur überprüft werden, wenn Wurzelzertifikat #: libpq/hba.c:1437 #, c-format msgid "clientcert can not be set to 0 when using \"cert\" authentication" -msgstr "clientcert kann nicht auf 0 gesetzt sein, wenn „cert“-Authentifizierung verwendet wird" +msgstr "clientcert kann nicht auf 0 gesetzt sein, wenn »cert«-Authentifizierung verwendet wird" #: libpq/hba.c:1464 #, c-format msgid "could not parse LDAP URL \"%s\": %s" -msgstr "konnte LDAP-URL „%s“ nicht interpretieren: %s" +msgstr "konnte LDAP-URL »%s« nicht interpretieren: %s" #: libpq/hba.c:1472 #, c-format @@ -11160,7 +11161,7 @@ msgstr "LDAP-URLs werden auf dieser Plattform nicht unterstützt" #: libpq/hba.c:1520 #, c-format msgid "invalid LDAP port number: \"%s\"" -msgstr "ungültige LDAP-Portnummer: „%s“" +msgstr "ungültige LDAP-Portnummer: »%s«" #: libpq/hba.c:1560 libpq/hba.c:1567 msgid "gssapi and sspi" @@ -11169,32 +11170,32 @@ msgstr "gssapi und sspi" #: libpq/hba.c:1609 #, c-format msgid "invalid RADIUS port number: \"%s\"" -msgstr "ungültige RADIUS-Portnummer: „%s“" +msgstr "ungültige RADIUS-Portnummer: »%s«" #: libpq/hba.c:1629 #, c-format msgid "unrecognized authentication option name: \"%s\"" -msgstr "unbekannter Authentifizierungsoptionsname: „%s“" +msgstr "unbekannter Authentifizierungsoptionsname: »%s«" #: libpq/hba.c:1814 #, c-format msgid "configuration file \"%s\" contains no entries" -msgstr "Konfigurationsdatei „%s“ enthält keine Einträge" +msgstr "Konfigurationsdatei »%s« enthält keine Einträge" #: libpq/hba.c:1910 #, c-format msgid "invalid regular expression \"%s\": %s" -msgstr "ungültiger regulärer Ausdruck „%s“: %s" +msgstr "ungültiger regulärer Ausdruck »%s«: %s" #: libpq/hba.c:1970 #, c-format msgid "regular expression match for \"%s\" failed: %s" -msgstr "Suche nach regulärem Ausdruck für „%s“ fehlgeschlagen: %s" +msgstr "Suche nach regulärem Ausdruck für »%s« fehlgeschlagen: %s" #: libpq/hba.c:1989 #, c-format msgid "regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"" -msgstr "regulärer Ausdruck „%s“ hat keine Teilausdrücke wie von der Backreference in „%s“ verlangt" +msgstr "regulärer Ausdruck »%s« hat keine Teilausdrücke wie von der Backreference in »%s« verlangt" #: libpq/hba.c:2086 #, c-format @@ -11204,12 +11205,12 @@ msgstr "angegebener Benutzername (%s) und authentifizierter Benutzername (%s) st #: libpq/hba.c:2106 #, c-format msgid "no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"" -msgstr "kein passender Eintrag in Usermap „%s“ für Benutzer „%s“, authentifiziert als „%s“" +msgstr "kein passender Eintrag in Usermap »%s« für Benutzer »%s«, authentifiziert als »%s«" #: libpq/hba.c:2141 #, c-format msgid "could not open usermap file \"%s\": %m" -msgstr "konnte Usermap-Datei „%s“ nicht öffnen: %m" +msgstr "konnte Usermap-Datei »%s« nicht öffnen: %m" #: libpq/pqcomm.c:201 #, c-format @@ -11219,17 +11220,17 @@ msgstr "konnte Socket nicht auf nicht-blockierenden Modus umstellen: %m" #: libpq/pqcomm.c:348 #, c-format msgid "Unix-domain socket path \"%s\" is too long (maximum %d bytes)" -msgstr "Unix-Domain-Socket-Pfad „%s“ ist zu lang (maximal %d Bytes)" +msgstr "Unix-Domain-Socket-Pfad »%s« ist zu lang (maximal %d Bytes)" #: libpq/pqcomm.c:369 #, c-format msgid "could not translate host name \"%s\", service \"%s\" to address: %s" -msgstr "konnte Hostname „%s“, Dienst „%s“ nicht in Adresse übersetzen: %s" +msgstr "konnte Hostname »%s«, Dienst »%s« nicht in Adresse übersetzen: %s" #: libpq/pqcomm.c:373 #, c-format msgid "could not translate service \"%s\" to address: %s" -msgstr "konnte Dienst „%s“ nicht in Adresse übersetzen: %s" +msgstr "konnte Dienst »%s« nicht in Adresse übersetzen: %s" #: libpq/pqcomm.c:400 #, c-format @@ -11278,7 +11279,7 @@ msgstr "konnte %s-Socket nicht binden: %m" #: libpq/pqcomm.c:496 #, c-format msgid "Is another postmaster already running on port %d? If not, remove socket file \"%s\" and retry." -msgstr "Läuft bereits ein anderer Postmaster auf Port %d? Wenn nicht, entfernen Sie die Socketdatei „%s“ und versuchen Sie erneut." +msgstr "Läuft bereits ein anderer Postmaster auf Port %d? Wenn nicht, entfernen Sie die Socketdatei »%s« und versuchen Sie erneut." #: libpq/pqcomm.c:499 #, c-format @@ -11294,17 +11295,17 @@ msgstr "konnte nicht auf %s-Socket hören: %m" #: libpq/pqcomm.c:617 #, c-format msgid "group \"%s\" does not exist" -msgstr "Gruppe „%s“ existiert nicht" +msgstr "Gruppe »%s« existiert nicht" #: libpq/pqcomm.c:627 #, c-format msgid "could not set group of file \"%s\": %m" -msgstr "konnte Gruppe von Datei „%s“ nicht setzen: %m" +msgstr "konnte Gruppe von Datei »%s« nicht setzen: %m" #: libpq/pqcomm.c:638 #, c-format msgid "could not set permissions of file \"%s\": %m" -msgstr "konnte Zugriffsrechte von Datei „%s“ nicht setzen: %m" +msgstr "konnte Zugriffsrechte von Datei »%s« nicht setzen: %m" #: libpq/pqcomm.c:668 #, c-format @@ -11321,7 +11322,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:1139 tcop/postgres.c:3902 +#: libpq/pqcomm.c:1139 tcop/postgres.c:3917 #, c-format msgid "terminating connection because protocol synchronization was lost" msgstr "breche Verbindung ab, weil Protokollsynchronisierung verloren wurde" @@ -11430,7 +11431,7 @@ msgstr " -e verwende europäisches Datumseingabeformat (DMY)\n" #: main/main.c:336 #, c-format msgid " -F turn fsync off\n" -msgstr " -F „fsync“ ausschalten\n" +msgstr " -F »fsync« ausschalten\n" #: main/main.c:337 #, c-format @@ -11460,7 +11461,7 @@ msgstr " -N ZAHL Anzahl der erlaubten Verbindungen\n" #: main/main.c:344 #, c-format msgid " -o OPTIONS pass \"OPTIONS\" to each server process (obsolete)\n" -msgstr " -o OPTIONEN „OPTIONEN“ an jeden Serverprozess weiterreichen (obsolet)\n" +msgstr " -o OPTIONEN »OPTIONEN« an jeden Serverprozess weiterreichen (obsolet)\n" #: main/main.c:345 #, c-format @@ -11631,7 +11632,7 @@ msgid "" "possible system security compromise. See the documentation for\n" "more information on how to properly start the server.\n" msgstr "" -"Der PostgreSQL-Server darf nicht als „root“ ausgeführt werden. Der\n" +"Der PostgreSQL-Server darf nicht als »root« ausgeführt werden. Der\n" "Server muss unter einer unprivilegierten Benutzer-ID gestartet werden,\n" "um mögliche Sicherheitskompromittierung zu verhindern. In der\n" "Dokumentation finden Sie weitere Informationen darüber, wie der\n" @@ -11691,44 +11692,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:1330 parser/analyze.c:1481 parser/analyze.c:1679 +#: optimizer/plan/planner.c:1341 parser/analyze.c:1481 parser/analyze.c:1679 #: parser/analyze.c:2460 #, c-format msgid "%s is not allowed with UNION/INTERSECT/EXCEPT" msgstr "%s ist nicht in UNION/INTERSECT/EXCEPT erlaubt" -#: optimizer/plan/planner.c:3587 +#: optimizer/plan/planner.c:3598 #, c-format msgid "could not implement GROUP BY" msgstr "konnte GROUP BY nicht implementieren" -#: optimizer/plan/planner.c:3588 optimizer/plan/planner.c:3756 +#: optimizer/plan/planner.c:3599 optimizer/plan/planner.c:3767 #: optimizer/prep/prepunion.c:828 #, 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:3755 +#: optimizer/plan/planner.c:3766 #, c-format msgid "could not implement DISTINCT" msgstr "konnte DISTINCT nicht implementieren" -#: optimizer/plan/planner.c:4361 +#: optimizer/plan/planner.c:4372 #, c-format msgid "could not implement window PARTITION BY" msgstr "konnte PARTITION BY für Fenster nicht implementieren" -#: optimizer/plan/planner.c:4362 +#: optimizer/plan/planner.c:4373 #, c-format msgid "Window partitioning columns must be of sortable datatypes." msgstr "Fensterpartitionierungsspalten müssen sortierbare Datentypen haben." -#: optimizer/plan/planner.c:4366 +#: optimizer/plan/planner.c:4377 #, c-format msgid "could not implement window ORDER BY" msgstr "konnte ORDER BY für Fenster nicht implementieren" -#: optimizer/plan/planner.c:4367 +#: optimizer/plan/planner.c:4378 #, c-format msgid "Window ordering columns must be of sortable datatypes." msgstr "Fenstersortierspalten müssen sortierbare Datentypen haben." @@ -11754,32 +11755,32 @@ msgstr "Alle Spaltendatentypen müssen hashbar sein." msgid "could not implement %s" msgstr "konnte %s nicht implementieren" -#: optimizer/util/clauses.c:4597 +#: optimizer/util/clauses.c:4602 #, c-format msgid "SQL function \"%s\" during inlining" -msgstr "SQL-Funktion „%s“ beim Inlining" +msgstr "SQL-Funktion »%s« beim Inlining" #: optimizer/util/plancat.c:108 #, c-format msgid "cannot access temporary or unlogged relations during recovery" msgstr "während der Wiederherstellung kann nicht auf temporäre oder ungeloggte Tabellen zugegriffen werden" -#: optimizer/util/plancat.c:498 +#: optimizer/util/plancat.c:490 #, c-format -msgid "system columns cannot be used in an ON CONFLICT clause" -msgstr "Systemspalten können nicht in der ON-CONFLICT-Klausel verwendet werden" +msgid "whole row unique index inference specifications are not supported" +msgstr "Inferenzangaben mit Unique-Index über die gesamte Zeile werden nicht unterstützt" -#: optimizer/util/plancat.c:516 +#: optimizer/util/plancat.c:507 #, c-format msgid "constraint in ON CONFLICT clause has no associated index" msgstr "Constraint in der ON-CONFLICT-Klausel hat keinen zugehörigen Index" -#: optimizer/util/plancat.c:568 +#: optimizer/util/plancat.c:558 #, c-format msgid "ON CONFLICT DO UPDATE not supported with exclusion constraints" msgstr "ON CONFLICT DO UDPATE nicht unterstützt mit Exclusion-Constraints" -#: optimizer/util/plancat.c:675 +#: optimizer/util/plancat.c:663 #, c-format 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" @@ -11977,7 +11978,7 @@ msgstr "%s kann nicht auf eine WITH-Anfrage angewendet werden" #: parser/analyze.c:2656 #, c-format msgid "relation \"%s\" in %s clause not found in FROM clause" -msgstr "Relation „%s“ in %s nicht in der FROM-Klausel gefunden" +msgstr "Relation »%s« in %s nicht in der FROM-Klausel gefunden" #: parser/parse_agg.c:207 parser/parse_oper.c:220 #, c-format @@ -12173,7 +12174,7 @@ msgstr "Fensterfunktionen sind in %s nicht erlaubt" #: parser/parse_agg.c:897 parser/parse_clause.c:2394 #, c-format msgid "window \"%s\" does not exist" -msgstr "Fenster „%s“ existiert nicht" +msgstr "Fenster »%s« existiert nicht" #: parser/parse_agg.c:982 #, c-format @@ -12188,7 +12189,7 @@ msgstr "Aggregatfunktionen sind nicht im rekursiven Ausdruck einer rekursiven An #: parser/parse_agg.c:1324 #, 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" +msgstr "Spalte »%s.%s« muss in der GROUP-BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden" #: parser/parse_agg.c:1327 #, c-format @@ -12198,7 +12199,7 @@ msgstr "Direkte Argumente einer Ordered-Set-Aggregatfunktion dürfen nur gruppie #: parser/parse_agg.c:1332 #, c-format msgid "subquery uses ungrouped column \"%s.%s\" from outer query" -msgstr "Unteranfrage verwendet nicht gruppierte Spalte „%s.%s“ aus äußerer Anfrage" +msgstr "Unteranfrage verwendet nicht gruppierte Spalte »%s.%s« aus äußerer Anfrage" #: parser/parse_agg.c:1496 #, c-format @@ -12248,7 +12249,7 @@ msgstr "Tablesample-Methode %s existiert nicht" #: parser/parse_clause.c:759 #, c-format msgid "function %s must return type \"tsm_handler\"" -msgstr "Funktion %s muss Typ „tsm_handler“ zurückgeben" +msgstr "Funktion %s muss Typ »tsm_handler« zurückgeben" #: parser/parse_clause.c:773 #, c-format @@ -12270,32 +12271,32 @@ msgstr "TABLESAMPLE-Klausel kann nur auf Tabellen und materialisierte Sichten an #: parser/parse_clause.c:1108 #, c-format msgid "column name \"%s\" appears more than once in USING clause" -msgstr "Spaltenname „%s“ erscheint mehrmals in der USING-Klausel" +msgstr "Spaltenname »%s« erscheint mehrmals in der USING-Klausel" #: parser/parse_clause.c:1123 #, c-format msgid "common column name \"%s\" appears more than once in left table" -msgstr "gemeinsamer Spaltenname „%s“ erscheint mehrmals in der linken Tabelle" +msgstr "gemeinsamer Spaltenname »%s« erscheint mehrmals in der linken Tabelle" #: parser/parse_clause.c:1132 #, c-format msgid "column \"%s\" specified in USING clause does not exist in left table" -msgstr "Spalte „%s“ aus der USING-Klausel existiert nicht in der linken Tabelle" +msgstr "Spalte »%s« aus der USING-Klausel existiert nicht in der linken Tabelle" #: parser/parse_clause.c:1146 #, c-format msgid "common column name \"%s\" appears more than once in right table" -msgstr "gemeinsamer Spaltenname „%s“ erscheint mehrmals in der rechten Tabelle" +msgstr "gemeinsamer Spaltenname »%s« erscheint mehrmals in der rechten Tabelle" #: parser/parse_clause.c:1155 #, c-format msgid "column \"%s\" specified in USING clause does not exist in right table" -msgstr "Spalte „%s“ aus der USING-Klausel existiert nicht in der rechten Tabelle" +msgstr "Spalte »%s« aus der USING-Klausel existiert nicht in der rechten Tabelle" #: parser/parse_clause.c:1209 #, c-format msgid "column alias list for \"%s\" has too many entries" -msgstr "Spaltenaliasliste für „%s“ hat zu viele Einträge" +msgstr "Spaltenaliasliste für »%s« hat zu viele Einträge" #. translator: %s is name of a SQL construct, eg LIMIT #: parser/parse_clause.c:1518 @@ -12307,7 +12308,7 @@ msgstr "Argument von %s darf keine Variablen enthalten" #: parser/parse_clause.c:1683 #, c-format msgid "%s \"%s\" is ambiguous" -msgstr "%s „%s“ ist nicht eindeutig" +msgstr "%s »%s« ist nicht eindeutig" #. translator: %s is name of a SQL construct, eg ORDER BY #: parser/parse_clause.c:1712 @@ -12329,22 +12330,22 @@ msgstr "CUBE ist auf 12 Elemente begrenzt" #: parser/parse_clause.c:2382 #, c-format msgid "window \"%s\" is already defined" -msgstr "Fenster „%s“ ist bereits definiert" +msgstr "Fenster »%s« ist bereits definiert" #: parser/parse_clause.c:2444 #, c-format msgid "cannot override PARTITION BY clause of window \"%s\"" -msgstr "PARTITION-BY-Klausel von Fenster „%s“ kann nicht aufgehoben werden" +msgstr "PARTITION-BY-Klausel von Fenster »%s« kann nicht aufgehoben werden" #: parser/parse_clause.c:2456 #, c-format msgid "cannot override ORDER BY clause of window \"%s\"" -msgstr "ORDER-BY-Klausel von Fenster „%s“ kann nicht aufgehoben werden" +msgstr "ORDER-BY-Klausel von Fenster »%s« kann nicht aufgehoben werden" #: parser/parse_clause.c:2486 parser/parse_clause.c:2492 #, c-format msgid "cannot copy window \"%s\" because it has a frame clause" -msgstr "kann Fenster „%s“ nicht kopieren, weil es eine Frame-Klausel hat" +msgstr "kann Fenster »%s« nicht kopieren, weil es eine Frame-Klausel hat" #: parser/parse_clause.c:2494 #, c-format @@ -12404,7 +12405,7 @@ msgstr "ON CONFLICT wird nicht mit Systemkatalogtabellen unterstützt" #: parser/parse_clause.c:2878 #, c-format msgid "ON CONFLICT is not supported on table \"%s\" used as a catalog table" -msgstr "ON CONFLICT wird nicht unterstützt mit Tabelle „%s“, die als Katalogtabelle verwendet wird" +msgstr "ON CONFLICT wird nicht unterstützt mit Tabelle »%s«, die als Katalogtabelle verwendet wird" #: parser/parse_clause.c:3010 #, c-format @@ -12414,7 +12415,7 @@ msgstr "Operator %s ist kein gültiger Sortieroperator" #: parser/parse_clause.c:3012 #, c-format msgid "Ordering operators must be \"<\" or \">\" members of btree operator families." -msgstr "Sortieroperatoren müssen die Mitglieder „<“ oder „>“ einer „btree“-Operatorfamilie sein." +msgstr "Sortieroperatoren müssen die Mitglieder »<« oder »>« einer »btree«-Operatorfamilie sein." #: parser/parse_coerce.c:971 parser/parse_coerce.c:1001 #: parser/parse_coerce.c:1019 parser/parse_coerce.c:1034 @@ -12472,53 +12473,53 @@ msgstr "%s konnte Typ %s nicht in %s umwandeln" #: parser/parse_coerce.c:1629 #, c-format msgid "arguments declared \"anyelement\" are not all alike" -msgstr "als „anyelement“ deklariert Argumente sind nicht alle gleich" +msgstr "als »anyelement« deklariert Argumente sind nicht alle gleich" #: parser/parse_coerce.c:1649 #, c-format msgid "arguments declared \"anyarray\" are not all alike" -msgstr "als „anyarray“ deklarierte Argumente sind nicht alle gleich" +msgstr "als »anyarray« deklarierte Argumente sind nicht alle gleich" #: parser/parse_coerce.c:1669 #, c-format msgid "arguments declared \"anyrange\" are not all alike" -msgstr "als „anyrange“ deklarierte Argumente sind nicht alle gleich" +msgstr "als »anyrange« deklarierte Argumente sind nicht alle gleich" #: parser/parse_coerce.c:1698 parser/parse_coerce.c:1909 #: parser/parse_coerce.c:1943 #, c-format msgid "argument declared \"anyarray\" is not an array but type %s" -msgstr "als „anyarray“ deklariertes Argument ist kein Array sondern Typ %s" +msgstr "als »anyarray« deklariertes Argument ist kein Array sondern Typ %s" #: parser/parse_coerce.c:1714 #, c-format msgid "argument declared \"anyarray\" is not consistent with argument declared \"anyelement\"" -msgstr "als „anyarray“ deklariertes Argument ist nicht mit als „anyelement“ deklariertem Argument konsistent" +msgstr "als »anyarray« deklariertes Argument ist nicht mit als »anyelement« deklariertem Argument konsistent" #: parser/parse_coerce.c:1735 parser/parse_coerce.c:1956 #, c-format msgid "argument declared \"anyrange\" is not a range type but type %s" -msgstr "als „anyrange“ deklariertes Argument ist kein Bereichstyp sondern Typ %s" +msgstr "als »anyrange« deklariertes Argument ist kein Bereichstyp sondern Typ %s" #: parser/parse_coerce.c:1751 #, c-format msgid "argument declared \"anyrange\" is not consistent with argument declared \"anyelement\"" -msgstr "als „anyrange“ deklariertes Argument ist nicht mit als „anyelement“ deklariertem Argument konsistent" +msgstr "als »anyrange« deklariertes Argument ist nicht mit als »anyelement« deklariertem Argument konsistent" #: parser/parse_coerce.c:1771 #, c-format msgid "could not determine polymorphic type because input has type \"unknown\"" -msgstr "konnte polymorphischen Typ nicht bestimmen, weil Eingabe Typ „unknown“ hat" +msgstr "konnte polymorphischen Typ nicht bestimmen, weil Eingabe Typ »unknown« hat" #: parser/parse_coerce.c:1781 #, c-format msgid "type matched to anynonarray is an array type: %s" -msgstr "mit „anynonarray“ gepaarter Typ ist ein Array-Typ: %s" +msgstr "mit »anynonarray« gepaarter Typ ist ein Array-Typ: %s" #: parser/parse_coerce.c:1791 #, c-format msgid "type matched to anyenum is not an enum type: %s" -msgstr "mit „anyenum“ gepaarter Typ ist kein Enum-Typ: %s" +msgstr "mit »anyenum« gepaarter Typ ist kein Enum-Typ: %s" #: parser/parse_coerce.c:1831 parser/parse_coerce.c:1861 #, c-format @@ -12529,7 +12530,7 @@ msgstr "konnte Bereichstyp für Datentyp %s nicht finden" #: parser/parse_collate.c:986 #, c-format msgid "collation mismatch between implicit collations \"%s\" and \"%s\"" -msgstr "implizite Sortierfolgen „%s“ und „%s“ stimmen nicht überein" +msgstr "implizite Sortierfolgen »%s« und »%s« stimmen nicht überein" #: parser/parse_collate.c:231 parser/parse_collate.c:478 #: parser/parse_collate.c:989 @@ -12540,37 +12541,37 @@ msgstr "Sie können die Sortierfolge auswählen, indem Sie die COLLATE-Klausel a #: parser/parse_collate.c:834 #, c-format msgid "collation mismatch between explicit collations \"%s\" and \"%s\"" -msgstr "explizite Sortierfolgen „%s“ und „%s“ stimmen nicht überein" +msgstr "explizite Sortierfolgen »%s« und »%s« stimmen nicht überein" #: parser/parse_cte.c:42 #, c-format msgid "recursive reference to query \"%s\" must not appear within its non-recursive term" -msgstr "rekursiver Verweis auf Anfrage „%s“ darf nicht in ihrem nicht-rekursiven Teilausdruck erscheinen" +msgstr "rekursiver Verweis auf Anfrage »%s« darf nicht in ihrem nicht-rekursiven Teilausdruck erscheinen" #: parser/parse_cte.c:44 #, c-format msgid "recursive reference to query \"%s\" must not appear within a subquery" -msgstr "rekursiver Verweis auf Anfrage „%s“ darf nicht in einer Unteranfrage erscheinen" +msgstr "rekursiver Verweis auf Anfrage »%s« darf nicht in einer Unteranfrage erscheinen" #: parser/parse_cte.c:46 #, c-format msgid "recursive reference to query \"%s\" must not appear within an outer join" -msgstr "rekursiver Verweis auf Anfrage „%s“ darf nicht in einem äußeren Verbund erscheinen" +msgstr "rekursiver Verweis auf Anfrage »%s« darf nicht in einem äußeren Verbund erscheinen" #: parser/parse_cte.c:48 #, c-format msgid "recursive reference to query \"%s\" must not appear within INTERSECT" -msgstr "rekursiver Verweis auf Anfrage „%s“ darf nicht in INTERSECT erscheinen" +msgstr "rekursiver Verweis auf Anfrage »%s« darf nicht in INTERSECT erscheinen" #: parser/parse_cte.c:50 #, c-format msgid "recursive reference to query \"%s\" must not appear within EXCEPT" -msgstr "rekursiver Verweis auf Anfrage „%s“ darf nicht in EXCEPT erscheinen" +msgstr "rekursiver Verweis auf Anfrage »%s« darf nicht in EXCEPT erscheinen" #: parser/parse_cte.c:132 #, c-format msgid "WITH query name \"%s\" specified more than once" -msgstr "WIHT-Anfragename „%s“ mehrmals angegeben" +msgstr "WIHT-Anfragename »%s« mehrmals angegeben" #: parser/parse_cte.c:264 #, c-format @@ -12580,7 +12581,7 @@ msgstr "WITH-Klausel mit datenmodifizierender Anweisung muss auf der obersten Eb #: parser/parse_cte.c:313 #, c-format msgid "recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall" -msgstr "Spalte %2$d in rekursiver Anfrage „%1$s“ hat Typ %3$s im nicht-rekursiven Teilausdruck aber Typ %4$s insgesamt" +msgstr "Spalte %2$d in rekursiver Anfrage »%1$s« hat Typ %3$s im nicht-rekursiven Teilausdruck aber Typ %4$s insgesamt" #: parser/parse_cte.c:319 #, c-format @@ -12590,7 +12591,7 @@ msgstr "Wandeln Sie die Ausgabe des nicht-rekursiven Teilausdrucks in den korrek #: parser/parse_cte.c:324 #, c-format msgid "recursive query \"%s\" column %d has collation \"%s\" in non-recursive term but collation \"%s\" overall" -msgstr "Spalte %2$d in rekursiver Anfrage „%1$s“ hat Sortierfolge %3$s im nicht-rekursiven Teilausdruck aber Sortierfolge %4$s insgesamt" +msgstr "Spalte %2$d in rekursiver Anfrage »%1$s« hat Sortierfolge %3$s im nicht-rekursiven Teilausdruck aber Sortierfolge %4$s insgesamt" #: parser/parse_cte.c:328 #, c-format @@ -12600,7 +12601,7 @@ msgstr "Verwenden Sie die COLLATE-Klausel, um die Sortierfolge des nicht-rekursi #: parser/parse_cte.c:419 #, c-format msgid "WITH query \"%s\" has %d columns available but %d columns specified" -msgstr "WITH-Anfrage „%s“ hat %d Spalten verfügbar, aber %d Spalten wurden angegeben" +msgstr "WITH-Anfrage »%s« hat %d Spalten verfügbar, aber %d Spalten wurden angegeben" #: parser/parse_cte.c:599 #, c-format @@ -12610,12 +12611,12 @@ msgstr "gegenseitige Rekursion zwischen WITH-Elementen ist nicht implementiert" #: parser/parse_cte.c:651 #, c-format msgid "recursive query \"%s\" must not contain data-modifying statements" -msgstr "rekursive Anfrage „%s“ darf keine datenmodifizierenden Anweisungen enthalten" +msgstr "rekursive Anfrage »%s« darf keine datenmodifizierenden Anweisungen enthalten" #: parser/parse_cte.c:659 #, c-format msgid "recursive query \"%s\" does not have the form non-recursive-term UNION [ALL] recursive-term" -msgstr "rekursive Anfrage „%s“ hat nicht die Form nicht-rekursiver-Ausdruck UNION [ALL] rekursiver-Ausdruck" +msgstr "rekursive Anfrage »%s« hat nicht die Form nicht-rekursiver-Ausdruck UNION [ALL] rekursiver-Ausdruck" #: parser/parse_cte.c:703 #, c-format @@ -12640,7 +12641,7 @@ msgstr "FOR UPDATE/SHARE in einer rekursiven Anfrage ist nicht implementiert" #: parser/parse_cte.c:778 #, c-format msgid "recursive reference to query \"%s\" must not appear more than once" -msgstr "rekursiver Verweis auf Anfrage „%s“ darf nicht mehrmals erscheinen" +msgstr "rekursiver Verweis auf Anfrage »%s« darf nicht mehrmals erscheinen" #: parser/parse_expr.c:387 parser/parse_relation.c:3083 #: parser/parse_relation.c:3103 @@ -12651,12 +12652,12 @@ msgstr "Spalte %s.%s existiert nicht" #: parser/parse_expr.c:399 #, c-format msgid "column \"%s\" not found in data type %s" -msgstr "Spalte „%s“ nicht gefunden im Datentyp %s" +msgstr "Spalte »%s« nicht gefunden im Datentyp %s" #: parser/parse_expr.c:405 #, c-format msgid "could not identify column \"%s\" in record data type" -msgstr "konnte Spalte „%s“ im Record-Datentyp nicht identifizieren" +msgstr "konnte Spalte »%s« im Record-Datentyp nicht identifizieren" #: parser/parse_expr.c:411 #, c-format @@ -12666,13 +12667,13 @@ msgstr "Spaltenschreibweise .%s mit Typ %s verwendet, der kein zusammengesetzter #: parser/parse_expr.c:441 parser/parse_target.c:660 #, c-format msgid "row expansion via \"*\" is not supported here" -msgstr "Zeilenexpansion mit „*“ wird hier nicht unterstützt" +msgstr "Zeilenexpansion mit »*« wird hier nicht unterstützt" #: parser/parse_expr.c:767 parser/parse_relation.c:667 #: parser/parse_relation.c:767 parser/parse_target.c:1109 #, c-format msgid "column reference \"%s\" is ambiguous" -msgstr "Spaltenverweis „%s“ ist nicht eindeutig" +msgstr "Spaltenverweis »%s« ist nicht eindeutig" #: parser/parse_expr.c:823 parser/parse_param.c:110 parser/parse_param.c:142 #: parser/parse_param.c:199 parser/parse_param.c:298 @@ -12756,7 +12757,7 @@ msgstr "unbenannter XML-Elementwert muss ein Spaltenverweis sein" #: parser/parse_expr.c:2222 #, c-format msgid "XML attribute name \"%s\" appears more than once" -msgstr "XML-Attributname „%s“ einscheint mehrmals" +msgstr "XML-Attributname »%s« einscheint mehrmals" #: parser/parse_expr.c:2329 #, c-format @@ -12791,7 +12792,7 @@ msgstr "konnte Interpretation des Zeilenvergleichsoperators %s nicht bestimmen" #: parser/parse_expr.c:2728 #, c-format msgid "Row comparison operators must be associated with btree operator families." -msgstr "Zeilenvergleichsoperatoren müssen einer „btree“-Operatorfamilie zugeordnet sein." +msgstr "Zeilenvergleichsoperatoren müssen einer »btree«-Operatorfamilie zugeordnet sein." #: parser/parse_expr.c:2769 #, c-format @@ -12811,7 +12812,7 @@ msgstr "Änderung der Operatorrangfolge: %s hat jetzt niedrigere Priorität als #: parser/parse_func.c:174 #, c-format msgid "argument name \"%s\" used more than once" -msgstr "Argumentname „%s“ mehrmals angegeben" +msgstr "Argumentname »%s« mehrmals angegeben" #: parser/parse_func.c:185 #, c-format @@ -13050,7 +13051,7 @@ msgstr "inkonsistente Typen für Parameter $%d ermittelt" #: parser/parse_relation.c:174 #, c-format msgid "table reference \"%s\" is ambiguous" -msgstr "Tabellenbezug „%s“ ist nicht eindeutig" +msgstr "Tabellenbezug »%s« ist nicht eindeutig" #: parser/parse_relation.c:218 #, c-format @@ -13060,17 +13061,17 @@ msgstr "Tabellenbezug %u ist nicht eindeutig" #: parser/parse_relation.c:397 #, c-format msgid "table name \"%s\" specified more than once" -msgstr "Tabellenname „%s“ mehrmals angegeben" +msgstr "Tabellenname »%s« mehrmals angegeben" #: parser/parse_relation.c:424 parser/parse_relation.c:3023 #, c-format msgid "invalid reference to FROM-clause entry for table \"%s\"" -msgstr "ungültiger Verweis auf FROM-Klausel-Eintrag für Tabelle „%s“" +msgstr "ungültiger Verweis auf FROM-Klausel-Eintrag für Tabelle »%s«" #: parser/parse_relation.c:427 parser/parse_relation.c:3028 #, c-format msgid "There is an entry for table \"%s\", but it cannot be referenced from this part of the query." -msgstr "Es gibt einen Eintrag für Tabelle „%s“, aber auf ihn kann aus diesem Teil der Anfrage nicht verwiesen werden." +msgstr "Es gibt einen Eintrag für Tabelle »%s«, aber auf ihn kann aus diesem Teil der Anfrage nicht verwiesen werden." #: parser/parse_relation.c:429 #, c-format @@ -13080,18 +13081,18 @@ msgstr "Der JOIN-Typ für LATERAL muss INNER oder LEFT sein." #: parser/parse_relation.c:705 #, c-format msgid "system column \"%s\" reference in check constraint is invalid" -msgstr "Verweis auf Systemspalte „%s“ im Check-Constraint ist ungültig" +msgstr "Verweis auf Systemspalte »%s« im Check-Constraint ist ungültig" #: parser/parse_relation.c:1065 parser/parse_relation.c:1345 #: parser/parse_relation.c:1847 #, c-format msgid "table \"%s\" has %d columns available but %d columns specified" -msgstr "Tabelle „%s“ hat %d Spalten, aber %d Spalten wurden angegeben" +msgstr "Tabelle »%s« hat %d Spalten, aber %d Spalten wurden angegeben" #: parser/parse_relation.c:1152 #, c-format msgid "There is a WITH item named \"%s\", but it cannot be referenced from this part of the query." -msgstr "Es gibt ein WITH-Element namens „%s“, aber darauf kann aus diesem Teil der Anfrage kein Bezug genommen werden." +msgstr "Es gibt ein WITH-Element namens »%s«, aber darauf kann aus diesem Teil der Anfrage kein Bezug genommen werden." #: parser/parse_relation.c:1154 #, c-format @@ -13101,22 +13102,22 @@ msgstr "Verwenden Sie WITH RECURSIVE oder sortieren Sie die WITH-Ausdrücke um, #: parser/parse_relation.c:1465 #, c-format msgid "a column definition list is only allowed for functions returning \"record\"" -msgstr "eine Spaltendefinitionsliste ist nur erlaubt bei Funktionen, die „record“ zurückgeben" +msgstr "eine Spaltendefinitionsliste ist nur erlaubt bei Funktionen, die »record« zurückgeben" #: parser/parse_relation.c:1474 #, c-format msgid "a column definition list is required for functions returning \"record\"" -msgstr "eine Spaltendefinitionsliste ist erforderlich bei Funktionen, die „record“ zurückgeben" +msgstr "eine Spaltendefinitionsliste ist erforderlich bei Funktionen, die »record« zurückgeben" #: parser/parse_relation.c:1553 #, c-format msgid "function \"%s\" in FROM has unsupported return type %s" -msgstr "Funktion „%s“ in FROM hat nicht unterstützten Rückgabetyp %s" +msgstr "Funktion »%s« in FROM hat nicht unterstützten Rückgabetyp %s" #: parser/parse_relation.c:1675 #, c-format msgid "VALUES lists \"%s\" have %d columns available but %d columns specified" -msgstr "VALUES-Liste „%s“ hat %d Spalten verfügbar, aber %d Spalten wurden angegeben" +msgstr "VALUES-Liste »%s« hat %d Spalten verfügbar, aber %d Spalten wurden angegeben" #: parser/parse_relation.c:1730 #, c-format @@ -13126,42 +13127,42 @@ msgstr "Verbunde können höchstens %d Spalten haben" #: parser/parse_relation.c:1820 #, c-format msgid "WITH query \"%s\" does not have a RETURNING clause" -msgstr "WITH-Anfrage „%s“ hat keine RETURNING-Klausel" +msgstr "WITH-Anfrage »%s« hat keine RETURNING-Klausel" #: parser/parse_relation.c:2652 parser/parse_relation.c:2807 #, c-format msgid "column %d of relation \"%s\" does not exist" -msgstr "Spalte %d von Relation „%s“ existiert nicht" +msgstr "Spalte %d von Relation »%s« existiert nicht" #: parser/parse_relation.c:3026 #, c-format msgid "Perhaps you meant to reference the table alias \"%s\"." -msgstr "Vielleicht wurde beabsichtigt, auf den Tabellenalias „%s“ zu verweisen." +msgstr "Vielleicht wurde beabsichtigt, auf den Tabellenalias »%s« zu verweisen." #: parser/parse_relation.c:3034 #, c-format msgid "missing FROM-clause entry for table \"%s\"" -msgstr "fehlender Eintrag in FROM-Klausel für Tabelle „%s“" +msgstr "fehlender Eintrag in FROM-Klausel für Tabelle »%s«" #: parser/parse_relation.c:3086 #, c-format msgid "Perhaps you meant to reference the column \"%s.%s\"." -msgstr "Vielleicht wurde beabsichtigt, auf die Spalte „%s.%s“ zu verweisen." +msgstr "Vielleicht wurde beabsichtigt, auf die Spalte »%s.%s« zu verweisen." #: parser/parse_relation.c:3088 #, c-format msgid "There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query." -msgstr "Es gibt eine Spalte namens „%s“ in Tabelle „%s“, aber auf sie kann aus diesem Teil der Anfrage nicht verwiesen werden." +msgstr "Es gibt eine Spalte namens »%s« in Tabelle »%s«, aber auf sie kann aus diesem Teil der Anfrage nicht verwiesen werden." #: parser/parse_relation.c:3105 #, c-format msgid "Perhaps you meant to reference the column \"%s.%s\" or the column \"%s.%s\"." -msgstr "Vielleicht wurde beabsichtigt, auf die Spalte „%s.%s“ oder die Spalte „%s.%s“ zu verweisen." +msgstr "Vielleicht wurde beabsichtigt, auf die Spalte »%s.%s« oder die Spalte »%s.%s« zu verweisen." #: parser/parse_target.c:421 parser/parse_target.c:713 #, c-format msgid "cannot assign to system column \"%s\"" -msgstr "kann Systemspalte „%s“ keinen Wert zuweisen" +msgstr "kann Systemspalte »%s« keinen Wert zuweisen" #: parser/parse_target.c:449 #, c-format @@ -13176,27 +13177,27 @@ msgstr "kann Subfeld nicht auf DEFAULT setzen" #: parser/parse_target.c:523 #, c-format msgid "column \"%s\" is of type %s but expression is of type %s" -msgstr "Spalte „%s“ hat Typ %s, aber der Ausdruck hat Typ %s" +msgstr "Spalte »%s« hat Typ %s, aber der Ausdruck hat Typ %s" #: parser/parse_target.c:697 #, c-format msgid "cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type" -msgstr "kann Feld „%s“ in Spalte „%s“ nicht setzen, weil ihr Typ %s kein zusammengesetzter Typ ist" +msgstr "kann Feld »%s« in Spalte »%s« nicht setzen, weil ihr Typ %s kein zusammengesetzter Typ ist" #: parser/parse_target.c:706 #, c-format msgid "cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s" -msgstr "kann Feld „%s“ in Spalte „%s“ nicht setzen, weil es keine solche Spalte in Datentyp %s gibt" +msgstr "kann Feld »%s« in Spalte »%s« nicht setzen, weil es keine solche Spalte in Datentyp %s gibt" #: parser/parse_target.c:773 #, c-format msgid "array assignment to \"%s\" requires type %s but expression is of type %s" -msgstr "Wertzuweisung für „%s“ erfordert Typ %s, aber Ausdruck hat Typ %s" +msgstr "Wertzuweisung für »%s« erfordert Typ %s, aber Ausdruck hat Typ %s" #: parser/parse_target.c:783 #, c-format msgid "subfield \"%s\" is of type %s but expression is of type %s" -msgstr "Subfeld „%s“ hat Typ %s, aber der Ausdruck hat Typ %s" +msgstr "Subfeld »%s« hat Typ %s, aber der Ausdruck hat Typ %s" #: parser/parse_target.c:1199 #, c-format @@ -13221,12 +13222,12 @@ msgstr "Typverweis %s in %s umgewandelt" #: parser/parse_type.c:261 parser/parse_type.c:805 utils/cache/typcache.c:238 #, c-format msgid "type \"%s\" is only a shell" -msgstr "Typ „%s“ ist nur eine Hülle" +msgstr "Typ »%s« ist nur eine Hülle" #: parser/parse_type.c:346 #, c-format msgid "type modifier is not allowed for type \"%s\"" -msgstr "Typmodifikator ist für Typ „%s“ nicht erlaubt" +msgstr "Typmodifikator ist für Typ »%s« nicht erlaubt" #: parser/parse_type.c:388 #, c-format @@ -13236,7 +13237,7 @@ msgstr "Typmodifikatoren müssen einfache Konstanten oder Bezeichner sein" #: parser/parse_type.c:671 parser/parse_type.c:770 #, c-format msgid "invalid type name \"%s\"" -msgstr "ungültiger Typname: „%s“" +msgstr "ungültiger Typname: »%s«" #: parser/parse_utilcmd.c:358 #, c-format @@ -13246,17 +13247,17 @@ msgstr "Array aus Typ serial ist nicht implementiert" #: parser/parse_utilcmd.c:406 #, c-format msgid "%s will create implicit sequence \"%s\" for serial column \"%s.%s\"" -msgstr "%s erstellt implizit eine Sequenz „%s“ für die „serial“-Spalte „%s.%s“" +msgstr "%s erstellt implizit eine Sequenz »%s« für die »serial«-Spalte »%s.%s«" #: parser/parse_utilcmd.c:500 parser/parse_utilcmd.c:512 #, c-format msgid "conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"" -msgstr "widersprüchliche NULL/NOT NULL-Deklarationen für Spalte „%s“ von Tabelle „%s“" +msgstr "widersprüchliche NULL/NOT NULL-Deklarationen für Spalte »%s« von Tabelle »%s«" #: parser/parse_utilcmd.c:524 #, c-format msgid "multiple default values specified for column \"%s\" of table \"%s\"" -msgstr "mehrere Vorgabewerte angegeben für Spalte „%s“ von Tabelle „%s“" +msgstr "mehrere Vorgabewerte angegeben für Spalte »%s« von Tabelle »%s«" #: parser/parse_utilcmd.c:541 parser/parse_utilcmd.c:632 #, c-format @@ -13283,174 +13284,174 @@ msgstr "Exclusion-Constraints auf Fremdtabellen werden nicht unterstützt" msgid "LIKE is not supported for creating foreign tables" msgstr "LIKE wird für das Erzeugen von Fremdtabellen nicht unterstützt" -#: parser/parse_utilcmd.c:1239 parser/parse_utilcmd.c:1315 +#: parser/parse_utilcmd.c:1241 parser/parse_utilcmd.c:1317 #, c-format msgid "Index \"%s\" contains a whole-row table reference." -msgstr "Index „%s“ enthält einen Verweis auf die ganze Zeile der Tabelle." +msgstr "Index »%s« enthält einen Verweis auf die ganze Zeile der Tabelle." -#: parser/parse_utilcmd.c:1584 +#: parser/parse_utilcmd.c:1586 #, 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:1604 +#: parser/parse_utilcmd.c:1606 #, c-format msgid "index \"%s\" is already associated with a constraint" -msgstr "Index „%s“ gehört bereits zu einem Constraint" +msgstr "Index »%s« gehört bereits zu einem Constraint" -#: parser/parse_utilcmd.c:1612 +#: parser/parse_utilcmd.c:1614 #, c-format msgid "index \"%s\" does not belong to table \"%s\"" -msgstr "Index „%s“ gehört nicht zu Tabelle „%s“" +msgstr "Index »%s« gehört nicht zu Tabelle »%s«" -#: parser/parse_utilcmd.c:1619 +#: parser/parse_utilcmd.c:1621 #, c-format msgid "index \"%s\" is not valid" -msgstr "Index „%s“ ist nicht gültig" +msgstr "Index »%s« ist nicht gültig" -#: parser/parse_utilcmd.c:1625 +#: parser/parse_utilcmd.c:1627 #, c-format msgid "\"%s\" is not a unique index" -msgstr "„%s“ ist kein Unique Index" +msgstr "»%s« ist kein Unique Index" -#: parser/parse_utilcmd.c:1626 parser/parse_utilcmd.c:1633 -#: parser/parse_utilcmd.c:1640 parser/parse_utilcmd.c:1710 +#: parser/parse_utilcmd.c:1628 parser/parse_utilcmd.c:1635 +#: parser/parse_utilcmd.c:1642 parser/parse_utilcmd.c:1712 #, 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:1632 +#: parser/parse_utilcmd.c:1634 #, c-format msgid "index \"%s\" contains expressions" -msgstr "Index „%s“ enthält Ausdrücke" +msgstr "Index »%s« enthält Ausdrücke" -#: parser/parse_utilcmd.c:1639 +#: parser/parse_utilcmd.c:1641 #, c-format msgid "\"%s\" is a partial index" -msgstr "„%s“ ist ein partieller Index" +msgstr "»%s« ist ein partieller Index" -#: parser/parse_utilcmd.c:1651 +#: parser/parse_utilcmd.c:1653 #, c-format msgid "\"%s\" is a deferrable index" -msgstr "„%s“ ist ein aufschiebbarer Index" +msgstr "»%s« ist ein aufschiebbarer Index" -#: parser/parse_utilcmd.c:1652 +#: parser/parse_utilcmd.c:1654 #, 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:1709 +#: parser/parse_utilcmd.c:1711 #, c-format msgid "index \"%s\" does not have default sorting behavior" -msgstr "Index „%s“ hat nicht das Standardsortierverhalten" +msgstr "Index »%s« hat nicht das Standardsortierverhalten" -#: parser/parse_utilcmd.c:1856 +#: parser/parse_utilcmd.c:1858 #, c-format msgid "column \"%s\" appears twice in primary key constraint" -msgstr "Spalte „%s“ erscheint zweimal im Primärschlüssel-Constraint" +msgstr "Spalte »%s« erscheint zweimal im Primärschlüssel-Constraint" -#: parser/parse_utilcmd.c:1862 +#: parser/parse_utilcmd.c:1864 #, c-format msgid "column \"%s\" appears twice in unique constraint" -msgstr "Spalte „%s“ erscheint zweimal im Unique-Constraint" +msgstr "Spalte »%s« erscheint zweimal im Unique-Constraint" -#: parser/parse_utilcmd.c:2032 +#: parser/parse_utilcmd.c:2034 #, c-format msgid "index expression cannot return a set" msgstr "Indexausdruck kann keine Ergebnismenge zurückgeben" -#: parser/parse_utilcmd.c:2043 +#: parser/parse_utilcmd.c:2045 #, 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:2089 +#: parser/parse_utilcmd.c:2091 #, c-format msgid "rules on materialized views are not supported" msgstr "Regeln für materialisierte Sichten werden nicht unterstützt" -#: parser/parse_utilcmd.c:2150 +#: parser/parse_utilcmd.c:2152 #, 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:2222 +#: parser/parse_utilcmd.c:2224 #, 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:2240 parser/parse_utilcmd.c:2339 +#: parser/parse_utilcmd.c:2242 parser/parse_utilcmd.c:2341 #: rewrite/rewriteHandler.c:478 rewrite/rewriteManip.c:1015 #, c-format msgid "conditional UNION/INTERSECT/EXCEPT statements are not implemented" msgstr "UNION/INTERSECTION/EXCEPT mit Bedingung sind nicht implementiert" -#: parser/parse_utilcmd.c:2258 +#: parser/parse_utilcmd.c:2260 #, c-format msgid "ON SELECT rule cannot use OLD" msgstr "ON-SELECT-Regel kann nicht OLD verwenden" -#: parser/parse_utilcmd.c:2262 +#: parser/parse_utilcmd.c:2264 #, c-format msgid "ON SELECT rule cannot use NEW" msgstr "ON-SELECT-Regel kann nicht NEW verwenden" -#: parser/parse_utilcmd.c:2271 +#: parser/parse_utilcmd.c:2273 #, c-format msgid "ON INSERT rule cannot use OLD" msgstr "ON-INSERT-Regel kann nicht OLD verwenden" -#: parser/parse_utilcmd.c:2277 +#: parser/parse_utilcmd.c:2279 #, c-format msgid "ON DELETE rule cannot use NEW" msgstr "ON-DELETE-Regel kann nicht NEW verwenden" -#: parser/parse_utilcmd.c:2305 +#: parser/parse_utilcmd.c:2307 #, c-format msgid "cannot refer to OLD within WITH query" msgstr "in WITH-Anfrage kann nicht auf OLD verweisen werden" -#: parser/parse_utilcmd.c:2312 +#: parser/parse_utilcmd.c:2314 #, c-format msgid "cannot refer to NEW within WITH query" msgstr "in WITH-Anfrage kann nicht auf NEW verwiesen werden" -#: parser/parse_utilcmd.c:2515 +#: parser/parse_utilcmd.c:2517 #, c-format msgid "transform expression must not return a set" msgstr "Umwandlungsausdruck kann keine Ergebnismenge zurückgeben" -#: parser/parse_utilcmd.c:2629 +#: parser/parse_utilcmd.c:2631 #, c-format msgid "misplaced DEFERRABLE clause" msgstr "falsch platzierte DEFERRABLE-Klausel" -#: parser/parse_utilcmd.c:2634 parser/parse_utilcmd.c:2649 +#: parser/parse_utilcmd.c:2636 parser/parse_utilcmd.c:2651 #, c-format msgid "multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed" msgstr "mehrere DEFERRABLE/NOT DEFERRABLE-Klauseln sind nicht erlaubt" -#: parser/parse_utilcmd.c:2644 +#: parser/parse_utilcmd.c:2646 #, c-format msgid "misplaced NOT DEFERRABLE clause" msgstr "falsch platzierte NOT DEFERRABLE-Klausel" -#: parser/parse_utilcmd.c:2665 +#: parser/parse_utilcmd.c:2667 #, c-format msgid "misplaced INITIALLY DEFERRED clause" msgstr "falsch platzierte INITIALLY DEFERRED-Klausel" -#: parser/parse_utilcmd.c:2670 parser/parse_utilcmd.c:2696 +#: parser/parse_utilcmd.c:2672 parser/parse_utilcmd.c:2698 #, c-format msgid "multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed" msgstr "mehrere INITIALLY IMMEDIATE/DEFERRED-Klauseln sind nicht erlaubt" -#: parser/parse_utilcmd.c:2691 +#: parser/parse_utilcmd.c:2693 #, c-format msgid "misplaced INITIALLY IMMEDIATE clause" msgstr "falsch platzierte INITIALLY IMMEDIATE-Klausel" -#: parser/parse_utilcmd.c:2882 +#: parser/parse_utilcmd.c:2884 #, 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)" @@ -13458,7 +13459,7 @@ msgstr "CREATE gibt ein Schema an (%s) welches nicht gleich dem zu erzeugenden S #: parser/scansup.c:194 #, c-format msgid "identifier \"%s\" will be truncated to \"%s\"" -msgstr "Bezeichner „%s“ wird auf „%s“ gekürzt" +msgstr "Bezeichner »%s« wird auf »%s« gekürzt" #: port/pg_latch.c:344 port/unix_latch.c:344 #, c-format @@ -13487,7 +13488,7 @@ msgid "" "This error does *not* mean that you have run out of disk space. It occurs when either the system limit for the maximum number of semaphore sets (SEMMNI), or the system wide maximum number of semaphores (SEMMNS), would be exceeded. You need to raise the respective kernel parameter. Alternatively, reduce PostgreSQL's consumption of semaphores by reducing its max_connections parameter.\n" "The PostgreSQL documentation contains more information about configuring your system for PostgreSQL." msgstr "" -"Dieser Fehler bedeutet *nicht*, dass kein Platz mehr auf der Festplatte ist. Er tritt auf, wenn entweder die Systemhöchstgrenze für die Anzahl Semaphor-Sets (SEMMNI) oder die Systemhöchstgrenze für die Anzahl Semaphore (SEMMNS) überschritten würde. Sie müssen den entsprechenden Kernelparameter erhöhen. Alternativ können Sie den Semaphorverbrauch von PostgreSQL reduzieren indem Sie den Parameter „max_connections“ herabsetzen.\n" +"Dieser Fehler bedeutet *nicht*, dass kein Platz mehr auf der Festplatte ist. Er tritt auf, wenn entweder die Systemhöchstgrenze für die Anzahl Semaphor-Sets (SEMMNI) oder die Systemhöchstgrenze für die Anzahl Semaphore (SEMMNS) überschritten würde. Sie müssen den entsprechenden Kernelparameter erhöhen. Alternativ können Sie den Semaphorverbrauch von PostgreSQL reduzieren indem Sie den Parameter »max_connections« herabsetzen.\n" "Die PostgreSQL-Dokumentation enthält weitere Informationen, wie Sie Ihr System für PostgreSQL konfigurieren können." #: port/pg_sema.c:148 port/sysv_sema.c:148 @@ -13546,7 +13547,7 @@ msgstr "konnte anonymes Shared Memory nicht mappen: %m" #, c-format msgid "This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently %zu bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections." msgstr "" -"Dieser Fehler bedeutet gewöhnlich, dass das von PostgreSQL angeforderte Shared-Memory-Segment den verfügbaren Speicher, Swap-Space oder Huge Pages überschreitet. Um die benötigte Shared-Memory-Größe zu reduzieren (aktuell %zu Bytes), reduzieren Sie den Shared-Memory-Verbrauch von PostgreSQL, beispielsweise indem Sie „shared_buffers“ oder „max_connections“ reduzieren.\n" +"Dieser Fehler bedeutet gewöhnlich, dass das von PostgreSQL angeforderte Shared-Memory-Segment den verfügbaren Speicher, Swap-Space oder Huge Pages überschreitet. Um die benötigte Shared-Memory-Größe zu reduzieren (aktuell %zu Bytes), reduzieren Sie den Shared-Memory-Verbrauch von PostgreSQL, beispielsweise indem Sie »shared_buffers« oder »max_connections« reduzieren.\n" "Die PostgreSQL-Dokumentation enthält weitere Informationen über die Konfiguration von Shared Memory." #: port/pg_shmem.c:439 port/sysv_shmem.c:439 port/win32_shmem.c:134 @@ -13557,32 +13558,32 @@ msgstr "Huge Pages werden auf dieser Plattform nicht unterstützt" #: port/pg_shmem.c:553 port/sysv_shmem.c:553 #, c-format msgid "could not stat data directory \"%s\": %m" -msgstr "konnte „stat“ für Datenverzeichnis „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Datenverzeichnis »%s« nicht ausführen: %m" -#: port/win32/crashdump.c:108 +#: port/win32/crashdump.c:122 #, c-format msgid "could not load dbghelp.dll, cannot write crash dump\n" msgstr "konnte dbghelp.dll nicht laden, kann Crash-Dump nicht schreiben\n" -#: port/win32/crashdump.c:116 +#: port/win32/crashdump.c:130 #, c-format msgid "could not load required functions in dbghelp.dll, cannot write crash dump\n" msgstr "konnte benötigte Funktionen in dbghelp.dll nicht laden, kann Crash-Dump nicht schreiben\n" -#: port/win32/crashdump.c:147 +#: port/win32/crashdump.c:161 #, c-format msgid "could not open crash dump file \"%s\" for writing: error code %lu\n" -msgstr "konnte Crash-Dump-Datei „%s“ nicht zum Schreiben öffnen: Fehlercode %lu\n" +msgstr "konnte Crash-Dump-Datei »%s« nicht zum Schreiben öffnen: Fehlercode %lu\n" -#: port/win32/crashdump.c:154 +#: port/win32/crashdump.c:168 #, c-format msgid "wrote crash dump to file \"%s\"\n" -msgstr "Crash-Dump nach Datei „%s“ geschrieben\n" +msgstr "Crash-Dump nach Datei »%s« geschrieben\n" -#: port/win32/crashdump.c:156 +#: port/win32/crashdump.c:170 #, c-format msgid "could not write crash dump to file \"%s\": error code %lu\n" -msgstr "konnte Crash-Dump nicht nach Datei „%s“ schreiben: Fehlercode %lu\n" +msgstr "konnte Crash-Dump nicht nach Datei »%s« schreiben: Fehlercode %lu\n" #: port/win32/security.c:43 #, c-format @@ -13664,100 +13665,100 @@ msgstr "Fehlgeschlagener Systemaufruf war DuplicateHandle." msgid "Failed system call was MapViewOfFileEx." msgstr "Fehlgeschlagener Systemaufruf war MapViewOfFileEx." -#: postmaster/autovacuum.c:377 +#: postmaster/autovacuum.c:380 #, c-format msgid "could not fork autovacuum launcher process: %m" msgstr "konnte Autovacuum-Launcher-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/autovacuum.c:413 +#: postmaster/autovacuum.c:416 #, c-format msgid "autovacuum launcher started" msgstr "Autovacuum-Launcher startet" -#: postmaster/autovacuum.c:775 +#: postmaster/autovacuum.c:779 #, c-format msgid "autovacuum launcher shutting down" msgstr "Autovacuum-Launcher fährt herunter" -#: postmaster/autovacuum.c:1443 +#: postmaster/autovacuum.c:1447 #, c-format msgid "could not fork autovacuum worker process: %m" msgstr "konnte Autovacuum-Worker-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/autovacuum.c:1639 +#: postmaster/autovacuum.c:1643 #, c-format msgid "autovacuum: processing database \"%s\"" -msgstr "Autovacuum: bearbeite Datenbank „%s“" +msgstr "Autovacuum: bearbeite Datenbank »%s«" -#: postmaster/autovacuum.c:2051 +#: postmaster/autovacuum.c:2056 #, c-format msgid "autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"" -msgstr "Autovacuum: lösche verwaiste temporäre Tabelle „%s.%s“ in Datenbank „%s“" +msgstr "Autovacuum: lösche verwaiste temporäre Tabelle »%s.%s« in Datenbank »%s«" -#: postmaster/autovacuum.c:2063 +#: postmaster/autovacuum.c:2068 #, c-format msgid "autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"" -msgstr "Autovacuum: verwaiste temporäre Tabelle „%s.%s“ in Datenbank „%s“ gefunden" +msgstr "Autovacuum: verwaiste temporäre Tabelle »%s.%s« in Datenbank »%s« gefunden" -#: postmaster/autovacuum.c:2346 +#: postmaster/autovacuum.c:2352 #, c-format msgid "automatic vacuum of table \"%s.%s.%s\"" -msgstr "automatisches Vacuum der Tabelle „%s.%s.%s“" +msgstr "automatisches Vacuum der Tabelle »%s.%s.%s«" -#: postmaster/autovacuum.c:2349 +#: postmaster/autovacuum.c:2355 #, c-format msgid "automatic analyze of table \"%s.%s.%s\"" -msgstr "automatisches Analysieren der Tabelle „%s.%s.%s“" +msgstr "automatisches Analysieren der Tabelle »%s.%s.%s«" -#: postmaster/autovacuum.c:2877 +#: postmaster/autovacuum.c:2885 #, c-format msgid "autovacuum not started because of misconfiguration" msgstr "Autovacuum wegen Fehlkonfiguration nicht gestartet" -#: postmaster/autovacuum.c:2878 +#: postmaster/autovacuum.c:2886 #, c-format msgid "Enable the \"track_counts\" option." -msgstr "Schalten Sie die Option „track_counts“ ein." +msgstr "Schalten Sie die Option »track_counts« ein." #: postmaster/bgworker.c:346 postmaster/bgworker.c:746 #, c-format msgid "registering background worker \"%s\"" -msgstr "registriere Background-Worker „%s“" +msgstr "registriere Background-Worker »%s«" #: postmaster/bgworker.c:375 #, c-format msgid "unregistering background worker \"%s\"" -msgstr "deregistriere Background-Worker „%s“" +msgstr "deregistriere Background-Worker »%s«" #: postmaster/bgworker.c:484 #, c-format msgid "background worker \"%s\": must attach to shared memory in order to request a database connection" -msgstr "Background-Worker „%s“: muss mit Shared Memory verbinden, um eine Datenbankverbindung anzufordern" +msgstr "Background-Worker »%s«: muss mit Shared Memory verbinden, um eine Datenbankverbindung anzufordern" #: postmaster/bgworker.c:493 #, c-format msgid "background worker \"%s\": cannot request database access if starting at postmaster start" -msgstr "Background-Worker „%s“: kann kein Datenbankzugriff anfordern, wenn er nach Postmaster-Start gestartet hat" +msgstr "Background-Worker »%s«: kann kein Datenbankzugriff anfordern, wenn er nach Postmaster-Start gestartet hat" #: postmaster/bgworker.c:507 #, c-format msgid "background worker \"%s\": invalid restart interval" -msgstr "Background-Worker „%s“: ungültiges Neustart-Intervall" +msgstr "Background-Worker »%s«: ungültiges Neustart-Intervall" #: postmaster/bgworker.c:552 #, c-format msgid "terminating background worker \"%s\" due to administrator command" -msgstr "breche Background-Worker „%s“ ab aufgrund von Anweisung des Administrators" +msgstr "breche Background-Worker »%s« ab aufgrund von Anweisung des Administrators" #: postmaster/bgworker.c:753 #, c-format msgid "background worker \"%s\": must be registered in shared_preload_libraries" -msgstr "Background-Worker „%s“: muss in shared_preload_libraries registriert sein" +msgstr "Background-Worker »%s«: muss in shared_preload_libraries registriert sein" #: postmaster/bgworker.c:765 #, c-format msgid "background worker \"%s\": only dynamic background workers can request notification" -msgstr "Background-Worker „%s“: nur dynamische Background-Worker können Benachrichtigung verlangen" +msgstr "Background-Worker »%s«: nur dynamische Background-Worker können Benachrichtigung verlangen" #: postmaster/bgworker.c:780 #, c-format @@ -13774,7 +13775,7 @@ msgstr[1] "Mit den aktuellen Einstellungen können bis zu %d Background-Worker r #: postmaster/bgworker.c:785 #, c-format msgid "Consider increasing the configuration parameter \"max_worker_processes\"." -msgstr "Erhöhen Sie eventuell den Konfigurationsparameter „max_worker_processes“." +msgstr "Erhöhen Sie eventuell den Konfigurationsparameter »max_worker_processes«." #: postmaster/checkpointer.c:470 #, c-format @@ -13786,7 +13787,7 @@ msgstr[1] "Checkpoints passieren zu oft (alle %d Sekunden)" #: postmaster/checkpointer.c:474 #, c-format msgid "Consider increasing the configuration parameter \"max_wal_size\"." -msgstr "Erhöhen Sie eventuell den Konfigurationsparameter „max_wal_size“." +msgstr "Erhöhen Sie eventuell den Konfigurationsparameter »max_wal_size«." #: postmaster/checkpointer.c:621 #, c-format @@ -13821,7 +13822,7 @@ msgstr "archive_mode ist an, aber archive_command ist nicht gesetzt" #: postmaster/pgarch.c:484 #, c-format msgid "archiving transaction log file \"%s\" failed too many times, will try again later" -msgstr "Archivieren der Transaktionslogdatei „%s“ schlug zu oft fehl, wird später erneut versucht" +msgstr "Archivieren der Transaktionslogdatei »%s« schlug zu oft fehl, wird später erneut versucht" #: postmaster/pgarch.c:587 #, c-format @@ -13839,10 +13840,10 @@ msgstr "Der fehlgeschlagene Archivbefehl war: %s" msgid "archive command was terminated by exception 0x%X" msgstr "Archivbefehl wurde durch Ausnahme 0x%X beendet" -#: postmaster/pgarch.c:598 postmaster/postmaster.c:3459 +#: postmaster/pgarch.c:598 postmaster/postmaster.c:3463 #, 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." +msgstr "Sehen Sie die Beschreibung des Hexadezimalwerts in der C-Include-Datei »ntstatus.h« nach." #: postmaster/pgarch.c:603 #, c-format @@ -13862,144 +13863,144 @@ msgstr "Archivbefehl hat mit unbekanntem Status %d beendet" #: postmaster/pgarch.c:631 #, c-format msgid "archived transaction log file \"%s\"" -msgstr "archivierte Transaktionslogdatei „%s“" +msgstr "archivierte Transaktionslogdatei »%s«" #: postmaster/pgarch.c:680 #, c-format msgid "could not open archive status directory \"%s\": %m" -msgstr "konnte Archivstatusverzeichnis „%s“ nicht öffnen: %m" +msgstr "konnte Archivstatusverzeichnis »%s« nicht öffnen: %m" -#: postmaster/pgstat.c:356 +#: postmaster/pgstat.c:352 #, c-format msgid "could not resolve \"localhost\": %s" -msgstr "konnte „localhost“ nicht auflösen: %s" +msgstr "konnte »localhost« nicht auflösen: %s" -#: postmaster/pgstat.c:379 +#: postmaster/pgstat.c:375 #, c-format msgid "trying another address for the statistics collector" msgstr "andere Adresse für Statistiksammelprozess wird versucht" -#: postmaster/pgstat.c:388 +#: postmaster/pgstat.c:384 #, c-format msgid "could not create socket for statistics collector: %m" msgstr "konnte Socket für Statistiksammelprozess nicht erzeugen: %m" -#: postmaster/pgstat.c:400 +#: postmaster/pgstat.c:396 #, c-format msgid "could not bind socket for statistics collector: %m" msgstr "konnte Socket für Statistiksammelprozess nicht binden: %m" -#: postmaster/pgstat.c:411 +#: postmaster/pgstat.c:407 #, c-format msgid "could not get address of socket for statistics collector: %m" msgstr "konnte Adresse für Socket für Statistiksammelprozess nicht ermitteln: %m" -#: postmaster/pgstat.c:427 +#: postmaster/pgstat.c:423 #, c-format msgid "could not connect socket for statistics collector: %m" msgstr "konnte nicht mit Socket für Statistiksammelprozess verbinden: %m" -#: postmaster/pgstat.c:448 +#: postmaster/pgstat.c:444 #, c-format msgid "could not send test message on socket for statistics collector: %m" msgstr "konnte Testnachricht auf Socket für Statistiksammelprozess nicht senden: %m" -#: postmaster/pgstat.c:474 +#: postmaster/pgstat.c:470 #, c-format msgid "select() failed in statistics collector: %m" msgstr "select() im Statistiksammelprozess fehlgeschlagen: %m" -#: postmaster/pgstat.c:489 +#: postmaster/pgstat.c:485 #, c-format msgid "test message did not get through on socket for statistics collector" msgstr "Testnachricht auf Socket für Statistiksammelprozess kam nicht durch" -#: postmaster/pgstat.c:504 +#: postmaster/pgstat.c:500 #, c-format msgid "could not receive test message on socket for statistics collector: %m" msgstr "konnte Testnachricht auf Socket für Statistiksammelprozess nicht empfangen: %m" -#: postmaster/pgstat.c:514 +#: postmaster/pgstat.c:510 #, c-format msgid "incorrect test message transmission on socket for statistics collector" msgstr "fehlerhafte Übertragung der Testnachricht auf Socket für Statistiksammelprozess" -#: postmaster/pgstat.c:537 +#: postmaster/pgstat.c:533 #, c-format msgid "could not set statistics collector socket to nonblocking mode: %m" msgstr "konnte Socket von Statistiksammelprozess nicht auf nicht blockierenden Modus setzen: %m" -#: postmaster/pgstat.c:547 +#: postmaster/pgstat.c:543 #, c-format msgid "disabling statistics collector for lack of working socket" msgstr "Statistiksammelprozess abgeschaltet wegen nicht funkionierender Socket" -#: postmaster/pgstat.c:694 +#: postmaster/pgstat.c:690 #, c-format msgid "could not fork statistics collector: %m" msgstr "konnte Statistiksammelprozess nicht starten (fork-Fehler): %m" -#: postmaster/pgstat.c:1233 postmaster/pgstat.c:1257 postmaster/pgstat.c:1290 +#: postmaster/pgstat.c:1229 postmaster/pgstat.c:1253 postmaster/pgstat.c:1286 #, c-format msgid "must be superuser to reset statistics counters" msgstr "nur Superuser können Statistikzähler zurücksetzen" -#: postmaster/pgstat.c:1266 +#: postmaster/pgstat.c:1262 #, c-format msgid "unrecognized reset target: \"%s\"" -msgstr "unbekanntes Reset-Ziel: „%s“" +msgstr "unbekanntes Reset-Ziel: »%s«" -#: postmaster/pgstat.c:1267 +#: postmaster/pgstat.c:1263 #, c-format msgid "Target must be \"archiver\" or \"bgwriter\"." -msgstr "Das Reset-Ziel muss „archiver“ oder „bgwriter“ sein." +msgstr "Das Reset-Ziel muss »archiver« oder »bgwriter« sein." #: postmaster/pgstat.c:3425 #, c-format msgid "could not read statistics message: %m" msgstr "konnte Statistiknachricht nicht lesen: %m" -#: postmaster/pgstat.c:3756 postmaster/pgstat.c:3933 +#: postmaster/pgstat.c:3756 postmaster/pgstat.c:3913 #, c-format msgid "could not open temporary statistics file \"%s\": %m" -msgstr "konnte temporäre Statistikdatei „%s“ nicht öffnen: %m" +msgstr "konnte temporäre Statistikdatei »%s« nicht öffnen: %m" -#: postmaster/pgstat.c:3824 postmaster/pgstat.c:3978 +#: postmaster/pgstat.c:3823 postmaster/pgstat.c:3958 #, c-format msgid "could not write temporary statistics file \"%s\": %m" -msgstr "konnte temporäre Statistikdatei „%s“ nicht schreiben: %m" +msgstr "konnte temporäre Statistikdatei »%s« nicht schreiben: %m" -#: postmaster/pgstat.c:3833 postmaster/pgstat.c:3987 +#: postmaster/pgstat.c:3832 postmaster/pgstat.c:3967 #, c-format msgid "could not close temporary statistics file \"%s\": %m" -msgstr "konnte temporäre Statistikdatei „%s“ nicht schließen: %m" +msgstr "konnte temporäre Statistikdatei »%s« nicht schließen: %m" -#: postmaster/pgstat.c:3841 postmaster/pgstat.c:3995 +#: postmaster/pgstat.c:3840 postmaster/pgstat.c:3975 #, c-format msgid "could not rename temporary statistics file \"%s\" to \"%s\": %m" -msgstr "konnte temporäre Statistikdatei „%s“ nicht in „%s“ umbenennen: %m" +msgstr "konnte temporäre Statistikdatei »%s« nicht in »%s« umbenennen: %m" -#: postmaster/pgstat.c:4077 postmaster/pgstat.c:4260 postmaster/pgstat.c:4415 +#: postmaster/pgstat.c:4064 postmaster/pgstat.c:4249 postmaster/pgstat.c:4402 #, c-format msgid "could not open statistics file \"%s\": %m" -msgstr "konnte Statistikdatei „%s“ nicht öffnen: %m" +msgstr "konnte Statistikdatei »%s« nicht öffnen: %m" -#: postmaster/pgstat.c:4089 postmaster/pgstat.c:4099 postmaster/pgstat.c:4109 -#: postmaster/pgstat.c:4130 postmaster/pgstat.c:4145 postmaster/pgstat.c:4201 -#: postmaster/pgstat.c:4272 postmaster/pgstat.c:4292 postmaster/pgstat.c:4310 -#: postmaster/pgstat.c:4326 postmaster/pgstat.c:4344 postmaster/pgstat.c:4360 -#: postmaster/pgstat.c:4427 postmaster/pgstat.c:4439 postmaster/pgstat.c:4451 -#: postmaster/pgstat.c:4476 postmaster/pgstat.c:4498 +#: postmaster/pgstat.c:4076 postmaster/pgstat.c:4086 postmaster/pgstat.c:4096 +#: postmaster/pgstat.c:4117 postmaster/pgstat.c:4132 postmaster/pgstat.c:4186 +#: postmaster/pgstat.c:4261 postmaster/pgstat.c:4281 postmaster/pgstat.c:4299 +#: postmaster/pgstat.c:4315 postmaster/pgstat.c:4333 postmaster/pgstat.c:4349 +#: postmaster/pgstat.c:4414 postmaster/pgstat.c:4426 postmaster/pgstat.c:4438 +#: postmaster/pgstat.c:4463 postmaster/pgstat.c:4485 #, c-format msgid "corrupted statistics file \"%s\"" -msgstr "verfälschte Statistikdatei „%s“" +msgstr "verfälschte Statistikdatei »%s«" -#: postmaster/pgstat.c:4615 +#: postmaster/pgstat.c:4614 #, c-format msgid "using stale statistics instead of current ones because stats collector is not responding" msgstr "verwende veraltete Statistiken anstatt aktueller, weil der Statistiksammelprozess nicht antwortet" -#: postmaster/pgstat.c:4933 +#: postmaster/pgstat.c:4943 #, c-format msgid "database hash table corrupted during cleanup --- abort" msgstr "Datenbank-Hash-Tabelle beim Aufräumen verfälscht --- Abbruch" @@ -14007,160 +14008,160 @@ msgstr "Datenbank-Hash-Tabelle beim Aufräumen verfälscht --- Abbruch" #: postmaster/postmaster.c:670 #, c-format msgid "%s: invalid argument for option -f: \"%s\"\n" -msgstr "%s: ungültiges Argument für Option -f: „%s“\n" +msgstr "%s: ungültiges Argument für Option -f: »%s«\n" #: postmaster/postmaster.c:756 #, c-format msgid "%s: invalid argument for option -t: \"%s\"\n" -msgstr "%s: ungültiges Argument für Option -t: „%s“\n" +msgstr "%s: ungültiges Argument für Option -t: »%s«\n" #: postmaster/postmaster.c:807 #, c-format msgid "%s: invalid argument: \"%s\"\n" -msgstr "%s: ungültiges Argument: „%s“\n" +msgstr "%s: ungültiges Argument: »%s«\n" -#: postmaster/postmaster.c:842 +#: postmaster/postmaster.c:846 #, c-format msgid "%s: superuser_reserved_connections must be less than max_connections\n" msgstr "%s: superuser_reserved_connections muss kleiner als max_connections sein\n" -#: postmaster/postmaster.c:847 +#: postmaster/postmaster.c:851 #, c-format msgid "%s: max_wal_senders must be less than max_connections\n" msgstr "%s: max_wal_senders muss kleiner als max_connections sein\n" -#: postmaster/postmaster.c:852 +#: postmaster/postmaster.c:856 #, 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" +msgstr "WAL-Archivierung kann nicht eingeschaltet werden, wenn wal_level »minimal« ist" -#: postmaster/postmaster.c:855 +#: postmaster/postmaster.c:859 #, c-format msgid "WAL streaming (max_wal_senders > 0) requires wal_level \"archive\", \"hot_standby\", or \"logical\"" -msgstr "WAL-Streaming (max_wal_senders > 0) benötigt wal_level „archive“, „hot_standby“ oder „logical“" +msgstr "WAL-Streaming (max_wal_senders > 0) benötigt wal_level »archive«, »hot_standby« oder »logical«" -#: postmaster/postmaster.c:863 +#: postmaster/postmaster.c:867 #, c-format msgid "%s: invalid datetoken tables, please fix\n" msgstr "%s: ungültige datetoken-Tabellen, bitte reparieren\n" -#: postmaster/postmaster.c:955 postmaster/postmaster.c:1053 +#: postmaster/postmaster.c:959 postmaster/postmaster.c:1057 #: utils/init/miscinit.c:1410 #, c-format msgid "invalid list syntax in parameter \"%s\"" -msgstr "ungültige Listensyntax für Parameter „%s“" +msgstr "ungültige Listensyntax für Parameter »%s«" -#: postmaster/postmaster.c:986 +#: postmaster/postmaster.c:990 #, c-format msgid "could not create listen socket for \"%s\"" -msgstr "konnte Listen-Socket für „%s“ nicht erzeugen" +msgstr "konnte Listen-Socket für »%s« nicht erzeugen" -#: postmaster/postmaster.c:992 +#: postmaster/postmaster.c:996 #, c-format msgid "could not create any TCP/IP sockets" msgstr "konnte keine TCP/IP-Sockets erstellen" -#: postmaster/postmaster.c:1075 +#: postmaster/postmaster.c:1079 #, c-format msgid "could not create Unix-domain socket in directory \"%s\"" -msgstr "konnte Unix-Domain-Socket in Verzeichnis „%s“ nicht erzeugen" +msgstr "konnte Unix-Domain-Socket in Verzeichnis »%s« nicht erzeugen" -#: postmaster/postmaster.c:1081 +#: postmaster/postmaster.c:1085 #, c-format msgid "could not create any Unix-domain sockets" msgstr "konnte keine Unix-Domain-Sockets erzeugen" -#: postmaster/postmaster.c:1093 +#: postmaster/postmaster.c:1097 #, c-format msgid "no socket created for listening" msgstr "keine Listen-Socket erzeugt" -#: postmaster/postmaster.c:1133 +#: postmaster/postmaster.c:1137 #, 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:1162 +#: postmaster/postmaster.c:1166 #, c-format msgid "%s: could not change permissions of external PID file \"%s\": %s\n" -msgstr "%s: konnte Rechte der externen PID-Datei „%s“ nicht ändern: %s\n" +msgstr "%s: konnte Rechte der externen PID-Datei »%s« nicht ändern: %s\n" -#: postmaster/postmaster.c:1166 +#: postmaster/postmaster.c:1170 #, c-format msgid "%s: could not write external PID file \"%s\": %s\n" -msgstr "%s: konnte externe PID-Datei „%s“ nicht schreiben: %s\n" +msgstr "%s: konnte externe PID-Datei »%s« nicht schreiben: %s\n" -#: postmaster/postmaster.c:1217 +#: postmaster/postmaster.c:1221 #, c-format msgid "ending log output to stderr" msgstr "Logausgabe nach stderr endet" -#: postmaster/postmaster.c:1218 +#: postmaster/postmaster.c:1222 #, c-format msgid "Future log output will go to log destination \"%s\"." -msgstr "Die weitere Logausgabe geht an Logziel „%s“." +msgstr "Die weitere Logausgabe geht an Logziel »%s«." -#: postmaster/postmaster.c:1244 utils/init/postinit.c:200 +#: postmaster/postmaster.c:1248 utils/init/postinit.c:200 #, c-format msgid "could not load pg_hba.conf" msgstr "konnte pg_hba.conf nicht laden" -#: postmaster/postmaster.c:1270 +#: postmaster/postmaster.c:1274 #, c-format msgid "postmaster became multithreaded during startup" msgstr "Postmaster ist während des Starts multithreaded geworden" -#: postmaster/postmaster.c:1271 +#: postmaster/postmaster.c:1275 #, 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:1368 +#: postmaster/postmaster.c:1372 #, c-format msgid "%s: could not locate matching postgres executable" -msgstr "%s: konnte kein passendes Programm „postgres“ finden" +msgstr "%s: konnte kein passendes Programm »postgres« finden" -#: postmaster/postmaster.c:1391 utils/misc/tzparser.c:341 +#: postmaster/postmaster.c:1395 utils/misc/tzparser.c:341 #, 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." +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:1419 +#: postmaster/postmaster.c:1423 #, c-format msgid "data directory \"%s\" does not exist" -msgstr "Datenverzeichnis „%s“ existiert nicht" +msgstr "Datenverzeichnis »%s« existiert nicht" -#: postmaster/postmaster.c:1424 +#: postmaster/postmaster.c:1428 #, c-format msgid "could not read permissions of directory \"%s\": %m" -msgstr "konnte Zugriffsrechte von Verzeichnis „%s“ nicht lesen: %m" +msgstr "konnte Zugriffsrechte von Verzeichnis »%s« nicht lesen: %m" -#: postmaster/postmaster.c:1432 +#: postmaster/postmaster.c:1436 #, c-format msgid "specified data directory \"%s\" is not a directory" -msgstr "angegebenes Datenverzeichnis „%s“ ist kein Verzeichnis" +msgstr "angegebenes Datenverzeichnis »%s« ist kein Verzeichnis" -#: postmaster/postmaster.c:1448 +#: postmaster/postmaster.c:1452 #, c-format msgid "data directory \"%s\" has wrong ownership" -msgstr "Datenverzeichnis „%s“ hat falschen Eigentümer" +msgstr "Datenverzeichnis »%s« hat falschen Eigentümer" -#: postmaster/postmaster.c:1450 +#: postmaster/postmaster.c:1454 #, c-format msgid "The server must be started by the user that owns the data directory." msgstr "Der Server muss von dem Benutzer gestartet werden, dem das Datenverzeichnis gehört." -#: postmaster/postmaster.c:1470 +#: postmaster/postmaster.c:1474 #, c-format msgid "data directory \"%s\" has group or world access" -msgstr "Datenverzeichnis „%s“ erlaubt Zugriff von Gruppe oder Welt" +msgstr "Datenverzeichnis »%s« erlaubt Zugriff von Gruppe oder Welt" -#: postmaster/postmaster.c:1472 +#: postmaster/postmaster.c:1476 #, c-format msgid "Permissions should be u=rwx (0700)." msgstr "Rechte sollten u=rwx (0700) sein." -#: postmaster/postmaster.c:1483 +#: postmaster/postmaster.c:1487 #, c-format msgid "" "%s: could not find the database system\n" @@ -14168,368 +14169,368 @@ msgid "" "but could not open file \"%s\": %s\n" msgstr "" "%s: konnte das Datenbanksystem nicht finden\n" -"Es wurde im Verzeichnis „%s“ erwartet,\n" -"aber die Datei „%s“ konnte nicht geöffnet werden: %s\n" +"Es wurde im Verzeichnis »%s« erwartet,\n" +"aber die Datei »%s« konnte nicht geöffnet werden: %s\n" -#: postmaster/postmaster.c:1660 +#: postmaster/postmaster.c:1664 #, c-format msgid "select() failed in postmaster: %m" msgstr "select() fehlgeschlagen im Postmaster: %m" -#: postmaster/postmaster.c:1810 +#: postmaster/postmaster.c:1814 #, 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:1888 postmaster/postmaster.c:1919 +#: postmaster/postmaster.c:1892 postmaster/postmaster.c:1923 #, c-format msgid "incomplete startup packet" msgstr "unvollständiges Startpaket" -#: postmaster/postmaster.c:1900 +#: postmaster/postmaster.c:1904 #, c-format msgid "invalid length of startup packet" msgstr "ungültige Länge des Startpakets" -#: postmaster/postmaster.c:1958 +#: postmaster/postmaster.c:1962 #, c-format msgid "failed to send SSL negotiation response: %m" msgstr "konnte SSL-Verhandlungsantwort nicht senden: %m" -#: postmaster/postmaster.c:1987 +#: postmaster/postmaster.c:1991 #, c-format msgid "unsupported frontend protocol %u.%u: server supports %u.0 to %u.%u" msgstr "nicht unterstütztes Frontend-Protokoll %u.%u: Server unterstützt %u.0 bis %u.%u" -#: postmaster/postmaster.c:2050 utils/misc/guc.c:5484 utils/misc/guc.c:5577 +#: postmaster/postmaster.c:2054 utils/misc/guc.c:5484 utils/misc/guc.c:5577 #: utils/misc/guc.c:6874 utils/misc/guc.c:9579 utils/misc/guc.c:9613 #, c-format msgid "invalid value for parameter \"%s\": \"%s\"" -msgstr "ungültiger Wert für Parameter „%s“: „%s“" +msgstr "ungültiger Wert für Parameter »%s«: »%s«" -#: postmaster/postmaster.c:2053 +#: postmaster/postmaster.c:2057 #, c-format msgid "Valid values are: \"false\", 0, \"true\", 1, \"database\"." -msgstr "Gültige Werte sind: „false“, 0, „true“, 1, „database“." +msgstr "Gültige Werte sind: »false«, 0, »true«, 1, »database«." -#: postmaster/postmaster.c:2073 +#: postmaster/postmaster.c:2077 #, c-format msgid "invalid startup packet layout: expected terminator as last byte" msgstr "ungültiges Layout des Startpakets: Abschluss als letztes Byte erwartet" -#: postmaster/postmaster.c:2101 +#: postmaster/postmaster.c:2105 #, c-format msgid "no PostgreSQL user name specified in startup packet" msgstr "kein PostgreSQL-Benutzername im Startpaket angegeben" -#: postmaster/postmaster.c:2160 +#: postmaster/postmaster.c:2164 #, c-format msgid "the database system is starting up" msgstr "das Datenbanksystem startet" -#: postmaster/postmaster.c:2165 +#: postmaster/postmaster.c:2169 #, c-format msgid "the database system is shutting down" msgstr "das Datenbanksystem fährt herunter" -#: postmaster/postmaster.c:2170 +#: postmaster/postmaster.c:2174 #, c-format msgid "the database system is in recovery mode" msgstr "das Datenbanksystem ist im Wiederherstellungsmodus" -#: postmaster/postmaster.c:2175 storage/ipc/procarray.c:284 +#: postmaster/postmaster.c:2179 storage/ipc/procarray.c:284 #: storage/ipc/sinvaladt.c:298 storage/lmgr/proc.c:334 #, c-format msgid "sorry, too many clients already" msgstr "tut mir leid, schon zu viele Verbindungen" -#: postmaster/postmaster.c:2237 +#: postmaster/postmaster.c:2241 #, c-format msgid "wrong key in cancel request for process %d" msgstr "falscher Schlüssel in Stornierungsanfrage für Prozess %d" -#: postmaster/postmaster.c:2245 +#: postmaster/postmaster.c:2249 #, c-format msgid "PID %d in cancel request did not match any process" msgstr "PID %d in Stornierungsanfrage stimmte mit keinem Prozess überein" -#: postmaster/postmaster.c:2465 +#: postmaster/postmaster.c:2469 #, c-format msgid "received SIGHUP, reloading configuration files" msgstr "SIGHUP empfangen, Konfigurationsdateien werden neu geladen" -#: postmaster/postmaster.c:2490 +#: postmaster/postmaster.c:2494 #, c-format msgid "pg_hba.conf not reloaded" msgstr "pg_hba.conf nicht neu geladen" -#: postmaster/postmaster.c:2494 +#: postmaster/postmaster.c:2498 #, c-format msgid "pg_ident.conf not reloaded" msgstr "pg_ident.conf nicht neu geladen" -#: postmaster/postmaster.c:2535 +#: postmaster/postmaster.c:2539 #, c-format msgid "received smart shutdown request" msgstr "intelligentes Herunterfahren verlangt" -#: postmaster/postmaster.c:2587 +#: postmaster/postmaster.c:2591 #, c-format msgid "received fast shutdown request" msgstr "schnelles Herunterfahren verlangt" -#: postmaster/postmaster.c:2613 +#: postmaster/postmaster.c:2617 #, c-format msgid "aborting any active transactions" msgstr "etwaige aktive Transaktionen werden abgebrochen" -#: postmaster/postmaster.c:2647 +#: postmaster/postmaster.c:2651 #, c-format msgid "received immediate shutdown request" msgstr "sofortiges Herunterfahren verlangt" -#: postmaster/postmaster.c:2708 +#: postmaster/postmaster.c:2712 #, c-format msgid "shutdown at recovery target" msgstr "Herunterfahren beim Wiederherstellungsziel" -#: postmaster/postmaster.c:2724 postmaster/postmaster.c:2747 +#: postmaster/postmaster.c:2728 postmaster/postmaster.c:2751 msgid "startup process" msgstr "Startprozess" -#: postmaster/postmaster.c:2727 +#: postmaster/postmaster.c:2731 #, c-format msgid "aborting startup due to startup process failure" msgstr "Serverstart abgebrochen wegen Startprozessfehler" -#: postmaster/postmaster.c:2788 +#: postmaster/postmaster.c:2792 #, c-format msgid "database system is ready to accept connections" msgstr "Datenbanksystem ist bereit, um Verbindungen anzunehmen" -#: postmaster/postmaster.c:2803 +#: postmaster/postmaster.c:2807 msgid "background writer process" msgstr "Background-Writer-Prozess" -#: postmaster/postmaster.c:2857 +#: postmaster/postmaster.c:2861 msgid "checkpointer process" msgstr "Checkpointer-Prozess" -#: postmaster/postmaster.c:2873 +#: postmaster/postmaster.c:2877 msgid "WAL writer process" msgstr "WAL-Schreibprozess" -#: postmaster/postmaster.c:2887 +#: postmaster/postmaster.c:2891 msgid "WAL receiver process" msgstr "WAL-Receiver-Prozess" -#: postmaster/postmaster.c:2902 +#: postmaster/postmaster.c:2906 msgid "autovacuum launcher process" msgstr "Autovacuum-Launcher-Prozess" -#: postmaster/postmaster.c:2917 +#: postmaster/postmaster.c:2921 msgid "archiver process" msgstr "Archivierprozess" -#: postmaster/postmaster.c:2933 +#: postmaster/postmaster.c:2937 msgid "statistics collector process" msgstr "Statistiksammelprozess" -#: postmaster/postmaster.c:2947 +#: postmaster/postmaster.c:2951 msgid "system logger process" msgstr "Systemlogger-Prozess" -#: postmaster/postmaster.c:3009 +#: postmaster/postmaster.c:3013 msgid "worker process" msgstr "Worker-Prozess" -#: postmaster/postmaster.c:3092 postmaster/postmaster.c:3112 -#: postmaster/postmaster.c:3119 postmaster/postmaster.c:3137 +#: postmaster/postmaster.c:3096 postmaster/postmaster.c:3116 +#: postmaster/postmaster.c:3123 postmaster/postmaster.c:3141 msgid "server process" msgstr "Serverprozess" -#: postmaster/postmaster.c:3191 +#: postmaster/postmaster.c:3195 #, 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:3447 +#: postmaster/postmaster.c:3451 #, c-format msgid "%s (PID %d) exited with exit code %d" msgstr "%s (PID %d) beendete mit Status %d" -#: postmaster/postmaster.c:3449 postmaster/postmaster.c:3460 -#: postmaster/postmaster.c:3471 postmaster/postmaster.c:3480 -#: postmaster/postmaster.c:3490 +#: postmaster/postmaster.c:3453 postmaster/postmaster.c:3464 +#: postmaster/postmaster.c:3475 postmaster/postmaster.c:3484 +#: postmaster/postmaster.c:3494 #, 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:3457 +#: postmaster/postmaster.c:3461 #, 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:3467 +#: postmaster/postmaster.c:3471 #, 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:3478 +#: postmaster/postmaster.c:3482 #, c-format msgid "%s (PID %d) was terminated by signal %d" msgstr "%s (PID %d) wurde von Signal %d beendet" #. translator: %s is a noun phrase describing a child process, such as #. "server process" -#: postmaster/postmaster.c:3488 +#: postmaster/postmaster.c:3492 #, c-format msgid "%s (PID %d) exited with unrecognized status %d" msgstr "%s (PID %d) beendete mit unbekanntem Status %d" -#: postmaster/postmaster.c:3675 +#: postmaster/postmaster.c:3679 #, c-format msgid "abnormal database system shutdown" msgstr "abnormales Herunterfahren des Datenbanksystems" -#: postmaster/postmaster.c:3715 +#: postmaster/postmaster.c:3719 #, c-format msgid "all server processes terminated; reinitializing" msgstr "alle Serverprozesse beendet; initialisiere neu" -#: postmaster/postmaster.c:3927 +#: postmaster/postmaster.c:3931 #, 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:3969 +#: postmaster/postmaster.c:3973 msgid "could not fork new process for connection: " msgstr "konnte neuen Prozess für Verbindung nicht starten (fork-Fehler): " -#: postmaster/postmaster.c:4083 +#: postmaster/postmaster.c:4087 #, c-format msgid "connection received: host=%s port=%s" msgstr "Verbindung empfangen: Host=%s Port=%s" -#: postmaster/postmaster.c:4088 +#: postmaster/postmaster.c:4092 #, c-format msgid "connection received: host=%s" msgstr "Verbindung empfangen: Host=%s" -#: postmaster/postmaster.c:4371 +#: postmaster/postmaster.c:4375 #, c-format msgid "could not execute server process \"%s\": %m" -msgstr "konnte Serverprozess „%s“ nicht ausführen: %m" +msgstr "konnte Serverprozess »%s« nicht ausführen: %m" -#: postmaster/postmaster.c:4931 +#: postmaster/postmaster.c:4935 #, c-format msgid "database system is ready to accept read only connections" msgstr "Datenbanksystem ist bereit, um lesende Verbindungen anzunehmen" -#: postmaster/postmaster.c:5214 +#: postmaster/postmaster.c:5218 #, c-format msgid "could not fork startup process: %m" msgstr "konnte Startprozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5218 +#: postmaster/postmaster.c:5222 #, c-format msgid "could not fork background writer process: %m" msgstr "konnte Background-Writer-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5222 +#: postmaster/postmaster.c:5226 #, c-format msgid "could not fork checkpointer process: %m" msgstr "konnte Checkpointer-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5226 +#: postmaster/postmaster.c:5230 #, c-format msgid "could not fork WAL writer process: %m" msgstr "konnte WAL-Writer-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5230 +#: postmaster/postmaster.c:5234 #, c-format msgid "could not fork WAL receiver process: %m" msgstr "konnte WAL-Receiver-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5234 +#: postmaster/postmaster.c:5238 #, c-format msgid "could not fork process: %m" msgstr "konnte Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5396 postmaster/postmaster.c:5419 +#: postmaster/postmaster.c:5400 postmaster/postmaster.c:5423 #, c-format msgid "database connection requirement not indicated during registration" msgstr "die Notwendigkeit, Datenbankverbindungen zu erzeugen, wurde bei der Registrierung nicht angezeigt" -#: postmaster/postmaster.c:5403 postmaster/postmaster.c:5426 +#: postmaster/postmaster.c:5407 postmaster/postmaster.c:5430 #, c-format msgid "invalid processing mode in background worker" msgstr "ungültiger Verarbeitungsmodus in Background-Worker" -#: postmaster/postmaster.c:5478 +#: postmaster/postmaster.c:5482 #, c-format msgid "starting background worker process \"%s\"" -msgstr "starte Background-Worker-Prozess „%s“" +msgstr "starte Background-Worker-Prozess »%s«" -#: postmaster/postmaster.c:5489 +#: postmaster/postmaster.c:5493 #, c-format msgid "could not fork worker process: %m" msgstr "konnte Worker-Prozess nicht starten (fork-Fehler): %m" -#: postmaster/postmaster.c:5865 +#: postmaster/postmaster.c:5869 #, c-format msgid "could not duplicate socket %d for use in backend: error code %d" msgstr "konnte Socket %d nicht für Verwendung in Backend duplizieren: Fehlercode %d" -#: postmaster/postmaster.c:5897 +#: postmaster/postmaster.c:5901 #, c-format msgid "could not create inherited socket: error code %d\n" msgstr "konnte geerbtes Socket nicht erzeugen: Fehlercode %d\n" -#: postmaster/postmaster.c:5926 +#: postmaster/postmaster.c:5930 #, c-format msgid "could not open backend variables file \"%s\": %s\n" -msgstr "konnte Servervariablendatei „%s“ nicht öffnen: %s\n" +msgstr "konnte Servervariablendatei »%s« nicht öffnen: %s\n" -#: postmaster/postmaster.c:5933 +#: postmaster/postmaster.c:5937 #, c-format msgid "could not read from backend variables file \"%s\": %s\n" -msgstr "konnte nicht aus Servervariablendatei „%s“ lesen: %s\n" +msgstr "konnte nicht aus Servervariablendatei »%s« lesen: %s\n" -#: postmaster/postmaster.c:5942 +#: postmaster/postmaster.c:5946 #, c-format msgid "could not remove file \"%s\": %s\n" -msgstr "konnte Datei „%s“ nicht löschen: %s\n" +msgstr "konnte Datei »%s« nicht löschen: %s\n" -#: postmaster/postmaster.c:5959 +#: postmaster/postmaster.c:5963 #, c-format msgid "could not map view of backend variables: error code %lu\n" msgstr "konnte Sicht der Backend-Variablen nicht mappen: Fehlercode %lu\n" -#: postmaster/postmaster.c:5968 +#: postmaster/postmaster.c:5972 #, c-format msgid "could not unmap view of backend variables: error code %lu\n" msgstr "konnte Sicht der Backend-Variablen nicht unmappen: Fehlercode %lu\n" -#: postmaster/postmaster.c:5975 +#: postmaster/postmaster.c:5979 #, c-format msgid "could not close handle to backend parameter variables: error code %lu\n" msgstr "konnte Handle für Backend-Parametervariablen nicht schließen: Fehlercode %lu\n" -#: postmaster/postmaster.c:6134 +#: postmaster/postmaster.c:6138 #, c-format msgid "could not read exit code for process\n" msgstr "konnte Exitcode des Prozesses nicht lesen\n" -#: postmaster/postmaster.c:6139 +#: postmaster/postmaster.c:6143 #, c-format msgid "could not post child completion status\n" msgstr "konnte Child-Completion-Status nicht versenden\n" @@ -14562,7 +14563,7 @@ msgstr "Logausgabe wird an Logsammelprozess umgeleitet" #: postmaster/syslogger.c:621 #, c-format msgid "Future log output will appear in directory \"%s\"." -msgstr "Die weitere Logausgabe wird im Verzeichnis „%s“ erscheinen." +msgstr "Die weitere Logausgabe wird im Verzeichnis »%s« erscheinen." #: postmaster/syslogger.c:629 #, c-format @@ -14582,7 +14583,7 @@ msgstr "konnte nicht in Logdatei schreiben: %s\n" #: postmaster/syslogger.c:1136 #, c-format msgid "could not open log file \"%s\": %m" -msgstr "konnte Logdatei „%s“ nicht öffnen: %m" +msgstr "konnte Logdatei »%s« nicht öffnen: %m" #: postmaster/syslogger.c:1198 postmaster/syslogger.c:1242 #, c-format @@ -14610,12 +14611,12 @@ msgstr "Zeichenkette in Anführungszeichen nicht abgeschlossen" #: repl_scanner.l:180 #, c-format msgid "syntax error: unexpected character \"%s\"" -msgstr "Syntaxfehler: unerwartetes Zeichen „%s“" +msgstr "Syntaxfehler: unerwartetes Zeichen »%s«" #: replication/basebackup.c:227 #, c-format msgid "could not stat control file \"%s\": %m" -msgstr "konnte „stat“ für Kontrolldatei „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Kontrolldatei »%s« nicht ausführen: %m" #: replication/basebackup.c:336 #, c-format @@ -14626,12 +14627,12 @@ msgstr "konnte keine WAL-Dateien finden" #: replication/basebackup.c:372 #, c-format msgid "could not find WAL file \"%s\"" -msgstr "konnte WAL-Datei „%s“ nicht finden" +msgstr "konnte WAL-Datei »%s« nicht finden" #: replication/basebackup.c:411 replication/basebackup.c:437 #, c-format msgid "unexpected WAL file size \"%s\"" -msgstr "unerwartete WAL-Dateigröße „%s“" +msgstr "unerwartete WAL-Dateigröße »%s«" #: replication/basebackup.c:423 replication/basebackup.c:1169 #, c-format @@ -14644,32 +14645,32 @@ msgstr "Basissicherung konnte keine Daten senden, Sicherung abgebrochen" #: replication/basebackup.c:589 #, c-format msgid "duplicate option \"%s\"" -msgstr "doppelte Option „%s“" +msgstr "doppelte Option »%s«" #: replication/basebackup.c:578 utils/misc/guc.c:5494 #, c-format msgid "%d is outside the valid range for parameter \"%s\" (%d .. %d)" -msgstr "%d ist außerhalb des gültigen Bereichs für Parameter „%s“ (%d ... %d)" +msgstr "%d ist außerhalb des gültigen Bereichs für Parameter »%s« (%d ... %d)" #: replication/basebackup.c:852 replication/basebackup.c:954 #, c-format msgid "could not stat file or directory \"%s\": %m" -msgstr "konnte „stat“ für Datei oder Verzeichnis „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Datei oder Verzeichnis »%s« nicht ausführen: %m" #: replication/basebackup.c:1121 #, c-format msgid "skipping special file \"%s\"" -msgstr "überspringe besondere Datei „%s“" +msgstr "überspringe besondere Datei »%s«" #: replication/basebackup.c:1232 #, c-format msgid "file name too long for tar format: \"%s\"" -msgstr "Dateiname zu lang für Tar-Format: „%s“" +msgstr "Dateiname zu lang für Tar-Format: »%s«" #: replication/basebackup.c:1237 #, c-format msgid "symbolic link target too long for tar format: file name \"%s\", target \"%s\"" -msgstr "Ziel der symbolischen Verknüpfung zu lang für Tar-Format: Dateiname „%s“, Ziel „%s“" +msgstr "Ziel der symbolischen Verknüpfung zu lang für Tar-Format: Dateiname »%s«, Ziel »%s«" #: replication/libpqwalreceiver/libpqwalreceiver.c:116 #, c-format @@ -14777,7 +14778,7 @@ msgstr "physischer Replikations-Slot kann nicht für logisches Dekodieren verwen #: replication/logical/logical.c:239 replication/logical/logical.c:388 #, c-format msgid "replication slot \"%s\" was not created in this database" -msgstr "Replikations-Slot „%s“ wurde nicht in dieser Datenbank erzeugt" +msgstr "Replikations-Slot »%s« wurde nicht in dieser Datenbank erzeugt" #: replication/logical/logical.c:246 #, c-format @@ -14787,7 +14788,7 @@ msgstr "logischer Replikations-Slot kann nicht in einer Transaktion erzeugt werd #: replication/logical/logical.c:425 #, c-format msgid "starting logical decoding for slot \"%s\"" -msgstr "starte logisches Dekodieren für Slot „%s“" +msgstr "starte logisches Dekodieren für Slot »%s«" #: replication/logical/logical.c:427 #, c-format @@ -14797,12 +14798,12 @@ msgstr "Streaming beginnt bei Transaktionen, die nach %X/%X committen; lese WAL #: replication/logical/logical.c:562 #, c-format msgid "slot \"%s\", output plugin \"%s\", in the %s callback, associated LSN %X/%X" -msgstr "Slot „%s“, Ausgabe-Plugin „%s“, im Callback %s, zugehörige LSN %X/%X" +msgstr "Slot »%s«, Ausgabe-Plugin »%s«, im Callback %s, zugehörige LSN %X/%X" #: replication/logical/logical.c:569 #, c-format msgid "slot \"%s\", output plugin \"%s\", in the %s callback" -msgstr "Slot „%s“, Ausgabe-Plugin „%s“, im Callback %s" +msgstr "Slot »%s«, Ausgabe-Plugin »%s«, im Callback %s" #: replication/logical/logicalfuncs.c:192 replication/walsender.c:2129 #, c-format @@ -14843,7 +14844,7 @@ msgstr "Array muss eine gerade Anzahl Elemente haben" #: replication/logical/logicalfuncs.c:412 #, c-format msgid "logical decoding output plugin \"%s\" produces binary output, but function \"%s\" expects textual data" -msgstr "Ausgabe-Plugin „%s“ erzeugt binäre Ausgabe, aber Funktion „%s“ erwartet Textdaten" +msgstr "Ausgabe-Plugin »%s« erzeugt binäre Ausgabe, aber Funktion »%s« erwartet Textdaten" #: replication/logical/origin.c:181 #, c-format @@ -14878,7 +14879,7 @@ msgstr "Replikations-Checkpoint hat falsche magische Zahl %u statt %u" #: replication/logical/origin.c:703 #, c-format msgid "could not read file \"%s\": read %d of %zu" -msgstr "konnte Datei „%s“ nicht lesen: %d von %zu gelesen" +msgstr "konnte Datei »%s« nicht lesen: %d von %zu gelesen" #: replication/logical/origin.c:712 #, c-format @@ -14922,34 +14923,34 @@ msgstr "Replikationsidentifikator %d ist bereits aktiv für PID %d" msgid "no replication origin is configured" msgstr "kein Replication-Origin konfiguriert" -#: replication/logical/reorderbuffer.c:2212 +#: replication/logical/reorderbuffer.c:2213 #, c-format msgid "could not write to data file for XID %u: %m" msgstr "konnte nicht in Datendatei für XID %u schreiben: %m" -#: replication/logical/reorderbuffer.c:2308 -#: replication/logical/reorderbuffer.c:2328 +#: replication/logical/reorderbuffer.c:2309 +#: replication/logical/reorderbuffer.c:2329 #, c-format msgid "could not read from reorderbuffer spill file: %m" msgstr "konnte nicht aus Reorder-Buffer-Spill-Datei lesen: %m" -#: replication/logical/reorderbuffer.c:2312 -#: replication/logical/reorderbuffer.c:2332 +#: replication/logical/reorderbuffer.c:2313 +#: replication/logical/reorderbuffer.c:2333 #, c-format msgid "could not read from reorderbuffer spill file: read %d instead of %u bytes" msgstr "konnte nicht aus Reorder-Buffer-Spill-Datei lesen: %d statt %u Bytes gelesen" -#: replication/logical/reorderbuffer.c:2963 +#: replication/logical/reorderbuffer.c:2964 #, c-format 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" +msgstr "konnte nicht aus Datei »%s« lesen: %d statt %d Bytes gelesen" #: replication/logical/snapbuild.c:600 #, c-format msgid "exported logical decoding snapshot: \"%s\" with %u transaction ID" msgid_plural "exported logical decoding snapshot: \"%s\" with %u transaction IDs" -msgstr[0] "logischer Dekodierungs-Snapshot exportiert: „%s“ mit %u Transaktions-ID" -msgstr[1] "logischer Dekodierungs-Snapshot exportiert: „%s“ mit %u Transaktions-IDs" +msgstr[0] "logischer Dekodierungs-Snapshot exportiert: »%s« mit %u Transaktions-ID" +msgstr[1] "logischer Dekodierungs-Snapshot exportiert: »%s« mit %u Transaktions-IDs" #: replication/logical/snapbuild.c:900 replication/logical/snapbuild.c:1265 #: replication/logical/snapbuild.c:1796 @@ -14983,22 +14984,22 @@ msgstr[1] "%u Transaktionen müssen noch abschließen." #: replication/logical/snapbuild.c:1710 replication/logical/snapbuild.c:1724 #, c-format msgid "could not read file \"%s\", read %d of %d: %m" -msgstr "konnte Datei „%s“ nicht lesen, %d von %d gelesen: %m" +msgstr "konnte Datei »%s« nicht lesen, %d von %d gelesen: %m" #: replication/logical/snapbuild.c:1676 #, c-format msgid "snapbuild state file \"%s\" has wrong magic number: %u instead of %u" -msgstr "Scanbuild-State-Datei „%s“ hat falsche magische Zahl %u statt %u" +msgstr "Scanbuild-State-Datei »%s« hat falsche magische Zahl %u statt %u" #: replication/logical/snapbuild.c:1681 #, c-format msgid "snapbuild state file \"%s\" has unsupported version: %u instead of %u" -msgstr "Snapbuild-State-Datei „%s“ hat nicht unterstützte Version: %u statt %u" +msgstr "Snapbuild-State-Datei »%s« hat nicht unterstützte Version: %u statt %u" #: replication/logical/snapbuild.c:1737 #, c-format msgid "checksum mismatch for snapbuild state file \"%s\": is %u, should be %u" -msgstr "Prüfsummenfehler bei Snapbuild-State-Datei „%s“: ist %u, sollte %u sein" +msgstr "Prüfsummenfehler bei Snapbuild-State-Datei »%s«: ist %u, sollte %u sein" #: replication/logical/snapbuild.c:1798 #, c-format @@ -15008,22 +15009,22 @@ msgstr "Logische Dekodierung beginnt mit gespeichertem Snapshot." #: replication/logical/snapbuild.c:1871 #, c-format msgid "could not parse file name \"%s\"" -msgstr "konnte Dateinamen „%s“ nicht parsen" +msgstr "konnte Dateinamen »%s« nicht parsen" #: replication/slot.c:174 #, c-format msgid "replication slot name \"%s\" is too short" -msgstr "Replikations-Slot-Name „%s“ ist zu kurz" +msgstr "Replikations-Slot-Name »%s« ist zu kurz" #: replication/slot.c:183 #, c-format msgid "replication slot name \"%s\" is too long" -msgstr "Replikations-Slot-Name „%s“ ist zu lang" +msgstr "Replikations-Slot-Name »%s« ist zu lang" #: replication/slot.c:196 #, c-format msgid "replication slot name \"%s\" contains invalid character" -msgstr "Replikations-Slot-Name „%s“ enthält ungültiges Zeichen" +msgstr "Replikations-Slot-Name »%s« enthält ungültiges Zeichen" #: replication/slot.c:198 #, c-format @@ -15033,7 +15034,7 @@ msgstr "Replikations-Slot-Namen dürfen nur Kleinbuchstaben, Zahlen und Unterstr #: replication/slot.c:245 #, c-format msgid "replication slot \"%s\" already exists" -msgstr "Replikations-Slot „%s“ existiert bereits" +msgstr "Replikations-Slot »%s« existiert bereits" #: replication/slot.c:255 #, c-format @@ -15048,17 +15049,17 @@ msgstr "Geben Sie einen frei oder erhöhen Sie max_replication_slots." #: replication/slot.c:348 #, c-format msgid "replication slot \"%s\" does not exist" -msgstr "Replikations-Slot „%s“ existiert nicht" +msgstr "Replikations-Slot »%s« existiert nicht" #: replication/slot.c:352 #, c-format msgid "replication slot \"%s\" is already active for PID %d" -msgstr "Replikations-Slot „%s“ ist bereits aktiv für PID %d" +msgstr "Replikations-Slot »%s« ist bereits aktiv für PID %d" #: replication/slot.c:501 replication/slot.c:857 replication/slot.c:1202 #, c-format msgid "could not remove directory \"%s\"" -msgstr "konnte Verzeichnis „%s“ nicht löschen" +msgstr "konnte Verzeichnis »%s« nicht löschen" #: replication/slot.c:776 #, c-format @@ -15073,27 +15074,27 @@ msgstr "Replikations-Slots können nur verwendet werden, wenn wal_level >= archi #: replication/slot.c:1134 replication/slot.c:1172 #, c-format msgid "could not read file \"%s\", read %d of %u: %m" -msgstr "konnte Datei „%s“ nicht lesen, %d von %u gelesen: %m" +msgstr "konnte Datei »%s« nicht lesen, %d von %u gelesen: %m" #: replication/slot.c:1143 #, c-format msgid "replication slot file \"%s\" has wrong magic number: %u instead of %u" -msgstr "Replikations-Slot-Datei „%s“ hat falsche magische Zahl: %u statt %u" +msgstr "Replikations-Slot-Datei »%s« hat falsche magische Zahl: %u statt %u" #: replication/slot.c:1150 #, c-format msgid "replication slot file \"%s\" has unsupported version %u" -msgstr "Replikations-Slot-Datei „%s“ hat nicht unterstützte Version %u" +msgstr "Replikations-Slot-Datei »%s« hat nicht unterstützte Version %u" #: replication/slot.c:1157 #, c-format msgid "replication slot file \"%s\" has corrupted length %u" -msgstr "Replikations-Slot-Datei „%s“ hat falsche Länge %u" +msgstr "Replikations-Slot-Datei »%s« hat falsche Länge %u" #: replication/slot.c:1187 #, c-format msgid "checksum mismatch for replication slot file \"%s\": is %u, should be %u" -msgstr "Prüfsummenfehler bei Replikations-Slot-Datei „%s“: ist %u, sollte %u sein" +msgstr "Prüfsummenfehler bei Replikations-Slot-Datei »%s«: ist %u, sollte %u sein" #: replication/slot.c:1240 #, c-format @@ -15118,12 +15119,12 @@ msgstr "storniere Warten auf synchrone Replikation wegen Benutzeraufforderung" #: replication/syncrep.c:346 #, c-format msgid "standby \"%s\" now has synchronous standby priority %u" -msgstr "Standby „%s“ hat jetzt synchrone Standby-Priorität %u" +msgstr "Standby »%s« hat jetzt synchrone Standby-Priorität %u" #: replication/syncrep.c:480 #, c-format msgid "standby \"%s\" is now the synchronous standby with priority %u" -msgstr "Standby „%s“ ist jetzt der synchrone Standby mit Priorität %u" +msgstr "Standby »%s« ist jetzt der synchrone Standby mit Priorität %u" #: replication/walreceiver.c:167 #, c-format @@ -15188,7 +15189,7 @@ msgstr "konnte nicht in Logsegment %s bei Position %u, Länge %lu schreiben: %m" #: replication/walsender.c:483 #, c-format msgid "could not seek to beginning of file \"%s\": %m" -msgstr "konnte Positionszeiger nicht den Anfang der Datei „%s“ setzen: %m" +msgstr "konnte Positionszeiger nicht den Anfang der Datei »%s« setzen: %m" #: replication/walsender.c:534 #, c-format @@ -15228,17 +15229,17 @@ msgstr "unerwartetes EOF auf Standby-Verbindung" #: replication/walsender.c:1415 #, c-format msgid "unexpected standby message type \"%c\", after receiving CopyDone" -msgstr "unerwarteter Standby-Message-Typ „%c“, nach Empfang von CopyDone" +msgstr "unerwarteter Standby-Message-Typ »%c«, nach Empfang von CopyDone" #: replication/walsender.c:1453 #, c-format msgid "invalid standby message type \"%c\"" -msgstr "ungültiger Standby-Message-Typ „%c“" +msgstr "ungültiger Standby-Message-Typ »%c«" #: replication/walsender.c:1494 #, c-format msgid "unexpected message type \"%c\"" -msgstr "unerwarteter Message-Typ „%c“" +msgstr "unerwarteter Message-Typ »%c«" #: replication/walsender.c:1781 #, c-format @@ -15248,7 +15249,7 @@ msgstr "breche WAL-Sender-Prozess ab wegen Zeitüberschreitung bei der Replikati #: replication/walsender.c:1874 #, c-format msgid "standby \"%s\" has now caught up with primary" -msgstr "Standby-Server „%s“ hat jetzt den Primärserver eingeholt" +msgstr "Standby-Server »%s« hat jetzt den Primärserver eingeholt" #: replication/walsender.c:1978 #, c-format @@ -15258,7 +15259,7 @@ msgstr "Anzahl angeforderter Standby-Verbindungen überschreitet max_wal_senders #: rewrite/rewriteDefine.c:112 rewrite/rewriteDefine.c:973 #, c-format msgid "rule \"%s\" for relation \"%s\" already exists" -msgstr "Regel „%s“ für Relation „%s“ existiert bereits" +msgstr "Regel »%s« für Relation »%s« existiert bereits" #: rewrite/rewriteDefine.c:297 #, c-format @@ -15313,22 +15314,22 @@ msgstr "Ereignisqualifikationen sind nicht implementiert für SELECT-Regeln" #: rewrite/rewriteDefine.c:379 #, c-format msgid "\"%s\" is already a view" -msgstr "„%s“ ist bereits eine Sicht" +msgstr "»%s« ist bereits eine Sicht" #: rewrite/rewriteDefine.c:403 #, c-format msgid "view rule for \"%s\" must be named \"%s\"" -msgstr "Sicht-Regel für „%s“ muss „%s“ heißen" +msgstr "Sicht-Regel für »%s« muss »%s« heißen" #: rewrite/rewriteDefine.c:432 #, c-format msgid "could not convert table \"%s\" to a view because it is not empty" -msgstr "konnte Tabelle „%s“ nicht in Sicht umwandeln, weil sie nicht leer ist" +msgstr "konnte Tabelle »%s« nicht in Sicht umwandeln, weil sie nicht leer ist" #: rewrite/rewriteDefine.c:440 #, c-format msgid "could not convert table \"%s\" to a view because it has triggers" -msgstr "konnte Tabelle „%s“ nicht in Sicht umwandeln, weil sie Trigger hat" +msgstr "konnte Tabelle »%s« nicht in Sicht umwandeln, weil sie Trigger hat" #: rewrite/rewriteDefine.c:442 #, c-format @@ -15338,22 +15339,22 @@ msgstr "Insbesondere darf die Tabelle nicht in Fremschlüsselverhältnisse einge #: rewrite/rewriteDefine.c:447 #, c-format msgid "could not convert table \"%s\" to a view because it has indexes" -msgstr "konnte Tabelle „%s“ nicht in Sicht umwandeln, weil sie Indexe hat" +msgstr "konnte Tabelle »%s« nicht in Sicht umwandeln, weil sie Indexe hat" #: rewrite/rewriteDefine.c:453 #, c-format msgid "could not convert table \"%s\" to a view because it has child tables" -msgstr "konnte Tabelle „%s“ nicht in Sicht umwandeln, weil sie abgeleitete Tabellen hat" +msgstr "konnte Tabelle »%s« nicht in Sicht umwandeln, weil sie abgeleitete Tabellen hat" #: rewrite/rewriteDefine.c:459 #, c-format msgid "could not convert table \"%s\" to a view because it has row security enabled" -msgstr "konnte Tabelle „%s“ nicht in Sicht umwandeln, weil sie Sicherheit auf Zeilenebene eingeschaltet hat" +msgstr "konnte Tabelle »%s« nicht in Sicht umwandeln, weil sie Sicherheit auf Zeilenebene eingeschaltet hat" #: rewrite/rewriteDefine.c:465 #, c-format msgid "could not convert table \"%s\" to a view because it has row security policies" -msgstr "konnte Tabelle „%s“ nicht in Sicht umwandeln, weil sie Policys für Sicherheit auf Zeilenebene hat" +msgstr "konnte Tabelle »%s« nicht in Sicht umwandeln, weil sie Policys für Sicherheit auf Zeilenebene hat" #: rewrite/rewriteDefine.c:492 #, c-format @@ -15393,22 +15394,22 @@ msgstr "für eine Relation mit gelöschten Spalten kann keine RETURNING-Liste er #: rewrite/rewriteDefine.c:702 #, c-format msgid "SELECT rule's target entry %d has different column name from column \"%s\"" -msgstr "Spaltenname in Targeteintrag %d von SELECT-Regel unterscheidet sich von Spalte „%s“" +msgstr "Spaltenname in Targeteintrag %d von SELECT-Regel unterscheidet sich von Spalte »%s«" #: rewrite/rewriteDefine.c:704 #, c-format msgid "SELECT target entry is named \"%s\"." -msgstr "SELECT-Targeteintrag heißt „%s“." +msgstr "SELECT-Targeteintrag heißt »%s«." #: rewrite/rewriteDefine.c:713 #, c-format msgid "SELECT rule's target entry %d has different type from column \"%s\"" -msgstr "Typ von Targeteintrag %d von SELECT-Regel unterscheidet sich von Spalte „%s“" +msgstr "Typ von Targeteintrag %d von SELECT-Regel unterscheidet sich von Spalte »%s«" #: rewrite/rewriteDefine.c:715 #, c-format msgid "RETURNING list's entry %d has different type from column \"%s\"" -msgstr "Eintrag %d in RETURNING-Liste hat anderen Typ als Spalte „%s“" +msgstr "Eintrag %d in RETURNING-Liste hat anderen Typ als Spalte »%s«" #: rewrite/rewriteDefine.c:718 rewrite/rewriteDefine.c:742 #, c-format @@ -15423,12 +15424,12 @@ msgstr "Eintrag in RETURNING-Liste hat Typ %s, aber Spalte hat Typ %s." #: rewrite/rewriteDefine.c:737 #, c-format msgid "SELECT rule's target entry %d has different size from column \"%s\"" -msgstr "Größe von Targeteintrag %d von SELECT-Regel unterscheidet sich von Spalte „%s“" +msgstr "Größe von Targeteintrag %d von SELECT-Regel unterscheidet sich von Spalte »%s«" #: rewrite/rewriteDefine.c:739 #, c-format msgid "RETURNING list's entry %d has different size from column \"%s\"" -msgstr "Eintrag %d in RETURNING-Liste hat andere Größe als Spalte „%s“" +msgstr "Eintrag %d in RETURNING-Liste hat andere Größe als Spalte »%s«" #: rewrite/rewriteDefine.c:756 #, c-format @@ -15444,7 +15445,7 @@ msgstr "RETURNING-Liste hat zu wenige Einträge" #: rewrite/rewriteSupport.c:112 #, c-format msgid "rule \"%s\" for relation \"%s\" does not exist" -msgstr "Regel „%s“ für Relation „%s“ existiert nicht" +msgstr "Regel »%s« für Relation »%s« existiert nicht" #: rewrite/rewriteDefine.c:983 #, c-format @@ -15454,7 +15455,7 @@ msgstr "Umbenennen einer ON-SELECT-Regel ist nicht erlaubt" #: rewrite/rewriteHandler.c:521 #, 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" +msgstr "WITH-Anfragename »%s« erscheint sowohl in der Regelaktion als auch in der umzuschreibenden Anfrage" #: rewrite/rewriteHandler.c:581 #, c-format @@ -15464,17 +15465,17 @@ msgstr "RETURNING-Listen können nicht in mehreren Regeln auftreten" #: rewrite/rewriteHandler.c:921 rewrite/rewriteHandler.c:939 #, c-format msgid "multiple assignments to same column \"%s\"" -msgstr "mehrere Zuweisungen zur selben Spalte „%s“" +msgstr "mehrere Zuweisungen zur selben Spalte »%s«" #: rewrite/rewriteHandler.c:1714 rewrite/rewriteHandler.c:3324 #, c-format msgid "infinite recursion detected in rules for relation \"%s\"" -msgstr "unendliche Rekursion entdeckt in Regeln für Relation „%s“" +msgstr "unendliche Rekursion entdeckt in Regeln für Relation »%s«" #: rewrite/rewriteHandler.c:1799 #, c-format msgid "infinite recursion detected in policy for relation \"%s\"" -msgstr "unendliche Rekursion entdeckt in Policys für Relation „%s“" +msgstr "unendliche Rekursion entdeckt in Policys für Relation »%s«" #: rewrite/rewriteHandler.c:2116 msgid "Junk view columns are not updatable." @@ -15544,12 +15545,12 @@ msgstr "Sichten, die keine aktualisierbaren Spalten haben, sind nicht automatisc #: rewrite/rewriteHandler.c:2717 #, c-format msgid "cannot insert into column \"%s\" of view \"%s\"" -msgstr "kann nicht in Spalte „%s“ von Sicht „%s“ einfügen" +msgstr "kann nicht in Spalte »%s« von Sicht »%s« einfügen" #: rewrite/rewriteHandler.c:2725 #, c-format msgid "cannot update column \"%s\" of view \"%s\"" -msgstr "kann Spalte „%s“ von Sicht „%s“ nicht aktualisieren" +msgstr "kann Spalte »%s« von Sicht »%s« nicht aktualisieren" #: rewrite/rewriteHandler.c:3123 #, c-format @@ -15574,7 +15575,7 @@ msgstr "DO INSTEAD-Regeln mit mehreren Anweisungen werden für datenmodifizieren #: rewrite/rewriteHandler.c:3361 #, c-format msgid "cannot perform INSERT RETURNING on relation \"%s\"" -msgstr "INSERT RETURNING kann in Relation „%s“ nicht ausgeführt werden" +msgstr "INSERT RETURNING kann in Relation »%s« nicht ausgeführt werden" #: rewrite/rewriteHandler.c:3363 #, c-format @@ -15584,7 +15585,7 @@ msgstr "Sie benötigen eine ON INSERT DO INSTEAD Regel ohne Bedingung, mit RETUR #: rewrite/rewriteHandler.c:3368 #, c-format msgid "cannot perform UPDATE RETURNING on relation \"%s\"" -msgstr "UPDATE RETURNING kann in Relation „%s“ nicht ausgeführt werden" +msgstr "UPDATE RETURNING kann in Relation »%s« nicht ausgeführt werden" #: rewrite/rewriteHandler.c:3370 #, c-format @@ -15594,7 +15595,7 @@ msgstr "Sie benötigen eine ON UPDATE DO INSTEAD Regel ohne Bedingung, mit RETUR #: rewrite/rewriteHandler.c:3375 #, c-format msgid "cannot perform DELETE RETURNING on relation \"%s\"" -msgstr "DELETE RETURNING kann in Relation „%s“ nicht ausgeführt werden" +msgstr "DELETE RETURNING kann in Relation »%s« nicht ausgeführt werden" #: rewrite/rewriteHandler.c:3377 #, c-format @@ -15629,12 +15630,12 @@ msgstr "NEW-Variablen in ON UPDATE-Regeln können nicht auf Spalten verweisen, d #: rewrite/rewriteSupport.c:154 #, c-format msgid "rule \"%s\" does not exist" -msgstr "Regel „%s“ existiert nicht" +msgstr "Regel »%s« existiert nicht" #: rewrite/rewriteSupport.c:167 #, c-format msgid "there are multiple rules named \"%s\"" -msgstr "es gibt mehrere Regeln namens „%s“" +msgstr "es gibt mehrere Regeln namens »%s«" #: rewrite/rewriteSupport.c:168 #, c-format @@ -15718,7 +15719,7 @@ msgstr "%s am Ende der Eingabe" #: scan.l:1080 #, c-format msgid "%s at or near \"%s\"" -msgstr "%s bei „%s“" +msgstr "%s bei »%s«" #: scan.l:1245 scan.l:1277 msgid "Unicode escape values cannot be used for code point values above 007F when the server encoding is not UTF8" @@ -15761,28 +15762,28 @@ msgstr "Verwenden Sie die Syntax für Escape-Zeichenketten, z.B. E'\\r\\n'." #: snowball/dict_snowball.c:177 #, c-format msgid "no Snowball stemmer available for language \"%s\" and encoding \"%s\"" -msgstr "kein Snowball-Stemmer für Sprache „%s“ und Kodierung „%s“ verfügbar" +msgstr "kein Snowball-Stemmer für Sprache »%s« und Kodierung »%s« verfügbar" #: snowball/dict_snowball.c:200 tsearch/dict_ispell.c:73 #: tsearch/dict_simple.c:48 #, c-format msgid "multiple StopWords parameters" -msgstr "mehrere „StopWords“-Parameter" +msgstr "mehrere »StopWords«-Parameter" #: snowball/dict_snowball.c:209 #, c-format msgid "multiple Language parameters" -msgstr "mehrere „Language“-Parameter" +msgstr "mehrere »Language«-Parameter" #: snowball/dict_snowball.c:216 #, c-format msgid "unrecognized Snowball parameter: \"%s\"" -msgstr "unbekannter Snowball-Parameter: „%s“" +msgstr "unbekannter Snowball-Parameter: »%s«" #: snowball/dict_snowball.c:224 #, c-format msgid "missing Language parameter" -msgstr "Parameter „Language“ fehlt" +msgstr "Parameter »Language« fehlt" #: storage/buffer/bufmgr.c:442 storage/buffer/bufmgr.c:555 #, c-format @@ -15827,7 +15828,7 @@ msgstr "kein leerer lokaler Puffer verfügbar" #: storage/file/fd.c:541 #, c-format msgid "could not link file \"%s\" to \"%s\": %m" -msgstr "konnte Datei „%s“ nicht nach „%s“ linken: %m" +msgstr "konnte Datei »%s« nicht nach »%s« linken: %m" #: storage/file/fd.c:635 #, c-format @@ -15853,7 +15854,7 @@ msgstr "keine Dateideskriptoren mehr: %m; freigeben und nochmal versuchen" #: storage/file/fd.c:1341 #, c-format msgid "temporary file: path \"%s\", size %lu" -msgstr "temporäre Datei: Pfad „%s“, Größe %lu" +msgstr "temporäre Datei: Pfad »%s«, Größe %lu" #: storage/file/fd.c:1490 #, c-format @@ -15863,22 +15864,22 @@ msgstr "Größe der temporären Datei überschreitet temp_file_limit (%dkB)" #: storage/file/fd.c:1777 storage/file/fd.c:1827 #, c-format msgid "exceeded maxAllocatedDescs (%d) while trying to open file \"%s\"" -msgstr "maxAllocatedDescs (%d) überschritten beim Versuch, die Datei „%s“ zu öffnen" +msgstr "maxAllocatedDescs (%d) überschritten beim Versuch, die Datei »%s« zu öffnen" #: storage/file/fd.c:1867 #, c-format msgid "exceeded maxAllocatedDescs (%d) while trying to execute command \"%s\"" -msgstr "maxAllocatedDescs (%d) überschritten beim Versuch, den Befehl „%s“ auszuführen" +msgstr "maxAllocatedDescs (%d) überschritten beim Versuch, den Befehl »%s« auszuführen" #: storage/file/fd.c:2018 #, c-format msgid "exceeded maxAllocatedDescs (%d) while trying to open directory \"%s\"" -msgstr "maxAllocatedDescs (%d) überschritten beim Versuch, das Verzeichnis „%s“ zu öffnen" +msgstr "maxAllocatedDescs (%d) überschritten beim Versuch, das Verzeichnis »%s« zu öffnen" #: storage/file/fd.c:2104 #, c-format msgid "could not read directory \"%s\": %m" -msgstr "konnte Verzeichnis „%s“ nicht lesen: %m" +msgstr "konnte Verzeichnis »%s« nicht lesen: %m" #: storage/ipc/dsm.c:363 #, c-format @@ -15893,7 +15894,7 @@ msgstr "dynamisches Shared-Memory ist abgeschaltet" #: storage/ipc/dsm.c:411 #, c-format msgid "Set dynamic_shared_memory_type to a value other than \"none\"." -msgstr "Setzen Sie dynamic_shared_memory_type auf einen anderen Wert als „none“." +msgstr "Setzen Sie dynamic_shared_memory_type auf einen anderen Wert als »none«." #: storage/ipc/dsm.c:431 #, c-format @@ -15910,37 +15911,37 @@ msgstr "zu viele dynamische Shared-Memory-Segmente" #: storage/ipc/dsm_impl.c:811 storage/ipc/dsm_impl.c:953 #, c-format msgid "could not unmap shared memory segment \"%s\": %m" -msgstr "konnte Shared-Memory-Segment „%s“ nicht unmappen: %m" +msgstr "konnte Shared-Memory-Segment »%s« nicht unmappen: %m" #: storage/ipc/dsm_impl.c:271 storage/ipc/dsm_impl.c:543 #: storage/ipc/dsm_impl.c:658 storage/ipc/dsm_impl.c:821 #, c-format msgid "could not remove shared memory segment \"%s\": %m" -msgstr "konnte Shared-Memory-Segment „%s“ nicht entfernen: %m" +msgstr "konnte Shared-Memory-Segment »%s« nicht entfernen: %m" #: storage/ipc/dsm_impl.c:292 storage/ipc/dsm_impl.c:721 #: storage/ipc/dsm_impl.c:835 #, c-format msgid "could not open shared memory segment \"%s\": %m" -msgstr "konnte Shared-Memory-Segment „%s“ nicht öffnen: %m" +msgstr "konnte Shared-Memory-Segment »%s« nicht öffnen: %m" #: storage/ipc/dsm_impl.c:316 storage/ipc/dsm_impl.c:559 #: storage/ipc/dsm_impl.c:766 storage/ipc/dsm_impl.c:859 #, c-format msgid "could not stat shared memory segment \"%s\": %m" -msgstr "konnte „stat“ für Shared-Memory-Segment „%s“ nicht ausführen: %m" +msgstr "konnte »stat« für Shared-Memory-Segment »%s« nicht ausführen: %m" #: storage/ipc/dsm_impl.c:335 storage/ipc/dsm_impl.c:878 #: storage/ipc/dsm_impl.c:926 #, c-format msgid "could not resize shared memory segment \"%s\" to %zu bytes: %m" -msgstr "konnte Größe des Shared-Memory-Segments „%s“ nicht auf %zu Bytes ändern: %m" +msgstr "konnte Größe des Shared-Memory-Segments »%s« nicht auf %zu Bytes ändern: %m" #: storage/ipc/dsm_impl.c:385 storage/ipc/dsm_impl.c:580 #: storage/ipc/dsm_impl.c:742 storage/ipc/dsm_impl.c:977 #, c-format msgid "could not map shared memory segment \"%s\": %m" -msgstr "konnte Shared-Memory-Segment „%s“ nicht mappen: %m" +msgstr "konnte Shared-Memory-Segment »%s« nicht mappen: %m" #: storage/ipc/dsm_impl.c:515 #, c-format @@ -15950,12 +15951,12 @@ msgstr "konnte Shared-Memory-Segment nicht finden: %m" #: storage/ipc/dsm_impl.c:694 #, c-format msgid "could not create shared memory segment \"%s\": %m" -msgstr "konnte Shared-Memory-Segment „%s“ nicht erzeugen: %m" +msgstr "konnte Shared-Memory-Segment »%s« nicht erzeugen: %m" #: storage/ipc/dsm_impl.c:1018 #, c-format msgid "could not duplicate handle for \"%s\": %m" -msgstr "konnte Handle für „%s“ nicht duplizieren: %m" +msgstr "konnte Handle für »%s« nicht duplizieren: %m" #: storage/ipc/shm_toc.c:108 storage/ipc/shm_toc.c:189 storage/ipc/shmem.c:205 #: storage/lmgr/lock.c:867 storage/lmgr/lock.c:901 storage/lmgr/lock.c:2598 @@ -15970,24 +15971,24 @@ msgstr "Shared Memory aufgebraucht" #: storage/ipc/shmem.c:361 storage/ipc/shmem.c:412 #, c-format msgid "not enough shared memory for data structure \"%s\" (%zu bytes requested)" -msgstr "nicht genug Shared-Memory für Datenstruktur „%s“ (%zu Bytes angefordert)" +msgstr "nicht genug Shared-Memory für Datenstruktur »%s« (%zu Bytes angefordert)" #: storage/ipc/shmem.c:380 #, c-format msgid "could not create ShmemIndex entry for data structure \"%s\"" -msgstr "konnte ShmemIndex-Eintrag für Datenstruktur „%s“ nicht erzeugen" +msgstr "konnte ShmemIndex-Eintrag für Datenstruktur »%s« nicht erzeugen" #: storage/ipc/shmem.c:395 #, c-format msgid "ShmemIndex entry size is wrong for data structure \"%s\": expected %zu, actual %zu" -msgstr "ShmemIndex-Eintraggröße ist falsch für Datenstruktur „%s“: erwartet %zu, tatsächlich %zu" +msgstr "ShmemIndex-Eintraggröße ist falsch für Datenstruktur »%s«: erwartet %zu, tatsächlich %zu" #: storage/ipc/shmem.c:440 storage/ipc/shmem.c:459 #, c-format msgid "requested shared memory size overflows size_t" msgstr "angeforderte Shared-Memory-Größe übersteigt Kapazität von size_t" -#: storage/ipc/standby.c:500 tcop/postgres.c:2974 +#: storage/ipc/standby.c:500 tcop/postgres.c:2989 #, c-format msgid "canceling statement due to conflict with recovery" msgstr "storniere Anfrage wegen Konflikt mit der Wiederherstellung" @@ -16010,7 +16011,7 @@ msgstr "ungültige Flags zum Öffnen eines Large Objects: %d" #: storage/large_object/inv_api.c:436 #, c-format msgid "invalid whence setting: %d" -msgstr "ungültige „whence“-Angabe: %d" +msgstr "ungültige »whence«-Angabe: %d" #: storage/large_object/inv_api.c:593 #, c-format @@ -16040,42 +16041,42 @@ msgstr "Einzelheiten zur Anfrage finden Sie im Serverlog." #: storage/lmgr/lmgr.c:684 #, c-format msgid "while updating tuple (%u,%u) in relation \"%s\"" -msgstr "beim Aktualisieren von Tupel (%u,%u) in Relation „%s“" +msgstr "beim Aktualisieren von Tupel (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:687 #, c-format msgid "while deleting tuple (%u,%u) in relation \"%s\"" -msgstr "beim Löschen von Tupel (%u,%u) in Relation „%s“" +msgstr "beim Löschen von Tupel (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:690 #, c-format msgid "while locking tuple (%u,%u) in relation \"%s\"" -msgstr "beim Sperren von Tupel (%u,%u) in Relation „%s“" +msgstr "beim Sperren von Tupel (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:693 #, c-format msgid "while locking updated version (%u,%u) of tuple in relation \"%s\"" -msgstr "beim Sperren von aktualisierter Version (%u,%u) von Tupel in Relation „%s“" +msgstr "beim Sperren von aktualisierter Version (%u,%u) von Tupel in Relation »%s«" #: storage/lmgr/lmgr.c:696 #, c-format msgid "while inserting index tuple (%u,%u) in relation \"%s\"" -msgstr "beim Einfügen von Indextupel (%u,%u) in Relation „%s“" +msgstr "beim Einfügen von Indextupel (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:699 #, c-format msgid "while checking uniqueness of tuple (%u,%u) in relation \"%s\"" -msgstr "beim Prüfen der Eindeutigkeit von Tupel (%u,%u) in Relation „%s“" +msgstr "beim Prüfen der Eindeutigkeit von Tupel (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:702 #, c-format msgid "while rechecking updated tuple (%u,%u) in relation \"%s\"" -msgstr "beim erneuten Prüfen des aktualisierten Tupels (%u,%u) in Relation „%s“" +msgstr "beim erneuten Prüfen des aktualisierten Tupels (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:705 #, c-format msgid "while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"" -msgstr "beim Prüfen eines Exclusion-Constraints für Tupel (%u,%u) in Relation „%s“" +msgstr "beim Prüfen eines Exclusion-Constraints für Tupel (%u,%u) in Relation »%s«" #: storage/lmgr/lmgr.c:925 #, c-format @@ -16181,7 +16182,7 @@ msgstr "Möglicherweise gibt es eine stillliegende Transaktion oder eine vergess #: storage/lmgr/predicate.c:1189 storage/lmgr/predicate.c:1260 #, c-format msgid "not enough shared memory for elements of data structure \"%s\" (%zu bytes requested)" -msgstr "nicht genug Shared-Memory für Elemente der Datenstruktur „%s“ (%zu Bytes angefordert)" +msgstr "nicht genug Shared-Memory für Elemente der Datenstruktur »%s« (%zu Bytes angefordert)" #: storage/lmgr/predicate.c:1548 #, c-format @@ -16191,12 +16192,12 @@ msgstr "aufschiebbarer Snapshot war unsicher; versuche einen neuen" #: storage/lmgr/predicate.c:1587 #, c-format msgid "\"default_transaction_isolation\" is set to \"serializable\"." -msgstr "„default_transaction_isolation“ ist auf „serializable“ gesetzt." +msgstr "»default_transaction_isolation« ist auf »serializable« gesetzt." #: storage/lmgr/predicate.c:1588 #, c-format msgid "You can use \"SET default_transaction_isolation = 'repeatable read'\" to change the default." -msgstr "Mit „SET default_transaction_isolation = 'repeatable read'“ können Sie die Voreinstellung ändern." +msgstr "Mit »SET default_transaction_isolation = 'repeatable read'« können Sie die Voreinstellung ändern." #: storage/lmgr/predicate.c:1627 #, c-format @@ -16283,30 +16284,30 @@ msgstr "Prozess %d konnte %s-Sperre auf %s nach %ld,%03d ms nicht erlangen" msgid "page verification failed, calculated checksum %u but expected %u" msgstr "Seitenüberprüfung fehlgeschlagen, berechnete Prüfsumme %u, aber erwartet %u" -#: storage/page/bufpage.c:200 storage/page/bufpage.c:490 -#: storage/page/bufpage.c:705 storage/page/bufpage.c:836 -#: storage/page/bufpage.c:936 +#: storage/page/bufpage.c:203 storage/page/bufpage.c:522 +#: storage/page/bufpage.c:737 storage/page/bufpage.c:868 +#: storage/page/bufpage.c:968 #, c-format msgid "corrupted page pointers: lower = %u, upper = %u, special = %u" msgstr "verfälschte Seitenzeiger: lower = %u, upper = %u, special = %u" -#: storage/page/bufpage.c:534 +#: storage/page/bufpage.c:566 #, c-format msgid "corrupted item pointer: %u" msgstr "verfälschter Item-Zeiger: %u" -#: storage/page/bufpage.c:545 storage/page/bufpage.c:887 -#: storage/page/bufpage.c:1042 +#: storage/page/bufpage.c:577 storage/page/bufpage.c:919 +#: storage/page/bufpage.c:1074 #, c-format msgid "corrupted item lengths: total %u, available space %u" msgstr "verfälschte Item-Längen: gesamt %u, verfügbarer Platz %u" -#: storage/page/bufpage.c:724 storage/page/bufpage.c:860 +#: storage/page/bufpage.c:756 storage/page/bufpage.c:892 #, c-format msgid "corrupted item pointer: offset = %u, size = %u" msgstr "verfälschter Item-Zeiger: offset = %u, size = %u" -#: storage/page/bufpage.c:965 +#: storage/page/bufpage.c:997 #, c-format msgid "corrupted item pointer: offset = %u, length = %u" msgstr "verfälschter Item-Zeiger: offset = %u, length = %u" @@ -16314,23 +16315,23 @@ msgstr "verfälschter Item-Zeiger: offset = %u, length = %u" #: storage/smgr/md.c:442 storage/smgr/md.c:913 #, c-format msgid "could not truncate file \"%s\": %m" -msgstr "kann Datei „%s“ nicht kürzen: %m" +msgstr "kann Datei »%s« nicht kürzen: %m" #: storage/smgr/md.c:509 #, c-format msgid "cannot extend file \"%s\" beyond %u blocks" -msgstr "kann Datei „%s“ nicht auf über %u Blöcke erweitern" +msgstr "kann Datei »%s« nicht auf über %u Blöcke erweitern" # XXX #: storage/smgr/md.c:531 storage/smgr/md.c:692 storage/smgr/md.c:767 #, c-format msgid "could not seek to block %u in file \"%s\": %m" -msgstr "konnte Positionszeiger nicht auf Block %u in Datei „%s“ setzen: %m" +msgstr "konnte Positionszeiger nicht auf Block %u in Datei »%s« setzen: %m" #: storage/smgr/md.c:539 #, c-format msgid "could not extend file \"%s\": %m" -msgstr "konnte Datei „%s“ nicht erweitern: %m" +msgstr "konnte Datei »%s« nicht erweitern: %m" #: storage/smgr/md.c:541 storage/smgr/md.c:548 storage/smgr/md.c:794 #, c-format @@ -16340,42 +16341,42 @@ msgstr "Prüfen Sie den freien Festplattenplatz." #: storage/smgr/md.c:545 #, c-format msgid "could not extend file \"%s\": wrote only %d of %d bytes at block %u" -msgstr "konnte Datei „%s“ nicht erweitern: es wurden nur %d von %d Bytes bei Block %u geschrieben" +msgstr "konnte Datei »%s« nicht erweitern: es wurden nur %d von %d Bytes bei Block %u geschrieben" #: storage/smgr/md.c:710 #, c-format msgid "could not read block %u in file \"%s\": %m" -msgstr "konnte Block %u in Datei „%s“ nicht lesen: %m" +msgstr "konnte Block %u in Datei »%s« nicht lesen: %m" #: storage/smgr/md.c:726 #, c-format msgid "could not read block %u in file \"%s\": read only %d of %d bytes" -msgstr "konnte Block %u in Datei „%s“ nicht lesen: es wurden nur %d von %d Bytes gelesen" +msgstr "konnte Block %u in Datei »%s« nicht lesen: es wurden nur %d von %d Bytes gelesen" #: storage/smgr/md.c:785 #, c-format msgid "could not write block %u in file \"%s\": %m" -msgstr "konnte Block %u in Datei „%s“ nicht schreiben: %m" +msgstr "konnte Block %u in Datei »%s« nicht schreiben: %m" #: storage/smgr/md.c:790 #, c-format msgid "could not write block %u in file \"%s\": wrote only %d of %d bytes" -msgstr "konnte Block %u in Datei „%s“ nicht schreiben: es wurden nur %d von %d Bytes geschrieben" +msgstr "konnte Block %u in Datei »%s« nicht schreiben: es wurden nur %d von %d Bytes geschrieben" #: storage/smgr/md.c:889 #, c-format msgid "could not truncate file \"%s\" to %u blocks: it's only %u blocks now" -msgstr "konnte Datei „%s“ nicht auf %u Blöcke kürzen: es sind jetzt nur %u Blöcke" +msgstr "konnte Datei »%s« nicht auf %u Blöcke kürzen: es sind jetzt nur %u Blöcke" #: storage/smgr/md.c:938 #, c-format msgid "could not truncate file \"%s\" to %u blocks: %m" -msgstr "konnte Datei „%s“ nicht auf %u Blöcke kürzen: %m" +msgstr "konnte Datei »%s« nicht auf %u Blöcke kürzen: %m" #: storage/smgr/md.c:1218 #, c-format msgid "could not fsync file \"%s\" but retrying: %m" -msgstr "konnte Datei „%s“ nicht fsyncen, versuche erneut: %m" +msgstr "konnte Datei »%s« nicht fsyncen, versuche erneut: %m" #: storage/smgr/md.c:1381 #, c-format @@ -16385,7 +16386,7 @@ msgstr "konnte fsync-Anfrage nicht weiterleiten, weil Anfrageschlange voll ist" #: storage/smgr/md.c:1776 #, c-format msgid "could not open file \"%s\" (target block %u): %m" -msgstr "konnte Datei „%s“ nicht öffnen (Zielblock %u): %m" +msgstr "konnte Datei »%s« nicht öffnen (Zielblock %u): %m" #: tcop/fastpath.c:111 tcop/fastpath.c:475 tcop/fastpath.c:605 #, c-format @@ -16402,7 +16403,7 @@ msgstr "aktuelle Transaktion wurde abgebrochen, Befehle werden bis zum Ende der #: tcop/fastpath.c:319 #, c-format msgid "fastpath function call: \"%s\" (OID %u)" -msgstr "Fastpath-Funktionsaufruf: „%s“ (OID %u)" +msgstr "Fastpath-Funktionsaufruf: »%s« (OID %u)" #: tcop/fastpath.c:401 tcop/postgres.c:1173 tcop/postgres.c:1438 #: tcop/postgres.c:1816 tcop/postgres.c:2033 @@ -16413,7 +16414,7 @@ msgstr "Dauer: %s ms" #: tcop/fastpath.c:405 #, c-format msgid "duration: %s ms fastpath function call: \"%s\" (OID %u)" -msgstr "Dauer: %s ms Fastpath-Funktionsaufruf: „%s“ (OID %u)" +msgstr "Dauer: %s ms Fastpath-Funktionsaufruf: »%s« (OID %u)" #: tcop/fastpath.c:443 tcop/fastpath.c:570 #, c-format @@ -16436,7 +16437,7 @@ msgid "unexpected EOF on client connection" msgstr "unerwartetes EOF auf Client-Verbindung" #: tcop/postgres.c:449 tcop/postgres.c:461 tcop/postgres.c:472 -#: tcop/postgres.c:484 tcop/postgres.c:4268 +#: tcop/postgres.c:484 tcop/postgres.c:4283 #, c-format msgid "invalid frontend message type %d" msgstr "ungültiger Frontend-Message-Typ %d" @@ -16484,7 +16485,7 @@ msgstr "Binden-Nachricht hat %d Parameterformate aber %d Parameter" #: tcop/postgres.c:1555 #, 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" +msgstr "Binden-Nachricht enthält %d Parameter, aber vorbereitete Anweisung »%s« erfordert %d" #: tcop/postgres.c:1723 #, c-format @@ -16499,7 +16500,7 @@ msgstr "Dauer: %s ms Binden %s%s%s: %s" #: tcop/postgres.c:1869 tcop/postgres.c:2403 #, c-format msgid "portal \"%s\" does not exist" -msgstr "Portal „%s“ existiert nicht" +msgstr "Portal »%s« existiert nicht" #: tcop/postgres.c:1954 #, c-format @@ -16609,87 +16610,87 @@ msgstr "breche Verbindung ab aufgrund von Anweisung des Administrators" msgid "connection to client lost" msgstr "Verbindung zum Client wurde verloren" -#: tcop/postgres.c:2951 +#: tcop/postgres.c:2966 #, c-format msgid "canceling statement due to lock timeout" msgstr "storniere Anfrage wegen Zeitüberschreitung einer Sperre" -#: tcop/postgres.c:2958 +#: tcop/postgres.c:2973 #, c-format msgid "canceling statement due to statement timeout" msgstr "storniere Anfrage wegen Zeitüberschreitung der Anfrage" -#: tcop/postgres.c:2965 +#: tcop/postgres.c:2980 #, c-format msgid "canceling autovacuum task" msgstr "storniere Autovacuum-Aufgabe" -#: tcop/postgres.c:2988 +#: tcop/postgres.c:3003 #, c-format msgid "canceling statement due to user request" msgstr "storniere Anfrage wegen Benutzeraufforderung" -#: tcop/postgres.c:3098 +#: tcop/postgres.c:3113 #, c-format msgid "stack depth limit exceeded" msgstr "Grenze für Stacktiefe überschritten" -#: tcop/postgres.c:3099 +#: tcop/postgres.c:3114 #, c-format msgid "Increase the configuration parameter \"max_stack_depth\" (currently %dkB), after ensuring the platform's stack depth limit is adequate." -msgstr "Erhöhen Sie den Konfigurationsparameter „max_stack_depth“ (aktuell %dkB), nachdem Sie sichergestellt haben, dass die Stacktiefenbegrenzung Ihrer Plattform ausreichend ist." +msgstr "Erhöhen Sie den Konfigurationsparameter »max_stack_depth« (aktuell %dkB), nachdem Sie sichergestellt haben, dass die Stacktiefenbegrenzung Ihrer Plattform ausreichend ist." -#: tcop/postgres.c:3162 +#: tcop/postgres.c:3177 #, c-format msgid "\"max_stack_depth\" must not exceed %ldkB." -msgstr "„max_stack_depth“ darf %ldkB nicht überschreiten." +msgstr "»max_stack_depth« darf %ldkB nicht überschreiten." -#: tcop/postgres.c:3164 +#: tcop/postgres.c:3179 #, c-format msgid "Increase the platform's stack depth limit via \"ulimit -s\" or local equivalent." -msgstr "Erhöhen Sie die Stacktiefenbegrenzung Ihrer Plattform mit „ulimit -s“ oder der lokalen Entsprechung." +msgstr "Erhöhen Sie die Stacktiefenbegrenzung Ihrer Plattform mit »ulimit -s« oder der lokalen Entsprechung." -#: tcop/postgres.c:3524 +#: tcop/postgres.c:3539 #, c-format msgid "invalid command-line argument for server process: %s" msgstr "ungültiges Kommandozeilenargument für Serverprozess: %s" -#: tcop/postgres.c:3525 tcop/postgres.c:3531 +#: tcop/postgres.c:3540 tcop/postgres.c:3546 #, c-format msgid "Try \"%s --help\" for more information." -msgstr "Versuchen Sie „%s --help“ für weitere Informationen." +msgstr "Versuchen Sie »%s --help« für weitere Informationen." -#: tcop/postgres.c:3529 +#: tcop/postgres.c:3544 #, c-format msgid "%s: invalid command-line argument: %s" msgstr "%s: ungültiges Kommandozeilenargument: %s" -#: tcop/postgres.c:3590 +#: tcop/postgres.c:3605 #, c-format msgid "%s: no database nor user name specified" msgstr "%s: weder Datenbankname noch Benutzername angegeben" -#: tcop/postgres.c:4176 +#: tcop/postgres.c:4191 #, c-format msgid "invalid CLOSE message subtype %d" msgstr "ungültiger Subtyp %d von CLOSE-Message" -#: tcop/postgres.c:4211 +#: tcop/postgres.c:4226 #, c-format msgid "invalid DESCRIBE message subtype %d" msgstr "ungültiger Subtyp %d von DESCRIBE-Message" -#: tcop/postgres.c:4289 +#: tcop/postgres.c:4304 #, 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:4293 +#: tcop/postgres.c:4308 #, 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:4463 +#: tcop/postgres.c:4478 #, 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" @@ -16751,47 +16752,47 @@ msgstr "mehrere AffFile-Parameter" #: tsearch/dict_ispell.c:81 #, c-format msgid "unrecognized Ispell parameter: \"%s\"" -msgstr "unbekannter Ispell-Parameter: „%s“" +msgstr "unbekannter Ispell-Parameter: »%s«" #: tsearch/dict_ispell.c:95 #, c-format msgid "missing AffFile parameter" -msgstr "Parameter „AffFile“ fehlt" +msgstr "Parameter »AffFile« fehlt" #: tsearch/dict_ispell.c:101 tsearch/dict_thesaurus.c:647 #, c-format msgid "missing DictFile parameter" -msgstr "Parameter „DictFile“ fehlt" +msgstr "Parameter »DictFile« fehlt" #: tsearch/dict_simple.c:57 #, c-format msgid "multiple Accept parameters" -msgstr "mehrere „Accept“-Parameter" +msgstr "mehrere »Accept«-Parameter" #: tsearch/dict_simple.c:65 #, c-format msgid "unrecognized simple dictionary parameter: \"%s\"" -msgstr "unbekannter Parameter für das einfache Wörterbuch: „%s“" +msgstr "unbekannter Parameter für das einfache Wörterbuch: »%s«" #: tsearch/dict_synonym.c:117 #, c-format msgid "unrecognized synonym parameter: \"%s\"" -msgstr "unbekannter Synonymparameter: „%s“" +msgstr "unbekannter Synonymparameter: »%s«" #: tsearch/dict_synonym.c:124 #, c-format msgid "missing Synonyms parameter" -msgstr "Parameter „Synonyms“ fehlt" +msgstr "Parameter »Synonyms« fehlt" #: tsearch/dict_synonym.c:131 #, c-format msgid "could not open synonym file \"%s\": %m" -msgstr "konnte Synonymdatei „%s“ nicht öffnen: %m" +msgstr "konnte Synonymdatei »%s« nicht öffnen: %m" #: tsearch/dict_thesaurus.c:178 #, c-format msgid "could not open thesaurus file \"%s\": %m" -msgstr "konnte Thesaurusdatei „%s“ nicht öffnen: %m" +msgstr "konnte Thesaurusdatei »%s« nicht öffnen: %m" #: tsearch/dict_thesaurus.c:211 #, c-format @@ -16816,27 +16817,27 @@ msgstr "zu viele Lexeme in Thesauruseintrag" #: tsearch/dict_thesaurus.c:420 #, c-format msgid "thesaurus sample word \"%s\" isn't recognized by subdictionary (rule %d)" -msgstr "Thesaurus-Beispielwort „%s“ wird nicht vom Unterwörterbuch erkannt (Regel %d)" +msgstr "Thesaurus-Beispielwort »%s« wird nicht vom Unterwörterbuch erkannt (Regel %d)" #: tsearch/dict_thesaurus.c:426 #, c-format msgid "thesaurus sample word \"%s\" is a stop word (rule %d)" -msgstr "Thesaurus-Beispielwort „%s“ ist ein Stoppwort (Regel %d)" +msgstr "Thesaurus-Beispielwort »%s« ist ein Stoppwort (Regel %d)" #: tsearch/dict_thesaurus.c:429 #, c-format msgid "Use \"?\" to represent a stop word within a sample phrase." -msgstr "Verwenden Sie „?“, um ein Stoppwort in einem Beispielsatz darzustellen." +msgstr "Verwenden Sie »?«, um ein Stoppwort in einem Beispielsatz darzustellen." #: tsearch/dict_thesaurus.c:575 #, c-format msgid "thesaurus substitute word \"%s\" is a stop word (rule %d)" -msgstr "Thesaurus-Ersatzwort „%s“ ist ein Stoppwort (Regel %d)" +msgstr "Thesaurus-Ersatzwort »%s« ist ein Stoppwort (Regel %d)" #: tsearch/dict_thesaurus.c:582 #, c-format msgid "thesaurus substitute word \"%s\" isn't recognized by subdictionary (rule %d)" -msgstr "Thesaurus-Ersatzwort „%s“ wird nicht vom Unterwörterbuch erkannt (Regel %d)" +msgstr "Thesaurus-Ersatzwort »%s« wird nicht vom Unterwörterbuch erkannt (Regel %d)" #: tsearch/dict_thesaurus.c:594 #, c-format @@ -16846,22 +16847,22 @@ msgstr "Thesaurus-Ersatzausdruck ist leer (Regel %d)" #: tsearch/dict_thesaurus.c:632 #, c-format msgid "multiple Dictionary parameters" -msgstr "mehrere „Dictionary“-Parameter" +msgstr "mehrere »Dictionary«-Parameter" #: tsearch/dict_thesaurus.c:639 #, c-format msgid "unrecognized Thesaurus parameter: \"%s\"" -msgstr "unbekannter Thesaurus-Parameter: „%s“" +msgstr "unbekannter Thesaurus-Parameter: »%s«" #: tsearch/dict_thesaurus.c:651 #, c-format msgid "missing Dictionary parameter" -msgstr "Parameter „Dictionary“ fehlt" +msgstr "Parameter »Dictionary« fehlt" #: tsearch/spell.c:289 #, c-format msgid "could not open dictionary file \"%s\": %m" -msgstr "konnte Wörterbuchdatei „%s“ nicht öffnen: %m" +msgstr "konnte Wörterbuchdatei »%s« nicht öffnen: %m" #: tsearch/spell.c:452 utils/adt/regexp.c:204 #, c-format @@ -16876,12 +16877,12 @@ msgstr "Mehrbytemarkierungszeichen ist nicht erlaubt" #: tsearch/spell.c:779 tsearch/spell.c:835 tsearch/spell.c:937 #, c-format msgid "could not open affix file \"%s\": %m" -msgstr "konnte Affixdatei „%s“ nicht öffnen: %m" +msgstr "konnte Affixdatei »%s« nicht öffnen: %m" #: tsearch/spell.c:825 #, c-format msgid "Ispell dictionary supports only default flag value" -msgstr "Ispell-Wörterbuch unterstützt nur den Default-Flag-Wert" +msgstr "Ispell-Wörterbuch unterstützt nur den Flag-Wert »default«" #: tsearch/spell.c:1050 #, c-format @@ -16896,7 +16897,7 @@ msgstr "Zeichenkette ist zu lang für tsvector (%d Bytes, maximal %d Bytes)" #: tsearch/ts_locale.c:177 #, c-format msgid "line %d of configuration file \"%s\": \"%s\"" -msgstr "Zeile %d in Konfigurationsdatei „%s“: „%s“" +msgstr "Zeile %d in Konfigurationsdatei »%s«: »%s«" #: tsearch/ts_locale.c:299 #, c-format @@ -16918,12 +16919,12 @@ msgstr "Wörter, die länger als %d Zeichen sind, werden ignoriert." #: tsearch/ts_utils.c:51 #, c-format msgid "invalid text search configuration file name \"%s\"" -msgstr "ungültiger Textsuchekonfigurationsdateiname „%s“" +msgstr "ungültiger Textsuchekonfigurationsdateiname »%s«" #: tsearch/ts_utils.c:83 #, c-format msgid "could not open stop-word file \"%s\": %m" -msgstr "konnte Stoppwortdatei „%s“ nicht öffnen: %m" +msgstr "konnte Stoppwortdatei »%s« nicht öffnen: %m" #: tsearch/wparser.c:306 #, c-format @@ -16933,27 +16934,27 @@ msgstr "Textsucheparser unterstützt das Erzeugen von Headlines nicht" #: tsearch/wparser_def.c:2559 #, c-format msgid "unrecognized headline parameter: \"%s\"" -msgstr "unbekannter Headline-Parameter: „%s“" +msgstr "unbekannter Headline-Parameter: »%s«" #: tsearch/wparser_def.c:2568 #, c-format msgid "MinWords should be less than MaxWords" -msgstr "„MinWords“ sollte kleiner als „MaxWords“ sein" +msgstr "»MinWords« sollte kleiner als »MaxWords« sein" #: tsearch/wparser_def.c:2572 #, c-format msgid "MinWords should be positive" -msgstr "„MinWords“ sollte positiv sein" +msgstr "»MinWords« sollte positiv sein" #: tsearch/wparser_def.c:2576 #, c-format msgid "ShortWord should be >= 0" -msgstr "„ShortWord“ sollte >= 0 sein" +msgstr "»ShortWord« sollte >= 0 sein" #: tsearch/wparser_def.c:2580 #, c-format msgid "MaxFragments should be >= 0" -msgstr "„MaxFragments“ sollte >= 0 sein" +msgstr "»MaxFragments« sollte >= 0 sein" #: utils/adt/acl.c:169 utils/adt/name.c:91 #, c-format @@ -16968,12 +16969,12 @@ msgstr "Bezeichner muss weniger als %d Zeichen haben." #: utils/adt/acl.c:256 #, c-format msgid "unrecognized key word: \"%s\"" -msgstr "unbekanntes Schlüsselwort: „%s“" +msgstr "unbekanntes Schlüsselwort: »%s«" #: utils/adt/acl.c:257 #, c-format msgid "ACL key word must be \"group\" or \"user\"." -msgstr "ACL-Schlüsselwort muss „group“ oder „user“ sein." +msgstr "ACL-Schlüsselwort muss »group« oder »user« sein." #: utils/adt/acl.c:262 #, c-format @@ -16983,22 +16984,22 @@ msgstr "Name fehlt" #: utils/adt/acl.c:263 #, c-format msgid "A name must follow the \"group\" or \"user\" key word." -msgstr "Auf das Schlüsselwort „group“ oder „user“ muss ein Name folgen." +msgstr "Auf das Schlüsselwort »group« oder »user« muss ein Name folgen." #: utils/adt/acl.c:269 #, c-format msgid "missing \"=\" sign" -msgstr "„=“-Zeichen fehlt" +msgstr "»=«-Zeichen fehlt" #: utils/adt/acl.c:322 #, c-format msgid "invalid mode character: must be one of \"%s\"" -msgstr "ungültiges Moduszeichen: muss eines aus „%s“ sein" +msgstr "ungültiges Moduszeichen: muss eines aus »%s« sein" #: utils/adt/acl.c:344 #, c-format msgid "a name must follow the \"/\" sign" -msgstr "auf das „/“-Zeichen muss ein Name folgen" +msgstr "auf das »/«-Zeichen muss ein Name folgen" #: utils/adt/acl.c:352 #, c-format @@ -17053,18 +17054,18 @@ msgstr "aclremove wird nicht mehr unterstützt" #: utils/adt/acl.c:1632 utils/adt/acl.c:1686 #, c-format msgid "unrecognized privilege type: \"%s\"" -msgstr "unbekannter Privilegtyp: „%s“" +msgstr "unbekannter Privilegtyp: »%s«" #: utils/adt/acl.c:3426 utils/adt/regproc.c:123 utils/adt/regproc.c:144 #: utils/adt/regproc.c:319 #, c-format msgid "function \"%s\" does not exist" -msgstr "Funktion „%s“ existiert nicht" +msgstr "Funktion »%s« existiert nicht" #: utils/adt/acl.c:4880 #, c-format msgid "must be member of role \"%s\"" -msgstr "Berechtigung nur für Mitglied von Rolle „%s“" +msgstr "Berechtigung nur für Mitglied von Rolle »%s«" #: utils/adt/array_expanded.c:276 utils/adt/arrayfuncs.c:934 #: utils/adt/arrayfuncs.c:1522 utils/adt/arrayfuncs.c:3225 @@ -17089,8 +17090,8 @@ msgid "input data type is not an array" msgstr "Eingabedatentyp ist kein Array" #: utils/adt/array_userfuncs.c:120 utils/adt/array_userfuncs.c:174 -#: utils/adt/arrayfuncs.c:1325 utils/adt/float.c:1161 utils/adt/float.c:1220 -#: utils/adt/float.c:2771 utils/adt/float.c:2787 utils/adt/int.c:623 +#: utils/adt/arrayfuncs.c:1325 utils/adt/float.c:1158 utils/adt/float.c:1217 +#: utils/adt/float.c:2768 utils/adt/float.c:2784 utils/adt/int.c:623 #: utils/adt/int.c:652 utils/adt/int.c:673 utils/adt/int.c:704 #: utils/adt/int.c:737 utils/adt/int.c:759 utils/adt/int.c:907 #: utils/adt/int.c:928 utils/adt/int.c:955 utils/adt/int.c:995 @@ -17164,12 +17165,12 @@ msgstr "Startposition darf nicht NULL sein" #: utils/adt/arrayfuncs.c:842 utils/adt/arrayfuncs.c:895 #, c-format msgid "malformed array literal: \"%s\"" -msgstr "fehlerhafte Arraykonstante: „%s“" +msgstr "fehlerhafte Arraykonstante: »%s«" #: utils/adt/arrayfuncs.c:272 #, c-format msgid "\"[\" must introduce explicitly-specified array dimensions." -msgstr "Auf „[“ müssen explizit angegebene Array-Dimensionen folgen." +msgstr "Auf »[« müssen explizit angegebene Array-Dimensionen folgen." #: utils/adt/arrayfuncs.c:286 #, c-format @@ -17179,7 +17180,7 @@ msgstr "Dimensionswert fehlt." #: utils/adt/arrayfuncs.c:297 utils/adt/arrayfuncs.c:334 #, c-format msgid "Missing \"%s\" after array dimensions." -msgstr "„%s“ fehlt nach Arraydimensionen." +msgstr "»%s« fehlt nach Arraydimensionen." #: utils/adt/arrayfuncs.c:306 utils/adt/arrayfuncs.c:2848 #: utils/adt/arrayfuncs.c:2876 utils/adt/arrayfuncs.c:2891 @@ -17190,12 +17191,12 @@ msgstr "Obergrenze kann nicht kleiner als Untergrenze sein" #: utils/adt/arrayfuncs.c:319 #, c-format msgid "Array value must start with \"{\" or dimension information." -msgstr "Arraywert muss mit „{“ oder Dimensionsinformationen anfangen." +msgstr "Arraywert muss mit »{« oder Dimensionsinformationen anfangen." #: utils/adt/arrayfuncs.c:348 #, c-format msgid "Array contents must start with \"{\"." -msgstr "Array-Inhalt muss mit {“ anfangen." +msgstr "Array-Inhalt muss mit {« anfangen." #: utils/adt/arrayfuncs.c:354 utils/adt/arrayfuncs.c:361 #, c-format @@ -17213,7 +17214,7 @@ msgstr "Unerwartetes Ende der Eingabe." #: utils/adt/arrayfuncs.c:585 utils/adt/arrayfuncs.c:634 #, c-format msgid "Unexpected \"%c\" character." -msgstr "Unerwartetes Zeichen „%c“." +msgstr "Unerwartetes Zeichen »%c«." #: utils/adt/arrayfuncs.c:534 utils/adt/arrayfuncs.c:657 #, c-format @@ -17223,7 +17224,7 @@ msgstr "Unerwartetes Arrayelement." #: utils/adt/arrayfuncs.c:592 #, c-format msgid "Unmatched \"%c\" character." -msgstr "Zeichen „%c“ ohne Gegenstück." +msgstr "Zeichen »%c« ohne Gegenstück." #: utils/adt/arrayfuncs.c:600 #, c-format @@ -17373,12 +17374,12 @@ msgstr "Entfernen von Elementen aus mehrdimensionalen Arrays wird nicht unterst #: utils/adt/arrayfuncs.c:6291 #, c-format msgid "thresholds must be one-dimensional array" -msgstr "Parameter „thresholds“ muss ein eindimensionales Array sein" +msgstr "Parameter »thresholds« muss ein eindimensionales Array sein" #: utils/adt/arrayfuncs.c:6296 #, c-format msgid "thresholds array must not contain NULLs" -msgstr "„thresholds“-Array darf keine NULL-Werte enthalten" +msgstr "»thresholds«-Array darf keine NULL-Werte enthalten" #: utils/adt/arrayutils.c:209 #, c-format @@ -17403,17 +17404,17 @@ msgstr "Kodierungsumwandlung zwischen %s und ASCII wird nicht unterstützt" #: utils/adt/bool.c:153 #, c-format msgid "invalid input syntax for type boolean: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ boolean: „%s“" +msgstr "ungültige Eingabesyntax für Typ boolean: »%s«" #: utils/adt/cash.c:246 #, c-format msgid "invalid input syntax for type money: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ money: „%s“" +msgstr "ungültige Eingabesyntax für Typ money: »%s«" #: utils/adt/cash.c:607 utils/adt/cash.c:657 utils/adt/cash.c:708 #: utils/adt/cash.c:757 utils/adt/cash.c:809 utils/adt/cash.c:859 -#: utils/adt/float.c:788 utils/adt/float.c:852 utils/adt/float.c:2530 -#: utils/adt/float.c:2593 utils/adt/geo_ops.c:4155 utils/adt/int.c:719 +#: utils/adt/float.c:785 utils/adt/float.c:849 utils/adt/float.c:2527 +#: utils/adt/float.c:2590 utils/adt/geo_ops.c:4163 utils/adt/int.c:719 #: utils/adt/int.c:861 utils/adt/int.c:969 utils/adt/int.c:1058 #: utils/adt/int.c:1097 utils/adt/int.c:1125 utils/adt/int8.c:597 #: utils/adt/int8.c:657 utils/adt/int8.c:897 utils/adt/int8.c:1005 @@ -17447,12 +17448,12 @@ msgstr "Präzision von TIME(%d)%s auf erlaubten Höchstwert %d reduziert" #: utils/adt/date.c:141 utils/adt/datetime.c:1208 utils/adt/datetime.c:2079 #, c-format msgid "date/time value \"current\" is no longer supported" -msgstr "Datum/Zeitwert „current“ wird nicht mehr unterstützt" +msgstr "Datum/Zeitwert »current« wird nicht mehr unterstützt" -#: utils/adt/date.c:166 utils/adt/formatting.c:3527 +#: utils/adt/date.c:166 utils/adt/formatting.c:3521 #, c-format msgid "date out of range: \"%s\"" -msgstr "date ist außerhalb des gültigen Bereichs: „%s“" +msgstr "date ist außerhalb des gültigen Bereichs: »%s«" #: utils/adt/date.c:216 utils/adt/xml.c:2029 #, c-format @@ -17477,11 +17478,11 @@ msgstr "kann unendliche date-Werte nicht subtrahieren" #: utils/adt/date.c:474 utils/adt/date.c:511 #, c-format msgid "date out of range for timestamp" -msgstr "Datum ist außerhalb des gültigen Bereichs für Typ „timestamp“" +msgstr "Datum ist außerhalb des gültigen Bereichs für Typ »timestamp«" #: utils/adt/date.c:970 utils/adt/date.c:1016 utils/adt/date.c:1616 -#: utils/adt/date.c:1652 utils/adt/date.c:2524 utils/adt/formatting.c:3403 -#: utils/adt/formatting.c:3435 utils/adt/formatting.c:3503 +#: utils/adt/date.c:1652 utils/adt/date.c:2524 utils/adt/formatting.c:3397 +#: utils/adt/formatting.c:3429 utils/adt/formatting.c:3497 #: utils/adt/json.c:1534 utils/adt/json.c:1556 utils/adt/jsonb.c:823 #: utils/adt/jsonb.c:847 utils/adt/nabstime.c:455 utils/adt/nabstime.c:498 #: utils/adt/nabstime.c:528 utils/adt/nabstime.c:571 utils/adt/timestamp.c:224 @@ -17509,7 +17510,7 @@ msgstr "timestamp ist außerhalb des gültigen Bereichs" #: utils/adt/date.c:1042 #, c-format msgid "cannot convert reserved abstime value to date" -msgstr "kann reservierten „abstime“-Wert nicht in „date“ umwandeln" +msgstr "kann reservierten »abstime«-Wert nicht in »date« umwandeln" #: utils/adt/date.c:1196 utils/adt/date.c:1203 utils/adt/date.c:2014 #: utils/adt/date.c:2021 @@ -17525,7 +17526,7 @@ msgstr "Zeit-Feldwert ist außerhalb des gültigen Bereichs: %d:%02d:%02g" #: utils/adt/date.c:1892 utils/adt/date.c:1909 #, c-format msgid "\"time\" units \"%s\" not recognized" -msgstr "„time“-Einheit „%s“ nicht erkannt" +msgstr "»time«-Einheit »%s« nicht erkannt" #: utils/adt/date.c:2030 #, c-format @@ -17535,7 +17536,7 @@ msgstr "Zeitzonenunterschied ist außerhalb des gültigen Bereichs" #: utils/adt/date.c:2654 utils/adt/date.c:2671 #, c-format msgid "\"time with time zone\" units \"%s\" not recognized" -msgstr "„time with time zone“-Einheit „%s“ nicht erkannt" +msgstr "»time with time zone«-Einheit »%s« nicht erkannt" #: utils/adt/date.c:2744 utils/adt/datetime.c:925 utils/adt/datetime.c:1805 #: utils/adt/datetime.c:4566 utils/adt/timestamp.c:531 @@ -17543,58 +17544,58 @@ msgstr "„time with time zone“-Einheit „%s“ nicht erkannt" #: utils/adt/timestamp.c:5261 #, c-format msgid "time zone \"%s\" not recognized" -msgstr "Zeitzone „%s“ nicht erkannt" +msgstr "Zeitzone »%s« nicht erkannt" #: utils/adt/date.c:2784 utils/adt/timestamp.c:5102 utils/adt/timestamp.c:5287 #, c-format msgid "interval time zone \"%s\" must not include months or days" -msgstr "Intervall-Zeitzone „%s“ darf keine Monate oder Tage enthalten" +msgstr "Intervall-Zeitzone »%s« darf keine Monate oder Tage enthalten" #: utils/adt/datetime.c:1680 #, c-format msgid "time zone abbreviation \"%s\" is not used in time zone \"%s\"" -msgstr "Zeitzonenabkürzung „%s“ wird in Zeitzone „%s“ nicht verwendet" +msgstr "Zeitzonenabkürzung »%s« wird in Zeitzone »%s« nicht verwendet" #: utils/adt/datetime.c:3766 utils/adt/datetime.c:3773 #, c-format msgid "date/time field value out of range: \"%s\"" -msgstr "Datum/Zeit-Feldwert ist außerhalb des gültigen Bereichs: „%s“" +msgstr "Datum/Zeit-Feldwert ist außerhalb des gültigen Bereichs: »%s«" #: utils/adt/datetime.c:3775 #, c-format msgid "Perhaps you need a different \"datestyle\" setting." -msgstr "Möglicherweise benötigen Sie eine andere „datestyle“-Einstellung." +msgstr "Möglicherweise benötigen Sie eine andere »datestyle«-Einstellung." #: utils/adt/datetime.c:3780 #, c-format msgid "interval field value out of range: \"%s\"" -msgstr "„interval“-Feldwert ist außerhalb des gültigen Bereichs: „%s“" +msgstr "»interval«-Feldwert ist außerhalb des gültigen Bereichs: »%s«" #: utils/adt/datetime.c:3786 #, c-format msgid "time zone displacement out of range: \"%s\"" -msgstr "Zeitzonenunterschied ist außerhalb des gültigen Bereichs: „%s“" +msgstr "Zeitzonenunterschied ist außerhalb des gültigen Bereichs: »%s«" #. translator: first %s is inet or cidr #: utils/adt/datetime.c:3793 utils/adt/network.c:58 #, c-format msgid "invalid input syntax for type %s: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ %s: „%s“" +msgstr "ungültige Eingabesyntax für Typ %s: »%s«" #: utils/adt/datetime.c:4568 #, c-format msgid "This time zone name appears in the configuration file for time zone abbreviation \"%s\"." -msgstr "Dieser Zeitzonenname erscheint in der Konfigurationsdatei für Zeitzonenabkürzung „%s“." +msgstr "Dieser Zeitzonenname erscheint in der Konfigurationsdatei für Zeitzonenabkürzung »%s«." #: utils/adt/datum.c:86 utils/adt/datum.c:98 #, c-format msgid "invalid Datum pointer" -msgstr "ungültiger „Datum“-Zeiger" +msgstr "ungültiger »Datum«-Zeiger" #: utils/adt/dbsize.c:108 #, c-format msgid "could not open tablespace directory \"%s\": %m" -msgstr "konnte Tablespace-Verzeichnis „%s“ nicht öffnen: %m" +msgstr "konnte Tablespace-Verzeichnis »%s« nicht öffnen: %m" #: utils/adt/domains.c:85 #, c-format @@ -17604,12 +17605,12 @@ msgstr "Typ %s ist keine Domäne" #: utils/adt/encode.c:55 utils/adt/encode.c:91 #, c-format msgid "unrecognized encoding: \"%s\"" -msgstr "unbekannte Kodierung: „%s“" +msgstr "unbekannte Kodierung: »%s«" #: utils/adt/encode.c:150 #, c-format msgid "invalid hexadecimal digit: \"%c\"" -msgstr "ungültige hexadezimale Ziffer: „%c“" +msgstr "ungültige hexadezimale Ziffer: »%c«" #: utils/adt/encode.c:178 #, c-format @@ -17619,12 +17620,12 @@ msgstr "ungültige hexadezimale Daten: ungerade Anzahl Ziffern" #: utils/adt/encode.c:295 #, c-format msgid "unexpected \"=\" while decoding base64 sequence" -msgstr "unerwartetes „=“ beim Dekodieren von Base64-Sequenz" +msgstr "unerwartetes »=« beim Dekodieren von Base64-Sequenz" #: utils/adt/encode.c:307 #, c-format msgid "invalid symbol \"%c\" while decoding base64 sequence" -msgstr "ungültiges Symbol „%c“ beim Dekodieren von Base64-Sequenz" +msgstr "ungültiges Symbol »%c« beim Dekodieren von Base64-Sequenz" #: utils/adt/encode.c:327 #, c-format @@ -17646,7 +17647,7 @@ msgstr "ungültige Eingabesyntax für Typ bytea" #: utils/adt/enum.c:123 #, c-format msgid "invalid input value for enum %s: \"%s\"" -msgstr "ungültiger Eingabewert für Enum %s: „%s“" +msgstr "ungültiger Eingabewert für Enum %s: »%s«" #: utils/adt/enum.c:85 utils/adt/enum.c:148 utils/adt/enum.c:198 #, c-format @@ -17674,28 +17675,28 @@ msgstr "Wert ist außerhalb des gültigen Bereichs: Überlauf" msgid "value out of range: underflow" msgstr "Wert ist außerhalb des gültigen Bereichs: Unterlauf" -#: utils/adt/float.c:218 utils/adt/float.c:292 utils/adt/float.c:316 +#: utils/adt/float.c:215 utils/adt/float.c:289 utils/adt/float.c:313 #, c-format msgid "invalid input syntax for type real: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ real: „%s“" +msgstr "ungültige Eingabesyntax für Typ real: »%s«" -#: utils/adt/float.c:286 +#: utils/adt/float.c:283 #, c-format msgid "\"%s\" is out of range for type real" -msgstr "„%s“ ist außerhalb des gültigen Bereichs für Typ real" +msgstr "»%s« ist außerhalb des gültigen Bereichs für Typ real" -#: utils/adt/float.c:417 utils/adt/float.c:491 utils/adt/float.c:515 +#: utils/adt/float.c:414 utils/adt/float.c:488 utils/adt/float.c:512 #: utils/adt/numeric.c:5373 utils/adt/numeric.c:5399 #, c-format msgid "invalid input syntax for type double precision: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ double precision: „%s“" +msgstr "ungültige Eingabesyntax für Typ double precision: »%s«" -#: utils/adt/float.c:485 +#: utils/adt/float.c:482 #, c-format msgid "\"%s\" is out of range for type double precision" -msgstr "„%s“ ist außerhalb des gültigen Bereichs für Typ double precision" +msgstr "»%s« ist außerhalb des gültigen Bereichs für Typ double precision" -#: utils/adt/float.c:1179 utils/adt/float.c:1237 utils/adt/int.c:349 +#: utils/adt/float.c:1176 utils/adt/float.c:1234 utils/adt/int.c:349 #: utils/adt/int.c:775 utils/adt/int.c:804 utils/adt/int.c:825 #: utils/adt/int.c:845 utils/adt/int.c:879 utils/adt/int.c:1174 #: utils/adt/int8.c:1323 utils/adt/numeric.c:3000 utils/adt/numeric.c:3009 @@ -17703,54 +17704,54 @@ msgstr "„%s“ ist außerhalb des gültigen Bereichs für Typ double precision msgid "smallint out of range" msgstr "smallint ist außerhalb des gültigen Bereichs" -#: utils/adt/float.c:1363 utils/adt/numeric.c:6599 +#: utils/adt/float.c:1360 utils/adt/numeric.c:6599 #, c-format msgid "cannot take square root of a negative number" msgstr "Quadratwurzel von negativer Zahl kann nicht ermittelt werden" -#: utils/adt/float.c:1405 utils/adt/numeric.c:2820 +#: utils/adt/float.c:1402 utils/adt/numeric.c:2820 #, c-format msgid "zero raised to a negative power is undefined" msgstr "null hoch eine negative Zahl ist undefiniert" -#: utils/adt/float.c:1409 utils/adt/numeric.c:2826 +#: utils/adt/float.c:1406 utils/adt/numeric.c:2826 #, c-format msgid "a negative number raised to a non-integer power yields a complex result" msgstr "eine negative Zahl hoch eine nicht ganze Zahl ergibt ein komplexes Ergebnis" -#: utils/adt/float.c:1475 utils/adt/float.c:1505 utils/adt/numeric.c:6817 +#: utils/adt/float.c:1472 utils/adt/float.c:1502 utils/adt/numeric.c:6817 #, c-format msgid "cannot take logarithm of zero" msgstr "Logarithmus von null kann nicht ermittelt werden" -#: utils/adt/float.c:1479 utils/adt/float.c:1509 utils/adt/numeric.c:6821 +#: utils/adt/float.c:1476 utils/adt/float.c:1506 utils/adt/numeric.c:6821 #, c-format msgid "cannot take logarithm of a negative number" msgstr "Logarithmus negativer Zahlen kann nicht ermittelt werden" -#: utils/adt/float.c:1536 utils/adt/float.c:1557 utils/adt/float.c:1578 -#: utils/adt/float.c:1600 utils/adt/float.c:1621 utils/adt/float.c:1642 -#: utils/adt/float.c:1664 utils/adt/float.c:1685 +#: utils/adt/float.c:1533 utils/adt/float.c:1554 utils/adt/float.c:1575 +#: utils/adt/float.c:1597 utils/adt/float.c:1618 utils/adt/float.c:1639 +#: utils/adt/float.c:1661 utils/adt/float.c:1682 #, c-format msgid "input is out of range" msgstr "Eingabe ist außerhalb des gültigen Bereichs" -#: utils/adt/float.c:2747 utils/adt/numeric.c:1454 +#: utils/adt/float.c:2744 utils/adt/numeric.c:1454 #, c-format msgid "count must be greater than zero" msgstr "Anzahl muss größer als null sein" -#: utils/adt/float.c:2752 utils/adt/numeric.c:1461 +#: utils/adt/float.c:2749 utils/adt/numeric.c:1461 #, c-format msgid "operand, lower bound, and upper bound cannot be NaN" msgstr "Operand, Untergrenze und Obergrenze dürfen nicht NaN sein" -#: utils/adt/float.c:2758 +#: utils/adt/float.c:2755 #, c-format msgid "lower and upper bounds must be finite" msgstr "Untergrenze und Obergrenze müssen endlich sein" -#: utils/adt/float.c:2796 utils/adt/numeric.c:1474 +#: utils/adt/float.c:2793 utils/adt/numeric.c:1474 #, c-format msgid "lower bound cannot equal upper bound" msgstr "Untergrenze kann nicht gleich der Obergrenze sein" @@ -17765,211 +17766,211 @@ 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:1059 +#: utils/adt/formatting.c:1058 #, c-format msgid "\"EEEE\" must be the last pattern used" -msgstr "„EEEE“ muss das letzte Muster sein" +msgstr "»EEEE« muss das letzte Muster sein" -#: utils/adt/formatting.c:1067 +#: utils/adt/formatting.c:1066 #, c-format msgid "\"9\" must be ahead of \"PR\"" -msgstr "„9“ muss vor „PR“ stehen" +msgstr "»9« muss vor »PR« stehen" -#: utils/adt/formatting.c:1083 +#: utils/adt/formatting.c:1082 #, c-format msgid "\"0\" must be ahead of \"PR\"" -msgstr "„0“ muss vor „PR“ stehen" +msgstr "»0« muss vor »PR« stehen" -#: utils/adt/formatting.c:1110 +#: utils/adt/formatting.c:1109 #, c-format msgid "multiple decimal points" msgstr "mehrere Dezimalpunkte" -#: utils/adt/formatting.c:1114 utils/adt/formatting.c:1197 +#: utils/adt/formatting.c:1113 utils/adt/formatting.c:1196 #, c-format msgid "cannot use \"V\" and decimal point together" -msgstr "„V“ und Dezimalpunkt können nicht zusammen verwendet werden" +msgstr "»V« und Dezimalpunkt können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1126 +#: utils/adt/formatting.c:1125 #, c-format msgid "cannot use \"S\" twice" -msgstr "„S“ kann nicht zweimal verwendet werden" +msgstr "»S« kann nicht zweimal verwendet werden" -#: utils/adt/formatting.c:1130 +#: utils/adt/formatting.c:1129 #, 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" +msgstr "»S« und »PL«/»MI«/»SG«/»PR« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1150 +#: utils/adt/formatting.c:1149 #, c-format msgid "cannot use \"S\" and \"MI\" together" -msgstr "„S“ und „MI“ können nicht zusammen verwendet werden" +msgstr "»S« und »MI« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1160 +#: utils/adt/formatting.c:1159 #, c-format msgid "cannot use \"S\" and \"PL\" together" -msgstr "„S“ und „PL“ können nicht zusammen verwendet werden" +msgstr "»S« und »PL« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1170 +#: utils/adt/formatting.c:1169 #, c-format msgid "cannot use \"S\" and \"SG\" together" -msgstr "„S“ und „SG“ können nicht zusammen verwendet werden" +msgstr "»S« und »SG« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1179 +#: utils/adt/formatting.c:1178 #, 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" +msgstr "»PR« und »S«/»PL«/»MI«/»SG« können nicht zusammen verwendet werden" -#: utils/adt/formatting.c:1205 +#: utils/adt/formatting.c:1204 #, c-format msgid "cannot use \"EEEE\" twice" -msgstr "„EEEE“ kann nicht zweimal verwendet werden" +msgstr "»EEEE« kann nicht zweimal verwendet werden" -#: utils/adt/formatting.c:1211 +#: utils/adt/formatting.c:1210 #, c-format msgid "\"EEEE\" is incompatible with other formats" -msgstr "„EEEE“ ist mit anderen Formaten inkompatibel" +msgstr "»EEEE« ist mit anderen Formaten inkompatibel" -#: utils/adt/formatting.c:1212 +#: utils/adt/formatting.c:1211 #, 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." +msgstr "»EEEE« kann nur zusammen mit Platzhaltern für Ziffern oder Dezimalpunkt verwendet werden." -#: utils/adt/formatting.c:1412 +#: utils/adt/formatting.c:1411 #, c-format msgid "\"%s\" is not a number" -msgstr "„%s“ ist keine Zahl" +msgstr "»%s« ist keine Zahl" -#: utils/adt/formatting.c:1513 utils/adt/formatting.c:1565 +#: utils/adt/formatting.c:1512 utils/adt/formatting.c:1564 #, c-format msgid "could not determine which collation to use for lower() function" msgstr "konnte die für die Funktion lower() zu verwendende Sortierfolge nicht bestimmen" -#: utils/adt/formatting.c:1633 utils/adt/formatting.c:1685 +#: utils/adt/formatting.c:1632 utils/adt/formatting.c:1684 #, c-format msgid "could not determine which collation to use for upper() function" msgstr "konnte die für die Funktion upper() zu verwendende Sortierfolge nicht bestimmen" -#: utils/adt/formatting.c:1754 utils/adt/formatting.c:1818 +#: utils/adt/formatting.c:1753 utils/adt/formatting.c:1817 #, c-format msgid "could not determine which collation to use for initcap() function" msgstr "konnte die für die Funktion initcap() zu verwendende Sortierfolge nicht bestimmen" -#: utils/adt/formatting.c:2122 +#: utils/adt/formatting.c:2114 #, c-format msgid "invalid combination of date conventions" msgstr "ungültige Kombination von Datumskonventionen" -#: utils/adt/formatting.c:2123 +#: utils/adt/formatting.c:2115 #, 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:2140 +#: utils/adt/formatting.c:2132 #, c-format msgid "conflicting values for \"%s\" field in formatting string" -msgstr "widersprüchliche Werte für das Feld „%s“ in Formatzeichenkette" +msgstr "widersprüchliche Werte für das Feld »%s« in Formatzeichenkette" -#: utils/adt/formatting.c:2142 +#: utils/adt/formatting.c:2134 #, 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:2203 +#: utils/adt/formatting.c:2195 #, c-format msgid "source string too short for \"%s\" formatting field" -msgstr "Quellzeichenkette zu kurz für Formatfeld „%s„" +msgstr "Quellzeichenkette zu kurz für Formatfeld »%s»" -#: utils/adt/formatting.c:2205 +#: utils/adt/formatting.c:2197 #, 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:2208 utils/adt/formatting.c:2222 +#: utils/adt/formatting.c:2200 utils/adt/formatting.c:2214 #, 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“." +msgstr "Wenn die Quellzeichenkette keine feste Breite hat, versuchen Sie den Modifikator »FM«." -#: utils/adt/formatting.c:2218 utils/adt/formatting.c:2231 -#: utils/adt/formatting.c:2361 +#: utils/adt/formatting.c:2210 utils/adt/formatting.c:2223 +#: utils/adt/formatting.c:2353 #, c-format msgid "invalid value \"%s\" for \"%s\"" -msgstr "ungültiger Wert „%s“ für „%s“" +msgstr "ungültiger Wert »%s« für »%s«" -#: utils/adt/formatting.c:2220 +#: utils/adt/formatting.c:2212 #, 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:2233 +#: utils/adt/formatting.c:2225 #, c-format msgid "Value must be an integer." msgstr "Der Wert muss eine ganze Zahl sein." -#: utils/adt/formatting.c:2238 +#: utils/adt/formatting.c:2230 #, 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" +msgstr "Wert für »%s« in der Eingabezeichenkette ist außerhalb des gültigen Bereichs" -#: utils/adt/formatting.c:2240 +#: utils/adt/formatting.c:2232 #, 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:2363 +#: utils/adt/formatting.c:2355 #, 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:2555 utils/adt/formatting.c:2575 -#: utils/adt/formatting.c:2595 utils/adt/formatting.c:2615 -#: utils/adt/formatting.c:2634 utils/adt/formatting.c:2653 -#: utils/adt/formatting.c:2676 utils/adt/formatting.c:2694 -#: utils/adt/formatting.c:2712 utils/adt/formatting.c:2730 -#: utils/adt/formatting.c:2747 utils/adt/formatting.c:2764 +#: utils/adt/formatting.c:2547 utils/adt/formatting.c:2567 +#: utils/adt/formatting.c:2587 utils/adt/formatting.c:2607 +#: utils/adt/formatting.c:2626 utils/adt/formatting.c:2645 +#: utils/adt/formatting.c:2668 utils/adt/formatting.c:2686 +#: utils/adt/formatting.c:2704 utils/adt/formatting.c:2722 +#: utils/adt/formatting.c:2739 utils/adt/formatting.c:2756 #, c-format msgid "localized string format value too long" msgstr "lokalisierter Formatwert ist zu lang" -#: utils/adt/formatting.c:3048 +#: utils/adt/formatting.c:3040 #, c-format msgid "\"TZ\"/\"tz\"/\"OF\" format patterns are not supported in to_date" -msgstr "Formatmuster „TZ“/„tz“/„OF“ werden in to_date nicht unterstützt" +msgstr "Formatmuster »TZ«/»tz«/»OF« werden in to_date nicht unterstützt" -#: utils/adt/formatting.c:3156 +#: utils/adt/formatting.c:3149 #, c-format msgid "invalid input string for \"Y,YYY\"" -msgstr "ungültige Eingabe für „Y,YYY“" +msgstr "ungültige Eingabe für »Y,YYY«" -#: utils/adt/formatting.c:3659 +#: utils/adt/formatting.c:3653 #, c-format msgid "hour \"%d\" is invalid for the 12-hour clock" -msgstr "Stunde „%d“ ist bei einer 12-Stunden-Uhr ungültig" +msgstr "Stunde »%d« ist bei einer 12-Stunden-Uhr ungültig" -#: utils/adt/formatting.c:3661 +#: utils/adt/formatting.c:3655 #, 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:3756 +#: utils/adt/formatting.c:3750 #, c-format msgid "cannot calculate day of year without year information" msgstr "kann Tag des Jahres nicht berechnen ohne Jahrinformationen" -#: utils/adt/formatting.c:4605 +#: utils/adt/formatting.c:4599 #, c-format msgid "\"EEEE\" not supported for input" -msgstr "„E“ wird nicht bei der Eingabe unterstützt" +msgstr "»E« wird nicht bei der Eingabe unterstützt" -#: utils/adt/formatting.c:4617 +#: utils/adt/formatting.c:4611 #, c-format msgid "\"RN\" not supported for input" -msgstr "„RN“ wird nicht bei der Eingabe unterstützt" +msgstr "»RN« wird nicht bei der Eingabe unterstützt" #: utils/adt/genfile.c:62 #, c-format msgid "reference to parent directory (\"..\") not allowed" -msgstr "Verweis auf übergeordnetes Verzeichnis („..“) nicht erlaubt" +msgstr "Verweis auf übergeordnetes Verzeichnis (»..«) nicht erlaubt" #: utils/adt/genfile.c:73 #, c-format @@ -17991,7 +17992,7 @@ msgstr "verlangte Länge zu groß" #: utils/adt/genfile.c:142 #, c-format msgid "could not seek in file \"%s\": %m" -msgstr "konnte Positionszeiger in Datei „%s“ nicht setzen: %m" +msgstr "konnte Positionszeiger in Datei »%s« nicht setzen: %m" #: utils/adt/genfile.c:200 utils/adt/genfile.c:241 #, c-format @@ -18008,8 +18009,8 @@ msgstr "nur Superuser können Dateiinformationen lesen" msgid "must be superuser to get directory listings" msgstr "nur Superuser können Verzeichnislisten lesen" -#: utils/adt/geo_ops.c:301 utils/adt/geo_ops.c:1400 utils/adt/geo_ops.c:3498 -#: utils/adt/geo_ops.c:4315 utils/adt/geo_ops.c:5259 +#: utils/adt/geo_ops.c:301 utils/adt/geo_ops.c:1400 utils/adt/geo_ops.c:3506 +#: utils/adt/geo_ops.c:4323 utils/adt/geo_ops.c:5267 #, c-format msgid "too many points requested" msgstr "zu viele Punkte verlangt" @@ -18017,120 +18018,120 @@ msgstr "zu viele Punkte verlangt" #: utils/adt/geo_ops.c:324 #, c-format msgid "could not format \"path\" value" -msgstr "konnte „path“-Wert nicht formatieren" +msgstr "konnte »path«-Wert nicht formatieren" #: utils/adt/geo_ops.c:399 #, c-format msgid "invalid input syntax for type box: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ box: „%s“" +msgstr "ungültige Eingabesyntax für Typ box: »%s«" #: utils/adt/geo_ops.c:994 #, c-format msgid "invalid line specification: must be two distinct points" -msgstr "ungültige „line“-Angabe: es müssen zwei verschiedene Punkte angegeben werden" +msgstr "ungültige »line«-Angabe: es müssen zwei verschiedene Punkte angegeben werden" #: utils/adt/geo_ops.c:1003 #, c-format msgid "invalid line specification: A and B cannot both be zero" -msgstr "ungültige „line“-Angabe: A und B können nicht beide null sein" +msgstr "ungültige »line«-Angabe: A und B können nicht beide null sein" #: utils/adt/geo_ops.c:1008 #, c-format msgid "invalid input syntax for type line: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ line: „%s“" +msgstr "ungültige Eingabesyntax für Typ line: »%s«" #: utils/adt/geo_ops.c:1380 utils/adt/geo_ops.c:1411 #, c-format msgid "invalid input syntax for type path: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ path: „%s“" +msgstr "ungültige Eingabesyntax für Typ path: »%s«" #: utils/adt/geo_ops.c:1450 #, c-format msgid "invalid number of points in external \"path\" value" -msgstr "ungültige Anzahl Punkte in externem „path“-Wert" +msgstr "ungültige Anzahl Punkte in externem »path«-Wert" #: utils/adt/geo_ops.c:1793 #, c-format msgid "invalid input syntax for type point: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ point: „%s“" +msgstr "ungültige Eingabesyntax für Typ point: »%s«" #: utils/adt/geo_ops.c:2021 #, c-format msgid "invalid input syntax for type lseg: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ lseg: „%s“" +msgstr "ungültige Eingabesyntax für Typ lseg: »%s«" #: utils/adt/geo_ops.c:2621 #, c-format msgid "function \"dist_lb\" not implemented" -msgstr "Funktion „dist_lb“ ist nicht implementiert" +msgstr "Funktion »dist_lb« ist nicht implementiert" -#: utils/adt/geo_ops.c:3073 +#: utils/adt/geo_ops.c:3081 #, c-format msgid "function \"close_sl\" not implemented" -msgstr "Funktion „close_sl“ ist nicht implementiert" +msgstr "Funktion »close_sl« ist nicht implementiert" -#: utils/adt/geo_ops.c:3175 +#: utils/adt/geo_ops.c:3183 #, c-format msgid "function \"close_lb\" not implemented" -msgstr "Funktion „close_lb“ ist nicht implementiert" +msgstr "Funktion »close_lb« ist nicht implementiert" -#: utils/adt/geo_ops.c:3464 +#: utils/adt/geo_ops.c:3472 #, c-format msgid "cannot create bounding box for empty polygon" msgstr "kann kein umschließendes Rechteck für leeres Polygon berechnen" -#: utils/adt/geo_ops.c:3489 utils/adt/geo_ops.c:3509 +#: utils/adt/geo_ops.c:3497 utils/adt/geo_ops.c:3517 #, c-format msgid "invalid input syntax for type polygon: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ polygon: „%s“" +msgstr "ungültige Eingabesyntax für Typ polygon: »%s«" -#: utils/adt/geo_ops.c:3549 +#: utils/adt/geo_ops.c:3557 #, c-format msgid "invalid number of points in external \"polygon\" value" -msgstr "ungültige Anzahl Punkte in externem „polygon“-Wert" +msgstr "ungültige Anzahl Punkte in externem »polygon«-Wert" -#: utils/adt/geo_ops.c:4074 +#: utils/adt/geo_ops.c:4082 #, c-format msgid "function \"poly_distance\" not implemented" -msgstr "Funktion „poly_distance“ ist nicht implementiert" +msgstr "Funktion »poly_distance« ist nicht implementiert" -#: utils/adt/geo_ops.c:4427 +#: utils/adt/geo_ops.c:4435 #, c-format msgid "function \"path_center\" not implemented" -msgstr "Funktion „path_center“ ist nicht implementiert" +msgstr "Funktion »path_center« ist nicht implementiert" -#: utils/adt/geo_ops.c:4444 +#: utils/adt/geo_ops.c:4452 #, c-format msgid "open path cannot be converted to polygon" msgstr "offener Pfad kann nicht in Polygon umgewandelt werden" -#: utils/adt/geo_ops.c:4621 utils/adt/geo_ops.c:4631 utils/adt/geo_ops.c:4646 -#: utils/adt/geo_ops.c:4652 +#: utils/adt/geo_ops.c:4629 utils/adt/geo_ops.c:4639 utils/adt/geo_ops.c:4654 +#: utils/adt/geo_ops.c:4660 #, c-format msgid "invalid input syntax for type circle: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ circle: „%s“" +msgstr "ungültige Eingabesyntax für Typ circle: »%s«" -#: utils/adt/geo_ops.c:4674 utils/adt/geo_ops.c:4682 +#: utils/adt/geo_ops.c:4682 utils/adt/geo_ops.c:4690 #, c-format msgid "could not format \"circle\" value" -msgstr "konnte „circle“-Wert nicht formatieren" +msgstr "konnte »circle«-Wert nicht formatieren" -#: utils/adt/geo_ops.c:4709 +#: utils/adt/geo_ops.c:4717 #, c-format msgid "invalid radius in external \"circle\" value" -msgstr "ungültiger Radius in externem „circle“-Wert" +msgstr "ungültiger Radius in externem »circle«-Wert" -#: utils/adt/geo_ops.c:5245 +#: utils/adt/geo_ops.c:5253 #, c-format msgid "cannot convert circle with radius zero to polygon" msgstr "kann Kreis mit Radius null nicht in Polygon umwandeln" -#: utils/adt/geo_ops.c:5250 +#: utils/adt/geo_ops.c:5258 #, c-format msgid "must request at least 2 points" msgstr "mindestens 2 Punkte müssen angefordert werden" -#: utils/adt/geo_ops.c:5294 +#: utils/adt/geo_ops.c:5302 #, c-format msgid "cannot convert empty polygon to circle" msgstr "kann leeres Polygon nicht in Kreis umwandeln" @@ -18160,12 +18161,12 @@ msgstr "Schrittgröße kann nicht gleich null sein" #: utils/adt/numutils.c:61 utils/adt/numutils.c:103 #, c-format msgid "invalid input syntax for integer: \"%s\"" -msgstr "ungültige Eingabesyntax für ganze Zahl: „%s“" +msgstr "ungültige Eingabesyntax für ganze Zahl: »%s«" #: utils/adt/int8.c:114 #, c-format msgid "value \"%s\" is out of range for type bigint" -msgstr "Wert „%s“ ist außerhalb des gültigen Bereichs für Typ bigint" +msgstr "Wert »%s« ist außerhalb des gültigen Bereichs für Typ bigint" #: utils/adt/int8.c:500 utils/adt/int8.c:529 utils/adt/int8.c:550 #: utils/adt/int8.c:581 utils/adt/int8.c:615 utils/adt/int8.c:640 @@ -18205,7 +18206,7 @@ msgstr "Zeichen mit Wert 0x%02x muss escapt werden." #: utils/adt/json.c:826 #, c-format msgid "\"\\u\" must be followed by four hexadecimal digits." -msgstr "Nach „\\u“ müssen vier Hexadezimalziffern folgen." +msgstr "Nach »\\u« müssen vier Hexadezimalziffern folgen." #: utils/adt/json.c:841 #, c-format @@ -18226,7 +18227,7 @@ msgstr "nicht unterstützte Unicode-Escape-Sequenz" #: utils/adt/json.c:878 #, c-format msgid "\\u0000 cannot be converted to text." -msgstr "\\u0000 kann nicht in „text“ umgewandelt werden." +msgstr "\\u0000 kann nicht in »text« umgewandelt werden." #: utils/adt/json.c:901 #, c-format @@ -18236,7 +18237,7 @@ msgstr "Unicode-Escape-Werte können nicht für Code-Punkt-Werte über 007F verw #: utils/adt/json.c:944 utils/adt/json.c:962 #, c-format msgid "Escape sequence \"\\%s\" is invalid." -msgstr "Escape-Sequenz „\\%s“ ist nicht gültig." +msgstr "Escape-Sequenz »\\%s« ist nicht gültig." #: utils/adt/json.c:1131 #, c-format @@ -18246,47 +18247,47 @@ msgstr "Die Eingabezeichenkette endete unerwartet." #: utils/adt/json.c:1145 #, c-format msgid "Expected end of input, but found \"%s\"." -msgstr "Ende der Eingabe erwartet, aber „%s“ gefunden." +msgstr "Ende der Eingabe erwartet, aber »%s« gefunden." #: utils/adt/json.c:1156 #, c-format msgid "Expected JSON value, but found \"%s\"." -msgstr "JSON-Wert erwartet, aber „%s“ gefunden." +msgstr "JSON-Wert erwartet, aber »%s« gefunden." #: utils/adt/json.c:1164 utils/adt/json.c:1212 #, c-format msgid "Expected string, but found \"%s\"." -msgstr "Zeichenkette erwartet, aber „%s“ gefunden." +msgstr "Zeichenkette erwartet, aber »%s« gefunden." #: utils/adt/json.c:1172 #, c-format msgid "Expected array element or \"]\", but found \"%s\"." -msgstr "Array-Element oder „]“ erwartet, aber „%s“ gefunden." +msgstr "Array-Element oder »]« erwartet, aber »%s« gefunden." #: utils/adt/json.c:1180 #, c-format msgid "Expected \",\" or \"]\", but found \"%s\"." -msgstr "„,“ oder „]“ erwartet, aber „%s“ gefunden." +msgstr "»,« oder »]« erwartet, aber »%s« gefunden." #: utils/adt/json.c:1188 #, c-format msgid "Expected string or \"}\", but found \"%s\"." -msgstr "Zeichenkette oder „}“ erwartet, aber „%s“ gefunden." +msgstr "Zeichenkette oder »}« erwartet, aber »%s« gefunden." #: utils/adt/json.c:1196 #, c-format msgid "Expected \":\", but found \"%s\"." -msgstr "„:“ erwartet, aber „%s“ gefunden." +msgstr "»:« erwartet, aber »%s« gefunden." #: utils/adt/json.c:1204 #, c-format msgid "Expected \",\" or \"}\", but found \"%s\"." -msgstr "„,“ oder „}“ erwartet, aber „%s“ gefunden." +msgstr "»,« oder »}« erwartet, aber »%s« gefunden." #: utils/adt/json.c:1242 #, c-format msgid "Token \"%s\" is invalid." -msgstr "Token „%s“ ist ungültig." +msgstr "Token »%s« ist ungültig." #: utils/adt/json.c:1314 #, c-format @@ -18517,7 +18518,7 @@ msgstr "Pfadelement auf Position %d ist NULL" #: utils/adt/jsonfuncs.c:3888 #, c-format msgid "path element at position %d is not an integer: \"%s\"" -msgstr "Pfadelement auf Position %d ist keine ganze Zahl: „%s“" +msgstr "Pfadelement auf Position %d ist keine ganze Zahl: »%s«" #: utils/adt/levenshtein.c:133 #, c-format @@ -18552,12 +18553,12 @@ msgstr "während einer parallelen Operation können keine Benutzersperren verwen #: utils/adt/mac.c:68 #, c-format msgid "invalid input syntax for type macaddr: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ macaddr: „%s“" +msgstr "ungültige Eingabesyntax für Typ macaddr: »%s«" #: utils/adt/mac.c:75 #, c-format msgid "invalid octet value in \"macaddr\" value: \"%s\"" -msgstr "ungültiger Oktettwert in „macaddr“-Wert: „%s“" +msgstr "ungültiger Oktettwert in »macaddr«-Wert: »%s«" #: utils/adt/misc.c:116 #, c-format @@ -18633,32 +18634,32 @@ msgstr "reserviert" #: utils/adt/nabstime.c:136 #, c-format msgid "invalid time zone name: \"%s\"" -msgstr "ungültiger Zeitzonenname: „%s“" +msgstr "ungültiger Zeitzonenname: »%s«" #: utils/adt/nabstime.c:481 utils/adt/nabstime.c:554 #, c-format msgid "cannot convert abstime \"invalid\" to timestamp" -msgstr "kann „abstime“-Wert „invalid“ nicht „timestamp“ umwandeln" +msgstr "kann »abstime«-Wert »invalid« nicht »timestamp« umwandeln" #: utils/adt/nabstime.c:781 #, c-format msgid "invalid status in external \"tinterval\" value" -msgstr "ungültiger Status in externem „tinterval“-Wert" +msgstr "ungültiger Status in externem »tinterval«-Wert" #: utils/adt/nabstime.c:855 #, c-format msgid "cannot convert reltime \"invalid\" to interval" -msgstr "kann „reltime“-Wert „invalid“ nicht in „interval“ umwandeln" +msgstr "kann »reltime«-Wert »invalid« nicht in »interval« umwandeln" #: utils/adt/nabstime.c:1550 #, c-format msgid "invalid input syntax for type tinterval: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ tinterval: „%s“" +msgstr "ungültige Eingabesyntax für Typ tinterval: »%s«" #: utils/adt/network.c:69 #, c-format msgid "invalid cidr value: \"%s\"" -msgstr "ungültiger cidr-Wert: „%s“" +msgstr "ungültiger cidr-Wert: »%s«" #: utils/adt/network.c:70 utils/adt/network.c:200 #, c-format @@ -18675,24 +18676,24 @@ msgstr "konnte inet-Wert nicht formatieren: %m" #: utils/adt/network.c:168 #, c-format msgid "invalid address family in external \"%s\" value" -msgstr "ungültige Adressfamilie in externem „%s“-Wert" +msgstr "ungültige Adressfamilie in externem »%s«-Wert" #. translator: %s is inet or cidr #: utils/adt/network.c:175 #, c-format msgid "invalid bits in external \"%s\" value" -msgstr "ungültige Bits in externem „%s“-Wert" +msgstr "ungültige Bits in externem »%s«-Wert" #. translator: %s is inet or cidr #: utils/adt/network.c:184 #, c-format msgid "invalid length in external \"%s\" value" -msgstr "ungültige Länge in externem „%s“-Wert" +msgstr "ungültige Länge in externem »%s«-Wert" #: utils/adt/network.c:199 #, c-format msgid "invalid external \"cidr\" value" -msgstr "ungültiger externer „cidr“-Wert" +msgstr "ungültiger externer »cidr«-Wert" #: utils/adt/network.c:321 utils/adt/network.c:348 #, c-format @@ -18712,12 +18713,12 @@ msgstr "Adressen verschiedener Familien können nicht zusammengeführt werden" #: utils/adt/network.c:1343 #, c-format msgid "cannot AND inet values of different sizes" -msgstr "binäres „Und“ nicht mit „inet“-Werten unterschiedlicher Größe möglich" +msgstr "binäres »Und« nicht mit »inet«-Werten unterschiedlicher Größe möglich" #: utils/adt/network.c:1375 #, c-format msgid "cannot OR inet values of different sizes" -msgstr "binäres „Oder“ nicht mit „inet“-Werten unterschiedlicher Größe möglich" +msgstr "binäres »Oder« nicht mit »inet«-Werten unterschiedlicher Größe möglich" #: utils/adt/network.c:1436 utils/adt/network.c:1512 #, c-format @@ -18727,33 +18728,33 @@ msgstr "Ergebnis ist außerhalb des gültigen Bereichs" #: utils/adt/network.c:1477 #, c-format msgid "cannot subtract inet values of different sizes" -msgstr "Subtraktion von „inet“-Werten unterschiedlicher Größe nicht möglich" +msgstr "Subtraktion von »inet«-Werten unterschiedlicher Größe nicht möglich" #: utils/adt/numeric.c:549 utils/adt/numeric.c:576 utils/adt/numeric.c:4604 #: utils/adt/numeric.c:4627 utils/adt/numeric.c:4651 utils/adt/numeric.c:4658 #, c-format msgid "invalid input syntax for type numeric: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ numeric: „%s“" +msgstr "ungültige Eingabesyntax für Typ numeric: »%s«" #: utils/adt/numeric.c:766 #, c-format msgid "invalid length in external \"numeric\" value" -msgstr "ungültige Länge in externem „numeric“-Wert" +msgstr "ungültige Länge in externem »numeric«-Wert" #: utils/adt/numeric.c:779 #, c-format msgid "invalid sign in external \"numeric\" value" -msgstr "ungültiges Vorzeichen in externem „numeric“-Wert" +msgstr "ungültiges Vorzeichen in externem »numeric«-Wert" #: utils/adt/numeric.c:785 #, c-format msgid "invalid scale in external \"numeric\" value" -msgstr "ungültige Skala in externem „numeric“-Wert" +msgstr "ungültige Skala in externem »numeric«-Wert" #: utils/adt/numeric.c:794 #, c-format msgid "invalid digit in external \"numeric\" value" -msgstr "ungültige Ziffer in externem „numeric“-Wert" +msgstr "ungültige Ziffer in externem »numeric«-Wert" #: utils/adt/numeric.c:985 utils/adt/numeric.c:999 #, c-format @@ -18788,7 +18789,7 @@ msgstr "Schrittgröße kann nicht NaN sein" #: utils/adt/numeric.c:2550 utils/adt/numeric.c:5104 utils/adt/numeric.c:7132 #, c-format msgid "value overflows numeric format" -msgstr "Wert verursacht Überlauf im „numeric“-Format" +msgstr "Wert verursacht Überlauf im »numeric«-Format" #: utils/adt/numeric.c:2881 #, c-format @@ -18808,7 +18809,7 @@ msgstr "kann NaN nicht in smallint umwandeln" #: utils/adt/numeric.c:5174 #, c-format msgid "numeric field overflow" -msgstr "Feldüberlauf bei Typ „numeric“" +msgstr "Feldüberlauf bei Typ »numeric«" #: utils/adt/numeric.c:5175 #, c-format @@ -18818,32 +18819,32 @@ msgstr "Ein Feld mit Präzision %d, Skala %d muss beim Runden einen Betrag von w #: utils/adt/numeric.c:6689 #, c-format msgid "argument for function \"exp\" too big" -msgstr "Argument für Funktion „exp“ zu groß" +msgstr "Argument für Funktion »exp« zu groß" #: utils/adt/numutils.c:75 #, c-format msgid "value \"%s\" is out of range for type integer" -msgstr "Wert „%s“ ist außerhalb des gültigen Bereichs für Typ integer" +msgstr "Wert »%s« ist außerhalb des gültigen Bereichs für Typ integer" #: utils/adt/numutils.c:81 #, c-format msgid "value \"%s\" is out of range for type smallint" -msgstr "Wert „%s“ ist außerhalb des gültigen Bereichs für Typ smallint" +msgstr "Wert »%s« ist außerhalb des gültigen Bereichs für Typ smallint" #: utils/adt/numutils.c:87 #, c-format msgid "value \"%s\" is out of range for 8-bit integer" -msgstr "Wert „%s“ ist außerhalb des gültigen Bereichs für 8-Bit-Ganzzahl" +msgstr "Wert »%s« ist außerhalb des gültigen Bereichs für 8-Bit-Ganzzahl" #: utils/adt/oid.c:43 utils/adt/oid.c:57 utils/adt/oid.c:63 utils/adt/oid.c:84 #, c-format msgid "invalid input syntax for type oid: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ „oid“: „%s“" +msgstr "ungültige Eingabesyntax für Typ »oid«: »%s«" #: utils/adt/oid.c:69 utils/adt/oid.c:107 #, c-format msgid "value \"%s\" is out of range for type oid" -msgstr "Wert „%s“ ist außerhalb des gültigen Bereichs für Typ „oid“" +msgstr "Wert »%s« ist außerhalb des gültigen Bereichs für Typ »oid«" #: utils/adt/oid.c:287 #, c-format @@ -18884,17 +18885,17 @@ msgstr "Aktualisieren Sie die Systembibliotheken." #: utils/adt/pg_locale.c:1122 #, c-format msgid "could not create locale \"%s\": %m" -msgstr "konnte Locale „%s“ nicht erzeugen: %m" +msgstr "konnte Locale »%s« nicht erzeugen: %m" #: utils/adt/pg_locale.c:1125 #, c-format msgid "The operating system could not find any locale data for the locale name \"%s\"." -msgstr "Das Betriebssystem konnte keine Locale-Daten für den Locale-Namen „%s“ finden." +msgstr "Das Betriebssystem konnte keine Locale-Daten für den Locale-Namen »%s« finden." #: utils/adt/pg_locale.c:1212 #, c-format msgid "collations with different collate and ctype values are not supported on this platform" -msgstr "Sortierfolgen mit unterschiedlichen „collate“- und „ctype“-Werten werden auf dieser Plattform nicht unterstützt" +msgstr "Sortierfolgen mit unterschiedlichen »collate«- und »ctype«-Werten werden auf dieser Plattform nicht unterstützt" #: utils/adt/pg_locale.c:1227 #, c-format @@ -18914,7 +18915,7 @@ msgstr "Die LC_CTYPE-Locale des Servers ist wahrscheinlich mit der Kodierung der #: utils/adt/pg_lsn.c:44 utils/adt/pg_lsn.c:49 #, c-format msgid "invalid input syntax for type pg_lsn: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ pg_lsn: „%s“" +msgstr "ungültige Eingabesyntax für Typ pg_lsn: »%s«" #: utils/adt/pg_upgrade_support.c:39 #, c-format @@ -19087,7 +19088,7 @@ msgstr "ungültige Markierungen für Bereichsgrenzen" #: utils/adt/rangetypes.c:1954 #, c-format msgid "Valid values are \"[]\", \"[)\", \"(]\", and \"()\"." -msgstr "Gültige Werte sind „[]“, „[)“, „(]“ und „()“." +msgstr "Gültige Werte sind »[]«, »[)«, »(]« und »()«." #: utils/adt/rangetypes.c:2019 utils/adt/rangetypes.c:2036 #: utils/adt/rangetypes.c:2049 utils/adt/rangetypes.c:2067 @@ -19095,12 +19096,12 @@ msgstr "Gültige Werte sind „[]“, „[)“, „(]“ und „()“." #: utils/adt/rangetypes.c:2130 #, c-format msgid "malformed range literal: \"%s\"" -msgstr "fehlerhafte Bereichskonstante: „%s“" +msgstr "fehlerhafte Bereichskonstante: »%s«" #: utils/adt/rangetypes.c:2021 #, c-format msgid "Junk after \"empty\" key word." -msgstr "Müll nach Schlüsselwort „empty“." +msgstr "Müll nach Schlüsselwort »empty«." #: utils/adt/rangetypes.c:2038 #, c-format @@ -19130,17 +19131,17 @@ msgstr "regulärer Ausdruck fehlgeschlagen: %s" #: utils/adt/regexp.c:422 #, c-format msgid "invalid regexp option: \"%c\"" -msgstr "ungültige Option für regulären Ausdruck: „%c“" +msgstr "ungültige Option für regulären Ausdruck: »%c«" #: utils/adt/regexp.c:948 #, c-format msgid "regexp_split does not support the global option" -msgstr "regexp_split unterstützt die „Global“-Option nicht" +msgstr "regexp_split unterstützt die »Global«-Option nicht" #: utils/adt/regproc.c:128 utils/adt/regproc.c:148 #, c-format msgid "more than one function named \"%s\"" -msgstr "es gibt mehrere Funktionen namens „%s“" +msgstr "es gibt mehrere Funktionen namens »%s«" #: utils/adt/regproc.c:587 utils/adt/regproc.c:607 #, c-format @@ -19148,7 +19149,7 @@ msgid "more than one operator named %s" msgstr "es gibt mehrere Operatoren namens %s" #: utils/adt/regproc.c:779 utils/adt/regproc.c:820 utils/adt/regproc.c:2006 -#: utils/adt/ruleutils.c:8185 utils/adt/ruleutils.c:8310 +#: utils/adt/ruleutils.c:8219 utils/adt/ruleutils.c:8344 #, c-format msgid "too many arguments" msgstr "zu viele Argumente" @@ -19189,7 +19190,7 @@ msgstr "falscher Typname" #: utils/adt/ri_triggers.c:3317 #, c-format msgid "insert or update on table \"%s\" violates foreign key constraint \"%s\"" -msgstr "Einfügen oder Aktualisieren in Tabelle „%s“ verletzt Fremdschlüssel-Constraint „%s“" +msgstr "Einfügen oder Aktualisieren in Tabelle »%s« verletzt Fremdschlüssel-Constraint »%s«" #: utils/adt/ri_triggers.c:348 utils/adt/ri_triggers.c:2495 #, c-format @@ -19199,22 +19200,22 @@ msgstr "MATCH FULL erlaubt das Mischen von Schlüsseln, die NULL und nicht NULL #: utils/adt/ri_triggers.c:2734 #, c-format msgid "function \"%s\" must be fired for INSERT" -msgstr "Funktion „%s“ muss von INSERT ausgelöst werden" +msgstr "Funktion »%s« muss von INSERT ausgelöst werden" #: utils/adt/ri_triggers.c:2740 #, c-format msgid "function \"%s\" must be fired for UPDATE" -msgstr "Funktion „%s“ muss von UPDATE ausgelöst werden" +msgstr "Funktion »%s« muss von UPDATE ausgelöst werden" #: utils/adt/ri_triggers.c:2746 #, c-format msgid "function \"%s\" must be fired for DELETE" -msgstr "Funktion „%s“ muss von DELETE ausgelöst werden" +msgstr "Funktion »%s« muss von DELETE ausgelöst werden" #: utils/adt/ri_triggers.c:2769 #, c-format msgid "no pg_constraint entry for trigger \"%s\" on table \"%s\"" -msgstr "kein „pg_constraint“-Eintrag für Trigger „%s“ für Tabelle „%s“" +msgstr "kein »pg_constraint«-Eintrag für Trigger »%s« für Tabelle »%s«" #: utils/adt/ri_triggers.c:2771 #, c-format @@ -19224,7 +19225,7 @@ msgstr "Entfernen Sie diesen Referentielle-Integritäts-Trigger und seine Partne #: utils/adt/ri_triggers.c:3227 #, c-format msgid "referential integrity query on \"%s\" from constraint \"%s\" on \"%s\" gave unexpected result" -msgstr "RI-Anfrage in Tabelle „%s“ für Constraint „%s“ von Tabelle „%s“ ergab unerwartetes Ergebnis" +msgstr "RI-Anfrage in Tabelle »%s« für Constraint »%s« von Tabelle »%s« ergab unerwartetes Ergebnis" #: utils/adt/ri_triggers.c:3231 #, c-format @@ -19234,27 +19235,27 @@ msgstr "Das liegt höchstwahrscheinlich daran, dass eine Regel die Anfrage umges #: utils/adt/ri_triggers.c:3321 #, c-format msgid "Key (%s)=(%s) is not present in table \"%s\"." -msgstr "Schlüssel (%s)=(%s) ist nicht in Tabelle „%s“ vorhanden." +msgstr "Schlüssel (%s)=(%s) ist nicht in Tabelle »%s« vorhanden." #: utils/adt/ri_triggers.c:3324 #, c-format msgid "Key is not present in table \"%s\"." -msgstr "Der Schlüssel ist nicht in Tabelle „%s“ vorhanden." +msgstr "Der Schlüssel ist nicht in Tabelle »%s« vorhanden." #: utils/adt/ri_triggers.c:3330 #, c-format msgid "update or delete on table \"%s\" violates foreign key constraint \"%s\" on table \"%s\"" -msgstr "Aktualisieren oder Löschen in Tabelle „%s“ verletzt Fremdschlüssel-Constraint „%s“ von Tabelle „%s“" +msgstr "Aktualisieren oder Löschen in Tabelle »%s« verletzt Fremdschlüssel-Constraint »%s« von Tabelle »%s«" #: utils/adt/ri_triggers.c:3335 #, c-format msgid "Key (%s)=(%s) is still referenced from table \"%s\"." -msgstr "Auf Schlüssel (%s)=(%s) wird noch aus Tabelle „%s“ verwiesen." +msgstr "Auf Schlüssel (%s)=(%s) wird noch aus Tabelle »%s« verwiesen." #: utils/adt/ri_triggers.c:3338 #, c-format msgid "Key is still referenced from table \"%s\"." -msgstr "Auf den Schlüssel wird noch aus Tabelle „%s“ verwiesen." +msgstr "Auf den Schlüssel wird noch aus Tabelle »%s« verwiesen." #: utils/adt/rowtypes.c:103 utils/adt/rowtypes.c:479 #, c-format @@ -19265,7 +19266,7 @@ msgstr "Eingabe anonymer zusammengesetzter Typen ist nicht implementiert" #: utils/adt/rowtypes.c:214 utils/adt/rowtypes.c:266 utils/adt/rowtypes.c:274 #, c-format msgid "malformed record literal: \"%s\"" -msgstr "fehlerhafte Record-Konstante: „%s“" +msgstr "fehlerhafte Record-Konstante: »%s«" #: utils/adt/rowtypes.c:156 #, c-format @@ -19317,7 +19318,7 @@ msgstr "kann Record-Typen mit unterschiedlicher Anzahl Spalten nicht vergleichen #: utils/adt/ruleutils.c:4147 #, c-format msgid "rule \"%s\" has unsupported event type %d" -msgstr "Regel „%s“ hat nicht unterstützten Ereignistyp %d" +msgstr "Regel »%s« hat nicht unterstützten Ereignistyp %d" #: utils/adt/selfuncs.c:5260 #, c-format @@ -19332,7 +19333,7 @@ msgstr "Mustersuche mit regulären Ausdrücken wird für Typ bytea nicht unterst #: utils/adt/tid.c:71 utils/adt/tid.c:79 utils/adt/tid.c:87 #, c-format msgid "invalid input syntax for type tid: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ tid: „%s“" +msgstr "ungültige Eingabesyntax für Typ tid: »%s«" #: utils/adt/timestamp.c:99 #, c-format @@ -19347,13 +19348,13 @@ msgstr "Präzision von TIMESTAMP(%d)%s auf erlaubten Höchstwert %d reduziert" #: utils/adt/timestamp.c:170 utils/adt/timestamp.c:444 #, c-format msgid "timestamp out of range: \"%s\"" -msgstr "timestamp ist außerhalb des gültigen Bereichs: „%s“" +msgstr "timestamp ist außerhalb des gültigen Bereichs: »%s«" #: utils/adt/timestamp.c:188 utils/adt/timestamp.c:462 #: utils/adt/timestamp.c:917 #, c-format msgid "date/time value \"%s\" is no longer supported" -msgstr "Datum/Zeit-Wert „%s“ wird nicht mehr unterstützt" +msgstr "Datum/Zeit-Wert »%s« wird nicht mehr unterstützt" #: utils/adt/timestamp.c:258 #, c-format @@ -19368,17 +19369,17 @@ msgstr "Präzision von timestamp(%d) muss zwischen %d und %d sein" #: utils/adt/timestamp.c:512 #, c-format msgid "invalid input syntax for numeric time zone: \"%s\"" -msgstr "ungültige Eingabesyntax für numerische Zeitzone: „%s“" +msgstr "ungültige Eingabesyntax für numerische Zeitzone: »%s«" #: utils/adt/timestamp.c:514 #, c-format msgid "Numeric time zones must have \"-\" or \"+\" as first character." -msgstr "Numerische Zeitzonen müssen „-“ oder „+“ als erstes Zeichen haben." +msgstr "Numerische Zeitzonen müssen »-« oder »+« als erstes Zeichen haben." #: utils/adt/timestamp.c:527 #, c-format msgid "numeric time zone \"%s\" out of range" -msgstr "numerische Zeitzone „%s“ ist außerhalb des gültigen Bereichs" +msgstr "numerische Zeitzone »%s« ist außerhalb des gültigen Bereichs" #: utils/adt/timestamp.c:630 utils/adt/timestamp.c:640 #, c-format @@ -19427,43 +19428,43 @@ msgstr "kann unendliche timestamp-Werte nicht subtrahieren" #: utils/adt/timestamp.c:4506 #, c-format msgid "timestamp units \"%s\" not supported" -msgstr "„timestamp“-Einheit „%s“ nicht unterstützt" +msgstr "»timestamp«-Einheit »%s« nicht unterstützt" #: utils/adt/timestamp.c:3874 utils/adt/timestamp.c:4516 #, c-format msgid "timestamp units \"%s\" not recognized" -msgstr "„timestamp“-Einheit „%s“ nicht erkannt" +msgstr "»timestamp«-Einheit »%s« nicht erkannt" #: utils/adt/timestamp.c:4014 utils/adt/timestamp.c:4697 #: utils/adt/timestamp.c:4718 #, c-format msgid "timestamp with time zone units \"%s\" not supported" -msgstr "„timestamp with time zone“-Einheit „%s“ nicht unterstützt" +msgstr "»timestamp with time zone«-Einheit »%s« nicht unterstützt" #: utils/adt/timestamp.c:4031 utils/adt/timestamp.c:4727 #, c-format msgid "timestamp with time zone units \"%s\" not recognized" -msgstr "„timestamp with time zone“-Einheit „%s“ nicht erkannt" +msgstr "»timestamp with time zone«-Einheit »%s« nicht erkannt" #: utils/adt/timestamp.c:4112 #, c-format msgid "interval units \"%s\" not supported because months usually have fractional weeks" -msgstr "„interval“-Einheit „%s“ wird nicht unterstützt, weil Monate gewöhnlich partielle Wochen haben" +msgstr "»interval«-Einheit »%s« wird nicht unterstützt, weil Monate gewöhnlich partielle Wochen haben" #: utils/adt/timestamp.c:4118 utils/adt/timestamp.c:4833 #, c-format msgid "interval units \"%s\" not supported" -msgstr "„interval“-Einheit „%s“ nicht unterstützt" +msgstr "»interval«-Einheit »%s« nicht unterstützt" #: utils/adt/timestamp.c:4134 utils/adt/timestamp.c:4860 #, c-format msgid "interval units \"%s\" not recognized" -msgstr "„interval“-Einheit „%s“ nicht erkannt" +msgstr "»interval«-Einheit »%s« nicht erkannt" #: utils/adt/timestamp.c:5024 utils/adt/timestamp.c:5254 #, c-format msgid "could not convert to time zone \"%s\"" -msgstr "konnte nicht in Zeitzone „%s“ umwandeln" +msgstr "konnte nicht in Zeitzone »%s« umwandeln" #: utils/adt/trigfuncs.c:42 #, c-format @@ -19494,32 +19495,32 @@ msgstr "gtsvector_in ist nicht implementiert" #: utils/adt/tsvector_parser.c:133 #, c-format msgid "syntax error in tsquery: \"%s\"" -msgstr "Syntaxfehler in tsquery: „%s“" +msgstr "Syntaxfehler in tsquery: »%s«" #: utils/adt/tsquery.c:176 #, c-format msgid "no operand in tsquery: \"%s\"" -msgstr "kein Operand in tsquery: „%s“" +msgstr "kein Operand in tsquery: »%s«" #: utils/adt/tsquery.c:248 #, c-format msgid "value is too big in tsquery: \"%s\"" -msgstr "Wert ist zu groß in tsquery: „%s“" +msgstr "Wert ist zu groß in tsquery: »%s«" #: utils/adt/tsquery.c:253 #, c-format msgid "operand is too long in tsquery: \"%s\"" -msgstr "Operator ist zu lang in tsquery: „%s“" +msgstr "Operator ist zu lang in tsquery: »%s«" #: utils/adt/tsquery.c:281 #, c-format msgid "word is too long in tsquery: \"%s\"" -msgstr "Wort ist zu lang in tsquery: „%s“" +msgstr "Wort ist zu lang in tsquery: »%s«" #: utils/adt/tsquery.c:510 #, c-format msgid "text-search query doesn't contain lexemes: \"%s\"" -msgstr "Textsucheanfrage enthält keine Lexeme: „%s“" +msgstr "Textsucheanfrage enthält keine Lexeme: »%s«" #: utils/adt/tsquery.c:521 utils/adt/tsquery_util.c:340 #, c-format @@ -19574,57 +19575,57 @@ msgstr "ts_stat-Anfrage muss eine tsvector-Spalte zurückgeben" #: utils/adt/tsvector_op.c:1353 #, c-format msgid "tsvector column \"%s\" does not exist" -msgstr "tsvector-Spalte „%s“ existiert nicht" +msgstr "tsvector-Spalte »%s« existiert nicht" #: utils/adt/tsvector_op.c:1359 #, c-format msgid "column \"%s\" is not of tsvector type" -msgstr "Spalte „%s“ hat nicht Typ tsvector" +msgstr "Spalte »%s« hat nicht Typ tsvector" #: utils/adt/tsvector_op.c:1371 #, c-format msgid "configuration column \"%s\" does not exist" -msgstr "Konfigurationsspalte „%s“ existiert nicht" +msgstr "Konfigurationsspalte »%s« existiert nicht" #: utils/adt/tsvector_op.c:1377 #, c-format msgid "column \"%s\" is not of regconfig type" -msgstr "Spalte „%s“ hat nicht Typ regconfig" +msgstr "Spalte »%s« hat nicht Typ regconfig" #: utils/adt/tsvector_op.c:1384 #, c-format msgid "configuration column \"%s\" must not be null" -msgstr "Konfigurationsspalte „%s“ darf nicht NULL sein" +msgstr "Konfigurationsspalte »%s« darf nicht NULL sein" #: utils/adt/tsvector_op.c:1397 #, c-format msgid "text search configuration name \"%s\" must be schema-qualified" -msgstr "Textsuchekonfigurationsname „%s“ muss Schemaqualifikation haben" +msgstr "Textsuchekonfigurationsname »%s« muss Schemaqualifikation haben" #: utils/adt/tsvector_op.c:1422 #, c-format msgid "column \"%s\" is not of a character type" -msgstr "Spalte „%s“ hat keinen Zeichentyp" +msgstr "Spalte »%s« hat keinen Zeichentyp" #: utils/adt/tsvector_parser.c:134 #, c-format msgid "syntax error in tsvector: \"%s\"" -msgstr "Syntaxfehler in tsvector: „%s“" +msgstr "Syntaxfehler in tsvector: »%s«" #: utils/adt/tsvector_parser.c:199 #, c-format msgid "there is no escaped character: \"%s\"" -msgstr "es gibt kein escaptes Zeichen: „%s“" +msgstr "es gibt kein escaptes Zeichen: »%s«" #: utils/adt/tsvector_parser.c:316 #, c-format msgid "wrong position info in tsvector: \"%s\"" -msgstr "falsche Positionsinformationen in tsvector: „%s“" +msgstr "falsche Positionsinformationen in tsvector: »%s«" #: utils/adt/txid.c:339 #, c-format msgid "invalid input syntax for type txid_snapshot: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ txid_snapshot: „%s“" +msgstr "ungültige Eingabesyntax für Typ txid_snapshot: »%s«" #: utils/adt/txid.c:534 #, c-format @@ -19634,7 +19635,7 @@ msgstr "ungültige externe txid_snapshot-Daten" #: utils/adt/uuid.c:128 #, c-format msgid "invalid input syntax for uuid: \"%s\"" -msgstr "ungültige Eingabesyntax für Typ uuid: „%s“" +msgstr "ungültige Eingabesyntax für Typ uuid: »%s«" #: utils/adt/varbit.c:57 utils/adt/varchar.c:49 #, c-format @@ -19659,12 +19660,12 @@ msgstr "Länge der Bitkette %d stimmt nicht mit Typ bit(%d) überein" #: utils/adt/varbit.c:199 utils/adt/varbit.c:511 #, c-format msgid "\"%c\" is not a valid binary digit" -msgstr "„%c“ ist keine gültige Binärziffer" +msgstr "»%c« ist keine gültige Binärziffer" #: utils/adt/varbit.c:224 utils/adt/varbit.c:536 #, c-format msgid "\"%c\" is not a valid hexadecimal digit" -msgstr "„%c“ ist keine gültige Hexadezimalziffer" +msgstr "»%c« ist keine gültige Hexadezimalziffer" #: utils/adt/varbit.c:311 utils/adt/varbit.c:627 #, c-format @@ -19686,17 +19687,17 @@ msgstr "negative Teilzeichenkettenlänge nicht erlaubt" #: utils/adt/varbit.c:1226 #, c-format msgid "cannot AND bit strings of different sizes" -msgstr "binäres „Und“ nicht mit Bitketten unterschiedlicher Länge möglich" +msgstr "binäres »Und« nicht mit Bitketten unterschiedlicher Länge möglich" #: utils/adt/varbit.c:1268 #, c-format msgid "cannot OR bit strings of different sizes" -msgstr "binäres „Oder“ nicht mit Bitketten unterschiedlicher Länge möglich" +msgstr "binäres »Oder« nicht mit Bitketten unterschiedlicher Länge möglich" #: utils/adt/varbit.c:1315 #, c-format msgid "cannot XOR bit strings of different sizes" -msgstr "binäres „Exklusiv-Oder“ nicht mit Bitketten unterschiedlicher Länge möglich" +msgstr "binäres »Exklusiv-Oder« nicht mit Bitketten unterschiedlicher Länge möglich" #: utils/adt/varbit.c:1793 utils/adt/varbit.c:1851 #, c-format @@ -19752,7 +19753,7 @@ msgstr "Formatspezifikation nicht abgeschlossen" #: utils/adt/varlena.c:4708 utils/adt/varlena.c:4828 #, c-format msgid "unrecognized conversion type specifier \"%c\"" -msgstr "unbekannte Konvertierungstypspezifikation „%c“" +msgstr "unbekannte Konvertierungstypspezifikation »%c«" #: utils/adt/varlena.c:4720 utils/adt/varlena.c:4777 #, c-format @@ -19772,7 +19773,7 @@ msgstr "Format gibt Argument 0 an, aber die Argumente sind von 1 an nummeriert" #: utils/adt/varlena.c:4956 #, c-format msgid "width argument position must be ended by \"$\"" -msgstr "Argumentposition der Breitenangabe muss mit „$“ enden" +msgstr "Argumentposition der Breitenangabe muss mit »$« enden" #: utils/adt/varlena.c:5001 #, c-format @@ -19807,7 +19808,7 @@ msgstr "Sie müssen PostgreSQL mit --with-libxml neu bauen." #: utils/adt/xml.c:192 utils/mb/mbutils.c:523 #, c-format msgid "invalid encoding name \"%s\"" -msgstr "ungültiger Kodierungsname „%s“" +msgstr "ungültiger Kodierungsname »%s«" #: utils/adt/xml.c:435 utils/adt/xml.c:440 #, c-format @@ -19827,12 +19828,12 @@ msgstr "ungültige XML-Verarbeitungsanweisung" #: utils/adt/xml.c:729 #, c-format msgid "XML processing instruction target name cannot be \"%s\"." -msgstr "Die Zielangabe der XML-Verarbeitungsanweisung darf nicht „%s“ sein." +msgstr "Die Zielangabe der XML-Verarbeitungsanweisung darf nicht »%s« sein." #: utils/adt/xml.c:752 #, c-format msgid "XML processing instruction cannot contain \"?>\"." -msgstr "XML-Verarbeitungsanweisung darf nicht „?>“ enthalten." +msgstr "XML-Verarbeitungsanweisung darf nicht »?>« enthalten." #: utils/adt/xml.c:831 #, c-format @@ -19869,7 +19870,7 @@ msgstr "Leerzeichen benötigt." #: utils/adt/xml.c:1743 msgid "standalone accepts only 'yes' or 'no'." -msgstr "standalone akzeptiert nur „yes“ oder „no“." +msgstr "standalone akzeptiert nur »yes« oder »no«." #: utils/adt/xml.c:1746 msgid "Malformed declaration: missing version." @@ -19881,7 +19882,7 @@ msgstr "Fehlende Kodierung in Textdeklaration." #: utils/adt/xml.c:1752 msgid "Parsing XML declaration: '?>' expected." -msgstr "Beim Parsen der XML-Deklaration: „?>“ erwartet." +msgstr "Beim Parsen der XML-Deklaration: »?>« erwartet." #: utils/adt/xml.c:1755 #, c-format @@ -19926,7 +19927,7 @@ msgstr "weder Namensraumname noch URI dürfen NULL sein" #: utils/adt/xml.c:3876 #, c-format msgid "could not register XML namespace with name \"%s\" and URI \"%s\"" -msgstr "konnte XML-Namensraum mit Namen „%s“ und URI „%s“ nicht registrieren" +msgstr "konnte XML-Namensraum mit Namen »%s« und URI »%s« nicht registrieren" #: utils/cache/lsyscache.c:2515 utils/cache/lsyscache.c:2548 #: utils/cache/lsyscache.c:2581 utils/cache/lsyscache.c:2614 @@ -19952,7 +19953,7 @@ msgstr "gecachter Plan darf den Ergebnistyp nicht ändern" #: utils/cache/relcache.c:5021 #, c-format msgid "could not create relation-cache initialization file \"%s\": %m" -msgstr "konnte Initialisierungsdatei für Relationscache „%s“ nicht erzeugen: %m" +msgstr "konnte Initialisierungsdatei für Relationscache »%s« nicht erzeugen: %m" #: utils/cache/relcache.c:5023 #, c-format @@ -19962,7 +19963,7 @@ msgstr "Setze trotzdem fort, aber irgendwas stimmt nicht." #: utils/cache/relcache.c:5256 #, c-format msgid "could not remove cache file \"%s\": %m" -msgstr "konnte Cache-Datei „%s“ nicht löschen: %m" +msgstr "konnte Cache-Datei »%s« nicht löschen: %m" #: utils/cache/relmapper.c:508 #, c-format @@ -19972,37 +19973,37 @@ msgstr "PREPARE kann nicht in einer Transaktion ausgeführt werden, die das Rela #: utils/cache/relmapper.c:651 utils/cache/relmapper.c:751 #, c-format msgid "could not open relation mapping file \"%s\": %m" -msgstr "konnte Relation-Mapping-Datei „%s“ nicht öffnen: %m" +msgstr "konnte Relation-Mapping-Datei »%s« nicht öffnen: %m" #: utils/cache/relmapper.c:664 #, c-format msgid "could not read relation mapping file \"%s\": %m" -msgstr "konnte nicht aus Relation-Mapping-Datei „%s“ lesen: %m" +msgstr "konnte nicht aus Relation-Mapping-Datei »%s« lesen: %m" #: utils/cache/relmapper.c:674 #, c-format msgid "relation mapping file \"%s\" contains invalid data" -msgstr "Relation-Mapping-Datei „%s“ enthält ungültige Daten" +msgstr "Relation-Mapping-Datei »%s« enthält ungültige Daten" #: utils/cache/relmapper.c:684 #, c-format msgid "relation mapping file \"%s\" contains incorrect checksum" -msgstr "Relation-Mapping-Datei „%s“ enthält falsche Prüfsumme" +msgstr "Relation-Mapping-Datei »%s« enthält falsche Prüfsumme" #: utils/cache/relmapper.c:784 #, c-format msgid "could not write to relation mapping file \"%s\": %m" -msgstr "konnte nicht in Relation-Mapping-Datei „%s“ schreiben: %m" +msgstr "konnte nicht in Relation-Mapping-Datei »%s« schreiben: %m" #: utils/cache/relmapper.c:797 #, c-format msgid "could not fsync relation mapping file \"%s\": %m" -msgstr "konnte Relation-Mapping-Datei „%s“ nicht fsyncen: %m" +msgstr "konnte Relation-Mapping-Datei »%s« nicht fsyncen: %m" #: utils/cache/relmapper.c:803 #, c-format msgid "could not close relation mapping file \"%s\": %m" -msgstr "konnte Relation-Mapping-Datei „%s“ nicht schließen: %m" +msgstr "konnte Relation-Mapping-Datei »%s« nicht schließen: %m" #: utils/cache/typcache.c:1210 #, c-format @@ -20022,7 +20023,7 @@ msgstr "TRAP: ExceptionalCondition: fehlerhafte Argumente\n" #: utils/error/assert.c:37 #, c-format msgid "TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n" -msgstr "TRAP: %s(„%s“, Datei: „%s“, Zeile: %d)\n" +msgstr "TRAP: %s(»%s«, Datei: »%s«, Zeile: %d)\n" #: utils/error/elog.c:316 utils/error/elog.c:1297 #, c-format @@ -20032,12 +20033,12 @@ msgstr "Fehler geschah bei %s:%d bevor Fehlermeldungsverarbeitung bereit war\n" #: utils/error/elog.c:1864 #, c-format msgid "could not reopen file \"%s\" as stderr: %m" -msgstr "konnte Datei „%s“ nicht als stderr neu öffnen: %m" +msgstr "konnte Datei »%s« nicht als stderr neu öffnen: %m" #: utils/error/elog.c:1877 #, c-format msgid "could not reopen file \"%s\" as stdout: %m" -msgstr "konnte Datei „%s“ nicht als stdou neu öffnen: %m" +msgstr "konnte Datei »%s« nicht als stdou neu öffnen: %m" #: utils/error/elog.c:2353 utils/error/elog.c:2370 utils/error/elog.c:2386 msgid "[unknown]" @@ -20125,22 +20126,22 @@ msgstr "PANIK" #: utils/fmgr/dfmgr.c:117 #, c-format msgid "could not find function \"%s\" in file \"%s\"" -msgstr "konnte Funktion „%s“ nicht in Datei „%s“ finden" +msgstr "konnte Funktion »%s« nicht in Datei »%s« finden" #: utils/fmgr/dfmgr.c:196 utils/fmgr/dfmgr.c:405 utils/fmgr/dfmgr.c:453 #, c-format msgid "could not access file \"%s\": %m" -msgstr "konnte nicht auf Datei „%s“ zugreifen: %m" +msgstr "konnte nicht auf Datei »%s« zugreifen: %m" #: utils/fmgr/dfmgr.c:234 #, c-format msgid "could not load library \"%s\": %s" -msgstr "konnte Bibliothek „%s“ nicht laden: %s" +msgstr "konnte Bibliothek »%s« nicht laden: %s" #: utils/fmgr/dfmgr.c:266 #, c-format msgid "incompatible library \"%s\": missing magic block" -msgstr "inkompatible Bibliothek „%s“: magischer Block fehlt" +msgstr "inkompatible Bibliothek »%s«: magischer Block fehlt" #: utils/fmgr/dfmgr.c:268 #, c-format @@ -20150,7 +20151,7 @@ msgstr "Erweiterungsbibliotheken müssen das Makro PG_MODULE_MAGIC verwenden." #: utils/fmgr/dfmgr.c:304 #, c-format msgid "incompatible library \"%s\": version mismatch" -msgstr "inkompatible Bibliothek „%s“: Version stimmt nicht überein" +msgstr "inkompatible Bibliothek »%s«: Version stimmt nicht überein" #: utils/fmgr/dfmgr.c:306 #, c-format @@ -20189,37 +20190,37 @@ msgstr "Magischer Block hat unerwartete Länge oder unterschiedliches Padding." #: utils/fmgr/dfmgr.c:371 #, c-format msgid "incompatible library \"%s\": magic block mismatch" -msgstr "inkompatible Bibliothek „%s“: magischer Block stimmt überein" +msgstr "inkompatible Bibliothek »%s«: magischer Block stimmt überein" #: utils/fmgr/dfmgr.c:535 #, c-format msgid "access to library \"%s\" is not allowed" -msgstr "Zugriff auf Bibliothek „%s“ ist nicht erlaubt" +msgstr "Zugriff auf Bibliothek »%s« ist nicht erlaubt" #: utils/fmgr/dfmgr.c:561 #, c-format msgid "invalid macro name in dynamic library path: %s" -msgstr "ungültiger Makroname in Parameter „dynamic_library_path“: %s" +msgstr "ungültiger Makroname in Parameter »dynamic_library_path«: %s" #: utils/fmgr/dfmgr.c:601 #, c-format msgid "zero-length component in parameter \"dynamic_library_path\"" -msgstr "eine Komponente im Parameter „dynamic_library_path“ hat Länge null" +msgstr "eine Komponente im Parameter »dynamic_library_path« hat Länge null" #: utils/fmgr/dfmgr.c:620 #, c-format msgid "component in parameter \"dynamic_library_path\" is not an absolute path" -msgstr "eine Komponente im Parameter „dynamic_library_path“ ist kein absoluter Pfad" +msgstr "eine Komponente im Parameter »dynamic_library_path« ist kein absoluter Pfad" #: utils/fmgr/fmgr.c:272 #, c-format msgid "internal function \"%s\" is not in internal lookup table" -msgstr "interne Funktion „%s“ ist nicht in der internen Suchtabelle" +msgstr "interne Funktion »%s« ist nicht in der internen Suchtabelle" #: utils/fmgr/fmgr.c:479 #, c-format msgid "unrecognized API version %d reported by info function \"%s\"" -msgstr "Info-Funktion „%2$s“ berichtete unbekannte API-Version %1$d" +msgstr "Info-Funktion »%2$s« berichtete unbekannte API-Version %1$d" #: utils/fmgr/fmgr.c:849 utils/fmgr/fmgr.c:2110 #, c-format @@ -20234,7 +20235,7 @@ msgstr "Sprachvalidierungsfunktion %u wurde für Sprache %u statt %u aufgerufen" #: utils/fmgr/funcapi.c:355 #, c-format msgid "could not determine actual result type for function \"%s\" declared to return type %s" -msgstr "konnte tatsächlichen Ergebnistyp von Funktion „%s“ mit deklarierten Rückgabetyp %s nicht bestimmen" +msgstr "konnte tatsächlichen Ergebnistyp von Funktion »%s« mit deklarierten Rückgabetyp %s nicht bestimmen" #: utils/fmgr/funcapi.c:1342 utils/fmgr/funcapi.c:1373 #, c-format @@ -20249,17 +20250,17 @@ msgstr "Spaltenalias fehlt" #: utils/fmgr/funcapi.c:1391 #, c-format msgid "could not determine row description for function returning record" -msgstr "konnte Zeilenbeschreibung für Funktion, die „record“ zurückgibt, nicht ermitteln" +msgstr "konnte Zeilenbeschreibung für Funktion, die »record« zurückgibt, nicht ermitteln" #: utils/init/miscinit.c:120 #, c-format msgid "could not change directory to \"%s\": %m" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %m" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %m" #: utils/init/miscinit.c:441 utils/misc/guc.c:5839 #, c-format msgid "cannot set parameter \"%s\" within security-restricted operation" -msgstr "kann Parameter „%s“ nicht in einer sicherheitsbeschränkten Operation setzen" +msgstr "kann Parameter »%s« nicht in einer sicherheitsbeschränkten Operation setzen" #: utils/init/miscinit.c:502 #, c-format @@ -20269,17 +20270,17 @@ msgstr "Rolle mit OID %u existiert nicht" #: utils/init/miscinit.c:532 #, c-format msgid "role \"%s\" is not permitted to log in" -msgstr "Rolle „%s“ hat keine Berechtigung zum Einloggen" +msgstr "Rolle »%s« hat keine Berechtigung zum Einloggen" #: utils/init/miscinit.c:550 #, c-format msgid "too many connections for role \"%s\"" -msgstr "zu viele Verbindungen von Rolle „%s“" +msgstr "zu viele Verbindungen von Rolle »%s«" #: utils/init/miscinit.c:610 #, c-format msgid "permission denied to set session authorization" -msgstr "keine Berechtigung, um Sitzungsauthorisierung zu setzen" +msgstr "keine Berechtigung, um Sitzungsautorisierung zu setzen" #: utils/init/miscinit.c:693 #, c-format @@ -20289,22 +20290,22 @@ msgstr "ungültige Rollen-OID: %u" #: utils/init/miscinit.c:823 #, c-format msgid "could not create lock file \"%s\": %m" -msgstr "konnte Sperrdatei „%s“ nicht erstellen: %m" +msgstr "konnte Sperrdatei »%s« nicht erstellen: %m" #: utils/init/miscinit.c:837 #, c-format msgid "could not open lock file \"%s\": %m" -msgstr "konnte Sperrdatei „%s“ nicht öffnen: %m" +msgstr "konnte Sperrdatei »%s« nicht öffnen: %m" #: utils/init/miscinit.c:843 #, c-format msgid "could not read lock file \"%s\": %m" -msgstr "konnte Sperrdatei „%s“ nicht lesen: %m" +msgstr "konnte Sperrdatei »%s« nicht lesen: %m" #: utils/init/miscinit.c:851 #, c-format msgid "lock file \"%s\" is empty" -msgstr "Sperrdatei „%s“ ist leer" +msgstr "Sperrdatei »%s« ist leer" #: utils/init/miscinit.c:852 #, c-format @@ -20314,27 +20315,27 @@ msgstr "Entweder startet gerade ein anderer Server oder die Sperrdatei ist von e #: utils/init/miscinit.c:899 #, c-format msgid "lock file \"%s\" already exists" -msgstr "Sperrdatei „%s“ existiert bereits" +msgstr "Sperrdatei »%s« existiert bereits" #: utils/init/miscinit.c:903 #, c-format msgid "Is another postgres (PID %d) running in data directory \"%s\"?" -msgstr "Läuft bereits ein anderer postgres-Prozess (PID %d) im Datenverzeichnis „%s“?" +msgstr "Läuft bereits ein anderer postgres-Prozess (PID %d) im Datenverzeichnis »%s«?" #: utils/init/miscinit.c:905 #, c-format msgid "Is another postmaster (PID %d) running in data directory \"%s\"?" -msgstr "Läuft bereits ein anderer postmaster-Prozess (PID %d) im Datenverzeichnis „%s“?" +msgstr "Läuft bereits ein anderer postmaster-Prozess (PID %d) im Datenverzeichnis »%s«?" #: utils/init/miscinit.c:908 #, c-format msgid "Is another postgres (PID %d) using socket file \"%s\"?" -msgstr "Verwendet bereits ein anderer postgres-Prozess (PID %d) die Socketdatei „%s“?" +msgstr "Verwendet bereits ein anderer postgres-Prozess (PID %d) die Socketdatei »%s«?" #: utils/init/miscinit.c:910 #, c-format msgid "Is another postmaster (PID %d) using socket file \"%s\"?" -msgstr "Verwendet bereits ein anderer postmaster-Prozess (PID %d) die Socketdatei „%s“?" +msgstr "Verwendet bereits ein anderer postmaster-Prozess (PID %d) die Socketdatei »%s«?" #: utils/init/miscinit.c:946 #, c-format @@ -20344,12 +20345,12 @@ msgstr "bereits bestehender Shared-Memory-Block (Schlüssel %lu, ID %lu) wird no #: utils/init/miscinit.c:949 #, c-format msgid "If you're sure there are no old server processes still running, remove the shared memory block or just delete the file \"%s\"." -msgstr "Wenn Sie sich sicher sind, dass kein alter Serverprozess mehr läuft, entfernen Sie den Shared-Memory-Block oder löschen Sie einfach die Datei „%s“." +msgstr "Wenn Sie sich sicher sind, dass kein alter Serverprozess mehr läuft, entfernen Sie den Shared-Memory-Block oder löschen Sie einfach die Datei »%s«." #: utils/init/miscinit.c:965 #, c-format msgid "could not remove old lock file \"%s\": %m" -msgstr "konnte alte Sperrdatei „%s“ nicht löschen: %m" +msgstr "konnte alte Sperrdatei »%s« nicht löschen: %m" #: utils/init/miscinit.c:967 #, c-format @@ -20360,37 +20361,37 @@ msgstr "Die Datei ist anscheinend aus Versehen übrig geblieben, konnte aber nic #: utils/init/miscinit.c:1024 #, c-format msgid "could not write lock file \"%s\": %m" -msgstr "konnte Sperrdatei „%s“ nicht schreiben: %m" +msgstr "konnte Sperrdatei »%s« nicht schreiben: %m" #: utils/init/miscinit.c:1153 utils/init/miscinit.c:1282 utils/misc/guc.c:8602 #, c-format msgid "could not read from file \"%s\": %m" -msgstr "konnte nicht aus Datei „%s“ lesen: %m" +msgstr "konnte nicht aus Datei »%s« lesen: %m" #: utils/init/miscinit.c:1272 #, c-format msgid "could not open file \"%s\": %m; continuing anyway" -msgstr "konnte Datei „%s“ nicht öffnen: %m; setze trotzdem fort" +msgstr "konnte Datei »%s« nicht öffnen: %m; setze trotzdem fort" #: utils/init/miscinit.c:1295 #, c-format msgid "lock file \"%s\" contains wrong PID: %ld instead of %ld" -msgstr "Sperrdatei „%s“ enthält falsche PID: %ld statt %ld" +msgstr "Sperrdatei »%s« enthält falsche PID: %ld statt %ld" #: utils/init/miscinit.c:1337 utils/init/miscinit.c:1350 #, c-format msgid "\"%s\" is not a valid data directory" -msgstr "„%s“ ist kein gültiges Datenverzeichnis" +msgstr "»%s« ist kein gültiges Datenverzeichnis" #: utils/init/miscinit.c:1339 #, c-format msgid "File \"%s\" is missing." -msgstr "Die Datei „%s“ fehlt." +msgstr "Die Datei »%s« fehlt." #: utils/init/miscinit.c:1352 #, c-format msgid "File \"%s\" does not contain valid data." -msgstr "Die Datei „%s“ enthält keine gültigen Daten." +msgstr "Die Datei »%s« enthält keine gültigen Daten." #: utils/init/miscinit.c:1354 #, c-format @@ -20405,12 +20406,12 @@ msgstr "Das Datenverzeichnis wurde von PostgreSQL Version %ld.%ld initialisiert, #: utils/init/miscinit.c:1433 #, c-format msgid "loaded library \"%s\"" -msgstr "Bibliothek „%s“ geladen" +msgstr "Bibliothek »%s« geladen" #: utils/init/postinit.c:238 #, c-format msgid "replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)" -msgstr "Replikationsverbindung authorisiert: Benutzer=%s SSL an (Protokoll=%s, Verschlüsselungsmethode=%s, Komprimierung=%s)" +msgstr "Replikationsverbindung autorisiert: Benutzer=%s SSL an (Protokoll=%s, Verschlüsselungsmethode=%s, Komprimierung=%s)" #: utils/init/postinit.c:240 utils/init/postinit.c:254 msgid "off" @@ -20423,37 +20424,37 @@ msgstr "an" #: utils/init/postinit.c:244 #, c-format msgid "replication connection authorized: user=%s" -msgstr "Replikationsverbindung authorisiert: Benutzer=%s" +msgstr "Replikationsverbindung autorisiert: Benutzer=%s" #: utils/init/postinit.c:252 #, c-format msgid "connection authorized: user=%s database=%s SSL enabled (protocol=%s, cipher=%s, compression=%s)" -msgstr "Verbindung authorisiert: Benutzer=%s Datenbank=%s SSL an (Protokoll=%s, Verschlüsselungsmethode=%s, Komprimierung=%s)" +msgstr "Verbindung autorisiert: Benutzer=%s Datenbank=%s SSL an (Protokoll=%s, Verschlüsselungsmethode=%s, Komprimierung=%s)" #: utils/init/postinit.c:258 #, c-format msgid "connection authorized: user=%s database=%s" -msgstr "Verbindung authorisiert: Benutzer=%s Datenbank=%s" +msgstr "Verbindung autorisiert: Benutzer=%s Datenbank=%s" #: utils/init/postinit.c:290 #, c-format msgid "database \"%s\" has disappeared from pg_database" -msgstr "Datenbank „%s“ ist aus pg_database verschwunden" +msgstr "Datenbank »%s« ist aus pg_database verschwunden" #: utils/init/postinit.c:292 #, c-format msgid "Database OID %u now seems to belong to \"%s\"." -msgstr "Datenbank-OID %u gehört jetzt anscheinend zu „%s“." +msgstr "Datenbank-OID %u gehört jetzt anscheinend zu »%s«." #: utils/init/postinit.c:312 #, c-format msgid "database \"%s\" is not currently accepting connections" -msgstr "Datenbank „%s“ akzeptiert gegenwärtig keine Verbindungen" +msgstr "Datenbank »%s« akzeptiert gegenwärtig keine Verbindungen" #: utils/init/postinit.c:325 #, c-format msgid "permission denied for database \"%s\"" -msgstr "keine Berechtigung für Datenbank „%s“" +msgstr "keine Berechtigung für Datenbank »%s«" #: utils/init/postinit.c:326 #, c-format @@ -20463,7 +20464,7 @@ msgstr "Benutzer hat das CONNECT-Privileg nicht." #: utils/init/postinit.c:343 #, c-format msgid "too many connections for database \"%s\"" -msgstr "zu viele Verbindungen für Datenbank „%s“" +msgstr "zu viele Verbindungen für Datenbank »%s«" #: utils/init/postinit.c:365 utils/init/postinit.c:372 #, c-format @@ -20473,7 +20474,7 @@ msgstr "Datenbank-Locale ist inkompatibel mit Betriebssystem" #: utils/init/postinit.c:366 #, c-format msgid "The database was initialized with LC_COLLATE \"%s\", which is not recognized by setlocale()." -msgstr "Die Datenbank wurde mit LC_COLLATE „%s“ initialisiert, was von setlocale() nicht erkannt wird." +msgstr "Die Datenbank wurde mit LC_COLLATE »%s« initialisiert, was von setlocale() nicht erkannt wird." #: utils/init/postinit.c:368 utils/init/postinit.c:375 #, c-format @@ -20483,7 +20484,7 @@ msgstr "Erzeugen Sie die Datenbank neu mit einer anderen Locale oder installiere #: utils/init/postinit.c:373 #, c-format msgid "The database was initialized with LC_CTYPE \"%s\", which is not recognized by setlocale()." -msgstr "Die Datenbank wurde mit LC_CTYPE „%s“ initialisiert, was von setlocale() nicht erkannt wird." +msgstr "Die Datenbank wurde mit LC_CTYPE »%s« initialisiert, was von setlocale() nicht erkannt wird." #: utils/init/postinit.c:699 #, c-format @@ -20533,12 +20534,12 @@ msgstr "Sie wurde anscheinend gerade gelöscht oder umbenannt." #: utils/init/postinit.c:947 #, c-format msgid "The database subdirectory \"%s\" is missing." -msgstr "Das Datenbankunterverzeichnis „%s“ fehlt." +msgstr "Das Datenbankunterverzeichnis »%s« fehlt." #: utils/init/postinit.c:952 #, c-format msgid "could not access directory \"%s\": %m" -msgstr "konnte nicht auf Verzeichnis „%s“ zugreifen: %m" +msgstr "konnte nicht auf Verzeichnis »%s« zugreifen: %m" #: utils/mb/conv.c:360 utils/mb/conv.c:546 #, c-format @@ -20570,7 +20571,7 @@ msgstr "Umwandlung zwischen %s und %s wird nicht unterstützt" #: utils/mb/mbutils.c:366 #, c-format msgid "default conversion function for encoding \"%s\" to \"%s\" does not exist" -msgstr "Standardumwandlung von Kodierung „%s“ nach „%s“ existiert nicht" +msgstr "Standardumwandlung von Kodierung »%s« nach »%s« existiert nicht" #: utils/mb/mbutils.c:377 utils/mb/mbutils.c:710 #, c-format @@ -20580,17 +20581,17 @@ msgstr "Zeichenkette mit %d Bytes ist zu lang für Kodierungsumwandlung." #: utils/mb/mbutils.c:464 #, c-format msgid "invalid source encoding name \"%s\"" -msgstr "ungültiger Quellkodierungsname „%s“" +msgstr "ungültiger Quellkodierungsname »%s«" #: utils/mb/mbutils.c:469 #, c-format msgid "invalid destination encoding name \"%s\"" -msgstr "ungültiger Zielkodierungsname „%s“" +msgstr "ungültiger Zielkodierungsname »%s«" #: utils/mb/mbutils.c:609 #, c-format msgid "invalid byte value for encoding \"%s\": 0x%02x" -msgstr "ungültiger Byte-Wert für Kodierung „%s“: 0x%02x" +msgstr "ungültiger Byte-Wert für Kodierung »%s«: 0x%02x" #: utils/mb/mbutils.c:951 #, c-format @@ -20600,12 +20601,12 @@ msgstr "bind_textdomain_codeset fehlgeschlagen" #: utils/mb/wchar.c:2015 #, c-format msgid "invalid byte sequence for encoding \"%s\": %s" -msgstr "ungültige Byte-Sequenz für Kodierung „%s“: %s" +msgstr "ungültige Byte-Sequenz für Kodierung »%s«: %s" #: utils/mb/wchar.c:2048 #, c-format msgid "character with byte sequence %s in encoding \"%s\" has no equivalent in encoding \"%s\"" -msgstr "Zeichen mit Byte-Folge %s in Kodierung „%s“ hat keine Entsprechung in Kodierung „%s“" +msgstr "Zeichen mit Byte-Folge %s in Kodierung »%s« hat keine Entsprechung in Kodierung »%s«" #: utils/misc/guc.c:535 msgid "Ungrouped" @@ -20797,11 +20798,11 @@ msgstr "Entwickleroptionen" #: utils/misc/guc.c:684 msgid "Valid units for this parameter are \"kB\", \"MB\", \"GB\", and \"TB\"." -msgstr "Gültige Einheiten für diesen Parameter sind „kB“, „MB“, „GB“ und „TB“." +msgstr "Gültige Einheiten für diesen Parameter sind »kB«, »MB«, »GB« und »TB«." #: utils/misc/guc.c:711 msgid "Valid units for this parameter are \"ms\", \"s\", \"min\", \"h\", and \"d\"." -msgstr "Gültige Einheiten für diesen Parameter sind „ms“, „s“, „min“, „h“ und „d“." +msgstr "Gültige Einheiten für diesen Parameter sind »ms«, »s«, »min«, »h« und »d«." #: utils/misc/guc.c:770 msgid "Enables the planner's use of sequential-scan plans." @@ -20889,7 +20890,7 @@ msgstr "Setzt die Verarbeitung trotz Prüfsummenfehler fort." #: utils/misc/guc.c:939 msgid "Detection of a checksum failure normally causes PostgreSQL to report an error, aborting the current transaction. Setting ignore_checksum_failure to true causes the system to ignore the failure (but still report a warning), and continue processing. This behavior could cause crashes or other serious problems. Only has an effect if checksums are enabled." -msgstr "Wenn eine fehlerhafte Prüfsumme entdeckt wird, gibt PostgreSQL normalerweise ein Fehler aus und bricht die aktuelle Transaktion ab. Wenn „ignore_checksum_failure“ an ist, dann wird der Fehler ignoriert (aber trotzdem eine Warnung ausgegeben) und die Verarbeitung geht weiter. Dieses Verhalten kann Abstürze und andere ernsthafte Probleme verursachen. Es hat keine Auswirkungen, wenn Prüfsummen nicht eingeschaltet sind." +msgstr "Wenn eine fehlerhafte Prüfsumme entdeckt wird, gibt PostgreSQL normalerweise ein Fehler aus und bricht die aktuelle Transaktion ab. Wenn »ignore_checksum_failure« an ist, dann wird der Fehler ignoriert (aber trotzdem eine Warnung ausgegeben) und die Verarbeitung geht weiter. Dieses Verhalten kann Abstürze und andere ernsthafte Probleme verursachen. Es hat keine Auswirkungen, wenn Prüfsummen nicht eingeschaltet sind." #: utils/misc/guc.c:953 msgid "Continues processing past damaged page headers." @@ -20897,7 +20898,7 @@ msgstr "Setzt die Verarbeitung trotz kaputter Seitenköpfe fort." #: utils/misc/guc.c:954 msgid "Detection of a damaged page header normally causes PostgreSQL to report an error, aborting the current transaction. Setting zero_damaged_pages to true causes the system to instead report a warning, zero out the damaged page, and continue processing. This behavior will destroy data, namely all the rows on the damaged page." -msgstr "Wenn ein kaputter Seitenkopf entdeckt wird, gibt PostgreSQL normalerweise einen Fehler aus und bricht die aktuelle Transaktion ab. Wenn „zero_damaged_pages“ an ist, dann wird eine Warnung ausgegeben, die kaputte Seite mit Nullen gefüllt und die Verarbeitung geht weiter. Dieses Verhalten zerstört Daten, nämlich alle Zeilen in der kaputten Seite." +msgstr "Wenn ein kaputter Seitenkopf entdeckt wird, gibt PostgreSQL normalerweise einen Fehler aus und bricht die aktuelle Transaktion ab. Wenn »zero_damaged_pages« an ist, dann wird eine Warnung ausgegeben, die kaputte Seite mit Nullen gefüllt und die Verarbeitung geht weiter. Dieses Verhalten zerstört Daten, nämlich alle Zeilen in der kaputten Seite." #: utils/misc/guc.c:967 msgid "Writes full pages to WAL when first modified after a checkpoint." @@ -21057,7 +21058,7 @@ msgstr "Wenn in CREATE USER oder ALTER USER ein Passwort ohne ENCRYPTED oder UNE #: utils/misc/guc.c:1311 msgid "Treats \"expr=NULL\" as \"expr IS NULL\"." -msgstr "Behandelt „ausdruck=NULL“ als „ausdruck IS NULL“." +msgstr "Behandelt »ausdruck=NULL« als »ausdruck IS NULL«." #: utils/misc/guc.c:1312 msgid "When turned on, expressions of the form expr = NULL (or NULL = expr) are treated as expr IS NULL, that is, they return true if expr evaluates to the null value, and false otherwise. The correct behavior of expr = NULL is to always return null (unknown)." @@ -21485,7 +21486,7 @@ msgstr "Setzt die Verzögerung in Millisekunden zwischen Transaktionsabschluss u #: utils/misc/guc.c:2281 msgid "Sets the minimum concurrent open transactions before performing commit_delay." -msgstr "Setzt die minimale Anzahl gleichzeitig offener Transaktionen bevor „commit_delay“ angewendet wird." +msgstr "Setzt die minimale Anzahl gleichzeitig offener Transaktionen bevor »commit_delay« angewendet wird." #: utils/misc/guc.c:2292 msgid "Sets the number of digits displayed for floating-point values." @@ -21825,7 +21826,7 @@ msgstr "Setzt das Ziel für die Serverlogausgabe." #: utils/misc/guc.c:3096 msgid "Valid values are combinations of \"stderr\", \"syslog\", \"csvlog\", and \"eventlog\", depending on the platform." -msgstr "Gültige Werte sind Kombinationen von „stderr“, „syslog“, „csvlog“ und „eventlog“, je nach Plattform." +msgstr "Gültige Werte sind Kombinationen von »stderr«, »syslog«, »csvlog« und »eventlog«, je nach Plattform." #: utils/misc/guc.c:3107 msgid "Sets the destination directory for log files." @@ -21885,11 +21886,11 @@ msgstr "Setzt die Hauptkonfigurationsdatei des Servers." #: utils/misc/guc.c:3245 msgid "Sets the server's \"hba\" configuration file." -msgstr "Setzt die „hba“-Konfigurationsdatei des Servers." +msgstr "Setzt die »hba«-Konfigurationsdatei des Servers." #: utils/misc/guc.c:3256 msgid "Sets the server's \"ident\" configuration file." -msgstr "Setzt die „ident“-Konfigurationsdatei des Servers." +msgstr "Setzt die »ident«-Konfigurationsdatei des Servers." #: utils/misc/guc.c:3267 msgid "Writes the postmaster PID to the specified file." @@ -21941,7 +21942,7 @@ msgstr "Setzt den Namen des Clusters, welcher im Prozesstitel angezeigt wird." #: utils/misc/guc.c:3411 msgid "Sets whether \"\\'\" is allowed in string literals." -msgstr "Bestimmt, ob „\\'“ in Zeichenkettenkonstanten erlaubt ist." +msgstr "Bestimmt, ob »\\'« in Zeichenkettenkonstanten erlaubt ist." #: utils/misc/guc.c:3421 msgid "Sets the output format for bytea." @@ -21990,7 +21991,7 @@ msgstr "Setzt die Anweisungsarten, die geloggt werden." #: utils/misc/guc.c:3516 msgid "Sets the syslog \"facility\" to be used when syslog enabled." -msgstr "Setzt die zu verwendende Syslog-„Facility“, wenn Syslog angeschaltet ist." +msgstr "Setzt die zu verwendende Syslog-»Facility«, wenn Syslog angeschaltet ist." #: utils/misc/guc.c:3531 msgid "Sets the session's behavior for triggers and rewrite rules." @@ -22049,7 +22050,7 @@ msgstr "" #: utils/misc/guc.c:4472 #, c-format msgid "%s cannot access the server configuration file \"%s\": %s\n" -msgstr "%s kann nicht auf die Serverkonfigurationsdatei „%s“ zugreifen: %s\n" +msgstr "%s kann nicht auf die Serverkonfigurationsdatei »%s« zugreifen: %s\n" #: utils/misc/guc.c:4498 #, c-format @@ -22058,7 +22059,7 @@ msgid "" "This can be specified as \"data_directory\" in \"%s\", or by the -D invocation option, or by the PGDATA environment variable.\n" msgstr "" "%s weiß nicht, wo die Systemdaten für das Datenbanksystem\n" -"zu finden sind. Sie können dies mit „data_directory“ in „%s“, mit der\n" +"zu finden sind. Sie können dies mit »data_directory« in »%s«, mit der\n" "Kommandozeilenoption -D oder der Umgebungsvariable PGDATA angeben.\n" #: utils/misc/guc.c:4546 @@ -22067,8 +22068,8 @@ msgid "" "%s does not know where to find the \"hba\" configuration file.\n" "This can be specified as \"hba_file\" in \"%s\", or by the -D invocation option, or by the PGDATA environment variable.\n" msgstr "" -"%s weiß nicht, wo die „hba“-Konfigurationsdatei zu finden ist.\n" -"Sie können dies mit „hba_file“ in „%s“, mit der\n" +"%s weiß nicht, wo die »hba«-Konfigurationsdatei zu finden ist.\n" +"Sie können dies mit »hba_file« in »%s«, mit der\n" "Kommandozeilenoption -D oder der Umgebungsvariable PGDATA angeben.\n" #: utils/misc/guc.c:4569 @@ -22077,8 +22078,8 @@ msgid "" "%s does not know where to find the \"ident\" configuration file.\n" "This can be specified as \"ident_file\" in \"%s\", or by the -D invocation option, or by the PGDATA environment variable.\n" msgstr "" -"%s weiß nicht, wo die „ident“-Konfigurationsdatei zu finden ist.\n" -"Sie können dies mit „ident_file“ in „%s“, mit der\n" +"%s weiß nicht, wo die »ident«-Konfigurationsdatei zu finden ist.\n" +"Sie können dies mit »ident_file« in »%s«, mit der\n" "Kommandozeilenoption -D oder der Umgebungsvariable PGDATA angeben.\n" #: utils/misc/guc.c:5243 utils/misc/guc.c:5290 @@ -22088,12 +22089,12 @@ msgstr "Wert überschreitet Bereich für ganze Zahlen." #: utils/misc/guc.c:5513 #, c-format msgid "parameter \"%s\" requires a numeric value" -msgstr "Parameter „%s“ erfordert einen numerischen Wert" +msgstr "Parameter »%s« erfordert einen numerischen Wert" #: utils/misc/guc.c:5522 #, c-format msgid "%g is outside the valid range for parameter \"%s\" (%g .. %g)" -msgstr "%g ist außerhalb des gültigen Bereichs für Parameter „%s“ (%g ... %g)" +msgstr "%g ist außerhalb des gültigen Bereichs für Parameter »%s« (%g ... %g)" #: utils/misc/guc.c:5675 utils/misc/guc.c:7017 #, c-format @@ -22105,37 +22106,37 @@ msgstr "während einer parallelen Operation können keine Parameter gesetzt werd #: utils/misc/guc.c:9399 #, c-format msgid "unrecognized configuration parameter \"%s\"" -msgstr "unbekannter Konfigurationsparameter „%s“" +msgstr "unbekannter Konfigurationsparameter »%s«" #: utils/misc/guc.c:5697 utils/misc/guc.c:6857 #, c-format msgid "parameter \"%s\" cannot be changed" -msgstr "Parameter „%s“ kann nicht geändert werden" +msgstr "Parameter »%s« kann nicht geändert werden" #: utils/misc/guc.c:5730 #, c-format msgid "parameter \"%s\" cannot be changed now" -msgstr "Parameter „%s“ kann jetzt nicht geändert werden" +msgstr "Parameter »%s« kann jetzt nicht geändert werden" #: utils/misc/guc.c:5748 utils/misc/guc.c:5793 utils/misc/guc.c:9415 #, c-format msgid "permission denied to set parameter \"%s\"" -msgstr "keine Berechtigung, um Parameter „%s“ zu setzen" +msgstr "keine Berechtigung, um Parameter »%s« zu setzen" #: utils/misc/guc.c:5783 #, c-format msgid "parameter \"%s\" cannot be set after connection start" -msgstr "Parameter „%s“ kann nach Start der Verbindung nicht geändert werden" +msgstr "Parameter »%s« kann nach Start der Verbindung nicht geändert werden" #: utils/misc/guc.c:5831 #, c-format msgid "cannot set parameter \"%s\" within security-definer function" -msgstr "Parameter „%s“ kann nicht in einer Security-Definer-Funktion gesetzt werden" +msgstr "Parameter »%s« kann nicht in einer Security-Definer-Funktion gesetzt werden" #: utils/misc/guc.c:6440 utils/misc/guc.c:6488 utils/misc/guc.c:7768 #, c-format msgid "must be superuser to examine \"%s\"" -msgstr "nur Superuser können „%s“ ansehen" +msgstr "nur Superuser können »%s« ansehen" #: utils/misc/guc.c:6554 #, c-format @@ -22155,7 +22156,7 @@ msgstr "Parameterwert für ALTER SYSTEM darf keine Newline enthalten" #: utils/misc/guc.c:6935 #, c-format msgid "could not parse contents of file \"%s\"" -msgstr "konnte Inhalt der Datei „%s“ nicht parsen" +msgstr "konnte Inhalt der Datei »%s« nicht parsen" #: utils/misc/guc.c:7093 #, c-format @@ -22170,32 +22171,32 @@ msgstr "SET benötigt Parameternamen" #: utils/misc/guc.c:7302 #, c-format msgid "attempt to redefine parameter \"%s\"" -msgstr "Versuch, den Parameter „%s“ zu redefinieren" +msgstr "Versuch, den Parameter »%s« zu redefinieren" #: utils/misc/guc.c:9032 #, c-format msgid "parameter \"%s\" could not be set" -msgstr "Parameter „%s“ kann nicht gesetzt werden" +msgstr "Parameter »%s« kann nicht gesetzt werden" #: utils/misc/guc.c:9119 #, c-format msgid "could not parse setting for parameter \"%s\"" -msgstr "konnte Wert von Parameter „%s“ nicht lesen" +msgstr "konnte Wert von Parameter »%s« nicht lesen" #: utils/misc/guc.c:9477 utils/misc/guc.c:9511 #, c-format msgid "invalid value for parameter \"%s\": %d" -msgstr "ungültiger Wert für Parameter „%s“: %d" +msgstr "ungültiger Wert für Parameter »%s«: %d" #: utils/misc/guc.c:9545 #, c-format msgid "invalid value for parameter \"%s\": %g" -msgstr "ungültiger Wert für Parameter „%s“: %g" +msgstr "ungültiger Wert für Parameter »%s«: %g" #: utils/misc/guc.c:9735 #, c-format msgid "\"temp_buffers\" cannot be changed after any temporary tables have been accessed in the session." -msgstr "„temp_buffers“ kann nicht geändert werden, nachdem in der Sitzung auf temporäre Tabellen zugriffen wurde." +msgstr "»temp_buffers« kann nicht geändert werden, nachdem in der Sitzung auf temporäre Tabellen zugriffen wurde." #: utils/misc/guc.c:9747 #, c-format @@ -22210,12 +22211,12 @@ msgstr "SSL wird von dieser Installation nicht unterstützt" #: utils/misc/guc.c:9772 #, c-format msgid "Cannot enable parameter when \"log_statement_stats\" is true." -msgstr "Kann Parameter nicht einschalten, wenn „log_statement_stats“ an ist." +msgstr "Kann Parameter nicht einschalten, wenn »log_statement_stats« an ist." #: utils/misc/guc.c:9784 #, 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." +msgstr "Kann »log_statement_stats« nicht einschalten, wenn »log_parser_stats«, »log_planner_stats« oder »log_executor_stats« an ist." #: utils/misc/help_config.c:131 #, c-format @@ -22225,7 +22226,7 @@ msgstr "interner Fehler: unbekannter Parametertyp\n" #: utils/misc/rls.c:127 #, c-format msgid "query would be affected by row-level security policy for table \"%s\"" -msgstr "Policy für Sicherheit auf Zeilenebene für Tabelle „%s“ würde Auswirkung auf die Anfrage haben" +msgstr "Policy für Sicherheit auf Zeilenebene für Tabelle »%s« würde Auswirkung auf die Anfrage haben" #: utils/misc/rls.c:129 #, c-format @@ -22240,72 +22241,72 @@ msgstr "kann keine weiteren Gründe für Zeitüberschreitungen hinzufügen" #: utils/misc/tzparser.c:61 #, c-format msgid "time zone abbreviation \"%s\" is too long (maximum %d characters) in time zone file \"%s\", line %d" -msgstr "Zeitzonenabkürzung „%s“ ist zu lang (maximal %d Zeichen) in Zeitzonendatei „%s“, Zeile %d" +msgstr "Zeitzonenabkürzung »%s« ist zu lang (maximal %d Zeichen) in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:73 #, c-format msgid "time zone offset %d is out of range in time zone file \"%s\", line %d" -msgstr "Zeitzonenabstand %d ist außerhalb des gültigen Bereichs in Zeitzonendatei „%s“, Zeile %d" +msgstr "Zeitzonenabstand %d ist außerhalb des gültigen Bereichs in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:112 #, c-format msgid "missing time zone abbreviation in time zone file \"%s\", line %d" -msgstr "fehlende Zeitzonenabkürzung in Zeitzonendatei „%s“, Zeile %d" +msgstr "fehlende Zeitzonenabkürzung in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:121 #, c-format msgid "missing time zone offset in time zone file \"%s\", line %d" -msgstr "fehlender Zeitzonenabstand in Zeitzonendatei „%s“, Zeile %d" +msgstr "fehlender Zeitzonenabstand in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:133 #, c-format msgid "invalid number for time zone offset in time zone file \"%s\", line %d" -msgstr "ungültige Zahl für Zeitzonenabstand in Zeitzonendatei „%s“, Zeile %d" +msgstr "ungültige Zahl für Zeitzonenabstand in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:169 #, c-format msgid "invalid syntax in time zone file \"%s\", line %d" -msgstr "ungültige Syntax in Zeitzonendatei „%s“, Zeile %d" +msgstr "ungültige Syntax in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:237 #, c-format msgid "time zone abbreviation \"%s\" is multiply defined" -msgstr "Zeitzonenabkürzung „%s“ ist mehrfach definiert" +msgstr "Zeitzonenabkürzung »%s« ist mehrfach definiert" #: utils/misc/tzparser.c:239 #, c-format msgid "Entry in time zone file \"%s\", line %d, conflicts with entry in file \"%s\", line %d." -msgstr "Eintrag in Zeitzonendatei „%s“, Zeile %d, steht im Konflikt mit Eintrag in Datei „%s“, Zeile %d." +msgstr "Eintrag in Zeitzonendatei »%s«, Zeile %d, steht im Konflikt mit Eintrag in Datei »%s«, Zeile %d." #: utils/misc/tzparser.c:301 #, c-format msgid "invalid time zone file name \"%s\"" -msgstr "ungültiger Zeitzonen-Dateiname „%s“" +msgstr "ungültiger Zeitzonen-Dateiname »%s«" #: utils/misc/tzparser.c:314 #, c-format msgid "time zone file recursion limit exceeded in file \"%s\"" -msgstr "Rekursionsbeschränkung für Zeitzonendatei überschritten in Datei „%s“" +msgstr "Rekursionsbeschränkung für Zeitzonendatei überschritten in Datei »%s«" #: utils/misc/tzparser.c:353 utils/misc/tzparser.c:366 #, c-format msgid "could not read time zone file \"%s\": %m" -msgstr "konnte Zeitzonendatei „%s“ nicht lesen: %m" +msgstr "konnte Zeitzonendatei »%s« nicht lesen: %m" #: utils/misc/tzparser.c:376 #, c-format msgid "line is too long in time zone file \"%s\", line %d" -msgstr "Zeile ist zu lang in Zeitzonendatei „%s“, Zeile %d" +msgstr "Zeile ist zu lang in Zeitzonendatei »%s«, Zeile %d" #: utils/misc/tzparser.c:399 #, c-format msgid "@INCLUDE without file name in time zone file \"%s\", line %d" -msgstr "@INCLUDE ohne Dateiname in Zeitzonendatei „%s“, Zeile %d" +msgstr "@INCLUDE ohne Dateiname in Zeitzonendatei »%s«, Zeile %d" #: utils/mmgr/aset.c:505 #, c-format msgid "Failed while creating memory context \"%s\"." -msgstr "Fehler während der Erzeugung des Speicherkontexts „%s“." +msgstr "Fehler während der Erzeugung des Speicherkontexts »%s«." #: utils/mmgr/mcxt.c:689 utils/mmgr/mcxt.c:724 utils/mmgr/mcxt.c:761 #: utils/mmgr/mcxt.c:798 utils/mmgr/mcxt.c:832 utils/mmgr/mcxt.c:861 @@ -22318,22 +22319,22 @@ msgstr "Fehler bei Anfrage mit Größe %zu." #: utils/mmgr/portalmem.c:208 #, c-format msgid "cursor \"%s\" already exists" -msgstr "Cursor „%s“ existiert bereits" +msgstr "Cursor »%s« existiert bereits" #: utils/mmgr/portalmem.c:212 #, c-format msgid "closing existing cursor \"%s\"" -msgstr "bestehender Cursor „%s“ wird geschlossen" +msgstr "bestehender Cursor »%s« wird geschlossen" #: utils/mmgr/portalmem.c:419 #, c-format msgid "portal \"%s\" cannot be run" -msgstr "Portal „%s“ kann nicht ausgeführt werden" +msgstr "Portal »%s« kann nicht ausgeführt werden" #: utils/mmgr/portalmem.c:499 #, c-format msgid "cannot drop active portal \"%s\"" -msgstr "aktives Portal „%s“ kann nicht gelöscht werden" +msgstr "aktives Portal »%s« kann nicht gelöscht werden" #: utils/mmgr/portalmem.c:689 #, c-format @@ -22348,7 +22349,7 @@ msgstr "konnte Block %ld von temporärer Datei nicht lesen: %m" #: utils/sort/tuplesort.c:3606 #, c-format msgid "could not create unique index \"%s\"" -msgstr "konnte Unique Index „%s“ nicht erstellen" +msgstr "konnte Unique Index »%s« nicht erstellen" #: utils/sort/tuplesort.c:3608 #, c-format @@ -22398,7 +22399,7 @@ msgstr "aus einer Subtransaktion kann kein Snapshot exportiert werden" #: utils/time/snapmgr.c:1310 #, c-format msgid "invalid snapshot data in file \"%s\"" -msgstr "ungültige Snapshot-Daten in Datei „%s“" +msgstr "ungültige Snapshot-Daten in Datei »%s«" #: utils/time/snapmgr.c:1207 #, c-format @@ -22413,7 +22414,7 @@ msgstr "eine Snapshot-importierende Transaktion muss Isolationsgrad SERIALIZABLE #: utils/time/snapmgr.c:1225 utils/time/snapmgr.c:1234 #, c-format msgid "invalid snapshot identifier: \"%s\"" -msgstr "ungültiger Snapshot-Bezeichner: „%s“" +msgstr "ungültiger Snapshot-Bezeichner: »%s«" #: utils/time/snapmgr.c:1323 #, c-format diff --git a/src/backend/po/es.po b/src/backend/po/es.po index 9ea918e9c9..3494a20677 100644 --- a/src/backend/po/es.po +++ b/src/backend/po/es.po @@ -59,7 +59,7 @@ msgstr "" "Project-Id-Version: PostgreSQL server 9.4\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" "POT-Creation-Date: 2015-10-04 00:38+0000\n" -"PO-Revision-Date: 2015-07-06 17:44-0300\n" +"PO-Revision-Date: 2016-07-22 19:04-0400\n" "Last-Translator: Ãlvaro Herrera \n" "Language-Team: PgSQL Español \n" "Language: es\n" @@ -2371,7 +2371,7 @@ msgstr "pg_stop_backup completado, todos los segmentos de WAL requeridos han sid #: access/transam/xlog.c:10538 #, c-format msgid "WAL archiving is not enabled; you must ensure that all required WAL segments are copied through other means to complete the backup" -msgstr "el archivado de WAL no está activo; debe asegurarse que todos los segmentos WAL requeridos se copian por algún otro mecanism para completar el respaldo" +msgstr "el archivado de WAL no está activo; debe asegurarse que todos los segmentos WAL requeridos se copian por algún otro mecanismo para completar el respaldo" #: access/transam/xlog.c:10822 #, c-format diff --git a/src/backend/po/ru.po b/src/backend/po/ru.po index e0b6961ec7..b9fb7d3700 100644 --- a/src/backend/po/ru.po +++ b/src/backend/po/ru.po @@ -27,7 +27,7 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 9 current\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" -"POT-Creation-Date: 2016-02-08 21:38+0000\n" +"POT-Creation-Date: 2016-05-26 20:46+0000\n" "PO-Revision-Date: 2016-02-10 14:52+0300\n" "Last-Translator: Alexander Lakhin \n" "Language-Team: Russian \n" @@ -104,27 +104,27 @@ msgid "could not close directory \"%s\": %s\n" msgstr "не удалоÑÑŒ закрыть каталог \"%s\": %s\n" #: ../common/psprintf.c:179 ../port/path.c:596 ../port/path.c:634 -#: ../port/path.c:651 access/transam/xlog.c:6041 lib/stringinfo.c:258 -#: libpq/auth.c:820 libpq/auth.c:1181 libpq/auth.c:1249 libpq/auth.c:1660 +#: ../port/path.c:651 access/transam/xlog.c:6023 lib/stringinfo.c:258 +#: libpq/auth.c:820 libpq/auth.c:1183 libpq/auth.c:1251 libpq/auth.c:1662 #: postmaster/bgworker.c:289 postmaster/bgworker.c:797 #: postmaster/postmaster.c:2317 postmaster/postmaster.c:2348 #: postmaster/postmaster.c:3867 postmaster/postmaster.c:4557 #: postmaster/postmaster.c:4625 postmaster/postmaster.c:5315 #: postmaster/postmaster.c:5568 replication/logical/logical.c:167 -#: storage/buffer/localbuf.c:396 storage/file/fd.c:481 storage/file/fd.c:878 -#: storage/file/fd.c:996 storage/file/fd.c:1609 storage/ipc/procarray.c:907 +#: storage/buffer/localbuf.c:396 storage/file/fd.c:588 storage/file/fd.c:985 +#: storage/file/fd.c:1103 storage/file/fd.c:1716 storage/ipc/procarray.c:907 #: storage/ipc/procarray.c:1393 storage/ipc/procarray.c:1400 #: storage/ipc/procarray.c:1793 storage/ipc/procarray.c:2377 -#: utils/adt/formatting.c:1523 utils/adt/formatting.c:1643 -#: utils/adt/formatting.c:1764 utils/adt/regexp.c:219 utils/adt/varlena.c:4199 -#: utils/adt/varlena.c:4220 utils/fmgr/dfmgr.c:216 utils/hash/dynahash.c:411 +#: utils/adt/formatting.c:1522 utils/adt/formatting.c:1642 +#: utils/adt/formatting.c:1763 utils/adt/regexp.c:219 utils/adt/varlena.c:4212 +#: utils/adt/varlena.c:4233 utils/fmgr/dfmgr.c:216 utils/hash/dynahash.c:411 #: utils/hash/dynahash.c:488 utils/hash/dynahash.c:1002 utils/mb/mbutils.c:376 #: utils/mb/mbutils.c:709 utils/misc/guc.c:3723 utils/misc/guc.c:3739 #: utils/misc/guc.c:3752 utils/misc/guc.c:6686 utils/misc/tzparser.c:470 #: utils/mmgr/aset.c:504 utils/mmgr/mcxt.c:688 utils/mmgr/mcxt.c:723 #: utils/mmgr/mcxt.c:760 utils/mmgr/mcxt.c:797 utils/mmgr/mcxt.c:831 -#: utils/mmgr/mcxt.c:860 utils/mmgr/mcxt.c:894 utils/mmgr/mcxt.c:974 -#: utils/mmgr/mcxt.c:1007 utils/mmgr/mcxt.c:1054 +#: utils/mmgr/mcxt.c:860 utils/mmgr/mcxt.c:894 utils/mmgr/mcxt.c:976 +#: utils/mmgr/mcxt.c:1010 utils/mmgr/mcxt.c:1059 #, c-format msgid "out of memory" msgstr "нехватка памÑти" @@ -191,7 +191,7 @@ msgstr "ошибка при удалении файла или каталога msgid "could not look up effective user ID %ld: %s" msgstr "выÑÑнить Ñффективный идентификатор Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ (%ld) не удалоÑÑŒ: %s" -#: ../common/username.c:47 libpq/auth.c:1607 +#: ../common/username.c:47 libpq/auth.c:1609 msgid "user does not exist" msgstr "пользователь не ÑущеÑтвует" @@ -235,40 +235,39 @@ msgstr "дочерний процеÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÑ‘Ð½ по Ñигналу %d" msgid "child process exited with unrecognized status %d" msgstr "дочерний процеÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ð»ÑÑ Ñ Ð½ÐµÑ€Ð°Ñпознанным ÑоÑтоÑнием %d" -#: ../port/chklocale.c:259 +#: ../port/chklocale.c:294 #, c-format msgid "could not determine encoding for codeset \"%s\"" msgstr "не удалоÑÑŒ определить кодировку Ð´Ð»Ñ Ð½Ð°Ð±Ð¾Ñ€Ð° Ñимволов \"%s\"" -#: ../port/chklocale.c:260 ../port/chklocale.c:389 -#: postmaster/postmaster.c:4857 +#: ../port/chklocale.c:295 ../port/chklocale.c:424 postmaster/postmaster.c:4857 #, c-format msgid "Please report this to ." msgstr "" "ПожалуйÑта, напишите об Ñтой ошибке по адреÑу ." -#: ../port/chklocale.c:381 ../port/chklocale.c:387 +#: ../port/chklocale.c:416 ../port/chklocale.c:422 #, c-format msgid "could not determine encoding for locale \"%s\": codeset is \"%s\"" msgstr "" "не удалоÑÑŒ определить кодировку Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»Ð¸ \"%s\": набор Ñимволов - \"%s\"" -#: ../port/dirmod.c:216 +#: ../port/dirmod.c:218 #, c-format msgid "could not set junction for \"%s\": %s" msgstr "не удалоÑÑŒ Ñоздать ÑвÑзь Ð´Ð»Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð° \"%s\": %s" -#: ../port/dirmod.c:219 +#: ../port/dirmod.c:221 #, c-format msgid "could not set junction for \"%s\": %s\n" msgstr "не удалоÑÑŒ Ñоздать ÑвÑзь Ð´Ð»Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð° \"%s\": %s\n" -#: ../port/dirmod.c:291 +#: ../port/dirmod.c:295 #, c-format msgid "could not get junction for \"%s\": %s" msgstr "не удалоÑÑŒ получить ÑвÑзь Ð´Ð»Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð° \"%s\": %s" -#: ../port/dirmod.c:294 +#: ../port/dirmod.c:298 #, c-format msgid "could not get junction for \"%s\": %s\n" msgstr "не удалоÑÑŒ получить ÑвÑзь Ð´Ð»Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð° \"%s\": %s\n" @@ -446,13 +445,13 @@ msgid "index row size %zu exceeds maximum %zu for index \"%s\"" msgstr "" "размер Ñтроки индекÑа (%zu) больше предельного размера (%zu) (Ð¸Ð½Ð´ÐµÐºÑ \"%s\")" -#: access/gin/ginscan.c:410 +#: access/gin/ginscan.c:412 #, c-format msgid "old GIN indexes do not support whole-index scans nor searches for nulls" msgstr "" "Ñтарые GIN-индекÑÑ‹ не поддерживают Ñканирование вÑего индекÑа и поиÑк NULL" -#: access/gin/ginscan.c:411 +#: access/gin/ginscan.c:413 #, c-format msgid "To fix this, do REINDEX INDEX \"%s\"." msgstr "Ð”Ð»Ñ Ð¸ÑÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ð¸Ñ‚Ðµ REINDEX INDEX \"%s\"." @@ -471,11 +470,11 @@ msgstr "" "Это вызвано неполным разделением Ñтраницы при воÑÑтановлении поÑле ÑÐ±Ð¾Ñ Ð² " "PostgreSQL до верÑии 9.1." -#: access/gist/gist.c:635 access/gist/gistutil.c:735 -#: access/gist/gistutil.c:746 access/gist/gistvacuum.c:269 -#: access/hash/hashutil.c:172 access/hash/hashutil.c:183 -#: access/hash/hashutil.c:195 access/hash/hashutil.c:216 -#: access/nbtree/nbtpage.c:518 access/nbtree/nbtpage.c:529 +#: access/gist/gist.c:635 access/gist/gistutil.c:735 access/gist/gistutil.c:746 +#: access/gist/gistvacuum.c:269 access/hash/hashutil.c:172 +#: access/hash/hashutil.c:183 access/hash/hashutil.c:195 +#: access/hash/hashutil.c:216 access/nbtree/nbtpage.c:518 +#: access/nbtree/nbtpage.c:529 #, c-format msgid "Please REINDEX it." msgstr "ПожалуйÑта, выполните REINDEX Ð´Ð»Ñ Ð½ÐµÐ³Ð¾." @@ -566,7 +565,7 @@ msgstr "\"%s\" - Ñто индекÑ" #: access/heap/heapam.c:1248 access/heap/heapam.c:1276 #: access/heap/heapam.c:1308 catalog/aclchk.c:1740 commands/tablecmds.c:8954 -#: commands/tablecmds.c:11995 +#: commands/tablecmds.c:12005 #, c-format msgid "\"%s\" is a composite type" msgstr "\"%s\" - Ñто ÑоÑтавной тип" @@ -614,21 +613,20 @@ msgstr "не удалоÑÑŒ запиÑать в файл \"%s\" (запиÑан #: access/heap/rewriteheap.c:965 access/heap/rewriteheap.c:1177 #: access/heap/rewriteheap.c:1274 access/transam/timeline.c:407 -#: access/transam/timeline.c:497 access/transam/xlog.c:3011 -#: access/transam/xlog.c:3173 replication/logical/origin.c:613 -#: replication/logical/snapbuild.c:1592 replication/slot.c:1026 -#: replication/slot.c:1115 storage/file/fd.c:459 storage/file/fd.c:2718 -#: storage/smgr/md.c:982 storage/smgr/md.c:1213 storage/smgr/md.c:1386 -#: utils/misc/guc.c:6708 +#: access/transam/timeline.c:483 access/transam/xlog.c:3011 +#: access/transam/xlog.c:3173 replication/logical/snapbuild.c:1588 +#: replication/slot.c:1026 replication/slot.c:1115 storage/file/fd.c:483 +#: storage/file/fd.c:2847 storage/smgr/md.c:982 storage/smgr/md.c:1213 +#: storage/smgr/md.c:1386 utils/misc/guc.c:6708 #, c-format msgid "could not fsync file \"%s\": %m" msgstr "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ файл \"%s\": %m" #: access/heap/rewriteheap.c:1020 access/heap/rewriteheap.c:1140 -#: access/transam/timeline.c:315 access/transam/timeline.c:475 +#: access/transam/timeline.c:315 access/transam/timeline.c:461 #: access/transam/xlog.c:2967 access/transam/xlog.c:3116 -#: access/transam/xlog.c:10105 access/transam/xlog.c:10141 -#: access/transam/xlog.c:10463 postmaster/postmaster.c:4332 +#: access/transam/xlog.c:10075 access/transam/xlog.c:10111 +#: access/transam/xlog.c:10433 postmaster/postmaster.c:4332 #: replication/logical/origin.c:542 replication/slot.c:983 #: storage/file/copydir.c:162 storage/smgr/md.c:320 utils/time/snapmgr.c:1071 #, c-format @@ -647,25 +645,25 @@ msgid "could not seek to end of file \"%s\": %m" msgstr "не удалоÑÑŒ перейти к концу файла \"%s\": %m" #: access/heap/rewriteheap.c:1167 access/transam/timeline.c:367 -#: access/transam/timeline.c:401 access/transam/timeline.c:491 +#: access/transam/timeline.c:401 access/transam/timeline.c:477 #: access/transam/xlog.c:3002 access/transam/xlog.c:3166 #: postmaster/postmaster.c:4342 postmaster/postmaster.c:4352 #: replication/logical/origin.c:551 replication/logical/origin.c:587 -#: replication/logical/origin.c:603 replication/logical/snapbuild.c:1576 +#: replication/logical/origin.c:603 replication/logical/snapbuild.c:1572 #: replication/slot.c:1012 storage/file/copydir.c:187 -#: utils/init/miscinit.c:1199 utils/init/miscinit.c:1208 -#: utils/init/miscinit.c:1215 utils/misc/guc.c:6669 utils/misc/guc.c:6700 -#: utils/misc/guc.c:8498 utils/misc/guc.c:8512 utils/time/snapmgr.c:1076 +#: utils/init/miscinit.c:1209 utils/init/miscinit.c:1218 +#: utils/init/miscinit.c:1225 utils/misc/guc.c:6669 utils/misc/guc.c:6700 +#: utils/misc/guc.c:8511 utils/misc/guc.c:8525 utils/time/snapmgr.c:1076 #: utils/time/snapmgr.c:1083 #, c-format msgid "could not write to file \"%s\": %m" msgstr "запиÑать в файл \"%s\" не удалоÑÑŒ: %m" -#: access/heap/rewriteheap.c:1250 access/transam/xlog.c:10330 +#: access/heap/rewriteheap.c:1250 access/transam/xlog.c:10300 #: access/transam/xlogarchive.c:114 access/transam/xlogarchive.c:468 -#: replication/logical/origin.c:529 replication/logical/reorderbuffer.c:2421 -#: replication/logical/reorderbuffer.c:2478 -#: replication/logical/snapbuild.c:1520 replication/logical/snapbuild.c:1895 +#: replication/logical/origin.c:529 replication/logical/reorderbuffer.c:2490 +#: replication/logical/reorderbuffer.c:2547 +#: replication/logical/snapbuild.c:1516 replication/logical/snapbuild.c:1891 #: replication/slot.c:1089 storage/ipc/dsm.c:326 storage/smgr/md.c:420 #: storage/smgr/md.c:469 storage/smgr/md.c:1333 #, c-format @@ -675,26 +673,26 @@ msgstr "не удалоÑÑŒ Ñтереть файл \"%s\": %m" #: access/heap/rewriteheap.c:1264 access/transam/timeline.c:111 #: access/transam/timeline.c:236 access/transam/timeline.c:334 #: access/transam/xlog.c:2943 access/transam/xlog.c:3060 -#: access/transam/xlog.c:3101 access/transam/xlog.c:3392 -#: access/transam/xlog.c:3470 replication/basebackup.c:398 +#: access/transam/xlog.c:3101 access/transam/xlog.c:3374 +#: access/transam/xlog.c:3452 replication/basebackup.c:398 #: replication/basebackup.c:1159 replication/logical/logicalfuncs.c:154 -#: replication/logical/origin.c:677 replication/logical/reorderbuffer.c:2038 -#: replication/logical/reorderbuffer.c:2242 -#: replication/logical/reorderbuffer.c:2869 -#: replication/logical/snapbuild.c:1569 replication/logical/snapbuild.c:1653 +#: replication/logical/origin.c:658 replication/logical/reorderbuffer.c:2071 +#: replication/logical/reorderbuffer.c:2284 +#: replication/logical/reorderbuffer.c:2938 +#: replication/logical/snapbuild.c:1565 replication/logical/snapbuild.c:1649 #: replication/slot.c:1104 replication/walsender.c:472 #: replication/walsender.c:2100 storage/file/copydir.c:155 -#: storage/file/fd.c:445 storage/file/fd.c:2653 storage/file/fd.c:2705 +#: storage/file/fd.c:466 storage/file/fd.c:2760 storage/file/fd.c:2826 #: storage/smgr/md.c:602 storage/smgr/md.c:860 utils/error/elog.c:1854 -#: utils/init/miscinit.c:1134 utils/init/miscinit.c:1255 -#: utils/init/miscinit.c:1333 utils/misc/guc.c:6912 utils/misc/guc.c:6944 +#: utils/init/miscinit.c:1144 utils/init/miscinit.c:1265 +#: utils/init/miscinit.c:1343 utils/misc/guc.c:6928 utils/misc/guc.c:6961 #, c-format msgid "could not open file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл \"%s\": %m" #: access/index/indexam.c:172 catalog/objectaddress.c:1144 #: commands/indexcmds.c:1754 commands/tablecmds.c:239 -#: commands/tablecmds.c:11986 +#: commands/tablecmds.c:11996 #, c-format msgid "\"%s\" is not an index" msgstr "\"%s\" - Ñто не индекÑ" @@ -1102,19 +1100,19 @@ msgstr "" "Идентификаторы линий времени должны быть меньше идентификатора линии-потомка." #: access/transam/timeline.c:346 access/transam/xlog.c:3144 -#: access/transam/xlog.c:10312 access/transam/xlog.c:10325 -#: access/transam/xlog.c:10688 access/transam/xlog.c:10731 -#: access/transam/xlog.c:10770 access/transam/xlog.c:10813 +#: access/transam/xlog.c:10282 access/transam/xlog.c:10295 +#: access/transam/xlog.c:10658 access/transam/xlog.c:10701 +#: access/transam/xlog.c:10740 access/transam/xlog.c:10783 #: access/transam/xlogfuncs.c:478 access/transam/xlogfuncs.c:497 -#: commands/extension.c:3047 replication/logical/origin.c:684 -#: replication/logical/origin.c:714 replication/logical/reorderbuffer.c:2887 +#: commands/extension.c:3047 replication/logical/origin.c:665 +#: replication/logical/origin.c:695 replication/logical/reorderbuffer.c:2956 #: replication/walsender.c:497 storage/file/copydir.c:176 #: utils/adt/genfile.c:151 #, c-format msgid "could not read file \"%s\": %m" msgstr "не удалоÑÑŒ прочитать файл \"%s\": %m" -#: access/transam/timeline.c:412 access/transam/timeline.c:502 +#: access/transam/timeline.c:412 access/transam/timeline.c:488 #: access/transam/xlog.c:3017 access/transam/xlog.c:3178 #: access/transam/xlogfuncs.c:503 commands/copy.c:1631 #: storage/file/copydir.c:201 @@ -1122,24 +1120,7 @@ msgstr "не удалоÑÑŒ прочитать файл \"%s\": %m" msgid "could not close file \"%s\": %m" msgstr "не удалоÑÑŒ закрыть файл \"%s\": %m" -#: access/transam/timeline.c:429 access/transam/timeline.c:519 -#, c-format -msgid "could not link file \"%s\" to \"%s\": %m" -msgstr "Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\" не удалоÑÑŒ Ñоздать ÑÑылку \"%s\": %m" - -#: access/transam/timeline.c:436 access/transam/timeline.c:526 -#: access/transam/xlog.c:5302 access/transam/xlog.c:6512 -#: access/transam/xlog.c:6529 access/transam/xlog.c:7310 -#: access/transam/xlogarchive.c:458 access/transam/xlogarchive.c:476 -#: access/transam/xlogarchive.c:586 postmaster/pgarch.c:734 -#: replication/logical/origin.c:624 replication/logical/snapbuild.c:1606 -#: replication/slot.c:470 replication/slot.c:926 replication/slot.c:1038 -#: utils/misc/guc.c:6968 utils/time/snapmgr.c:1094 -#, c-format -msgid "could not rename file \"%s\" to \"%s\": %m" -msgstr "не удалоÑÑŒ переименовать файл \"%s\" в \"%s\": %m" - -#: access/transam/timeline.c:598 +#: access/transam/timeline.c:570 #, c-format msgid "requested timeline %u is not in this server's history" msgstr "в иÑтории Ñервера нет запрошенной линии времени %u" @@ -1476,94 +1457,80 @@ msgstr "Ð¼Ð¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼Ðµ msgid "not enough data in file \"%s\"" msgstr "недоÑтаточно данных в файле\"%s\"" -#: access/transam/xlog.c:3267 -#, c-format -msgid "could not link file \"%s\" to \"%s\" (initialization of log file): %m" -msgstr "" -"Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\" не удалоÑÑŒ Ñоздать ÑÑылку \"%s\" (при инициализации файла " -"журнала): %m" - -#: access/transam/xlog.c:3279 -#, c-format -msgid "could not rename file \"%s\" to \"%s\" (initialization of log file): %m" -msgstr "" -"не удалоÑÑŒ переименовать файл \"%s\" в \"%s\" (при инициализации файла " -"журнала): %m" - -#: access/transam/xlog.c:3307 +#: access/transam/xlog.c:3289 #, c-format msgid "could not open transaction log file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл журнала транзакций \"%s\": %m" -#: access/transam/xlog.c:3496 access/transam/xlog.c:5272 +#: access/transam/xlog.c:3478 access/transam/xlog.c:5254 #, c-format msgid "could not close log file %s: %m" msgstr "не удалоÑÑŒ закрыть файл журнала \"%s\": %m" -#: access/transam/xlog.c:3553 replication/logical/logicalfuncs.c:149 +#: access/transam/xlog.c:3535 replication/logical/logicalfuncs.c:149 #: replication/walsender.c:2095 #, c-format msgid "requested WAL segment %s has already been removed" msgstr "запрошенный Ñегмент WAL %s уже удалён" -#: access/transam/xlog.c:3613 access/transam/xlog.c:3688 -#: access/transam/xlog.c:3886 +#: access/transam/xlog.c:3595 access/transam/xlog.c:3670 +#: access/transam/xlog.c:3868 #, c-format msgid "could not open transaction log directory \"%s\": %m" msgstr "не удалоÑÑŒ открыть каталог журнала транзакций \"%s\": %m" -#: access/transam/xlog.c:3769 +#: access/transam/xlog.c:3751 #, c-format msgid "recycled transaction log file \"%s\"" msgstr "файл журнала транзакций \"%s\" иÑпользуетÑÑ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾" -#: access/transam/xlog.c:3781 +#: access/transam/xlog.c:3763 #, c-format msgid "removing transaction log file \"%s\"" msgstr "файл журнала транзакций \"%s\" удалÑетÑÑ" -#: access/transam/xlog.c:3801 +#: access/transam/xlog.c:3783 #, c-format msgid "could not rename old transaction log file \"%s\": %m" msgstr "не удалоÑÑŒ переименовать Ñтарый файл журнала транзакций \"%s\": %m" -#: access/transam/xlog.c:3813 +#: access/transam/xlog.c:3795 #, c-format msgid "could not remove old transaction log file \"%s\": %m" msgstr "не удалоÑÑŒ Ñтереть Ñтарый файл журнала транзакций \"%s\": %m" -#: access/transam/xlog.c:3846 access/transam/xlog.c:3856 +#: access/transam/xlog.c:3828 access/transam/xlog.c:3838 #, c-format msgid "required WAL directory \"%s\" does not exist" msgstr "требуемый каталог WAL \"%s\" не ÑущеÑтвует" -#: access/transam/xlog.c:3862 +#: access/transam/xlog.c:3844 #, c-format msgid "creating missing WAL directory \"%s\"" msgstr "ÑоздаётÑÑ Ð¾Ñ‚ÑутÑтвующий каталог WAL \"%s\"" -#: access/transam/xlog.c:3865 +#: access/transam/xlog.c:3847 #, c-format msgid "could not create missing directory \"%s\": %m" msgstr "не удалоÑÑŒ Ñоздать отÑутÑтвующий каталог \"%s\": %m" -#: access/transam/xlog.c:3896 +#: access/transam/xlog.c:3878 #, c-format msgid "removing transaction log backup history file \"%s\"" msgstr "удалÑетÑÑ Ñ„Ð°Ð¹Ð» иÑтории ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð°: \"%s\"" -#: access/transam/xlog.c:3977 +#: access/transam/xlog.c:3959 #, c-format msgid "unexpected timeline ID %u in log segment %s, offset %u" msgstr "неожиданный ID линии времени %u в Ñегменте журнала %s, Ñмещение %u" -#: access/transam/xlog.c:4099 +#: access/transam/xlog.c:4081 #, c-format msgid "new timeline %u is not a child of database system timeline %u" msgstr "" "Ð½Ð¾Ð²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ %u не ÑвлÑетÑÑ Ð¾Ñ‚Ð²ÐµÑ‚Ð²Ð»ÐµÐ½Ð¸ÐµÐ¼ линии времени ÑиÑтемы БД %u" -#: access/transam/xlog.c:4113 +#: access/transam/xlog.c:4095 #, c-format msgid "" "new timeline %u forked off current database system timeline %u before " @@ -1572,56 +1539,56 @@ msgstr "" "Ð½Ð¾Ð²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ %u ответвилаÑÑŒ от текущей линии времени базы данных %u " "до текущей точки воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ %X/%X" -#: access/transam/xlog.c:4132 +#: access/transam/xlog.c:4114 #, c-format msgid "new target timeline is %u" msgstr "Ð½Ð¾Ð²Ð°Ñ Ñ†ÐµÐ»ÐµÐ²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ %u" -#: access/transam/xlog.c:4212 +#: access/transam/xlog.c:4194 #, c-format msgid "could not create control file \"%s\": %m" msgstr "не удалоÑÑŒ Ñоздать файл \"%s\": %m" -#: access/transam/xlog.c:4223 access/transam/xlog.c:4459 +#: access/transam/xlog.c:4205 access/transam/xlog.c:4441 #, c-format msgid "could not write to control file: %m" msgstr "не удалоÑÑŒ запиÑать в файл pg_control: %m" -#: access/transam/xlog.c:4229 access/transam/xlog.c:4465 +#: access/transam/xlog.c:4211 access/transam/xlog.c:4447 #, c-format msgid "could not fsync control file: %m" msgstr "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ файл pg_control: %m" -#: access/transam/xlog.c:4234 access/transam/xlog.c:4470 +#: access/transam/xlog.c:4216 access/transam/xlog.c:4452 #, c-format msgid "could not close control file: %m" msgstr "не удалоÑÑŒ закрыть файл pg_control: %m" -#: access/transam/xlog.c:4252 access/transam/xlog.c:4448 +#: access/transam/xlog.c:4234 access/transam/xlog.c:4430 #, c-format msgid "could not open control file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл \"%s\": %m" -#: access/transam/xlog.c:4258 +#: access/transam/xlog.c:4240 #, c-format msgid "could not read from control file: %m" msgstr "не удалоÑÑŒ прочитать файл pg_control: %m" -#: access/transam/xlog.c:4271 access/transam/xlog.c:4280 -#: access/transam/xlog.c:4304 access/transam/xlog.c:4311 -#: access/transam/xlog.c:4318 access/transam/xlog.c:4323 -#: access/transam/xlog.c:4330 access/transam/xlog.c:4337 -#: access/transam/xlog.c:4344 access/transam/xlog.c:4351 -#: access/transam/xlog.c:4358 access/transam/xlog.c:4365 -#: access/transam/xlog.c:4372 access/transam/xlog.c:4381 -#: access/transam/xlog.c:4388 access/transam/xlog.c:4397 -#: access/transam/xlog.c:4404 access/transam/xlog.c:4413 -#: access/transam/xlog.c:4420 utils/init/miscinit.c:1351 +#: access/transam/xlog.c:4253 access/transam/xlog.c:4262 +#: access/transam/xlog.c:4286 access/transam/xlog.c:4293 +#: access/transam/xlog.c:4300 access/transam/xlog.c:4305 +#: access/transam/xlog.c:4312 access/transam/xlog.c:4319 +#: access/transam/xlog.c:4326 access/transam/xlog.c:4333 +#: access/transam/xlog.c:4340 access/transam/xlog.c:4347 +#: access/transam/xlog.c:4354 access/transam/xlog.c:4363 +#: access/transam/xlog.c:4370 access/transam/xlog.c:4379 +#: access/transam/xlog.c:4386 access/transam/xlog.c:4395 +#: access/transam/xlog.c:4402 utils/init/miscinit.c:1361 #, c-format msgid "database files are incompatible with server" msgstr "файлы базы данных не ÑовмеÑтимы Ñ Ñервером" -#: access/transam/xlog.c:4272 +#: access/transam/xlog.c:4254 #, c-format msgid "" "The database cluster was initialized with PG_CONTROL_VERSION %d (0x%08x), " @@ -1630,7 +1597,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ PG_CONTROL_VERSION %d (0x%08x), но " "Ñервер Ñкомпилирован Ñ PG_CONTROL_VERSION %d (0x%08x)." -#: access/transam/xlog.c:4276 +#: access/transam/xlog.c:4258 #, c-format msgid "" "This could be a problem of mismatched byte ordering. It looks like you need " @@ -1639,7 +1606,7 @@ msgstr "" "Возможно, проблема вызвана разным порÑдком байт. КажетÑÑ, вам надо выполнить " "initdb." -#: access/transam/xlog.c:4281 +#: access/transam/xlog.c:4263 #, c-format msgid "" "The database cluster was initialized with PG_CONTROL_VERSION %d, but the " @@ -1648,18 +1615,18 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ PG_CONTROL_VERSION %d, но Ñервер " "Ñкомпилирован Ñ PG_CONTROL_VERSION %d." -#: access/transam/xlog.c:4284 access/transam/xlog.c:4308 -#: access/transam/xlog.c:4315 access/transam/xlog.c:4320 +#: access/transam/xlog.c:4266 access/transam/xlog.c:4290 +#: access/transam/xlog.c:4297 access/transam/xlog.c:4302 #, c-format msgid "It looks like you need to initdb." msgstr "КажетÑÑ, вам надо выполнить initdb." -#: access/transam/xlog.c:4295 +#: access/transam/xlog.c:4277 #, c-format msgid "incorrect checksum in control file" msgstr "ошибка контрольной Ñуммы в файле pg_control" -#: access/transam/xlog.c:4305 +#: access/transam/xlog.c:4287 #, c-format msgid "" "The database cluster was initialized with CATALOG_VERSION_NO %d, but the " @@ -1668,7 +1635,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ CATALOG_VERSION_NO %d, но Ñервер " "Ñкомпилирован Ñ CATALOG_VERSION_NO %d." -#: access/transam/xlog.c:4312 +#: access/transam/xlog.c:4294 #, c-format msgid "" "The database cluster was initialized with MAXALIGN %d, but the server was " @@ -1677,7 +1644,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ MAXALIGN %d, но Ñервер " "Ñкомпилирован Ñ MAXALIGN %d." -#: access/transam/xlog.c:4319 +#: access/transam/xlog.c:4301 #, c-format msgid "" "The database cluster appears to use a different floating-point number format " @@ -1686,7 +1653,7 @@ msgstr "" "КажетÑÑ, в клаÑтере баз данных и в программе Ñервера иÑпользуютÑÑ Ñ€Ð°Ð·Ð½Ñ‹Ðµ " "форматы чиÑел Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой." -#: access/transam/xlog.c:4324 +#: access/transam/xlog.c:4306 #, c-format msgid "" "The database cluster was initialized with BLCKSZ %d, but the server was " @@ -1695,18 +1662,18 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ BLCKSZ %d, но Ñервер Ñкомпилирован " "Ñ BLCKSZ %d." -#: access/transam/xlog.c:4327 access/transam/xlog.c:4334 -#: access/transam/xlog.c:4341 access/transam/xlog.c:4348 -#: access/transam/xlog.c:4355 access/transam/xlog.c:4362 -#: access/transam/xlog.c:4369 access/transam/xlog.c:4376 -#: access/transam/xlog.c:4384 access/transam/xlog.c:4391 -#: access/transam/xlog.c:4400 access/transam/xlog.c:4407 -#: access/transam/xlog.c:4416 access/transam/xlog.c:4423 +#: access/transam/xlog.c:4309 access/transam/xlog.c:4316 +#: access/transam/xlog.c:4323 access/transam/xlog.c:4330 +#: access/transam/xlog.c:4337 access/transam/xlog.c:4344 +#: access/transam/xlog.c:4351 access/transam/xlog.c:4358 +#: access/transam/xlog.c:4366 access/transam/xlog.c:4373 +#: access/transam/xlog.c:4382 access/transam/xlog.c:4389 +#: access/transam/xlog.c:4398 access/transam/xlog.c:4405 #, c-format msgid "It looks like you need to recompile or initdb." msgstr "КажетÑÑ, вам надо перекомпилировать Ñервер или выполнить initdb." -#: access/transam/xlog.c:4331 +#: access/transam/xlog.c:4313 #, c-format msgid "" "The database cluster was initialized with RELSEG_SIZE %d, but the server was " @@ -1715,7 +1682,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ RELSEG_SIZE %d, но Ñервер " "Ñкомпилирован Ñ RELSEG_SIZE %d." -#: access/transam/xlog.c:4338 +#: access/transam/xlog.c:4320 #, c-format msgid "" "The database cluster was initialized with XLOG_BLCKSZ %d, but the server was " @@ -1724,7 +1691,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ XLOG_BLCKSZ %d, но Ñервер " "Ñкомпилирован Ñ XLOG_BLCKSZ %d." -#: access/transam/xlog.c:4345 +#: access/transam/xlog.c:4327 #, c-format msgid "" "The database cluster was initialized with XLOG_SEG_SIZE %d, but the server " @@ -1733,7 +1700,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ XLOG_SEG_SIZE %d, но Ñервер " "Ñкомпилирован Ñ XLOG_SEG_SIZE %d." -#: access/transam/xlog.c:4352 +#: access/transam/xlog.c:4334 #, c-format msgid "" "The database cluster was initialized with NAMEDATALEN %d, but the server was " @@ -1742,7 +1709,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ NAMEDATALEN %d, но Ñервер " "Ñкомпилирован Ñ NAMEDATALEN %d." -#: access/transam/xlog.c:4359 +#: access/transam/xlog.c:4341 #, c-format msgid "" "The database cluster was initialized with INDEX_MAX_KEYS %d, but the server " @@ -1751,7 +1718,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ INDEX_MAX_KEYS %d, но Ñервер " "Ñкомпилирован Ñ INDEX_MAX_KEYS %d." -#: access/transam/xlog.c:4366 +#: access/transam/xlog.c:4348 #, c-format msgid "" "The database cluster was initialized with TOAST_MAX_CHUNK_SIZE %d, but the " @@ -1760,7 +1727,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ TOAST_MAX_CHUNK_SIZE %d, но Ñервер " "Ñкомпилирован Ñ TOAST_MAX_CHUNK_SIZE %d." -#: access/transam/xlog.c:4373 +#: access/transam/xlog.c:4355 #, c-format msgid "" "The database cluster was initialized with LOBLKSIZE %d, but the server was " @@ -1769,7 +1736,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ LOBLKSIZE %d, но Ñервер " "Ñкомпилирован Ñ LOBLKSIZE %d." -#: access/transam/xlog.c:4382 +#: access/transam/xlog.c:4364 #, c-format msgid "" "The database cluster was initialized without HAVE_INT64_TIMESTAMP but the " @@ -1778,7 +1745,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован без HAVE_INT64_TIMESTAMP, но Ñервер " "Ñкомпилирован Ñ HAVE_INT64_TIMESTAMP." -#: access/transam/xlog.c:4389 +#: access/transam/xlog.c:4371 #, c-format msgid "" "The database cluster was initialized with HAVE_INT64_TIMESTAMP but the " @@ -1787,7 +1754,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ HAVE_INT64_TIMESTAMP, но Ñервер " "Ñкомпилирован без HAVE_INT64_TIMESTAMP." -#: access/transam/xlog.c:4398 +#: access/transam/xlog.c:4380 #, c-format msgid "" "The database cluster was initialized without USE_FLOAT4_BYVAL but the server " @@ -1796,7 +1763,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован без USE_FLOAT4_BYVAL, но Ñервер " "Ñкомпилирован Ñ USE_FLOAT4_BYVAL." -#: access/transam/xlog.c:4405 +#: access/transam/xlog.c:4387 #, c-format msgid "" "The database cluster was initialized with USE_FLOAT4_BYVAL but the server " @@ -1805,7 +1772,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ USE_FLOAT4_BYVAL, но Ñервер " "Ñкомпилирован без USE_FLOAT4_BYVAL." -#: access/transam/xlog.c:4414 +#: access/transam/xlog.c:4396 #, c-format msgid "" "The database cluster was initialized without USE_FLOAT8_BYVAL but the server " @@ -1814,7 +1781,7 @@ msgstr "" "КлаÑтер баз данных был инициализирован без USE_FLOAT8_BYVAL, но Ñервер " "Ñкомпилирован Ñ USE_FLOAT8_BYVAL." -#: access/transam/xlog.c:4421 +#: access/transam/xlog.c:4403 #, c-format msgid "" "The database cluster was initialized with USE_FLOAT8_BYVAL but the server " @@ -1823,86 +1790,85 @@ msgstr "" "КлаÑтер баз данных был инициализирован Ñ USE_FLOAT8_BYVAL, но Ñервер был " "Ñкомпилирован без USE_FLOAT8_BYVAL." -#: access/transam/xlog.c:4847 +#: access/transam/xlog.c:4829 #, c-format msgid "could not write bootstrap transaction log file: %m" msgstr "не удалоÑÑŒ запиÑать начальный файл журнала транзакций: %m" -#: access/transam/xlog.c:4853 +#: access/transam/xlog.c:4835 #, c-format msgid "could not fsync bootstrap transaction log file: %m" msgstr "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ начальный файл журнала транзакций: %m" -#: access/transam/xlog.c:4858 +#: access/transam/xlog.c:4840 #, c-format msgid "could not close bootstrap transaction log file: %m" msgstr "не удалоÑÑŒ закрыть начальный файл журнала транзакций: %m" -#: access/transam/xlog.c:4933 +#: access/transam/xlog.c:4915 #, c-format msgid "could not open recovery command file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл команд воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\": %m" -#: access/transam/xlog.c:4979 access/transam/xlog.c:5062 +#: access/transam/xlog.c:4961 access/transam/xlog.c:5044 #, c-format msgid "invalid value for recovery parameter \"%s\": \"%s\"" msgstr "неверное значение Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\": \"%s\"" -#: access/transam/xlog.c:4982 +#: access/transam/xlog.c:4964 #, c-format msgid "Valid values are \"pause\", \"promote\", and \"shutdown\"." msgstr "ДопуÑтимые значениÑ: \"pause\", \"promote\" и \"shutdown\"." -#: access/transam/xlog.c:5001 +#: access/transam/xlog.c:4983 #, c-format msgid "recovery_target_timeline is not a valid number: \"%s\"" msgstr "recovery_target_timeline не ÑвлÑетÑÑ Ð´Ð¾Ð¿ÑƒÑтимым чиÑлом: \"%s\"" -#: access/transam/xlog.c:5017 +#: access/transam/xlog.c:4999 #, c-format msgid "recovery_target_xid is not a valid number: \"%s\"" msgstr "recovery_target_xid не ÑвлÑетÑÑ Ð´Ð¾Ð¿ÑƒÑтимым чиÑлом: \"%s\"" -#: access/transam/xlog.c:5048 +#: access/transam/xlog.c:5030 #, c-format msgid "recovery_target_name is too long (maximum %d characters)" msgstr "длина recovery_target_name превышает предел (%d)" -#: access/transam/xlog.c:5065 +#: access/transam/xlog.c:5047 #, c-format msgid "The only allowed value is \"immediate\"." msgstr "ЕдинÑтвенное допуÑтимое значение: \"immediate\"." -#: access/transam/xlog.c:5078 access/transam/xlog.c:5089 +#: access/transam/xlog.c:5060 access/transam/xlog.c:5071 #: commands/extension.c:531 commands/extension.c:539 utils/misc/guc.c:5464 #, c-format msgid "parameter \"%s\" requires a Boolean value" msgstr "параметр \"%s\" требует логичеÑкое значение" -#: access/transam/xlog.c:5124 +#: access/transam/xlog.c:5106 #, c-format msgid "parameter \"%s\" requires a temporal value" msgstr "параметр \"%s\" требует временное значение" -#: access/transam/xlog.c:5126 catalog/dependency.c:984 -#: catalog/dependency.c:985 catalog/dependency.c:991 catalog/dependency.c:992 -#: catalog/dependency.c:1003 catalog/dependency.c:1004 -#: catalog/objectaddress.c:1053 commands/tablecmds.c:791 -#: commands/tablecmds.c:9415 commands/user.c:1027 commands/view.c:482 -#: libpq/auth.c:285 port/win32/security.c:51 storage/lmgr/deadlock.c:955 -#: storage/lmgr/proc.c:1177 utils/misc/guc.c:5486 utils/misc/guc.c:5579 -#: utils/misc/guc.c:9469 utils/misc/guc.c:9503 utils/misc/guc.c:9537 -#: utils/misc/guc.c:9571 utils/misc/guc.c:9606 +#: access/transam/xlog.c:5108 catalog/dependency.c:984 catalog/dependency.c:985 +#: catalog/dependency.c:991 catalog/dependency.c:992 catalog/dependency.c:1003 +#: catalog/dependency.c:1004 catalog/objectaddress.c:1053 +#: commands/tablecmds.c:791 commands/tablecmds.c:9415 commands/user.c:1027 +#: commands/view.c:482 libpq/auth.c:285 port/win32/security.c:51 +#: storage/lmgr/deadlock.c:955 storage/lmgr/proc.c:1177 utils/misc/guc.c:5486 +#: utils/misc/guc.c:5579 utils/misc/guc.c:9482 utils/misc/guc.c:9516 +#: utils/misc/guc.c:9550 utils/misc/guc.c:9584 utils/misc/guc.c:9619 #, c-format msgid "%s" msgstr "%s" -#: access/transam/xlog.c:5132 +#: access/transam/xlog.c:5114 #, c-format msgid "unrecognized recovery parameter \"%s\"" msgstr "нераÑпознанный параметр воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\"" -#: access/transam/xlog.c:5143 +#: access/transam/xlog.c:5125 #, c-format msgid "" "recovery command file \"%s\" specified neither primary_conninfo nor " @@ -1911,7 +1877,7 @@ msgstr "" "в файле команд воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\" не указан параметр primary_conninfo или " "restore_command" -#: access/transam/xlog.c:5145 +#: access/transam/xlog.c:5127 #, c-format msgid "" "The database server will regularly poll the pg_xlog subdirectory to check " @@ -1920,7 +1886,7 @@ msgstr "" "Сервер БД будет регулÑрно опрашивать подкаталог pg_xlog и проверÑть " "ÑодержащиеÑÑ Ð² нём файлы." -#: access/transam/xlog.c:5151 +#: access/transam/xlog.c:5133 #, c-format msgid "" "recovery command file \"%s\" must specify restore_command when standby mode " @@ -1929,62 +1895,62 @@ msgstr "" "в файле команд воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\" может отÑутÑтвовать restore_command, " "только еÑли Ñто резервный Ñервер" -#: access/transam/xlog.c:5181 +#: access/transam/xlog.c:5163 #, c-format msgid "recovery target timeline %u does not exist" msgstr "Ñ†ÐµÐ»ÐµÐ²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ %u не ÑущеÑтвует" -#: access/transam/xlog.c:5306 +#: access/transam/xlog.c:5284 #, c-format msgid "archive recovery complete" msgstr "воÑÑтановление архива завершено" -#: access/transam/xlog.c:5365 access/transam/xlog.c:5593 +#: access/transam/xlog.c:5343 access/transam/xlog.c:5571 #, c-format msgid "recovery stopping after reaching consistency" msgstr "" "воÑÑтановление оÑтанавливаетÑÑ Ð¿Ð¾Ñле доÑÑ‚Ð¸Ð¶ÐµÐ½Ð¸Ñ ÑоглаÑованного ÑоÑтоÑниÑ" -#: access/transam/xlog.c:5453 +#: access/transam/xlog.c:5431 #, c-format msgid "recovery stopping before commit of transaction %u, time %s" msgstr "" "воÑÑтановление оÑтанавливаетÑÑ Ð¿ÐµÑ€ÐµÐ´ фикÑированием транзакции %u, Ð²Ñ€ÐµÐ¼Ñ %s" -#: access/transam/xlog.c:5460 +#: access/transam/xlog.c:5438 #, c-format msgid "recovery stopping before abort of transaction %u, time %s" msgstr "" "воÑÑтановление оÑтанавливаетÑÑ Ð¿ÐµÑ€ÐµÐ´ прерыванием транзакции %u, Ð²Ñ€ÐµÐ¼Ñ %s" -#: access/transam/xlog.c:5505 +#: access/transam/xlog.c:5483 #, c-format msgid "recovery stopping at restore point \"%s\", time %s" msgstr "воÑÑтановление оÑтанавливаетÑÑ Ð² точке воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\", Ð²Ñ€ÐµÐ¼Ñ %s" -#: access/transam/xlog.c:5573 +#: access/transam/xlog.c:5551 #, c-format msgid "recovery stopping after commit of transaction %u, time %s" msgstr "" "воÑÑтановление оÑтанавливаетÑÑ Ð¿Ð¾Ñле фикÑÐ¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¸ %u, Ð²Ñ€ÐµÐ¼Ñ %s" -#: access/transam/xlog.c:5581 +#: access/transam/xlog.c:5559 #, c-format msgid "recovery stopping after abort of transaction %u, time %s" msgstr "" "воÑÑтановление оÑтанавливаетÑÑ Ð¿Ð¾Ñле Ð¿Ñ€ÐµÑ€Ñ‹Ð²Ð°Ð½Ð¸Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¸ %u, Ð²Ñ€ÐµÐ¼Ñ %s" -#: access/transam/xlog.c:5620 +#: access/transam/xlog.c:5598 #, c-format msgid "recovery has paused" msgstr "воÑÑтановление приоÑтановлено" -#: access/transam/xlog.c:5621 +#: access/transam/xlog.c:5599 #, c-format msgid "Execute pg_xlog_replay_resume() to continue." msgstr "Выполните pg_xlog_replay_resume() Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶ÐµÐ½Ð¸Ñ." -#: access/transam/xlog.c:5824 +#: access/transam/xlog.c:5806 #, c-format msgid "" "hot standby is not possible because %s = %d is a lower setting than on the " @@ -1993,12 +1959,12 @@ msgstr "" "режим горÑчего резерва невозможен, так как параметр %s = %d, меньше чем на " "главном Ñервере (на нём было значение %d)" -#: access/transam/xlog.c:5850 +#: access/transam/xlog.c:5832 #, c-format msgid "WAL was generated with wal_level=minimal, data may be missing" msgstr "WAL был Ñоздан Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ wal_level=minimal, возможна Ð¿Ð¾Ñ‚ÐµÑ€Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…" -#: access/transam/xlog.c:5851 +#: access/transam/xlog.c:5833 #, c-format msgid "" "This happens if you temporarily set wal_level=minimal without taking a new " @@ -2007,7 +1973,7 @@ msgstr "" "Это проиÑходит, еÑли вы на Ð²Ñ€ÐµÐ¼Ñ ÑƒÑтановили wal_level=minimal и не Ñделали " "резервную копию базу данных." -#: access/transam/xlog.c:5862 +#: access/transam/xlog.c:5844 #, c-format msgid "" "hot standby is not possible because wal_level was not set to \"hot_standby\" " @@ -2016,7 +1982,7 @@ msgstr "" "режим горÑчего резерва невозможен, так как на главном Ñервере уÑтановлен " "неподходÑщий wal_level (должен быть \"hot_standby\" или выше)" -#: access/transam/xlog.c:5863 +#: access/transam/xlog.c:5845 #, c-format msgid "" "Either set wal_level to \"hot_standby\" on the master, or turn off " @@ -2025,32 +1991,32 @@ msgstr "" "Либо уÑтановите Ð´Ð»Ñ wal_level значение \"hot_standby\" на главном Ñервере, " "либо выключите hot_standby здеÑÑŒ." -#: access/transam/xlog.c:5920 +#: access/transam/xlog.c:5902 #, c-format msgid "control file contains invalid data" msgstr "файл pg_control Ñодержит неверные данные" -#: access/transam/xlog.c:5926 +#: access/transam/xlog.c:5908 #, c-format msgid "database system was shut down at %s" msgstr "ÑиÑтема БД была выключена: %s" -#: access/transam/xlog.c:5931 +#: access/transam/xlog.c:5913 #, c-format msgid "database system was shut down in recovery at %s" msgstr "ÑиÑтема БД была выключена в процеÑÑе воÑÑтановлениÑ: %s" -#: access/transam/xlog.c:5935 +#: access/transam/xlog.c:5917 #, c-format msgid "database system shutdown was interrupted; last known up at %s" msgstr "выключение ÑиÑтемы БД было прервано; поÑледний момент работы: %s" -#: access/transam/xlog.c:5939 +#: access/transam/xlog.c:5921 #, c-format msgid "database system was interrupted while in recovery at %s" msgstr "работа ÑиÑтемы БД была прервана во Ð²Ñ€ÐµÐ¼Ñ Ð²Ð¾ÑÑтановлениÑ: %s" -#: access/transam/xlog.c:5941 +#: access/transam/xlog.c:5923 #, c-format msgid "" "This probably means that some data is corrupted and you will have to use the " @@ -2059,14 +2025,14 @@ msgstr "" "Это Ñкорее вÑего означает, что некоторые данные повреждены и вам придётÑÑ " "воÑÑтановить БД из поÑледней резервной копии." -#: access/transam/xlog.c:5945 +#: access/transam/xlog.c:5927 #, c-format msgid "database system was interrupted while in recovery at log time %s" msgstr "" "работа ÑиÑтемы БД была прервана в процеÑÑе воÑÑтановлениÑ, Ð²Ñ€ÐµÐ¼Ñ Ð² журнале: " "%s" -#: access/transam/xlog.c:5947 +#: access/transam/xlog.c:5929 #, c-format msgid "" "If this has occurred more than once some data might be corrupted and you " @@ -2075,58 +2041,58 @@ msgstr "" "ЕÑли Ñто проиÑходит поÑтоÑнно, возможно, какие-то данные были иÑпорчены и " "Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñтоит выбрать более раннюю точку." -#: access/transam/xlog.c:5951 +#: access/transam/xlog.c:5933 #, c-format msgid "database system was interrupted; last known up at %s" msgstr "работа ÑиÑтемы БД была прервана; поÑледний момент работы: %s" -#: access/transam/xlog.c:6007 +#: access/transam/xlog.c:5989 #, c-format msgid "entering standby mode" msgstr "переход в режим резервного Ñервера" -#: access/transam/xlog.c:6010 +#: access/transam/xlog.c:5992 #, c-format msgid "starting point-in-time recovery to XID %u" msgstr "начинаетÑÑ Ð²Ð¾ÑÑтановление точки во времени до XID %u" -#: access/transam/xlog.c:6014 +#: access/transam/xlog.c:5996 #, c-format msgid "starting point-in-time recovery to %s" msgstr "начинаетÑÑ Ð²Ð¾ÑÑтановление точки во времени до %s" -#: access/transam/xlog.c:6018 +#: access/transam/xlog.c:6000 #, c-format msgid "starting point-in-time recovery to \"%s\"" msgstr "начинаетÑÑ Ð²Ð¾ÑÑтановление точки во времени до \"%s\"" -#: access/transam/xlog.c:6022 +#: access/transam/xlog.c:6004 #, c-format msgid "starting point-in-time recovery to earliest consistent point" msgstr "" "начинаетÑÑ Ð²Ð¾ÑÑтановление точки во времени до первой точки ÑоглаÑованноÑти" -#: access/transam/xlog.c:6025 +#: access/transam/xlog.c:6007 #, c-format msgid "starting archive recovery" msgstr "начинаетÑÑ Ð²Ð¾ÑÑтановление архива" -#: access/transam/xlog.c:6042 +#: access/transam/xlog.c:6024 #, c-format msgid "Failed while allocating an XLog reading processor." msgstr "Ðе удалоÑÑŒ размеÑтить обработчик журнала транзакций." -#: access/transam/xlog.c:6069 access/transam/xlog.c:6197 +#: access/transam/xlog.c:6051 access/transam/xlog.c:6179 #, c-format msgid "checkpoint record is at %X/%X" msgstr "запиÑÑŒ о контрольной точке по Ñмещению %X/%X" -#: access/transam/xlog.c:6083 +#: access/transam/xlog.c:6065 #, c-format msgid "could not find redo location referenced by checkpoint record" msgstr "не удалоÑÑŒ найти положение REDO, указанное запиÑью контрольной точки" -#: access/transam/xlog.c:6084 access/transam/xlog.c:6091 +#: access/transam/xlog.c:6066 access/transam/xlog.c:6073 #, c-format msgid "" "If you are not restoring from a backup, try removing the file \"%s/" @@ -2135,52 +2101,52 @@ msgstr "" "ЕÑли вы не воÑÑтанавливаете БД из резервной копии, попробуйте удалить файл " "\"%s/backup_label\"." -#: access/transam/xlog.c:6090 +#: access/transam/xlog.c:6072 #, c-format msgid "could not locate required checkpoint record" msgstr "не удалоÑÑŒ Ñчитать нужную запиÑÑŒ контрольной точки" -#: access/transam/xlog.c:6116 commands/tablespace.c:641 +#: access/transam/xlog.c:6098 commands/tablespace.c:641 #, c-format msgid "could not create symbolic link \"%s\": %m" msgstr "не удалоÑÑŒ Ñоздать ÑимволичеÑкую ÑÑылку \"%s\": %m" -#: access/transam/xlog.c:6148 +#: access/transam/xlog.c:6130 #, c-format msgid "ignoring file \"%s\" because no file \"%s\" exists" msgstr "файл \"%s\" игнорируетÑÑ Ð²Ð²Ð¸Ð´Ñƒ отÑутÑÑ‚Ð²Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\"" -#: access/transam/xlog.c:6150 access/transam/xlog.c:10888 +#: access/transam/xlog.c:6132 access/transam/xlog.c:10858 #, c-format msgid "File \"%s\" was renamed to \"%s\"." msgstr "Файл \"%s\" был переименован в \"%s\"." -#: access/transam/xlog.c:6154 +#: access/transam/xlog.c:6136 #, c-format msgid "ignoring \"%s\" file because no \"%s\" file exists" msgstr "файл \"%s\" игнорируетÑÑ Ð²Ð²Ð¸Ð´Ñƒ отÑутÑÑ‚Ð²Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\"" -#: access/transam/xlog.c:6156 +#: access/transam/xlog.c:6138 #, c-format msgid "Could not rename file \"%s\" to \"%s\": %m." msgstr "Ðе удалоÑÑŒ переименовать файл \"%s\" в \"%s\" (%m)." -#: access/transam/xlog.c:6207 access/transam/xlog.c:6222 +#: access/transam/xlog.c:6189 access/transam/xlog.c:6204 #, c-format msgid "could not locate a valid checkpoint record" msgstr "не удалоÑÑŒ Ñчитать правильную запиÑÑŒ контрольной точки" -#: access/transam/xlog.c:6216 +#: access/transam/xlog.c:6198 #, c-format msgid "using previous checkpoint record at %X/%X" msgstr "иÑпользуетÑÑ Ð¿Ñ€ÐµÐ´Ñ‹Ð´ÑƒÑ‰Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ контрольной точки по Ñмещению %X/%X" -#: access/transam/xlog.c:6260 +#: access/transam/xlog.c:6242 #, c-format msgid "requested timeline %u is not a child of this server's history" msgstr "в иÑтории Ñервера нет Ð¾Ñ‚Ð²ÐµÑ‚Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ð¾Ð¹ линии времени %u" -#: access/transam/xlog.c:6262 +#: access/transam/xlog.c:6244 #, c-format msgid "" "Latest checkpoint is at %X/%X on timeline %u, but in the history of the " @@ -2189,7 +2155,7 @@ msgstr "" "ПоÑледнÑÑ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ°: %X/%X на линии времени %u, но в иÑтории " "запрошенной линии времени Ñервер ответвилÑÑ Ñ Ñтой линии в %X/%X." -#: access/transam/xlog.c:6278 +#: access/transam/xlog.c:6260 #, c-format msgid "" "requested timeline %u does not contain minimum recovery point %X/%X on " @@ -2198,22 +2164,22 @@ msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ %u не Ñодержит минимальную точку воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ %X/" "%X на линии времени %u" -#: access/transam/xlog.c:6309 +#: access/transam/xlog.c:6291 #, c-format msgid "invalid next transaction ID" msgstr "неверный ID Ñледующей транзакции" -#: access/transam/xlog.c:6392 +#: access/transam/xlog.c:6374 #, c-format msgid "invalid redo in checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ REDO в контрольной точке" -#: access/transam/xlog.c:6403 +#: access/transam/xlog.c:6385 #, c-format msgid "invalid redo record in shutdown checkpoint" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ REDO в контрольной точке выключениÑ" -#: access/transam/xlog.c:6431 +#: access/transam/xlog.c:6413 #, c-format msgid "" "database system was not properly shut down; automatic recovery in progress" @@ -2221,19 +2187,19 @@ msgstr "" "ÑиÑтема БД была оÑтановлена нештатно; производитÑÑ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкое " "воÑÑтановление" -#: access/transam/xlog.c:6435 +#: access/transam/xlog.c:6417 #, c-format msgid "crash recovery starts in timeline %u and has target timeline %u" msgstr "" "воÑÑтановление поÑле ÑÐ±Ð¾Ñ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÐµÑ‚ÑÑ Ð½Ð° линии времени %u, Ñ†ÐµÐ»ÐµÐ²Ð°Ñ Ð»Ð¸Ð½Ð¸Ñ " "времени: %u" -#: access/transam/xlog.c:6479 +#: access/transam/xlog.c:6461 #, c-format msgid "backup_label contains data inconsistent with control file" msgstr "backup_label Ñодержит данные, не ÑоглаÑованные Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð¼ pg_control" -#: access/transam/xlog.c:6480 +#: access/transam/xlog.c:6462 #, c-format msgid "" "This means that the backup is corrupted and you will have to use another " @@ -2242,44 +2208,44 @@ msgstr "" "Это означает, что Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð¿Ð¾Ð²Ñ€ÐµÐ¶Ð´ÐµÐ½Ð° и Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð‘Ð” " "придётÑÑ Ð¸Ñпользовать другую копию." -#: access/transam/xlog.c:6562 +#: access/transam/xlog.c:6536 #, c-format msgid "initializing for hot standby" msgstr "Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð»Ñ Ð³Ð¾Ñ€Ñчего резерва" -#: access/transam/xlog.c:6694 +#: access/transam/xlog.c:6668 #, c-format msgid "redo starts at %X/%X" msgstr "запиÑÑŒ REDO начинаетÑÑ Ñо ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ %X/%X" -#: access/transam/xlog.c:6908 +#: access/transam/xlog.c:6882 #, c-format msgid "requested recovery stop point is before consistent recovery point" msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° оÑтановки воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´ÑˆÐµÑтвует ÑоглаÑованной точке " "воÑÑтановлениÑ" -#: access/transam/xlog.c:6946 +#: access/transam/xlog.c:6920 #, c-format msgid "redo done at %X/%X" msgstr "запиÑи REDO обработаны до ÑÐ¼ÐµÑ‰ÐµÐ½Ð¸Ñ %X/%X" -#: access/transam/xlog.c:6951 access/transam/xlog.c:8885 +#: access/transam/xlog.c:6925 access/transam/xlog.c:8855 #, c-format msgid "last completed transaction was at log time %s" msgstr "поÑледнÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÑ‘Ð½Ð½Ð°Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ Ð±Ñ‹Ð»Ð° выполнена в %s" -#: access/transam/xlog.c:6960 +#: access/transam/xlog.c:6934 #, c-format msgid "redo is not required" msgstr "данные REDO не требуютÑÑ" -#: access/transam/xlog.c:7035 access/transam/xlog.c:7039 +#: access/transam/xlog.c:7009 access/transam/xlog.c:7013 #, c-format msgid "WAL ends before end of online backup" msgstr "WAL закончилÑÑ Ð±ÐµÐ· признака Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ" -#: access/transam/xlog.c:7036 +#: access/transam/xlog.c:7010 #, c-format msgid "" "All WAL generated while online backup was taken must be available at " @@ -2288,7 +2254,7 @@ msgstr "" "Ð’Ñе журналы WAL, Ñозданные во Ð²Ñ€ÐµÐ¼Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð³Ð¾ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"на ходу\", " "должны быть в наличии Ð´Ð»Ñ Ð²Ð¾ÑÑтановлениÑ." -#: access/transam/xlog.c:7040 +#: access/transam/xlog.c:7014 #, c-format msgid "" "Online backup started with pg_start_backup() must be ended with " @@ -2298,107 +2264,107 @@ msgstr "" "должно закончитьÑÑ pg_stop_backup(), и Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ‹ быть " "доÑтупны вÑе журналы WAL." -#: access/transam/xlog.c:7043 +#: access/transam/xlog.c:7017 #, c-format msgid "WAL ends before consistent recovery point" msgstr "WAL закончилÑÑ Ð´Ð¾ ÑоглаÑованной точки воÑÑтановлениÑ" -#: access/transam/xlog.c:7070 +#: access/transam/xlog.c:7044 #, c-format msgid "selected new timeline ID: %u" msgstr "выбранный ID новой линии времени: %u" -#: access/transam/xlog.c:7485 +#: access/transam/xlog.c:7455 #, c-format msgid "consistent recovery state reached at %X/%X" msgstr "ÑоглаÑованное ÑоÑтоÑние воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð¾Ñтигнуто по Ñмещению %X/%X" -#: access/transam/xlog.c:7676 +#: access/transam/xlog.c:7646 #, c-format msgid "invalid primary checkpoint link in control file" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑÑылка на первичную контрольную точку в файле pg_control" -#: access/transam/xlog.c:7680 +#: access/transam/xlog.c:7650 #, c-format msgid "invalid secondary checkpoint link in control file" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑÑылка на вторичную контрольную точку в файле pg_control" -#: access/transam/xlog.c:7684 +#: access/transam/xlog.c:7654 #, c-format msgid "invalid checkpoint link in backup_label file" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑÑылка на контрольную точку в файле backup_label" -#: access/transam/xlog.c:7701 +#: access/transam/xlog.c:7671 #, c-format msgid "invalid primary checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ первичной контрольной точки" -#: access/transam/xlog.c:7705 +#: access/transam/xlog.c:7675 #, c-format msgid "invalid secondary checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ вторичной контрольной точки" -#: access/transam/xlog.c:7709 +#: access/transam/xlog.c:7679 #, c-format msgid "invalid checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ контрольной точки" -#: access/transam/xlog.c:7720 +#: access/transam/xlog.c:7690 #, c-format msgid "invalid resource manager ID in primary checkpoint record" msgstr "неверный ID менеджера реÑурÑов в запиÑи первичной контрольной точки" -#: access/transam/xlog.c:7724 +#: access/transam/xlog.c:7694 #, c-format msgid "invalid resource manager ID in secondary checkpoint record" msgstr "неверный ID менеджера реÑурÑов в запиÑи вторичной контрольной точки" -#: access/transam/xlog.c:7728 +#: access/transam/xlog.c:7698 #, c-format msgid "invalid resource manager ID in checkpoint record" msgstr "неверный ID менеджера реÑурÑов в запиÑи контрольной точки" -#: access/transam/xlog.c:7740 +#: access/transam/xlog.c:7710 #, c-format msgid "invalid xl_info in primary checkpoint record" msgstr "неверные флаги xl_info в запиÑи первичной контрольной точки" -#: access/transam/xlog.c:7744 +#: access/transam/xlog.c:7714 #, c-format msgid "invalid xl_info in secondary checkpoint record" msgstr "неверные флаги xl_info в запиÑи вторичной контрольной точки" -#: access/transam/xlog.c:7748 +#: access/transam/xlog.c:7718 #, c-format msgid "invalid xl_info in checkpoint record" msgstr "неверные флаги xl_info в запиÑи контрольной точки" -#: access/transam/xlog.c:7759 +#: access/transam/xlog.c:7729 #, c-format msgid "invalid length of primary checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° запиÑи первичной контрольной точки" -#: access/transam/xlog.c:7763 +#: access/transam/xlog.c:7733 #, c-format msgid "invalid length of secondary checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° запиÑи вторичной контрольной точки" -#: access/transam/xlog.c:7767 +#: access/transam/xlog.c:7737 #, c-format msgid "invalid length of checkpoint record" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° запиÑи контрольной точки" -#: access/transam/xlog.c:7937 +#: access/transam/xlog.c:7907 #, c-format msgid "shutting down" msgstr "выключение" -#: access/transam/xlog.c:7961 +#: access/transam/xlog.c:7931 #, c-format msgid "database system is shut down" msgstr "ÑиÑтема БД выключена" -#: access/transam/xlog.c:8454 +#: access/transam/xlog.c:8424 #, c-format msgid "" "concurrent transaction log activity while database system is shutting down" @@ -2406,29 +2372,29 @@ msgstr "" "во Ð²Ñ€ÐµÐ¼Ñ Ð²Ñ‹ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ ÑиÑтемы баз данных отмечена активноÑть в журнале " "транзакций" -#: access/transam/xlog.c:8705 +#: access/transam/xlog.c:8675 #, c-format msgid "skipping restartpoint, recovery has already ended" msgstr "" "Ñоздание точки перезапуÑка пропуÑкаетÑÑ, воÑÑтановление уже закончилоÑÑŒ" -#: access/transam/xlog.c:8728 +#: access/transam/xlog.c:8698 #, c-format msgid "skipping restartpoint, already performed at %X/%X" msgstr "" "Ñоздание точки перезапуÑка пропуÑкаетÑÑ, она уже Ñоздана по Ñмещению %X/%X" -#: access/transam/xlog.c:8883 +#: access/transam/xlog.c:8853 #, c-format msgid "recovery restart point at %X/%X" msgstr "точка перезапуÑка воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾ Ñмещению %X/%X" -#: access/transam/xlog.c:9016 +#: access/transam/xlog.c:8986 #, c-format msgid "restore point \"%s\" created at %X/%X" msgstr "точка воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\" Ñоздана по Ñмещению %X/%X" -#: access/transam/xlog.c:9146 +#: access/transam/xlog.c:9116 #, c-format msgid "" "unexpected previous timeline ID %u (current timeline ID %u) in checkpoint " @@ -2437,12 +2403,12 @@ msgstr "" "неожиданный ID предыдущей линии времени %u (ID текущей линии времени %u) в " "запиÑи контрольной точки" -#: access/transam/xlog.c:9155 +#: access/transam/xlog.c:9125 #, c-format msgid "unexpected timeline ID %u (after %u) in checkpoint record" msgstr "неожиданный ID линии времени %u (поÑле %u) в запиÑи контрольной точки" -#: access/transam/xlog.c:9171 +#: access/transam/xlog.c:9141 #, c-format msgid "" "unexpected timeline ID %u in checkpoint record, before reaching minimum " @@ -2451,43 +2417,43 @@ msgstr "" "неожиданный ID линии времени %u в запиÑи контрольной точки, до доÑÑ‚Ð¸Ð¶ÐµÐ½Ð¸Ñ " "минимальной к.Ñ‚. %X/%X на линии времени %u" -#: access/transam/xlog.c:9242 +#: access/transam/xlog.c:9212 #, c-format msgid "online backup was canceled, recovery cannot continue" msgstr "" "резервное копирование \"на ходу\" было отменено, продолжить воÑÑтановление " "нельзÑ" -#: access/transam/xlog.c:9298 access/transam/xlog.c:9345 -#: access/transam/xlog.c:9368 +#: access/transam/xlog.c:9268 access/transam/xlog.c:9315 +#: access/transam/xlog.c:9338 #, c-format msgid "unexpected timeline ID %u (should be %u) in checkpoint record" msgstr "" "неожиданный ID линии времени %u (должен быть %u) в запиÑи точки " "воÑÑтановлениÑ" -#: access/transam/xlog.c:9645 +#: access/transam/xlog.c:9615 #, c-format msgid "could not fsync log segment %s: %m" msgstr "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ Ñегмент журнала %s: %m" -#: access/transam/xlog.c:9669 +#: access/transam/xlog.c:9639 #, c-format msgid "could not fsync log file %s: %m" msgstr "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ файл журнала %s: %m" -#: access/transam/xlog.c:9677 +#: access/transam/xlog.c:9647 #, c-format msgid "could not fsync write-through log file %s: %m" msgstr "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ файл журнала Ñквозной запиÑи %s: %m" -#: access/transam/xlog.c:9686 +#: access/transam/xlog.c:9656 #, c-format msgid "could not fdatasync log file %s: %m" msgstr "" "не удалоÑÑŒ Ñинхронизировать Ñ Ð¤Ð¡ данные (fdatasync) файла журнала %s: %m" -#: access/transam/xlog.c:9778 access/transam/xlog.c:10249 +#: access/transam/xlog.c:9748 access/transam/xlog.c:10219 #: access/transam/xlogfuncs.c:121 access/transam/xlogfuncs.c:150 #: access/transam/xlogfuncs.c:189 access/transam/xlogfuncs.c:210 #: access/transam/xlogfuncs.c:280 access/transam/xlogfuncs.c:336 @@ -2495,20 +2461,20 @@ msgstr "" msgid "recovery is in progress" msgstr "идёт процеÑÑ Ð²Ð¾ÑÑтановлениÑ" -#: access/transam/xlog.c:9779 access/transam/xlog.c:10250 +#: access/transam/xlog.c:9749 access/transam/xlog.c:10220 #: access/transam/xlogfuncs.c:122 access/transam/xlogfuncs.c:151 #: access/transam/xlogfuncs.c:190 access/transam/xlogfuncs.c:211 #, c-format msgid "WAL control functions cannot be executed during recovery." msgstr "Функции ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ WAL Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать в процеÑÑе воÑÑтановлениÑ." -#: access/transam/xlog.c:9788 access/transam/xlog.c:10259 +#: access/transam/xlog.c:9758 access/transam/xlog.c:10229 #, c-format msgid "WAL level not sufficient for making an online backup" msgstr "" "Выбранный уровень WAL недоÑтаточен Ð´Ð»Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð³Ð¾ ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"на ходу\"" -#: access/transam/xlog.c:9789 access/transam/xlog.c:10260 +#: access/transam/xlog.c:9759 access/transam/xlog.c:10230 #: access/transam/xlogfuncs.c:157 #, c-format msgid "" @@ -2518,23 +2484,23 @@ msgstr "" "УÑтановите wal_level \"archive\", \"hot_standby\" или \"logical\" при " "запуÑке Ñервера." -#: access/transam/xlog.c:9794 +#: access/transam/xlog.c:9764 #, c-format msgid "backup label too long (max %d bytes)" msgstr "длина метки резервной копии превышает предел (%d байт)" -#: access/transam/xlog.c:9826 access/transam/xlog.c:10096 -#: access/transam/xlog.c:10132 +#: access/transam/xlog.c:9796 access/transam/xlog.c:10066 +#: access/transam/xlog.c:10102 #, c-format msgid "a backup is already in progress" -msgstr "резервное копирование уже запущено" +msgstr "резервное копирование уже выполнÑетÑÑ" -#: access/transam/xlog.c:9827 +#: access/transam/xlog.c:9797 #, c-format msgid "Run pg_stop_backup() and try again." msgstr "Выполните pg_stop_backup() и повторите операцию." -#: access/transam/xlog.c:9922 +#: access/transam/xlog.c:9892 #, c-format msgid "" "WAL generated with full_page_writes=off was replayed since last restartpoint" @@ -2542,7 +2508,7 @@ msgstr "" "ПоÑле поÑледней точки перезапуÑка был воÑпроизведён WAL, Ñозданный в режиме " "full_page_writes=off." -#: access/transam/xlog.c:9924 access/transam/xlog.c:10414 +#: access/transam/xlog.c:9894 access/transam/xlog.c:10384 #, c-format msgid "" "This means that the backup being taken on the standby is corrupt and should " @@ -2554,39 +2520,39 @@ msgstr "" "CHECKPOINT на главном Ñервере, а затем попробуйте резервное копирование \"на " "ходу\" ещё раз." -#: access/transam/xlog.c:9990 replication/basebackup.c:1035 +#: access/transam/xlog.c:9960 replication/basebackup.c:1035 #: utils/adt/misc.c:378 #, c-format msgid "could not read symbolic link \"%s\": %m" msgstr "не удалоÑÑŒ прочитать ÑимволичеÑкую ÑÑылку \"%s\": %m" -#: access/transam/xlog.c:9997 replication/basebackup.c:1040 +#: access/transam/xlog.c:9967 replication/basebackup.c:1040 #: utils/adt/misc.c:383 #, c-format msgid "symbolic link \"%s\" target is too long" msgstr "целевой путь ÑимволичеÑкой ÑÑылки \"%s\" Ñлишком длинный" -#: access/transam/xlog.c:10050 commands/tablespace.c:391 -#: commands/tablespace.c:553 replication/basebackup.c:1056 -#: utils/adt/misc.c:391 +#: access/transam/xlog.c:10020 commands/tablespace.c:391 +#: commands/tablespace.c:553 replication/basebackup.c:1056 utils/adt/misc.c:391 #, c-format msgid "tablespaces are not supported on this platform" msgstr "табличные проÑтранÑтва не поддерживаютÑÑ Ð½Ð° Ñтой платформе" -#: access/transam/xlog.c:10090 access/transam/xlog.c:10126 -#: access/transam/xlog.c:10300 access/transam/xlogarchive.c:106 +#: access/transam/xlog.c:10060 access/transam/xlog.c:10096 +#: access/transam/xlog.c:10270 access/transam/xlogarchive.c:106 #: access/transam/xlogarchive.c:265 commands/copy.c:1738 commands/copy.c:2764 -#: commands/extension.c:3026 commands/tablespace.c:860 -#: replication/basebackup.c:404 replication/basebackup.c:472 -#: replication/logical/snapbuild.c:1478 storage/file/copydir.c:72 -#: storage/file/copydir.c:115 storage/file/fd.c:2519 storage/file/fd.c:2611 -#: utils/adt/dbsize.c:68 utils/adt/dbsize.c:218 utils/adt/dbsize.c:298 -#: utils/adt/genfile.c:114 utils/adt/genfile.c:333 guc-file.l:1003 +#: commands/extension.c:3026 commands/tablespace.c:782 +#: commands/tablespace.c:873 replication/basebackup.c:404 +#: replication/basebackup.c:472 replication/logical/snapbuild.c:1474 +#: storage/file/copydir.c:72 storage/file/copydir.c:115 storage/file/fd.c:2626 +#: storage/file/fd.c:2718 utils/adt/dbsize.c:68 utils/adt/dbsize.c:218 +#: utils/adt/dbsize.c:298 utils/adt/genfile.c:114 utils/adt/genfile.c:333 +#: guc-file.l:1003 #, c-format msgid "could not stat file \"%s\": %m" msgstr "не удалоÑÑŒ получить информацию о файле \"%s\": %m" -#: access/transam/xlog.c:10097 access/transam/xlog.c:10133 +#: access/transam/xlog.c:10067 access/transam/xlog.c:10103 #, c-format msgid "" "If you're sure there is no backup in progress, remove file \"%s\" and try " @@ -2595,31 +2561,31 @@ msgstr "" "ЕÑли вы Ñчитаете, что Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ резервном копировании неверна, удалите " "файл \"%s\" и попробуйте Ñнова." -#: access/transam/xlog.c:10114 access/transam/xlog.c:10150 -#: access/transam/xlog.c:10475 +#: access/transam/xlog.c:10084 access/transam/xlog.c:10120 +#: access/transam/xlog.c:10445 #, c-format msgid "could not write file \"%s\": %m" msgstr "не удалоÑÑŒ запиÑать файл \"%s\": %m" -#: access/transam/xlog.c:10304 +#: access/transam/xlog.c:10274 #, c-format msgid "a backup is not in progress" -msgstr "резервное копирование не запущено" +msgstr "резервное копирование не выполнÑетÑÑ" -#: access/transam/xlog.c:10349 access/transam/xlog.c:10362 -#: access/transam/xlog.c:10702 access/transam/xlog.c:10708 -#: access/transam/xlog.c:10792 access/transam/xlogfuncs.c:508 +#: access/transam/xlog.c:10319 access/transam/xlog.c:10332 +#: access/transam/xlog.c:10672 access/transam/xlog.c:10678 +#: access/transam/xlog.c:10762 access/transam/xlogfuncs.c:508 #, c-format msgid "invalid data in file \"%s\"" msgstr "неверные данные в файле \"%s\"" -#: access/transam/xlog.c:10366 replication/basebackup.c:933 +#: access/transam/xlog.c:10336 replication/basebackup.c:933 #, c-format msgid "the standby was promoted during online backup" msgstr "" "дежурный Ñервер был повышен в процеÑÑе резервного ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"на ходу\"" -#: access/transam/xlog.c:10367 replication/basebackup.c:934 +#: access/transam/xlog.c:10337 replication/basebackup.c:934 #, c-format msgid "" "This means that the backup being taken is corrupt and should not be used. " @@ -2628,7 +2594,7 @@ msgstr "" "Это означает, что ÑÐ¾Ð·Ð´Ð°Ð²Ð°ÐµÐ¼Ð°Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð¸Ñпорчена и иÑпользовать её не " "Ñледует. Попробуйте резервное копирование \"на ходу\" ещё раз." -#: access/transam/xlog.c:10412 +#: access/transam/xlog.c:10382 #, c-format msgid "" "WAL generated with full_page_writes=off was replayed during online backup" @@ -2636,7 +2602,7 @@ msgstr "" "Ð’ процеÑÑе резервного ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"на ходу\" был воÑпроизведён WAL, " "Ñозданный в режиме full_page_writes=off" -#: access/transam/xlog.c:10524 +#: access/transam/xlog.c:10494 #, c-format msgid "" "pg_stop_backup cleanup done, waiting for required WAL segments to be archived" @@ -2644,7 +2610,7 @@ msgstr "" "очиÑтка в pg_stop_backup выполнена, ожидаютÑÑ Ñ‚Ñ€ÐµÐ±ÑƒÐµÐ¼Ñ‹Ðµ Ñегменты WAL Ð´Ð»Ñ " "архивации" -#: access/transam/xlog.c:10534 +#: access/transam/xlog.c:10504 #, c-format msgid "" "pg_stop_backup still waiting for all required WAL segments to be archived " @@ -2653,7 +2619,7 @@ msgstr "" "pg_stop_backup вÑÑ‘ ещё ждёт вÑе требуемые Ñегменты WAL Ð´Ð»Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð°Ñ†Ð¸Ð¸ (прошло " "%d Ñек.)" -#: access/transam/xlog.c:10536 +#: access/transam/xlog.c:10506 #, c-format msgid "" "Check that your archive_command is executing properly. pg_stop_backup can " @@ -2664,13 +2630,13 @@ msgstr "" "можно отменить безопаÑно, но Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð°Ñ ÐºÐ¾Ð¿Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных будет непригодна " "без вÑех Ñегментов WAL." -#: access/transam/xlog.c:10543 +#: access/transam/xlog.c:10513 #, c-format msgid "pg_stop_backup complete, all required WAL segments have been archived" msgstr "" "команда pg_stop_backup завершена, вÑе требуемые Ñегменты WAL заархивированы" -#: access/transam/xlog.c:10547 +#: access/transam/xlog.c:10517 #, c-format msgid "" "WAL archiving is not enabled; you must ensure that all required WAL segments " @@ -2679,35 +2645,35 @@ msgstr "" "Ð°Ñ€Ñ…Ð¸Ð²Ð°Ñ†Ð¸Ñ WAL не наÑтроена; вы должны обеÑпечить копирование вÑех требуемых " "Ñегментов WAL другими ÑредÑтвами Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ð¹ копии" -#: access/transam/xlog.c:10831 +#: access/transam/xlog.c:10801 #, c-format msgid "xlog redo %s" msgstr "XLOG-запиÑÑŒ REDO: %s" -#: access/transam/xlog.c:10877 +#: access/transam/xlog.c:10847 #, c-format msgid "online backup mode was not canceled" msgstr "режим ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"на ходу\" не был отменён" -#: access/transam/xlog.c:10878 +#: access/transam/xlog.c:10848 #, c-format msgid "File \"%s\" could not be renamed to \"%s\": %m." msgstr "Ðе удалоÑÑŒ переименовать файл \"%s\" в \"%s\": %m." -#: access/transam/xlog.c:10887 access/transam/xlog.c:10899 -#: access/transam/xlog.c:10909 +#: access/transam/xlog.c:10857 access/transam/xlog.c:10869 +#: access/transam/xlog.c:10879 #, c-format msgid "online backup mode canceled" msgstr "режим ÐºÐ¾Ð¿Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"на ходу\" отменён" -#: access/transam/xlog.c:10900 +#: access/transam/xlog.c:10870 #, c-format msgid "" "Files \"%s\" and \"%s\" were renamed to \"%s\" and \"%s\", respectively." msgstr "" "Файлы \"%s\" и \"%s\" были переименованы в \"%s\" и \"%s\", ÑоответÑтвенно." -#: access/transam/xlog.c:10910 +#: access/transam/xlog.c:10880 #, c-format msgid "" "File \"%s\" was renamed to \"%s\", but file \"%s\" could not be renamed to " @@ -2716,28 +2682,28 @@ msgstr "" "Файл \"%s\" был переименован в \"%s\", но переименовать \"%s\" в \"%s\" не " "удалоÑÑŒ: %m." -#: access/transam/xlog.c:11032 replication/logical/logicalfuncs.c:171 +#: access/transam/xlog.c:11002 replication/logical/logicalfuncs.c:171 #: replication/walreceiver.c:932 replication/walsender.c:2112 #, c-format msgid "could not seek in log segment %s to offset %u: %m" msgstr "не удалоÑÑŒ перемеÑтитьÑÑ Ð² Ñегменте журнала %s к Ñмещению %u: %m" -#: access/transam/xlog.c:11044 +#: access/transam/xlog.c:11014 #, c-format msgid "could not read from log segment %s, offset %u: %m" msgstr "не удалоÑÑŒ прочитать Ñегмент журнала %s, Ñмещение %u: %m" -#: access/transam/xlog.c:11518 +#: access/transam/xlog.c:11488 #, c-format msgid "received promote request" msgstr "получен Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð²Ñ‹ÑˆÐµÐ½Ð¸Ñ ÑтатуÑа" -#: access/transam/xlog.c:11531 +#: access/transam/xlog.c:11501 #, c-format msgid "trigger file found: %s" msgstr "найден файл триггера: %s" -#: access/transam/xlog.c:11540 +#: access/transam/xlog.c:11510 #, c-format msgid "could not stat trigger file \"%s\": %m" msgstr "не удалоÑÑŒ получить информацию о файле триггера \"%s\": %m" @@ -2765,12 +2731,19 @@ msgstr "воÑÑтановить файл \"%s\" из архива не удал msgid "%s \"%s\": %s" msgstr "%s \"%s\": %s" -#: access/transam/xlogarchive.c:529 access/transam/xlogarchive.c:598 +#: access/transam/xlogarchive.c:458 replication/logical/snapbuild.c:1602 +#: replication/slot.c:470 replication/slot.c:926 replication/slot.c:1038 +#: storage/file/fd.c:494 storage/file/fd.c:552 utils/time/snapmgr.c:1094 +#, c-format +msgid "could not rename file \"%s\" to \"%s\": %m" +msgstr "не удалоÑÑŒ переименовать файл \"%s\" в \"%s\": %m" + +#: access/transam/xlogarchive.c:525 access/transam/xlogarchive.c:589 #, c-format msgid "could not create archive status file \"%s\": %m" msgstr "не удалоÑÑŒ Ñоздать файл ÑоÑтоÑÐ½Ð¸Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð° \"%s\": %m" -#: access/transam/xlogarchive.c:537 access/transam/xlogarchive.c:606 +#: access/transam/xlogarchive.c:533 access/transam/xlogarchive.c:597 #, c-format msgid "could not write archive status file \"%s\": %m" msgstr "не удалоÑÑŒ запиÑать файл ÑоÑтоÑÐ½Ð¸Ñ Ð°Ñ€Ñ…Ð¸Ð²Ð° \"%s\": %m" @@ -2785,8 +2758,8 @@ msgstr "" #: access/transam/xlogfuncs.c:67 commands/tablespace.c:705 #: commands/tablespace.c:715 postmaster/postmaster.c:1389 #: replication/basebackup.c:292 replication/basebackup.c:632 -#: storage/file/copydir.c:53 storage/file/copydir.c:96 storage/file/fd.c:1985 -#: storage/file/fd.c:2584 storage/ipc/dsm.c:300 utils/adt/genfile.c:439 +#: storage/file/copydir.c:53 storage/file/copydir.c:96 storage/file/fd.c:2092 +#: storage/file/fd.c:2691 storage/ipc/dsm.c:300 utils/adt/genfile.c:439 #: utils/adt/misc.c:291 utils/misc/tzparser.c:339 #, c-format msgid "could not open directory \"%s\": %m" @@ -3204,7 +3177,7 @@ msgid "column \"%s\" of relation \"%s\" does not exist" msgstr "Ñтолбец \"%s\" в таблице \"%s\" не ÑущеÑтвует" #: catalog/aclchk.c:1748 catalog/objectaddress.c:1151 commands/sequence.c:1078 -#: commands/tablecmds.c:221 commands/tablecmds.c:11960 utils/adt/acl.c:2075 +#: commands/tablecmds.c:221 commands/tablecmds.c:11970 utils/adt/acl.c:2075 #: utils/adt/acl.c:2105 utils/adt/acl.c:2137 utils/adt/acl.c:2169 #: utils/adt/acl.c:2197 utils/adt/acl.c:2227 #, c-format @@ -3701,10 +3674,10 @@ msgstr "" "Ñортировки" #: catalog/heap.c:584 commands/createas.c:375 commands/indexcmds.c:1087 -#: commands/view.c:116 regex/regc_pg_locale.c:262 utils/adt/formatting.c:1514 -#: utils/adt/formatting.c:1566 utils/adt/formatting.c:1634 -#: utils/adt/formatting.c:1686 utils/adt/formatting.c:1755 -#: utils/adt/formatting.c:1819 utils/adt/like.c:213 utils/adt/selfuncs.c:5276 +#: commands/view.c:116 regex/regc_pg_locale.c:262 utils/adt/formatting.c:1513 +#: utils/adt/formatting.c:1565 utils/adt/formatting.c:1633 +#: utils/adt/formatting.c:1685 utils/adt/formatting.c:1754 +#: utils/adt/formatting.c:1818 utils/adt/like.c:213 utils/adt/selfuncs.c:5276 #: utils/adt/varlena.c:1411 utils/adt/varlena.c:1800 #, c-format msgid "Use the COLLATE clause to set the collation explicitly." @@ -3980,8 +3953,8 @@ msgstr "перемещать объекты в/из внутренних Ñхе msgid "cannot move objects into or out of TOAST schema" msgstr "перемещать объекты в/из Ñхем TOAST нельзÑ" -#: catalog/namespace.c:2873 commands/schemacmds.c:238 -#: commands/schemacmds.c:317 commands/tablecmds.c:736 +#: catalog/namespace.c:2873 commands/schemacmds.c:238 commands/schemacmds.c:317 +#: commands/tablecmds.c:736 #, c-format msgid "schema \"%s\" does not exist" msgstr "Ñхема \"%s\" не ÑущеÑтвует" @@ -4016,8 +3989,8 @@ msgstr "Ñоздавать временные таблицы в процеÑÑе msgid "cannot create temporary tables in parallel mode" msgstr "Ñоздавать временные таблицы в параллельном режиме нельзÑ" -#: catalog/namespace.c:3898 commands/tablespace.c:1159 commands/variable.c:63 -#: replication/syncrep.c:700 utils/misc/guc.c:9636 +#: catalog/namespace.c:3898 commands/tablespace.c:1173 commands/variable.c:63 +#: replication/syncrep.c:700 utils/misc/guc.c:9649 #, c-format msgid "List syntax is invalid." msgstr "Ошибка ÑинтакÑиÑа в ÑпиÑке." @@ -4068,19 +4041,19 @@ msgid "\"%s\" is not a table" msgstr "\"%s\" - Ñто не таблица" #: catalog/objectaddress.c:1165 commands/tablecmds.c:227 -#: commands/tablecmds.c:4368 commands/tablecmds.c:11965 commands/view.c:155 +#: commands/tablecmds.c:4368 commands/tablecmds.c:11975 commands/view.c:155 #, c-format msgid "\"%s\" is not a view" msgstr "\"%s\" - Ñто не предÑтавление" -#: catalog/objectaddress.c:1172 commands/matview.c:174 -#: commands/tablecmds.c:233 commands/tablecmds.c:11970 +#: catalog/objectaddress.c:1172 commands/matview.c:174 commands/tablecmds.c:233 +#: commands/tablecmds.c:11980 #, c-format msgid "\"%s\" is not a materialized view" msgstr "\"%s\" - Ñто не материализованное предÑтавление" #: catalog/objectaddress.c:1179 commands/tablecmds.c:251 -#: commands/tablecmds.c:4371 commands/tablecmds.c:11975 +#: commands/tablecmds.c:4371 commands/tablecmds.c:11985 #, c-format msgid "\"%s\" is not a foreign table" msgstr "\"%s\" - Ñто не ÑтороннÑÑ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð°" @@ -4120,8 +4093,7 @@ msgid "user mapping for user \"%s\" on server \"%s\" does not exist" msgstr "ÑопоÑтавление Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\" на Ñервере \"%s\" не ÑущеÑтвует" #: catalog/objectaddress.c:1670 commands/foreigncmds.c:430 -#: commands/foreigncmds.c:997 commands/foreigncmds.c:1359 -#: foreign/foreign.c:691 +#: commands/foreigncmds.c:997 commands/foreigncmds.c:1359 foreign/foreign.c:691 #, c-format msgid "server \"%s\" does not exist" msgstr "Ñервер \"%s\" не ÑущеÑтвует" @@ -4570,12 +4542,12 @@ msgstr "" "оператор Ñортировки можно указать только Ð´Ð»Ñ Ð°Ð³Ñ€ÐµÐ³Ð°Ñ‚Ð½Ñ‹Ñ… функций Ñ Ð¾Ð´Ð½Ð¸Ð¼ " "аргументом" -#: catalog/pg_aggregate.c:700 commands/typecmds.c:1702 -#: commands/typecmds.c:1753 commands/typecmds.c:1784 commands/typecmds.c:1807 -#: commands/typecmds.c:1828 commands/typecmds.c:1855 commands/typecmds.c:1882 -#: commands/typecmds.c:1959 commands/typecmds.c:2001 parser/parse_func.c:364 -#: parser/parse_func.c:393 parser/parse_func.c:418 parser/parse_func.c:432 -#: parser/parse_func.c:507 parser/parse_func.c:518 parser/parse_func.c:1920 +#: catalog/pg_aggregate.c:700 commands/typecmds.c:1702 commands/typecmds.c:1753 +#: commands/typecmds.c:1784 commands/typecmds.c:1807 commands/typecmds.c:1828 +#: commands/typecmds.c:1855 commands/typecmds.c:1882 commands/typecmds.c:1959 +#: commands/typecmds.c:2001 parser/parse_func.c:364 parser/parse_func.c:393 +#: parser/parse_func.c:418 parser/parse_func.c:432 parser/parse_func.c:507 +#: parser/parse_func.c:518 parser/parse_func.c:1920 #, c-format msgid "function %s does not exist" msgstr "Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ %s не ÑущеÑтвует" @@ -4985,7 +4957,7 @@ msgid "could not form array type name for type \"%s\"" msgstr "не удалоÑÑŒ Ñформировать Ð¸Ð¼Ñ Ñ‚Ð¸Ð¿Ð° маÑÑива Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° \"%s\"" #: catalog/toasting.c:104 commands/indexcmds.c:381 commands/tablecmds.c:4350 -#: commands/tablecmds.c:11853 +#: commands/tablecmds.c:11863 #, c-format msgid "\"%s\" is not a table or materialized view" msgstr "\"%s\" - Ñто не таблица и не материализованное предÑтавление" @@ -5008,23 +4980,22 @@ msgstr "нераÑпознанный атрибут \"%s\" в определен #: commands/aggregatecmds.c:181 #, c-format msgid "aggregate stype must be specified" -msgstr "в определении агрегатной функции требуетÑÑ stype" +msgstr "в определении агрегата требуетÑÑ stype" #: commands/aggregatecmds.c:185 #, c-format msgid "aggregate sfunc must be specified" -msgstr "в определении агрегатной функции требуетÑÑ sfunc" +msgstr "в определении агрегата требуетÑÑ sfunc" #: commands/aggregatecmds.c:197 #, c-format msgid "aggregate msfunc must be specified when mstype is specified" -msgstr "в определении агрегатной функции требуетÑÑ msfunc, еÑли указан mstype" +msgstr "в определении агрегата требуетÑÑ msfunc, еÑли указан mstype" #: commands/aggregatecmds.c:201 #, c-format msgid "aggregate minvfunc must be specified when mstype is specified" -msgstr "" -"в определении агрегатной функции требуетÑÑ minvfunc, еÑли указан mstype" +msgstr "в определении агрегата требуетÑÑ minvfunc, еÑли указан mstype" #: commands/aggregatecmds.c:208 #, c-format @@ -5054,19 +5025,17 @@ msgstr "minitcond Ð´Ð»Ñ Ð°Ð³Ñ€ÐµÐ³Ð°Ñ‚Ð° не должна ÑƒÐºÐ°Ð·Ñ‹Ð²Ð°Ñ‚ÑŒÑ #: commands/aggregatecmds.c:244 #, c-format msgid "aggregate input type must be specified" -msgstr "в определении агрегатной функции требуетÑÑ Ð²Ñ…Ð¾Ð´Ð½Ð¾Ð¹ тип" +msgstr "в определении агрегата требуетÑÑ Ð²Ñ…Ð¾Ð´Ð½Ð¾Ð¹ тип" #: commands/aggregatecmds.c:274 #, c-format msgid "basetype is redundant with aggregate input type specification" -msgstr "" -"в определении агрегатной функции Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸ÐµÐ¼ входного типа не нужен базовый " -"тип" +msgstr "в определении агрегата Ñ ÑƒÐºÐ°Ð·Ð°Ð½Ð¸ÐµÐ¼ входного типа не нужен базовый тип" #: commands/aggregatecmds.c:315 commands/aggregatecmds.c:335 #, c-format msgid "aggregate transition data type cannot be %s" -msgstr "переходным типом агрегатной функции не может быть %s" +msgstr "переходным типом агрегата не может быть %s" #: commands/alter.c:80 commands/event_trigger.c:230 #, c-format @@ -6237,7 +6206,7 @@ msgstr "ИÑпользуйте DROP AGGREGATE Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð°Ð³Ñ€ÐµÐ³ #: commands/dropcmds.c:165 commands/sequence.c:424 commands/tablecmds.c:2369 #: commands/tablecmds.c:2520 commands/tablecmds.c:2562 -#: commands/tablecmds.c:11336 tcop/utility.c:1104 +#: commands/tablecmds.c:11346 tcop/utility.c:1104 #, c-format msgid "relation \"%s\" does not exist, skipping" msgstr "отношение \"%s\" не ÑущеÑтвует, пропуÑкаетÑÑ" @@ -6428,12 +6397,12 @@ msgstr "%s можно вызывать только в Ñобытийной тр #: commands/extension.c:1947 commands/prepare.c:701 executor/execQual.c:1735 #: executor/execQual.c:1760 executor/execQual.c:2135 executor/execQual.c:5376 #: executor/functions.c:1021 foreign/foreign.c:491 -#: replication/logical/logicalfuncs.c:324 replication/logical/origin.c:1410 -#: replication/slotfuncs.c:173 replication/walsender.c:2762 +#: replication/logical/logicalfuncs.c:324 replication/logical/origin.c:1391 +#: replication/slotfuncs.c:173 replication/walsender.c:2766 #: utils/adt/jsonfuncs.c:1474 utils/adt/jsonfuncs.c:1606 #: utils/adt/jsonfuncs.c:1796 utils/adt/jsonfuncs.c:1925 #: utils/adt/jsonfuncs.c:2693 utils/adt/pgstatfuncs.c:547 -#: utils/fmgr/funcapi.c:61 utils/misc/guc.c:8207 utils/mmgr/portalmem.c:1052 +#: utils/fmgr/funcapi.c:61 utils/misc/guc.c:8220 utils/mmgr/portalmem.c:1052 #, c-format msgid "set-valued function called in context that cannot accept a set" msgstr "" @@ -6442,9 +6411,9 @@ msgstr "" #: commands/event_trigger.c:1450 commands/event_trigger.c:2001 #: commands/extension.c:1649 commands/extension.c:1758 #: commands/extension.c:1951 commands/prepare.c:705 foreign/foreign.c:496 -#: replication/logical/logicalfuncs.c:328 replication/logical/origin.c:1414 -#: replication/slotfuncs.c:177 replication/walsender.c:2766 -#: utils/adt/pgstatfuncs.c:551 utils/misc/guc.c:8211 +#: replication/logical/logicalfuncs.c:328 replication/logical/origin.c:1395 +#: replication/slotfuncs.c:177 replication/walsender.c:2770 +#: utils/adt/pgstatfuncs.c:551 utils/misc/guc.c:8224 #: utils/mmgr/portalmem.c:1056 #, c-format msgid "materialize mode required, but it is not allowed in this context" @@ -7166,9 +7135,8 @@ msgstr "нет внедрённого кода" msgid "language \"%s\" does not support inline code execution" msgstr "Ñзык \"%s\" не поддерживает выполнение внедрённого кода" -#: commands/indexcmds.c:159 commands/indexcmds.c:487 -#: commands/opclasscmds.c:360 commands/opclasscmds.c:786 -#: commands/opclasscmds.c:1749 +#: commands/indexcmds.c:159 commands/indexcmds.c:487 commands/opclasscmds.c:360 +#: commands/opclasscmds.c:786 commands/opclasscmds.c:1749 #, c-format msgid "access method \"%s\" does not exist" msgstr "метод доÑтупа \"%s\" не ÑущеÑтвует" @@ -7249,7 +7217,7 @@ msgstr "функции в индекÑном выражении должны б msgid "could not determine which collation to use for index expression" msgstr "не удалоÑÑŒ определить правило ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¸Ð½Ð´ÐµÐºÑного выражениÑ" -#: commands/indexcmds.c:1094 commands/typecmds.c:825 parser/parse_expr.c:2559 +#: commands/indexcmds.c:1094 commands/typecmds.c:825 parser/parse_expr.c:2583 #: parser/parse_type.c:550 parser/parse_utilcmd.c:2736 utils/adt/misc.c:546 #, c-format msgid "collations are not supported by type %s" @@ -7589,12 +7557,11 @@ msgid "join estimator function %s must return type \"float8\"" msgstr "Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¾Ñ†ÐµÐ½ÐºÐ¸ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ %s должна возвращать тип \"float8\"" #: commands/policy.c:87 commands/policy.c:390 commands/policy.c:479 -#: commands/tablecmds.c:966 commands/tablecmds.c:1308 -#: commands/tablecmds.c:2176 commands/tablecmds.c:4320 -#: commands/tablecmds.c:6249 commands/tablecmds.c:11886 -#: commands/tablecmds.c:11921 commands/trigger.c:240 commands/trigger.c:1126 -#: commands/trigger.c:1234 rewrite/rewriteDefine.c:273 -#: rewrite/rewriteDefine.c:905 +#: commands/tablecmds.c:966 commands/tablecmds.c:1308 commands/tablecmds.c:2176 +#: commands/tablecmds.c:4320 commands/tablecmds.c:6249 +#: commands/tablecmds.c:11896 commands/tablecmds.c:11931 commands/trigger.c:240 +#: commands/trigger.c:1126 commands/trigger.c:1234 rewrite/rewriteDefine.c:273 +#: rewrite/rewriteDefine.c:917 #, c-format msgid "permission denied: \"%s\" is a system catalog" msgstr "доÑтуп запрещён: \"%s\" - Ñто ÑиÑтемный каталог" @@ -7639,8 +7606,7 @@ msgstr "политика \"%s\" Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s\" не ÑущеÑтв msgid "only USING expression allowed for SELECT, DELETE" msgstr "Ð´Ð»Ñ SELECT, DELETE допуÑкаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ выражение USING" -#: commands/portalcmds.c:61 commands/portalcmds.c:160 -#: commands/portalcmds.c:212 +#: commands/portalcmds.c:61 commands/portalcmds.c:160 commands/portalcmds.c:212 #, c-format msgid "invalid cursor name: must not be empty" msgstr "Ð¸Ð¼Ñ ÐºÑƒÑ€Ñора не может быть пуÑтым" @@ -7955,7 +7921,7 @@ msgid "Use DROP TYPE to remove a type." msgstr "Выполните DROP TYPE Ð´Ð»Ñ ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ñ‚Ð¸Ð¿Ð°." #: commands/tablecmds.c:249 commands/tablecmds.c:8456 -#: commands/tablecmds.c:11153 +#: commands/tablecmds.c:11163 #, c-format msgid "foreign table \"%s\" does not exist" msgstr "ÑтороннÑÑ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ð° \"%s\" не ÑущеÑтвует" @@ -8213,8 +8179,8 @@ msgstr "Ñтолбец \"%s\" Ñодержит Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ NULL" msgid "check constraint \"%s\" is violated by some row" msgstr "ограничение-проверку \"%s\" нарушает Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñтрока" -#: commands/tablecmds.c:4341 commands/trigger.c:234 -#: rewrite/rewriteDefine.c:267 rewrite/rewriteDefine.c:900 +#: commands/tablecmds.c:4341 commands/trigger.c:234 rewrite/rewriteDefine.c:267 +#: rewrite/rewriteDefine.c:912 #, c-format msgid "\"%s\" is not a table or view" msgstr "\"%s\" - Ñто не таблица и не предÑтавление" @@ -8623,12 +8589,12 @@ msgstr "Однако возможно Ñменить владельца табл msgid "cannot change owner of sequence \"%s\"" msgstr "Ñменить владельца поÑледовательноÑти \"%s\" нельзÑ" -#: commands/tablecmds.c:8944 commands/tablecmds.c:11355 +#: commands/tablecmds.c:8944 commands/tablecmds.c:11365 #, c-format msgid "Sequence \"%s\" is linked to table \"%s\"." msgstr "ПоÑледовательноÑть \"%s\" ÑвÑзана Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†ÐµÐ¹ \"%s\"." -#: commands/tablecmds.c:8956 commands/tablecmds.c:11996 +#: commands/tablecmds.c:8956 commands/tablecmds.c:12006 #, c-format msgid "Use ALTER TYPE instead." msgstr "ИÑпользуйте ALTER TYPE." @@ -8816,7 +8782,16 @@ msgstr "Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ реплики Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпол msgid "cannot use invalid index \"%s\" as replica identity" msgstr "Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ реплики Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать нерабочий Ð¸Ð½Ð´ÐµÐºÑ \"%s\"" -#: commands/tablecmds.c:11031 +#: commands/tablecmds.c:11034 +#, c-format +msgid "" +"index \"%s\" cannot be used as replica identity because column %d is a " +"system column" +msgstr "" +"Ð¸Ð½Ð´ÐµÐºÑ \"%s\" Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ реплики, так как Ñтолбец " +"%d - ÑиÑтемный" + +#: commands/tablecmds.c:11041 #, c-format msgid "" "index \"%s\" cannot be used as replica identity because column \"%s\" is " @@ -8825,13 +8800,13 @@ msgstr "" "Ð¸Ð½Ð´ÐµÐºÑ \"%s\" Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать Ð´Ð»Ñ Ð¸Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸ реплики, так как Ñтолбец " "\"%s\" допуÑкает NULL" -#: commands/tablecmds.c:11228 +#: commands/tablecmds.c:11238 #, c-format msgid "cannot change logged status of table \"%s\" because it is temporary" msgstr "" "изменить ÑоÑтоÑние Ð¶ÑƒÑ€Ð½Ð°Ð»Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ %s нельзÑ, так как она временнаÑ" -#: commands/tablecmds.c:11287 +#: commands/tablecmds.c:11297 #, c-format msgid "" "could not change table \"%s\" to logged because it references unlogged table " @@ -8840,7 +8815,7 @@ msgstr "" "не удалоÑÑŒ Ñделать таблицу \"%s\" журналируемой, так как она ÑÑылаетÑÑ Ð½Ð° " "нежурналируемую таблицу \"%s\"" -#: commands/tablecmds.c:11297 +#: commands/tablecmds.c:11307 #, c-format msgid "" "could not change table \"%s\" to unlogged because it references logged table " @@ -8849,22 +8824,22 @@ msgstr "" "не удалоÑÑŒ Ñделать таблицу \"%s\" нежурналируемой, так как она ÑÑылаетÑÑ Ð½Ð° " "журналируемую таблицу \"%s\"" -#: commands/tablecmds.c:11354 +#: commands/tablecmds.c:11364 #, c-format msgid "cannot move an owned sequence into another schema" msgstr "перемеÑтить поÑледовательноÑть Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†ÐµÐ¼ в другую Ñхему нельзÑ" -#: commands/tablecmds.c:11455 +#: commands/tablecmds.c:11465 #, c-format msgid "relation \"%s\" already exists in schema \"%s\"" msgstr "отношение \"%s\" уже ÑущеÑтвует в Ñхеме \"%s\"" -#: commands/tablecmds.c:11980 +#: commands/tablecmds.c:11990 #, c-format msgid "\"%s\" is not a composite type" msgstr "\"%s\" - Ñто не ÑоÑтавной тип" -#: commands/tablecmds.c:12010 +#: commands/tablecmds.c:12020 #, c-format msgid "" "\"%s\" is not a table, view, materialized view, sequence, or foreign table" @@ -8919,24 +8894,24 @@ msgstr "путь к табличному проÑтранÑтву \"%s\" Ñли msgid "tablespace location should not be inside the data directory" msgstr "табличное проÑтранÑтво не должно раÑполагатьÑÑ Ð²Ð½ÑƒÑ‚Ñ€Ð¸ каталога данных" -#: commands/tablespace.c:304 commands/tablespace.c:938 +#: commands/tablespace.c:304 commands/tablespace.c:952 #, c-format msgid "unacceptable tablespace name \"%s\"" msgstr "неприемлемое Ð¸Ð¼Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ проÑтранÑтва: \"%s\"" -#: commands/tablespace.c:306 commands/tablespace.c:939 +#: commands/tablespace.c:306 commands/tablespace.c:953 #, c-format msgid "The prefix \"pg_\" is reserved for system tablespaces." msgstr "ÐŸÑ€ÐµÑ„Ð¸ÐºÑ \"pg_\" зарезервирован Ð´Ð»Ñ ÑиÑтемных табличных проÑтранÑтв." -#: commands/tablespace.c:316 commands/tablespace.c:951 +#: commands/tablespace.c:316 commands/tablespace.c:965 #, c-format msgid "tablespace \"%s\" already exists" msgstr "табличное проÑтранÑтво \"%s\" уже ÑущеÑтвует" -#: commands/tablespace.c:430 commands/tablespace.c:921 -#: commands/tablespace.c:1002 commands/tablespace.c:1071 -#: commands/tablespace.c:1204 commands/tablespace.c:1404 +#: commands/tablespace.c:430 commands/tablespace.c:935 +#: commands/tablespace.c:1016 commands/tablespace.c:1085 +#: commands/tablespace.c:1218 commands/tablespace.c:1418 #, c-format msgid "tablespace \"%s\" does not exist" msgstr "табличное проÑтранÑтво \"%s\" не ÑущеÑтвует" @@ -8973,32 +8948,32 @@ msgid "directory \"%s\" already in use as a tablespace" msgstr "каталог \"%s\" уже иÑпользуетÑÑ ÐºÐ°Ðº табличное проÑтранÑтво" #: commands/tablespace.c:744 commands/tablespace.c:757 -#: commands/tablespace.c:781 commands/tablespace.c:872 +#: commands/tablespace.c:793 commands/tablespace.c:885 #, c-format msgid "could not remove directory \"%s\": %m" msgstr "ошибка при удалении каталога \"%s\": %m" -#: commands/tablespace.c:793 commands/tablespace.c:881 +#: commands/tablespace.c:806 commands/tablespace.c:894 #, c-format msgid "could not remove symbolic link \"%s\": %m" msgstr "ошибка при удалении ÑимволичеÑкой ÑÑылки \"%s\": %m" -#: commands/tablespace.c:803 commands/tablespace.c:889 +#: commands/tablespace.c:816 commands/tablespace.c:903 #, c-format msgid "\"%s\" is not a directory or symbolic link" msgstr "\"%s\" - Ñто не каталог или ÑимволичеÑÐºÐ°Ñ ÑÑылка" -#: commands/tablespace.c:1076 +#: commands/tablespace.c:1090 #, c-format msgid "Tablespace \"%s\" does not exist." msgstr "Табличное проÑтранÑтво \"%s\" не ÑущеÑтвует." -#: commands/tablespace.c:1503 +#: commands/tablespace.c:1517 #, c-format msgid "directories for tablespace %u could not be removed" msgstr "удалить каталоги табличного проÑтранÑтва %u не удалоÑÑŒ" -#: commands/tablespace.c:1505 +#: commands/tablespace.c:1519 #, c-format msgid "You can remove the directories manually if necessary." msgstr "При необходимоÑти вы можете удалить их вручную." @@ -9169,10 +9144,9 @@ msgstr "" "Возможно, Ð´Ð»Ñ Ñ€Ð°ÑпроÑÑ‚Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ в другие Ñтроки Ñледует иÑпользовать " "триггер AFTER вмеÑто BEFORE." -#: commands/trigger.c:2742 executor/execMain.c:2344 -#: executor/nodeLockRows.c:216 executor/nodeModifyTable.c:183 -#: executor/nodeModifyTable.c:661 executor/nodeModifyTable.c:955 -#: executor/nodeModifyTable.c:1122 +#: commands/trigger.c:2742 executor/execMain.c:2344 executor/nodeLockRows.c:216 +#: executor/nodeModifyTable.c:183 executor/nodeModifyTable.c:661 +#: executor/nodeModifyTable.c:955 executor/nodeModifyTable.c:1122 #, c-format msgid "could not serialize access due to concurrent update" msgstr "не удалоÑÑŒ Ñериализовать доÑтуп из-за параллельного изменениÑ" @@ -9788,44 +9762,44 @@ msgstr "" "Скорее закройте открытые транзакции в мультитранзакциÑÑ…, чтобы избежать " "проблемы наложениÑ." -#: commands/vacuum.c:1130 +#: commands/vacuum.c:1138 #, c-format msgid "some databases have not been vacuumed in over 2 billion transactions" msgstr "" "еÑть базы данных, которые не очищалиÑÑŒ на протÑжении более чем 2 миллиардов " "транзакций" -#: commands/vacuum.c:1131 +#: commands/vacuum.c:1139 #, c-format msgid "You might have already suffered transaction-wraparound data loss." msgstr "Возможно, вы уже потерÑли данные в результате Ð½Ð°Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ID транзакций." -#: commands/vacuum.c:1252 +#: commands/vacuum.c:1260 #, c-format msgid "skipping vacuum of \"%s\" --- lock not available" msgstr "очиÑтка \"%s\" пропуÑкаетÑÑ --- блокировка недоÑтупна" -#: commands/vacuum.c:1278 +#: commands/vacuum.c:1286 #, c-format msgid "skipping \"%s\" --- only superuser can vacuum it" msgstr "" "\"%s\" пропуÑкаетÑÑ --- только Ñуперпользователь может очиÑтить Ñту таблицу" -#: commands/vacuum.c:1282 +#: commands/vacuum.c:1290 #, c-format msgid "skipping \"%s\" --- only superuser or database owner can vacuum it" msgstr "" "пропуÑкаетÑÑ \"%s\" --- только Ñуперпользователь или владелец БД может " "очиÑтить Ñту таблицу" -#: commands/vacuum.c:1286 +#: commands/vacuum.c:1294 #, c-format msgid "skipping \"%s\" --- only table or database owner can vacuum it" msgstr "" "\"%s\" пропуÑкаетÑÑ --- только владелец базы данных или Ñтой таблицы может " "очиÑтить её" -#: commands/vacuum.c:1304 +#: commands/vacuum.c:1312 #, c-format msgid "skipping \"%s\" --- cannot vacuum non-tables or special system tables" msgstr "" @@ -9955,7 +9929,7 @@ msgstr "\"%s\": уÑечение (было Ñтраниц: %u, Ñтало: %u)" msgid "\"%s\": suspending truncate due to conflicting lock request" msgstr "\"%s\": приоÑтановка уÑÐµÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð·-за конфликтующего запроÑа блокировки" -#: commands/variable.c:164 utils/misc/guc.c:9660 +#: commands/variable.c:164 utils/misc/guc.c:9673 #, c-format msgid "Unrecognized key word: \"%s\"." msgstr "нераÑпознанное ключевое Ñлово: \"%s\"." @@ -10176,32 +10150,32 @@ msgstr "" "ON CONFLICT не поддерживает откладываемые Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ ÑƒÐ½Ð¸ÐºÐ°Ð»ÑŒÐ½Ð¾Ñти/" "ограничениÑ-иÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð² качеÑтве определÑющего индекÑа" -#: executor/execIndexing.c:814 +#: executor/execIndexing.c:816 #, c-format msgid "could not create exclusion constraint \"%s\"" msgstr "не удалоÑÑŒ Ñоздать ограничение-иÑключение \"%s\"" -#: executor/execIndexing.c:817 +#: executor/execIndexing.c:819 #, c-format msgid "Key %s conflicts with key %s." msgstr "Ключ %s конфликтует Ñ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ %s." -#: executor/execIndexing.c:819 +#: executor/execIndexing.c:821 #, c-format msgid "Key conflicts exist." msgstr "Обнаружен конфликт ключей." -#: executor/execIndexing.c:825 +#: executor/execIndexing.c:827 #, c-format msgid "conflicting key value violates exclusion constraint \"%s\"" msgstr "конфликтующее значение ключа нарушает ограничение-иÑключение \"%s\"" -#: executor/execIndexing.c:828 +#: executor/execIndexing.c:830 #, c-format msgid "Key %s conflicts with existing key %s." msgstr "Ключ %s конфликтует Ñ ÑущеÑтвующим ключом %s." -#: executor/execIndexing.c:830 +#: executor/execIndexing.c:832 #, c-format msgid "Key conflicts with existing key." msgstr "Ключ конфликтует Ñ ÑƒÐ¶Ðµ ÑущеÑтвующим." @@ -10827,7 +10801,7 @@ msgstr "DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE не поддерживает msgid "Scrollable cursors must be READ ONLY." msgstr "Прокручиваемые курÑоры должны быть READ ONLY." -#: executor/spi.c:2450 +#: executor/spi.c:2458 #, c-format msgid "SQL statement \"%s\"" msgstr "SQL-оператор: \"%s\"" @@ -11062,162 +11036,162 @@ msgstr "принÑть контекÑÑ‚ безопаÑноÑти GSS не уда msgid "retrieving GSS user name failed" msgstr "получить Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ GSS не удалоÑÑŒ" -#: libpq/auth.c:1062 +#: libpq/auth.c:1064 #, c-format msgid "SSPI is not supported in protocol version 2" msgstr "SSPI не поддерживаетÑÑ Ð² протоколе верÑии 2" -#: libpq/auth.c:1077 +#: libpq/auth.c:1079 msgid "could not acquire SSPI credentials" msgstr "не удалоÑÑŒ получить удоÑтоверение SSPI" -#: libpq/auth.c:1095 +#: libpq/auth.c:1097 #, c-format msgid "expected SSPI response, got message type %d" msgstr "ожидалÑÑ Ð¾Ñ‚Ð²ÐµÑ‚ SSPI, но получено Ñообщение %d" -#: libpq/auth.c:1167 +#: libpq/auth.c:1169 msgid "could not accept SSPI security context" msgstr "принÑть контекÑÑ‚ безопаÑноÑти SSPI не удалоÑÑŒ" -#: libpq/auth.c:1229 +#: libpq/auth.c:1231 msgid "could not get token from SSPI security context" msgstr "не удалоÑÑŒ получить маркер из контекÑта безопаÑноÑти SSPI" -#: libpq/auth.c:1476 +#: libpq/auth.c:1478 #, c-format msgid "could not create socket for Ident connection: %m" msgstr "не удалоÑÑŒ Ñоздать Ñокет Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñерверу Ident: %m" -#: libpq/auth.c:1491 +#: libpq/auth.c:1493 #, c-format msgid "could not bind to local address \"%s\": %m" msgstr "не удалоÑÑŒ привÑзатьÑÑ Ðº локальному адреÑу \"%s\": %m" -#: libpq/auth.c:1503 +#: libpq/auth.c:1505 #, c-format msgid "could not connect to Ident server at address \"%s\", port %s: %m" msgstr "не удалоÑÑŒ подключитьÑÑ Ðº Ñерверу Ident по адреÑу \"%s\", порт %s: %m" -#: libpq/auth.c:1525 +#: libpq/auth.c:1527 #, c-format msgid "could not send query to Ident server at address \"%s\", port %s: %m" msgstr "" "не удалоÑÑŒ отправить Ð·Ð°Ð¿Ñ€Ð¾Ñ Ñерверу Ident по адреÑу \"%s\", порт %s: %m" -#: libpq/auth.c:1542 +#: libpq/auth.c:1544 #, c-format msgid "" "could not receive response from Ident server at address \"%s\", port %s: %m" msgstr "" "не удалоÑÑŒ получить ответ от Ñервера Ident по адреÑу \"%s\", порт %s: %m" -#: libpq/auth.c:1552 +#: libpq/auth.c:1554 #, c-format msgid "invalidly formatted response from Ident server: \"%s\"" msgstr "неверно форматированный ответ от Ñервера Ident: \"%s\"" -#: libpq/auth.c:1592 +#: libpq/auth.c:1594 #, c-format msgid "peer authentication is not supported on this platform" msgstr "проверка подлинноÑти peer в Ñтой ОС не поддерживаетÑÑ" -#: libpq/auth.c:1596 +#: libpq/auth.c:1598 #, c-format msgid "could not get peer credentials: %m" msgstr "не удалоÑÑŒ получить данные Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ‡ÐµÑ€ÐµÐ· механизм peer: %m" -#: libpq/auth.c:1605 +#: libpq/auth.c:1607 #, c-format msgid "could not look up local user ID %ld: %s" msgstr "найти локального Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð¿Ð¾ идентификатору (%ld) не удалоÑÑŒ: %s" -#: libpq/auth.c:1689 libpq/auth.c:1960 libpq/auth.c:2316 +#: libpq/auth.c:1691 libpq/auth.c:1962 libpq/auth.c:2318 #, c-format msgid "empty password returned by client" msgstr "клиент возвратил пуÑтой пароль" -#: libpq/auth.c:1699 +#: libpq/auth.c:1701 #, c-format msgid "error from underlying PAM layer: %s" msgstr "ошибка в нижележащем Ñлое PAM: %s" -#: libpq/auth.c:1768 +#: libpq/auth.c:1770 #, c-format msgid "could not create PAM authenticator: %s" msgstr "не удалоÑÑŒ Ñоздать аутентификатор PAM: %s" -#: libpq/auth.c:1779 +#: libpq/auth.c:1781 #, c-format msgid "pam_set_item(PAM_USER) failed: %s" msgstr "ошибка в pam_set_item(PAM_USER): %s" -#: libpq/auth.c:1790 +#: libpq/auth.c:1792 #, c-format msgid "pam_set_item(PAM_CONV) failed: %s" msgstr "ошибка в pam_set_item(PAM_CONV): %s" -#: libpq/auth.c:1801 +#: libpq/auth.c:1803 #, c-format msgid "pam_authenticate failed: %s" msgstr "ошибка в pam_authenticate: %s" -#: libpq/auth.c:1812 +#: libpq/auth.c:1814 #, c-format msgid "pam_acct_mgmt failed: %s" msgstr "ошибка в pam_acct_mgmt: %s" -#: libpq/auth.c:1823 +#: libpq/auth.c:1825 #, c-format msgid "could not release PAM authenticator: %s" msgstr "не удалоÑÑŒ оÑвободить аутентификатор PAM: %s" -#: libpq/auth.c:1856 +#: libpq/auth.c:1858 #, c-format msgid "could not initialize LDAP: %m" msgstr "не удалоÑÑŒ инициализировать LDAP: %m" -#: libpq/auth.c:1859 +#: libpq/auth.c:1861 #, c-format msgid "could not initialize LDAP: error code %d" msgstr "не удалоÑÑŒ инициализировать LDAP (код ошибки: %d)" -#: libpq/auth.c:1869 +#: libpq/auth.c:1871 #, c-format msgid "could not set LDAP protocol version: %s" msgstr "не удалоÑÑŒ задать верÑию протокола LDAP: %s" -#: libpq/auth.c:1898 +#: libpq/auth.c:1900 #, c-format msgid "could not load wldap32.dll" msgstr "не удалоÑÑŒ загрузить wldap32.dll" -#: libpq/auth.c:1906 +#: libpq/auth.c:1908 #, c-format msgid "could not load function _ldap_start_tls_sA in wldap32.dll" msgstr "не удалоÑÑŒ найти функцию _ldap_start_tls_sA в wldap32.dll" -#: libpq/auth.c:1907 +#: libpq/auth.c:1909 #, c-format msgid "LDAP over SSL is not supported on this platform." msgstr "LDAP через SSL не поддерживаетÑÑ Ð² Ñтой ОС." -#: libpq/auth.c:1922 +#: libpq/auth.c:1924 #, c-format msgid "could not start LDAP TLS session: %s" msgstr "не удалоÑÑŒ начать ÑÐµÐ°Ð½Ñ LDAP TLS: %s" -#: libpq/auth.c:1944 +#: libpq/auth.c:1946 #, c-format msgid "LDAP server not specified" msgstr "LDAP-Ñервер не определён" -#: libpq/auth.c:1997 +#: libpq/auth.c:1999 #, c-format msgid "invalid character in user name for LDAP authentication" msgstr "недопуÑтимый Ñимвол в имени Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ подлинноÑти LDAP" -#: libpq/auth.c:2012 +#: libpq/auth.c:2014 #, c-format msgid "" "could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": " @@ -11226,28 +11200,28 @@ msgstr "" "не удалоÑÑŒ выполнить начальную привÑзку LDAP Ð´Ð»Ñ ldapbinddn \"%s\" на " "Ñервере \"%s\": %s" -#: libpq/auth.c:2036 +#: libpq/auth.c:2038 #, c-format msgid "could not search LDAP for filter \"%s\" on server \"%s\": %s" msgstr "" "не удалоÑÑŒ выполнить LDAP-поиÑк по фильтру \"%s\" на Ñервере \"%s\": %s" -#: libpq/auth.c:2047 +#: libpq/auth.c:2049 #, c-format msgid "LDAP user \"%s\" does not exist" msgstr "в LDAP нет Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\"" -#: libpq/auth.c:2048 +#: libpq/auth.c:2050 #, c-format msgid "LDAP search for filter \"%s\" on server \"%s\" returned no entries." msgstr "LDAP-поиÑк по фильтру \"%s\" на Ñервере \"%s\" не вернул результатов" -#: libpq/auth.c:2052 +#: libpq/auth.c:2054 #, c-format msgid "LDAP user \"%s\" is not unique" msgstr "пользователь LDAP \"%s\" не уникален" -#: libpq/auth.c:2053 +#: libpq/auth.c:2055 #, c-format msgid "LDAP search for filter \"%s\" on server \"%s\" returned %d entry." msgid_plural "" @@ -11256,7 +11230,7 @@ msgstr[0] "LDAP-поиÑк по фильтру \"%s\" на Ñервере \"%s\" msgstr[1] "LDAP-поиÑк по фильтру \"%s\" на Ñервере \"%s\" вернул %d запиÑи." msgstr[2] "LDAP-поиÑк по фильтру \"%s\" на Ñервере \"%s\" вернул %d запиÑей." -#: libpq/auth.c:2071 +#: libpq/auth.c:2073 #, c-format msgid "" "could not get dn for the first entry matching \"%s\" on server \"%s\": %s" @@ -11264,19 +11238,19 @@ msgstr "" "не удалоÑÑŒ получить dn Ð´Ð»Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ результата, ÑоответÑтвующего \"%s\" на " "Ñервере \"%s\": %s" -#: libpq/auth.c:2091 +#: libpq/auth.c:2093 #, c-format msgid "could not unbind after searching for user \"%s\" on server \"%s\": %s" msgstr "" "не удалоÑÑŒ отвÑзатьÑÑ Ð¿Ð¾Ñле поиÑка Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\" на Ñервере \"%s\": %s" -#: libpq/auth.c:2121 +#: libpq/auth.c:2123 #, c-format msgid "LDAP login failed for user \"%s\" on server \"%s\": %s" msgstr "" "ошибка при региÑтрации в LDAP Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\" на Ñервере \"%s\": %s" -#: libpq/auth.c:2149 +#: libpq/auth.c:2151 #, c-format msgid "" "certificate authentication failed for user \"%s\": client certificate " @@ -11285,98 +11259,98 @@ msgstr "" "ошибка проверки подлинноÑти Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\" по Ñертификату: Ñертификат " "клиента не Ñодержит Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" -#: libpq/auth.c:2272 +#: libpq/auth.c:2274 #, c-format msgid "RADIUS server not specified" msgstr "RADIUS-Ñервер не определён" -#: libpq/auth.c:2279 +#: libpq/auth.c:2281 #, c-format msgid "RADIUS secret not specified" msgstr "Ñекрет RADIUS не определён" -#: libpq/auth.c:2295 libpq/hba.c:1590 +#: libpq/auth.c:2297 libpq/hba.c:1590 #, c-format msgid "could not translate RADIUS server name \"%s\" to address: %s" msgstr "не удалоÑÑŒ преобразовать Ð¸Ð¼Ñ Ñервера RADIUS \"%s\" в адреÑ: %s" -#: libpq/auth.c:2323 +#: libpq/auth.c:2325 #, c-format msgid "" "RADIUS authentication does not support passwords longer than 16 characters" msgstr "проверка подлинноÑти RADIUS не поддерживает пароли длиннее 16 Ñимволов" -#: libpq/auth.c:2334 +#: libpq/auth.c:2336 #, c-format msgid "could not generate random encryption vector" msgstr "не удалоÑÑŒ Ñгенерировать Ñлучайный вектор шифрованиÑ" -#: libpq/auth.c:2357 +#: libpq/auth.c:2359 #, c-format msgid "could not perform MD5 encryption of password" msgstr "не удалоÑÑŒ вычиÑлить MD5-хеш паролÑ" -#: libpq/auth.c:2379 +#: libpq/auth.c:2381 #, c-format msgid "could not create RADIUS socket: %m" msgstr "не удалоÑÑŒ Ñоздать Ñокет RADIUS: %m" -#: libpq/auth.c:2400 +#: libpq/auth.c:2402 #, c-format msgid "could not bind local RADIUS socket: %m" msgstr "не удалоÑÑŒ привÑзатьÑÑ Ðº локальному Ñокету RADIUS: %m" -#: libpq/auth.c:2410 +#: libpq/auth.c:2412 #, c-format msgid "could not send RADIUS packet: %m" msgstr "не удалоÑÑŒ отправить пакет RADIUS: %m" -#: libpq/auth.c:2443 libpq/auth.c:2468 +#: libpq/auth.c:2445 libpq/auth.c:2470 #, c-format msgid "timeout waiting for RADIUS response" msgstr "превышено Ð²Ñ€ÐµÐ¼Ñ Ð¾Ð¶Ð¸Ð´Ð°Ð½Ð¸Ñ Ð¾Ñ‚Ð²ÐµÑ‚Ð° RADIUS" -#: libpq/auth.c:2461 +#: libpq/auth.c:2463 #, c-format msgid "could not check status on RADIUS socket: %m" msgstr "не удалоÑÑŒ проверить ÑоÑтоÑние Ñокета RADIUS: %m" -#: libpq/auth.c:2490 +#: libpq/auth.c:2492 #, c-format msgid "could not read RADIUS response: %m" msgstr "не удалоÑÑŒ прочитать ответ RADIUS: %m" -#: libpq/auth.c:2502 libpq/auth.c:2506 +#: libpq/auth.c:2504 libpq/auth.c:2508 #, c-format msgid "RADIUS response was sent from incorrect port: %d" msgstr "ответ RADIUS был отправлен Ñ Ð½ÐµÐ²ÐµÑ€Ð½Ð¾Ð³Ð¾ порта: %d" -#: libpq/auth.c:2515 +#: libpq/auth.c:2517 #, c-format msgid "RADIUS response too short: %d" msgstr "Ñлишком короткий ответ RADIUS: %d" -#: libpq/auth.c:2522 +#: libpq/auth.c:2524 #, c-format msgid "RADIUS response has corrupt length: %d (actual length %d)" msgstr "в ответе RADIUS иÑпорчена длина: %d (фактичеÑÐºÐ°Ñ Ð´Ð»Ð¸Ð½Ð° %d)" -#: libpq/auth.c:2530 +#: libpq/auth.c:2532 #, c-format msgid "RADIUS response is to a different request: %d (should be %d)" msgstr "пришёл ответ RADIUS на другой запроÑ: %d (ожидалÑÑ %d)" -#: libpq/auth.c:2555 +#: libpq/auth.c:2557 #, c-format msgid "could not perform MD5 encryption of received packet" msgstr "не удалоÑÑŒ вычиÑлить MD5 Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð½Ñтого пакета" -#: libpq/auth.c:2564 +#: libpq/auth.c:2566 #, c-format msgid "RADIUS response has incorrect MD5 signature" msgstr "ответ RADIUS Ñодержит неверную подпиÑÑŒ MD5" -#: libpq/auth.c:2581 +#: libpq/auth.c:2583 #, c-format msgid "RADIUS response has invalid code (%d) for user \"%s\"" msgstr "ответ RADIUS Ñодержит неверный код (%d) Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\"" @@ -11519,67 +11493,67 @@ msgid "could not load SSL certificate revocation list file \"%s\": %s" msgstr "" "не удалоÑÑŒ загрузить файл Ñо ÑпиÑком отзыва Ñертификатов SSL \"%s\": %s" -#: libpq/be-secure-openssl.c:341 +#: libpq/be-secure-openssl.c:342 #, c-format msgid "could not initialize SSL connection: %s" msgstr "инициализировать SSL-подключение не удалоÑÑŒ: %s" -#: libpq/be-secure-openssl.c:349 +#: libpq/be-secure-openssl.c:350 #, c-format msgid "could not set SSL socket: %s" msgstr "не удалоÑÑŒ Ñоздать SSL-Ñокет: %s" -#: libpq/be-secure-openssl.c:383 +#: libpq/be-secure-openssl.c:404 #, c-format msgid "could not accept SSL connection: %m" msgstr "не удалоÑÑŒ принÑть SSL-подключение: %m" -#: libpq/be-secure-openssl.c:387 libpq/be-secure-openssl.c:398 +#: libpq/be-secure-openssl.c:408 libpq/be-secure-openssl.c:419 #, c-format msgid "could not accept SSL connection: EOF detected" msgstr "не удалоÑÑŒ принÑть SSL-подключение: обрыв данных" -#: libpq/be-secure-openssl.c:392 +#: libpq/be-secure-openssl.c:413 #, c-format msgid "could not accept SSL connection: %s" msgstr "не удалоÑÑŒ принÑть SSL-подключение: %s" -#: libpq/be-secure-openssl.c:403 libpq/be-secure-openssl.c:541 -#: libpq/be-secure-openssl.c:598 +#: libpq/be-secure-openssl.c:424 libpq/be-secure-openssl.c:565 +#: libpq/be-secure-openssl.c:625 #, c-format msgid "unrecognized SSL error code: %d" msgstr "нераÑпознанный код ошибки SSL: %d" -#: libpq/be-secure-openssl.c:447 +#: libpq/be-secure-openssl.c:468 #, c-format msgid "SSL certificate's common name contains embedded null" msgstr "Ð˜Ð¼Ñ SSL-Ñертификата включает нулевой байт" -#: libpq/be-secure-openssl.c:458 +#: libpq/be-secure-openssl.c:479 #, c-format msgid "SSL connection from \"%s\"" msgstr "SSL-подключение от \"%s\"" -#: libpq/be-secure-openssl.c:532 libpq/be-secure-openssl.c:589 +#: libpq/be-secure-openssl.c:556 libpq/be-secure-openssl.c:616 #, c-format msgid "SSL error: %s" msgstr "ошибка SSL: %s" -#: libpq/be-secure-openssl.c:937 +#: libpq/be-secure-openssl.c:965 #, c-format msgid "ECDH: unrecognized curve name: %s" msgstr "ECDH: нераÑпознанное Ð¸Ð¼Ñ ÐºÑ€Ð¸Ð²Ð¾Ð¹: %s" -#: libpq/be-secure-openssl.c:942 +#: libpq/be-secure-openssl.c:970 #, c-format msgid "ECDH: could not create key" msgstr "ECDH: не удалоÑÑŒ Ñоздать ключ" -#: libpq/be-secure-openssl.c:966 +#: libpq/be-secure-openssl.c:994 msgid "no SSL error reported" msgstr "нет ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ð± ошибке SSL" -#: libpq/be-secure-openssl.c:970 +#: libpq/be-secure-openssl.c:998 #, c-format msgid "SSL error code %lu" msgstr "код ошибки SSL: %lu" @@ -12100,12 +12074,12 @@ msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñтрока в Ñообщении" msgid "invalid message format" msgstr "неверный формат ÑообщениÑ" -#: main/main.c:259 +#: main/main.c:264 #, c-format msgid "%s: WSAStartup failed: %d\n" msgstr "%s: ошибка WSAStartup: %d\n" -#: main/main.c:306 +#: main/main.c:327 #, c-format msgid "" "%s is the PostgreSQL server.\n" @@ -12114,7 +12088,7 @@ msgstr "" "%s - Ñервер PostgreSQL.\n" "\n" -#: main/main.c:307 +#: main/main.c:328 #, c-format msgid "" "Usage:\n" @@ -12125,114 +12099,114 @@ msgstr "" " %s [ПÐРÐМЕТР]...\n" "\n" -#: main/main.c:308 +#: main/main.c:329 #, c-format msgid "Options:\n" msgstr "Параметры:\n" -#: main/main.c:309 +#: main/main.c:330 #, c-format msgid " -B NBUFFERS number of shared buffers\n" msgstr " -B ЧИСЛО_БУФ чиÑло разделÑемых буферов\n" -#: main/main.c:310 +#: main/main.c:331 #, c-format msgid " -c NAME=VALUE set run-time parameter\n" msgstr " -c ИМЯ=ЗÐÐЧЕÐИЕ уÑтановить параметр выполнениÑ\n" -#: main/main.c:311 +#: main/main.c:332 #, c-format msgid " -C NAME print value of run-time parameter, then exit\n" msgstr " -C ИМЯ вывеÑти значение параметра Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¸ выйти\n" -#: main/main.c:312 +#: main/main.c:333 #, c-format msgid " -d 1-5 debugging level\n" msgstr " -d 1-5 уровень отладочных Ñообщений\n" -#: main/main.c:313 +#: main/main.c:334 #, c-format msgid " -D DATADIR database directory\n" msgstr " -D КÐТÐЛОГ каталог Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼Ð¸\n" -#: main/main.c:314 +#: main/main.c:335 #, c-format msgid " -e use European date input format (DMY)\n" msgstr " -e иÑпользовать европейÑкий формат дат (ДМГ)\n" -#: main/main.c:315 +#: main/main.c:336 #, c-format msgid " -F turn fsync off\n" msgstr " -F выключить Ñинхронизацию Ñ Ð¤Ð¡\n" -#: main/main.c:316 +#: main/main.c:337 #, c-format msgid " -h HOSTNAME host name or IP address to listen on\n" msgstr " -h ИМЯ Ð¸Ð¼Ñ Ð¸Ð»Ð¸ IP-Ð°Ð´Ñ€ÐµÑ Ð´Ð»Ñ Ð¿Ñ€Ð¸Ñ‘Ð¼Ð° Ñетевых Ñоединений\n" -#: main/main.c:317 +#: main/main.c:338 #, c-format msgid " -i enable TCP/IP connections\n" msgstr " -i включить ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ TCP/IP\n" -#: main/main.c:318 +#: main/main.c:339 #, c-format msgid " -k DIRECTORY Unix-domain socket location\n" msgstr " -k КÐТÐЛОГ раÑположение доменных Ñокетов Unix\n" -#: main/main.c:320 +#: main/main.c:341 #, c-format msgid " -l enable SSL connections\n" msgstr " -l разрешить SSL-подключениÑ\n" -#: main/main.c:322 +#: main/main.c:343 #, c-format msgid " -N MAX-CONNECT maximum number of allowed connections\n" msgstr " -N МÐКС_ПОДКЛ предельное чиÑло подключений\n" -#: main/main.c:323 +#: main/main.c:344 #, c-format msgid "" " -o OPTIONS pass \"OPTIONS\" to each server process (obsolete)\n" msgstr "" " -o ПÐРÐМЕТРЫ параметры Ð´Ð»Ñ Ñерверных процеÑÑов (уже неактуально)\n" -#: main/main.c:324 +#: main/main.c:345 #, c-format msgid " -p PORT port number to listen on\n" msgstr " -p ПОРТ номер порта Ð´Ð»Ñ Ð¿Ñ€Ð¸Ñ‘Ð¼Ð° подключений\n" -#: main/main.c:325 +#: main/main.c:346 #, c-format msgid " -s show statistics after each query\n" msgstr " -s показывать ÑтатиÑтику поÑле каждого запроÑа\n" -#: main/main.c:326 +#: main/main.c:347 #, c-format msgid " -S WORK-MEM set amount of memory for sorts (in kB)\n" msgstr " -S РÐБ_ПÐМЯТЬ задать объём памÑти Ð´Ð»Ñ Ñортировки (в КБ)\n" -#: main/main.c:327 +#: main/main.c:348 #, c-format msgid " -V, --version output version information, then exit\n" msgstr " -V, --version показать верÑию и выйти\n" -#: main/main.c:328 +#: main/main.c:349 #, c-format msgid " --NAME=VALUE set run-time parameter\n" msgstr " --ИМЯ=ЗÐÐЧЕÐИЕ уÑтановить параметр выполнениÑ\n" -#: main/main.c:329 +#: main/main.c:350 #, c-format msgid " --describe-config describe configuration parameters, then exit\n" msgstr " --describe-config вывеÑти параметры конфигурации и выйти\n" -#: main/main.c:330 +#: main/main.c:351 #, c-format msgid " -?, --help show this help, then exit\n" msgstr " -?, --help показать Ñту Ñправку и выйти\n" -#: main/main.c:332 +#: main/main.c:353 #, c-format msgid "" "\n" @@ -12241,12 +12215,12 @@ msgstr "" "\n" "Параметры Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ¾Ð²:\n" -#: main/main.c:333 +#: main/main.c:354 #, c-format msgid " -f s|i|n|m|h forbid use of some plan types\n" msgstr " -f s|i|n|m|h запретить некоторые типы планов\n" -#: main/main.c:334 +#: main/main.c:355 #, c-format msgid "" " -n do not reinitialize shared memory after abnormal exit\n" @@ -12254,22 +12228,22 @@ msgstr "" " -n не переинициализировать разделÑемую памÑть поÑле\n" " аварийного выхода\n" -#: main/main.c:335 +#: main/main.c:356 #, c-format msgid " -O allow system table structure changes\n" msgstr " -O разрешить изменÑть Ñтруктуру ÑиÑтемных таблиц\n" -#: main/main.c:336 +#: main/main.c:357 #, c-format msgid " -P disable system indexes\n" msgstr " -P отключить ÑиÑтемные индекÑÑ‹\n" -#: main/main.c:337 +#: main/main.c:358 #, c-format msgid " -t pa|pl|ex show timings after each query\n" msgstr " -t pa|pl|ex показать Ð²Ñ€ÐµÐ¼Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ запроÑа\n" -#: main/main.c:338 +#: main/main.c:359 #, c-format msgid "" " -T send SIGSTOP to all backend processes if one dies\n" @@ -12277,13 +12251,13 @@ msgstr "" " -T поÑылать Ñигнал SIGSTOP вÑем Ñерверным процеÑÑам\n" " при отключении одного\n" -#: main/main.c:339 +#: main/main.c:360 #, c-format msgid " -W NUM wait NUM seconds to allow attach from a debugger\n" msgstr "" " -W СЕК ждать заданное чиÑло Ñекунд Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ð»Ð°Ð´Ñ‡Ð¸ÐºÐ°\n" -#: main/main.c:341 +#: main/main.c:362 #, c-format msgid "" "\n" @@ -12292,7 +12266,7 @@ msgstr "" "\n" "Параметры Ð´Ð»Ñ Ð¼Ð¾Ð½Ð¾Ð¿Ð¾Ð»ÑŒÐ½Ð¾Ð³Ð¾ режима:\n" -#: main/main.c:342 +#: main/main.c:363 #, c-format msgid "" " --single selects single-user mode (must be first argument)\n" @@ -12300,22 +12274,22 @@ msgstr "" " --single включить монопольный режим\n" " (Ñтот аргумент должен быть первым)\n" -#: main/main.c:343 +#: main/main.c:364 #, c-format msgid " DBNAME database name (defaults to user name)\n" msgstr " ИМЯ_БД база данных (по умолчанию - Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ)\n" -#: main/main.c:344 +#: main/main.c:365 #, c-format msgid " -d 0-5 override debugging level\n" msgstr " -d 0-5 переопределить уровень отладочных Ñообщений\n" -#: main/main.c:345 +#: main/main.c:366 #, c-format msgid " -E echo statement before execution\n" msgstr " -E выводить SQL-операторы перед выполнением\n" -#: main/main.c:346 +#: main/main.c:367 #, c-format msgid "" " -j do not use newline as interactive query delimiter\n" @@ -12323,12 +12297,12 @@ msgstr "" " -j не Ñчитать конец Ñтроки разделителем интерактивных " "запроÑов\n" -#: main/main.c:347 main/main.c:352 +#: main/main.c:368 main/main.c:373 #, c-format msgid " -r FILENAME send stdout and stderr to given file\n" msgstr " -r ИМЯ_ФÐЙЛРперенаправить STDOUT и STDERR в указанный файл\n" -#: main/main.c:349 +#: main/main.c:370 #, c-format msgid "" "\n" @@ -12337,7 +12311,7 @@ msgstr "" "\n" "Параметры Ð´Ð»Ñ Ñ€ÐµÐ¶Ð¸Ð¼Ð° инициализации:\n" -#: main/main.c:350 +#: main/main.c:371 #, c-format msgid "" " --boot selects bootstrapping mode (must be first argument)\n" @@ -12345,7 +12319,7 @@ msgstr "" " --boot включить режим инициализации\n" " (Ñтот аргумент должен быть первым)\n" -#: main/main.c:351 +#: main/main.c:372 #, c-format msgid "" " DBNAME database name (mandatory argument in bootstrapping " @@ -12353,12 +12327,12 @@ msgid "" msgstr "" " ИМЯ_БД Ð¸Ð¼Ñ Ð±Ð°Ð·Ñ‹ данных (необходимо в режиме инициализации)\n" -#: main/main.c:353 +#: main/main.c:374 #, c-format msgid " -x NUM internal use\n" msgstr " -x ЧИСЛО параметр Ð´Ð»Ñ Ð²Ð½ÑƒÑ‚Ñ€ÐµÐ½Ð½ÐµÐ³Ð¾ иÑпользованиÑ\n" -#: main/main.c:355 +#: main/main.c:376 #, c-format msgid "" "\n" @@ -12375,7 +12349,7 @@ msgstr "" "\n" "Об ошибках Ñообщайте по адреÑу .\n" -#: main/main.c:369 +#: main/main.c:390 #, c-format msgid "" "\"root\" execution of the PostgreSQL server is not permitted.\n" @@ -12388,12 +12362,12 @@ msgstr "" "должен запуÑкать обычный пользователь. Подробнее о том, как\n" "правильно запуÑкать Ñервер, вы можете узнать в документации.\n" -#: main/main.c:386 +#: main/main.c:407 #, c-format msgid "%s: real and effective user IDs must match\n" msgstr "%s: фактичеÑкий и Ñффективный ID Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ‹ Ñовпадать\n" -#: main/main.c:393 +#: main/main.c:414 #, c-format msgid "" "Execution of PostgreSQL by a user with administrative permissions is not\n" @@ -12410,7 +12384,7 @@ msgstr "" #: nodes/nodeFuncs.c:118 nodes/nodeFuncs.c:149 parser/parse_coerce.c:1820 #: parser/parse_coerce.c:1848 parser/parse_coerce.c:1924 -#: parser/parse_expr.c:1981 parser/parse_func.c:597 parser/parse_oper.c:952 +#: parser/parse_expr.c:1994 parser/parse_func.c:597 parser/parse_oper.c:952 #, c-format msgid "could not find array type for data type %s" msgstr "тип маÑÑива Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° данных %s не найден" @@ -12455,18 +12429,18 @@ msgid "%s cannot be applied to the nullable side of an outer join" msgstr "%s не может применÑтьÑÑ Ðº NULL-Ñодержащей Ñтороне внешнего ÑоединениÑ" #. translator: %s is a SQL row locking clause such as FOR UPDATE -#: optimizer/plan/planner.c:1330 parser/analyze.c:1481 parser/analyze.c:1679 +#: optimizer/plan/planner.c:1341 parser/analyze.c:1481 parser/analyze.c:1679 #: parser/analyze.c:2460 #, c-format msgid "%s is not allowed with UNION/INTERSECT/EXCEPT" msgstr "%s неÑовмеÑтимо Ñ UNION/INTERSECT/EXCEPT" -#: optimizer/plan/planner.c:3587 +#: optimizer/plan/planner.c:3598 #, c-format msgid "could not implement GROUP BY" msgstr "не удалоÑÑŒ реализовать GROUP BY" -#: optimizer/plan/planner.c:3588 optimizer/plan/planner.c:3756 +#: optimizer/plan/planner.c:3599 optimizer/plan/planner.c:3767 #: optimizer/prep/prepunion.c:828 #, c-format msgid "" @@ -12476,27 +12450,27 @@ msgstr "" "Одни типы данных поддерживают только хеширование, а другие - только " "Ñортировку." -#: optimizer/plan/planner.c:3755 +#: optimizer/plan/planner.c:3766 #, c-format msgid "could not implement DISTINCT" msgstr "не удалоÑÑŒ реализовать DISTINCT" -#: optimizer/plan/planner.c:4361 +#: optimizer/plan/planner.c:4372 #, c-format msgid "could not implement window PARTITION BY" msgstr "не удалоÑÑŒ реализовать PARTITION BY Ð´Ð»Ñ Ð¾ÐºÐ½Ð°" -#: optimizer/plan/planner.c:4362 +#: optimizer/plan/planner.c:4373 #, c-format msgid "Window partitioning columns must be of sortable datatypes." msgstr "Столбцы, разбивающие окна, должны иметь Ñортируемые типы данных." -#: optimizer/plan/planner.c:4366 +#: optimizer/plan/planner.c:4377 #, c-format msgid "could not implement window ORDER BY" msgstr "не удалоÑÑŒ реализовать ORDER BY Ð´Ð»Ñ Ð¾ÐºÐ½Ð°" -#: optimizer/plan/planner.c:4367 +#: optimizer/plan/planner.c:4378 #, c-format msgid "Window ordering columns must be of sortable datatypes." msgstr "Столбцы, Ñортирующие окна, должны иметь Ñортируемые типы данных." @@ -12534,22 +12508,24 @@ msgstr "" "обращатьÑÑ Ðº временным или нежурналируемым отношениÑм в процеÑÑе " "воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð½ÐµÐ»ÑŒÐ·Ñ" -#: optimizer/util/plancat.c:498 +#: optimizer/util/plancat.c:490 #, c-format -msgid "system columns cannot be used in an ON CONFLICT clause" -msgstr "ÑиÑтемные Ñтолбцы Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать в предложении ON CONFLICT" +msgid "whole row unique index inference specifications are not supported" +msgstr "" +"ÑƒÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ñо ÑÑылкой на вÑÑŽ Ñтроку Ð´Ð»Ñ Ð²Ñ‹Ð±Ð¾Ñ€Ð° уникального индекÑа не " +"поддерживаютÑÑ" -#: optimizer/util/plancat.c:516 +#: optimizer/util/plancat.c:507 #, c-format msgid "constraint in ON CONFLICT clause has no associated index" msgstr "ограничению в ON CONFLICT не ÑоответÑтвует индекÑ" -#: optimizer/util/plancat.c:568 +#: optimizer/util/plancat.c:558 #, c-format msgid "ON CONFLICT DO UPDATE not supported with exclusion constraints" msgstr "ON CONFLICT DO UPDATE не поддерживаетÑÑ Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñми-иÑключениÑми" -#: optimizer/util/plancat.c:675 +#: optimizer/util/plancat.c:663 #, c-format msgid "" "there is no unique or exclusion constraint matching the ON CONFLICT " @@ -13265,7 +13241,7 @@ msgstr "" #: parser/parse_coerce.c:971 parser/parse_coerce.c:1001 #: parser/parse_coerce.c:1019 parser/parse_coerce.c:1034 -#: parser/parse_expr.c:2015 parser/parse_expr.c:2528 parser/parse_target.c:874 +#: parser/parse_expr.c:2028 parser/parse_expr.c:2552 parser/parse_target.c:874 #, c-format msgid "cannot cast type %s to %s" msgstr "привеÑти тип %s к %s нельзÑ" @@ -13574,141 +13550,141 @@ msgstr "Ð½ÐµÐ¾Ð´Ð½Ð¾Ð·Ð½Ð°Ñ‡Ð½Ð°Ñ ÑÑылка на Ñтолбец \"%s\"" msgid "there is no parameter $%d" msgstr "параметр $%d не ÑущеÑтвует" -#: parser/parse_expr.c:1034 +#: parser/parse_expr.c:1042 #, c-format msgid "NULLIF requires = operator to yield boolean" msgstr "Ð´Ð»Ñ NULLIF требуетÑÑ, чтобы оператор = возвращал логичеÑкое значение" -#: parser/parse_expr.c:1468 gram.y:9745 +#: parser/parse_expr.c:1476 gram.y:9745 #, c-format msgid "number of columns does not match number of values" msgstr "чиÑло Ñтолбцов не равно чиÑлу значений" -#: parser/parse_expr.c:1697 +#: parser/parse_expr.c:1705 msgid "cannot use subquery in check constraint" msgstr "в ограничении-проверке Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать подзапроÑÑ‹" -#: parser/parse_expr.c:1701 +#: parser/parse_expr.c:1709 msgid "cannot use subquery in DEFAULT expression" msgstr "в выражении DEFAULT Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать подзапроÑÑ‹" -#: parser/parse_expr.c:1704 +#: parser/parse_expr.c:1712 msgid "cannot use subquery in index expression" msgstr "в индекÑном выражении Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать подзапроÑÑ‹" -#: parser/parse_expr.c:1707 +#: parser/parse_expr.c:1715 msgid "cannot use subquery in index predicate" msgstr "в предикате индекÑа Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать подзапроÑÑ‹" -#: parser/parse_expr.c:1710 +#: parser/parse_expr.c:1718 msgid "cannot use subquery in transform expression" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать Ð¿Ð¾Ð´Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð² выражении преобразованиÑ" -#: parser/parse_expr.c:1713 +#: parser/parse_expr.c:1721 msgid "cannot use subquery in EXECUTE parameter" msgstr "в качеÑтве параметра EXECUTE Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать подзапроÑ" -#: parser/parse_expr.c:1716 +#: parser/parse_expr.c:1724 msgid "cannot use subquery in trigger WHEN condition" msgstr "в уÑловии WHEN Ð´Ð»Ñ Ñ‚Ñ€Ð¸Ð³Ð³ÐµÑ€Ð° Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать подзапроÑÑ‹" -#: parser/parse_expr.c:1770 +#: parser/parse_expr.c:1778 #, c-format msgid "subquery must return only one column" msgstr "Ð¿Ð¾Ð´Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ вернуть только один Ñтолбец" -#: parser/parse_expr.c:1854 +#: parser/parse_expr.c:1862 #, c-format msgid "subquery has too many columns" msgstr "в подзапроÑе Ñлишком много Ñтолбцов" -#: parser/parse_expr.c:1859 +#: parser/parse_expr.c:1867 #, c-format msgid "subquery has too few columns" msgstr "в подзапроÑе недоÑтаточно Ñтолбцов" -#: parser/parse_expr.c:1955 +#: parser/parse_expr.c:1968 #, c-format msgid "cannot determine type of empty array" msgstr "тип пуÑтого маÑÑива определить нельзÑ" -#: parser/parse_expr.c:1956 +#: parser/parse_expr.c:1969 #, c-format msgid "Explicitly cast to the desired type, for example ARRAY[]::integer[]." msgstr "" "Приведите его к желаемому типу Ñвным образом, например ARRAY[]::integer[]." -#: parser/parse_expr.c:1970 +#: parser/parse_expr.c:1983 #, c-format msgid "could not find element type for data type %s" msgstr "не удалоÑÑŒ определить тип Ñлемента Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° данных %s" -#: parser/parse_expr.c:2193 +#: parser/parse_expr.c:2206 #, c-format msgid "unnamed XML attribute value must be a column reference" msgstr "вмеÑто Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ XML-атрибута без имени должен указыватьÑÑ Ñтолбец" -#: parser/parse_expr.c:2194 +#: parser/parse_expr.c:2207 #, c-format msgid "unnamed XML element value must be a column reference" msgstr "вмеÑто Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ XML-Ñлемента без имени должен указыватьÑÑ Ñтолбец" -#: parser/parse_expr.c:2209 +#: parser/parse_expr.c:2222 #, c-format msgid "XML attribute name \"%s\" appears more than once" msgstr "Ð¸Ð¼Ñ XML-атрибута \"%s\" указано неоднократно" -#: parser/parse_expr.c:2316 +#: parser/parse_expr.c:2329 #, c-format msgid "cannot cast XMLSERIALIZE result to %s" msgstr "привеÑти результат XMLSERIALIZE к типу %s нельзÑ" -#: parser/parse_expr.c:2601 parser/parse_expr.c:2797 +#: parser/parse_expr.c:2625 parser/parse_expr.c:2821 #, c-format msgid "unequal number of entries in row expressions" msgstr "разное чиÑло Ñлементов в Ñтроках" -#: parser/parse_expr.c:2611 +#: parser/parse_expr.c:2635 #, c-format msgid "cannot compare rows of zero length" msgstr "Ñтроки нулевой длины Ñравнивать нельзÑ" -#: parser/parse_expr.c:2636 +#: parser/parse_expr.c:2660 #, c-format msgid "row comparison operator must yield type boolean, not type %s" msgstr "" "оператор ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ñтрок должен выдавать результат логичеÑкого типа, а не %s" -#: parser/parse_expr.c:2643 +#: parser/parse_expr.c:2667 #, c-format msgid "row comparison operator must not return a set" msgstr "оператор ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ñтрок не должен возвращать множеÑтво" -#: parser/parse_expr.c:2702 parser/parse_expr.c:2743 +#: parser/parse_expr.c:2726 parser/parse_expr.c:2767 #, c-format msgid "could not determine interpretation of row comparison operator %s" msgstr "не удалоÑÑŒ выбрать интерпретацию оператора ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ñтрок %s" -#: parser/parse_expr.c:2704 +#: parser/parse_expr.c:2728 #, c-format msgid "" "Row comparison operators must be associated with btree operator families." msgstr "" "Операторы ÑÑ€Ð°Ð²Ð½ÐµÐ½Ð¸Ñ Ñтрок должны быть ÑвÑзаны Ñ ÑемейÑтвом операторов btree." -#: parser/parse_expr.c:2745 +#: parser/parse_expr.c:2769 #, c-format msgid "There are multiple equally-plausible candidates." msgstr "ОказалоÑÑŒ неÑколько равноценных кандидатур." -#: parser/parse_expr.c:2837 +#: parser/parse_expr.c:2861 #, c-format msgid "IS DISTINCT FROM requires = operator to yield boolean" msgstr "" "Ð´Ð»Ñ IS DISTINCT FROM требуетÑÑ, чтобы оператор = возвращал логичеÑкое " "значение" -#: parser/parse_expr.c:3127 parser/parse_expr.c:3145 +#: parser/parse_expr.c:3151 parser/parse_expr.c:3169 #, c-format msgid "operator precedence change: %s is now lower precedence than %s" msgstr "" @@ -14600,12 +14576,12 @@ msgstr "гигантÑкие Ñтраницы на Ñтой платформе msgid "could not stat data directory \"%s\": %m" msgstr "не удалоÑÑŒ получить информацию о каталоге данных \"%s\": %m" -#: port/win32/crashdump.c:108 +#: port/win32/crashdump.c:122 #, c-format msgid "could not load dbghelp.dll, cannot write crash dump\n" msgstr "не удалоÑÑŒ загрузить dbghelp.dll, Ñохранить аварийный дамп нельзÑ\n" -#: port/win32/crashdump.c:116 +#: port/win32/crashdump.c:130 #, c-format msgid "" "could not load required functions in dbghelp.dll, cannot write crash dump\n" @@ -14613,17 +14589,17 @@ msgstr "" "не удалоÑÑŒ найти требуемые функции в dbghelp.dll, Ñохранить аварийный дамп " "нельзÑ\n" -#: port/win32/crashdump.c:147 +#: port/win32/crashdump.c:161 #, c-format msgid "could not open crash dump file \"%s\" for writing: error code %lu\n" msgstr "не удалоÑÑŒ открыть файл дампа \"%s\" Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи (код ошибки: %lu)\n" -#: port/win32/crashdump.c:154 +#: port/win32/crashdump.c:168 #, c-format msgid "wrote crash dump to file \"%s\"\n" msgstr "аварийный дамп запиÑан в файл\"%s\"\n" -#: port/win32/crashdump.c:156 +#: port/win32/crashdump.c:170 #, c-format msgid "could not write crash dump to file \"%s\": error code %lu\n" msgstr "не удалоÑÑŒ запиÑать аварийный дамп в файл \"%s\" (код ошибки: %lu)\n" @@ -14644,21 +14620,21 @@ msgid "could not get SID for PowerUsers group: error code %lu\n" msgstr "" "не удалоÑÑŒ получить SID группы Опытные пользователи (код ошибки: %lu)\n" -#: port/win32/signal.c:193 +#: port/win32/signal.c:194 #, c-format msgid "could not create signal listener pipe for PID %d: error code %lu" msgstr "" "не удалоÑÑŒ Ñоздать канал приёма Ñигналов Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑÑа Ñ PID %d (код ошибки: " "%lu)" -#: port/win32/signal.c:273 port/win32/signal.c:305 +#: port/win32/signal.c:274 port/win32/signal.c:306 #, c-format msgid "could not create signal listener pipe: error code %lu; retrying\n" msgstr "" "не удалоÑÑŒ Ñоздать канал приёма Ñигналов (код ошибки: %lu); ещё одна " "попытка...\n" -#: port/win32/signal.c:316 +#: port/win32/signal.c:317 #, c-format msgid "could not create signal dispatch thread: error code %lu\n" msgstr "не удалоÑÑŒ Ñоздать поток раÑÐ¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ñигналов (код ошибки: %lu)\n" @@ -14716,59 +14692,59 @@ msgstr "Ошибка в ÑиÑтемном вызове DuplicateHandle." msgid "Failed system call was MapViewOfFileEx." msgstr "Ошибка в ÑиÑтемном вызове MapViewOfFileEx." -#: postmaster/autovacuum.c:377 +#: postmaster/autovacuum.c:380 #, c-format msgid "could not fork autovacuum launcher process: %m" msgstr "породить процеÑÑ Ð·Ð°Ð¿ÑƒÑка автоочиÑтки не удалоÑÑŒ: %m" -#: postmaster/autovacuum.c:413 +#: postmaster/autovacuum.c:416 #, c-format msgid "autovacuum launcher started" msgstr "процеÑÑ Ð·Ð°Ð¿ÑƒÑка автоочиÑтки Ñоздан" -#: postmaster/autovacuum.c:775 +#: postmaster/autovacuum.c:779 #, c-format msgid "autovacuum launcher shutting down" msgstr "процеÑÑ Ð·Ð°Ð¿ÑƒÑка автоочиÑтки завершаетÑÑ" -#: postmaster/autovacuum.c:1443 +#: postmaster/autovacuum.c:1447 #, c-format msgid "could not fork autovacuum worker process: %m" msgstr "не удалоÑÑŒ породить рабочий процеÑÑ Ð°Ð²Ñ‚Ð¾Ð¾Ñ‡Ð¸Ñтки: %m" -#: postmaster/autovacuum.c:1639 +#: postmaster/autovacuum.c:1643 #, c-format msgid "autovacuum: processing database \"%s\"" msgstr "автоочиÑтка: обработка базы данных \"%s\"" -#: postmaster/autovacuum.c:2051 +#: postmaster/autovacuum.c:2056 #, c-format msgid "autovacuum: dropping orphan temp table \"%s\".\"%s\" in database \"%s\"" msgstr "" "автоочиÑтка: удаление уÑтаревшей врем. таблицы \"%s\".\"%s\" в базе \"%s\"" -#: postmaster/autovacuum.c:2063 +#: postmaster/autovacuum.c:2068 #, c-format msgid "autovacuum: found orphan temp table \"%s\".\"%s\" in database \"%s\"" msgstr "" "автоочиÑтка: найдена уÑÑ‚Ð°Ñ€ÐµÐ²ÑˆÐ°Ñ Ð²Ñ€ÐµÐ¼. таблица \"%s\".\"%s\" в базе \"%s\"" -#: postmaster/autovacuum.c:2346 +#: postmaster/autovacuum.c:2352 #, c-format msgid "automatic vacuum of table \"%s.%s.%s\"" msgstr "автоматичеÑÐºÐ°Ñ Ð¾Ñ‡Ð¸Ñтка таблицы \"%s.%s.%s\"" -#: postmaster/autovacuum.c:2349 +#: postmaster/autovacuum.c:2355 #, c-format msgid "automatic analyze of table \"%s.%s.%s\"" msgstr "автоматичеÑкий анализ таблицы \"%s.%s.%s\"" -#: postmaster/autovacuum.c:2877 +#: postmaster/autovacuum.c:2885 #, c-format msgid "autovacuum not started because of misconfiguration" msgstr "автоочиÑтка не запущена из-за неправильной конфигурации" -#: postmaster/autovacuum.c:2878 +#: postmaster/autovacuum.c:2886 #, c-format msgid "Enable the \"track_counts\" option." msgstr "Включите параметр \"track_counts\"." @@ -15142,7 +15118,7 @@ msgid "%s: invalid datetoken tables, please fix\n" msgstr "%s: ошибка в таблицах маркеров времени, требуетÑÑ Ð¸Ñправление\n" #: postmaster/postmaster.c:955 postmaster/postmaster.c:1053 -#: utils/init/miscinit.c:1400 +#: utils/init/miscinit.c:1410 #, c-format msgid "invalid list syntax in parameter \"%s\"" msgstr "неверный формат ÑпиÑка в параметре \"%s\"" @@ -15308,7 +15284,7 @@ msgstr "" "%u.0 - %u.%u " #: postmaster/postmaster.c:2050 utils/misc/guc.c:5484 utils/misc/guc.c:5577 -#: utils/misc/guc.c:6869 utils/misc/guc.c:9566 utils/misc/guc.c:9600 +#: utils/misc/guc.c:6874 utils/misc/guc.c:9579 utils/misc/guc.c:9613 #, c-format msgid "invalid value for parameter \"%s\": \"%s\"" msgstr "неверное значение Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° \"%s\": \"%s\"" @@ -15999,37 +15975,37 @@ msgstr "" "удалить иÑточник репликации Ñ OID %d нельзÑ, он иÑпользуетÑÑ Ð¿Ñ€Ð¾Ñ†ÐµÑÑом Ñ PID " "%d" -#: replication/logical/origin.c:690 +#: replication/logical/origin.c:671 #, c-format msgid "replication checkpoint has wrong magic %u instead of %u" msgstr "" "ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° репликации имеет неправильную Ñигнатуру (%u вмеÑто %u)" -#: replication/logical/origin.c:722 +#: replication/logical/origin.c:703 #, c-format msgid "could not read file \"%s\": read %d of %zu" msgstr "не удалоÑÑŒ прочитать файл \"%s\" (прочитано байт: %d из %zu)" -#: replication/logical/origin.c:731 +#: replication/logical/origin.c:712 #, c-format msgid "could not find free replication state, increase max_replication_slots" msgstr "" "не удалоÑÑŒ найти Ñвободную Ñчейку Ð´Ð»Ñ ÑоÑтоÑÐ½Ð¸Ñ Ñ€ÐµÐ¿Ð»Ð¸ÐºÐ°Ñ†Ð¸Ð¸, увеличьте " "max_replication_slots" -#: replication/logical/origin.c:749 +#: replication/logical/origin.c:730 #, c-format msgid "replication slot checkpoint has wrong checksum %u, expected %u" msgstr "" "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñумма файла контрольной точки Ð´Ð»Ñ Ñлота репликации (%u " "вмеÑто %u)" -#: replication/logical/origin.c:873 +#: replication/logical/origin.c:854 #, c-format msgid "replication origin with OID %d is already active for PID %d" msgstr "иÑточник репликации Ñ OID %d уже занÑÑ‚ процеÑÑом Ñ PID %d" -#: replication/logical/origin.c:884 replication/logical/origin.c:1064 +#: replication/logical/origin.c:865 replication/logical/origin.c:1045 #, c-format msgid "" "could not find free replication state slot for replication origin with OID %u" @@ -16037,41 +16013,41 @@ msgstr "" "не удалоÑÑŒ найти Ñвободный Ñлот ÑоÑтоÑÐ½Ð¸Ñ Ñ€ÐµÐ¿Ð»Ð¸ÐºÐ°Ñ†Ð¸Ð¸ Ð´Ð»Ñ Ð¸Ñточника " "репликации Ñ OID %u" -#: replication/logical/origin.c:886 replication/logical/origin.c:1066 +#: replication/logical/origin.c:867 replication/logical/origin.c:1047 #: replication/slot.c:1241 #, c-format msgid "Increase max_replication_slots and try again." msgstr "Увеличьте параметр max_replication_slots и повторите попытку." -#: replication/logical/origin.c:1023 +#: replication/logical/origin.c:1004 #, c-format msgid "cannot setup replication origin when one is already setup" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð½Ð°Ñтроить иÑточник репликации, когда он уже наÑтроен" -#: replication/logical/origin.c:1052 +#: replication/logical/origin.c:1033 #, c-format msgid "replication identifier %d is already active for PID %d" msgstr "идентификатор репликации %d уже занÑÑ‚ процеÑÑом Ñ PID %d" -#: replication/logical/origin.c:1098 replication/logical/origin.c:1293 -#: replication/logical/origin.c:1313 +#: replication/logical/origin.c:1079 replication/logical/origin.c:1274 +#: replication/logical/origin.c:1294 #, c-format msgid "no replication origin is configured" msgstr "ни один иÑточник репликации не наÑтроен" -#: replication/logical/reorderbuffer.c:2170 +#: replication/logical/reorderbuffer.c:2212 #, c-format msgid "could not write to data file for XID %u: %m" msgstr "не удалоÑÑŒ запиÑать в файл данных Ð´Ð»Ñ XID %u: %m" -#: replication/logical/reorderbuffer.c:2266 -#: replication/logical/reorderbuffer.c:2286 +#: replication/logical/reorderbuffer.c:2308 +#: replication/logical/reorderbuffer.c:2328 #, c-format msgid "could not read from reorderbuffer spill file: %m" msgstr "не удалоÑÑŒ прочитать из файла подкачки буфера переÑортировки: %m" -#: replication/logical/reorderbuffer.c:2270 -#: replication/logical/reorderbuffer.c:2290 +#: replication/logical/reorderbuffer.c:2312 +#: replication/logical/reorderbuffer.c:2332 #, c-format msgid "" "could not read from reorderbuffer spill file: read %d instead of %u bytes" @@ -16079,7 +16055,7 @@ msgstr "" "не удалоÑÑŒ прочитать из файла подкачки буфера переÑортировки (прочитано " "байт: %d, требовалоÑÑŒ: %u)" -#: replication/logical/reorderbuffer.c:2894 +#: replication/logical/reorderbuffer.c:2963 #, c-format msgid "could not read from file \"%s\": read %d instead of %d bytes" msgstr "" @@ -16097,29 +16073,29 @@ msgstr[1] "" msgstr[2] "" "ÑкÑпортирован Ñнимок логичеÑкого декодированиÑ: \"%s\" (ид. транзакций: %u)" -#: replication/logical/snapbuild.c:904 replication/logical/snapbuild.c:1269 -#: replication/logical/snapbuild.c:1800 +#: replication/logical/snapbuild.c:900 replication/logical/snapbuild.c:1265 +#: replication/logical/snapbuild.c:1796 #, c-format msgid "logical decoding found consistent point at %X/%X" msgstr "процеÑÑ Ð»Ð¾Ð³Ð¸Ñ‡ÐµÑкого Ð´ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¾Ñтиг точки ÑоглаÑованноÑти в %X/%X" -#: replication/logical/snapbuild.c:906 +#: replication/logical/snapbuild.c:902 #, c-format msgid "Transaction ID %u finished; no more running transactions." msgstr "Ð¢Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ñ %u завершена, больше активных транзакций нет." -#: replication/logical/snapbuild.c:1271 +#: replication/logical/snapbuild.c:1267 #, c-format msgid "There are no running transactions." msgstr "Больше активных транзакций нет." -#: replication/logical/snapbuild.c:1333 +#: replication/logical/snapbuild.c:1329 #, c-format msgid "logical decoding found initial starting point at %X/%X" msgstr "" "процеÑÑ Ð»Ð¾Ð³Ð¸Ñ‡ÐµÑкого Ð´ÐµÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ð°ÑˆÑ‘Ð» начальную Ñтартовую точку в %X/%X" -#: replication/logical/snapbuild.c:1335 +#: replication/logical/snapbuild.c:1331 #, c-format msgid "%u transaction needs to finish." msgid_plural "%u transactions need to finish." @@ -16127,36 +16103,36 @@ msgstr[0] "Ðеобходимо дождатьÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ‚Ñ€Ð°Ð½ msgstr[1] "Ðеобходимо дождатьÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¹ (%u)." msgstr[2] "Ðеобходимо дождатьÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ‚Ñ€Ð°Ð½Ð·Ð°ÐºÑ†Ð¸Ð¹ (%u)." -#: replication/logical/snapbuild.c:1674 replication/logical/snapbuild.c:1700 -#: replication/logical/snapbuild.c:1714 replication/logical/snapbuild.c:1728 +#: replication/logical/snapbuild.c:1670 replication/logical/snapbuild.c:1696 +#: replication/logical/snapbuild.c:1710 replication/logical/snapbuild.c:1724 #, c-format msgid "could not read file \"%s\", read %d of %d: %m" msgstr "не удалоÑÑŒ прочитать файл \"%s\" (прочитано байт: %d из %d): %m" -#: replication/logical/snapbuild.c:1680 +#: replication/logical/snapbuild.c:1676 #, c-format msgid "snapbuild state file \"%s\" has wrong magic number: %u instead of %u" msgstr "" "файл ÑоÑтоÑÐ½Ð¸Ñ snapbuild \"%s\" имеет неправильную Ñигнатуру (%u вмеÑто %u)" -#: replication/logical/snapbuild.c:1685 +#: replication/logical/snapbuild.c:1681 #, c-format msgid "snapbuild state file \"%s\" has unsupported version: %u instead of %u" msgstr "" "файл ÑоÑтоÑÐ½Ð¸Ñ snapbuild \"%s\" имеет неправильную верÑию (%u вмеÑто %u)" -#: replication/logical/snapbuild.c:1741 +#: replication/logical/snapbuild.c:1737 #, c-format msgid "checksum mismatch for snapbuild state file \"%s\": is %u, should be %u" msgstr "" "в файле ÑоÑтоÑÐ½Ð¸Ñ snapbuild \"%s\" Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñумма (%u вмеÑто %u)" -#: replication/logical/snapbuild.c:1802 +#: replication/logical/snapbuild.c:1798 #, c-format msgid "Logical decoding will begin using saved snapshot." msgstr "ЛогичеÑкое декодирование начнётÑÑ Ñ Ñохранённого Ñнимка." -#: replication/logical/snapbuild.c:1875 +#: replication/logical/snapbuild.c:1871 #, c-format msgid "could not parse file name \"%s\"" msgstr "не удалоÑÑŒ разобрать Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\"" @@ -16441,7 +16417,7 @@ msgstr "" "чиÑло запрошенных подключений резервных Ñерверов превоÑходит max_wal_senders " "(ÑейчаÑ: %d)" -#: rewrite/rewriteDefine.c:112 rewrite/rewriteDefine.c:961 +#: rewrite/rewriteDefine.c:112 rewrite/rewriteDefine.c:973 #, c-format msgid "rule \"%s\" for relation \"%s\" already exists" msgstr "правило \"%s\" Ð´Ð»Ñ Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ \"%s\" уже ÑущеÑтвует" @@ -16582,13 +16558,20 @@ msgstr "ÑпиÑок результата правила Ð´Ð»Ñ SELECT Ñоде msgid "RETURNING list has too many entries" msgstr "ÑпиÑок RETURNING Ñодержит Ñлишком много Ñтолбцов" -#: rewrite/rewriteDefine.c:684 +#: rewrite/rewriteDefine.c:695 #, c-format msgid "cannot convert relation containing dropped columns to view" msgstr "" "преобразовать отношение, Ñодержащее удалённые Ñтолбцы, в предÑтавление нельзÑ" -#: rewrite/rewriteDefine.c:690 +#: rewrite/rewriteDefine.c:696 +#, c-format +msgid "" +"cannot create a RETURNING list for a relation containing dropped columns" +msgstr "" +"Ñоздать ÑпиÑок RETURNING Ð´Ð»Ñ Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ, Ñодержащего удалённые Ñтолбцы, нельзÑ" + +#: rewrite/rewriteDefine.c:702 #, c-format msgid "" "SELECT rule's target entry %d has different column name from column \"%s\"" @@ -16596,62 +16579,62 @@ msgstr "" "Ñлементу %d результата правила Ð´Ð»Ñ SELECT приÑвоено имÑ, отличное от имени " "Ñтолбца \"%s\"" -#: rewrite/rewriteDefine.c:692 +#: rewrite/rewriteDefine.c:704 #, c-format msgid "SELECT target entry is named \"%s\"." msgstr "Ð˜Ð¼Ñ Ñлемента результата SELECT: \"%s\"." -#: rewrite/rewriteDefine.c:701 +#: rewrite/rewriteDefine.c:713 #, c-format msgid "SELECT rule's target entry %d has different type from column \"%s\"" msgstr "" "Ñлемент %d результата правила Ð´Ð»Ñ SELECT имеет тип, отличный от типа Ñтолбца " "\"%s\"" -#: rewrite/rewriteDefine.c:703 +#: rewrite/rewriteDefine.c:715 #, c-format msgid "RETURNING list's entry %d has different type from column \"%s\"" msgstr "Ñлемент %d ÑпиÑка RETURNING имеет тип, отличный от типа Ñтолбца \"%s\"" -#: rewrite/rewriteDefine.c:706 rewrite/rewriteDefine.c:730 +#: rewrite/rewriteDefine.c:718 rewrite/rewriteDefine.c:742 #, c-format msgid "SELECT target entry has type %s, but column has type %s." msgstr "Элемент результата SELECT имеет тип %s, тогда как тип Ñтолбца - %s." -#: rewrite/rewriteDefine.c:709 rewrite/rewriteDefine.c:734 +#: rewrite/rewriteDefine.c:721 rewrite/rewriteDefine.c:746 #, c-format msgid "RETURNING list entry has type %s, but column has type %s." msgstr "Элемент ÑпиÑка RETURNING имеет тип %s, тогда как тип Ñтолбца - %s." -#: rewrite/rewriteDefine.c:725 +#: rewrite/rewriteDefine.c:737 #, c-format msgid "SELECT rule's target entry %d has different size from column \"%s\"" msgstr "" "Ñлемент %d результата правила Ð´Ð»Ñ SELECT имеет размер, отличный от Ñтолбца " "\"%s\"" -#: rewrite/rewriteDefine.c:727 +#: rewrite/rewriteDefine.c:739 #, c-format msgid "RETURNING list's entry %d has different size from column \"%s\"" msgstr "Ñлемент %d ÑпиÑка RETURNING имеет размер, отличный от Ñтолбца \"%s\"" -#: rewrite/rewriteDefine.c:744 +#: rewrite/rewriteDefine.c:756 #, c-format msgid "SELECT rule's target list has too few entries" msgstr "ÑпиÑок результата правила Ð´Ð»Ñ SELECT Ñодержит недоÑтаточно Ñлементов" -#: rewrite/rewriteDefine.c:745 +#: rewrite/rewriteDefine.c:757 #, c-format msgid "RETURNING list has too few entries" msgstr "ÑпиÑок RETURNING Ñодержит недоÑтаточно Ñлементов" -#: rewrite/rewriteDefine.c:837 rewrite/rewriteDefine.c:952 +#: rewrite/rewriteDefine.c:849 rewrite/rewriteDefine.c:964 #: rewrite/rewriteSupport.c:112 #, c-format msgid "rule \"%s\" for relation \"%s\" does not exist" msgstr "правило \"%s\" Ð´Ð»Ñ Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ\"%s\" не ÑущеÑтвует" -#: rewrite/rewriteDefine.c:971 +#: rewrite/rewriteDefine.c:983 #, c-format msgid "renaming an ON SELECT rule is not allowed" msgstr "переименовывать правило ON SELECT нельзÑ" @@ -16969,55 +16952,60 @@ msgstr "запиÑÑŒ блока %u Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ %s" msgid "no empty local buffer available" msgstr "нет пуÑтого локального буфера" -#: storage/file/fd.c:528 +#: storage/file/fd.c:541 +#, c-format +msgid "could not link file \"%s\" to \"%s\": %m" +msgstr "Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\" не удалоÑÑŒ Ñоздать ÑÑылку \"%s\": %m" + +#: storage/file/fd.c:635 #, c-format msgid "getrlimit failed: %m" msgstr "ошибка в getrlimit(): %m" -#: storage/file/fd.c:618 +#: storage/file/fd.c:725 #, c-format msgid "insufficient file descriptors available to start server process" msgstr "недоÑтаточно деÑкрипторов файлов Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка Ñерверного процеÑÑа" -#: storage/file/fd.c:619 +#: storage/file/fd.c:726 #, c-format msgid "System allows %d, we need at least %d." msgstr "СиÑтема выделÑет: %d, а требуетÑÑ Ð¼Ð¸Ð½Ð¸Ð¼ÑƒÐ¼: %d." -#: storage/file/fd.c:660 storage/file/fd.c:1694 storage/file/fd.c:1787 -#: storage/file/fd.c:1935 +#: storage/file/fd.c:767 storage/file/fd.c:1801 storage/file/fd.c:1894 +#: storage/file/fd.c:2042 #, c-format msgid "out of file descriptors: %m; release and retry" msgstr "нехватка деÑкрипторов файлов: %m; оÑвободите их и повторите попытку" -#: storage/file/fd.c:1234 +#: storage/file/fd.c:1341 #, c-format msgid "temporary file: path \"%s\", size %lu" msgstr "временный файл: путь \"%s\", размер %lu" -#: storage/file/fd.c:1383 +#: storage/file/fd.c:1490 #, c-format msgid "temporary file size exceeds temp_file_limit (%dkB)" msgstr "размер временного файла превышает предел temp_file_limit (%d КБ)" -#: storage/file/fd.c:1670 storage/file/fd.c:1720 +#: storage/file/fd.c:1777 storage/file/fd.c:1827 #, c-format msgid "exceeded maxAllocatedDescs (%d) while trying to open file \"%s\"" msgstr "превышен предел maxAllocatedDescs (%d) при попытке открыть файл \"%s\"" -#: storage/file/fd.c:1760 +#: storage/file/fd.c:1867 #, c-format msgid "exceeded maxAllocatedDescs (%d) while trying to execute command \"%s\"" msgstr "" "превышен предел maxAllocatedDescs (%d) при попытке выполнить команду \"%s\"" -#: storage/file/fd.c:1911 +#: storage/file/fd.c:2018 #, c-format msgid "exceeded maxAllocatedDescs (%d) while trying to open directory \"%s\"" msgstr "" "превышен предел maxAllocatedDescs (%d) при попытке открыть каталог \"%s\"" -#: storage/file/fd.c:1997 +#: storage/file/fd.c:2104 #, c-format msgid "could not read directory \"%s\": %m" msgstr "не удалоÑÑŒ прочитать каталог \"%s\": %m" @@ -18117,38 +18105,38 @@ msgstr "нераÑпознанный параметр тезауруÑа: \"%s\" msgid "missing Dictionary parameter" msgstr "отÑутÑтвует параметр Dictionary" -#: tsearch/spell.c:276 +#: tsearch/spell.c:289 #, c-format msgid "could not open dictionary file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл ÑÐ»Ð¾Ð²Ð°Ñ€Ñ \"%s\": %m" -#: tsearch/spell.c:439 utils/adt/regexp.c:204 +#: tsearch/spell.c:452 utils/adt/regexp.c:204 #, c-format msgid "invalid regular expression: %s" msgstr "неверное регулÑрное выражение: %s" -#: tsearch/spell.c:518 tsearch/spell.c:535 tsearch/spell.c:552 -#: tsearch/spell.c:569 tsearch/spell.c:591 gram.y:14253 gram.y:14270 +#: tsearch/spell.c:667 tsearch/spell.c:684 tsearch/spell.c:701 +#: tsearch/spell.c:718 tsearch/spell.c:740 gram.y:14253 gram.y:14270 #, c-format msgid "syntax error" msgstr "ошибка ÑинтакÑиÑа" -#: tsearch/spell.c:596 +#: tsearch/spell.c:745 #, c-format msgid "multibyte flag character is not allowed" msgstr "многобайтные Ñимволы флагов не допуÑкаютÑÑ" -#: tsearch/spell.c:632 tsearch/spell.c:690 tsearch/spell.c:787 +#: tsearch/spell.c:779 tsearch/spell.c:835 tsearch/spell.c:937 #, c-format msgid "could not open affix file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл аффикÑов \"%s\": %m" -#: tsearch/spell.c:678 +#: tsearch/spell.c:825 #, c-format msgid "Ispell dictionary supports only default flag value" msgstr "Ñловарь Ispell поддерживает Ð´Ð»Ñ FLAG только значение default" -#: tsearch/spell.c:901 +#: tsearch/spell.c:1050 #, c-format msgid "affix file contains both old-style and new-style commands" msgstr "файл аффикÑов Ñодержит команды и в Ñтаром, и в новом Ñтиле" @@ -18195,27 +18183,27 @@ msgstr "не удалоÑÑŒ открыть файл Ñтоп-Ñлов \"%s\": %m msgid "text search parser does not support headline creation" msgstr "анализатор текÑтового поиÑка не поддерживает Ñоздание выдержек" -#: tsearch/wparser_def.c:2557 +#: tsearch/wparser_def.c:2559 #, c-format msgid "unrecognized headline parameter: \"%s\"" msgstr "нераÑпознанный параметр функции выдержки: \"%s\"" -#: tsearch/wparser_def.c:2566 +#: tsearch/wparser_def.c:2568 #, c-format msgid "MinWords should be less than MaxWords" msgstr "Значение MinWords должно быть меньше MaxWords" -#: tsearch/wparser_def.c:2570 +#: tsearch/wparser_def.c:2572 #, c-format msgid "MinWords should be positive" msgstr "Значение MinWords должно быть положительным" -#: tsearch/wparser_def.c:2574 +#: tsearch/wparser_def.c:2576 #, c-format msgid "ShortWord should be >= 0" msgstr "Значение ShortWord должно быть >= 0" -#: tsearch/wparser_def.c:2578 +#: tsearch/wparser_def.c:2580 #, c-format msgid "MaxFragments should be >= 0" msgstr "Значение MaxFragments должно быть >= 0" @@ -18343,7 +18331,7 @@ msgstr "размер маÑÑива превышает предел (%d)" #: utils/adt/array_userfuncs.c:67 utils/adt/array_userfuncs.c:529 #: utils/adt/array_userfuncs.c:609 utils/adt/json.c:1759 utils/adt/json.c:1854 #: utils/adt/json.c:1892 utils/adt/jsonb.c:1126 utils/adt/jsonb.c:1155 -#: utils/adt/jsonb.c:1590 utils/adt/jsonb.c:1754 utils/adt/jsonb.c:1764 +#: utils/adt/jsonb.c:1591 utils/adt/jsonb.c:1755 utils/adt/jsonb.c:1765 #, c-format msgid "could not determine input data type" msgstr "не удалоÑÑŒ определить тип входных данных" @@ -18362,7 +18350,7 @@ msgstr "тип входных данных не ÑвлÑетÑÑ Ð¼Ð°ÑÑиво #: utils/adt/int.c:1016 utils/adt/int.c:1043 utils/adt/int.c:1076 #: utils/adt/int.c:1159 utils/adt/int8.c:1298 utils/adt/numeric.c:2903 #: utils/adt/numeric.c:2912 utils/adt/varbit.c:1173 utils/adt/varbit.c:1565 -#: utils/adt/varlena.c:1045 utils/adt/varlena.c:2582 +#: utils/adt/varlena.c:1045 utils/adt/varlena.c:2595 #, c-format msgid "integer out of range" msgstr "целое вне диапазона" @@ -18542,8 +18530,7 @@ msgstr "разрезание маÑÑивов поÑтоÑнной длины н #: utils/adt/arrayfuncs.c:2830 utils/adt/arrayfuncs.c:5718 #: utils/adt/arrayfuncs.c:5750 utils/adt/arrayfuncs.c:5767 #: utils/adt/json.c:2290 utils/adt/json.c:2365 utils/adt/jsonb.c:1369 -#: utils/adt/jsonb.c:1455 utils/adt/jsonfuncs.c:3528 -#: utils/adt/jsonfuncs.c:3573 +#: utils/adt/jsonb.c:1455 utils/adt/jsonfuncs.c:3528 utils/adt/jsonfuncs.c:3573 #, c-format msgid "wrong number of array subscripts" msgstr "неверное чиÑло индекÑов маÑÑива" @@ -18719,7 +18706,7 @@ msgstr "TIME(%d)%s: точноÑть уменьшена до дозволенн msgid "date/time value \"current\" is no longer supported" msgstr "значение \"current\" Ð´Ð»Ñ Ð´Ð°Ñ‚Ñ‹/времени больше не поддерживаетÑÑ" -#: utils/adt/date.c:166 utils/adt/formatting.c:3523 +#: utils/adt/date.c:166 utils/adt/formatting.c:3521 #, c-format msgid "date out of range: \"%s\"" msgstr "дата вне диапазона: \"%s\"" @@ -18750,8 +18737,8 @@ msgid "date out of range for timestamp" msgstr "дата вне диапазона Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° timestamp" #: utils/adt/date.c:970 utils/adt/date.c:1016 utils/adt/date.c:1616 -#: utils/adt/date.c:1652 utils/adt/date.c:2524 utils/adt/formatting.c:3399 -#: utils/adt/formatting.c:3431 utils/adt/formatting.c:3499 +#: utils/adt/date.c:1652 utils/adt/date.c:2524 utils/adt/formatting.c:3397 +#: utils/adt/formatting.c:3429 utils/adt/formatting.c:3497 #: utils/adt/json.c:1534 utils/adt/json.c:1556 utils/adt/jsonb.c:823 #: utils/adt/jsonb.c:847 utils/adt/nabstime.c:455 utils/adt/nabstime.c:498 #: utils/adt/nabstime.c:528 utils/adt/nabstime.c:571 utils/adt/timestamp.c:224 @@ -19043,110 +19030,110 @@ msgstr "Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð°Ñ ÑÐ¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð° Ð´Ð»Ñ msgid "Intervals are not tied to specific calendar dates." msgstr "Интервалы не привÑзываютÑÑ Ðº определённым календарным датам." -#: utils/adt/formatting.c:1059 +#: utils/adt/formatting.c:1058 #, c-format msgid "\"EEEE\" must be the last pattern used" msgstr "\"EEEE\" может быть только поÑледним шаблоном" -#: utils/adt/formatting.c:1067 +#: utils/adt/formatting.c:1066 #, c-format msgid "\"9\" must be ahead of \"PR\"" msgstr "\"9\" должна ÑтоÑть до \"PR\"" -#: utils/adt/formatting.c:1083 +#: utils/adt/formatting.c:1082 #, c-format msgid "\"0\" must be ahead of \"PR\"" msgstr "\"0\" должен ÑтоÑть до \"PR\"" -#: utils/adt/formatting.c:1110 +#: utils/adt/formatting.c:1109 #, c-format msgid "multiple decimal points" msgstr "многочиÑленные деÑÑтичные точки" -#: utils/adt/formatting.c:1114 utils/adt/formatting.c:1197 +#: utils/adt/formatting.c:1113 utils/adt/formatting.c:1196 #, c-format msgid "cannot use \"V\" and decimal point together" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"V\" вмеÑте Ñ Ð´ÐµÑÑтичной точкой" -#: utils/adt/formatting.c:1126 +#: utils/adt/formatting.c:1125 #, c-format msgid "cannot use \"S\" twice" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"S\" дважды" -#: utils/adt/formatting.c:1130 +#: utils/adt/formatting.c:1129 #, c-format msgid "cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"S\" вмеÑте Ñ \"PL\"/\"MI\"/\"SG\"/\"PR\"" -#: utils/adt/formatting.c:1150 +#: utils/adt/formatting.c:1149 #, c-format msgid "cannot use \"S\" and \"MI\" together" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"S\" вмеÑте Ñ \"MI\"" -#: utils/adt/formatting.c:1160 +#: utils/adt/formatting.c:1159 #, c-format msgid "cannot use \"S\" and \"PL\" together" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"S\" вмеÑте Ñ \"PL\"" -#: utils/adt/formatting.c:1170 +#: utils/adt/formatting.c:1169 #, c-format msgid "cannot use \"S\" and \"SG\" together" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"S\" вмеÑте Ñ \"SG\"" -#: utils/adt/formatting.c:1179 +#: utils/adt/formatting.c:1178 #, c-format msgid "cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"PR\" вмеÑте Ñ \"S\"/\"PL\"/\"MI\"/\"SG\"" -#: utils/adt/formatting.c:1205 +#: utils/adt/formatting.c:1204 #, c-format msgid "cannot use \"EEEE\" twice" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать \"EEEE\" дважды" -#: utils/adt/formatting.c:1211 +#: utils/adt/formatting.c:1210 #, c-format msgid "\"EEEE\" is incompatible with other formats" msgstr "\"EEEE\" неÑовмеÑтим Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸ форматами" -#: utils/adt/formatting.c:1212 +#: utils/adt/formatting.c:1211 #, c-format msgid "" "\"EEEE\" may only be used together with digit and decimal point patterns." msgstr "" "\"EEEE\" может иÑпользоватьÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð°Ð¼Ð¸ цифр и деÑÑтичной точки." -#: utils/adt/formatting.c:1412 +#: utils/adt/formatting.c:1411 #, c-format msgid "\"%s\" is not a number" msgstr "\"%s\" не ÑвлÑетÑÑ Ñ‡Ð¸Ñлом" -#: utils/adt/formatting.c:1513 utils/adt/formatting.c:1565 +#: utils/adt/formatting.c:1512 utils/adt/formatting.c:1564 #, c-format msgid "could not determine which collation to use for lower() function" msgstr "" "не удалоÑÑŒ определить, какое правило Ñортировки иÑпользовать Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ " "lower()" -#: utils/adt/formatting.c:1633 utils/adt/formatting.c:1685 +#: utils/adt/formatting.c:1632 utils/adt/formatting.c:1684 #, c-format msgid "could not determine which collation to use for upper() function" msgstr "" "не удалоÑÑŒ определить, какое правило Ñортировки иÑпользовать Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ " "upper()" -#: utils/adt/formatting.c:1754 utils/adt/formatting.c:1818 +#: utils/adt/formatting.c:1753 utils/adt/formatting.c:1817 #, c-format msgid "could not determine which collation to use for initcap() function" msgstr "" "не удалоÑÑŒ определить, какое правило Ñортировки иÑпользовать Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ " "initcap()" -#: utils/adt/formatting.c:2122 +#: utils/adt/formatting.c:2114 #, c-format msgid "invalid combination of date conventions" msgstr "неверное Ñочетание Ñтилей дат" -#: utils/adt/formatting.c:2123 +#: utils/adt/formatting.c:2115 #, c-format msgid "" "Do not mix Gregorian and ISO week date conventions in a formatting template." @@ -19154,27 +19141,27 @@ msgstr "" "Ðе Ñмешивайте ГригорианÑкий Ñтиль дат (недель) Ñ ISO в одном шаблоне " "форматированиÑ." -#: utils/adt/formatting.c:2140 +#: utils/adt/formatting.c:2132 #, c-format msgid "conflicting values for \"%s\" field in formatting string" msgstr "конфликтующие Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»Ñ \"%s\" в Ñтроке форматированиÑ" -#: utils/adt/formatting.c:2142 +#: utils/adt/formatting.c:2134 #, c-format msgid "This value contradicts a previous setting for the same field type." msgstr "Это значение противоречит предыдущему значению Ð¿Ð¾Ð»Ñ Ñ‚Ð¾Ð³Ð¾ же типа." -#: utils/adt/formatting.c:2203 +#: utils/adt/formatting.c:2195 #, c-format msgid "source string too short for \"%s\" formatting field" msgstr "Ð²Ñ…Ð¾Ð´Ð½Ð°Ñ Ñтрока короче, чем требует поле Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ \"%s\"" -#: utils/adt/formatting.c:2205 +#: utils/adt/formatting.c:2197 #, c-format msgid "Field requires %d characters, but only %d remain." msgstr "ТребуетÑÑ Ñимволов: %d, а оÑталоÑÑŒ только %d." -#: utils/adt/formatting.c:2208 utils/adt/formatting.c:2222 +#: utils/adt/formatting.c:2200 utils/adt/formatting.c:2214 #, c-format msgid "" "If your source string is not fixed-width, try using the \"FM\" modifier." @@ -19182,80 +19169,80 @@ msgstr "" "ЕÑли Ð²Ñ…Ð¾Ð´Ð½Ð°Ñ Ñтрока имеет переменную длину, попробуйте иÑпользовать " "модификатор \"FM\"." -#: utils/adt/formatting.c:2218 utils/adt/formatting.c:2231 -#: utils/adt/formatting.c:2361 +#: utils/adt/formatting.c:2210 utils/adt/formatting.c:2223 +#: utils/adt/formatting.c:2353 #, c-format msgid "invalid value \"%s\" for \"%s\"" msgstr "неверное значение \"%s\" Ð´Ð»Ñ \"%s\"" -#: utils/adt/formatting.c:2220 +#: utils/adt/formatting.c:2212 #, c-format msgid "Field requires %d characters, but only %d could be parsed." msgstr "Поле должно поглотить Ñимволов: %d, но удалоÑÑŒ разобрать только %d." -#: utils/adt/formatting.c:2233 +#: utils/adt/formatting.c:2225 #, c-format msgid "Value must be an integer." msgstr "Значение должно быть целым чиÑлом." -#: utils/adt/formatting.c:2238 +#: utils/adt/formatting.c:2230 #, c-format msgid "value for \"%s\" in source string is out of range" msgstr "значение \"%s\" во входной Ñтроке вне диапазона" -#: utils/adt/formatting.c:2240 +#: utils/adt/formatting.c:2232 #, c-format msgid "Value must be in the range %d to %d." msgstr "Значение должно быть в интервале %d..%d." -#: utils/adt/formatting.c:2363 +#: utils/adt/formatting.c:2355 #, c-format msgid "The given value did not match any of the allowed values for this field." msgstr "" "Данное значение не ÑоответÑтвует ни одному из допуÑтимых значений Ð´Ð»Ñ Ñтого " "полÑ." -#: utils/adt/formatting.c:2551 utils/adt/formatting.c:2571 -#: utils/adt/formatting.c:2591 utils/adt/formatting.c:2611 -#: utils/adt/formatting.c:2630 utils/adt/formatting.c:2649 -#: utils/adt/formatting.c:2672 utils/adt/formatting.c:2690 -#: utils/adt/formatting.c:2708 utils/adt/formatting.c:2726 -#: utils/adt/formatting.c:2743 utils/adt/formatting.c:2760 +#: utils/adt/formatting.c:2547 utils/adt/formatting.c:2567 +#: utils/adt/formatting.c:2587 utils/adt/formatting.c:2607 +#: utils/adt/formatting.c:2626 utils/adt/formatting.c:2645 +#: utils/adt/formatting.c:2668 utils/adt/formatting.c:2686 +#: utils/adt/formatting.c:2704 utils/adt/formatting.c:2722 +#: utils/adt/formatting.c:2739 utils/adt/formatting.c:2756 #, c-format msgid "localized string format value too long" msgstr "Ñлишком длинное значение формата локализованной Ñтроки" -#: utils/adt/formatting.c:3044 +#: utils/adt/formatting.c:3040 #, c-format msgid "\"TZ\"/\"tz\"/\"OF\" format patterns are not supported in to_date" msgstr "шаблоны формата \"TZ\"/\"tz\"/\"OF\" не поддерживаютÑÑ Ð² to_date" -#: utils/adt/formatting.c:3152 +#: utils/adt/formatting.c:3149 #, c-format msgid "invalid input string for \"Y,YYY\"" msgstr "ошибка ÑинтакÑиÑа в значении Ð´Ð»Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð° \"Y,YYY\"" -#: utils/adt/formatting.c:3655 +#: utils/adt/formatting.c:3653 #, c-format msgid "hour \"%d\" is invalid for the 12-hour clock" msgstr "Ñ‡Ð°Ñ \"%d\" не ÑоответÑтвует 12-чаÑовому формату времени" -#: utils/adt/formatting.c:3657 +#: utils/adt/formatting.c:3655 #, c-format msgid "Use the 24-hour clock, or give an hour between 1 and 12." msgstr "ИÑпользуйте 24-чаÑовой формат или передавайте чаÑÑ‹ от 1 до 12." -#: utils/adt/formatting.c:3752 +#: utils/adt/formatting.c:3750 #, c-format msgid "cannot calculate day of year without year information" msgstr "Ð½ÐµÐ»ÑŒÐ·Ñ Ñ€Ð°ÑÑчитать день года без информации о годе" -#: utils/adt/formatting.c:4601 +#: utils/adt/formatting.c:4599 #, c-format msgid "\"EEEE\" not supported for input" msgstr "\"EEEE\" не поддерживаетÑÑ Ð¿Ñ€Ð¸ вводе" -#: utils/adt/formatting.c:4613 +#: utils/adt/formatting.c:4611 #, c-format msgid "\"RN\" not supported for input" msgstr "\"RN\" не поддерживаетÑÑ Ð¿Ñ€Ð¸ вводе" @@ -19608,7 +19595,7 @@ msgstr "не удалоÑÑŒ определить тип данных аргум msgid "could not determine data type for argument 2" msgstr "не удалоÑÑŒ определить тип данных аргумента 2" -#: utils/adt/json.c:2040 utils/adt/jsonb.c:1780 +#: utils/adt/json.c:2040 utils/adt/jsonb.c:1781 #, c-format msgid "field name must not be null" msgstr "Ð¸Ð¼Ñ Ð¿Ð¾Ð»Ñ Ð½Ðµ может быть NULL" @@ -19685,7 +19672,7 @@ msgstr "аргумент %d: ключ не может быть NULL" msgid "argument %d: could not determine data type" msgstr "аргумент %d: не удалоÑÑŒ определить тип данных" -#: utils/adt/jsonb.c:1833 +#: utils/adt/jsonb.c:1834 #, c-format msgid "object keys must be strings" msgstr "ключи объектов должны быть Ñтроковыми" @@ -19820,6 +19807,16 @@ msgstr "удалить путь в ÑкалÑре нельзÑ" msgid "invalid concatenation of jsonb objects" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð½ÐºÐ°Ñ‚ÐµÐ½Ð°Ñ†Ð¸Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð² jsonb" +#: utils/adt/jsonfuncs.c:3732 +#, c-format +msgid "path element at position %d is null" +msgstr "Ñлемент пути в позиции %d равен NULL" + +#: utils/adt/jsonfuncs.c:3888 +#, c-format +msgid "path element at position %d is not an integer: \"%s\"" +msgstr "Ñлемент пути в позиции %d - не целочиÑленный: \"%s\"" + #: utils/adt/levenshtein.c:133 #, c-format msgid "levenshtein argument exceeds maximum length of %d characters" @@ -20183,24 +20180,24 @@ msgstr "Ñимвол не может быть null" msgid "percentile value %g is not between 0 and 1" msgstr "значение Ð¿ÐµÑ€Ñ†ÐµÐ½Ñ‚Ð¸Ð»Ñ %g лежит не в диапазоне 0..1" -#: utils/adt/pg_locale.c:911 +#: utils/adt/pg_locale.c:917 #, c-format msgid "Apply system library package updates." msgstr "Обновите пакет Ñ ÑиÑтемной библиотекой." -#: utils/adt/pg_locale.c:1116 +#: utils/adt/pg_locale.c:1122 #, c-format msgid "could not create locale \"%s\": %m" msgstr "не удалоÑÑŒ Ñоздать локаль \"%s\": %m" -#: utils/adt/pg_locale.c:1119 +#: utils/adt/pg_locale.c:1125 #, c-format msgid "" "The operating system could not find any locale data for the locale name \"%s" "\"." msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема не может найти данные локали Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ \"%s\"." -#: utils/adt/pg_locale.c:1206 +#: utils/adt/pg_locale.c:1212 #, c-format msgid "" "collations with different collate and ctype values are not supported on this " @@ -20209,17 +20206,17 @@ msgstr "" "правила Ñортировки Ñ Ñ€Ð°Ð·Ð½Ñ‹Ð¼Ð¸ значениÑми collate и ctype не поддерживаютÑÑ Ð½Ð° " "Ñтой платформе" -#: utils/adt/pg_locale.c:1221 +#: utils/adt/pg_locale.c:1227 #, c-format msgid "nondefault collations are not supported on this platform" msgstr "на Ñтой платформе поддерживаютÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ñтандартные правила Ñортировки" -#: utils/adt/pg_locale.c:1392 +#: utils/adt/pg_locale.c:1398 #, c-format msgid "invalid multibyte character for locale" msgstr "неверный многобайтный Ñимвол Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»Ð¸" -#: utils/adt/pg_locale.c:1393 +#: utils/adt/pg_locale.c:1399 #, c-format msgid "" "The server's LC_CTYPE locale is probably incompatible with the database " @@ -20439,7 +20436,7 @@ msgstr "Слишком много запÑтых." msgid "Junk after right parenthesis or bracket." msgstr "МуÑор поÑле правой Ñкобки." -#: utils/adt/regexp.c:285 utils/adt/regexp.c:1288 utils/adt/varlena.c:3588 +#: utils/adt/regexp.c:285 utils/adt/regexp.c:1288 utils/adt/varlena.c:3601 #, c-format msgid "regular expression failed: %s" msgstr "ошибка в регулÑрном выражении: %s" @@ -20476,7 +20473,7 @@ msgstr "" "Чтобы обозначить отÑутÑтвующий аргумент унарного оператора, укажите NONE." #: utils/adt/regproc.c:779 utils/adt/regproc.c:820 utils/adt/regproc.c:2006 -#: utils/adt/ruleutils.c:8167 utils/adt/ruleutils.c:8292 +#: utils/adt/ruleutils.c:8188 utils/adt/ruleutils.c:8313 #, c-format msgid "too many arguments" msgstr "Ñлишком много аргументов" @@ -20488,7 +20485,7 @@ msgstr "ПредоÑтавьте Ð´Ð»Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ‚Ð¾Ñ€Ð° два типа ар #: utils/adt/regproc.c:1594 utils/adt/regproc.c:1618 utils/adt/regproc.c:1715 #: utils/adt/regproc.c:1739 utils/adt/regproc.c:1841 utils/adt/regproc.c:1846 -#: utils/adt/varlena.c:2859 utils/adt/varlena.c:2864 +#: utils/adt/varlena.c:2872 utils/adt/varlena.c:2877 #, c-format msgid "invalid name syntax" msgstr "ошибка ÑинтакÑиÑа в имени" @@ -20655,14 +20652,14 @@ msgstr "неверный тип данных: %u, ожидалÑÑ %u" msgid "improper binary format in record column %d" msgstr "неподходÑщий двоичный формат в Ñтолбце запиÑи %d" -#: utils/adt/rowtypes.c:902 utils/adt/rowtypes.c:1142 -#: utils/adt/rowtypes.c:1396 utils/adt/rowtypes.c:1673 +#: utils/adt/rowtypes.c:902 utils/adt/rowtypes.c:1142 utils/adt/rowtypes.c:1396 +#: utils/adt/rowtypes.c:1673 #, c-format msgid "cannot compare dissimilar column types %s and %s at record column %d" msgstr "не удалоÑÑŒ Ñравнить различные типы Ñтолбцов %s и %s, Ñтолбец запиÑи %d" -#: utils/adt/rowtypes.c:991 utils/adt/rowtypes.c:1213 -#: utils/adt/rowtypes.c:1529 utils/adt/rowtypes.c:1769 +#: utils/adt/rowtypes.c:991 utils/adt/rowtypes.c:1213 utils/adt/rowtypes.c:1529 +#: utils/adt/rowtypes.c:1769 #, c-format msgid "cannot compare record types with different numbers of columns" msgstr "Ñравнивать типы запиÑей Ñ Ñ€Ð°Ð·Ð½Ñ‹Ð¼ чиÑлом Ñтолбцов нельзÑ" @@ -21045,8 +21042,8 @@ msgid "bit string too long for type bit varying(%d)" msgstr "Ñтрока битов не умещаетÑÑ Ð² тип bit varying(%d)" #: utils/adt/varbit.c:1066 utils/adt/varbit.c:1168 utils/adt/varlena.c:832 -#: utils/adt/varlena.c:896 utils/adt/varlena.c:1040 utils/adt/varlena.c:2510 -#: utils/adt/varlena.c:2577 +#: utils/adt/varlena.c:896 utils/adt/varlena.c:1040 utils/adt/varlena.c:2523 +#: utils/adt/varlena.c:2590 #, c-format msgid "negative substring length not allowed" msgstr "подÑтрока должна иметь неотрицательную длину" @@ -21072,7 +21069,7 @@ msgstr "" msgid "bit index %d out of valid range (0..%d)" msgstr "Ð¸Ð½Ð´ÐµÐºÑ Ð±Ð¸Ñ‚Ð° %d вне диапазона 0..%d" -#: utils/adt/varbit.c:1802 utils/adt/varlena.c:2777 +#: utils/adt/varbit.c:1802 utils/adt/varlena.c:2790 #, c-format msgid "new bit must be 0 or 1" msgstr "значением бита должен быть 0 или 1" @@ -21104,48 +21101,48 @@ msgstr "не удалоÑÑŒ преобразовать Ñтроку в UTF-16 ( msgid "could not compare Unicode strings: %m" msgstr "не удалоÑÑŒ Ñравнить Ñтроки в Unicode: %m" -#: utils/adt/varlena.c:2655 utils/adt/varlena.c:2686 utils/adt/varlena.c:2722 -#: utils/adt/varlena.c:2765 +#: utils/adt/varlena.c:2668 utils/adt/varlena.c:2699 utils/adt/varlena.c:2735 +#: utils/adt/varlena.c:2778 #, c-format msgid "index %d out of valid range, 0..%d" msgstr "Ð¸Ð½Ð´ÐµÐºÑ %d вне диапазона 0..%d" -#: utils/adt/varlena.c:3684 +#: utils/adt/varlena.c:3697 #, c-format msgid "field position must be greater than zero" msgstr "Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿Ð¾Ð»Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° быть больше нулÑ" -#: utils/adt/varlena.c:4563 +#: utils/adt/varlena.c:4576 #, c-format msgid "unterminated format specifier" msgstr "незавершённый Ñпецификатор формата" -#: utils/adt/varlena.c:4695 utils/adt/varlena.c:4815 +#: utils/adt/varlena.c:4708 utils/adt/varlena.c:4828 #, c-format msgid "unrecognized conversion type specifier \"%c\"" msgstr "нераÑпознанный Ñпецификатор Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ \"%c\"" -#: utils/adt/varlena.c:4707 utils/adt/varlena.c:4764 +#: utils/adt/varlena.c:4720 utils/adt/varlena.c:4777 #, c-format msgid "too few arguments for format" msgstr "мало аргументов Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð°" -#: utils/adt/varlena.c:4858 utils/adt/varlena.c:5041 +#: utils/adt/varlena.c:4871 utils/adt/varlena.c:5054 #, c-format msgid "number is out of range" msgstr "чиÑло вне диапазона" -#: utils/adt/varlena.c:4922 utils/adt/varlena.c:4950 +#: utils/adt/varlena.c:4935 utils/adt/varlena.c:4963 #, c-format msgid "format specifies argument 0, but arguments are numbered from 1" msgstr "формат ÑÑылаетÑÑ Ð½Ð° аргумент 0, но аргументы нумеруютÑÑ Ñ 1" -#: utils/adt/varlena.c:4943 +#: utils/adt/varlena.c:4956 #, c-format msgid "width argument position must be ended by \"$\"" msgstr "указание аргумента ширины должно оканчиватьÑÑ \"$\"" -#: utils/adt/varlena.c:4988 +#: utils/adt/varlena.c:5001 #, c-format msgid "null values cannot be formatted as an SQL identifier" msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ null Ð½ÐµÐ»ÑŒÐ·Ñ Ð¿Ñ€ÐµÐ´Ñтавить в виде SQL-идентификатора" @@ -21323,7 +21320,7 @@ msgstr "Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° %s нет функции ввода" msgid "no output function available for type %s" msgstr "Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ð° %s нет функции вывода" -#: utils/cache/plancache.c:725 +#: utils/cache/plancache.c:729 #, c-format msgid "cached plan must not change result type" msgstr "в кешированном плане не должен изменÑтьÑÑ Ñ‚Ð¸Ð¿ результата" @@ -21652,47 +21649,52 @@ msgstr "" "параметр \"%s\" Ð½ÐµÐ»ÑŒÐ·Ñ Ð·Ð°Ð´Ð°Ñ‚ÑŒ в рамках операции Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñми по " "безопаÑноÑти" -#: utils/init/miscinit.c:522 +#: utils/init/miscinit.c:502 +#, c-format +msgid "role with OID %u does not exist" +msgstr "роль Ñ OID %u не ÑущеÑтвует" + +#: utils/init/miscinit.c:532 #, c-format msgid "role \"%s\" is not permitted to log in" msgstr "Ð´Ð»Ñ Ñ€Ð¾Ð»Ð¸ \"%s\" вход запрещён" -#: utils/init/miscinit.c:540 +#: utils/init/miscinit.c:550 #, c-format msgid "too many connections for role \"%s\"" msgstr "Ñлишком много подключений Ð´Ð»Ñ Ñ€Ð¾Ð»Ð¸ \"%s\"" -#: utils/init/miscinit.c:600 +#: utils/init/miscinit.c:610 #, c-format msgid "permission denied to set session authorization" msgstr "нет прав Ð´Ð»Ñ Ñмены объекта авторизации в ÑеанÑе" -#: utils/init/miscinit.c:683 +#: utils/init/miscinit.c:693 #, c-format msgid "invalid role OID: %u" msgstr "неверный OID роли: %u" -#: utils/init/miscinit.c:813 +#: utils/init/miscinit.c:823 #, c-format msgid "could not create lock file \"%s\": %m" msgstr "не удалоÑÑŒ Ñоздать файл блокировки \"%s\": %m" -#: utils/init/miscinit.c:827 +#: utils/init/miscinit.c:837 #, c-format msgid "could not open lock file \"%s\": %m" msgstr "не удалоÑÑŒ открыть файл блокировки \"%s\": %m" -#: utils/init/miscinit.c:833 +#: utils/init/miscinit.c:843 #, c-format msgid "could not read lock file \"%s\": %m" msgstr "не удалоÑÑŒ прочитать файл блокировки \"%s\": %m" -#: utils/init/miscinit.c:841 +#: utils/init/miscinit.c:851 #, c-format msgid "lock file \"%s\" is empty" msgstr "файл блокировки \"%s\" пуÑÑ‚" -#: utils/init/miscinit.c:842 +#: utils/init/miscinit.c:852 #, c-format msgid "" "Either another server is starting, or the lock file is the remnant of a " @@ -21701,40 +21703,40 @@ msgstr "" "Либо ÑÐµÐ¹Ñ‡Ð°Ñ Ð·Ð°Ð¿ÑƒÑкаетÑÑ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ Ñервер, либо Ñтот файл оÑталÑÑ Ð² результате " "ÑÐ±Ð¾Ñ Ð¿Ñ€Ð¸ предыдущем запуÑке." -#: utils/init/miscinit.c:889 +#: utils/init/miscinit.c:899 #, c-format msgid "lock file \"%s\" already exists" msgstr "файл блокировки \"%s\" уже ÑущеÑтвует" -#: utils/init/miscinit.c:893 +#: utils/init/miscinit.c:903 #, c-format msgid "Is another postgres (PID %d) running in data directory \"%s\"?" msgstr "Другой ÑкземплÑÑ€ postgres (PID %d) работает Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼ данных \"%s\"?" -#: utils/init/miscinit.c:895 +#: utils/init/miscinit.c:905 #, c-format msgid "Is another postmaster (PID %d) running in data directory \"%s\"?" msgstr "" "Другой ÑкземплÑÑ€ postmaster (PID %d) работает Ñ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼ данных \"%s\"?" -#: utils/init/miscinit.c:898 +#: utils/init/miscinit.c:908 #, c-format msgid "Is another postgres (PID %d) using socket file \"%s\"?" msgstr "Другой ÑкземплÑÑ€ postgres (PID %d) иÑпользует файл Ñокета \"%s\"?" -#: utils/init/miscinit.c:900 +#: utils/init/miscinit.c:910 #, c-format msgid "Is another postmaster (PID %d) using socket file \"%s\"?" msgstr "Другой ÑкземплÑÑ€ postmaster (PID %d) иÑпользует файл Ñокета \"%s\"?" -#: utils/init/miscinit.c:936 +#: utils/init/miscinit.c:946 #, c-format msgid "pre-existing shared memory block (key %lu, ID %lu) is still in use" msgstr "" "ранее выделенный блок разделÑемой памÑти (ключ %lu, ID %lu) по-прежнему " "иÑпользуетÑÑ" -#: utils/init/miscinit.c:939 +#: utils/init/miscinit.c:949 #, c-format msgid "" "If you're sure there are no old server processes still running, remove the " @@ -21743,12 +21745,12 @@ msgstr "" "ЕÑли вы уверены, что процеÑÑов Ñтарого Ñервера уже не оÑталоÑÑŒ, оÑвободите " "Ñтот блок разделÑемой памÑти или проÑто удалите файл \"%s\"." -#: utils/init/miscinit.c:955 +#: utils/init/miscinit.c:965 #, c-format msgid "could not remove old lock file \"%s\": %m" msgstr "не удалоÑÑŒ Ñтереть Ñтарый файл блокировки \"%s\": %m" -#: utils/init/miscinit.c:957 +#: utils/init/miscinit.c:967 #, c-format msgid "" "The file seems accidentally left over, but it could not be removed. Please " @@ -21757,48 +21759,48 @@ msgstr "" "КажетÑÑ, файл ÑохранилÑÑ Ð¿Ð¾ ошибке, но удалить его не получилоÑÑŒ. " "ПожалуйÑта, удалите файл вручную и повторите попытку." -#: utils/init/miscinit.c:993 utils/init/miscinit.c:1004 -#: utils/init/miscinit.c:1014 +#: utils/init/miscinit.c:1003 utils/init/miscinit.c:1014 +#: utils/init/miscinit.c:1024 #, c-format msgid "could not write lock file \"%s\": %m" msgstr "не удалоÑÑŒ запиÑать файл блокировки \"%s\": %m" -#: utils/init/miscinit.c:1143 utils/init/miscinit.c:1272 utils/misc/guc.c:8589 +#: utils/init/miscinit.c:1153 utils/init/miscinit.c:1282 utils/misc/guc.c:8602 #, c-format msgid "could not read from file \"%s\": %m" msgstr "не удалоÑÑŒ прочитать файл \"%s\": %m" -#: utils/init/miscinit.c:1262 +#: utils/init/miscinit.c:1272 #, c-format msgid "could not open file \"%s\": %m; continuing anyway" msgstr "не удалоÑÑŒ открыть файл \"%s\": %m; ошибка игнорируетÑÑ" -#: utils/init/miscinit.c:1285 +#: utils/init/miscinit.c:1295 #, c-format msgid "lock file \"%s\" contains wrong PID: %ld instead of %ld" msgstr "файл блокировки \"%s\" Ñодержит неверный PID: %ld вмеÑто %ld" -#: utils/init/miscinit.c:1327 utils/init/miscinit.c:1340 +#: utils/init/miscinit.c:1337 utils/init/miscinit.c:1350 #, c-format msgid "\"%s\" is not a valid data directory" msgstr "\"%s\" не ÑвлÑетÑÑ ÐºÐ°Ñ‚Ð°Ð»Ð¾Ð³Ð¾Ð¼ данных" -#: utils/init/miscinit.c:1329 +#: utils/init/miscinit.c:1339 #, c-format msgid "File \"%s\" is missing." msgstr "Файл \"%s\" отÑутÑтвует." -#: utils/init/miscinit.c:1342 +#: utils/init/miscinit.c:1352 #, c-format msgid "File \"%s\" does not contain valid data." msgstr "Файл \"%s\" Ñодержит неприемлемые данные." -#: utils/init/miscinit.c:1344 +#: utils/init/miscinit.c:1354 #, c-format msgid "You might need to initdb." msgstr "Возможно, вам нужно выполнить initdb." -#: utils/init/miscinit.c:1352 +#: utils/init/miscinit.c:1362 #, c-format msgid "" "The data directory was initialized by PostgreSQL version %ld.%ld, which is " @@ -21807,7 +21809,7 @@ msgstr "" "Каталог данных инициализирован Ñервером PostgreSQL верÑии %ld.%ld, не " "ÑовмеÑтимой Ñ Ð´Ð°Ð½Ð½Ð¾Ð¹ верÑией (%s)." -#: utils/init/miscinit.c:1423 +#: utils/init/miscinit.c:1433 #, c-format msgid "loaded library \"%s\"" msgstr "загружена библиотека \"%s\"" @@ -23892,14 +23894,14 @@ msgstr "параметр \"%s\" требует чиÑловое значение msgid "%g is outside the valid range for parameter \"%s\" (%g .. %g)" msgstr "%g вне диапазона, допуÑтимого Ð´Ð»Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° \"%s\" (%g .. %g)" -#: utils/misc/guc.c:5675 utils/misc/guc.c:7004 +#: utils/misc/guc.c:5675 utils/misc/guc.c:7017 #, c-format msgid "cannot set parameters during a parallel operation" msgstr "уÑтанавливать параметры во Ð²Ñ€ÐµÐ¼Ñ Ð¿Ð°Ñ€Ð°Ð»Ð»ÐµÐ»ÑŒÐ½Ñ‹Ñ… операций нельзÑ" #: utils/misc/guc.c:5682 utils/misc/guc.c:6432 utils/misc/guc.c:6484 -#: utils/misc/guc.c:6845 utils/misc/guc.c:7592 utils/misc/guc.c:7751 -#: utils/misc/guc.c:9386 +#: utils/misc/guc.c:6845 utils/misc/guc.c:7605 utils/misc/guc.c:7764 +#: utils/misc/guc.c:9399 #, c-format msgid "unrecognized configuration parameter \"%s\"" msgstr "нераÑпознанный параметр конфигурации: \"%s\"" @@ -23921,7 +23923,7 @@ msgstr "параметр \"%s\" изменÑетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ при пер msgid "parameter \"%s\" cannot be changed now" msgstr "параметр \"%s\" Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ ÑейчаÑ" -#: utils/misc/guc.c:5748 utils/misc/guc.c:5793 utils/misc/guc.c:9402 +#: utils/misc/guc.c:5748 utils/misc/guc.c:5793 utils/misc/guc.c:9415 #, c-format msgid "permission denied to set parameter \"%s\"" msgstr "нет прав Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° \"%s\"" @@ -23938,7 +23940,7 @@ msgstr "" "параметр \"%s\" Ð½ÐµÐ»ÑŒÐ·Ñ Ð·Ð°Ð´Ð°Ñ‚ÑŒ в функции Ñ ÐºÐ¾Ð½Ñ‚ÐµÐºÑтом безопаÑноÑти " "определившего" -#: utils/misc/guc.c:6440 utils/misc/guc.c:6488 utils/misc/guc.c:7755 +#: utils/misc/guc.c:6440 utils/misc/guc.c:6488 utils/misc/guc.c:7768 #, c-format msgid "must be superuser to examine \"%s\"" msgstr "прочитать \"%s\" может только Ñуперпользователь" @@ -23953,47 +23955,52 @@ msgstr "SET %s принимает только один аргумент" msgid "must be superuser to execute ALTER SYSTEM command" msgstr "выполнить команду ALTER SYSTEM может только Ñуперпользователь" -#: utils/misc/guc.c:6918 +#: utils/misc/guc.c:6890 +#, c-format +msgid "parameter value for ALTER SYSTEM must not contain a newline" +msgstr "значение параметра Ð´Ð»Ñ ALTER SYSTEM не должно быть многоÑтрочным" + +#: utils/misc/guc.c:6935 #, c-format msgid "could not parse contents of file \"%s\"" msgstr "не удалоÑÑŒ разобрать Ñодержимое файла \"%s\"" -#: utils/misc/guc.c:7080 +#: utils/misc/guc.c:7093 #, c-format msgid "SET LOCAL TRANSACTION SNAPSHOT is not implemented" msgstr "SET LOCAL TRANSACTION SNAPSHOT не реализовано" -#: utils/misc/guc.c:7165 +#: utils/misc/guc.c:7178 #, c-format msgid "SET requires parameter name" msgstr "SET требует Ð¸Ð¼Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°" -#: utils/misc/guc.c:7289 +#: utils/misc/guc.c:7302 #, c-format msgid "attempt to redefine parameter \"%s\"" msgstr "попытка переопределить параметр \"%s\"" -#: utils/misc/guc.c:9019 +#: utils/misc/guc.c:9032 #, c-format msgid "parameter \"%s\" could not be set" msgstr "параметр \"%s\" Ð½ÐµÐ»ÑŒÐ·Ñ ÑƒÑтановить" -#: utils/misc/guc.c:9106 +#: utils/misc/guc.c:9119 #, c-format msgid "could not parse setting for parameter \"%s\"" msgstr "не удалоÑÑŒ разобрать значение параметра \"%s\"" -#: utils/misc/guc.c:9464 utils/misc/guc.c:9498 +#: utils/misc/guc.c:9477 utils/misc/guc.c:9511 #, c-format msgid "invalid value for parameter \"%s\": %d" msgstr "неверное значение параметра \"%s\": %d" -#: utils/misc/guc.c:9532 +#: utils/misc/guc.c:9545 #, c-format msgid "invalid value for parameter \"%s\": %g" msgstr "неверное значение параметра \"%s\": %g" -#: utils/misc/guc.c:9722 +#: utils/misc/guc.c:9735 #, c-format msgid "" "\"temp_buffers\" cannot be changed after any temporary tables have been " @@ -24002,23 +24009,23 @@ msgstr "" "параметр \"temp_buffers\" Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ð·Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ поÑле Ð¾Ð±Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ Ðº временным " "таблицам в текущем ÑеанÑе." -#: utils/misc/guc.c:9734 +#: utils/misc/guc.c:9747 #, c-format msgid "Bonjour is not supported by this build" msgstr "Bonjour не поддерживаетÑÑ Ð² данной Ñборке" -#: utils/misc/guc.c:9747 +#: utils/misc/guc.c:9760 #, c-format msgid "SSL is not supported by this build" msgstr "SSL не поддерживаетÑÑ Ð² данной Ñборке" -#: utils/misc/guc.c:9759 +#: utils/misc/guc.c:9772 #, c-format msgid "Cannot enable parameter when \"log_statement_stats\" is true." msgstr "" "Этот параметр Ð½ÐµÐ»ÑŒÐ·Ñ Ð²ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒ, когда \"log_statement_stats\" равен true." -#: utils/misc/guc.c:9771 +#: utils/misc/guc.c:9784 #, c-format msgid "" "Cannot enable \"log_statement_stats\" when \"log_parser_stats\", " @@ -24141,8 +24148,8 @@ msgstr "Ошибка при Ñоздании контекÑта памÑти \"% #: utils/mmgr/mcxt.c:689 utils/mmgr/mcxt.c:724 utils/mmgr/mcxt.c:761 #: utils/mmgr/mcxt.c:798 utils/mmgr/mcxt.c:832 utils/mmgr/mcxt.c:861 -#: utils/mmgr/mcxt.c:895 utils/mmgr/mcxt.c:975 utils/mmgr/mcxt.c:1008 -#: utils/mmgr/mcxt.c:1055 +#: utils/mmgr/mcxt.c:895 utils/mmgr/mcxt.c:977 utils/mmgr/mcxt.c:1011 +#: utils/mmgr/mcxt.c:1060 #, c-format msgid "Failed on request of size %zu." msgstr "Ошибка при запроÑе памÑти (%zu Б)." @@ -24753,6 +24760,21 @@ msgstr "неÑтандартное иÑпользование ÑпецÑимво msgid "Use the escape string syntax for escapes, e.g., E'\\r\\n'." msgstr "ИÑпользуйте Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи ÑпецÑимволов ÑинтакÑÐ¸Ñ ÑпецÑтрок E'\\r\\n'." +#~ msgid "" +#~ "could not link file \"%s\" to \"%s\" (initialization of log file): %m" +#~ msgstr "" +#~ "Ð´Ð»Ñ Ñ„Ð°Ð¹Ð»Ð° \"%s\" не удалоÑÑŒ Ñоздать ÑÑылку \"%s\" (при инициализации " +#~ "файла журнала): %m" + +#~ msgid "" +#~ "could not rename file \"%s\" to \"%s\" (initialization of log file): %m" +#~ msgstr "" +#~ "не удалоÑÑŒ переименовать файл \"%s\" в \"%s\" (при инициализации файла " +#~ "журнала): %m" + +#~ msgid "system columns cannot be used in an ON CONFLICT clause" +#~ msgstr "ÑиÑтемные Ñтолбцы Ð½ÐµÐ»ÑŒÐ·Ñ Ð¸Ñпользовать в предложении ON CONFLICT" + #~ msgid "insufficient privilege to bypass row-level security" #~ msgstr "недоÑтаточно прав Ð´Ð»Ñ Ð¾Ð±Ñ…Ð¾Ð´Ð° защиты на уровне Ñтрок" @@ -24932,9 +24954,6 @@ msgstr "ИÑпользуйте Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи ÑпецÑимволов Ñи #~ msgid "incorrect total length in record at %X/%X" #~ msgstr "Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð°Ñ Ð¾Ð±Ñ‰Ð°Ñ Ð´Ð»Ð¸Ð½Ð° в запиÑи по Ñмещению %X/%X" -#~ msgid "role with OID %u does not exist" -#~ msgstr "роль Ñ OID %u не ÑущеÑтвует" - #~ msgid "=> is deprecated as an operator name" #~ msgstr "=> как Ð¸Ð¼Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ‚Ð¾Ñ€Ð° ÑчитаетÑÑ ÑƒÑтаревшим" diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 76619e9517..fd55262668 100644 --- a/src/backend/postmaster/bgworker.c +++ b/src/backend/postmaster/bgworker.c @@ -1025,13 +1025,16 @@ WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle) status = GetBackgroundWorkerPid(handle, &pid); if (status == BGWH_STOPPED) - return status; + break; rc = WaitLatch(&MyProc->procLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); if (rc & WL_POSTMASTER_DEATH) - return BGWH_POSTMASTER_DIED; + { + status = BGWH_POSTMASTER_DIED; + break; + } ResetLatch(&MyProc->procLatch); } diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 3c862feb92..0440f4a1d4 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -28,6 +28,9 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif #include "pgstat.h" diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index c576986c6b..5db878f9b4 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -569,6 +569,16 @@ PostmasterMain(int argc, char *argv[]) */ umask(S_IRWXG | S_IRWXO); + /* + * Initialize random(3) so we don't get the same values in every run. + * + * Note: the seed is pretty predictable from externally-visible facts such + * as postmaster start time, so avoid using random() for security-critical + * random values during postmaster startup. At the time of first + * connection, PostmasterRandom will select a hopefully-more-random seed. + */ + srandom((unsigned int) (MyProcPid ^ MyStartTime)); + /* * By default, palloc() requests in the postmaster will be allocated in * the PostmasterContext, which is space that can be recycled by backends. @@ -4608,10 +4618,17 @@ SubPostmasterMain(int argc, char *argv[]) /* Setup essential subsystems (to ensure elog() behaves sanely) */ InitializeGUCOptions(); + /* Check we got appropriate args */ + if (argc < 3) + elog(FATAL, "invalid subpostmaster invocation"); + /* Read in the variables file */ memset(&port, 0, sizeof(Port)); read_backend_variables(argv[2], &port); + /* Close the postmaster's sockets (as soon as we know them) */ + ClosePostmasterPorts(strcmp(argv[1], "--forklog") == 0); + /* * Set reference point for stack-depth checking */ @@ -4629,15 +4646,21 @@ SubPostmasterMain(int argc, char *argv[]) errmsg("out of memory"))); #endif - /* Check we got appropriate args */ - if (argc < 3) - elog(FATAL, "invalid subpostmaster invocation"); - /* * If appropriate, physically re-attach to shared memory segment. We want * to do this before going any further to ensure that we can attach at the * same address the postmaster used. On the other hand, if we choose not * to re-attach, we may have other cleanup to do. + * + * If testing EXEC_BACKEND on Linux, you should run this as root before + * starting the postmaster: + * + * echo 0 >/proc/sys/kernel/randomize_va_space + * + * This prevents using randomized stack and code addresses that cause the + * child process's memory map to be different from the parent's, making it + * sometimes impossible to attach to shared memory at the desired address. + * Return the setting to its old value (usually '1' or '2') when finished. */ if (strcmp(argv[1], "--forkbackend") == 0 || strcmp(argv[1], "--forkavlauncher") == 0 || @@ -4683,9 +4706,6 @@ SubPostmasterMain(int argc, char *argv[]) { Assert(argc == 3); /* shouldn't be any more args */ - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* * Need to reinitialize the SSL library in the backend, since the * context structures contain function pointers and cannot be passed @@ -4716,17 +4736,7 @@ SubPostmasterMain(int argc, char *argv[]) /* Need a PGPROC to run CreateSharedMemoryAndSemaphores */ InitProcess(); - /* - * Attach process to shared data structures. If testing EXEC_BACKEND - * on Linux, you must run this as root before starting the postmaster: - * - * echo 0 >/proc/sys/kernel/randomize_va_space - * - * This prevents a randomized stack base address that causes child - * shared memory to be at a different address than the parent, making - * it impossible to attached to shared memory. Return the value to - * '1' when finished. - */ + /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); /* And run the backend */ @@ -4734,9 +4744,6 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkboot") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4750,9 +4757,6 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkavlauncher") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4766,9 +4770,6 @@ SubPostmasterMain(int argc, char *argv[]) } if (strcmp(argv[1], "--forkavworker") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4787,11 +4788,6 @@ SubPostmasterMain(int argc, char *argv[]) /* do this as early as possible; in particular, before InitProcess() */ IsBackgroundWorker = true; - InitPostmasterChild(); - - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Restore basic shared memory pointers */ InitShmemAccess(UsedShmemSegAddr); @@ -4801,33 +4797,26 @@ SubPostmasterMain(int argc, char *argv[]) /* Attach process to shared data structures */ CreateSharedMemoryAndSemaphores(false, 0); + /* Fetch MyBgworkerEntry from shared memory */ shmem_slot = atoi(argv[1] + 15); MyBgworkerEntry = BackgroundWorkerEntry(shmem_slot); + StartBackgroundWorker(); } if (strcmp(argv[1], "--forkarch") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Do not want to attach to shared memory */ PgArchiverMain(argc, argv); /* does not return */ } if (strcmp(argv[1], "--forkcol") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(false); - /* Do not want to attach to shared memory */ PgstatCollectorMain(argc, argv); /* does not return */ } if (strcmp(argv[1], "--forklog") == 0) { - /* Close the postmaster's sockets */ - ClosePostmasterPorts(true); - /* Do not want to attach to shared memory */ SysLoggerMain(argc, argv); /* does not return */ @@ -5076,6 +5065,10 @@ RandomSalt(char *md5Salt) /* * PostmasterRandom + * + * Caution: use this only for values needed during connection-request + * processing. Otherwise, the intended property of having an unpredictable + * delay between random_start_time and random_stop_time will be broken. */ static long PostmasterRandom(void) diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 9b5642a516..74b33c5ec4 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -744,13 +744,14 @@ ReorderBufferCommitChild(ReorderBuffer *rb, TransactionId xid, elog(ERROR, "subxact logged without previous toplevel record"); /* - * Pass the our base snapshot to the parent transaction if it doesn't have + * Pass our base snapshot to the parent transaction if it doesn't have * one, or ours is older. That can happen if there are no changes in the * toplevel transaction but in one of the child transactions. This allows - * the parent to simply use it's base snapshot initially. + * the parent to simply use its base snapshot initially. */ - if (txn->base_snapshot == NULL || - txn->base_snapshot_lsn > subtxn->base_snapshot_lsn) + if (subtxn->base_snapshot != NULL && + (txn->base_snapshot == NULL || + txn->base_snapshot_lsn > subtxn->base_snapshot_lsn)) { txn->base_snapshot = subtxn->base_snapshot; txn->base_snapshot_lsn = subtxn->base_snapshot_lsn; @@ -2206,7 +2207,10 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn, if (write(fd, rb->outbuf, ondisk->size) != ondisk->size) { + int save_errno = errno; + CloseTransientFile(fd); + errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to data file for XID %u: %m", @@ -2935,7 +2939,8 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, const char *fname) fd = OpenTransientFile(path, O_RDONLY | PG_BINARY, 0); if (fd < 0) ereport(ERROR, - (errmsg("could not open file \"%s\": %m", path))); + (errcode_for_file_access(), + errmsg("could not open file \"%s\": %m", path))); while (true) { diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index e100b8c2f3..8ae0acd61f 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -263,12 +263,22 @@ ReplicationSlotCreate(const char *name, bool db_specific, */ Assert(!slot->in_use); Assert(slot->active_pid == 0); - slot->data.persistency = persistency; - slot->data.xmin = InvalidTransactionId; - slot->effective_xmin = InvalidTransactionId; + + /* first initialize persistent data */ + memset(&slot->data, 0, sizeof(ReplicationSlotPersistentData)); StrNCpy(NameStr(slot->data.name), name, NAMEDATALEN); slot->data.database = db_specific ? MyDatabaseId : InvalidOid; - slot->data.restart_lsn = InvalidXLogRecPtr; + slot->data.persistency = persistency; + + /* and then data only present in shared memory */ + slot->just_dirtied = false; + slot->dirty = false; + slot->effective_xmin = InvalidTransactionId; + slot->effective_catalog_xmin = InvalidTransactionId; + slot->candidate_catalog_xmin = InvalidTransactionId; + slot->candidate_xmin_lsn = InvalidXLogRecPtr; + slot->candidate_restart_valid = InvalidXLogRecPtr; + slot->candidate_restart_lsn = InvalidXLogRecPtr; /* * Create the slot on disk. We haven't actually marked the slot allocated diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c index 3fa08567e7..132212a451 100644 --- a/src/backend/replication/syncrep.c +++ b/src/backend/replication/syncrep.c @@ -160,24 +160,16 @@ SyncRepWaitForLSN(XLogRecPtr XactCommitLSN) */ for (;;) { - int syncRepState; - /* Must reset the latch before testing state. */ ResetLatch(MyLatch); /* - * Try checking the state without the lock first. There's no - * guarantee that we'll read the most up-to-date value, so if it looks - * like we're still waiting, recheck while holding the lock. But if - * it looks like we're done, we must really be done, because once - * walsender changes the state to SYNC_REP_WAIT_COMPLETE, it will - * never update it again, so we can't be seeing a stale value in that - * case. + * Acquiring the lock is not needed, the latch ensures proper barriers. + * If it looks like we're done, we must really be done, because once + * walsender changes the state to SYNC_REP_WAIT_COMPLETE, it will never + * update it again, so we can't be seeing a stale value in that case. */ - syncRepState = MyProc->syncRepState; - if (syncRepState == SYNC_REP_WAITING) - syncRepState = MyProc->syncRepState; - if (syncRepState == SYNC_REP_WAIT_COMPLETE) + if (MyProc->syncRepState == SYNC_REP_WAIT_COMPLETE) break; /* diff --git a/src/backend/storage/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c index 0b10dac729..c611ab0baf 100644 --- a/src/backend/storage/ipc/dsm_impl.c +++ b/src/backend/storage/ipc/dsm_impl.c @@ -41,7 +41,7 @@ * * * IDENTIFICATION - * src/backend/storage/ipc/dsm.c + * src/backend/storage/ipc/dsm_impl.c * *------------------------------------------------------------------------- */ @@ -671,6 +671,7 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, { DWORD size_high; DWORD size_low; + DWORD errcode; /* Shifts >= the width of the type are undefined. */ #ifdef _WIN64 @@ -680,33 +681,40 @@ dsm_impl_windows(dsm_op op, dsm_handle handle, Size request_size, #endif size_low = (DWORD) request_size; + /* CreateFileMapping might not clear the error code on success */ + SetLastError(0); + hmap = CreateFileMapping(INVALID_HANDLE_VALUE, /* Use the pagefile */ NULL, /* Default security attrs */ PAGE_READWRITE, /* Memory is read/write */ size_high, /* Upper 32 bits of size */ size_low, /* Lower 32 bits of size */ name); + + errcode = GetLastError(); + if (errcode == ERROR_ALREADY_EXISTS || errcode == ERROR_ACCESS_DENIED) + { + /* + * On Windows, when the segment already exists, a handle for the + * existing segment is returned. We must close it before + * returning. However, if the existing segment is created by a + * service, then it returns ERROR_ACCESS_DENIED. We don't do + * _dosmaperr here, so errno won't be modified. + */ + if (hmap) + CloseHandle(hmap); + return false; + } + if (!hmap) { - _dosmaperr(GetLastError()); + _dosmaperr(errcode); ereport(elevel, (errcode_for_dynamic_shared_memory(), errmsg("could not create shared memory segment \"%s\": %m", name))); return false; } - _dosmaperr(GetLastError()); - if (errno == EEXIST) - { - /* - * On Windows, when the segment already exists, a handle for the - * existing segment is returned. We must close it before - * returning. We don't do _dosmaperr here, so errno won't be - * modified. - */ - CloseHandle(hmap); - return false; - } } else { diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c index 0abde43565..961d267ce0 100644 --- a/src/backend/storage/ipc/procsignal.c +++ b/src/backend/storage/ipc/procsignal.c @@ -67,12 +67,17 @@ typedef struct */ bool set_latch_on_sigusr1; +static bool CustomSignalPendings[NUM_CUSTOM_PROCSIGNALS]; +static ProcSignalHandler_type CustomHandlers[NUM_CUSTOM_PROCSIGNALS]; + static ProcSignalSlot *ProcSignalSlots = NULL; static volatile ProcSignalSlot *MyProcSignalSlot = NULL; static bool CheckProcSignal(ProcSignalReason reason); static void CleanupProcSignalState(int status, Datum arg); +static void CustomSignalInterrupt(ProcSignalReason reason); + /* * ProcSignalShmemSize * Compute space needed for procsignal's shared memory @@ -172,6 +177,57 @@ CleanupProcSignalState(int status, Datum arg) slot->pss_pid = 0; } +/* + * RegisterCustomProcSignalHandler + * Assign specific handler of custom process signal with new ProcSignalReason key. + * Return INVALID_PROCSIGNAL if all custom signals have been assigned. + */ +ProcSignalReason +RegisterCustomProcSignalHandler(ProcSignalHandler_type handler) +{ + ProcSignalReason reason; + + /* iterate through custom signal keys to find free spot */ + for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++) + if (!CustomHandlers[reason - PROCSIG_CUSTOM_1]) + { + CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler; + return reason; + } + return INVALID_PROCSIGNAL; +} + +/* + * AssignCustomProcSignalHandler + * Assign handler of custom process signal with specific ProcSignalReason key. + * Return old ProcSignal handler. + * Assume incoming reason is one of custom ProcSignals. + */ +ProcSignalHandler_type +AssignCustomProcSignalHandler(ProcSignalReason reason, ProcSignalHandler_type handler) +{ + ProcSignalHandler_type old; + + Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); + + old = CustomHandlers[reason - PROCSIG_CUSTOM_1]; + CustomHandlers[reason - PROCSIG_CUSTOM_1] = handler; + return old; +} + +/* + * GetCustomProcSignalHandler + * Get handler of custom process signal. + * Assume incoming reason is one of custom ProcSignals. + */ +ProcSignalHandler_type +GetCustomProcSignalHandler(ProcSignalReason reason) +{ + Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); + + return CustomHandlers[reason - PROCSIG_CUSTOM_1]; +} + /* * SendProcSignal * Send a signal to a Postgres process @@ -267,7 +323,8 @@ CheckProcSignal(ProcSignalReason reason) void procsignal_sigusr1_handler(SIGNAL_ARGS) { - int save_errno = errno; + int save_errno = errno; + ProcSignalReason reason; if (CheckProcSignal(PROCSIG_CATCHUP_INTERRUPT)) HandleCatchupInterrupt(); @@ -296,6 +353,10 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN)) RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); + for (reason = PROCSIG_CUSTOM_1; reason <= PROCSIG_CUSTOM_N; reason++) + if (CheckProcSignal(reason)) + CustomSignalInterrupt(reason); + if (set_latch_on_sigusr1) SetLatch(MyLatch); @@ -303,3 +364,45 @@ procsignal_sigusr1_handler(SIGNAL_ARGS) errno = save_errno; } + +/* + * Handle receipt of an interrupt indicating a custom process signal. + */ +static void +CustomSignalInterrupt(ProcSignalReason reason) +{ + int save_errno = errno; + + Assert(reason >= PROCSIG_CUSTOM_1 && reason <= PROCSIG_CUSTOM_N); + + /* set interrupt flags */ + InterruptPending = true; + CustomSignalPendings[reason - PROCSIG_CUSTOM_1] = true; + + /* make sure the event is processed in due course */ + SetLatch(MyLatch); + + errno = save_errno; +} + +/* + * CheckAndHandleCustomSignals + * Check custom signal flags and call handler assigned to that signal if it is not NULL. + * This function is called within CHECK_FOR_INTERRUPTS if interrupt have been occurred. + */ +void +CheckAndHandleCustomSignals(void) +{ + int i; + + for (i = 0; i < NUM_CUSTOM_PROCSIGNALS; i++) + if (CustomSignalPendings[i]) + { + ProcSignalHandler_type handler; + + CustomSignalPendings[i] = false; + handler = CustomHandlers[i]; + if (handler) + handler(); + } +} diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c index f88e624a41..65348dca97 100644 --- a/src/backend/storage/ipc/shm_mq.c +++ b/src/backend/storage/ipc/shm_mq.c @@ -868,11 +868,11 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data, */ WaitLatch(MyLatch, WL_LATCH_SET, 0); - /* An interrupt may have occurred while we were waiting. */ - CHECK_FOR_INTERRUPTS(); - /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); + + /* An interrupt may have occurred while we were waiting. */ + CHECK_FOR_INTERRUPTS(); } else { @@ -965,11 +965,11 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait, */ WaitLatch(MyLatch, WL_LATCH_SET, 0); - /* An interrupt may have occurred while we were waiting. */ - CHECK_FOR_INTERRUPTS(); - /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); + + /* An interrupt may have occurred while we were waiting. */ + CHECK_FOR_INTERRUPTS(); } } @@ -1071,11 +1071,11 @@ shm_mq_wait_internal(volatile shm_mq *mq, PGPROC *volatile * ptr, /* Wait to be signalled. */ WaitLatch(MyLatch, WL_LATCH_SET, 0); - /* An interrupt may have occurred while we were waiting. */ - CHECK_FOR_INTERRUPTS(); - /* Reset the latch so we don't spin. */ ResetLatch(MyLatch); + + /* An interrupt may have occurred while we were waiting. */ + CHECK_FOR_INTERRUPTS(); } } PG_CATCH(); diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 42a43bb07b..b36198ed4a 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -918,6 +918,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks) v = v->mdfd_chain; Assert(ov != reln->md_fd[forknum]); /* we never drop the 1st * segment */ + FileClose(ov->mdfd_vfd); pfree(ov); } else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index f78321d754..9ef7dd8f50 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3006,6 +3006,8 @@ ProcessInterrupts(void) if (ParallelMessagePending) HandleParallelMessages(); + + CheckAndHandleCustomSignals(); } diff --git a/src/backend/tsearch/ts_typanalyze.c b/src/backend/tsearch/ts_typanalyze.c index 432b582599..f6735957e6 100644 --- a/src/backend/tsearch/ts_typanalyze.c +++ b/src/backend/tsearch/ts_typanalyze.c @@ -295,7 +295,7 @@ compute_tsvector_stats(VacAttrStats *stats, stats->stawidth = total_width / (double) nonnull_cnt; /* Assume it's a unique column (see notes above) */ - stats->stadistinct = -1.0; + stats->stadistinct = -1.0 * (1.0 - stats->stanullfrac); /* * Construct an array of the interesting hashtable items, that is, diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c index 761e37501b..395e340196 100644 --- a/src/backend/utils/adt/datetime.c +++ b/src/backend/utils/adt/datetime.c @@ -52,8 +52,9 @@ static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, int scale); static int DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp); -static int DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, - pg_tz *tzp, int *isdst); +static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, + const char *abbr, pg_tz *tzp, + int *offset, int *isdst); static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp); @@ -1620,19 +1621,40 @@ DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp, pg_time_t *tp) * This differs from the behavior of DetermineTimeZoneOffset() in that a * standard-time or daylight-time abbreviation forces use of the corresponding * GMT offset even when the zone was then in DS or standard time respectively. + * (However, that happens only if we can match the given abbreviation to some + * abbreviation that appears in the IANA timezone data. Otherwise, we fall + * back to doing DetermineTimeZoneOffset().) */ int DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp) { pg_time_t t; + int zone_offset; + int abbr_offset; + int abbr_isdst; /* * Compute the UTC time we want to probe at. (In event of overflow, we'll * probe at the epoch, which is a bit random but probably doesn't matter.) */ - (void) DetermineTimeZoneOffsetInternal(tm, tzp, &t); + zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t); - return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, &tm->tm_isdst); + /* + * Try to match the abbreviation to something in the zone definition. + */ + if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, + &abbr_offset, &abbr_isdst)) + { + /* Success, so use the abbrev-specific answers. */ + tm->tm_isdst = abbr_isdst; + return abbr_offset; + } + + /* + * No match, so use the answers we already got from + * DetermineTimeZoneOffsetInternal. + */ + return zone_offset; } @@ -1646,19 +1668,41 @@ DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst) { pg_time_t t = timestamptz_to_time_t(ts); + int zone_offset; + int abbr_offset; + int tz; + struct pg_tm tm; + fsec_t fsec; - return DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, isdst); + /* + * If the abbrev matches anything in the zone data, this is pretty easy. + */ + if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp, + &abbr_offset, isdst)) + return abbr_offset; + + /* + * Else, break down the timestamp so we can use DetermineTimeZoneOffset. + */ + if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0) + ereport(ERROR, + (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), + errmsg("timestamp out of range"))); + + zone_offset = DetermineTimeZoneOffset(&tm, tzp); + *isdst = tm.tm_isdst; + return zone_offset; } /* DetermineTimeZoneAbbrevOffsetInternal() * * Workhorse for above two functions: work from a pg_time_t probe instant. - * DST status is returned into *isdst. + * On success, return GMT offset and DST status into *offset and *isdst. */ -static int -DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, - pg_tz *tzp, int *isdst) +static bool +DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, + int *offset, int *isdst) { char upabbr[TZ_STRLEN_MAX + 1]; unsigned char *p; @@ -1670,18 +1714,17 @@ DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, *p = pg_toupper(*p); /* Look up the abbrev's meaning at this time in this zone */ - if (!pg_interpret_timezone_abbrev(upabbr, - &t, - &gmtoff, - isdst, - tzp)) - ereport(ERROR, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("time zone abbreviation \"%s\" is not used in time zone \"%s\"", - abbr, pg_get_timezone_name(tzp)))); - - /* Change sign to agree with DetermineTimeZoneOffset() */ - return (int) -gmtoff; + if (pg_interpret_timezone_abbrev(upabbr, + &t, + &gmtoff, + isdst, + tzp)) + { + /* Change sign to agree with DetermineTimeZoneOffset() */ + *offset = (int) -gmtoff; + return true; + } + return false; } diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c index 4e927d807d..76aa636213 100644 --- a/src/backend/utils/adt/float.c +++ b/src/backend/utils/adt/float.c @@ -68,9 +68,6 @@ do { \ int extra_float_digits = 0; /* Added to DBL_DIG or FLT_DIG */ -static int float4_cmp_internal(float4 a, float4 b); -static int float8_cmp_internal(float8 a, float8 b); - #ifndef HAVE_CBRT /* * Some machines (in particular, some versions of AIX) have an extern @@ -867,7 +864,7 @@ float8div(PG_FUNCTION_ARGS) /* * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations */ -static int +int float4_cmp_internal(float4 a, float4 b) { /* @@ -981,7 +978,7 @@ btfloat4sortsupport(PG_FUNCTION_ARGS) /* * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations */ -static int +int float8_cmp_internal(float8 a, float8 b) { /* diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index d1d393e45d..43a9f33467 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -4432,12 +4432,12 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???"); #endif - if (*Np->inout_p == ' ') - Np->inout_p++; - #define OVERLOAD_TEST (Np->inout_p >= Np->inout + input_len) #define AMOUNT_TEST(_s) (input_len-(Np->inout_p-Np->inout) >= _s) + if (OVERLOAD_TEST) + return; + if (*Np->inout_p == ' ') Np->inout_p++; @@ -4575,7 +4575,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) * next char is not digit */ if (IS_LSIGN(Np->Num) && isread && - (Np->inout_p + 1) <= Np->inout + input_len && + (Np->inout_p + 1) < Np->inout + input_len && !isdigit((unsigned char) *(Np->inout_p + 1))) { int x; diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index ad48dfcb4b..dfb71a2f4e 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -2914,7 +2914,7 @@ close_ps(PG_FUNCTION_ARGS) } /* - * at this point the "normal" from point will hit lseg. The closet point + * at this point the "normal" from point will hit lseg. The closest point * will be somewhere on the lseg */ tmp = line_construct_pm(pt, invm); @@ -2923,7 +2923,15 @@ close_ps(PG_FUNCTION_ARGS) tmp->A, tmp->B, tmp->C); #endif result = interpt_sl(lseg, tmp); - Assert(result != NULL); + + /* + * ordinarily we should always find an intersection point, but that could + * fail in the presence of NaN coordinates, and perhaps even from simple + * roundoff issues. Return a SQL NULL if so. + */ + if (result == NULL) + PG_RETURN_NULL(); + #ifdef GEODEBUG printf("close_ps- result.x %f result.y %f\n", result->x, result->y); #endif diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c index 71fd213ed9..f2826f4522 100644 --- a/src/backend/utils/adt/numeric.c +++ b/src/backend/utils/adt/numeric.c @@ -760,10 +760,6 @@ numeric_recv(PG_FUNCTION_ARGS) init_var(&value); len = (uint16) pq_getmsgint(buf, sizeof(uint16)); - if (len < 0 || len > NUMERIC_MAX_PRECISION + NUMERIC_MAX_RESULT_SCALE) - ereport(ERROR, - (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), - errmsg("invalid length in external \"numeric\" value"))); alloc_var(&value, len); @@ -4651,12 +4647,19 @@ set_var_from_str(const char *str, const char *cp, NumericVar *dest) errmsg("invalid input syntax for type numeric: \"%s\"", str))); cp = endptr; - if (exponent > NUMERIC_MAX_PRECISION || - exponent < -NUMERIC_MAX_PRECISION) + + /* + * At this point, dweight and dscale can't be more than about + * INT_MAX/2 due to the MaxAllocSize limit on string length, so + * constraining the exponent similarly should be enough to prevent + * integer overflow in this function. If the value is too large to + * fit in storage format, make_result() will complain about it later; + * for consistency use the same ereport errcode/text as make_result(). + */ + if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2)) ereport(ERROR, - (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), - errmsg("invalid input syntax for type numeric: \"%s\"", - str))); + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("value overflows numeric format"))); dweight += (int) exponent; dscale -= (int) exponent; if (dscale < 0) diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index f7c9bf6333..7f8f63c46c 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -577,27 +577,17 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); - if (pid != -1) - { - /* Skip any which are not the one we're looking for. */ - PgBackendStatus *be = pgstat_fetch_stat_beentry(curr_backend); - - if (!be || be->st_procpid != pid) - continue; - - } - /* Get the next one in the list */ local_beentry = pgstat_fetch_stat_local_beentry(curr_backend); if (!local_beentry) - continue; - - beentry = &local_beentry->backendStatus; - if (!beentry) { int i; - for (i = 0; i < sizeof(nulls) / sizeof(nulls[0]); i++) + /* Ignore missing entries if looking for specific PID */ + if (pid != -1) + continue; + + for (i = 0; i < lengthof(nulls); i++) nulls[i] = true; nulls[5] = false; @@ -607,6 +597,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) continue; } + beentry = &local_beentry->backendStatus; + + /* If looking for specific PID, ignore all the others */ + if (pid != -1 && beentry->st_procpid != pid) + continue; + /* Values available to all callers */ values[0] = ObjectIdGetDatum(beentry->st_databaseid); values[1] = Int32GetDatum(beentry->st_procpid); diff --git a/src/backend/utils/adt/rangetypes_typanalyze.c b/src/backend/utils/adt/rangetypes_typanalyze.c index e0c09180ff..2710dae2b4 100644 --- a/src/backend/utils/adt/rangetypes_typanalyze.c +++ b/src/backend/utils/adt/rangetypes_typanalyze.c @@ -203,7 +203,9 @@ compute_range_stats(VacAttrStats *stats, AnalyzeAttrFetchFunc fetchfunc, /* Do the simple null-frac and width stats */ stats->stanullfrac = (double) null_cnt / (double) samplerows; stats->stawidth = total_width / (double) non_null_cnt; - stats->stadistinct = -1.0; + + /* Estimate that non-null values are unique */ + stats->stadistinct = -1.0 * (1.0 - stats->stanullfrac); /* Must copy the target values into anl_context */ old_cxt = MemoryContextSwitchTo(stats->anl_context); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9872c4a84d..05d222e80d 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -7928,17 +7928,43 @@ get_rule_expr(Node *node, deparse_context *context, if (!PRETTY_PAREN(context)) appendStringInfoChar(buf, '('); get_rule_expr_paren((Node *) ntest->arg, context, true, node); - switch (ntest->nulltesttype) + + /* + * For scalar inputs, we prefer to print as IS [NOT] NULL, + * which is shorter and traditional. If it's a rowtype input + * but we're applying a scalar test, must print IS [NOT] + * DISTINCT FROM NULL to be semantically correct. + */ + if (ntest->argisrow || + !type_is_rowtype(exprType((Node *) ntest->arg))) { - case IS_NULL: - appendStringInfoString(buf, " IS NULL"); - break; - case IS_NOT_NULL: - appendStringInfoString(buf, " IS NOT NULL"); - break; - default: - elog(ERROR, "unrecognized nulltesttype: %d", - (int) ntest->nulltesttype); + switch (ntest->nulltesttype) + { + case IS_NULL: + appendStringInfoString(buf, " IS NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(buf, " IS NOT NULL"); + break; + default: + elog(ERROR, "unrecognized nulltesttype: %d", + (int) ntest->nulltesttype); + } + } + else + { + switch (ntest->nulltesttype) + { + case IS_NULL: + appendStringInfoString(buf, " IS NOT DISTINCT FROM NULL"); + break; + case IS_NOT_NULL: + appendStringInfoString(buf, " IS DISTINCT FROM NULL"); + break; + default: + elog(ERROR, "unrecognized nulltesttype: %d", + (int) ntest->nulltesttype); + } } if (!PRETTY_PAREN(context)) appendStringInfoChar(buf, ')'); diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 2307f814b8..636ab2c9b3 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -4684,6 +4684,7 @@ double get_variable_numdistinct(VariableStatData *vardata, bool *isdefault) { double stadistinct; + double stanullfrac = 0.0; double ntuples; *isdefault = false; @@ -4691,7 +4692,8 @@ get_variable_numdistinct(VariableStatData *vardata, bool *isdefault) /* * Determine the stadistinct value to use. There are cases where we can * get an estimate even without a pg_statistic entry, or can get a better - * value than is in pg_statistic. + * value than is in pg_statistic. Grab stanullfrac too if we can find it + * (otherwise, assume no nulls, for lack of any better idea). */ if (HeapTupleIsValid(vardata->statsTuple)) { @@ -4700,6 +4702,7 @@ get_variable_numdistinct(VariableStatData *vardata, bool *isdefault) stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple); stadistinct = stats->stadistinct; + stanullfrac = stats->stanullfrac; } else if (vardata->vartype == BOOLOID) { @@ -4723,7 +4726,7 @@ get_variable_numdistinct(VariableStatData *vardata, bool *isdefault) { case ObjectIdAttributeNumber: case SelfItemPointerAttributeNumber: - stadistinct = -1.0; /* unique */ + stadistinct = -1.0; /* unique (and all non null) */ break; case TableOidAttributeNumber: stadistinct = 1.0; /* only 1 value */ @@ -4745,10 +4748,11 @@ get_variable_numdistinct(VariableStatData *vardata, bool *isdefault) * If there is a unique index or DISTINCT clause for the variable, assume * it is unique no matter what pg_statistic says; the statistics could be * out of date, or we might have found a partial unique index that proves - * the var is unique for this query. + * the var is unique for this query. However, we'd better still believe + * the null-fraction statistic. */ if (vardata->isunique) - stadistinct = -1.0; + stadistinct = -1.0 * (1.0 - stanullfrac); /* * If we had an absolute estimate, use that. diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 088c714821..afe41ff645 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -1585,7 +1585,10 @@ FlushErrorState(void) /* * ThrowErrorData --- report an error described by an ErrorData structure * - * This is intended to be used to re-report errors originally thrown by + * This is somewhat like ReThrowError, but it allows elevels besides ERROR, + * and the boolean flags such as output_to_server are computed via the + * default rules rather than being copied from the given ErrorData. + * This is primarily used to re-report errors originally reported by * background worker processes and then propagated (with or without * modification) to the backend responsible for them. */ @@ -1597,13 +1600,14 @@ ThrowErrorData(ErrorData *edata) if (!errstart(edata->elevel, edata->filename, edata->lineno, edata->funcname, NULL)) - return; + return; /* error is not to be reported at all */ newedata = &errordata[errordata_stack_depth]; - oldcontext = MemoryContextSwitchTo(edata->assoc_context); + recursion_depth++; + oldcontext = MemoryContextSwitchTo(newedata->assoc_context); - /* Copy the supplied fields to the error stack. */ - if (edata->sqlerrcode > 0) + /* Copy the supplied fields to the error stack entry. */ + if (edata->sqlerrcode != 0) newedata->sqlerrcode = edata->sqlerrcode; if (edata->message) newedata->message = pstrdup(edata->message); @@ -1615,6 +1619,7 @@ ThrowErrorData(ErrorData *edata) newedata->hint = pstrdup(edata->hint); if (edata->context) newedata->context = pstrdup(edata->context); + /* assume message_id is not available */ if (edata->schema_name) newedata->schema_name = pstrdup(edata->schema_name); if (edata->table_name) @@ -1625,11 +1630,15 @@ ThrowErrorData(ErrorData *edata) newedata->datatype_name = pstrdup(edata->datatype_name); if (edata->constraint_name) newedata->constraint_name = pstrdup(edata->constraint_name); + newedata->cursorpos = edata->cursorpos; + newedata->internalpos = edata->internalpos; if (edata->internalquery) newedata->internalquery = pstrdup(edata->internalquery); MemoryContextSwitchTo(oldcontext); + recursion_depth--; + /* Process the error. */ errfinish(0); } diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 18c433b919..7e622e37fd 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -62,8 +62,6 @@ # (change requires restart) #port = 5432 # (change requires restart) #max_connections = 100 # (change requires restart) -# Note: Increasing max_connections costs ~400 bytes of shared memory per -# connection slot, plus lock space (see max_locks_per_transaction). #superuser_reserved_connections = 3 # (change requires restart) #unix_socket_directories = '/tmp' # comma-separated list of directories # (change requires restart) @@ -119,10 +117,8 @@ #temp_buffers = 8MB # min 800kB #max_prepared_transactions = 0 # zero disables the feature # (change requires restart) -# Note: Increasing max_prepared_transactions costs ~600 bytes of shared memory -# per transaction slot, plus lock space (see max_locks_per_transaction). -# It is not advisable to set max_prepared_transactions nonzero unless you -# actively intend to use prepared transactions. +# Caution: it is not advisable to set max_prepared_transactions nonzero unless +# you actively intend to use prepared transactions. #work_mem = 4MB # min 64kB #maintenance_work_mem = 64MB # min 1MB #autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem @@ -573,9 +569,6 @@ #deadlock_timeout = 1s #max_locks_per_transaction = 64 # min 10 # (change requires restart) -# Note: Each lock table slot uses ~270 bytes of shared memory, and there are -# max_locks_per_transaction * (max_connections + max_prepared_transactions) -# lock table slots. #max_pred_locks_per_transaction = 64 # min 10 # (change requires restart) diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index 9b29e275c0..34f2b46b9e 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -1315,7 +1315,7 @@ tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel, mtup->datum1 = index_getattr(tuple, 1, RelationGetDescr(state->indexRel), - &stup.isnull1); + &mtup->isnull1); } } @@ -3441,7 +3441,7 @@ copytup_cluster(Tuplesortstate *state, SortTuple *stup, void *tup) mtup->datum1 = heap_getattr(tuple, state->indexInfo->ii_KeyAttrNumbers[0], state->tupDesc, - &stup->isnull1); + &mtup->isnull1); } } } @@ -3745,7 +3745,7 @@ copytup_index(Tuplesortstate *state, SortTuple *stup, void *tup) mtup->datum1 = index_getattr(tuple, 1, RelationGetDescr(state->indexRel), - &stup->isnull1); + &mtup->isnull1); } } } diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index 2d44985208..9cc780ee10 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -408,8 +408,8 @@ HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, /* * An invalid Xmin can be left behind by a speculative insertion that - * is cancelled by super-deleting the tuple. We shouldn't see any of - * those in TOAST tables, but better safe than sorry. + * is canceled by super-deleting the tuple. This also applies to + * TOAST tuples created during speculative insertion. */ else if (!TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple))) return false; diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c index bdc3b99611..4a9ea2d9bc 100644 --- a/src/bin/initdb/findtimezone.c +++ b/src/bin/initdb/findtimezone.c @@ -99,15 +99,15 @@ pg_load_tz(const char *name) */ if (strcmp(name, "GMT") == 0) { - if (tzparse(name, &tz.state, TRUE) != 0) + if (!tzparse(name, &tz.state, true)) { /* This really, really should not happen ... */ return NULL; } } - else if (tzload(name, NULL, &tz.state, TRUE) != 0) + else if (tzload(name, NULL, &tz.state, true) != 0) { - if (name[0] == ':' || tzparse(name, &tz.state, FALSE) != 0) + if (name[0] == ':' || !tzparse(name, &tz.state, false)) { return NULL; /* unknown timezone */ } @@ -584,7 +584,7 @@ static const struct /* * This list was built from the contents of the registry at * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time - * Zones on Windows 2003 R2. + * Zones on Windows 10 and Windows 7. * * The zones have been matched to Olson timezones by looking at the cities * listed in the win32 display name (in the comment here) in most cases. @@ -592,417 +592,590 @@ static const struct { "Afghanistan Standard Time", "Afghanistan Daylight Time", "Asia/Kabul" - }, /* (GMT+04:30) Kabul */ + }, /* (UTC+04:30) Kabul */ { "Alaskan Standard Time", "Alaskan Daylight Time", "US/Alaska" - }, /* (GMT-09:00) Alaska */ + }, /* (UTC-09:00) Alaska */ + { + "Aleutian Standard Time", "Aleutian Daylight Time", + "US/Aleutan" + }, /* (UTC-10:00) Aleutian Islands */ + { + "Altai Standard Time", "Altai Daylight Time", + "Asia/Barnaul" + }, /* (UTC+07:00) Barnaul, Gorno-Altaysk */ { "Arab Standard Time", "Arab Daylight Time", "Asia/Kuwait" - }, /* (GMT+03:00) Kuwait, Riyadh */ + }, /* (UTC+03:00) Kuwait, Riyadh */ { "Arabian Standard Time", "Arabian Daylight Time", "Asia/Muscat" - }, /* (GMT+04:00) Abu Dhabi, Muscat */ + }, /* (UTC+04:00) Abu Dhabi, Muscat */ { "Arabic Standard Time", "Arabic Daylight Time", "Asia/Baghdad" - }, /* (GMT+03:00) Baghdad */ + }, /* (UTC+03:00) Baghdad */ { "Argentina Standard Time", "Argentina Daylight Time", "America/Buenos_Aires" - }, /* (GMT-03:00) Buenos Aires */ + }, /* (UTC-03:00) City of Buenos Aires */ { "Armenian Standard Time", "Armenian Daylight Time", "Asia/Yerevan" - }, /* (GMT+04:00) Yerevan */ + }, /* (UTC+04:00) Baku, Tbilisi, Yerevan */ + { + "Astrakhan Standard Time", "Astrakhan Daylight Time", + "Europe/Astrakhan" + }, /* (UTC+04:00) Astrakhan, Ulyanovsk */ { "Atlantic Standard Time", "Atlantic Daylight Time", "Canada/Atlantic" - }, /* (GMT-04:00) Atlantic Time (Canada) */ + }, /* (UTC-04:00) Atlantic Time (Canada) */ { "AUS Central Standard Time", "AUS Central Daylight Time", "Australia/Darwin" - }, /* (GMT+09:30) Darwin */ + }, /* (UTC+09:30) Darwin */ + { + "Aus Central W. Standard Time", "Aus Central W. Daylight Time", + "Australia/Eucla" + }, /* (UTC+08:45) Eucla */ { "AUS Eastern Standard Time", "AUS Eastern Daylight Time", "Australia/Canberra" - }, /* (GMT+10:00) Canberra, Melbourne, Sydney */ + }, /* (UTC+10:00) Canberra, Melbourne, Sydney */ { "Azerbaijan Standard Time", "Azerbaijan Daylight Time", "Asia/Baku" - }, /* (GMT+04:00) Baku */ + }, /* (UTC+04:00) Baku */ { "Azores Standard Time", "Azores Daylight Time", "Atlantic/Azores" - }, /* (GMT-01:00) Azores */ + }, /* (UTC-01:00) Azores */ + { + "Bahia Standard Time", "Bahia Daylight Time", + "America/Salvador" + }, /* (UTC-03:00) Salvador */ { "Bangladesh Standard Time", "Bangladesh Daylight Time", "Asia/Dhaka" - }, /* (GMT+06:00) Dhaka */ + }, /* (UTC+06:00) Dhaka */ + { + "Bougainville Standard Time", "Bougainville Daylight Time", + "Pacific/Bougainville" + }, /* (UTC+11:00) Bougainville Island */ + { + "Belarus Standard Time", "Belarus Daylight Time", + "Europe/Minsk" + }, /* (UTC+03:00) Minsk */ + { + "Cabo Verde Standard Time", "Cabo Verde Daylight Time", + "Atlantic/Cape_Verde" + }, /* (UTC-01:00) Cabo Verde Is. */ + { + "Chatham Islands Standard Time", "Chatham Islands Daylight Time", + "Pacific/Chatham" + }, /* (UTC+12:45) Chatham Islands */ { "Canada Central Standard Time", "Canada Central Daylight Time", "Canada/Saskatchewan" - }, /* (GMT-06:00) Saskatchewan */ + }, /* (UTC-06:00) Saskatchewan */ { "Cape Verde Standard Time", "Cape Verde Daylight Time", "Atlantic/Cape_Verde" - }, /* (GMT-01:00) Cape Verde Is. */ + }, /* (UTC-01:00) Cape Verde Is. */ { "Caucasus Standard Time", "Caucasus Daylight Time", "Asia/Baku" - }, /* (GMT+04:00) Baku, Tbilisi, Yerevan */ + }, /* (UTC+04:00) Yerevan */ { "Cen. Australia Standard Time", "Cen. Australia Daylight Time", "Australia/Adelaide" - }, /* (GMT+09:30) Adelaide */ + }, /* (UTC+09:30) Adelaide */ /* Central America (other than Mexico) generally does not observe DST */ { "Central America Standard Time", "Central America Daylight Time", "CST6" - }, /* (GMT-06:00) Central America */ + }, /* (UTC-06:00) Central America */ { "Central Asia Standard Time", "Central Asia Daylight Time", "Asia/Dhaka" - }, /* (GMT+06:00) Astana, Dhaka */ + }, /* (UTC+06:00) Astana */ { "Central Brazilian Standard Time", "Central Brazilian Daylight Time", "America/Cuiaba" - }, /* (GMT-04:00) Cuiaba */ + }, /* (UTC-04:00) Cuiaba */ { "Central Europe Standard Time", "Central Europe Daylight Time", "Europe/Belgrade" - }, /* (GMT+01:00) Belgrade, Bratislava, Budapest, + }, /* (UTC+01:00) Belgrade, Bratislava, Budapest, * Ljubljana, Prague */ { "Central European Standard Time", "Central European Daylight Time", "Europe/Sarajevo" - }, /* (GMT+01:00) Sarajevo, Skopje, Warsaw, + }, /* (UTC+01:00) Sarajevo, Skopje, Warsaw, * Zagreb */ { "Central Pacific Standard Time", "Central Pacific Daylight Time", "Pacific/Noumea" - }, /* (GMT+11:00) Magadan, Solomon Is., New - * Caledonia */ + }, /* (UTC+11:00) Solomon Is., New Caledonia */ { "Central Standard Time", "Central Daylight Time", "US/Central" - }, /* (GMT-06:00) Central Time (US & Canada) */ + }, /* (UTC-06:00) Central Time (US & Canada) */ { "Central Standard Time (Mexico)", "Central Daylight Time (Mexico)", "America/Mexico_City" - }, /* (GMT-06:00) Guadalajara, Mexico City, - * Monterrey - New */ + }, /* (UTC-06:00) Guadalajara, Mexico City, + * Monterrey */ { "China Standard Time", "China Daylight Time", "Asia/Hong_Kong" - }, /* (GMT+08:00) Beijing, Chongqing, Hong Kong, + }, /* (UTC+08:00) Beijing, Chongqing, Hong Kong, * Urumqi */ + { + "Cuba Standard Time", "Cuba Daylight Time", + "America/Havana" + }, /* (UTC-05:00) Havana */ { "Dateline Standard Time", "Dateline Daylight Time", - "Etc/GMT+12" - }, /* (GMT-12:00) International Date Line West */ + "Etc/UTC+12" + }, /* (UTC-12:00) International Date Line West */ { "E. Africa Standard Time", "E. Africa Daylight Time", "Africa/Nairobi" - }, /* (GMT+03:00) Nairobi */ + }, /* (UTC+03:00) Nairobi */ { "E. Australia Standard Time", "E. Australia Daylight Time", "Australia/Brisbane" - }, /* (GMT+10:00) Brisbane */ + }, /* (UTC+10:00) Brisbane */ { "E. Europe Standard Time", "E. Europe Daylight Time", "Europe/Bucharest" - }, /* (GMT+02:00) Bucharest */ + }, /* (UTC+02:00) E. Europe */ { "E. South America Standard Time", "E. South America Daylight Time", "America/Araguaina" - }, /* (GMT-03:00) Brasilia */ + }, /* (UTC-03:00) Brasilia */ { "Eastern Standard Time", "Eastern Daylight Time", "US/Eastern" - }, /* (GMT-05:00) Eastern Time (US & Canada) */ + }, /* (UTC-05:00) Eastern Time (US & Canada) */ + { + "Eastern Standard Time (Mexico)", "Eastern Daylight Time (Mexico)", + "America/Mexico_City" + }, /* (UTC-05:00) Chetumal */ + { + "Easter Island Standard Time", "Easter Island Daylight Time", + "Pacific/Easter" + }, /* (UTC-06:00) Easter Island */ { "Egypt Standard Time", "Egypt Daylight Time", "Africa/Cairo" - }, /* (GMT+02:00) Cairo */ + }, /* (UTC+02:00) Cairo */ { - "Ekaterinburg Standard Time", "Ekaterinburg Daylight Time", + "Ekaterinburg Standard Time (RTZ 4)", "Ekaterinburg Daylight Time", "Asia/Yekaterinburg" - }, /* (GMT+05:00) Ekaterinburg */ + }, /* (UTC+05:00) Ekaterinburg */ { "Fiji Standard Time", "Fiji Daylight Time", "Pacific/Fiji" - }, /* (GMT+12:00) Fiji, Kamchatka, Marshall Is. */ + }, /* (UTC+12:00) Fiji */ { "FLE Standard Time", "FLE Daylight Time", "Europe/Helsinki" - }, /* (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, + }, /* (UTC+02:00) Helsinki, Kyiv, Riga, Sofia, * Tallinn, Vilnius */ { "Georgian Standard Time", "Georgian Daylight Time", "Asia/Tbilisi" - }, /* (GMT+03:00) Tbilisi */ + }, /* (UTC+04:00) Tbilisi */ { "GMT Standard Time", "GMT Daylight Time", "Europe/London" - }, /* (GMT) Greenwich Mean Time : Dublin, - * Edinburgh, Lisbon, London */ + }, /* (UTC) Dublin, Edinburgh, Lisbon, London */ { "Greenland Standard Time", "Greenland Daylight Time", "America/Godthab" - }, /* (GMT-03:00) Greenland */ + }, /* (UTC-03:00) Greenland */ { "Greenwich Standard Time", "Greenwich Daylight Time", "Africa/Casablanca" - }, /* (GMT) Casablanca, Monrovia */ + }, /* (UTC) Monrovia, Reykjavik */ { "GTB Standard Time", "GTB Daylight Time", "Europe/Athens" - }, /* (GMT+02:00) Athens, Istanbul, Minsk */ + }, /* (UTC+02:00) Athens, Bucharest */ + { + "Haiti Standard Time", "Haiti Daylight Time", + "US/Eastern" + }, /* (UTC-05:00) Haiti */ { "Hawaiian Standard Time", "Hawaiian Daylight Time", "US/Hawaii" - }, /* (GMT-10:00) Hawaii */ + }, /* (UTC-10:00) Hawaii */ { "India Standard Time", "India Daylight Time", "Asia/Calcutta" - }, /* (GMT+05:30) Chennai, Kolkata, Mumbai, New + }, /* (UTC+05:30) Chennai, Kolkata, Mumbai, New * Delhi */ { "Iran Standard Time", "Iran Daylight Time", "Asia/Tehran" - }, /* (GMT+03:30) Tehran */ + }, /* (UTC+03:30) Tehran */ { "Jerusalem Standard Time", "Jerusalem Daylight Time", "Asia/Jerusalem" - }, /* (GMT+02:00) Jerusalem */ + }, /* (UTC+02:00) Jerusalem */ { "Jordan Standard Time", "Jordan Daylight Time", "Asia/Amman" - }, /* (GMT+02:00) Amman */ + }, /* (UTC+02:00) Amman */ { "Kamchatka Standard Time", "Kamchatka Daylight Time", "Asia/Kamchatka" - }, /* (GMT+12:00) Petropavlovsk-Kamchatsky */ + }, /* (UTC+12:00) Petropavlovsk-Kamchatsky - Old */ { "Korea Standard Time", "Korea Daylight Time", "Asia/Seoul" - }, /* (GMT+09:00) Seoul */ + }, /* (UTC+09:00) Seoul */ + { + "Libya Standard Time", "Libya Daylight Time", + "Africa/Tripoli" + }, /* (UTC+02:00) Tripoli */ + { + "Line Islands Standard Time", "Line Islands Daylight Time", + "Pacific/Kiritimati" + }, /* (UTC+14:00) Kiritimati Island */ + { + "Lord Howe Standard Time", "Lord Howe Daylight Time", + "Australia/Lord_Howe" + }, /* (UTC+10:30) Lord Howe Island */ + { + "Magadan Standard Time", "Magadan Daylight Time", + "Asia/Magadan" + }, /* (UTC+10:00) Magadan */ + { + "Marquesas Standard Time", "Marquesas Daylight Time", + "Pacific/Marquesas" + }, /* (UTC-09:30) Marquesas Islands */ { "Mauritius Standard Time", "Mauritius Daylight Time", "Indian/Mauritius" - }, /* (GMT+04:00) Port Louis */ + }, /* (UTC+04:00) Port Louis */ { "Mexico Standard Time", "Mexico Daylight Time", "America/Mexico_City" - }, /* (GMT-06:00) Guadalajara, Mexico City, + }, /* (UTC-06:00) Guadalajara, Mexico City, * Monterrey */ { "Mexico Standard Time 2", "Mexico Daylight Time 2", "America/Chihuahua" - }, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan */ + }, /* (UTC-07:00) Chihuahua, La Paz, Mazatlan */ { "Mid-Atlantic Standard Time", "Mid-Atlantic Daylight Time", "Atlantic/South_Georgia" - }, /* (GMT-02:00) Mid-Atlantic */ + }, /* (UTC-02:00) Mid-Atlantic - Old */ { "Middle East Standard Time", "Middle East Daylight Time", "Asia/Beirut" - }, /* (GMT+02:00) Beirut */ + }, /* (UTC+02:00) Beirut */ { "Montevideo Standard Time", "Montevideo Daylight Time", "America/Montevideo" - }, /* (GMT-03:00) Montevideo */ + }, /* (UTC-03:00) Montevideo */ { "Morocco Standard Time", "Morocco Daylight Time", "Africa/Casablanca" - }, /* (GMT) Casablanca */ + }, /* (UTC) Casablanca */ { "Mountain Standard Time", "Mountain Daylight Time", "US/Mountain" - }, /* (GMT-07:00) Mountain Time (US & Canada) */ + }, /* (UTC-07:00) Mountain Time (US & Canada) */ { "Mountain Standard Time (Mexico)", "Mountain Daylight Time (Mexico)", "America/Chihuahua" - }, /* (GMT-07:00) Chihuahua, La Paz, Mazatlan - - * New */ + }, /* (UTC-07:00) Chihuahua, La Paz, Mazatlan */ { "Myanmar Standard Time", "Myanmar Daylight Time", "Asia/Rangoon" - }, /* (GMT+06:30) Rangoon */ + }, /* (UTC+06:30) Yangon (Rangoon) */ { "N. Central Asia Standard Time", "N. Central Asia Daylight Time", "Asia/Novosibirsk" - }, /* (GMT+06:00) Novosibirsk */ + }, /* (UTC+06:00) Novosibirsk (RTZ 5) */ { "Namibia Standard Time", "Namibia Daylight Time", "Africa/Windhoek" - }, /* (GMT+02:00) Windhoek */ + }, /* (UTC+01:00) Windhoek */ { "Nepal Standard Time", "Nepal Daylight Time", "Asia/Katmandu" - }, /* (GMT+05:45) Kathmandu */ + }, /* (UTC+05:45) Kathmandu */ { "New Zealand Standard Time", "New Zealand Daylight Time", "Pacific/Auckland" - }, /* (GMT+12:00) Auckland, Wellington */ + }, /* (UTC+12:00) Auckland, Wellington */ { "Newfoundland Standard Time", "Newfoundland Daylight Time", "Canada/Newfoundland" - }, /* (GMT-03:30) Newfoundland */ + }, /* (UTC-03:30) Newfoundland */ + { + "Norfolk Standard Time", "Norfolk Daylight Time", + "Pacific/Norfolk" + }, /* (UTC+11:00) Norfolk Island */ { "North Asia East Standard Time", "North Asia East Daylight Time", "Asia/Irkutsk" - }, /* (GMT+08:00) Irkutsk, Ulaan Bataar */ + }, /* (UTC+08:00) Irkutsk, Ulaan Bataar */ { "North Asia Standard Time", "North Asia Daylight Time", "Asia/Krasnoyarsk" - }, /* (GMT+07:00) Krasnoyarsk */ + }, /* (UTC+07:00) Krasnoyarsk */ + { + "North Korea Standard Time", "North Korea Daylight Time", + "Asia/Pyongyang" + }, /* (UTC+08:30) Pyongyang */ { "Pacific SA Standard Time", "Pacific SA Daylight Time", "America/Santiago" - }, /* (GMT-04:00) Santiago */ + }, /* (UTC-03:00) Santiago */ { "Pacific Standard Time", "Pacific Daylight Time", "US/Pacific" - }, /* (GMT-08:00) Pacific Time (US & Canada); - * Tijuana */ + }, /* (UTC-08:00) Pacific Time (US & Canada) */ { "Pacific Standard Time (Mexico)", "Pacific Daylight Time (Mexico)", "America/Tijuana" - }, /* (GMT-08:00) Tijuana, Baja California */ + }, /* (UTC-08:00) Baja California */ { "Pakistan Standard Time", "Pakistan Daylight Time", "Asia/Karachi" - }, /* (GMT+05:00) Islamabad, Karachi */ + }, /* (UTC+05:00) Islamabad, Karachi */ { "Paraguay Standard Time", "Paraguay Daylight Time", "America/Asuncion" - }, /* (GMT-04:00) Asuncion */ + }, /* (UTC-04:00) Asuncion */ { "Romance Standard Time", "Romance Daylight Time", "Europe/Brussels" - }, /* (GMT+01:00) Brussels, Copenhagen, Madrid, + }, /* (UTC+01:00) Brussels, Copenhagen, Madrid, * Paris */ + { + "Russia TZ 1 Standard Time", "Russia TZ 1 Daylight Time", + "Europe/Kaliningrad" + }, /* (UTC+02:00) Kaliningrad (RTZ 1) */ + { + "Russia TZ 2 Standard Time", "Russia TZ 2 Daylight Time", + "Europe/Moscow" + }, /* (UTC+03:00) Moscow, St. Petersburg, + * Volgograd (RTZ 2) */ + { + "Russia TZ 3 Standard Time", "Russia TZ 3 Daylight Time", + "Europe/Samara" + }, /* (UTC+04:00) Izhevsk, Samara (RTZ 3) */ + { + "Russia TZ 4 Standard Time", "Russia TZ 4 Daylight Time", + "Asia/Yekaterinburg" + }, /* (UTC+05:00) Ekaterinburg (RTZ 4) */ + { + "Russia TZ 5 Standard Time", "Russia TZ 5 Daylight Time", + "Asia/Novosibirsk" + }, /* (UTC+06:00) Novosibirsk (RTZ 5) */ + { + "Russia TZ 6 Standard Time", "Russia TZ 6 Daylight Time", + "Asia/Krasnoyarsk" + }, /* (UTC+07:00) Krasnoyarsk (RTZ 6) */ + { + "Russia TZ 7 Standard Time", "Russia TZ 7 Daylight Time", + "Asia/Irkutsk" + }, /* (UTC+08:00) Irkutsk (RTZ 7) */ + { + "Russia TZ 8 Standard Time", "Russia TZ 8 Daylight Time", + "Asia/Yakutsk" + }, /* (UTC+09:00) Yakutsk (RTZ 8) */ + { + "Russia TZ 9 Standard Time", "Russia TZ 9 Daylight Time", + "Asia/Vladivostok" + }, /* (UTC+10:00) Vladivostok, Magadan + * (RTZ 9) */ + { + "Russia TZ 10 Standard Time", "Russia TZ 10 Daylight Time", + "Asia/Magadan" + }, /* (UTC+11:00) Chokurdakh (RTZ 10) */ + { + "Russia TZ 11 Standard Time", "Russia TZ 11 Daylight Time", + "Asia/Anadyr" + }, /* (UTC+12:00) Anadyr, Petropavlovsk-Kamchatsky + * (RTZ 11) */ { "Russian Standard Time", "Russian Daylight Time", "Europe/Moscow" - }, /* (GMT+03:00) Moscow, St. Petersburg, + }, /* (UTC+03:00) Moscow, St. Petersburg, * Volgograd */ { "SA Eastern Standard Time", "SA Eastern Daylight Time", "America/Buenos_Aires" - }, /* (GMT-03:00) Buenos Aires, Georgetown */ + }, /* (UTC-03:00) Cayenne, Fortaleza */ { "SA Pacific Standard Time", "SA Pacific Daylight Time", "America/Bogota" - }, /* (GMT-05:00) Bogota, Lima, Quito */ + }, /* (UTC-05:00) Bogota, Lima, Quito, Rio + * Branco */ { "SA Western Standard Time", "SA Western Daylight Time", "America/Caracas" - }, /* (GMT-04:00) Caracas, La Paz */ + }, /* (UTC-04:00) Georgetown, La Paz, Manaus, + * San Juan */ + { + "Saint Pierre Standard Time", "Saint Pierre Daylight Time", + "America/Miquelon" + }, /* (UTC-03:00) Saint Pierre and Miquelon */ { "Samoa Standard Time", "Samoa Daylight Time", - "Pacific/Midway" - }, /* (GMT-11:00) Midway Island, Samoa */ + "Pacific/Samoa" + }, /* (UTC+13:00) Samoa */ { "SE Asia Standard Time", "SE Asia Daylight Time", "Asia/Bangkok" - }, /* (GMT+07:00) Bangkok, Hanoi, Jakarta */ + }, /* (UTC+07:00) Bangkok, Hanoi, Jakarta */ { "Malay Peninsula Standard Time", "Malay Peninsula Daylight Time", "Asia/Kuala_Lumpur" - }, /* (GMT+08:00) Kuala Lumpur, Singapore */ + }, /* (UTC+08:00) Kuala Lumpur, Singapore */ + { + "Sakhalin Standard Time", "Sakhalin Daylight Time", + "Asia/Sakhalin" + }, /* (UTC+11:00) Sakhalin */ { "South Africa Standard Time", "South Africa Daylight Time", "Africa/Harare" - }, /* (GMT+02:00) Harare, Pretoria */ + }, /* (UTC+02:00) Harare, Pretoria */ { "Sri Lanka Standard Time", "Sri Lanka Daylight Time", "Asia/Colombo" - }, /* (GMT+06:00) Sri Jayawardenepura */ + }, /* (UTC+05:30) Sri Jayawardenepura */ + { + "Syria Standard Time", "Syria Daylight Time", + "Asia/Damascus" + }, /* (UTC+02:00) Damascus */ { "Taipei Standard Time", "Taipei Daylight Time", "Asia/Taipei" - }, /* (GMT+08:00) Taipei */ + }, /* (UTC+08:00) Taipei */ { "Tasmania Standard Time", "Tasmania Daylight Time", "Australia/Hobart" - }, /* (GMT+10:00) Hobart */ + }, /* (UTC+10:00) Hobart */ + { + "Tocantins Standard Time", "Tocantins Daylight Time", + "America/Araguaina" + }, /* (UTC-03:00) Araguaina */ { "Tokyo Standard Time", "Tokyo Daylight Time", "Asia/Tokyo" - }, /* (GMT+09:00) Osaka, Sapporo, Tokyo */ + }, /* (UTC+09:00) Osaka, Sapporo, Tokyo */ { "Tonga Standard Time", "Tonga Daylight Time", "Pacific/Tongatapu" - }, /* (GMT+13:00) Nuku'alofa */ + }, /* (UTC+13:00) Nuku'alofa */ + { + "Tomsk Standard Time", "Tomsk Daylight Time", + "Asia/Tomsk" + }, /* (UTC+07:00) Tomsk */ + { + "Transbaikal Standard Time", "Transbaikal Daylight Time", + "Asia/Chita" + }, /* (UTC+09:00) Chita */ + { + "Turkey Standard Time", "Turkey Daylight Time", + "Europe/Istanbul" + }, /* (UTC+02:00) Istanbul */ + { + "Turks and Caicos Standard Time", "Turks and Caicos Daylight Time", + "America/Grand_Turk" + }, /* (UTC-04:00) Turks and Caicos */ { "Ulaanbaatar Standard Time", "Ulaanbaatar Daylight Time", "Asia/Ulaanbaatar", - }, /* (GMT+08:00) Ulaanbaatar */ + }, /* (UTC+08:00) Ulaanbaatar */ { "US Eastern Standard Time", "US Eastern Daylight Time", "US/Eastern" - }, /* (GMT-05:00) Indiana (East) */ + }, /* (UTC-05:00) Indiana (East) */ { "US Mountain Standard Time", "US Mountain Daylight Time", "US/Arizona" - }, /* (GMT-07:00) Arizona */ + }, /* (UTC-07:00) Arizona */ { "Coordinated Universal Time", "Coordinated Universal Time", "UTC" - }, /* (GMT) Coordinated Universal Time */ + }, /* (UTC) Coordinated Universal Time */ { "UTC+12", "UTC+12", "Etc/GMT+12" - }, /* (GMT+12:00) Coordinated Universal Time+12 */ + }, /* (UTC+12:00) Coordinated Universal Time+12 */ { "UTC-02", "UTC-02", "Etc/GMT-02" - }, /* (GMT-02:00) Coordinated Universal Time-02 */ + }, /* (UTC-02:00) Coordinated Universal Time-02 */ + { + "UTC-08", "UTC-08", + "Etc/GMT-08" + }, /* (UTC-08:00) Coordinated Universal Time-08 */ + { + "UTC-09", "UTC-09", + "Etc/GMT-09" + }, /* (UTC-09:00) Coordinated Universal Time-09 */ { "UTC-11", "UTC-11", "Etc/GMT-11" - }, /* (GMT-11:00) Coordinated Universal Time-11 */ + }, /* (UTC-11:00) Coordinated Universal Time-11 */ { "Venezuela Standard Time", "Venezuela Daylight Time", "America/Caracas", - }, /* (GMT-04:30) Caracas */ + }, /* (UTC-04:30) Caracas */ { "Vladivostok Standard Time", "Vladivostok Daylight Time", "Asia/Vladivostok" - }, /* (GMT+10:00) Vladivostok */ + }, /* (UTC+10:00) Vladivostok (RTZ 9) */ { "W. Australia Standard Time", "W. Australia Daylight Time", "Australia/Perth" - }, /* (GMT+08:00) Perth */ + }, /* (UTC+08:00) Perth */ #ifdef NOT_USED /* Could not find a match for this one (just a guess). Excluded for now. */ { "W. Central Africa Standard Time", "W. Central Africa Daylight Time", "WAT" - }, /* (GMT+01:00) West Central Africa */ + }, /* (UTC+01:00) West Central Africa */ #endif { "W. Europe Standard Time", "W. Europe Daylight Time", "CET" - }, /* (GMT+01:00) Amsterdam, Berlin, Bern, Rome, + }, /* (UTC+01:00) Amsterdam, Berlin, Bern, Rome, * Stockholm, Vienna */ + { + "W. Mongolia Standard Time", "W. Mongolia Daylight Time", + "Asia/Hovd" + }, /* (UTC+07:00) Hovd */ { "West Asia Standard Time", "West Asia Daylight Time", "Asia/Karachi" - }, /* (GMT+05:00) Islamabad, Karachi, Tashkent */ + }, /* (UTC+05:00) Ashgabat, Tashkent */ + { + "West Bank Gaza Standard Time", "West Bank Gaza Daylight Time", + "Asia/Gaza" + }, /* (UTC+02:00) Gaza, Hebron */ { "West Pacific Standard Time", "West Pacific Daylight Time", "Pacific/Guam" - }, /* (GMT+10:00) Guam, Port Moresby */ + }, /* (UTC+10:00) Guam, Port Moresby */ { "Yakutsk Standard Time", "Yakutsk Daylight Time", "Asia/Yakutsk" - }, /* (GMT+09:00) Yakutsk */ + }, /* (UTC+09:00) Yakutsk */ { NULL, NULL, NULL } diff --git a/src/bin/initdb/po/de.po b/src/bin/initdb/po/de.po index 888ddc6066..51245b5180 100644 --- a/src/bin/initdb/po/de.po +++ b/src/bin/initdb/po/de.po @@ -1,7 +1,7 @@ # German message translation file for initdb. # Peter Eisentraut , 2003 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -24,27 +24,27 @@ msgstr "konnte aktuelles Verzeichnis nicht ermitteln: %s" #: ../../common/exec.c:146 #, c-format msgid "invalid binary \"%s\"" -msgstr "ungültige Programmdatei „%s“" +msgstr "ungültige Programmdatei »%s«" #: ../../common/exec.c:195 #, c-format msgid "could not read binary \"%s\"" -msgstr "konnte Programmdatei „%s“ nicht lesen" +msgstr "konnte Programmdatei »%s« nicht lesen" #: ../../common/exec.c:202 #, c-format msgid "could not find a \"%s\" to execute" -msgstr "konnte kein „%s“ zum Ausführen finden" +msgstr "konnte kein »%s« zum Ausführen finden" #: ../../common/exec.c:257 ../../common/exec.c:293 #, c-format msgid "could not change directory to \"%s\": %s" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %s" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %s" #: ../../common/exec.c:272 #, c-format msgid "could not read symbolic link \"%s\"" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen" #: ../../common/exec.c:523 #, c-format @@ -65,17 +65,17 @@ msgstr "kann NULL-Zeiger nicht kopieren (interner Fehler)\n" #: ../../common/pgfnames.c:45 #, c-format msgid "could not open directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht öffnen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht öffnen: %s\n" #: ../../common/pgfnames.c:72 #, c-format msgid "could not read directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht lesen: %s\n" #: ../../common/pgfnames.c:84 #, c-format msgid "could not close directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht schließen: %s\n" #: ../../common/restricted_token.c:68 #, c-format @@ -100,7 +100,7 @@ msgstr "%s: konnte beschränktes Token nicht erzeugen: Fehlercode %lu\n" #: ../../common/restricted_token.c:132 #, c-format msgid "%s: could not start process for command \"%s\": error code %lu\n" -msgstr "%s: konnte Prozess für Befehl „%s“ nicht starten: Fehlercode %lu\n" +msgstr "%s: konnte Prozess für Befehl »%s« nicht starten: Fehlercode %lu\n" #: ../../common/restricted_token.c:170 #, c-format @@ -115,12 +115,12 @@ msgstr "%s: konnte Statuscode des Subprozesses nicht ermitteln: Fehlercode %lu\n #: ../../common/rmtree.c:77 #, c-format msgid "could not stat file or directory \"%s\": %s\n" -msgstr "konnte „stat“ für Datei oder Verzeichnis „%s“ nicht ausführen: %s\n" +msgstr "konnte »stat« für Datei oder Verzeichnis »%s« nicht ausführen: %s\n" #: ../../common/rmtree.c:104 ../../common/rmtree.c:121 #, c-format msgid "could not remove file or directory \"%s\": %s\n" -msgstr "konnte Datei oder Verzeichnis „%s“ nicht entfernen: %s\n" +msgstr "konnte Datei oder Verzeichnis »%s« nicht entfernen: %s\n" #: ../../common/username.c:45 #, c-format @@ -174,12 +174,12 @@ msgstr "Kindprozess hat mit unbekanntem Status %d beendet" #: ../../port/dirmod.c:219 #, c-format msgid "could not set junction for \"%s\": %s\n" -msgstr "konnte Junction für „%s“ nicht erzeugen: %s\n" +msgstr "konnte Junction für »%s« nicht erzeugen: %s\n" #: ../../port/dirmod.c:294 #, c-format msgid "could not get junction for \"%s\": %s\n" -msgstr "konnte Junction für „%s“ nicht ermitteln: %s\n" +msgstr "konnte Junction für »%s« nicht ermitteln: %s\n" #: initdb.c:329 #, c-format @@ -189,57 +189,57 @@ msgstr "%s: Speicher aufgebraucht\n" #: initdb.c:439 initdb.c:1651 #, c-format msgid "%s: could not open file \"%s\" for reading: %s\n" -msgstr "%s: konnte Datei „%s“ nicht zum Lesen öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht zum Lesen öffnen: %s\n" #: initdb.c:495 initdb.c:1047 initdb.c:1075 #, c-format msgid "%s: could not open file \"%s\" for writing: %s\n" -msgstr "%s: konnte Datei „%s“ nicht zum Schreiben öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht zum Schreiben öffnen: %s\n" #: initdb.c:503 initdb.c:511 initdb.c:1054 initdb.c:1081 #, c-format msgid "%s: could not write file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht schreiben: %s\n" +msgstr "%s: konnte Datei »%s« nicht schreiben: %s\n" #: initdb.c:533 initdb.c:600 #, c-format msgid "%s: could not open directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht öffnen: %s\n" #: initdb.c:550 #, c-format msgid "%s: could not stat file \"%s\": %s\n" -msgstr "%s: konnte „stat“ für Datei „%s“ nicht ausführen: %s\n" +msgstr "%s: konnte »stat« für Datei »%s« nicht ausführen: %s\n" #: initdb.c:563 initdb.c:620 #, c-format msgid "%s: could not read directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht lesen: %s\n" #: initdb.c:570 initdb.c:627 #, c-format msgid "%s: could not close directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht schließen: %s\n" #: initdb.c:654 initdb.c:706 #, c-format msgid "%s: could not open file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht öffnen: %s\n" #: initdb.c:722 #, c-format msgid "%s: could not fsync file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht fsyncen: %s\n" +msgstr "%s: konnte Datei »%s« nicht fsyncen: %s\n" #: initdb.c:743 #, c-format msgid "%s: could not execute command \"%s\": %s\n" -msgstr "%s: konnte Befehl „%s“ nicht ausführen: %s\n" +msgstr "%s: konnte Befehl »%s« nicht ausführen: %s\n" #: initdb.c:759 #, c-format msgid "%s: removing data directory \"%s\"\n" -msgstr "%s: entferne Datenverzeichnis „%s“\n" +msgstr "%s: entferne Datenverzeichnis »%s«\n" #: initdb.c:762 #, c-format @@ -249,7 +249,7 @@ msgstr "%s: konnte Datenverzeichnis nicht entfernen\n" #: initdb.c:768 #, c-format msgid "%s: removing contents of data directory \"%s\"\n" -msgstr "%s: entferne Inhalt des Datenverzeichnisses „%s“\n" +msgstr "%s: entferne Inhalt des Datenverzeichnisses »%s«\n" #: initdb.c:771 #, c-format @@ -259,7 +259,7 @@ msgstr "%s: konnte Inhalt des Datenverzeichnisses nicht entfernen\n" #: initdb.c:777 #, c-format msgid "%s: removing transaction log directory \"%s\"\n" -msgstr "%s: entferne Transaktionslogverzeichnis „%s“\n" +msgstr "%s: entferne Transaktionslogverzeichnis »%s«\n" #: initdb.c:780 #, c-format @@ -269,7 +269,7 @@ msgstr "%s: konnte Transaktionslogverzeichnis nicht entfernen\n" #: initdb.c:786 #, c-format msgid "%s: removing contents of transaction log directory \"%s\"\n" -msgstr "%s: entferne Inhalt des Transaktionslogverzeichnisses „%s“\n" +msgstr "%s: entferne Inhalt des Transaktionslogverzeichnisses »%s«\n" #: initdb.c:789 #, c-format @@ -279,12 +279,12 @@ msgstr "%s: konnte Inhalt des Transaktionslogverzeichnisses nicht entfernen\n" #: initdb.c:798 #, c-format msgid "%s: data directory \"%s\" not removed at user's request\n" -msgstr "%s: Datenverzeichnis „%s“ wurde auf Anwenderwunsch nicht entfernt\n" +msgstr "%s: Datenverzeichnis »%s« wurde auf Anwenderwunsch nicht entfernt\n" #: initdb.c:803 #, c-format msgid "%s: transaction log directory \"%s\" not removed at user's request\n" -msgstr "%s: Transaktionslogverzeichnis „%s“ wurde auf Anwenderwunsch nicht entfernt\n" +msgstr "%s: Transaktionslogverzeichnis »%s« wurde auf Anwenderwunsch nicht entfernt\n" #: initdb.c:824 #, c-format @@ -294,23 +294,23 @@ msgid "" "own the server process.\n" msgstr "" "%s: kann nicht als root ausgeführt werden\n" -"Bitte loggen Sie sich (z.B. mit „su“) als der (unprivilegierte) Benutzer\n" +"Bitte loggen Sie sich (z.B. mit »su«) als der (unprivilegierte) Benutzer\n" "ein, der Eigentümer des Serverprozesses sein soll.\n" #: initdb.c:860 #, c-format msgid "%s: \"%s\" is not a valid server encoding name\n" -msgstr "%s: „%s“ ist keine gültige Serverkodierung\n" +msgstr "%s: »%s« ist keine gültige Serverkodierung\n" #: initdb.c:974 initdb.c:3225 #, c-format msgid "%s: could not create directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht erzeugen: %s\n" #: initdb.c:1003 #, c-format msgid "%s: file \"%s\" does not exist\n" -msgstr "%s: Datei „%s“ existiert nicht\n" +msgstr "%s: Datei »%s« existiert nicht\n" #: initdb.c:1005 initdb.c:1014 initdb.c:1024 #, c-format @@ -324,12 +324,12 @@ msgstr "" #: initdb.c:1011 #, c-format msgid "%s: could not access file \"%s\": %s\n" -msgstr "%s: konnte nicht auf Datei „%s“ zugreifen: %s\n" +msgstr "%s: konnte nicht auf Datei »%s« zugreifen: %s\n" #: initdb.c:1022 #, c-format msgid "%s: file \"%s\" is not a regular file\n" -msgstr "%s: Datei „%s“ ist keine normale Datei\n" +msgstr "%s: Datei »%s« ist keine normale Datei\n" #: initdb.c:1167 #, c-format @@ -353,7 +353,7 @@ msgstr "erzeuge Konfigurationsdateien ... " #: initdb.c:1345 initdb.c:1365 initdb.c:1449 initdb.c:1465 #, c-format msgid "%s: could not change permissions of \"%s\": %s\n" -msgstr "%s: konnte Zugriffsrechte von „%s“ nicht ändern: %s\n" +msgstr "%s: konnte Zugriffsrechte von »%s« nicht ändern: %s\n" #: initdb.c:1489 #, c-format @@ -366,7 +366,7 @@ msgid "" "%s: input file \"%s\" does not belong to PostgreSQL %s\n" "Check your installation or specify the correct path using the option -L.\n" msgstr "" -"%s: Eingabedatei „%s“ gehört nicht zu PostgreSQL %s\n" +"%s: Eingabedatei »%s« gehört nicht zu PostgreSQL %s\n" "Prüfen Sie Ihre Installation oder geben Sie den korrekten Pfad mit der\n" "Option -L an.\n" @@ -390,12 +390,12 @@ msgstr "Passwörter stimmten nicht überein.\n" #: initdb.c:1658 #, c-format msgid "%s: could not read password from file \"%s\": %s\n" -msgstr "%s: konnte Passwort nicht aus Datei „%s“ lesen: %s\n" +msgstr "%s: konnte Passwort nicht aus Datei »%s« lesen: %s\n" #: initdb.c:1661 #, c-format msgid "%s: password file \"%s\" is empty\n" -msgstr "%s: Passwortdatei „%s“ ist leer\n" +msgstr "%s: Passwortdatei »%s« ist leer\n" #: initdb.c:1674 #, c-format @@ -421,12 +421,12 @@ msgstr "erzeuge Sortierfolgen ... " #: initdb.c:1977 #, c-format msgid "%s: locale name too long, skipped: \"%s\"\n" -msgstr "%s: Locale-Name zu lang, wird ausgelassen: „%s“\n" +msgstr "%s: Locale-Name zu lang, wird ausgelassen: »%s«\n" #: initdb.c:2002 #, c-format msgid "%s: locale name has non-ASCII characters, skipped: \"%s\"\n" -msgstr "%s: Locale-Name hat Nicht-ASCII-Zeichen, wird ausgelassen: „%s“\n" +msgstr "%s: Locale-Name hat Nicht-ASCII-Zeichen, wird ausgelassen: »%s«\n" #: initdb.c:2071 #, c-format @@ -436,7 +436,7 @@ msgstr "Es wurden keine brauchbaren System-Locales gefunden.\n" #: initdb.c:2072 #, c-format msgid "Use the option \"--debug\" to see details.\n" -msgstr "Verwenden Sie die Option „--debug“, um Einzelheiten zu sehen.\n" +msgstr "Verwenden Sie die Option »--debug«, um Einzelheiten zu sehen.\n" #: initdb.c:2075 #, c-format @@ -502,12 +502,12 @@ msgstr "%s: setlocale() fehlgeschlagen\n" #: initdb.c:2631 #, c-format msgid "%s: failed to restore old locale \"%s\"\n" -msgstr "%s: konnte alte Locale „%s“ nicht wiederherstellen\n" +msgstr "%s: konnte alte Locale »%s« nicht wiederherstellen\n" #: initdb.c:2641 #, c-format msgid "%s: invalid locale name \"%s\"\n" -msgstr "%s: ungültiger Locale-Name „%s“\n" +msgstr "%s: ungültiger Locale-Name »%s«\n" #: initdb.c:2653 #, c-format @@ -737,7 +737,7 @@ msgid "" "--auth-local and --auth-host, the next time you run initdb.\n" msgstr "" "\n" -"WARNUNG: Authentifizierung für lokale Verbindungen auf „trust“ gesetzt\n" +"WARNUNG: Authentifizierung für lokale Verbindungen auf »trust« gesetzt\n" "Sie können dies ändern, indem Sie pg_hba.conf bearbeiten oder beim\n" "nächsten Aufruf von initdb die Option -A, oder --auth-local und\n" "--auth-host, verwenden.\n" @@ -745,7 +745,7 @@ msgstr "" #: initdb.c:2819 #, c-format msgid "%s: invalid authentication method \"%s\" for \"%s\" connections\n" -msgstr "%s: ungültige Authentifizierungsmethode „%s“ für „%s“-Verbindungen\n" +msgstr "%s: ungültige Authentifizierungsmethode »%s« für »%s«-Verbindungen\n" #: initdb.c:2833 #, c-format @@ -772,8 +772,8 @@ msgid "" "same directory as \"%s\".\n" "Check your installation.\n" msgstr "" -"Das Programm „postgres“ wird von %s benötigt, aber wurde nicht im\n" -"selben Verzeichnis wie „%s“ gefunden.\n" +"Das Programm »postgres« wird von %s benötigt, aber wurde nicht im\n" +"selben Verzeichnis wie »%s« gefunden.\n" "Prüfen Sie Ihre Installation.\n" #: initdb.c:2905 @@ -783,7 +783,7 @@ msgid "" "but was not the same version as %s.\n" "Check your installation.\n" msgstr "" -"Das Programm „postgres“ wurde von %s gefunden,\n" +"Das Programm »postgres« wurde von %s gefunden,\n" "aber es hatte nicht die gleiche Version wie %s.\n" "Prüfen Sie Ihre Installation.\n" @@ -795,7 +795,7 @@ msgstr "%s: Eingabedatei muss absoluten Pfad haben\n" #: initdb.c:2943 #, c-format msgid "The database cluster will be initialized with locale \"%s\".\n" -msgstr "Der Datenbankcluster wird mit der Locale „%s“ initialisiert werden.\n" +msgstr "Der Datenbankcluster wird mit der Locale »%s« initialisiert werden.\n" #: initdb.c:2946 #, c-format @@ -819,7 +819,7 @@ msgstr "" #: initdb.c:2970 #, c-format msgid "%s: could not find suitable encoding for locale \"%s\"\n" -msgstr "%s: konnte keine passende Kodierung für Locale „%s“ finden\n" +msgstr "%s: konnte keine passende Kodierung für Locale »%s« finden\n" #: initdb.c:2972 #, c-format @@ -829,7 +829,7 @@ msgstr "Führen Sie %s erneut mit der Option -E aus.\n" #: initdb.c:2973 initdb.c:3549 initdb.c:3570 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: initdb.c:2985 #, c-format @@ -837,13 +837,13 @@ msgid "" "Encoding \"%s\" implied by locale is not allowed as a server-side encoding.\n" "The default database encoding will be set to \"%s\" instead.\n" msgstr "" -"Die von der Locale gesetzte Kodierung „%s“ ist nicht als serverseitige Kodierung erlaubt.\n" -"Die Standarddatenbankkodierung wird stattdessen auf „%s“ gesetzt.\n" +"Die von der Locale gesetzte Kodierung »%s« ist nicht als serverseitige Kodierung erlaubt.\n" +"Die Standarddatenbankkodierung wird stattdessen auf »%s« gesetzt.\n" #: initdb.c:2993 #, c-format msgid "%s: locale \"%s\" requires unsupported encoding \"%s\"\n" -msgstr "%s: Locale „%s“ benötigt nicht unterstützte Kodierung „%s“\n" +msgstr "%s: Locale »%s« benötigt nicht unterstützte Kodierung »%s«\n" #: initdb.c:2996 #, c-format @@ -851,33 +851,33 @@ msgid "" "Encoding \"%s\" is not allowed as a server-side encoding.\n" "Rerun %s with a different locale selection.\n" msgstr "" -"Kodierung „%s“ ist nicht als serverseitige Kodierung erlaubt.\n" +"Kodierung »%s« ist nicht als serverseitige Kodierung erlaubt.\n" "Starten Sie %s erneut mit einer anderen Locale-Wahl.\n" #: initdb.c:3005 #, c-format msgid "The default database encoding has accordingly been set to \"%s\".\n" -msgstr "Die Standarddatenbankkodierung wurde entsprechend auf „%s“ gesetzt.\n" +msgstr "Die Standarddatenbankkodierung wurde entsprechend auf »%s« gesetzt.\n" #: initdb.c:3076 #, c-format msgid "%s: could not find suitable text search configuration for locale \"%s\"\n" -msgstr "%s: konnte keine passende Textsuchekonfiguration für Locale „%s“ finden\n" +msgstr "%s: konnte keine passende Textsuchekonfiguration für Locale »%s« finden\n" #: initdb.c:3087 #, c-format msgid "%s: warning: suitable text search configuration for locale \"%s\" is unknown\n" -msgstr "%s: Warnung: passende Textsuchekonfiguration für Locale „%s“ ist unbekannt\n" +msgstr "%s: Warnung: passende Textsuchekonfiguration für Locale »%s« ist unbekannt\n" #: initdb.c:3092 #, c-format msgid "%s: warning: specified text search configuration \"%s\" might not match locale \"%s\"\n" -msgstr "%s: Warnung: angegebene Textsuchekonfiguration „%s“ passt möglicherweise nicht zur Locale „%s“\n" +msgstr "%s: Warnung: angegebene Textsuchekonfiguration »%s« passt möglicherweise nicht zur Locale »%s«\n" #: initdb.c:3097 #, c-format msgid "The default text search configuration will be set to \"%s\".\n" -msgstr "Die Standardtextsuchekonfiguration wird auf „%s“ gesetzt.\n" +msgstr "Die Standardtextsuchekonfiguration wird auf »%s« gesetzt.\n" #: initdb.c:3141 initdb.c:3219 #, c-format @@ -892,12 +892,12 @@ msgstr "berichtige Zugriffsrechte des bestehenden Verzeichnisses %s ... " #: initdb.c:3161 initdb.c:3243 #, c-format msgid "%s: could not change permissions of directory \"%s\": %s\n" -msgstr "%s: konnte Rechte des Verzeichnisses „%s“ nicht ändern: %s\n" +msgstr "%s: konnte Rechte des Verzeichnisses »%s« nicht ändern: %s\n" #: initdb.c:3176 initdb.c:3258 #, c-format msgid "%s: directory \"%s\" exists but is not empty\n" -msgstr "%s: Verzeichnis „%s“ existiert aber ist nicht leer\n" +msgstr "%s: Verzeichnis »%s« existiert aber ist nicht leer\n" #: initdb.c:3182 #, c-format @@ -907,13 +907,13 @@ msgid "" "with an argument other than \"%s\".\n" msgstr "" "Wenn Sie ein neues Datenbanksystem erzeugen wollen, entfernen oder leeren\n" -"Sie das Verzeichnis „%s“ or führen Sie %s\n" -"mit einem anderen Argument als „%s“ aus.\n" +"Sie das Verzeichnis »%s« or führen Sie %s\n" +"mit einem anderen Argument als »%s« aus.\n" #: initdb.c:3190 initdb.c:3271 #, c-format msgid "%s: could not access directory \"%s\": %s\n" -msgstr "%s: konnte nicht auf Verzeichnis „%s“ zugreifen: %s\n" +msgstr "%s: konnte nicht auf Verzeichnis »%s« zugreifen: %s\n" #: initdb.c:3210 #, c-format @@ -927,12 +927,12 @@ msgid "" "remove or empty the directory \"%s\".\n" msgstr "" "Wenn Sie dort den Transaktionslog ablegen wollen, entfernen oder leeren\n" -"Sie das Verzeichnis „%s“.\n" +"Sie das Verzeichnis »%s«.\n" #: initdb.c:3282 #, c-format msgid "%s: could not create symbolic link \"%s\": %s\n" -msgstr "%s: konnte symbolische Verknüpfung „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte symbolische Verknüpfung »%s« nicht erzeugen: %s\n" #: initdb.c:3287 #, c-format @@ -947,7 +947,7 @@ msgstr "Es enthält eine unsichtbare Datei (beginnt mit Punkt), vielleicht weil #: initdb.c:3303 #, c-format msgid "It contains a lost+found directory, perhaps due to it being a mount point.\n" -msgstr "Es enthält ein Verzeichnis „lost+found“, vielleicht weil es ein Einhängepunkt ist.\n" +msgstr "Es enthält ein Verzeichnis »lost+found«, vielleicht weil es ein Einhängepunkt ist.\n" #: initdb.c:3306 #, c-format @@ -976,7 +976,7 @@ msgstr "Noclean-Modus ist an. Bei Fehlern wird nicht aufgeräumt.\n" #: initdb.c:3568 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: initdb.c:3585 #, c-format @@ -991,7 +991,7 @@ msgid "" "\n" msgstr "" "Die Dateien, die zu diesem Datenbanksystem gehören, werden dem Benutzer\n" -"„%s“ gehören. Diesem Benutzer muss auch der Serverprozess gehören.\n" +"»%s« gehören. Diesem Benutzer muss auch der Serverprozess gehören.\n" "\n" #: initdb.c:3623 diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 309f7f4568..7234c49c37 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -20,7 +20,9 @@ #include #include #include - +#ifdef HAVE_SYS_SELECT_H +#include +#endif #ifdef HAVE_LIBZ #include #endif @@ -2062,7 +2064,7 @@ main(int argc, char **argv) break; case 'Z': compresslevel = atoi(optarg); - if (compresslevel <= 0 || compresslevel > 9) + if (compresslevel < 0 || compresslevel > 9) { fprintf(stderr, _("%s: invalid compression level \"%s\"\n"), progname, optarg); diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c index 73625256ac..5907d607b0 100644 --- a/src/bin/pg_basebackup/pg_recvlogical.c +++ b/src/bin/pg_basebackup/pg_recvlogical.c @@ -15,6 +15,9 @@ #include #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* local includes */ #include "streamutil.h" diff --git a/src/bin/pg_basebackup/po/de.po b/src/bin/pg_basebackup/po/de.po index 5e5d56a38c..ab9e0bc6d5 100644 --- a/src/bin/pg_basebackup/po/de.po +++ b/src/bin/pg_basebackup/po/de.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the PostgreSQL package. # Peter Eisentraut , 2011 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -38,12 +38,12 @@ msgstr "%s: Verzeichnisname zu lang\n" #: pg_basebackup.c:164 #, c-format msgid "%s: multiple \"=\" signs in tablespace mapping\n" -msgstr "%s: mehrere „=“-Zeichen im Tablespace-Mapping\n" +msgstr "%s: mehrere »=«-Zeichen im Tablespace-Mapping\n" #: pg_basebackup.c:177 #, c-format msgid "%s: invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"\n" -msgstr "%s: ungültiges Tablespace-Mapping-Format „%s“, muss „ALTES_VERZ=NEUES_VERZ“ sein\n" +msgstr "%s: ungültiges Tablespace-Mapping-Format »%s«, muss »ALTES_VERZ=NEUES_VERZ« sein\n" #: pg_basebackup.c:190 #, c-format @@ -100,7 +100,7 @@ msgid "" " (in kB/s, or use suffix \"k\" or \"M\")\n" msgstr "" " -r, --max-rate=RATE maximale Transferrate für Übertragung des Datenver-\n" -" zeichnisses (in kB/s, oder Suffix „k“ oder „M“ abgeben)\n" +" zeichnisses (in kB/s, oder Suffix »k« oder »M« abgeben)\n" #: pg_basebackup.c:240 #, c-format @@ -182,7 +182,7 @@ msgstr " -P, --progress Fortschrittsinformationen zeigen\n" #: pg_basebackup.c:255 pg_receivexlog.c:76 pg_recvlogical.c:89 #, c-format msgid " -v, --verbose output verbose messages\n" -msgstr " -v, --verbose „Verbose“-Modus\n" +msgstr " -v, --verbose »Verbose«-Modus\n" #: pg_basebackup.c:256 pg_receivexlog.c:77 pg_recvlogical.c:90 #, c-format @@ -260,7 +260,7 @@ msgstr "%s: konnte nicht aus bereiter Pipe lesen: %s\n" #: streamutil.c:285 #, c-format msgid "%s: could not parse transaction log location \"%s\"\n" -msgstr "%s: konnte Transaktionslogposition „%s“ nicht interpretieren\n" +msgstr "%s: konnte Transaktionslogposition »%s« nicht interpretieren\n" #: pg_basebackup.c:424 #, c-format @@ -270,7 +270,7 @@ msgstr "%s: konnte Pipe für Hintergrundprozess nicht erzeugen: %s\n" #: pg_basebackup.c:449 pg_basebackup.c:504 pg_basebackup.c:1262 #, c-format msgid "%s: could not create directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht erzeugen: %s\n" #: pg_basebackup.c:467 #, c-format @@ -285,12 +285,12 @@ msgstr "%s: konnte Hintergrund-Thread nicht erzeugen: %s\n" #: pg_basebackup.c:523 #, c-format msgid "%s: directory \"%s\" exists but is not empty\n" -msgstr "%s: Verzeichnis „%s“ existiert aber ist nicht leer\n" +msgstr "%s: Verzeichnis »%s« existiert aber ist nicht leer\n" #: pg_basebackup.c:531 #, c-format msgid "%s: could not access directory \"%s\": %s\n" -msgstr "%s: konnte nicht auf Verzeichnis „%s“ zugreifen: %s\n" +msgstr "%s: konnte nicht auf Verzeichnis »%s« zugreifen: %s\n" #: pg_basebackup.c:593 #, c-format @@ -316,12 +316,12 @@ msgstr[1] "%*s/%s kB (%d%%), %d/%d Tablespaces" #: pg_basebackup.c:643 #, c-format msgid "%s: transfer rate \"%s\" is not a valid value\n" -msgstr "%s: Transferrate „%s“ ist kein gültiger Wert\n" +msgstr "%s: Transferrate »%s« ist kein gültiger Wert\n" #: pg_basebackup.c:650 #, c-format msgid "%s: invalid transfer rate \"%s\": %s\n" -msgstr "%s: ungültige Transferrate „%s“: %s\n" +msgstr "%s: ungültige Transferrate »%s«: %s\n" #: pg_basebackup.c:660 #, c-format @@ -331,27 +331,27 @@ msgstr "%s: Transferrate muss größer als null sein\n" #: pg_basebackup.c:694 #, c-format msgid "%s: invalid --max-rate unit: \"%s\"\n" -msgstr "%s: ungültige Einheit für --max-rate: „%s“\n" +msgstr "%s: ungültige Einheit für --max-rate: »%s«\n" #: pg_basebackup.c:703 #, c-format msgid "%s: transfer rate \"%s\" exceeds integer range\n" -msgstr "%s: Transferrate „%s“ überschreitet Bereich für ganze Zahlen\n" +msgstr "%s: Transferrate »%s« überschreitet Bereich für ganze Zahlen\n" #: pg_basebackup.c:715 #, c-format msgid "%s: transfer rate \"%s\" is out of range\n" -msgstr "%s: Transferrate „%s“ ist außerhalb des gültigen Bereichs\n" +msgstr "%s: Transferrate »%s« ist außerhalb des gültigen Bereichs\n" #: pg_basebackup.c:739 #, c-format msgid "%s: could not write to compressed file \"%s\": %s\n" -msgstr "%s: konnte nicht in komprimierte Datei „%s“ schreiben: %s\n" +msgstr "%s: konnte nicht in komprimierte Datei »%s« schreiben: %s\n" #: pg_basebackup.c:749 pg_basebackup.c:1356 pg_basebackup.c:1574 #, c-format msgid "%s: could not write to file \"%s\": %s\n" -msgstr "%s: konnte nicht in Datei „%s“ schreiben: %s\n" +msgstr "%s: konnte nicht in Datei »%s« schreiben: %s\n" #: pg_basebackup.c:804 pg_basebackup.c:825 pg_basebackup.c:853 #, c-format @@ -361,12 +361,12 @@ msgstr "%s: konnte Komprimierungsniveau %d nicht setzen: %s\n" #: pg_basebackup.c:874 #, c-format msgid "%s: could not create compressed file \"%s\": %s\n" -msgstr "%s: konnte komprimierte Datei „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte komprimierte Datei »%s« nicht erzeugen: %s\n" #: pg_basebackup.c:885 pg_basebackup.c:1316 pg_basebackup.c:1567 #, c-format msgid "%s: could not create file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte Datei »%s« nicht erzeugen: %s\n" #: pg_basebackup.c:897 pg_basebackup.c:1161 #, c-format @@ -376,13 +376,13 @@ msgstr "%s: konnte COPY-Datenstrom nicht empfangen: %s" #: pg_basebackup.c:954 #, c-format msgid "%s: could not close compressed file \"%s\": %s\n" -msgstr "%s: konnte komprimierte Datei „%s“ nicht schließen: %s\n" +msgstr "%s: konnte komprimierte Datei »%s« nicht schließen: %s\n" #: pg_basebackup.c:967 pg_recvlogical.c:569 receivelog.c:213 receivelog.c:362 #: receivelog.c:754 #, c-format msgid "%s: could not close file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht schließen: %s\n" +msgstr "%s: konnte Datei »%s« nicht schließen: %s\n" #: pg_basebackup.c:978 pg_basebackup.c:1190 pg_recvlogical.c:435 #: receivelog.c:1044 @@ -408,22 +408,22 @@ msgstr "%s: konnte Dateimodus nicht entziffern\n" #: pg_basebackup.c:1270 #, c-format msgid "%s: could not set permissions on directory \"%s\": %s\n" -msgstr "%s: konnte Zugriffsrechte des Verzeichnisses „%s“ nicht setzen: %s\n" +msgstr "%s: konnte Zugriffsrechte des Verzeichnisses »%s« nicht setzen: %s\n" #: pg_basebackup.c:1294 #, c-format msgid "%s: could not create symbolic link from \"%s\" to \"%s\": %s\n" -msgstr "%s: konnte symbolische Verknüpfung von „%s“ nach „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte symbolische Verknüpfung von »%s« nach »%s« nicht erzeugen: %s\n" #: pg_basebackup.c:1303 #, c-format msgid "%s: unrecognized link indicator \"%c\"\n" -msgstr "%s: unbekannter Verknüpfungsindikator „%c“\n" +msgstr "%s: unbekannter Verknüpfungsindikator »%c«\n" #: pg_basebackup.c:1323 #, c-format msgid "%s: could not set permissions on file \"%s\": %s\n" -msgstr "%s: konnte Rechte der Datei „%s“ nicht setzen: %s\n" +msgstr "%s: konnte Rechte der Datei »%s« nicht setzen: %s\n" #: pg_basebackup.c:1382 #, c-format @@ -445,7 +445,7 @@ msgstr "%s: inkompatible Serverversion %s\n" #: receivelog.c:641 streamutil.c:255 streamutil.c:353 streamutil.c:399 #, c-format msgid "%s: could not send replication command \"%s\": %s" -msgstr "%s: konnte Replikationsbefehl „%s“ nicht senden: %s" +msgstr "%s: konnte Replikationsbefehl »%s« nicht senden: %s" #: pg_basebackup.c:1677 #, c-format @@ -545,7 +545,7 @@ msgstr "%s: Kind-Thread hat mit Fehler %u beendet\n" #: pg_basebackup.c:1993 #, c-format msgid "%s: invalid output format \"%s\", must be \"plain\" or \"tar\"\n" -msgstr "%s: ungültiges Ausgabeformat „%s“, muss „plain“ oder „tar“ sein\n" +msgstr "%s: ungültiges Ausgabeformat »%s«, muss »plain« oder »tar« sein\n" #: pg_basebackup.c:2011 pg_basebackup.c:2023 #, c-format @@ -555,22 +555,22 @@ msgstr "%s: --xlog und --xlog-method können nicht zusammen verwendet werden\n" #: pg_basebackup.c:2038 #, c-format msgid "%s: invalid xlog-method option \"%s\", must be \"fetch\" or \"stream\"\n" -msgstr "%s: ungültige Option „%s“ für --xlog-method, muss „fetch“ oder „stream“ sein\n" +msgstr "%s: ungültige Option »%s« für --xlog-method, muss »fetch« oder »stream« sein\n" #: pg_basebackup.c:2060 #, c-format msgid "%s: invalid compression level \"%s\"\n" -msgstr "%s: ungültiges Komprimierungsniveau „%s“\n" +msgstr "%s: ungültiges Komprimierungsniveau »%s«\n" #: pg_basebackup.c:2072 #, c-format msgid "%s: invalid checkpoint argument \"%s\", must be \"fast\" or \"spread\"\n" -msgstr "%s: ungültiges Checkpoint-Argument „%s“, muss „fast“ oder „spread“ sein\n" +msgstr "%s: ungültiges Checkpoint-Argument »%s«, muss »fast« oder »spread« sein\n" #: pg_basebackup.c:2099 pg_receivexlog.c:439 pg_recvlogical.c:752 #, c-format msgid "%s: invalid status interval \"%s\"\n" -msgstr "%s: ungültiges Statusintervall „%s“\n" +msgstr "%s: ungültiges Statusintervall »%s«\n" #: pg_basebackup.c:2115 pg_basebackup.c:2129 pg_basebackup.c:2140 #: pg_basebackup.c:2153 pg_basebackup.c:2163 pg_basebackup.c:2175 @@ -581,12 +581,12 @@ msgstr "%s: ungültiges Statusintervall „%s“\n" #: pg_recvlogical.c:836 pg_recvlogical.c:844 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: pg_basebackup.c:2127 pg_receivexlog.c:483 pg_recvlogical.c:791 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: pg_basebackup.c:2139 pg_receivexlog.c:513 #, c-format @@ -601,12 +601,12 @@ msgstr "%s: nur Sicherungen im Tar-Modus können komprimiert werden\n" #: pg_basebackup.c:2161 #, c-format msgid "%s: WAL streaming can only be used in plain mode\n" -msgstr "%s: WAL-Streaming kann nur im „plain“-Modus verwendet werden\n" +msgstr "%s: WAL-Streaming kann nur im »plain«-Modus verwendet werden\n" #: pg_basebackup.c:2173 #, c-format msgid "%s: transaction log directory location can only be specified in plain mode\n" -msgstr "%s: Transaktionslogverzeichnis kann nur im „plain“-Modus angegeben werden\n" +msgstr "%s: Transaktionslogverzeichnis kann nur im »plain«-Modus angegeben werden\n" #: pg_basebackup.c:2184 #, c-format @@ -621,7 +621,7 @@ msgstr "%s: diese Installation unterstützt keine Komprimierung\n" #: pg_basebackup.c:2223 #, c-format msgid "%s: could not create symbolic link \"%s\": %s\n" -msgstr "%s: konnte symbolische Verknüpfung „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte symbolische Verknüpfung »%s« nicht erzeugen: %s\n" #: pg_basebackup.c:2228 #, c-format @@ -717,27 +717,27 @@ msgstr "%s: Interrupt-Signal erhalten, beende\n" #: pg_receivexlog.c:142 #, c-format msgid "%s: could not open directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht öffnen: %s\n" #: pg_receivexlog.c:160 #, c-format msgid "%s: could not close directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht schließen: %s\n" #: pg_receivexlog.c:218 pg_recvlogical.c:343 #, c-format msgid "%s: could not stat file \"%s\": %s\n" -msgstr "%s: konnte „stat“ für Datei „%s“ nicht ausführen: %s\n" +msgstr "%s: konnte »stat« für Datei »%s« nicht ausführen: %s\n" #: pg_receivexlog.c:226 #, c-format msgid "%s: segment file \"%s\" has incorrect size %d, skipping\n" -msgstr "%s: Segmentdatei „%s“ hat falsche Größe %d, wird übersprungen\n" +msgstr "%s: Segmentdatei »%s« hat falsche Größe %d, wird übersprungen\n" #: pg_receivexlog.c:245 #, c-format msgid "%s: could not read directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht lesen: %s\n" #: pg_receivexlog.c:331 #, c-format @@ -747,7 +747,7 @@ msgstr "%s: starte Log-Streaming bei %X/%X (Zeitleiste %u)\n" #: pg_receivexlog.c:420 pg_recvlogical.c:699 #, c-format msgid "%s: invalid port number \"%s\"\n" -msgstr "%s: ungültige Portnummer „%s“\n" +msgstr "%s: ungültige Portnummer »%s«\n" #: pg_receivexlog.c:492 #, c-format @@ -763,17 +763,17 @@ msgstr "%s: für %s muss ein Slot mit --slot angegeben werden\n" #: pg_receivexlog.c:556 #, c-format msgid "%s: replication connection using slot \"%s\" is unexpectedly database specific\n" -msgstr "%s: Replikationsverbindung, die Slot „%s“ verwendet, ist unerwarteterweise datenbankspezifisch\n" +msgstr "%s: Replikationsverbindung, die Slot »%s« verwendet, ist unerwarteterweise datenbankspezifisch\n" #: pg_receivexlog.c:568 pg_recvlogical.c:884 #, c-format msgid "%s: dropping replication slot \"%s\"\n" -msgstr "%s: lösche Replikations-Slot „%s“\n" +msgstr "%s: lösche Replikations-Slot »%s«\n" #: pg_receivexlog.c:581 pg_recvlogical.c:896 #, c-format msgid "%s: creating replication slot \"%s\"\n" -msgstr "%s: erzeuge Replikations-Slot „%s“\n" +msgstr "%s: erzeuge Replikations-Slot »%s«\n" #: pg_receivexlog.c:608 pg_recvlogical.c:922 #, c-format @@ -867,7 +867,7 @@ msgstr "%s: konnte Rückmeldungspaket nicht senden: %s" #: pg_recvlogical.c:190 #, c-format msgid "%s: could not fsync log file \"%s\": %s\n" -msgstr "%s: konnte Logdatei „%s“ nicht fsyncen: %s\n" +msgstr "%s: konnte Logdatei »%s« nicht fsyncen: %s\n" #: pg_recvlogical.c:229 #, c-format @@ -882,7 +882,7 @@ msgstr "%s: Streaming eingeleitet\n" #: pg_recvlogical.c:336 #, c-format msgid "%s: could not open log file \"%s\": %s\n" -msgstr "%s: konnte Logdatei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Logdatei »%s« nicht öffnen: %s\n" #: pg_recvlogical.c:412 receivelog.c:980 #, c-format @@ -903,12 +903,12 @@ msgstr "%s: Streaming-Header zu klein: %d\n" #: pg_recvlogical.c:484 receivelog.c:924 #, c-format msgid "%s: unrecognized streaming header: \"%c\"\n" -msgstr "%s: unbekannter Streaming-Header: „%c“\n" +msgstr "%s: unbekannter Streaming-Header: »%c«\n" #: pg_recvlogical.c:530 pg_recvlogical.c:544 #, c-format msgid "%s: could not write %u bytes to log file \"%s\": %s\n" -msgstr "%s: konnte %u Bytes nicht in Logdatei „%s“ schreiben: %s\n" +msgstr "%s: konnte %u Bytes nicht in Logdatei »%s« schreiben: %s\n" #: pg_recvlogical.c:555 receivelog.c:707 receivelog.c:745 #, c-format @@ -918,12 +918,12 @@ msgstr "%s: unerwarteter Abbruch des Replikations-Streams: %s" #: pg_recvlogical.c:678 #, c-format msgid "%s: invalid fsync interval \"%s\"\n" -msgstr "%s: ungültiges Fsync-Intervall „%s“\n" +msgstr "%s: ungültiges Fsync-Intervall »%s«\n" #: pg_recvlogical.c:719 #, c-format msgid "%s: could not parse start position \"%s\"\n" -msgstr "%s: konnte Startposition „%s“ nicht parsen\n" +msgstr "%s: konnte Startposition »%s« nicht parsen\n" #: pg_recvlogical.c:803 #, c-format @@ -963,58 +963,58 @@ msgstr "%s: konnte keine datenbankspezifische Replikationsverbindung herstellen\ #: receivelog.c:75 #, c-format msgid "%s: could not create archive status file \"%s\": %s\n" -msgstr "%s: konnte Archivstatusdatei „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte Archivstatusdatei »%s« nicht erzeugen: %s\n" #: receivelog.c:82 receivelog.c:206 receivelog.c:355 receivelog.c:848 #: receivelog.c:1096 #, c-format msgid "%s: could not fsync file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht fsyncen: %s\n" +msgstr "%s: konnte Datei »%s« nicht fsyncen: %s\n" #: receivelog.c:121 #, c-format msgid "%s: could not open transaction log file \"%s\": %s\n" -msgstr "%s: konnte Transaktionslogdatei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Transaktionslogdatei »%s« nicht öffnen: %s\n" #: receivelog.c:133 #, c-format msgid "%s: could not stat transaction log file \"%s\": %s\n" -msgstr "%s: konnte „stat“ für Transaktionslogdatei „%s“ nicht ausführen: %s\n" +msgstr "%s: konnte »stat« für Transaktionslogdatei »%s« nicht ausführen: %s\n" #: receivelog.c:147 #, c-format msgid "%s: transaction log file \"%s\" has %d bytes, should be 0 or %d\n" -msgstr "%s: Transaktionslogdatei „%s“ hat %d Bytes, sollte 0 oder %d sein\n" +msgstr "%s: Transaktionslogdatei »%s« hat %d Bytes, sollte 0 oder %d sein\n" #: receivelog.c:160 #, c-format msgid "%s: could not pad transaction log file \"%s\": %s\n" -msgstr "%s: konnte Transaktionslogdatei „%s“ nicht auffüllen: %s\n" +msgstr "%s: konnte Transaktionslogdatei »%s« nicht auffüllen: %s\n" #: receivelog.c:173 #, c-format msgid "%s: could not seek to beginning of transaction log file \"%s\": %s\n" -msgstr "%s: konnte Positionszeiger nicht an den Anfang der Transaktionslogdatei „%s“ setzen: %s\n" +msgstr "%s: konnte Positionszeiger nicht an den Anfang der Transaktionslogdatei »%s« setzen: %s\n" #: receivelog.c:199 #, c-format msgid "%s: could not determine seek position in file \"%s\": %s\n" -msgstr "%s: konnte Positionszeiger in Datei „%s“ nicht ermitteln: %s\n" +msgstr "%s: konnte Positionszeiger in Datei »%s« nicht ermitteln: %s\n" #: receivelog.c:232 #, c-format msgid "%s: could not rename file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht umbenennen: %s\n" +msgstr "%s: konnte Datei »%s« nicht umbenennen: %s\n" #: receivelog.c:239 #, c-format msgid "%s: not renaming \"%s%s\", segment is not complete\n" -msgstr "%s: „%s%s“ wird nicht umbenannt, Segment ist noch nicht vollständig\n" +msgstr "%s: »%s%s« wird nicht umbenannt, Segment ist noch nicht vollständig\n" #: receivelog.c:285 #, c-format msgid "%s: could not open timeline history file \"%s\": %s\n" -msgstr "%s: konnte Zeitleisten-History-Datei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Zeitleisten-History-Datei »%s« nicht öffnen: %s\n" #: receivelog.c:313 #, c-format @@ -1024,17 +1024,17 @@ msgstr "%s: Server berichtete unerwarteten History-Dateinamen für Zeitleiste %u #: receivelog.c:330 #, c-format msgid "%s: could not create timeline history file \"%s\": %s\n" -msgstr "%s: konnte Zeitleisten-History-Datei „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte Zeitleisten-History-Datei »%s« nicht erzeugen: %s\n" #: receivelog.c:347 #, c-format msgid "%s: could not write timeline history file \"%s\": %s\n" -msgstr "%s: konnte Zeitleisten-History-Datei „%s“ nicht schreiben: %s\n" +msgstr "%s: konnte Zeitleisten-History-Datei »%s« nicht schreiben: %s\n" #: receivelog.c:372 #, c-format msgid "%s: could not rename file \"%s\" to \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht in „%s“ umbenennen: %s\n" +msgstr "%s: konnte Datei »%s« nicht in »%s« umbenennen: %s\n" #: receivelog.c:449 #, c-format @@ -1089,7 +1089,7 @@ msgstr "%s: unerwartete Ergebnismenge nach Ende der Zeitleiste: %d Zeilen und %d #: receivelog.c:795 #, c-format msgid "%s: could not parse next timeline's starting point \"%s\"\n" -msgstr "%s: konnte Startpunkt der nächsten Zeitleiste („%s“) nicht interpretieren\n" +msgstr "%s: konnte Startpunkt der nächsten Zeitleiste (»%s«) nicht interpretieren\n" #: receivelog.c:959 #, c-format @@ -1109,7 +1109,7 @@ msgstr "%s: WAL-Daten-Offset %08x erhalten, %08x erwartet\n" #: receivelog.c:1212 #, c-format msgid "%s: could not write %u bytes to WAL file \"%s\": %s\n" -msgstr "%s: konnte %u Bytes nicht in WAL-Datei „%s“ schreiben: %s\n" +msgstr "%s: konnte %u Bytes nicht in WAL-Datei »%s« schreiben: %s\n" #: receivelog.c:1237 receivelog.c:1279 receivelog.c:1311 #, c-format @@ -1138,14 +1138,14 @@ msgstr "%s: konnte Servereinstellung für integer_datetimes nicht ermitteln\n" #: streamutil.c:224 #, c-format msgid "%s: integer_datetimes compile flag does not match server\n" -msgstr "%s: Kompilieroption „integer_datetimes“ stimmt nicht mit Server überein\n" +msgstr "%s: Kompilieroption »integer_datetimes« stimmt nicht mit Server überein\n" #: streamutil.c:365 #, c-format msgid "%s: could not create replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields\n" -msgstr "%s: konnte Replikations-Slot „%s“ nicht erzeugen: %d Zeilen und %d Felder erhalten, %d Zeilen und %d Felder erwartet\n" +msgstr "%s: konnte Replikations-Slot »%s« nicht erzeugen: %d Zeilen und %d Felder erhalten, %d Zeilen und %d Felder erwartet\n" #: streamutil.c:410 #, c-format msgid "%s: could not drop replication slot \"%s\": got %d rows and %d fields, expected %d rows and %d fields\n" -msgstr "%s: konnte Replikations-Slot „%s“ nicht löschen: %d Zeilen und %d Felder erhalten, %d Zeilen und %d Felder erwartet\n" +msgstr "%s: konnte Replikations-Slot »%s« nicht löschen: %d Zeilen und %d Felder erhalten, %d Zeilen und %d Felder erwartet\n" diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c index 3c60626541..406c01bfcc 100644 --- a/src/bin/pg_basebackup/receivelog.c +++ b/src/bin/pg_basebackup/receivelog.c @@ -16,6 +16,9 @@ #include #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* local includes */ #include "receivelog.h" @@ -516,26 +519,28 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, if (!CheckServerVersionForStreaming(conn)) return false; + /* + * Decide whether we want to report the flush position. If we report + * the flush position, the primary will know what WAL we'll + * possibly re-request, and it can then remove older WAL safely. + * We must always do that when we are using slots. + * + * Reporting the flush position makes one eligible as a synchronous + * replica. People shouldn't include generic names in + * synchronous_standby_names, but we've protected them against it so + * far, so let's continue to do so unless specifically requested. + */ if (replication_slot != NULL) { - /* - * Report the flush position, so the primary can know what WAL we'll - * possibly re-request, and remove older WAL safely. - * - * We only report it when a slot has explicitly been used, because - * reporting the flush position makes one eligible as a synchronous - * replica. People shouldn't include generic names in - * synchronous_standby_names, but we've protected them against it so - * far, so let's continue to do so in the situations when possible. If - * they've got a slot, though, we need to report the flush position, - * so that the master can remove WAL. - */ reportFlushPosition = true; sprintf(slotcmd, "SLOT \"%s\" ", replication_slot); } else { - reportFlushPosition = false; + if (synchronous) + reportFlushPosition = true; + else + reportFlushPosition = false; slotcmd[0] = 0; } diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index 99828e5879..ac3eb48cd6 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -64,9 +64,15 @@ GetConnection(void) PQconninfoOption *conn_opt; char *err_msg = NULL; + /* pg_recvlogical uses dbname only; others use connection_string only. */ + Assert(dbname == NULL || connection_string == NULL); + /* * Merge the connection info inputs given in form of connection string, * options and default values (dbname=replication, replication=true, etc.) + * Explicitly discard any dbname value in the connection string; + * otherwise, PQconnectdbParams() would interpret that value as being + * itself a connection string. */ i = 0; if (connection_string) @@ -80,7 +86,8 @@ GetConnection(void) for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) { - if (conn_opt->val != NULL && conn_opt->val[0] != '\0') + if (conn_opt->val != NULL && conn_opt->val[0] != '\0' && + strcmp(conn_opt->keyword, "dbname") != 0) argcount++; } @@ -89,7 +96,8 @@ GetConnection(void) for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) { - if (conn_opt->val != NULL && conn_opt->val[0] != '\0') + if (conn_opt->val != NULL && conn_opt->val[0] != '\0' && + strcmp(conn_opt->keyword, "dbname") != 0) { keywords[i] = conn_opt->keyword; values[i] = conn_opt->val; diff --git a/src/bin/pg_config/po/de.po b/src/bin/pg_config/po/de.po index ebe3bb111c..7d1e64015e 100644 --- a/src/bin/pg_config/po/de.po +++ b/src/bin/pg_config/po/de.po @@ -1,7 +1,7 @@ # German message translation file for pg_config # Peter Eisentraut , 2004 - 2013. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -24,27 +24,27 @@ msgstr "konnte aktuelles Verzeichnis nicht ermitteln: %s" #: ../../port/exec.c:146 #, c-format msgid "invalid binary \"%s\"" -msgstr "ungültige Programmdatei „%s“" +msgstr "ungültige Programmdatei »%s«" #: ../../port/exec.c:195 #, c-format msgid "could not read binary \"%s\"" -msgstr "konnte Programmdatei „%s“ nicht lesen" +msgstr "konnte Programmdatei »%s« nicht lesen" #: ../../port/exec.c:202 #, c-format msgid "could not find a \"%s\" to execute" -msgstr "konnte kein „%s“ zum Ausführen finden" +msgstr "konnte kein »%s« zum Ausführen finden" #: ../../port/exec.c:257 ../../port/exec.c:293 #, c-format msgid "could not change directory to \"%s\": %s" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %s" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %s" #: ../../port/exec.c:272 #, c-format msgid "could not read symbolic link \"%s\"" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen" #: ../../port/exec.c:523 #, c-format @@ -171,7 +171,7 @@ msgid "" " --configure show options given to \"configure\" script when\n" " PostgreSQL was built\n" msgstr "" -" --configure zeige Optionen des „configure“-Skriptes beim Bauen\n" +" --configure zeige Optionen des »configure«-Skriptes beim Bauen\n" " von PostgreSQL\n" #: pg_config.c:448 @@ -243,7 +243,7 @@ msgstr "Berichten Sie Fehler an .\n" #: pg_config.c:465 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: pg_config.c:504 #, c-format diff --git a/src/bin/pg_controldata/po/de.po b/src/bin/pg_controldata/po/de.po index fe61851cc8..5f7e55af82 100644 --- a/src/bin/pg_controldata/po/de.po +++ b/src/bin/pg_controldata/po/de.po @@ -1,7 +1,7 @@ # German message translation file for pg_controldata # Peter Eisentraut , 2002 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -116,12 +116,12 @@ msgstr "unbekanntes wal_level" #: pg_controldata.c:134 pg_controldata.c:152 pg_controldata.c:160 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: pg_controldata.c:150 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: pg_controldata.c:159 #, c-format @@ -131,12 +131,12 @@ msgstr "%s: kein Datenverzeichnis angegeben\n" #: pg_controldata.c:168 #, c-format msgid "%s: could not open file \"%s\" for reading: %s\n" -msgstr "%s: konnte Datei „%s“ nicht zum Lesen öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht zum Lesen öffnen: %s\n" #: pg_controldata.c:175 #, c-format msgid "%s: could not read file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht lesen: %s\n" +msgstr "%s: konnte Datei »%s« nicht lesen: %s\n" #: pg_controldata.c:189 #, c-format diff --git a/src/bin/pg_ctl/po/de.po b/src/bin/pg_ctl/po/de.po index cff8dd78d1..079f903aa2 100644 --- a/src/bin/pg_ctl/po/de.po +++ b/src/bin/pg_ctl/po/de.po @@ -1,7 +1,7 @@ # German message translation file for pg_ctl # Peter Eisentraut , 2004 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -24,27 +24,27 @@ msgstr "konnte aktuelles Verzeichnis nicht ermitteln: %s" #: ../../common/exec.c:146 #, c-format msgid "invalid binary \"%s\"" -msgstr "ungültige Programmdatei „%s“" +msgstr "ungültige Programmdatei »%s«" #: ../../common/exec.c:195 #, c-format msgid "could not read binary \"%s\"" -msgstr "konnte Programmdatei „%s“ nicht lesen" +msgstr "konnte Programmdatei »%s« nicht lesen" #: ../../common/exec.c:202 #, c-format msgid "could not find a \"%s\" to execute" -msgstr "konnte kein „%s“ zum Ausführen finden" +msgstr "konnte kein »%s« zum Ausführen finden" #: ../../common/exec.c:257 ../../common/exec.c:293 #, c-format msgid "could not change directory to \"%s\": %s" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %s" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %s" #: ../../common/exec.c:272 #, c-format msgid "could not read symbolic link \"%s\"" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen" #: ../../common/exec.c:523 #, c-format @@ -106,32 +106,32 @@ msgstr "konnte aktuelles Arbeitsverzeichnis nicht ermitteln: %s\n" #: pg_ctl.c:258 #, c-format msgid "%s: directory \"%s\" does not exist\n" -msgstr "%s: Verzeichnis „%s“ existiert nicht\n" +msgstr "%s: Verzeichnis »%s« existiert nicht\n" #: pg_ctl.c:261 #, c-format msgid "%s: could not access directory \"%s\": %s\n" -msgstr "%s: konnte nicht auf Verzeichnis „%s“ zugreifen: %s\n" +msgstr "%s: konnte nicht auf Verzeichnis »%s« zugreifen: %s\n" #: pg_ctl.c:275 #, c-format msgid "%s: directory \"%s\" is not a database cluster directory\n" -msgstr "%s: Verzeichnis „%s“ ist kein Datenbankclusterverzeichnis\n" +msgstr "%s: Verzeichnis »%s« ist kein Datenbankclusterverzeichnis\n" #: pg_ctl.c:288 #, c-format msgid "%s: could not open PID file \"%s\": %s\n" -msgstr "%s: konnte PID-Datei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte PID-Datei »%s« nicht öffnen: %s\n" #: pg_ctl.c:297 #, c-format msgid "%s: the PID file \"%s\" is empty\n" -msgstr "%s: die PID-Datei „%s“ ist leer\n" +msgstr "%s: die PID-Datei »%s« ist leer\n" #: pg_ctl.c:300 #, c-format msgid "%s: invalid data in PID file \"%s\"\n" -msgstr "%s: ungültige Daten in PID-Datei „%s“\n" +msgstr "%s: ungültige Daten in PID-Datei »%s«\n" #: pg_ctl.c:450 pg_ctl.c:478 #, c-format @@ -169,12 +169,12 @@ msgstr "%s: kann Grenzwert für Core-Datei-Größe nicht setzen; durch harten Gr #: pg_ctl.c:760 #, c-format msgid "%s: could not read file \"%s\"\n" -msgstr "%s: konnte Datei „%s“ nicht lesen\n" +msgstr "%s: konnte Datei »%s« nicht lesen\n" #: pg_ctl.c:765 #, c-format msgid "%s: option file \"%s\" must have exactly one line\n" -msgstr "%s: Optionsdatei „%s“ muss genau eine Zeile haben\n" +msgstr "%s: Optionsdatei »%s« muss genau eine Zeile haben\n" #: pg_ctl.c:816 #, c-format @@ -183,8 +183,8 @@ msgid "" "same directory as \"%s\".\n" "Check your installation.\n" msgstr "" -"Das Programm „%s“ wird von %s benötigt, aber wurde nicht im\n" -"selben Verzeichnis wie „%s“ gefunden.\n" +"Das Programm »%s« wird von %s benötigt, aber wurde nicht im\n" +"selben Verzeichnis wie »%s« gefunden.\n" "Prüfen Sie Ihre Installation.\n" #: pg_ctl.c:822 @@ -194,7 +194,7 @@ msgid "" "but was not the same version as %s.\n" "Check your installation.\n" msgstr "" -"Das Programm „%s“ wurde von %s gefunden,\n" +"Das Programm »%s« wurde von %s gefunden,\n" "aber es hatte nicht die gleiche Version wie %s.\n" "Prüfen Sie Ihre Installation.\n" @@ -253,7 +253,7 @@ msgstr "Server startet\n" #: pg_ctl.c:956 pg_ctl.c:1042 pg_ctl.c:1132 pg_ctl.c:1172 #, c-format msgid "%s: PID file \"%s\" does not exist\n" -msgstr "%s: PID-Datei „%s“ existiert nicht\n" +msgstr "%s: PID-Datei »%s« existiert nicht\n" #: pg_ctl.c:957 pg_ctl.c:1044 pg_ctl.c:1133 pg_ctl.c:1173 msgid "Is server running?\n" @@ -297,7 +297,7 @@ msgid "" "HINT: The \"-m fast\" option immediately disconnects sessions rather than\n" "waiting for session-initiated disconnection.\n" msgstr "" -"TIPP: Die Option „-m fast“ beendet Sitzungen sofort, statt auf das Beenden\n" +"TIPP: Die Option »-m fast« beendet Sitzungen sofort, statt auf das Beenden\n" "durch die Sitzungen selbst zu warten.\n" #: pg_ctl.c:1022 pg_ctl.c:1112 @@ -349,12 +349,12 @@ msgstr "%s: kann Server nicht befördern; Server ist nicht im Standby-Modus\n" #: pg_ctl.c:1203 #, c-format msgid "%s: could not create promote signal file \"%s\": %s\n" -msgstr "%s: konnte Signaldatei zum Befördern „%s“ nicht erzeugen: %s\n" +msgstr "%s: konnte Signaldatei zum Befördern »%s« nicht erzeugen: %s\n" #: pg_ctl.c:1209 #, c-format msgid "%s: could not write promote signal file \"%s\": %s\n" -msgstr "%s: konnte Signaldatei zum Befördern „%s“ nicht schreiben: %s\n" +msgstr "%s: konnte Signaldatei zum Befördern »%s« nicht schreiben: %s\n" #: pg_ctl.c:1217 #, c-format @@ -364,7 +364,7 @@ msgstr "%s: konnte Signal zum Befördern nicht senden (PID: %ld): %s\n" #: pg_ctl.c:1220 #, c-format msgid "%s: could not remove promote signal file \"%s\": %s\n" -msgstr "%s: konnte Signaldatei zum Befördern „%s“ nicht entfernen: %s\n" +msgstr "%s: konnte Signaldatei zum Befördern »%s« nicht entfernen: %s\n" #: pg_ctl.c:1225 msgid "server promoting\n" @@ -398,7 +398,7 @@ msgstr "%s: konnte eigene Programmdatei nicht finden\n" #: pg_ctl.c:1386 #, c-format msgid "%s: could not find postgres program executable\n" -msgstr "%s: konnte „postgres“ Programmdatei nicht finden\n" +msgstr "%s: konnte »postgres« Programmdatei nicht finden\n" #: pg_ctl.c:1469 pg_ctl.c:1503 #, c-format @@ -408,27 +408,27 @@ msgstr "%s: konnte Servicemanager nicht öffnen\n" #: pg_ctl.c:1475 #, c-format msgid "%s: service \"%s\" already registered\n" -msgstr "%s: Systemdienst „%s“ ist bereits registriert\n" +msgstr "%s: Systemdienst »%s« ist bereits registriert\n" #: pg_ctl.c:1486 #, c-format msgid "%s: could not register service \"%s\": error code %lu\n" -msgstr "%s: konnte Systemdienst „%s“ nicht registrieren: Fehlercode %lu\n" +msgstr "%s: konnte Systemdienst »%s« nicht registrieren: Fehlercode %lu\n" #: pg_ctl.c:1509 #, c-format msgid "%s: service \"%s\" not registered\n" -msgstr "%s: Systemdienst „%s“ ist nicht registriert\n" +msgstr "%s: Systemdienst »%s« ist nicht registriert\n" #: pg_ctl.c:1516 #, c-format msgid "%s: could not open service \"%s\": error code %lu\n" -msgstr "%s: konnte Systemdienst „%s“ nicht öffnen: Fehlercode %lu\n" +msgstr "%s: konnte Systemdienst »%s« nicht öffnen: Fehlercode %lu\n" #: pg_ctl.c:1525 #, c-format msgid "%s: could not unregister service \"%s\": error code %lu\n" -msgstr "%s: konnte Systemdienst „%s“ nicht deregistrieren: Fehlercode %lu\n" +msgstr "%s: konnte Systemdienst »%s« nicht deregistrieren: Fehlercode %lu\n" #: pg_ctl.c:1612 msgid "Waiting for server startup...\n" @@ -445,7 +445,7 @@ msgstr "Server wurde gestartet und nimmt Verbindungen an\n" #: pg_ctl.c:1674 #, c-format msgid "%s: could not start service \"%s\": error code %lu\n" -msgstr "%s: konnte Systemdienst „%s“ nicht starten: Fehlercode %lu\n" +msgstr "%s: konnte Systemdienst »%s« nicht starten: Fehlercode %lu\n" #: pg_ctl.c:1748 #, c-format @@ -475,7 +475,7 @@ msgstr "%s: WARNUNG: konnte nicht alle Job-Objekt-Funtionen in der System-API fi #: pg_ctl.c:1914 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: pg_ctl.c:1922 #, c-format @@ -670,7 +670,7 @@ msgstr "" #: pg_ctl.c:1964 #, c-format msgid " -m, --mode=MODE MODE can be \"smart\", \"fast\", or \"immediate\"\n" -msgstr " -m, --mode=MODUS MODUS kann „smart“, „fast“ oder „immediate“ sein\n" +msgstr " -m, --mode=MODUS MODUS kann »smart«, »fast« oder »immediate« sein\n" #: pg_ctl.c:1966 #, c-format @@ -705,7 +705,7 @@ msgid "" "Allowed signal names for kill:\n" msgstr "" "\n" -"Erlaubte Signalnamen für „kill“:\n" +"Erlaubte Signalnamen für »kill«:\n" #: pg_ctl.c:1975 #, c-format @@ -714,7 +714,7 @@ msgid "" "Options for register and unregister:\n" msgstr "" "\n" -"Optionen für „register“ und „unregister“:\n" +"Optionen für »register« und »unregister«:\n" #: pg_ctl.c:1976 #, c-format @@ -769,22 +769,22 @@ msgstr "" #: pg_ctl.c:2011 #, c-format msgid "%s: unrecognized shutdown mode \"%s\"\n" -msgstr "%s: unbekannter Shutdown-Modus „%s“\n" +msgstr "%s: unbekannter Shutdown-Modus »%s«\n" #: pg_ctl.c:2043 #, c-format msgid "%s: unrecognized signal name \"%s\"\n" -msgstr "%s: unbekannter Signalname „%s“\n" +msgstr "%s: unbekannter Signalname »%s«\n" #: pg_ctl.c:2060 #, c-format msgid "%s: unrecognized start type \"%s\"\n" -msgstr "%s: unbekannter Starttyp „%s“\n" +msgstr "%s: unbekannter Starttyp »%s«\n" #: pg_ctl.c:2115 #, c-format msgid "%s: could not determine the data directory using command \"%s\"\n" -msgstr "%s: konnte das Datenverzeichnis mit Befehl „%s“ nicht ermitteln\n" +msgstr "%s: konnte das Datenverzeichnis mit Befehl »%s« nicht ermitteln\n" #: pg_ctl.c:2187 #, c-format @@ -794,7 +794,7 @@ msgid "" "own the server process.\n" msgstr "" "%s: kann nicht als root ausgeführt werden\n" -"Bitte loggen Sie sich (z.B. mit „su“) als der (unprivilegierte) Benutzer\n" +"Bitte loggen Sie sich (z.B. mit »su«) als der (unprivilegierte) Benutzer\n" "ein, der Eigentümer des Serverprozesses sein soll.\n" #: pg_ctl.c:2266 @@ -805,17 +805,17 @@ msgstr "%s: Option -S wird auf dieser Plattform nicht unterstützt\n" #: pg_ctl.c:2304 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: pg_ctl.c:2328 #, c-format msgid "%s: missing arguments for kill mode\n" -msgstr "%s: fehlende Argumente für „kill“-Modus\n" +msgstr "%s: fehlende Argumente für »kill«-Modus\n" #: pg_ctl.c:2346 #, c-format msgid "%s: unrecognized operation mode \"%s\"\n" -msgstr "%s: unbekannter Operationsmodus „%s“\n" +msgstr "%s: unbekannter Operationsmodus »%s«\n" #: pg_ctl.c:2356 #, c-format diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index d7506e119e..216d7bc6f5 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -178,6 +178,44 @@ fmtQualifiedId(int remoteVersion, const char *schema, const char *id) return id_return->data; } +/* + * Format a Postgres version number (in the PG_VERSION_NUM integer format + * returned by PQserverVersion()) as a string. This exists mainly to + * encapsulate knowledge about two-part vs. three-part version numbers. + * + * For re-entrancy, caller must supply the buffer the string is put in. + * Recommended size of the buffer is 32 bytes. + * + * Returns address of 'buf', as a notational convenience. + */ +char * +formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen) +{ + if (version_number >= 100000) + { + /* New two-part style */ + if (include_minor) + snprintf(buf, buflen, "%d.%d", version_number / 10000, + version_number % 10000); + else + snprintf(buf, buflen, "%d", version_number / 10000); + } + else + { + /* Old three-part style */ + if (include_minor) + snprintf(buf, buflen, "%d.%d.%d", version_number / 10000, + (version_number / 100) % 100, + version_number % 100); + else + snprintf(buf, buflen, "%d.%d", version_number / 10000, + (version_number / 100) % 100); + } + return buf; +} + + /* * Convert a string value to an SQL string literal and append it to * the given buffer. We assume the specified client_encoding and @@ -339,6 +377,210 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix) } +/* + * Append the given string to the shell command being built in the buffer, + * with suitable shell-style quoting to create exactly one argument. + * + * Forbid LF or CR characters, which have scant practical use beyond designing + * security breaches. The Windows command shell is unusable as a conduit for + * arguments containing LF or CR characters. A future major release should + * reject those characters in CREATE ROLE and CREATE DATABASE, because use + * there eventually leads to errors here. + */ +void +appendShellString(PQExpBuffer buf, const char *str) +{ + const char *p; + +#ifndef WIN32 + appendPQExpBufferChar(buf, '\''); + for (p = str; *p; p++) + { + if (*p == '\n' || *p == '\r') + { + fprintf(stderr, + _("shell command argument contains a newline or carriage return: \"%s\"\n"), + str); + exit(EXIT_FAILURE); + } + + if (*p == '\'') + appendPQExpBufferStr(buf, "'\"'\"'"); + else + appendPQExpBufferChar(buf, *p); + } + appendPQExpBufferChar(buf, '\''); +#else /* WIN32 */ + int backslash_run_length = 0; + + /* + * A Windows system() argument experiences two layers of interpretation. + * First, cmd.exe interprets the string. Its behavior is undocumented, + * but a caret escapes any byte except LF or CR that would otherwise have + * special meaning. Handling of a caret before LF or CR differs between + * "cmd.exe /c" and other modes, and it is unusable here. + * + * Second, the new process parses its command line to construct argv (see + * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats + * backslash-double quote sequences specially. + */ + appendPQExpBufferStr(buf, "^\""); + for (p = str; *p; p++) + { + if (*p == '\n' || *p == '\r') + { + fprintf(stderr, + _("shell command argument contains a newline or carriage return: \"%s\"\n"), + str); + exit(EXIT_FAILURE); + } + + /* Change N backslashes before a double quote to 2N+1 backslashes. */ + if (*p == '"') + { + while (backslash_run_length) + { + appendPQExpBufferStr(buf, "^\\"); + backslash_run_length--; + } + appendPQExpBufferStr(buf, "^\\"); + } + else if (*p == '\\') + backslash_run_length++; + else + backslash_run_length = 0; + + /* + * Decline to caret-escape the most mundane characters, to ease + * debugging and lest we approach the command length limit. + */ + if (!((*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9'))) + appendPQExpBufferChar(buf, '^'); + appendPQExpBufferChar(buf, *p); + } + + /* + * Change N backslashes at end of argument to 2N backslashes, because they + * precede the double quote that terminates the argument. + */ + while (backslash_run_length) + { + appendPQExpBufferStr(buf, "^\\"); + backslash_run_length--; + } + appendPQExpBufferStr(buf, "^\""); +#endif /* WIN32 */ +} + + +/* + * Append the given string to the buffer, with suitable quoting for passing + * the string as a value, in a keyword/pair value in a libpq connection + * string + */ +void +appendConnStrVal(PQExpBuffer buf, const char *str) +{ + const char *s; + bool needquotes; + + /* + * If the string is one or more plain ASCII characters, no need to quote + * it. This is quite conservative, but better safe than sorry. + */ + needquotes = true; + for (s = str; *s; s++) + { + if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || *s == '_' || *s == '.')) + { + needquotes = true; + break; + } + needquotes = false; + } + + if (needquotes) + { + appendPQExpBufferChar(buf, '\''); + while (*str) + { + /* ' and \ must be escaped by to \' and \\ */ + if (*str == '\'' || *str == '\\') + appendPQExpBufferChar(buf, '\\'); + + appendPQExpBufferChar(buf, *str); + str++; + } + appendPQExpBufferChar(buf, '\''); + } + else + appendPQExpBufferStr(buf, str); +} + + +/* + * Append a psql meta-command that connects to the given database with the + * then-current connection's user, host and port. + */ +void +appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname) +{ + const char *s; + bool complex; + + /* + * If the name is plain ASCII characters, emit a trivial "\connect "foo"". + * For other names, even many not technically requiring it, skip to the + * general case. No database has a zero-length name. + */ + complex = false; + for (s = dbname; *s; s++) + { + if (*s == '\n' || *s == '\r') + { + fprintf(stderr, + _("database name contains a newline or carriage return: \"%s\"\n"), + dbname); + exit(EXIT_FAILURE); + } + + if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || *s == '_' || *s == '.')) + { + complex = true; + } + } + + appendPQExpBufferStr(buf, "\\connect "); + if (complex) + { + PQExpBufferData connstr; + + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, dbname); + + appendPQExpBuffer(buf, "-reuse-previous=on "); + + /* + * As long as the name does not contain a newline, SQL identifier + * quoting satisfies the psql meta-command parser. Prefer not to + * involve psql-interpreted single quotes, which behaved differently + * before PostgreSQL 9.2. + */ + appendPQExpBufferStr(buf, fmtId(connstr.data)); + + termPQExpBuffer(&connstr); + } + else + appendPQExpBufferStr(buf, fmtId(dbname)); + appendPQExpBufferChar(buf, '\n'); +} + + /* * Convert a bytea value (presented as raw bytes) to an SQL string literal * and append it to the given buffer. We assume the specified diff --git a/src/bin/pg_dump/dumputils.h b/src/bin/pg_dump/dumputils.h index b1767468c1..f1d1af6dab 100644 --- a/src/bin/pg_dump/dumputils.h +++ b/src/bin/pg_dump/dumputils.h @@ -72,6 +72,8 @@ extern PQExpBuffer (*getLocalPQExpBuffer) (void); extern const char *fmtId(const char *identifier); extern const char *fmtQualifiedId(int remoteVersion, const char *schema, const char *id); +extern char *formatPGVersionNumber(int version_number, bool include_minor, + char *buf, size_t buflen); extern void appendStringLiteral(PQExpBuffer buf, const char *str, int encoding, bool std_strings); extern void appendStringLiteralConn(PQExpBuffer buf, const char *str, @@ -81,6 +83,9 @@ extern void appendStringLiteralDQ(PQExpBuffer buf, const char *str, extern void appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length, bool std_strings); +extern void appendShellString(PQExpBuffer buf, const char *str); +extern void appendConnStrVal(PQExpBuffer buf, const char *str); +extern void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname); extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems); extern bool buildACLCommands(const char *name, const char *subname, const char *type, const char *acls, const char *owner, diff --git a/src/bin/pg_dump/parallel.c b/src/bin/pg_dump/parallel.c index 51a8eee369..ce3a06ae81 100644 --- a/src/bin/pg_dump/parallel.c +++ b/src/bin/pg_dump/parallel.c @@ -59,6 +59,10 @@ #include "postgres_fe.h" +#ifdef HAVE_SYS_SELECT_H +#include +#endif + #include "parallel.h" #include "pg_backup_utils.h" diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h index e0b3746277..9eae81924b 100644 --- a/src/bin/pg_dump/pg_backup.h +++ b/src/bin/pg_dump/pg_backup.h @@ -102,7 +102,7 @@ typedef struct _restoreOptions SimpleStringList tableNames; int useDB; - char *dbname; + char *dbname; /* subject to expand_dbname */ char *pgport; char *pghost; char *username; @@ -120,7 +120,7 @@ typedef struct _restoreOptions typedef struct _dumpOptions { - const char *dbname; + const char *dbname; /* subject to expand_dbname */ const char *pghost; const char *pgport; const char *username; diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 70f80f365a..6fe96f0662 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -762,9 +762,16 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel) /* If we created a DB, connect to it... */ if (strcmp(te->desc, "DATABASE") == 0) { + PQExpBufferData connstr; + + initPQExpBuffer(&connstr); + appendPQExpBufferStr(&connstr, "dbname="); + appendConnStrVal(&connstr, te->tag); + /* Abandon struct, but keep its buffer until process exit. */ + ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag); _reconnectToDB(AH, te->tag); - ropt->dbname = pg_strdup(te->tag); + ropt->dbname = connstr.data; } } @@ -2921,12 +2928,17 @@ _reconnectToDB(ArchiveHandle *AH, const char *dbname) ReconnectToServer(AH, dbname, NULL); else { - PQExpBuffer qry = createPQExpBuffer(); + if (dbname) + { + PQExpBufferData connectbuf; - appendPQExpBuffer(qry, "\\connect %s\n\n", - dbname ? fmtId(dbname) : "-"); - ahprintf(AH, "%s", qry->data); - destroyPQExpBuffer(qry); + initPQExpBuffer(&connectbuf); + appendPsqlMetaConnect(&connectbuf, dbname); + ahprintf(AH, "%s\n", connectbuf.data); + termPQExpBuffer(&connectbuf); + } + else + ahprintf(AH, "%s\n", "\\connect -\n"); } /* @@ -3205,15 +3217,22 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass) /* * Avoid dumping the public schema, as it will already be created ... - * unless we are using --clean mode, in which case it's been deleted and - * we'd better recreate it. Likewise for its comment, if any. + * unless we are using --clean mode (and *not* --create mode), in which + * case we've previously issued a DROP for it so we'd better recreate it. + * + * Likewise for its comment, if any. (We could try issuing the COMMENT + * command anyway; but it'd fail if the restore is done as non-super-user, + * so let's not.) + * + * XXX it looks pretty ugly to hard-wire the public schema like this, but + * it sits in a sort of no-mans-land between being a system object and a + * user object, so it really is special in a way. */ - if (!ropt->dropSchema) + if (!(ropt->dropSchema && !ropt->createDB)) { if (strcmp(te->desc, "SCHEMA") == 0 && strcmp(te->tag, "public") == 0) return; - /* The comment restore would require super-user privs, so avoid it. */ if (strcmp(te->desc, "COMMENT") == 0 && strcmp(te->tag, "SCHEMA public") == 0) return; @@ -4393,7 +4412,7 @@ CloneArchive(ArchiveHandle *AH) } else { - char *dbname; + PQExpBufferData connstr; char *pghost; char *pgport; char *username; @@ -4406,14 +4425,18 @@ CloneArchive(ArchiveHandle *AH) * because all just return a pointer and do not actually send/receive * any data to/from the database. */ - dbname = PQdb(AH->connection); + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, PQdb(AH->connection)); pghost = PQhost(AH->connection); pgport = PQport(AH->connection); username = PQuser(AH->connection); /* this also sets clone->connection */ - ConnectDatabase((Archive *) clone, dbname, pghost, pgport, username, TRI_NO); + ConnectDatabase((Archive *) clone, connstr.data, + pghost, pgport, username, TRI_NO); + termPQExpBuffer(&connstr); /* setupDumpWorker will fix up connection state */ } diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c index 1f88753244..f6299b9c20 100644 --- a/src/bin/pg_dump/pg_backup_db.c +++ b/src/bin/pg_dump/pg_backup_db.c @@ -133,6 +133,7 @@ ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username) static PGconn * _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) { + PQExpBufferData connstr; PGconn *newConn; const char *newdb; const char *newuser; @@ -161,6 +162,10 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) exit_horribly(modulename, "out of memory\n"); } + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, newdb); + do { const char *keywords[7]; @@ -175,7 +180,7 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) keywords[3] = "password"; values[3] = password; keywords[4] = "dbname"; - values[4] = newdb; + values[4] = connstr.data; keywords[5] = "fallback_application_name"; values[5] = progname; keywords[6] = NULL; @@ -227,6 +232,8 @@ _connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser) if (password) free(password); + termPQExpBuffer(&connstr); + /* check for version mismatch */ _check_database_version(AH); diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 7273e6494d..baf86e5486 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -2444,7 +2444,8 @@ dumpDatabase(Archive *fout) appendPQExpBufferStr(creaQry, " LC_CTYPE = "); appendStringLiteralAH(creaQry, ctype, fout); } - if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0) + if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 && + !dopt->outputNoTablespaces) appendPQExpBuffer(creaQry, " TABLESPACE = %s", fmtId(tablespace)); appendPQExpBufferStr(creaQry, ";\n"); @@ -4480,19 +4481,22 @@ getFuncs(Archive *fout, int *numFuncs) selectSourceSchema(fout, "pg_catalog"); /* - * Find all user-defined functions. Normally we can exclude functions in - * pg_catalog, which is worth doing since there are several thousand of - * 'em. However, there are some extensions that create functions in - * pg_catalog. In normal dumps we can still ignore those --- but in - * binary-upgrade mode, we must dump the member objects of the extension, - * so be sure to fetch any such functions. + * Find all interesting functions. This is a bit complicated: * - * Also, in 9.2 and up, exclude functions that are internally dependent on - * something else, since presumably those will be created as a result of - * creating the something else. This currently only acts to suppress - * constructor functions for range types. Note that this is OK only - * because the constructors don't have any dependencies the range type - * doesn't have; otherwise we might not get creation ordering correct. + * 1. Always exclude aggregates; those are handled elsewhere. + * + * 2. Always exclude functions that are internally dependent on something + * else, since presumably those will be created as a result of creating + * the something else. This currently acts only to suppress constructor + * functions for range types (so we only need it in 9.2 and up). Note + * this is OK only because the constructors don't have any dependencies + * the range type doesn't have; otherwise we might not get creation + * ordering correct. + * + * 3. Otherwise, we normally exclude functions in pg_catalog. However, if + * they're members of extensions and we are in binary-upgrade mode then + * include them, since we want to dump extension members individually in + * that mode. */ if (fout->remoteVersion >= 70300) @@ -4503,16 +4507,18 @@ getFuncs(Archive *fout, int *numFuncs) "pronamespace, " "(%s proowner) AS rolname " "FROM pg_proc p " - "WHERE NOT proisagg AND (" - "pronamespace != " - "(SELECT oid FROM pg_namespace " - "WHERE nspname = 'pg_catalog')", + "WHERE NOT proisagg", username_subquery); if (fout->remoteVersion >= 90200) appendPQExpBufferStr(query, "\n AND NOT EXISTS (SELECT 1 FROM pg_depend " "WHERE classid = 'pg_proc'::regclass AND " "objid = p.oid AND deptype = 'i')"); + appendPQExpBufferStr(query, + "\n AND (" + "\n pronamespace != " + "(SELECT oid FROM pg_namespace " + "WHERE nspname = 'pg_catalog')"); if (dopt->binary_upgrade && fout->remoteVersion >= 90100) appendPQExpBufferStr(query, "\n OR EXISTS(SELECT 1 FROM pg_depend WHERE " diff --git a/src/bin/pg_dump/pg_dumpall.c b/src/bin/pg_dump/pg_dumpall.c index 4b166050cd..6ea6be569c 100644 --- a/src/bin/pg_dump/pg_dumpall.c +++ b/src/bin/pg_dump/pg_dumpall.c @@ -49,8 +49,6 @@ static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem, const char *name2); static void dumpDatabases(PGconn *conn); static void dumpTimestamp(const char *msg); -static void doShellQuoting(PQExpBuffer buf, const char *str); -static void doConnStrQuoting(PQExpBuffer buf, const char *str); static int runPgDump(const char *dbname); static void buildShSecLabels(PGconn *conn, const char *catalog_name, @@ -214,7 +212,7 @@ main(int argc, char *argv[]) case 'f': filename = pg_strdup(optarg); appendPQExpBufferStr(pgdumpopts, " -f "); - doShellQuoting(pgdumpopts, filename); + appendShellString(pgdumpopts, filename); break; case 'g': @@ -251,7 +249,7 @@ main(int argc, char *argv[]) case 'S': appendPQExpBufferStr(pgdumpopts, " -S "); - doShellQuoting(pgdumpopts, optarg); + appendShellString(pgdumpopts, optarg); break; case 't': @@ -287,13 +285,13 @@ main(int argc, char *argv[]) case 2: appendPQExpBufferStr(pgdumpopts, " --lock-wait-timeout "); - doShellQuoting(pgdumpopts, optarg); + appendShellString(pgdumpopts, optarg); break; case 3: use_role = pg_strdup(optarg); appendPQExpBufferStr(pgdumpopts, " --role "); - doShellQuoting(pgdumpopts, use_role); + appendShellString(pgdumpopts, use_role); break; default: @@ -1428,7 +1426,7 @@ dumpCreateDB(PGconn *conn) fdbname, fmtId(dbtablespace)); /* connect to original database */ - appendPQExpBuffer(buf, "\\connect %s\n", fdbname); + appendPsqlMetaConnect(buf, dbname); } if (binary_upgrade) @@ -1654,11 +1652,15 @@ dumpDatabases(PGconn *conn) int ret; char *dbname = PQgetvalue(res, i, 0); + PQExpBufferData connectbuf; if (verbose) fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname); - fprintf(OPF, "\\connect %s\n\n", fmtId(dbname)); + initPQExpBuffer(&connectbuf); + appendPsqlMetaConnect(&connectbuf, dbname); + fprintf(OPF, "%s\n", connectbuf.data); + termPQExpBuffer(&connectbuf); /* * Restore will need to write to the target cluster. This connection @@ -1726,9 +1728,9 @@ runPgDump(const char *dbname) * string. */ appendPQExpBuffer(connstrbuf, "%s dbname=", connstr); - doConnStrQuoting(connstrbuf, dbname); + appendConnStrVal(connstrbuf, dbname); - doShellQuoting(cmd, connstrbuf->data); + appendShellString(cmd, connstrbuf->data); if (verbose) fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data); @@ -1814,7 +1816,9 @@ connectDatabase(const char *dbname, const char *connection_string, /* * Merge the connection info inputs given in form of connection string - * and other options. + * and other options. Explicitly discard any dbname value in the + * connection string; otherwise, PQconnectdbParams() would interpret + * that value as being itself a connection string. */ if (connection_string) { @@ -1827,7 +1831,8 @@ connectDatabase(const char *dbname, const char *connection_string, for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) { - if (conn_opt->val != NULL && conn_opt->val[0] != '\0') + if (conn_opt->val != NULL && conn_opt->val[0] != '\0' && + strcmp(conn_opt->keyword, "dbname") != 0) argcount++; } @@ -1836,7 +1841,8 @@ connectDatabase(const char *dbname, const char *connection_string, for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++) { - if (conn_opt->val != NULL && conn_opt->val[0] != '\0') + if (conn_opt->val != NULL && conn_opt->val[0] != '\0' && + strcmp(conn_opt->keyword, "dbname") != 0) { keywords[i] = conn_opt->keyword; values[i] = conn_opt->val; @@ -2008,7 +2014,7 @@ constructConnStr(const char **keywords, const char **values) appendPQExpBufferChar(buf, ' '); firstkeyword = false; appendPQExpBuffer(buf, "%s=", keywords[i]); - doConnStrQuoting(buf, values[i]); + appendConnStrVal(buf, values[i]); } connstr = pg_strdup(buf->data); @@ -2081,81 +2087,3 @@ dumpTimestamp(const char *msg) if (strftime(buf, sizeof(buf), PGDUMP_STRFTIME_FMT, localtime(&now)) != 0) fprintf(OPF, "-- %s %s\n\n", msg, buf); } - - -/* - * Append the given string to the buffer, with suitable quoting for passing - * the string as a value, in a keyword/pair value in a libpq connection - * string - */ -static void -doConnStrQuoting(PQExpBuffer buf, const char *str) -{ - const char *s; - bool needquotes; - - /* - * If the string consists entirely of plain ASCII characters, no need to - * quote it. This is quite conservative, but better safe than sorry. - */ - needquotes = false; - for (s = str; *s; s++) - { - if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || - (*s >= '0' && *s <= '9') || *s == '_' || *s == '.')) - { - needquotes = true; - break; - } - } - - if (needquotes) - { - appendPQExpBufferChar(buf, '\''); - while (*str) - { - /* ' and \ must be escaped by to \' and \\ */ - if (*str == '\'' || *str == '\\') - appendPQExpBufferChar(buf, '\\'); - - appendPQExpBufferChar(buf, *str); - str++; - } - appendPQExpBufferChar(buf, '\''); - } - else - appendPQExpBufferStr(buf, str); -} - -/* - * Append the given string to the shell command being built in the buffer, - * with suitable shell-style quoting. - */ -static void -doShellQuoting(PQExpBuffer buf, const char *str) -{ - const char *p; - -#ifndef WIN32 - appendPQExpBufferChar(buf, '\''); - for (p = str; *p; p++) - { - if (*p == '\'') - appendPQExpBufferStr(buf, "'\"'\"'"); - else - appendPQExpBufferChar(buf, *p); - } - appendPQExpBufferChar(buf, '\''); -#else /* WIN32 */ - - appendPQExpBufferChar(buf, '"'); - for (p = str; *p; p++) - { - if (*p == '"') - appendPQExpBufferStr(buf, "\\\""); - else - appendPQExpBufferChar(buf, *p); - } - appendPQExpBufferChar(buf, '"'); -#endif /* WIN32 */ -} diff --git a/src/bin/pg_dump/po/de.po b/src/bin/pg_dump/po/de.po index 3f3e736aee..90261e77c9 100644 --- a/src/bin/pg_dump/po/de.po +++ b/src/bin/pg_dump/po/de.po @@ -1,14 +1,14 @@ # German message translation file for pg_dump and friends # Peter Eisentraut , 2001 - 2016. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" "Project-Id-Version: PostgreSQL 9.5\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" -"POT-Creation-Date: 2016-02-08 10:43+0000\n" -"PO-Revision-Date: 2016-02-08 12:22-0500\n" +"POT-Creation-Date: 2016-06-06 22:21+0000\n" +"PO-Revision-Date: 2016-06-07 06:33-0400\n" "Last-Translator: Peter Eisentraut \n" "Language-Team: German \n" "Language: de\n" @@ -25,27 +25,27 @@ msgstr "konnte aktuelles Verzeichnis nicht ermitteln: %s" #: ../../common/exec.c:146 #, c-format msgid "invalid binary \"%s\"" -msgstr "ungültige Programmdatei „%s“" +msgstr "ungültige Programmdatei »%s«" #: ../../common/exec.c:195 #, c-format msgid "could not read binary \"%s\"" -msgstr "konnte Programmdatei „%s“ nicht lesen" +msgstr "konnte Programmdatei »%s« nicht lesen" #: ../../common/exec.c:202 #, c-format msgid "could not find a \"%s\" to execute" -msgstr "konnte kein „%s“ zum Ausführen finden" +msgstr "konnte kein »%s« zum Ausführen finden" #: ../../common/exec.c:257 ../../common/exec.c:293 #, c-format msgid "could not change directory to \"%s\": %s" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %s" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %s" #: ../../common/exec.c:272 #, c-format msgid "could not read symbolic link \"%s\"" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen" #: ../../common/exec.c:523 #, c-format @@ -53,8 +53,8 @@ msgid "pclose failed: %s" msgstr "pclose fehlgeschlagen: %s" #: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75 -#: ../../common/fe_memutils.c:98 pg_backup_db.c:137 pg_backup_db.c:188 -#: pg_backup_db.c:245 pg_backup_db.c:287 +#: ../../common/fe_memutils.c:98 pg_backup_db.c:156 pg_backup_db.c:207 +#: pg_backup_db.c:264 pg_backup_db.c:306 #, c-format msgid "out of memory\n" msgstr "Speicher aufgebraucht\n" @@ -267,180 +267,160 @@ msgstr "lese Policies\n" #: common.c:902 #, c-format msgid "failed sanity check, parent OID %u of table \"%s\" (OID %u) not found\n" -msgstr "Sanity-Check fehlgeschlagen, Eltern-OID %u von Tabelle „%s“ (OID %u) nicht gefunden\n" +msgstr "Sanity-Check fehlgeschlagen, Eltern-OID %u von Tabelle »%s« (OID %u) nicht gefunden\n" #: common.c:944 #, c-format msgid "could not parse numeric array \"%s\": too many numbers\n" -msgstr "konnte numerisches Array „%s“ nicht parsen: zu viele Zahlen\n" +msgstr "konnte numerisches Array »%s« nicht parsen: zu viele Zahlen\n" #: common.c:959 #, c-format msgid "could not parse numeric array \"%s\": invalid character in number\n" -msgstr "konnte numerisches Array „%s“ nicht parsen: ungültiges Zeichen in Zahl\n" +msgstr "konnte numerisches Array »%s« nicht parsen: ungültiges Zeichen in Zahl\n" #. translator: this is a module name -#: compress_io.c:79 +#: compress_io.c:78 msgid "compress_io" msgstr "compress_io" -#: compress_io.c:115 +#: compress_io.c:114 #, c-format msgid "invalid compression code: %d\n" msgstr "ungültiger Komprimierungscode: %d\n" -#: compress_io.c:139 compress_io.c:175 compress_io.c:196 compress_io.c:529 -#: compress_io.c:572 +#: compress_io.c:138 compress_io.c:174 compress_io.c:192 compress_io.c:519 +#: compress_io.c:562 #, c-format msgid "not built with zlib support\n" msgstr "nicht mit zlib-Unterstützung gebaut\n" -#: compress_io.c:246 compress_io.c:348 +#: compress_io.c:242 compress_io.c:344 #, c-format msgid "could not initialize compression library: %s\n" msgstr "konnte Komprimierungsbibliothek nicht initialisieren: %s\n" -#: compress_io.c:267 +#: compress_io.c:263 #, c-format msgid "could not close compression stream: %s\n" msgstr "konnte Komprimierungsstrom nicht schließen: %s\n" -#: compress_io.c:285 +#: compress_io.c:281 #, c-format msgid "could not compress data: %s\n" msgstr "konnte Daten nicht komprimieren: %s\n" -#: compress_io.c:368 compress_io.c:384 +#: compress_io.c:361 compress_io.c:377 #, c-format msgid "could not uncompress data: %s\n" msgstr "konnte Daten nicht dekomprimieren: %s\n" -#: compress_io.c:392 +#: compress_io.c:385 #, c-format msgid "could not close compression library: %s\n" msgstr "konnte Komprimierungsbibliothek nicht schließen: %s\n" -#: compress_io.c:606 compress_io.c:642 pg_backup_custom.c:591 +#: compress_io.c:596 compress_io.c:632 pg_backup_custom.c:591 #: pg_backup_tar.c:560 #, c-format msgid "could not read from input file: %s\n" msgstr "konnte nicht aus Eingabedatei lesen: %s\n" -#: compress_io.c:645 pg_backup_custom.c:588 pg_backup_directory.c:552 +#: compress_io.c:635 pg_backup_custom.c:588 pg_backup_directory.c:548 #: pg_backup_tar.c:796 pg_backup_tar.c:820 #, c-format msgid "could not read from input file: end of file\n" msgstr "konnte nicht aus Eingabedatei lesen: Dateiende\n" -#: parallel.c:76 +#: parallel.c:162 msgid "parallel archiver" msgstr "paralleler Archivierer" -#: parallel.c:139 +#: parallel.c:226 #, c-format msgid "%s: WSAStartup failed: %d\n" msgstr "%s: WSAStartup fehlgeschlagen: %d\n" -#: parallel.c:339 -#, c-format -msgid "worker is terminating\n" -msgstr "Arbeitsprozess bricht ab\n" - -#: parallel.c:529 +#: parallel.c:929 #, c-format msgid "could not create communication channels: %s\n" msgstr "konnte Kommunikationskanäle nicht erzeugen: %s\n" -#: parallel.c:601 +#: parallel.c:992 #, c-format msgid "could not create worker process: %s\n" msgstr "konnte Arbeitsprozess nicht erzeugen: %s\n" -#: parallel.c:818 -#, c-format -msgid "could not get relation name for OID %u: %s\n" -msgstr "konnte Relationsnamen für OID %u nicht ermitteln: %s\n" - -#: parallel.c:835 +#: parallel.c:1187 #, c-format msgid "" "could not obtain lock on relation \"%s\"\n" "This usually means that someone requested an ACCESS EXCLUSIVE lock on the table after the pg_dump parent process had gotten the initial ACCESS SHARE lock on the table.\n" msgstr "" -"konnte Sperre für Relation „%s“ nicht setzen\n" +"konnte Sperre für Relation »%s« nicht setzen\n" "Das bedeutet meistens, dass jemand eine ACCESS-EXCLUSIVE-Sperre auf die Tabelle gesetzt hat, nachdem der pg-dump-Elternprozess die anfängliche ACCESS-SHARE-Sperre gesetzt hatte.\n" -#: parallel.c:919 +#: parallel.c:1257 #, c-format -msgid "unrecognized command on communication channel: %s\n" -msgstr "unbekannter Befehl auf Kommunikationskanal: %s\n" +msgid "unrecognized command received from master: \"%s\"\n" +msgstr "unbekannter Befehl vom Master empfangen: »%s«\n" -#: parallel.c:952 +#: parallel.c:1295 #, c-format msgid "a worker process died unexpectedly\n" msgstr "ein Arbeitsprozess endete unerwartet\n" -#: parallel.c:979 parallel.c:988 +#: parallel.c:1321 parallel.c:1327 #, c-format -msgid "invalid message received from worker: %s\n" -msgstr "ungültige Nachricht vom Arbeitsprozess empfangen: %s\n" - -#: parallel.c:985 pg_backup_db.c:355 -#, c-format -msgid "%s" -msgstr "%s" +msgid "invalid message received from worker: \"%s\"\n" +msgstr "ungültige Nachricht vom Arbeitsprozess empfangen: »%s«\n" -#: parallel.c:1037 parallel.c:1081 +#: parallel.c:1384 parallel.c:1435 #, c-format msgid "error processing a parallel work item\n" msgstr "Fehler beim Verarbeiten eines parallelen Arbeitselements\n" -#: parallel.c:1109 parallel.c:1247 +#: parallel.c:1464 parallel.c:1582 #, c-format msgid "could not write to the communication channel: %s\n" msgstr "konnte nicht in den Kommunikationskanal schreiben: %s\n" -#: parallel.c:1158 +#: parallel.c:1542 #, c-format -msgid "terminated by user\n" -msgstr "vom Benutzer abgebrochen\n" +msgid "select() failed: %s\n" +msgstr "select() fehlgeschlagen: %s\n" -#: parallel.c:1210 -#, c-format -msgid "error in ListenToWorkers(): %s\n" -msgstr "Fehler in ListenToWorkers(): %s\n" - -#: parallel.c:1335 +#: parallel.c:1667 #, c-format msgid "pgpipe: could not create socket: error code %d\n" msgstr "pgpipe: konnte Socket nicht erzeugen: Fehlercode %d\n" -#: parallel.c:1346 +#: parallel.c:1678 #, c-format msgid "pgpipe: could not bind: error code %d\n" msgstr "pgpipe: konnte nicht binden: Fehlercode %d\n" -#: parallel.c:1353 +#: parallel.c:1685 #, c-format msgid "pgpipe: could not listen: error code %d\n" msgstr "pgpipe: konnte nicht auf Socket hören: Fehlercode %d\n" -#: parallel.c:1360 +#: parallel.c:1692 #, c-format msgid "pgpipe: getsockname() failed: error code %d\n" msgstr "pgpipe: getsockname() fehlgeschlagen: Fehlercode %d\n" -#: parallel.c:1371 +#: parallel.c:1703 #, c-format msgid "pgpipe: could not create second socket: error code %d\n" msgstr "pgpipe: konnte zweites Socket nicht erzeugen: Fehlercode %d\n" -#: parallel.c:1380 +#: parallel.c:1712 #, c-format msgid "pgpipe: could not connect socket: error code %d\n" msgstr "pgpipe: konnte Socket nicht verbinden: Fehlercode %d\n" -#: parallel.c:1387 +#: parallel.c:1721 #, c-format msgid "pgpipe: could not accept connection: error code %d\n" msgstr "pgpipe: konnte Verbindung nicht annehmen: Fehlercode %d\n" @@ -508,12 +488,12 @@ msgstr "entferne %s %s\n" #: pg_backup_archiver.c:637 #, c-format msgid "setting owner and privileges for %s \"%s.%s\"\n" -msgstr "setze Eigentümer und Privilegien für %s „%s.%s“\n" +msgstr "setze Eigentümer und Privilegien für %s »%s.%s«\n" #: pg_backup_archiver.c:640 #, c-format msgid "setting owner and privileges for %s \"%s\"\n" -msgstr "setze Eigentümer und Privilegien für %s „%s“\n" +msgstr "setze Eigentümer und Privilegien für %s »%s«\n" #: pg_backup_archiver.c:706 pg_backup_archiver.c:708 #, c-format @@ -523,17 +503,17 @@ msgstr "Warnung aus der ursprünglichen Ausgabedatei: %s\n" #: pg_backup_archiver.c:717 #, c-format msgid "creating %s \"%s.%s\"\n" -msgstr "erstelle %s „%s.%s“\n" +msgstr "erstelle %s »%s.%s«\n" #: pg_backup_archiver.c:720 #, c-format msgid "creating %s \"%s\"\n" -msgstr "erstelle %s „%s“\n" +msgstr "erstelle %s »%s«\n" #: pg_backup_archiver.c:765 #, c-format msgid "connecting to new database \"%s\"\n" -msgstr "verbinde mit neuer Datenbank „%s“\n" +msgstr "verbinde mit neuer Datenbank »%s«\n" #: pg_backup_archiver.c:793 #, c-format @@ -543,7 +523,7 @@ msgstr "verarbeite %s\n" #: pg_backup_archiver.c:813 #, c-format msgid "processing data for table \"%s.%s\"\n" -msgstr "verarbeite Daten für Tabelle „%s.%s“\n" +msgstr "verarbeite Daten für Tabelle »%s.%s«\n" #: pg_backup_archiver.c:875 #, c-format @@ -587,7 +567,7 @@ msgstr "Wiederherstellung von Large Object mit OID %u\n" msgid "could not create large object %u: %s" msgstr "konnte Large Object %u nicht erstellen: %s" -#: pg_backup_archiver.c:1233 pg_dump.c:2859 +#: pg_backup_archiver.c:1233 pg_dump.c:2881 #, c-format msgid "could not open large object %u: %s" msgstr "konnte Large Object %u nicht öffnen: %s" @@ -595,7 +575,7 @@ msgstr "konnte Large Object %u nicht öffnen: %s" #: pg_backup_archiver.c:1291 #, c-format msgid "could not open TOC file \"%s\": %s\n" -msgstr "konnte Inhaltsverzeichnisdatei „%s“ nicht öffnen: %s\n" +msgstr "konnte Inhaltsverzeichnisdatei »%s« nicht öffnen: %s\n" #: pg_backup_archiver.c:1332 #, c-format @@ -608,17 +588,17 @@ msgid "could not find entry for ID %d\n" msgstr "konnte Eintrag für ID %d nicht finden\n" #: pg_backup_archiver.c:1360 pg_backup_directory.c:230 -#: pg_backup_directory.c:601 +#: pg_backup_directory.c:597 #, c-format msgid "could not close TOC file: %s\n" msgstr "konnte Inhaltsverzeichnisdatei nicht finden: %s\n" #: pg_backup_archiver.c:1469 pg_backup_custom.c:162 pg_backup_directory.c:341 -#: pg_backup_directory.c:587 pg_backup_directory.c:645 -#: pg_backup_directory.c:665 +#: pg_backup_directory.c:583 pg_backup_directory.c:641 +#: pg_backup_directory.c:661 #, c-format msgid "could not open output file \"%s\": %s\n" -msgstr "konnte Ausgabedatei „%s“ nicht öffnen: %s\n" +msgstr "konnte Ausgabedatei »%s« nicht öffnen: %s\n" #: pg_backup_archiver.c:1472 pg_backup_custom.c:169 #, c-format @@ -665,7 +645,7 @@ msgstr "ungültige DumpId\n" #: pg_backup_archiver.c:1786 #, c-format msgid "bad table dumpId for TABLE DATA item\n" -msgstr "ungültige Tabellen-DumpId für „TABLE DATA“-Eintrag\n" +msgstr "ungültige Tabellen-DumpId für »TABLE DATA«-Eintrag\n" #: pg_backup_archiver.c:1878 #, c-format @@ -685,18 +665,18 @@ msgstr "versuche Archivformat zu ermitteln\n" #: pg_backup_archiver.c:2030 pg_backup_archiver.c:2040 #, c-format msgid "directory name too long: \"%s\"\n" -msgstr "Verzeichnisname zu lang: „%s“\n" +msgstr "Verzeichnisname zu lang: »%s«\n" #: pg_backup_archiver.c:2048 #, c-format msgid "directory \"%s\" does not appear to be a valid archive (\"toc.dat\" does not exist)\n" -msgstr "Verzeichnis „%s“ scheint kein gültiges Archiv zu sein („toc.dat“ existiert nicht)\n" +msgstr "Verzeichnis »%s« scheint kein gültiges Archiv zu sein (»toc.dat« existiert nicht)\n" #: pg_backup_archiver.c:2056 pg_backup_custom.c:181 pg_backup_custom.c:770 -#: pg_backup_directory.c:214 pg_backup_directory.c:402 +#: pg_backup_directory.c:214 pg_backup_directory.c:399 #, c-format msgid "could not open input file \"%s\": %s\n" -msgstr "konnte Eingabedatei „%s“ nicht öffnen: %s\n" +msgstr "konnte Eingabedatei »%s« nicht öffnen: %s\n" #: pg_backup_archiver.c:2064 pg_backup_custom.c:188 #, c-format @@ -741,177 +721,172 @@ msgstr "erstelle AH für %s, Format %d\n" #: pg_backup_archiver.c:2310 #, c-format msgid "unrecognized file format \"%d\"\n" -msgstr "nicht erkanntes Dateiformat „%d“\n" +msgstr "nicht erkanntes Dateiformat »%d«\n" -#: pg_backup_archiver.c:2460 +#: pg_backup_archiver.c:2466 #, c-format msgid "entry ID %d out of range -- perhaps a corrupt TOC\n" msgstr "ID %d des Eintrags außerhalb des gültigen Bereichs -- vielleicht ein verfälschtes Inhaltsverzeichnis\n" -#: pg_backup_archiver.c:2576 +#: pg_backup_archiver.c:2582 #, c-format msgid "read TOC entry %d (ID %d) for %s %s\n" msgstr "Inhaltsverzeichniseintrag %d (ID %d) von %s %s gelesen\n" -#: pg_backup_archiver.c:2610 +#: pg_backup_archiver.c:2616 #, c-format msgid "unrecognized encoding \"%s\"\n" -msgstr "nicht erkannte Kodierung „%s“\n" +msgstr "nicht erkannte Kodierung »%s«\n" -#: pg_backup_archiver.c:2615 +#: pg_backup_archiver.c:2621 #, c-format msgid "invalid ENCODING item: %s\n" msgstr "ungültiger ENCODING-Eintrag: %s\n" -#: pg_backup_archiver.c:2633 +#: pg_backup_archiver.c:2639 #, c-format msgid "invalid STDSTRINGS item: %s\n" msgstr "ungültiger STDSTRINGS-Eintrag: %s\n" -#: pg_backup_archiver.c:2858 +#: pg_backup_archiver.c:2864 #, c-format msgid "could not set session user to \"%s\": %s" -msgstr "konnte Sitzungsbenutzer nicht auf „%s“ setzen: %s" +msgstr "konnte Sitzungsbenutzer nicht auf »%s« setzen: %s" -#: pg_backup_archiver.c:2890 +#: pg_backup_archiver.c:2896 #, c-format msgid "could not set default_with_oids: %s" msgstr "konnte default_with_oids nicht setzen: %s" -#: pg_backup_archiver.c:3030 +#: pg_backup_archiver.c:3036 #, c-format msgid "could not set search_path to \"%s\": %s" -msgstr "konnte search_path nicht auf „%s“ setzen: %s" +msgstr "konnte search_path nicht auf »%s« setzen: %s" -#: pg_backup_archiver.c:3092 +#: pg_backup_archiver.c:3098 #, c-format msgid "could not set default_tablespace to %s: %s" -msgstr "konnte default_tablespace nicht auf „%s“ setzen: %s" +msgstr "konnte default_tablespace nicht auf »%s« setzen: %s" -#: pg_backup_archiver.c:3179 pg_backup_archiver.c:3366 +#: pg_backup_archiver.c:3185 pg_backup_archiver.c:3372 #, c-format msgid "WARNING: don't know how to set owner for object type %s\n" msgstr "WARNUNG: kann Eigentümer für Objekttyp %s nicht setzen\n" -#: pg_backup_archiver.c:3419 -#, c-format -msgid "WARNING: requested compression not available in this installation -- archive will be uncompressed\n" -msgstr "WARNUNG: Komprimierung ist in dieser Installation nicht verfügbar -- Archiv wird nicht komprimiert\n" - -#: pg_backup_archiver.c:3458 +#: pg_backup_archiver.c:3454 #, c-format msgid "did not find magic string in file header\n" msgstr "magische Zeichenkette im Dateikopf nicht gefunden\n" -#: pg_backup_archiver.c:3471 +#: pg_backup_archiver.c:3467 #, c-format msgid "unsupported version (%d.%d) in file header\n" msgstr "nicht unterstützte Version (%d.%d) im Dateikopf\n" -#: pg_backup_archiver.c:3476 +#: pg_backup_archiver.c:3472 #, c-format msgid "sanity check on integer size (%lu) failed\n" msgstr "Prüfung der Integer-Größe (%lu) fehlgeschlagen\n" -#: pg_backup_archiver.c:3480 +#: pg_backup_archiver.c:3476 #, c-format msgid "WARNING: archive was made on a machine with larger integers, some operations might fail\n" msgstr "WARNUNG: Archiv wurde auf einer Maschine mit größeren Integers erstellt; einige Operationen könnten fehlschlagen\n" -#: pg_backup_archiver.c:3490 +#: pg_backup_archiver.c:3486 #, c-format msgid "expected format (%d) differs from format found in file (%d)\n" msgstr "erwartetes Format (%d) ist nicht das gleiche wie das in der Datei gefundene (%d)\n" -#: pg_backup_archiver.c:3506 +#: pg_backup_archiver.c:3502 #, c-format msgid "WARNING: archive is compressed, but this installation does not support compression -- no data will be available\n" msgstr "WARNUNG: Archiv ist komprimiert, aber diese Installation unterstützt keine Komprimierung -- keine Daten verfügbar\n" -#: pg_backup_archiver.c:3524 +#: pg_backup_archiver.c:3520 #, c-format msgid "WARNING: invalid creation date in header\n" msgstr "WARNUNG: ungültiges Erstellungsdatum im Kopf\n" -#: pg_backup_archiver.c:3599 +#: pg_backup_archiver.c:3595 #, c-format msgid "entering restore_toc_entries_prefork\n" msgstr "Eintritt in restore_toc_entries_prefork\n" -#: pg_backup_archiver.c:3643 +#: pg_backup_archiver.c:3639 #, c-format msgid "processing item %d %s %s\n" msgstr "verarbeite Element %d %s %s\n" -#: pg_backup_archiver.c:3695 +#: pg_backup_archiver.c:3691 #, c-format msgid "entering restore_toc_entries_parallel\n" msgstr "Eintritt in restore_toc_entries_parallel\n" -#: pg_backup_archiver.c:3743 +#: pg_backup_archiver.c:3739 #, c-format msgid "entering main parallel loop\n" msgstr "Eintritt in Hauptparallelschleife\n" -#: pg_backup_archiver.c:3754 +#: pg_backup_archiver.c:3750 #, c-format msgid "skipping item %d %s %s\n" msgstr "Element %d %s %s wird übersprungen\n" -#: pg_backup_archiver.c:3764 +#: pg_backup_archiver.c:3760 #, c-format msgid "launching item %d %s %s\n" msgstr "starte Element %d %s %s\n" -#: pg_backup_archiver.c:3822 +#: pg_backup_archiver.c:3816 #, c-format msgid "finished main parallel loop\n" msgstr "Hauptparallelschleife beendet\n" -#: pg_backup_archiver.c:3831 +#: pg_backup_archiver.c:3825 #, c-format msgid "entering restore_toc_entries_postfork\n" msgstr "Eintritt in restore_toc_entries_postfork\n" -#: pg_backup_archiver.c:3849 +#: pg_backup_archiver.c:3844 #, c-format msgid "processing missed item %d %s %s\n" msgstr "verarbeite verpasstes Element %d %s %s\n" -#: pg_backup_archiver.c:3998 +#: pg_backup_archiver.c:3993 #, c-format msgid "no item ready\n" msgstr "kein Element bereit\n" -#: pg_backup_archiver.c:4047 +#: pg_backup_archiver.c:4041 #, c-format msgid "could not find slot of finished worker\n" msgstr "konnte Slot des beendeten Arbeitsprozesses nicht finden\n" -#: pg_backup_archiver.c:4049 +#: pg_backup_archiver.c:4043 #, c-format msgid "finished item %d %s %s\n" msgstr "Element %d %s %s abgeschlossen\n" -#: pg_backup_archiver.c:4062 +#: pg_backup_archiver.c:4056 #, c-format msgid "worker process failed: exit code %d\n" msgstr "Arbeitsprozess fehlgeschlagen: Code %d\n" -#: pg_backup_archiver.c:4224 +#: pg_backup_archiver.c:4218 #, c-format msgid "transferring dependency %d -> %d to %d\n" msgstr "übertrage Abhängigkeit %d -> %d an %d\n" -#: pg_backup_archiver.c:4297 +#: pg_backup_archiver.c:4291 #, c-format msgid "reducing dependencies for %d\n" msgstr "reduziere Abhängigkeiten für %d\n" -#: pg_backup_archiver.c:4336 +#: pg_backup_archiver.c:4330 #, c-format msgid "table \"%s\" could not be created, will not restore its data\n" -msgstr "Tabelle „%s“ konnte nicht erzeugt werden, ihre Daten werden nicht wiederhergestellt werden\n" +msgstr "Tabelle »%s« konnte nicht erzeugt werden, ihre Daten werden nicht wiederhergestellt werden\n" #. translator: this is a module name #: pg_backup_custom.c:94 @@ -1000,104 +975,121 @@ msgid "WARNING: ftell mismatch with expected position -- ftell used\n" msgstr "WARNUNG: erwartete Dateiposition stimmt nicht mit ftell überein -- benutze ftell\n" #. translator: this is a module name -#: pg_backup_db.c:29 +#: pg_backup_db.c:30 msgid "archiver (db)" msgstr "Archivierer (DB)" -#: pg_backup_db.c:44 +#: pg_backup_db.c:46 #, c-format msgid "could not get server_version from libpq\n" msgstr "konnte server_version nicht von libpq ermitteln\n" -#: pg_backup_db.c:55 pg_dumpall.c:1965 +#: pg_backup_db.c:57 pg_dumpall.c:1965 #, c-format msgid "server version: %s; %s version: %s\n" msgstr "Version des Servers: %s; Version von %s: %s\n" -#: pg_backup_db.c:57 pg_dumpall.c:1967 +#: pg_backup_db.c:59 pg_dumpall.c:1967 #, c-format msgid "aborting because of server version mismatch\n" msgstr "Abbruch wegen unpassender Serverversion\n" -#: pg_backup_db.c:128 +#: pg_backup_db.c:147 #, c-format msgid "connecting to database \"%s\" as user \"%s\"\n" -msgstr "verbinde mit Datenbank „%s“ als Benutzer „%s“\n" +msgstr "verbinde mit Datenbank »%s« als Benutzer »%s«\n" -#: pg_backup_db.c:135 pg_backup_db.c:183 pg_backup_db.c:243 pg_backup_db.c:285 +#: pg_backup_db.c:154 pg_backup_db.c:202 pg_backup_db.c:262 pg_backup_db.c:304 #: pg_dumpall.c:1795 pg_dumpall.c:1903 msgid "Password: " msgstr "Passwort: " -#: pg_backup_db.c:164 +#: pg_backup_db.c:183 #, c-format msgid "failed to reconnect to database\n" msgstr "konnte nicht wieder zur Datenbank verbinden\n" -#: pg_backup_db.c:169 +#: pg_backup_db.c:188 #, c-format msgid "could not reconnect to database: %s" msgstr "konnte nicht wieder zur Datenbank verbinden: %s" -#: pg_backup_db.c:185 +#: pg_backup_db.c:204 #, c-format msgid "connection needs password\n" msgstr "Verbindung benötigt Passwort\n" -#: pg_backup_db.c:237 +#: pg_backup_db.c:256 #, c-format msgid "already connected to a database\n" msgstr "bereits mit einer Datenbank verbunden\n" -#: pg_backup_db.c:277 +#: pg_backup_db.c:296 #, c-format msgid "failed to connect to database\n" msgstr "Verbinden zur Datenbank schlug fehl\n" -#: pg_backup_db.c:294 +#: pg_backup_db.c:313 #, c-format msgid "connection to database \"%s\" failed: %s" -msgstr "Verbindung zur Datenbank „%s“ fehlgeschlagen: %s" +msgstr "Verbindung zur Datenbank »%s« fehlgeschlagen: %s" -#: pg_backup_db.c:362 +#: pg_backup_db.c:383 +#, c-format +msgid "%s" +msgstr "%s" + +#: pg_backup_db.c:390 #, c-format msgid "query failed: %s" msgstr "Anfrage fehlgeschlagen: %s" -#: pg_backup_db.c:364 +#: pg_backup_db.c:392 #, c-format msgid "query was: %s\n" msgstr "Anfrage war: %s\n" -#: pg_backup_db.c:428 +#: pg_backup_db.c:434 +#, c-format +msgid "query returned %d row instead of one: %s\n" +msgid_plural "query returned %d rows instead of one: %s\n" +msgstr[0] "Anfrage ergab %d Zeile anstatt einer: %s\n" +msgstr[1] "Anfrage ergab %d Zeilen anstatt einer: %s\n" + +#: pg_backup_db.c:479 #, c-format msgid "%s: %s Command was: %s\n" msgstr "%s: %s Die Anweisung war: %s\n" -#: pg_backup_db.c:484 pg_backup_db.c:558 pg_backup_db.c:565 +#: pg_backup_db.c:535 pg_backup_db.c:609 pg_backup_db.c:616 msgid "could not execute query" msgstr "konnte Anfrage nicht ausführen" -#: pg_backup_db.c:537 +#: pg_backup_db.c:588 #, c-format msgid "error returned by PQputCopyData: %s" msgstr "Fehler in PQputCopyData: %s" -#: pg_backup_db.c:586 +#: pg_backup_db.c:637 #, c-format msgid "error returned by PQputCopyEnd: %s" msgstr "Fehler in PQputCopyEnd: %s" -#: pg_backup_db.c:592 +#: pg_backup_db.c:643 #, c-format msgid "COPY failed for table \"%s\": %s" -msgstr "COPY fehlgeschlagen für Tabelle „%s“: %s" +msgstr "COPY fehlgeschlagen für Tabelle »%s«: %s" + +#: pg_backup_db.c:649 pg_dump.c:1681 +#, c-format +msgid "WARNING: unexpected extra results during COPY of table \"%s\"\n" +msgstr "WARNUNG: unerwartete zusätzliche Ergebnisse während COPY von Tabelle »%s«\n" -#: pg_backup_db.c:605 +#: pg_backup_db.c:661 msgid "could not start database transaction" msgstr "konnte Datenbanktransaktion nicht starten" -#: pg_backup_db.c:613 +#: pg_backup_db.c:669 msgid "could not commit database transaction" msgstr "konnte Datenbanktransaktion nicht beenden" @@ -1114,54 +1106,54 @@ msgstr "kein Ausgabeverzeichnis angegeben\n" #: pg_backup_directory.c:191 #, c-format msgid "could not read directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht lesen: %s\n" #: pg_backup_directory.c:195 #, c-format msgid "could not close directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht schließen: %s\n" #: pg_backup_directory.c:201 #, c-format msgid "could not create directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht erzeugen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht erzeugen: %s\n" -#: pg_backup_directory.c:413 +#: pg_backup_directory.c:412 #, c-format msgid "could not close data file: %s\n" msgstr "konnte Datendatei nicht schließen: %s\n" -#: pg_backup_directory.c:454 +#: pg_backup_directory.c:453 #, c-format msgid "could not open large object TOC file \"%s\" for input: %s\n" -msgstr "konnte Large-Object-Inhaltsverzeichnisdatei „%s“ nicht zur Eingabe öffnen: %s\n" +msgstr "konnte Large-Object-Inhaltsverzeichnisdatei »%s« nicht zur Eingabe öffnen: %s\n" -#: pg_backup_directory.c:465 +#: pg_backup_directory.c:464 #, c-format msgid "invalid line in large object TOC file \"%s\": \"%s\"\n" -msgstr "ungültige Zeile in Large-Object-Inhaltsverzeichnisdatei „%s“: %s\n" +msgstr "ungültige Zeile in Large-Object-Inhaltsverzeichnisdatei »%s«: %s\n" -#: pg_backup_directory.c:474 +#: pg_backup_directory.c:473 #, c-format msgid "error reading large object TOC file \"%s\"\n" -msgstr "Fehler beim Lesen von Large-Object-Inhaltsverzeichnisdatei „%s“\n" +msgstr "Fehler beim Lesen von Large-Object-Inhaltsverzeichnisdatei »%s«\n" -#: pg_backup_directory.c:478 +#: pg_backup_directory.c:477 #, c-format msgid "could not close large object TOC file \"%s\": %s\n" -msgstr "konnte Large-Object-Inhaltsverzeichnisdatei „%s“ nicht schließen: %s\n" +msgstr "konnte Large-Object-Inhaltsverzeichnisdatei »%s« nicht schließen: %s\n" -#: pg_backup_directory.c:688 +#: pg_backup_directory.c:684 #, c-format msgid "could not write to blobs TOC file\n" msgstr "konnte nicht in Blobs-Inhaltsverzeichnisdatei schreiben\n" -#: pg_backup_directory.c:720 +#: pg_backup_directory.c:716 #, c-format msgid "file name too long: \"%s\"\n" -msgstr "Dateiname zu lang: „%s“\n" +msgstr "Dateiname zu lang: »%s«\n" -#: pg_backup_directory.c:806 +#: pg_backup_directory.c:802 #, c-format msgid "error during backup\n" msgstr "Fehler bei der Sicherung\n" @@ -1179,7 +1171,7 @@ msgstr "Tar-Archivierer" #: pg_backup_tar.c:182 #, c-format msgid "could not open TOC file \"%s\" for output: %s\n" -msgstr "konnte Inhaltsverzeichnisdatei „%s“ nicht zur Ausgabe öffnen: %s\n" +msgstr "konnte Inhaltsverzeichnisdatei »%s« nicht zur Ausgabe öffnen: %s\n" #: pg_backup_tar.c:190 #, c-format @@ -1194,7 +1186,7 @@ msgstr "Komprimierung ist im Tar-Format nicht unterstützt\n" #: pg_backup_tar.c:219 #, c-format msgid "could not open TOC file \"%s\" for input: %s\n" -msgstr "konnte Inhaltsverzeichnisdatei „%s“ nicht zur Eingabe öffnen: %s\n" +msgstr "konnte Inhaltsverzeichnisdatei »%s« nicht zur Eingabe öffnen: %s\n" #: pg_backup_tar.c:226 #, c-format @@ -1204,7 +1196,7 @@ msgstr "konnte Inhaltsverzeichnisdatei nicht zur Eingabe öffnen: %s\n" #: pg_backup_tar.c:353 #, c-format msgid "could not find file \"%s\" in archive\n" -msgstr "konnte Datei „%s“ nicht im Archiv finden\n" +msgstr "konnte Datei »%s« nicht im Archiv finden\n" #: pg_backup_tar.c:419 #, c-format @@ -1229,7 +1221,7 @@ msgstr "interner Fehler -- weder th noch fh in tarReadRaw() angegeben\n" #: pg_backup_tar.c:693 #, c-format msgid "unexpected COPY statement syntax: \"%s\"\n" -msgstr "unerwartete Syntax der COPY-Anweisung: „%s“\n" +msgstr "unerwartete Syntax der COPY-Anweisung: »%s«\n" #: pg_backup_tar.c:959 #, c-format @@ -1259,7 +1251,7 @@ msgstr "jetzt bei Dateiposition %s\n" #: pg_backup_tar.c:1170 pg_backup_tar.c:1200 #, c-format msgid "could not find header for file \"%s\" in tar archive\n" -msgstr "konnte Kopf für Datei „%s“ im Tar-Archiv nicht finden\n" +msgstr "konnte Kopf für Datei »%s« im Tar-Archiv nicht finden\n" #: pg_backup_tar.c:1184 #, c-format @@ -1269,7 +1261,7 @@ msgstr "Tar-Mitglied %s übersprungen\n" #: pg_backup_tar.c:1188 #, 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.\n" -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.\n" +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.\n" #: pg_backup_tar.c:1234 #, c-format @@ -1291,66 +1283,71 @@ msgstr "beschädigter Tar-Kopf in %s gefunden (%d erwartet, %d berechnet), Datei #: pg_backup_utils.c:54 #, c-format msgid "%s: unrecognized section name: \"%s\"\n" -msgstr "%s: unbekannter Abschnittsname: „%s“\n" +msgstr "%s: unbekannter Abschnittsname: »%s«\n" -#: pg_backup_utils.c:56 pg_dump.c:524 pg_dump.c:541 pg_dumpall.c:300 +#: pg_backup_utils.c:56 pg_dump.c:523 pg_dump.c:540 pg_dumpall.c:300 #: pg_dumpall.c:310 pg_dumpall.c:320 pg_dumpall.c:329 pg_dumpall.c:345 #: pg_dumpall.c:403 pg_restore.c:277 pg_restore.c:293 pg_restore.c:305 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" -#: pg_backup_utils.c:101 +#: pg_backup_utils.c:118 #, c-format msgid "out of on_exit_nicely slots\n" msgstr "on_exit_nicely-Slots aufgebraucht\n" -#: pg_dump.c:494 +#: pg_dump.c:493 #, c-format msgid "compression level must be in range 0..9\n" msgstr "Komprimierungsniveau muss im Bereich 0..9 sein\n" -#: pg_dump.c:539 pg_dumpall.c:308 pg_restore.c:291 +#: pg_dump.c:538 pg_dumpall.c:308 pg_restore.c:291 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" -#: pg_dump.c:552 +#: pg_dump.c:551 #, c-format msgid "options -s/--schema-only and -a/--data-only cannot be used together\n" msgstr "Optionen -s/--schema-only und -a/--data-only können nicht zusammen verwendet werden\n" -#: pg_dump.c:558 +#: pg_dump.c:557 #, c-format msgid "options -c/--clean and -a/--data-only cannot be used together\n" msgstr "Optionen -c/--clean und -a/--data-only können nicht zusammen verwendet werden\n" -#: pg_dump.c:564 +#: pg_dump.c:563 #, c-format msgid "options --inserts/--column-inserts and -o/--oids cannot be used together\n" msgstr "Optionen --inserts/--column-inserts und -o/--oids können nicht zusammen verwendet werden\n" -#: pg_dump.c:565 +#: pg_dump.c:564 #, c-format msgid "(The INSERT command cannot set OIDs.)\n" msgstr "(Die INSERT-Anweisung kann OIDs nicht setzen.)\n" -#: pg_dump.c:570 +#: pg_dump.c:569 #, c-format msgid "option --if-exists requires option -c/--clean\n" msgstr "Option --if-exists benötigt Option -c/--clean\n" -#: pg_dump.c:598 +#: pg_dump.c:591 +#, c-format +msgid "WARNING: requested compression not available in this installation -- archive will be uncompressed\n" +msgstr "WARNUNG: Komprimierung ist in dieser Installation nicht verfügbar -- Archiv wird nicht komprimiert\n" + +#: pg_dump.c:606 #, c-format msgid "%s: invalid number of parallel jobs\n" msgstr "%s: ungültige Anzahl paralleler Jobs\n" -#: pg_dump.c:602 +#: pg_dump.c:610 #, c-format msgid "parallel backup only supported by the directory format\n" -msgstr "parallele Sicherung wird nur vom Ausgabeformat „Verzeichnis“ unterstützt\n" +msgstr "parallele Sicherung wird nur vom Ausgabeformat »Verzeichnis« unterstützt\n" -#: pg_dump.c:671 +#: pg_dump.c:667 #, c-format msgid "" "Synchronized snapshots are not supported by this server version.\n" @@ -1361,27 +1358,27 @@ msgstr "" "Verwenden Sie --no-synchronized-snapshots, wenn Sie keine synchronisierten\n" "Snapshots benötigen.\n" -#: pg_dump.c:678 +#: pg_dump.c:674 #, c-format msgid "Exported snapshots are not supported by this server version.\n" msgstr "Exportierte Snapshots werden in dieser Serverversion nicht unterstützt.\n" -#: pg_dump.c:689 +#: pg_dump.c:685 #, c-format msgid "last built-in OID is %u\n" msgstr "letzte eingebaute OID ist %u\n" -#: pg_dump.c:698 +#: pg_dump.c:694 #, c-format msgid "No matching schemas were found\n" msgstr "Keine passenden Schemas gefunden\n" -#: pg_dump.c:710 +#: pg_dump.c:706 #, c-format msgid "No matching tables were found\n" msgstr "Keine passenden Tabellen gefunden\n" -#: pg_dump.c:867 +#: pg_dump.c:863 #, c-format msgid "" "%s dumps a database as a text file or to other formats.\n" @@ -1390,17 +1387,17 @@ msgstr "" "%s gibt eine Datenbank als Textdatei oder in anderen Formaten aus.\n" "\n" -#: pg_dump.c:868 pg_dumpall.c:548 pg_restore.c:434 +#: pg_dump.c:864 pg_dumpall.c:548 pg_restore.c:434 #, c-format msgid "Usage:\n" msgstr "Aufruf:\n" -#: pg_dump.c:869 +#: pg_dump.c:865 #, c-format msgid " %s [OPTION]... [DBNAME]\n" msgstr " %s [OPTION]... [DBNAME]\n" -#: pg_dump.c:871 pg_dumpall.c:551 pg_restore.c:437 +#: pg_dump.c:867 pg_dumpall.c:551 pg_restore.c:437 #, c-format msgid "" "\n" @@ -1409,12 +1406,12 @@ msgstr "" "\n" "Allgemeine Optionen:\n" -#: pg_dump.c:872 +#: pg_dump.c:868 #, c-format msgid " -f, --file=FILENAME output file or directory name\n" msgstr " -f, --file=DATEINAME Name der Ausgabedatei oder des -verzeichnisses\n" -#: pg_dump.c:873 +#: pg_dump.c:869 #, c-format msgid "" " -F, --format=c|d|t|p output file format (custom, directory, tar,\n" @@ -1423,37 +1420,37 @@ msgstr "" " -F, --format=c|d|t|p Ausgabeformat (custom, d=Verzeichnis, tar,\n" " plain text)\n" -#: pg_dump.c:875 +#: pg_dump.c:871 #, c-format msgid " -j, --jobs=NUM use this many parallel jobs to dump\n" msgstr " -j, --jobs=NUM so viele parallele Jobs zur Sicherung verwenden\n" -#: pg_dump.c:876 +#: pg_dump.c:872 #, c-format msgid " -v, --verbose verbose mode\n" -msgstr " -v, --verbose „Verbose“-Modus\n" +msgstr " -v, --verbose »Verbose«-Modus\n" -#: pg_dump.c:877 pg_dumpall.c:553 +#: pg_dump.c:873 pg_dumpall.c:553 #, c-format msgid " -V, --version output version information, then exit\n" msgstr " -V, --version Versionsinformationen anzeigen, dann beenden\n" -#: pg_dump.c:878 +#: pg_dump.c:874 #, c-format msgid " -Z, --compress=0-9 compression level for compressed formats\n" msgstr " -Z, --compress=0-9 Komprimierungsniveau für komprimierte Formate\n" -#: pg_dump.c:879 pg_dumpall.c:554 +#: pg_dump.c:875 pg_dumpall.c:554 #, c-format msgid " --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" msgstr " --lock-wait-timeout=ZEIT Abbruch nach ZEIT Warten auf Tabellensperre\n" -#: pg_dump.c:880 pg_dumpall.c:555 +#: pg_dump.c:876 pg_dumpall.c:555 #, c-format msgid " -?, --help show this help, then exit\n" msgstr " -?, --help diese Hilfe anzeigen, dann beenden\n" -#: pg_dump.c:882 pg_dumpall.c:556 +#: pg_dump.c:878 pg_dumpall.c:556 #, c-format msgid "" "\n" @@ -1462,109 +1459,109 @@ msgstr "" "\n" "Optionen die den Inhalt der Ausgabe kontrollieren:\n" -#: pg_dump.c:883 pg_dumpall.c:557 +#: pg_dump.c:879 pg_dumpall.c:557 #, c-format msgid " -a, --data-only dump only the data, not the schema\n" msgstr " -a, --data-only nur Daten ausgeben, nicht das Schema\n" -#: pg_dump.c:884 +#: pg_dump.c:880 #, c-format msgid " -b, --blobs include large objects in dump\n" msgstr " -b, --blobs Large Objects mit ausgeben\n" -#: pg_dump.c:885 pg_restore.c:448 +#: pg_dump.c:881 pg_restore.c:448 #, c-format msgid " -c, --clean clean (drop) database objects before recreating\n" msgstr " -c, --clean Datenbankobjekte vor der Wiedererstellung löschen\n" -#: pg_dump.c:886 +#: pg_dump.c:882 #, c-format msgid " -C, --create include commands to create database in dump\n" msgstr "" " -C, --create Anweisungen zum Erstellen der Datenbank in\n" " Ausgabe einfügen\n" -#: pg_dump.c:887 +#: pg_dump.c:883 #, c-format msgid " -E, --encoding=ENCODING dump the data in encoding ENCODING\n" msgstr " -E, --encoding=KODIERUNG Daten in Kodierung KODIERUNG ausgeben\n" -#: pg_dump.c:888 +#: pg_dump.c:884 #, c-format msgid " -n, --schema=SCHEMA dump the named schema(s) only\n" msgstr " -n, --schema=SCHEMA nur das/die angegebene(n) Schema(s) ausgeben\n" -#: pg_dump.c:889 +#: pg_dump.c:885 #, c-format msgid " -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n" msgstr " -N, --exclude-schema=SCHEMA das/die angegebene(n) Schema(s) NICHT ausgeben\n" -#: pg_dump.c:890 pg_dumpall.c:560 +#: pg_dump.c:886 pg_dumpall.c:560 #, c-format msgid " -o, --oids include OIDs in dump\n" msgstr " -o, --oids OIDs mit ausgeben\n" -#: pg_dump.c:891 +#: pg_dump.c:887 #, c-format msgid "" " -O, --no-owner skip restoration of object ownership in\n" " plain-text format\n" msgstr "" " -O, --no-owner Wiederherstellung der Objekteigentümerschaft im\n" -" „plain text“-Format auslassen\n" +" »plain text«-Format auslassen\n" -#: pg_dump.c:893 pg_dumpall.c:563 +#: pg_dump.c:889 pg_dumpall.c:563 #, c-format msgid " -s, --schema-only dump only the schema, no data\n" msgstr " -s, --schema-only nur das Schema, nicht die Daten, ausgeben\n" -#: pg_dump.c:894 +#: pg_dump.c:890 #, c-format msgid " -S, --superuser=NAME superuser user name to use in plain-text format\n" -msgstr " -S, --superuser=NAME Superusername für „plain text“-Format\n" +msgstr " -S, --superuser=NAME Superusername für »plain text«-Format\n" -#: pg_dump.c:895 +#: pg_dump.c:891 #, c-format msgid " -t, --table=TABLE dump the named table(s) only\n" msgstr " -t, --table=TABELLE nur die angegebene(n) Tabelle(n) ausgeben\n" -#: pg_dump.c:896 +#: pg_dump.c:892 #, c-format msgid " -T, --exclude-table=TABLE do NOT dump the named table(s)\n" msgstr " -T, --exclude-table=TABELLE die angegebene(n) Tabelle(n) NICHT ausgeben\n" -#: pg_dump.c:897 pg_dumpall.c:566 +#: pg_dump.c:893 pg_dumpall.c:566 #, c-format msgid " -x, --no-privileges do not dump privileges (grant/revoke)\n" msgstr " -x, --no-privileges Zugriffsprivilegien (grant/revoke) nicht ausgeben\n" -#: pg_dump.c:898 pg_dumpall.c:567 +#: pg_dump.c:894 pg_dumpall.c:567 #, c-format msgid " --binary-upgrade for use by upgrade utilities only\n" msgstr " --binary-upgrade wird nur von Upgrade-Programmen verwendet\n" -#: pg_dump.c:899 pg_dumpall.c:568 +#: pg_dump.c:895 pg_dumpall.c:568 #, c-format msgid " --column-inserts dump data as INSERT commands with column names\n" msgstr "" " --column-inserts Daten als INSERT-Anweisungen mit Spaltennamen\n" " ausgeben\n" -#: pg_dump.c:900 pg_dumpall.c:569 +#: pg_dump.c:896 pg_dumpall.c:569 #, c-format msgid " --disable-dollar-quoting disable dollar quoting, use SQL standard quoting\n" msgstr "" " --disable-dollar-quoting Dollar-Quoting abschalten, normales SQL-Quoting\n" " verwenden\n" -#: pg_dump.c:901 pg_dumpall.c:570 pg_restore.c:464 +#: pg_dump.c:897 pg_dumpall.c:570 pg_restore.c:464 #, c-format msgid " --disable-triggers disable triggers during data-only restore\n" msgstr "" " --disable-triggers Trigger während der Datenwiederherstellung\n" " abschalten\n" -#: pg_dump.c:902 +#: pg_dump.c:898 #, c-format msgid "" " --enable-row-security enable row security (dump only content user has\n" @@ -1573,68 +1570,68 @@ msgstr "" " --enable-row-security Sicherheit auf Zeilenebene einschalten (nur Daten\n" " ausgeben, auf die der Benutzer Zugriff hat)\n" -#: pg_dump.c:904 +#: pg_dump.c:900 #, c-format msgid " --exclude-table-data=TABLE do NOT dump data for the named table(s)\n" msgstr " --exclude-table-data=TABELLE Daten der angegebenen Tabelle(n) NICHT ausgeben\n" -#: pg_dump.c:905 pg_dumpall.c:571 pg_restore.c:466 +#: pg_dump.c:901 pg_dumpall.c:571 pg_restore.c:466 #, c-format msgid " --if-exists use IF EXISTS when dropping objects\n" msgstr " --if-exists IF EXISTS verwenden, wenn Objekte gelöscht werden\n" -#: pg_dump.c:906 pg_dumpall.c:572 +#: pg_dump.c:902 pg_dumpall.c:572 #, c-format msgid " --inserts dump data as INSERT commands, rather than COPY\n" msgstr " --inserts Daten als INSERT-Anweisungen statt COPY ausgeben\n" -#: pg_dump.c:907 pg_dumpall.c:573 +#: pg_dump.c:903 pg_dumpall.c:573 #, c-format msgid " --no-security-labels do not dump security label assignments\n" msgstr " --no-security-labels Security-Label-Zuweisungen nicht ausgeben\n" -#: pg_dump.c:908 +#: pg_dump.c:904 #, c-format msgid " --no-synchronized-snapshots do not use synchronized snapshots in parallel jobs\n" msgstr "" " --no-synchronized-snapshots keine synchronisierten Snapshots in parallelen\n" " Jobs verwenden\n" -#: pg_dump.c:909 pg_dumpall.c:574 +#: pg_dump.c:905 pg_dumpall.c:574 #, c-format msgid " --no-tablespaces do not dump tablespace assignments\n" msgstr " --no-tablespaces Tablespace-Zuordnungen nicht ausgeben\n" -#: pg_dump.c:910 pg_dumpall.c:575 +#: pg_dump.c:906 pg_dumpall.c:575 #, c-format msgid " --no-unlogged-table-data do not dump unlogged table data\n" msgstr " --no-unlogged-table-data Daten in ungeloggten Tabellen nicht ausgeben\n" -#: pg_dump.c:911 pg_dumpall.c:576 +#: pg_dump.c:907 pg_dumpall.c:576 #, c-format msgid " --quote-all-identifiers quote all identifiers, even if not key words\n" msgstr "" " --quote-all-identifiers alle Bezeichner in Anführungszeichen, selbst wenn\n" " kein Schlüsselwort\n" -#: pg_dump.c:912 +#: pg_dump.c:908 #, c-format msgid " --section=SECTION dump named section (pre-data, data, or post-data)\n" msgstr "" " --section=ABSCHNITT angegebenen Abschnitt ausgeben (pre-data, data\n" " oder post-data)\n" -#: pg_dump.c:913 +#: pg_dump.c:909 #, c-format msgid " --serializable-deferrable wait until the dump can run without anomalies\n" msgstr " --serializable-deferrable warten bis der Dump ohne Anomalien laufen kann\n" -#: pg_dump.c:914 +#: pg_dump.c:910 #, c-format msgid " --snapshot=SNAPSHOT use given snapshot for the dump\n" msgstr " --snapshot=SNAPSHOT angegebenen Snapshot für den Dump verwenden\n" -#: pg_dump.c:915 pg_dumpall.c:577 pg_restore.c:472 +#: pg_dump.c:911 pg_dumpall.c:577 pg_restore.c:472 #, c-format msgid "" " --use-set-session-authorization\n" @@ -1646,7 +1643,7 @@ msgstr "" " OWNER Befehle verwenden, um Eigentümerschaft zu\n" " setzen\n" -#: pg_dump.c:919 pg_dumpall.c:581 pg_restore.c:476 +#: pg_dump.c:915 pg_dumpall.c:581 pg_restore.c:476 #, c-format msgid "" "\n" @@ -1655,42 +1652,42 @@ msgstr "" "\n" "Verbindungsoptionen:\n" -#: pg_dump.c:920 +#: pg_dump.c:916 #, c-format msgid " -d, --dbname=DBNAME database to dump\n" msgstr " -d, --dbname=DBNAME auszugebende Datenbank\n" -#: pg_dump.c:921 pg_dumpall.c:583 pg_restore.c:477 +#: pg_dump.c:917 pg_dumpall.c:583 pg_restore.c:477 #, c-format msgid " -h, --host=HOSTNAME database server host or socket directory\n" msgstr " -h, --host=HOSTNAME Name des Datenbankservers oder Socket-Verzeichnis\n" -#: pg_dump.c:922 pg_dumpall.c:585 pg_restore.c:478 +#: pg_dump.c:918 pg_dumpall.c:585 pg_restore.c:478 #, c-format msgid " -p, --port=PORT database server port number\n" msgstr " -p, --port=PORT Portnummer des Datenbankservers\n" -#: pg_dump.c:923 pg_dumpall.c:586 pg_restore.c:479 +#: pg_dump.c:919 pg_dumpall.c:586 pg_restore.c:479 #, c-format msgid " -U, --username=NAME connect as specified database user\n" msgstr " -U, --username=NAME Datenbankbenutzername\n" -#: pg_dump.c:924 pg_dumpall.c:587 pg_restore.c:480 +#: pg_dump.c:920 pg_dumpall.c:587 pg_restore.c:480 #, c-format msgid " -w, --no-password never prompt for password\n" msgstr " -w, --no-password niemals nach Passwort fragen\n" -#: pg_dump.c:925 pg_dumpall.c:588 pg_restore.c:481 +#: pg_dump.c:921 pg_dumpall.c:588 pg_restore.c:481 #, c-format msgid " -W, --password force password prompt (should happen automatically)\n" msgstr " -W, --password nach Passwort fragen (sollte automatisch geschehen)\n" -#: pg_dump.c:926 pg_dumpall.c:589 +#: pg_dump.c:922 pg_dumpall.c:589 #, c-format msgid " --role=ROLENAME do SET ROLE before dump\n" msgstr " --role=ROLLENNAME vor der Ausgabe SET ROLE ausführen\n" -#: pg_dump.c:928 +#: pg_dump.c:924 #, c-format msgid "" "\n" @@ -1703,367 +1700,371 @@ msgstr "" "PGDATABASE verwendet.\n" "\n" -#: pg_dump.c:930 pg_dumpall.c:593 pg_restore.c:488 +#: pg_dump.c:926 pg_dumpall.c:593 pg_restore.c:488 #, c-format msgid "Report bugs to .\n" msgstr "Berichten Sie Fehler an .\n" -#: pg_dump.c:950 +#: pg_dump.c:943 #, c-format msgid "invalid client encoding \"%s\" specified\n" -msgstr "ungültige Clientkodierung „%s“ angegeben\n" +msgstr "ungültige Clientkodierung »%s« angegeben\n" -#: pg_dump.c:1135 +#: pg_dump.c:1083 +#, c-format +msgid "" +"Synchronized snapshots are not supported on standby servers.\n" +"Run with --no-synchronized-snapshots instead if you do not need\n" +"synchronized snapshots.\n" +msgstr "" +"Synchronisierte Snapshots werden auf Standby-Servern nicht unterstützt.\n" +"Verwenden Sie --no-synchronized-snapshots, wenn Sie keine synchronisierten\n" +"Snapshots benötigen.\n" + +#: pg_dump.c:1152 #, c-format msgid "invalid output format \"%s\" specified\n" -msgstr "ungültiges Ausgabeformat „%s“ angegeben\n" +msgstr "ungültiges Ausgabeformat »%s« angegeben\n" -#: pg_dump.c:1157 +#: pg_dump.c:1174 #, c-format msgid "server version must be at least 7.3 to use schema selection switches\n" msgstr "Serverversion muss mindestens 7.3 sein um Schemas auswählen zu können\n" -#: pg_dump.c:1521 +#: pg_dump.c:1538 #, c-format msgid "dumping contents of table \"%s.%s\"\n" -msgstr "gebe Inhalt der Tabelle „%s.%s“ aus\n" +msgstr "gebe Inhalt der Tabelle »%s.%s« aus\n" -#: pg_dump.c:1645 +#: pg_dump.c:1662 #, c-format msgid "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n" -msgstr "Ausgabe des Inhalts der Tabelle „%s“ fehlgeschlagen: PQgetCopyData() fehlgeschlagen.\n" +msgstr "Ausgabe des Inhalts der Tabelle »%s« fehlgeschlagen: PQgetCopyData() fehlgeschlagen.\n" -#: pg_dump.c:1646 pg_dump.c:1656 +#: pg_dump.c:1663 pg_dump.c:1673 #, c-format msgid "Error message from server: %s" msgstr "Fehlermeldung vom Server: %s" -#: pg_dump.c:1647 pg_dump.c:1657 +#: pg_dump.c:1664 pg_dump.c:1674 #, c-format msgid "The command was: %s\n" msgstr "Die Anweisung war: %s\n" -#: pg_dump.c:1655 +#: pg_dump.c:1672 #, c-format msgid "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n" -msgstr "Ausgabe des Inhalts der Tabelle „%s“ fehlgeschlagen: PQgetResult() fehlgeschlagen.\n" +msgstr "Ausgabe des Inhalts der Tabelle »%s« fehlgeschlagen: PQgetResult() fehlgeschlagen.\n" -#: pg_dump.c:2297 +#: pg_dump.c:2319 #, c-format msgid "saving database definition\n" msgstr "sichere Datenbankdefinition\n" -#: pg_dump.c:2630 +#: pg_dump.c:2652 #, c-format msgid "saving encoding = %s\n" msgstr "sichere Kodierung = %s\n" -#: pg_dump.c:2657 +#: pg_dump.c:2679 #, c-format msgid "saving standard_conforming_strings = %s\n" msgstr "sichere standard_conforming_strings = %s\n" -#: pg_dump.c:2690 +#: pg_dump.c:2712 #, c-format msgid "reading large objects\n" msgstr "lese Large Objects\n" -#: pg_dump.c:2822 +#: pg_dump.c:2844 #, c-format msgid "saving large objects\n" msgstr "sichere Large Objects\n" -#: pg_dump.c:2869 +#: pg_dump.c:2891 #, c-format msgid "error reading large object %u: %s" msgstr "Fehler beim Lesen von Large Object %u: %s" -#: pg_dump.c:2921 +#: pg_dump.c:2943 #, c-format msgid "reading row security enabled for table \"%s.%s\"\n" -msgstr "lese Einstellung von Sicherheit auf Zeilenebene für Tabelle „%s.%s“\n" +msgstr "lese Einstellung von Sicherheit auf Zeilenebene für Tabelle »%s.%s«\n" -#: pg_dump.c:2952 +#: pg_dump.c:2974 #, c-format msgid "reading policies for table \"%s.%s\"\n" -msgstr "lese Policys von Tabelle „%s.%s“\n" +msgstr "lese Policys von Tabelle »%s.%s«\n" -#: pg_dump.c:3083 +#: pg_dump.c:3105 #, c-format msgid "unexpected policy command type: \"%s\"\n" -msgstr "unerwarteter Policy-Befehlstyp: „%s“\n" +msgstr "unerwarteter Policy-Befehlstyp: »%s«\n" -#: pg_dump.c:3298 +#: pg_dump.c:3320 #, c-format msgid "could not find parent extension for %s\n" msgstr "konnte Erweiterung, zu der %s gehört, nicht finden\n" -#: pg_dump.c:3402 +#: pg_dump.c:3424 #, c-format msgid "WARNING: owner of schema \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer des Schemas „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer des Schemas »%s« scheint ungültig zu sein\n" -#: pg_dump.c:3445 +#: pg_dump.c:3467 #, c-format msgid "schema with OID %u does not exist\n" msgstr "Schema mit OID %u existiert nicht\n" -#: pg_dump.c:3797 +#: pg_dump.c:3819 #, c-format msgid "WARNING: owner of data type \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer des Datentypen „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer des Datentypen »%s« scheint ungültig zu sein\n" -#: pg_dump.c:3909 +#: pg_dump.c:3931 #, c-format msgid "WARNING: owner of operator \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer des Operatoren „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer des Operatoren »%s« scheint ungültig zu sein\n" -#: pg_dump.c:4171 +#: pg_dump.c:4193 #, c-format msgid "WARNING: owner of operator class \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer der Operatorklasse „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer der Operatorklasse »%s« scheint ungültig zu sein\n" -#: pg_dump.c:4260 +#: pg_dump.c:4282 #, c-format msgid "WARNING: owner of operator family \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer der Operatorfamilie „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer der Operatorfamilie »%s« scheint ungültig zu sein\n" -#: pg_dump.c:4399 +#: pg_dump.c:4421 #, c-format msgid "WARNING: owner of aggregate function \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer der Aggregatfunktion „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer der Aggregatfunktion »%s« scheint ungültig zu sein\n" -#: pg_dump.c:4582 +#: pg_dump.c:4604 #, c-format msgid "WARNING: owner of function \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer der Funktion „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer der Funktion »%s« scheint ungültig zu sein\n" -#: pg_dump.c:5270 +#: pg_dump.c:5292 #, c-format msgid "WARNING: owner of table \"%s\" appears to be invalid\n" -msgstr "WARNUNG: Eigentümer der Tabelle „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: Eigentümer der Tabelle »%s« scheint ungültig zu sein\n" -#: pg_dump.c:5422 +#: pg_dump.c:5444 #, c-format msgid "reading indexes for table \"%s.%s\"\n" -msgstr "lese Indexe von Tabelle „%s.%s“\n" +msgstr "lese Indexe von Tabelle »%s.%s«\n" -#: pg_dump.c:5789 +#: pg_dump.c:5811 #, c-format msgid "reading foreign key constraints for table \"%s.%s\"\n" -msgstr "lese Fremdschlüssel-Constraints von Tabelle „%s.%s“\n" +msgstr "lese Fremdschlüssel-Constraints von Tabelle »%s.%s«\n" -#: pg_dump.c:6035 +#: pg_dump.c:6057 #, c-format msgid "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n" msgstr "Sanity-Check fehlgeschlagen, Elterntabelle %u von pg_rewrite-Eintrag OID %u nicht gefunden\n" -#: pg_dump.c:6128 +#: pg_dump.c:6150 #, c-format msgid "reading triggers for table \"%s.%s\"\n" -msgstr "lese Trigger von Tabelle „%s.%s“\n" +msgstr "lese Trigger von Tabelle »%s.%s«\n" -#: pg_dump.c:6293 +#: pg_dump.c:6315 #, c-format msgid "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n" -msgstr "Anfrage ergab NULL als Name der Tabelle auf die sich Fremdschlüssel-Trigger „%s“ von Tabelle „%s“ bezieht (OID der Tabelle: %u)\n" +msgstr "Anfrage ergab NULL als Name der Tabelle auf die sich Fremdschlüssel-Trigger »%s« von Tabelle »%s« bezieht (OID der Tabelle: %u)\n" -#: pg_dump.c:6879 +#: pg_dump.c:6901 #, c-format msgid "finding the columns and types of table \"%s.%s\"\n" -msgstr "finde Spalten und Typen von Tabelle „%s.%s“\n" +msgstr "finde Spalten und Typen von Tabelle »%s.%s«\n" -#: pg_dump.c:7058 +#: pg_dump.c:7080 #, c-format msgid "invalid column numbering in table \"%s\"\n" -msgstr "ungültige Spaltennummerierung in Tabelle „%s“\n" +msgstr "ungültige Spaltennummerierung in Tabelle »%s«\n" -#: pg_dump.c:7092 +#: pg_dump.c:7114 #, c-format msgid "finding default expressions of table \"%s.%s\"\n" -msgstr "finde DEFAULT-Ausdrücke von Tabelle „%s.%s“\n" +msgstr "finde DEFAULT-Ausdrücke von Tabelle »%s.%s«\n" -#: pg_dump.c:7145 +#: pg_dump.c:7167 #, c-format msgid "invalid adnum value %d for table \"%s\"\n" -msgstr "ungültiger adnum-Wert %d für Tabelle „%s“\n" +msgstr "ungültiger adnum-Wert %d für Tabelle »%s«\n" -#: pg_dump.c:7217 +#: pg_dump.c:7239 #, c-format msgid "finding check constraints for table \"%s.%s\"\n" -msgstr "finde Check-Constraints für Tabelle „%s.%s“\n" +msgstr "finde Check-Constraints für Tabelle »%s.%s«\n" -#: pg_dump.c:7313 +#: pg_dump.c:7335 #, c-format msgid "expected %d check constraint on table \"%s\" but found %d\n" msgid_plural "expected %d check constraints on table \"%s\" but found %d\n" msgstr[0] "%d Check-Constraint für Tabelle %s erwartet, aber %d gefunden\n" msgstr[1] "%d Check-Constraints für Tabelle %s erwartet, aber %d gefunden\n" -#: pg_dump.c:7317 +#: pg_dump.c:7339 #, c-format msgid "(The system catalogs might be corrupted.)\n" msgstr "(Die Systemkataloge sind wahrscheinlich verfälscht.)\n" -#: pg_dump.c:8707 +#: pg_dump.c:8729 #, c-format msgid "WARNING: typtype of data type \"%s\" appears to be invalid\n" -msgstr "WARNUNG: typtype des Datentypen „%s“ scheint ungültig zu sein\n" +msgstr "WARNUNG: typtype des Datentypen »%s« scheint ungültig zu sein\n" -#: pg_dump.c:10203 +#: pg_dump.c:10225 #, c-format msgid "WARNING: bogus value in proargmodes array\n" msgstr "WARNUNG: unsinniger Wert in proargmodes-Array\n" -#: pg_dump.c:10555 +#: pg_dump.c:10577 #, c-format msgid "WARNING: could not parse proallargtypes array\n" msgstr "WARNUNG: konnte proallargtypes-Array nicht interpretieren\n" -#: pg_dump.c:10571 +#: pg_dump.c:10593 #, c-format msgid "WARNING: could not parse proargmodes array\n" msgstr "WARNUNG: konnte proargmodes-Array nicht interpretieren\n" -#: pg_dump.c:10585 +#: pg_dump.c:10607 #, c-format msgid "WARNING: could not parse proargnames array\n" msgstr "WARNUNG: konnte proargnames-Array nicht interpretieren\n" -#: pg_dump.c:10596 +#: pg_dump.c:10618 #, c-format msgid "WARNING: could not parse proconfig array\n" msgstr "WARNUNG: konnte proconfig-Array nicht interpretieren\n" -#: pg_dump.c:10667 +#: pg_dump.c:10689 #, c-format msgid "unrecognized provolatile value for function \"%s\"\n" -msgstr "ungültiger provolatile-Wert für Funktion „%s“\n" +msgstr "ungültiger provolatile-Wert für Funktion »%s«\n" -#: pg_dump.c:10844 +#: pg_dump.c:10866 #, c-format msgid "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n" msgstr "WARNUNG: unsinniger Wert in Feld pg_cast.castfunc oder pg_cast.castmethod\n" -#: pg_dump.c:10847 +#: pg_dump.c:10869 #, c-format msgid "WARNING: bogus value in pg_cast.castmethod field\n" msgstr "WARNUNG: unsinniger Wert in Feld pg_cast.castmethod\n" -#: pg_dump.c:10931 +#: pg_dump.c:10953 #, c-format msgid "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n" msgstr "WARNUNG: unsinnige Transformationsdefinition, mindestens eins von trffromsql und trftosql sollte nicht null sein\n" -#: pg_dump.c:10948 +#: pg_dump.c:10970 #, c-format msgid "WARNING: bogus value in pg_transform.trffromsql field\n" msgstr "WARNUNG: unsinniger Wert in Feld pg_transform.trffromsql\n" -#: pg_dump.c:10969 +#: pg_dump.c:10991 #, c-format msgid "WARNING: bogus value in pg_transform.trftosql field\n" msgstr "WARNUNG: unsinniger Wert in Feld pg_transform.trftosql\n" -#: pg_dump.c:11356 +#: pg_dump.c:11378 #, c-format msgid "WARNING: could not find operator with OID %s\n" msgstr "WARNUNG: konnte Operator mit OID %s nicht finden\n" -#: pg_dump.c:12536 +#: pg_dump.c:12513 #, c-format msgid "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n" msgstr "WARNUNG: Aggregatfunktion %s konnte für diese Datenbankversion nicht korrekt ausgegeben werden - ignoriert\n" -#: pg_dump.c:13360 +#: pg_dump.c:13337 #, c-format msgid "unrecognized object type in default privileges: %d\n" msgstr "unbekannter Objekttyp in den Vorgabeprivilegien: %d\n" -#: pg_dump.c:13375 +#: pg_dump.c:13352 #, c-format msgid "could not parse default ACL list (%s)\n" msgstr "konnte Vorgabe-ACL-Liste (%s) nicht interpretieren\n" -#: pg_dump.c:13431 +#: pg_dump.c:13408 #, c-format msgid "could not parse ACL list (%s) for object \"%s\" (%s)\n" -msgstr "konnte ACL-Zeichenkette (%s) für Objekt „%s“ (%s) nicht interpretieren\n" +msgstr "konnte ACL-Zeichenkette (%s) für Objekt »%s« (%s) nicht interpretieren\n" -#: pg_dump.c:13852 +#: pg_dump.c:13829 #, c-format msgid "query to obtain definition of view \"%s\" returned no data\n" -msgstr "Anfrage um die Definition der Sicht „%s“ zu ermitteln lieferte keine Daten\n" +msgstr "Anfrage um die Definition der Sicht »%s« zu ermitteln lieferte keine Daten\n" -#: pg_dump.c:13855 +#: pg_dump.c:13832 #, c-format msgid "query to obtain definition of view \"%s\" returned more than one definition\n" -msgstr "Anfrage um die Definition der Sicht „%s“ zu ermitteln lieferte mehr als eine Definition\n" +msgstr "Anfrage um die Definition der Sicht »%s« zu ermitteln lieferte mehr als eine Definition\n" -#: pg_dump.c:13862 +#: pg_dump.c:13839 #, c-format msgid "definition of view \"%s\" appears to be empty (length zero)\n" -msgstr "Definition der Sicht „%s“ scheint leer zu sein (Länge null)\n" +msgstr "Definition der Sicht »%s« scheint leer zu sein (Länge null)\n" -#: pg_dump.c:14610 +#: pg_dump.c:14587 #, c-format msgid "invalid column number %d for table \"%s\"\n" -msgstr "ungültige Spaltennummer %d in Tabelle „%s“\n" +msgstr "ungültige Spaltennummer %d in Tabelle »%s«\n" -#: pg_dump.c:14736 +#: pg_dump.c:14713 #, c-format msgid "missing index for constraint \"%s\"\n" -msgstr "fehlender Index für Constraint „%s“\n" +msgstr "fehlender Index für Constraint »%s«\n" -#: pg_dump.c:14927 +#: pg_dump.c:14904 #, c-format msgid "unrecognized constraint type: %c\n" msgstr "unbekannter Constraint-Typ: %c\n" -#: pg_dump.c:15077 pg_dump.c:15241 +#: pg_dump.c:15054 pg_dump.c:15218 #, c-format msgid "query to get data of sequence \"%s\" returned %d row (expected 1)\n" msgid_plural "query to get data of sequence \"%s\" returned %d rows (expected 1)\n" msgstr[0] "Anfrage nach Daten der Sequenz %s ergab %d Zeile (erwartete 1)\n" msgstr[1] "Anfrage nach Daten der Sequenz %s ergab %d Zeilen (erwartete 1)\n" -#: pg_dump.c:15088 +#: pg_dump.c:15065 #, c-format msgid "query to get data of sequence \"%s\" returned name \"%s\"\n" -msgstr "Anfrage nach Daten der Sequenz %s ergab Name „%s“\n" +msgstr "Anfrage nach Daten der Sequenz %s ergab Name »%s«\n" -#: pg_dump.c:15337 +#: pg_dump.c:15314 #, c-format msgid "unexpected tgtype value: %d\n" msgstr "unerwarteter tgtype-Wert: %d\n" -#: pg_dump.c:15419 +#: pg_dump.c:15396 #, c-format msgid "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n" -msgstr "fehlerhafte Argumentzeichenkette (%s) für Trigger „%s“ von Tabelle „%s“\n" +msgstr "fehlerhafte Argumentzeichenkette (%s) für Trigger »%s« von Tabelle »%s«\n" -#: pg_dump.c:15608 +#: pg_dump.c:15585 #, c-format msgid "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n" -msgstr "Anfrage nach Regel „%s“ der Tabelle „%s“ fehlgeschlagen: falsche Anzahl Zeilen zurückgegeben\n" +msgstr "Anfrage nach Regel »%s« der Tabelle »%s« fehlgeschlagen: falsche Anzahl Zeilen zurückgegeben\n" -#: pg_dump.c:15990 +#: pg_dump.c:15967 #, c-format msgid "reading dependency data\n" msgstr "lese Abhängigkeitsdaten\n" -#: pg_dump.c:16550 +#: pg_dump.c:16527 #, c-format msgid "WARNING: could not parse reloptions array\n" msgstr "WARNUNG: konnte reloptions-Array nicht interpretieren\n" -#: pg_dump.c:16614 -#, c-format -msgid "query returned %d row instead of one: %s\n" -msgid_plural "query returned %d rows instead of one: %s\n" -msgstr[0] "Anfrage ergab %d Zeile anstatt einer: %s\n" -msgstr[1] "Anfrage ergab %d Zeilen anstatt einer: %s\n" - #. translator: this is a module name #: pg_dump_sort.c:23 msgid "sorter" @@ -2118,8 +2119,8 @@ msgid "" "same directory as \"%s\".\n" "Check your installation.\n" msgstr "" -"Das Programm „pg_dump“ wird von %s benötigt, aber wurde nicht im\n" -"selben Verzeichnis wie „%s“ gefunden.\n" +"Das Programm »pg_dump« wird von %s benötigt, aber wurde nicht im\n" +"selben Verzeichnis wie »%s« gefunden.\n" "Prüfen Sie Ihre Installation.\n" #: pg_dumpall.c:188 @@ -2129,7 +2130,7 @@ msgid "" "but was not the same version as %s.\n" "Check your installation.\n" msgstr "" -"Das Programm „pg_dump“ wurde von „%s“ gefunden,\n" +"Das Programm »pg_dump« wurde von »%s« gefunden,\n" "aber war nicht die gleiche Version wie %s.\n" "Prüfen Sie Ihre Installation.\n" @@ -2156,7 +2157,7 @@ msgstr "%s: Optionen -r/--roles-only und -t/--tablespaces-only können nicht zus #: pg_dumpall.c:385 pg_dumpall.c:1892 #, c-format msgid "%s: could not connect to database \"%s\"\n" -msgstr "%s: konnte nicht mit der Datenbank „%s“ verbinden\n" +msgstr "%s: konnte nicht mit der Datenbank »%s« verbinden\n" #: pg_dumpall.c:400 #, c-format @@ -2164,13 +2165,13 @@ msgid "" "%s: could not connect to databases \"postgres\" or \"template1\"\n" "Please specify an alternative database.\n" msgstr "" -"%s: konnte nicht mit Datenbank „postgres“ oder „template1“ verbinden\n" +"%s: konnte nicht mit Datenbank »postgres« oder »template1« verbinden\n" "Bitte geben Sie eine alternative Datenbank an.\n" #: pg_dumpall.c:417 #, c-format msgid "%s: could not open the output file \"%s\": %s\n" -msgstr "%s: konnte die Ausgabedatei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte die Ausgabedatei »%s« nicht öffnen: %s\n" #: pg_dumpall.c:547 #, c-format @@ -2253,37 +2254,37 @@ msgstr "" #: pg_dumpall.c:1118 #, c-format msgid "%s: could not parse ACL list (%s) for tablespace \"%s\"\n" -msgstr "%s: konnte ACL-Zeichenkette (%s) für Tablespace „%s“ nicht interpretieren\n" +msgstr "%s: konnte ACL-Zeichenkette (%s) für Tablespace »%s« nicht interpretieren\n" #: pg_dumpall.c:1449 #, c-format msgid "%s: could not parse ACL list (%s) for database \"%s\"\n" -msgstr "%s: konnte ACL-Zeichenkette (%s) für Datenbank „%s“ nicht interpretieren\n" +msgstr "%s: konnte ACL-Zeichenkette (%s) für Datenbank »%s« nicht interpretieren\n" #: pg_dumpall.c:1659 #, c-format msgid "%s: dumping database \"%s\"...\n" -msgstr "%s: Ausgabe der Datenbank „%s“...\n" +msgstr "%s: Ausgabe der Datenbank »%s«...\n" #: pg_dumpall.c:1680 #, c-format msgid "%s: pg_dump failed on database \"%s\", exiting\n" -msgstr "%s: pg_dump für Datenbank „%s“ fehlgeschlagen; beende\n" +msgstr "%s: pg_dump für Datenbank »%s« fehlgeschlagen; beende\n" #: pg_dumpall.c:1689 #, c-format msgid "%s: could not re-open the output file \"%s\": %s\n" -msgstr "%s: konnte die Ausgabedatei „%s“ nicht neu öffnen: %s\n" +msgstr "%s: konnte die Ausgabedatei »%s« nicht neu öffnen: %s\n" #: pg_dumpall.c:1734 #, c-format msgid "%s: running \"%s\"\n" -msgstr "%s: führe „%s“ aus\n" +msgstr "%s: führe »%s« aus\n" #: pg_dumpall.c:1914 #, c-format msgid "%s: could not connect to database \"%s\": %s\n" -msgstr "%s: konnte nicht mit der Datenbank „%s“ verbinden: %s\n" +msgstr "%s: konnte nicht mit der Datenbank »%s« verbinden: %s\n" #: pg_dumpall.c:1944 #, c-format @@ -2293,7 +2294,7 @@ msgstr "%s: konnte Version des Servers nicht ermitteln\n" #: pg_dumpall.c:1950 #, c-format msgid "%s: could not parse server version \"%s\"\n" -msgstr "%s: konnte Versionszeichenkette „%s“ nicht entziffern\n" +msgstr "%s: konnte Versionszeichenkette »%s« nicht entziffern\n" #: pg_dumpall.c:2028 pg_dumpall.c:2054 #, c-format @@ -2333,7 +2334,7 @@ msgstr "%s: --single-transaction und mehrere Jobs können nicht zusammen verwend #: pg_restore.c:369 #, c-format msgid "unrecognized archive format \"%s\"; please specify \"c\", \"d\", or \"t\"\n" -msgstr "unbekanntes Archivformat „%s“; bitte „c“, „d“ oder „t“ angeben\n" +msgstr "unbekanntes Archivformat »%s«; bitte »c«, »d« oder »t« angeben\n" #: pg_restore.c:401 #, c-format @@ -2383,7 +2384,7 @@ msgstr " -l, --list Inhaltsverzeichnis für dieses Archiv anzeige #: pg_restore.c:442 #, c-format msgid " -v, --verbose verbose mode\n" -msgstr " -v, --verbose „Verbose“-Modus\n" +msgstr " -v, --verbose »Verbose«-Modus\n" #: pg_restore.c:443 #, c-format diff --git a/src/bin/pg_dump/po/ru.po b/src/bin/pg_dump/po/ru.po index 2e09288f47..58a42e9363 100644 --- a/src/bin/pg_dump/po/ru.po +++ b/src/bin/pg_dump/po/ru.po @@ -27,7 +27,7 @@ msgid "" msgstr "" "Project-Id-Version: PostgreSQL 9 current\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" -"POT-Creation-Date: 2016-01-15 04:43+0000\n" +"POT-Creation-Date: 2016-06-13 18:21+0000\n" "PO-Revision-Date: 2016-01-17 08:02+0300\n" "Last-Translator: Alexander Lakhin \n" "Language-Team: Russian \n" @@ -77,8 +77,8 @@ msgid "pclose failed: %s" msgstr "ошибка pclose: %s" #: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75 -#: ../../common/fe_memutils.c:98 pg_backup_db.c:137 pg_backup_db.c:188 -#: pg_backup_db.c:245 pg_backup_db.c:287 +#: ../../common/fe_memutils.c:98 pg_backup_db.c:156 pg_backup_db.c:207 +#: pg_backup_db.c:264 pg_backup_db.c:306 #, c-format msgid "out of memory\n" msgstr "нехватка памÑти\n" @@ -304,88 +304,78 @@ msgid "could not parse numeric array \"%s\": invalid character in number\n" msgstr "не удалоÑÑŒ разобрать чиÑловой маÑÑив \"%s\": неверный Ñимвол в чиÑле\n" #. translator: this is a module name -#: compress_io.c:79 +#: compress_io.c:78 msgid "compress_io" msgstr "compress_io" -#: compress_io.c:115 +#: compress_io.c:114 #, c-format msgid "invalid compression code: %d\n" msgstr "неверный код ÑжатиÑ: %d\n" -#: compress_io.c:139 compress_io.c:175 compress_io.c:196 compress_io.c:529 -#: compress_io.c:572 +#: compress_io.c:138 compress_io.c:174 compress_io.c:192 compress_io.c:519 +#: compress_io.c:562 #, c-format msgid "not built with zlib support\n" msgstr "программа Ñобрана без поддержки zlib\n" -#: compress_io.c:246 compress_io.c:348 +#: compress_io.c:242 compress_io.c:344 #, c-format msgid "could not initialize compression library: %s\n" msgstr "не удалоÑÑŒ инициализировать библиотеку ÑжатиÑ: %s\n" -#: compress_io.c:267 +#: compress_io.c:263 #, c-format msgid "could not close compression stream: %s\n" msgstr "не удалоÑÑŒ закрыть поток Ñжатых данных: %s\n" -#: compress_io.c:285 +#: compress_io.c:281 #, c-format msgid "could not compress data: %s\n" msgstr "не удалоÑÑŒ Ñжать данные: %s\n" -#: compress_io.c:368 compress_io.c:384 +#: compress_io.c:361 compress_io.c:377 #, c-format msgid "could not uncompress data: %s\n" msgstr "не удалоÑÑŒ раÑпаковать данные: %s\n" -#: compress_io.c:392 +#: compress_io.c:385 #, c-format msgid "could not close compression library: %s\n" msgstr "не удалоÑÑŒ закрыть библиотеку ÑжатиÑ: %s\n" -#: compress_io.c:606 compress_io.c:642 pg_backup_custom.c:591 +#: compress_io.c:596 compress_io.c:632 pg_backup_custom.c:591 #: pg_backup_tar.c:560 #, c-format msgid "could not read from input file: %s\n" msgstr "не удалоÑÑŒ прочитать входной файл: %s\n" -#: compress_io.c:645 pg_backup_custom.c:588 pg_backup_directory.c:552 +#: compress_io.c:635 pg_backup_custom.c:588 pg_backup_directory.c:548 #: pg_backup_tar.c:796 pg_backup_tar.c:820 #, c-format msgid "could not read from input file: end of file\n" msgstr "не удалоÑÑŒ прочитать входной файл: конец файла\n" -#: parallel.c:76 +#: parallel.c:162 msgid "parallel archiver" msgstr "параллельный архиватор" -#: parallel.c:139 +#: parallel.c:226 #, c-format msgid "%s: WSAStartup failed: %d\n" msgstr "%s: ошибка WSAStartup: %d\n" -#: parallel.c:339 -#, c-format -msgid "worker is terminating\n" -msgstr "рабочий процеÑÑ Ð¿Ñ€ÐµÑ€Ñ‹Ð²Ð°ÐµÑ‚ÑÑ\n" - -#: parallel.c:529 +#: parallel.c:929 #, c-format msgid "could not create communication channels: %s\n" msgstr "не удалоÑÑŒ Ñоздать каналы межпроцеÑÑного взаимодейÑтвиÑ: %s\n" -#: parallel.c:601 +#: parallel.c:992 #, c-format msgid "could not create worker process: %s\n" msgstr "не удалоÑÑŒ Ñоздать рабочий процеÑÑ: %s\n" -#: parallel.c:818 -#, c-format -msgid "could not get relation name for OID %u: %s\n" -msgstr "не удалоÑÑŒ получить Ð¸Ð¼Ñ Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ Ñ OID %u: %s\n" - -#: parallel.c:835 +#: parallel.c:1187 #, c-format msgid "" "could not obtain lock on relation \"%s\"\n" @@ -398,77 +388,67 @@ msgstr "" "Ñтой таблицы поÑле того, как родительÑкий процеÑÑ pg_dump получил Ð´Ð»Ñ Ð½ÐµÑ‘ " "начальную блокировку ACCESS SHARE.\n" -#: parallel.c:919 +#: parallel.c:1257 #, c-format -msgid "unrecognized command on communication channel: %s\n" -msgstr "ÐеизвеÑÑ‚Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° в канале взаимодейÑтвиÑ: %s\n" +msgid "unrecognized command received from master: \"%s\"\n" +msgstr "от ведущего получена нераÑÐ¿Ð¾Ð·Ð½Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°: \"%s\"\n" -#: parallel.c:952 +#: parallel.c:1295 #, c-format msgid "a worker process died unexpectedly\n" msgstr "рабочий процеÑÑ Ð½ÐµÐ¾Ð¶Ð¸Ð´Ð°Ð½Ð½Ð¾ прекратилÑÑ\n" -#: parallel.c:979 parallel.c:988 +#: parallel.c:1321 parallel.c:1327 #, c-format -msgid "invalid message received from worker: %s\n" -msgstr "от рабочего процеÑÑа получено ошибочное Ñообщение: %s\n" +msgid "invalid message received from worker: \"%s\"\n" +msgstr "от рабочего процеÑÑа получено ошибочное Ñообщение: \"%s\"\n" -#: parallel.c:985 pg_backup_db.c:355 -#, c-format -msgid "%s" -msgstr "%s" - -#: parallel.c:1037 parallel.c:1081 +#: parallel.c:1384 parallel.c:1435 #, c-format msgid "error processing a parallel work item\n" msgstr "ошибка Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ñ‡Ð°Ñти параллельной работы\n" -#: parallel.c:1109 parallel.c:1247 +#: parallel.c:1464 parallel.c:1582 #, c-format msgid "could not write to the communication channel: %s\n" msgstr "не удалоÑÑŒ запиÑать в канал взаимодейÑтвиÑ: %s\n" -#: parallel.c:1158 +#: parallel.c:1542 #, c-format -msgid "terminated by user\n" -msgstr "прервано пользователем\n" +msgid "select() failed: %s\n" +msgstr "ошибка в select(): %s\n" -#: parallel.c:1210 -#, c-format -msgid "error in ListenToWorkers(): %s\n" -msgstr "ошибка в ListenToWorkers(): %s\n" - -#: parallel.c:1335 +#: parallel.c:1667 #, c-format msgid "pgpipe: could not create socket: error code %d\n" msgstr "pgpipe: не удалоÑÑŒ Ñоздать Ñокет (код ошибки: %d)\n" -#: parallel.c:1346 +#: parallel.c:1678 #, c-format msgid "pgpipe: could not bind: error code %d\n" msgstr "pgpipe: не удалоÑÑŒ привÑзатьÑÑ Ðº Ñокету (код ошибки: %d)\n" -#: parallel.c:1353 +#: parallel.c:1685 #, c-format msgid "pgpipe: could not listen: error code %d\n" msgstr "pgpipe: не удалоÑÑŒ начать приём (код ошибки: %d)\n" -#: parallel.c:1360 +#: parallel.c:1692 #, c-format msgid "pgpipe: getsockname() failed: error code %d\n" msgstr "pgpipe: ошибка в getsockname() (код ошибки: %d)\n" -#: parallel.c:1371 +#: parallel.c:1703 #, c-format msgid "pgpipe: could not create second socket: error code %d\n" msgstr "pgpipe: не удалоÑÑŒ Ñоздать второй Ñокет (код ошибки: %d)\n" -#: parallel.c:1380 +#: parallel.c:1712 #, c-format msgid "pgpipe: could not connect socket: error code %d\n" msgstr "pgpipe: не удалоÑÑŒ подключить Ñокет (код ошибки: %d)\n" -#: parallel.c:1387 +#: parallel.c:1721 #, c-format msgid "pgpipe: could not accept connection: error code %d\n" msgstr "pgpipe: не удалоÑÑŒ принÑть Ñоединение (код ошибки: %d)\n" @@ -632,7 +612,7 @@ msgstr "воÑÑтановление большого объекта Ñ OID %u\n msgid "could not create large object %u: %s" msgstr "не удалоÑÑŒ Ñоздать большой объект %u: %s" -#: pg_backup_archiver.c:1233 pg_dump.c:2862 +#: pg_backup_archiver.c:1233 pg_dump.c:2881 #, c-format msgid "could not open large object %u: %s" msgstr "не удалоÑÑŒ открыть большой объект %u: %s" @@ -653,14 +633,14 @@ msgid "could not find entry for ID %d\n" msgstr "не найдена запиÑÑŒ Ð´Ð»Ñ ID %d\n" #: pg_backup_archiver.c:1360 pg_backup_directory.c:230 -#: pg_backup_directory.c:601 +#: pg_backup_directory.c:597 #, c-format msgid "could not close TOC file: %s\n" msgstr "не удалоÑÑŒ закрыть файл оглавлениÑ: %s\n" #: pg_backup_archiver.c:1469 pg_backup_custom.c:162 pg_backup_directory.c:341 -#: pg_backup_directory.c:587 pg_backup_directory.c:645 -#: pg_backup_directory.c:665 +#: pg_backup_directory.c:583 pg_backup_directory.c:641 +#: pg_backup_directory.c:661 #, c-format msgid "could not open output file \"%s\": %s\n" msgstr "не удалоÑÑŒ открыть выходной файл \"%s\": %s\n" @@ -741,7 +721,7 @@ msgid "" msgstr "каталог \"%s\" не похож на архивный (в нём отÑутÑтвует \"toc.dat\")\n" #: pg_backup_archiver.c:2056 pg_backup_custom.c:181 pg_backup_custom.c:770 -#: pg_backup_directory.c:214 pg_backup_directory.c:402 +#: pg_backup_directory.c:214 pg_backup_directory.c:399 #, c-format msgid "could not open input file \"%s\": %s\n" msgstr "не удалоÑÑŒ открыть входной файл \"%s\": %s\n" @@ -792,82 +772,73 @@ msgstr "выделение Ñтруктуры AH Ð´Ð»Ñ %s, формат %d\n" msgid "unrecognized file format \"%d\"\n" msgstr "неопознанный формат файла: \"%d\"\n" -#: pg_backup_archiver.c:2460 +#: pg_backup_archiver.c:2466 #, c-format msgid "entry ID %d out of range -- perhaps a corrupt TOC\n" msgstr "ID запиÑи %d вне диапазона - возможно повреждено оглавление\n" -#: pg_backup_archiver.c:2576 +#: pg_backup_archiver.c:2582 #, c-format msgid "read TOC entry %d (ID %d) for %s %s\n" msgstr "прочитана запиÑÑŒ Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ñ %d (ID %d): %s %s\n" -#: pg_backup_archiver.c:2610 +#: pg_backup_archiver.c:2616 #, c-format msgid "unrecognized encoding \"%s\"\n" msgstr "нераÑÐ¿Ð¾Ð·Ð½Ð°Ð½Ð½Ð°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ° \"%s\"\n" -#: pg_backup_archiver.c:2615 +#: pg_backup_archiver.c:2621 #, c-format msgid "invalid ENCODING item: %s\n" msgstr "неверный Ñлемент ENCODING: %s\n" -#: pg_backup_archiver.c:2633 +#: pg_backup_archiver.c:2639 #, c-format msgid "invalid STDSTRINGS item: %s\n" msgstr "неверный Ñлемент STDSTRINGS: %s\n" -#: pg_backup_archiver.c:2858 +#: pg_backup_archiver.c:2864 #, c-format msgid "could not set session user to \"%s\": %s" msgstr "не удалоÑÑŒ переключить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ ÑеÑÑии на \"%s\": %s" -#: pg_backup_archiver.c:2890 +#: pg_backup_archiver.c:2896 #, c-format msgid "could not set default_with_oids: %s" msgstr "не удалоÑÑŒ уÑтановить параметр default_with_oids: %s" -#: pg_backup_archiver.c:3030 +#: pg_backup_archiver.c:3036 #, c-format msgid "could not set search_path to \"%s\": %s" msgstr "не удалоÑÑŒ приÑвоить search_path значение \"%s\": %s" -#: pg_backup_archiver.c:3092 +#: pg_backup_archiver.c:3098 #, c-format msgid "could not set default_tablespace to %s: %s" msgstr "не удалоÑÑŒ задать Ð´Ð»Ñ default_tablespace значение %s: %s" -#: pg_backup_archiver.c:3179 pg_backup_archiver.c:3366 +#: pg_backup_archiver.c:3185 pg_backup_archiver.c:3372 #, c-format msgid "WARNING: don't know how to set owner for object type %s\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: неизвеÑтно, как назначить владельца Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° типа %s\n" -#: pg_backup_archiver.c:3419 -#, c-format -msgid "" -"WARNING: requested compression not available in this installation -- archive " -"will be uncompressed\n" -msgstr "" -"ПРЕДУПРЕЖДЕÐИЕ: уÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ не поддерживает Ñжатие -- " -"архив не будет ÑжиматьÑÑ\n" - -#: pg_backup_archiver.c:3458 +#: pg_backup_archiver.c:3454 #, c-format msgid "did not find magic string in file header\n" msgstr "в файле заголовка не найдена магичеÑÐºÐ°Ñ Ñтрока\n" -#: pg_backup_archiver.c:3471 +#: pg_backup_archiver.c:3467 #, c-format msgid "unsupported version (%d.%d) in file header\n" msgstr "Ð½ÐµÐ¿Ð¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ (%d.%d) в заголовке файла\n" -#: pg_backup_archiver.c:3476 +#: pg_backup_archiver.c:3472 #, c-format msgid "sanity check on integer size (%lu) failed\n" msgstr "неÑоответÑтвие размера integer (%lu)\n" -#: pg_backup_archiver.c:3480 +#: pg_backup_archiver.c:3476 #, c-format msgid "" "WARNING: archive was made on a machine with larger integers, some operations " @@ -876,12 +847,12 @@ msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: архив был Ñделан на компьютере большей разрÑдноÑти -- " "возможен Ñбой некоторых операций\n" -#: pg_backup_archiver.c:3490 +#: pg_backup_archiver.c:3486 #, c-format msgid "expected format (%d) differs from format found in file (%d)\n" msgstr "ожидаемый формат (%d) отличаетÑÑ Ð¾Ñ‚ формата, указанного в файле (%d)\n" -#: pg_backup_archiver.c:3506 +#: pg_backup_archiver.c:3502 #, c-format msgid "" "WARNING: archive is compressed, but this installation does not support " @@ -890,87 +861,87 @@ msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: архив Ñжат, но уÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð½Ðµ поддерживает Ñжатие " "-- данные недоÑтупны\n" -#: pg_backup_archiver.c:3524 +#: pg_backup_archiver.c:3520 #, c-format msgid "WARNING: invalid creation date in header\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð´Ð°Ñ‚Ð° ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð² заголовке\n" -#: pg_backup_archiver.c:3599 +#: pg_backup_archiver.c:3595 #, c-format msgid "entering restore_toc_entries_prefork\n" msgstr "вход в restore_toc_entries_prefork\n" -#: pg_backup_archiver.c:3643 +#: pg_backup_archiver.c:3639 #, c-format msgid "processing item %d %s %s\n" msgstr "обработка объекта %d %s %s\n" -#: pg_backup_archiver.c:3695 +#: pg_backup_archiver.c:3691 #, c-format msgid "entering restore_toc_entries_parallel\n" msgstr "вход в restore_toc_entries_parallel\n" -#: pg_backup_archiver.c:3743 +#: pg_backup_archiver.c:3739 #, c-format msgid "entering main parallel loop\n" msgstr "вход в оÑновной параллельный цикл\n" -#: pg_backup_archiver.c:3754 +#: pg_backup_archiver.c:3750 #, c-format msgid "skipping item %d %s %s\n" msgstr "объект %d %s %s пропуÑкаетÑÑ\n" -#: pg_backup_archiver.c:3764 +#: pg_backup_archiver.c:3760 #, c-format msgid "launching item %d %s %s\n" msgstr "объект %d %s %s запуÑкаетÑÑ\n" -#: pg_backup_archiver.c:3822 +#: pg_backup_archiver.c:3816 #, c-format msgid "finished main parallel loop\n" msgstr "оÑновной параллельный цикл закончен\n" -#: pg_backup_archiver.c:3831 +#: pg_backup_archiver.c:3825 #, c-format msgid "entering restore_toc_entries_postfork\n" msgstr "вход в restore_toc_entries_postfork\n" -#: pg_backup_archiver.c:3849 +#: pg_backup_archiver.c:3844 #, c-format msgid "processing missed item %d %s %s\n" msgstr "обработка пропущенного объекта %d %s %s\n" -#: pg_backup_archiver.c:3998 +#: pg_backup_archiver.c:3993 #, c-format msgid "no item ready\n" msgstr "Ñлемент не готов\n" -#: pg_backup_archiver.c:4047 +#: pg_backup_archiver.c:4041 #, c-format msgid "could not find slot of finished worker\n" msgstr "не удалоÑÑŒ найти Ñлот законченного рабочего объекта\n" -#: pg_backup_archiver.c:4049 +#: pg_backup_archiver.c:4043 #, c-format msgid "finished item %d %s %s\n" msgstr "закончен объект %d %s %s\n" -#: pg_backup_archiver.c:4062 +#: pg_backup_archiver.c:4056 #, c-format msgid "worker process failed: exit code %d\n" msgstr "рабочий процеÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ð»ÑÑ Ñ ÐºÐ¾Ð´Ð¾Ð¼ возврата %d\n" -#: pg_backup_archiver.c:4224 +#: pg_backup_archiver.c:4218 #, c-format msgid "transferring dependency %d -> %d to %d\n" msgstr "переключение завиÑимоÑти %d -> %d на %d\n" -#: pg_backup_archiver.c:4297 +#: pg_backup_archiver.c:4291 #, c-format msgid "reducing dependencies for %d\n" msgstr "уменьшение завиÑимоÑтей Ð´Ð»Ñ %d\n" -#: pg_backup_archiver.c:4336 +#: pg_backup_archiver.c:4330 #, c-format msgid "table \"%s\" could not be created, will not restore its data\n" msgstr "Ñоздать таблицу \"%s\" не удалоÑÑŒ, её данные не будут воÑÑтановлены\n" @@ -1076,104 +1047,124 @@ msgstr "" "ftell\n" #. translator: this is a module name -#: pg_backup_db.c:29 +#: pg_backup_db.c:30 msgid "archiver (db)" msgstr "архиватор (БД)" -#: pg_backup_db.c:44 +#: pg_backup_db.c:46 #, c-format msgid "could not get server_version from libpq\n" msgstr "не удалоÑÑŒ получить верÑию Ñервера из libpq\n" -#: pg_backup_db.c:55 pg_dumpall.c:1965 +#: pg_backup_db.c:57 pg_dumpall.c:1965 #, c-format msgid "server version: %s; %s version: %s\n" msgstr "верÑÐ¸Ñ Ñервера: %s; верÑÐ¸Ñ %s: %s\n" -#: pg_backup_db.c:57 pg_dumpall.c:1967 +#: pg_backup_db.c:59 pg_dumpall.c:1967 #, c-format msgid "aborting because of server version mismatch\n" msgstr "продолжение работы Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ верÑией Ñервера невозможно\n" -#: pg_backup_db.c:128 +#: pg_backup_db.c:147 #, c-format msgid "connecting to database \"%s\" as user \"%s\"\n" msgstr "подключение к базе \"%s\" Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ \"%s\"\n" -#: pg_backup_db.c:135 pg_backup_db.c:183 pg_backup_db.c:243 pg_backup_db.c:285 +#: pg_backup_db.c:154 pg_backup_db.c:202 pg_backup_db.c:262 pg_backup_db.c:304 #: pg_dumpall.c:1795 pg_dumpall.c:1903 msgid "Password: " msgstr "Пароль: " -#: pg_backup_db.c:164 +#: pg_backup_db.c:183 #, c-format msgid "failed to reconnect to database\n" msgstr "ошибка Ð¿ÐµÑ€ÐµÐ¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº базе данных\n" -#: pg_backup_db.c:169 +#: pg_backup_db.c:188 #, c-format msgid "could not reconnect to database: %s" msgstr "не удалоÑÑŒ переподключитьÑÑ Ðº базе: %s" -#: pg_backup_db.c:185 +#: pg_backup_db.c:204 #, c-format msgid "connection needs password\n" msgstr "Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ…Ð¾Ð´Ð¸Ð¼ пароль\n" -#: pg_backup_db.c:237 +#: pg_backup_db.c:256 #, c-format msgid "already connected to a database\n" msgstr "подключение к базе данных уже уÑтановлено\n" -#: pg_backup_db.c:277 +#: pg_backup_db.c:296 #, c-format msgid "failed to connect to database\n" msgstr "ошибка Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº базе данных\n" -#: pg_backup_db.c:294 +#: pg_backup_db.c:313 #, c-format msgid "connection to database \"%s\" failed: %s" msgstr "не удалоÑÑŒ подключитьÑÑ Ðº базе \"%s\": %s" -#: pg_backup_db.c:362 +#: pg_backup_db.c:383 +#, c-format +msgid "%s" +msgstr "%s" + +#: pg_backup_db.c:390 #, c-format msgid "query failed: %s" msgstr "ошибка при выполнении запроÑа: %s" -#: pg_backup_db.c:364 +#: pg_backup_db.c:392 #, c-format msgid "query was: %s\n" msgstr "запроÑ: %s\n" -#: pg_backup_db.c:428 +#: pg_backup_db.c:434 +#, c-format +msgid "query returned %d row instead of one: %s\n" +msgid_plural "query returned %d rows instead of one: %s\n" +msgstr[0] "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ð½ÑƒÐ» %d Ñтроку вмеÑто одной: %s\n" +msgstr[1] "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ð½ÑƒÐ» %d Ñтроки вмеÑто одной: %s\n" +msgstr[2] "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ð½ÑƒÐ» %d Ñтрок вмеÑто одной: %s\n" + +#: pg_backup_db.c:479 #, c-format msgid "%s: %s Command was: %s\n" msgstr "%s: %s ВыполнÑлаÑÑŒ команда: %s\n" -#: pg_backup_db.c:484 pg_backup_db.c:558 pg_backup_db.c:565 +#: pg_backup_db.c:535 pg_backup_db.c:609 pg_backup_db.c:616 msgid "could not execute query" msgstr "не удалоÑÑŒ выполнить запроÑ" -#: pg_backup_db.c:537 +#: pg_backup_db.c:588 #, c-format msgid "error returned by PQputCopyData: %s" msgstr "ошибка в PQputCopyData: %s" -#: pg_backup_db.c:586 +#: pg_backup_db.c:637 #, c-format msgid "error returned by PQputCopyEnd: %s" msgstr "ошибка в PQputCopyEnd: %s" -#: pg_backup_db.c:592 +#: pg_backup_db.c:643 #, c-format msgid "COPY failed for table \"%s\": %s" msgstr "Ñбой команды COPY Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s\": %s" -#: pg_backup_db.c:605 +#: pg_backup_db.c:649 pg_dump.c:1681 +#, c-format +msgid "WARNING: unexpected extra results during COPY of table \"%s\"\n" +msgstr "" +"ПРЕДУПРЕЖДЕÐИЕ: неожиданные лишние результаты получены при COPY Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ " +"\"%s\"\n" + +#: pg_backup_db.c:661 msgid "could not start database transaction" msgstr "не удаётÑÑ Ð½Ð°Ñ‡Ð°Ñ‚ÑŒ транзакцию" -#: pg_backup_db.c:613 +#: pg_backup_db.c:669 msgid "could not commit database transaction" msgstr "не удалоÑÑŒ зафикÑировать транзакцию" @@ -1202,43 +1193,43 @@ msgstr "не удалоÑÑŒ закрыть каталог \"%s\": %s\n" msgid "could not create directory \"%s\": %s\n" msgstr "Ñоздать каталог \"%s\" не удалоÑÑŒ: %s\n" -#: pg_backup_directory.c:413 +#: pg_backup_directory.c:412 #, c-format msgid "could not close data file: %s\n" msgstr "не удалоÑÑŒ закрыть файл данных: %s\n" -#: pg_backup_directory.c:454 +#: pg_backup_directory.c:453 #, c-format msgid "could not open large object TOC file \"%s\" for input: %s\n" msgstr "" "не удалоÑÑŒ открыть Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð» Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… объектов \"%s\": %s\n" -#: pg_backup_directory.c:465 +#: pg_backup_directory.c:464 #, c-format msgid "invalid line in large object TOC file \"%s\": \"%s\"\n" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñтрока в файле Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… объектов \"%s\": \"%s\"\n" -#: pg_backup_directory.c:474 +#: pg_backup_directory.c:473 #, c-format msgid "error reading large object TOC file \"%s\"\n" msgstr "ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… объектов \"%s\"\n" -#: pg_backup_directory.c:478 +#: pg_backup_directory.c:477 #, c-format msgid "could not close large object TOC file \"%s\": %s\n" msgstr "не удалоÑÑŒ закрыть файл Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… объектов \"%s\": %s\n" -#: pg_backup_directory.c:688 +#: pg_backup_directory.c:684 #, c-format msgid "could not write to blobs TOC file\n" msgstr "не удалоÑÑŒ запиÑать в файл Ð¾Ð³Ð»Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… объектов\n" -#: pg_backup_directory.c:720 +#: pg_backup_directory.c:716 #, c-format msgid "file name too long: \"%s\"\n" msgstr "Ñлишком длинное Ð¸Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°: \"%s\"\n" -#: pg_backup_directory.c:806 +#: pg_backup_directory.c:802 #, c-format msgid "error during backup\n" msgstr "ошибка в процеÑÑе резервного копированиÑ\n" @@ -1379,73 +1370,77 @@ msgstr "" msgid "%s: unrecognized section name: \"%s\"\n" msgstr "%s: нераÑпознанное Ð¸Ð¼Ñ Ñ€Ð°Ð·Ð´ÐµÐ»Ð°: \"%s\"\n" -#: pg_backup_utils.c:56 pg_dump.c:524 pg_dump.c:541 pg_dumpall.c:300 +#: pg_backup_utils.c:56 pg_dump.c:523 pg_dump.c:540 pg_dumpall.c:300 #: pg_dumpall.c:310 pg_dumpall.c:320 pg_dumpall.c:329 pg_dumpall.c:345 #: pg_dumpall.c:403 pg_restore.c:277 pg_restore.c:293 pg_restore.c:305 #, c-format msgid "Try \"%s --help\" for more information.\n" msgstr "Ð”Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации попробуйте \"%s --help\".\n" -#: pg_backup_utils.c:101 +#: pg_backup_utils.c:118 #, c-format msgid "out of on_exit_nicely slots\n" msgstr "превышен предел обработчиков штатного выхода\n" -#: pg_dump.c:494 +#: pg_dump.c:493 #, c-format msgid "compression level must be in range 0..9\n" msgstr "уровень ÑÐ¶Ð°Ñ‚Ð¸Ñ Ð´Ð¾Ð»Ð¶ÐµÐ½ быть в диапазоне 0..9\n" -#: pg_dump.c:539 pg_dumpall.c:308 pg_restore.c:291 +#: pg_dump.c:538 pg_dumpall.c:308 pg_restore.c:291 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" msgstr "%s: Ñлишком много аргументов командной Ñтроки (первый: \"%s\")\n" -#: pg_dump.c:552 +#: pg_dump.c:551 #, c-format msgid "options -s/--schema-only and -a/--data-only cannot be used together\n" msgstr "параметры -s/--schema-only и -a/--data-only иÑключают друг друга\n" -#: pg_dump.c:558 +#: pg_dump.c:557 #, c-format msgid "options -c/--clean and -a/--data-only cannot be used together\n" msgstr "параметры -c/--clean и -a/--data-only иÑключают друг друга\n" -#: pg_dump.c:564 +#: pg_dump.c:563 #, c-format msgid "" "options --inserts/--column-inserts and -o/--oids cannot be used together\n" msgstr "" "параметры --inserts/--column-inserts и -o/--oids иÑключают друг друга\n" -#: pg_dump.c:565 +#: pg_dump.c:564 #, c-format msgid "(The INSERT command cannot set OIDs.)\n" msgstr "(Ð’ INSERT Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñть OID.)\n" -#: pg_dump.c:570 +#: pg_dump.c:569 #, c-format msgid "option --if-exists requires option -c/--clean\n" msgstr "параметру --if-exists требуетÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€ -c/--clean\n" -#: pg_dump.c:598 +#: pg_dump.c:591 +#, c-format +msgid "" +"WARNING: requested compression not available in this installation -- archive " +"will be uncompressed\n" +msgstr "" +"ПРЕДУПРЕЖДЕÐИЕ: уÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ñ‹ не поддерживает Ñжатие -- " +"архив не будет ÑжиматьÑÑ\n" + +#: pg_dump.c:606 #, c-format msgid "%s: invalid number of parallel jobs\n" msgstr "%s: неверное чиÑло параллельных заданий\n" -#: pg_dump.c:602 +#: pg_dump.c:610 #, c-format msgid "parallel backup only supported by the directory format\n" msgstr "" "параллельное резервное копирование поддерживаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¾Ð¼ \"каталог" "\"\n" -#: pg_dump.c:615 -#, c-format -msgid "could not open output file \"%s\" for writing\n" -msgstr "не удалоÑÑŒ открыть выходной файл \"%s\" Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи\n" - -#: pg_dump.c:674 +#: pg_dump.c:667 #, c-format msgid "" "Synchronized snapshots are not supported by this server version.\n" @@ -1456,27 +1451,27 @@ msgstr "" "ЕÑли они вам не нужны, укажите при запуÑке ключ\n" "--no-synchronized-snapshots.\n" -#: pg_dump.c:681 +#: pg_dump.c:674 #, c-format msgid "Exported snapshots are not supported by this server version.\n" msgstr "ЭкÑпортированные Ñнимки не поддерживаютÑÑ Ñтой верÑией Ñервера.\n" -#: pg_dump.c:692 +#: pg_dump.c:685 #, c-format msgid "last built-in OID is %u\n" msgstr "поÑледний ÑиÑтемный OID: %u\n" -#: pg_dump.c:701 +#: pg_dump.c:694 #, c-format msgid "No matching schemas were found\n" msgstr "СоответÑтвующие Ñхемы не найдены\n" -#: pg_dump.c:713 +#: pg_dump.c:706 #, c-format msgid "No matching tables were found\n" msgstr "СоответÑтвующие таблицы не найдены\n" -#: pg_dump.c:870 +#: pg_dump.c:863 #, c-format msgid "" "%s dumps a database as a text file or to other formats.\n" @@ -1485,17 +1480,17 @@ msgstr "" "%s ÑохранÑет резервную копию БД в текÑтовом файле или другом виде.\n" "\n" -#: pg_dump.c:871 pg_dumpall.c:548 pg_restore.c:434 +#: pg_dump.c:864 pg_dumpall.c:548 pg_restore.c:434 #, c-format msgid "Usage:\n" msgstr "ИÑпользование:\n" -#: pg_dump.c:872 +#: pg_dump.c:865 #, c-format msgid " %s [OPTION]... [DBNAME]\n" msgstr " %s [ПÐРÐМЕТР]... [ИМЯ_БД]\n" -#: pg_dump.c:874 pg_dumpall.c:551 pg_restore.c:437 +#: pg_dump.c:867 pg_dumpall.c:551 pg_restore.c:437 #, c-format msgid "" "\n" @@ -1504,12 +1499,12 @@ msgstr "" "\n" "Общие параметры:\n" -#: pg_dump.c:875 +#: pg_dump.c:868 #, c-format msgid " -f, --file=FILENAME output file or directory name\n" msgstr " -f, --file=ИМЯ Ð¸Ð¼Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð¾Ð³Ð¾ файла или каталога\n" -#: pg_dump.c:876 +#: pg_dump.c:869 #, c-format msgid "" " -F, --format=c|d|t|p output file format (custom, directory, tar,\n" @@ -1519,7 +1514,7 @@ msgstr "" " (пользовательÑкий | каталог | tar |\n" " текÑтовый (по умолчанию))\n" -#: pg_dump.c:878 +#: pg_dump.c:871 #, c-format msgid " -j, --jobs=NUM use this many parallel jobs to dump\n" msgstr "" @@ -1527,23 +1522,23 @@ msgstr "" "чиÑло\n" " заданий\n" -#: pg_dump.c:879 +#: pg_dump.c:872 #, c-format msgid " -v, --verbose verbose mode\n" msgstr " -v, --verbose режим подробных Ñообщений\n" -#: pg_dump.c:880 pg_dumpall.c:553 +#: pg_dump.c:873 pg_dumpall.c:553 #, c-format msgid " -V, --version output version information, then exit\n" msgstr " -V, --version показать верÑию и выйти\n" -#: pg_dump.c:881 +#: pg_dump.c:874 #, c-format msgid "" " -Z, --compress=0-9 compression level for compressed formats\n" msgstr " -Z, --compress=0-9 уровень ÑÐ¶Ð°Ñ‚Ð¸Ñ Ð¿Ñ€Ð¸ архивации\n" -#: pg_dump.c:882 pg_dumpall.c:554 +#: pg_dump.c:875 pg_dumpall.c:554 #, c-format msgid "" " --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n" @@ -1551,12 +1546,12 @@ msgstr "" " --lock-wait-timeout=ТÐЙМÐУТ прервать операцию при таймауте блокировки " "таблицы\n" -#: pg_dump.c:883 pg_dumpall.c:555 +#: pg_dump.c:876 pg_dumpall.c:555 #, c-format msgid " -?, --help show this help, then exit\n" msgstr " -?, --help показать Ñту Ñправку и выйти\n" -#: pg_dump.c:885 pg_dumpall.c:556 +#: pg_dump.c:878 pg_dumpall.c:556 #, c-format msgid "" "\n" @@ -1565,17 +1560,17 @@ msgstr "" "\n" "Параметры, управлÑющие выводом:\n" -#: pg_dump.c:886 pg_dumpall.c:557 +#: pg_dump.c:879 pg_dumpall.c:557 #, c-format msgid " -a, --data-only dump only the data, not the schema\n" msgstr " -a, --data-only выгрузить только данные, без Ñхемы\n" -#: pg_dump.c:887 +#: pg_dump.c:880 #, c-format msgid " -b, --blobs include large objects in dump\n" msgstr " -b, --blobs выгрузить также большие объекты\n" -#: pg_dump.c:888 pg_restore.c:448 +#: pg_dump.c:881 pg_restore.c:448 #, c-format msgid "" " -c, --clean clean (drop) database objects before " @@ -1584,7 +1579,7 @@ msgstr "" " -c, --clean очиÑтить (удалить) объекты БД при " "воÑÑтановлении\n" -#: pg_dump.c:889 +#: pg_dump.c:882 #, c-format msgid "" " -C, --create include commands to create database in dump\n" @@ -1592,27 +1587,27 @@ msgstr "" " -C, --create добавить в копию команды ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð±Ð°Ð·Ñ‹ " "данных\n" -#: pg_dump.c:890 +#: pg_dump.c:883 #, c-format msgid " -E, --encoding=ENCODING dump the data in encoding ENCODING\n" msgstr " -E, --encoding=КОДИРОВКРвыгружать данные в заданной кодировке\n" -#: pg_dump.c:891 +#: pg_dump.c:884 #, c-format msgid " -n, --schema=SCHEMA dump the named schema(s) only\n" msgstr " -n, --schema=СХЕМРвыгрузить только указанную Ñхему(Ñ‹)\n" -#: pg_dump.c:892 +#: pg_dump.c:885 #, c-format msgid " -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n" msgstr " -N, --exclude-schema=СХЕМРÐЕ выгружать указанную Ñхему(Ñ‹)\n" -#: pg_dump.c:893 pg_dumpall.c:560 +#: pg_dump.c:886 pg_dumpall.c:560 #, c-format msgid " -o, --oids include OIDs in dump\n" msgstr " -o, --oids выгружать данные Ñ OID\n" -#: pg_dump.c:894 +#: pg_dump.c:887 #, c-format msgid "" " -O, --no-owner skip restoration of object ownership in\n" @@ -1621,12 +1616,12 @@ msgstr "" " -O, --no-owner не воÑÑтанавливать владение объектами\n" " при иÑпользовании текÑтового формата\n" -#: pg_dump.c:896 pg_dumpall.c:563 +#: pg_dump.c:889 pg_dumpall.c:563 #, c-format msgid " -s, --schema-only dump only the schema, no data\n" msgstr " -s, --schema-only выгрузить только Ñхему, без данных\n" -#: pg_dump.c:897 +#: pg_dump.c:890 #, c-format msgid "" " -S, --superuser=NAME superuser user name to use in plain-text " @@ -1635,27 +1630,27 @@ msgstr "" " -S, --superuser=ИМЯ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ, который будет задейÑтвован\n" " при воÑÑтановлении из текÑтового формата\n" -#: pg_dump.c:898 +#: pg_dump.c:891 #, c-format msgid " -t, --table=TABLE dump the named table(s) only\n" msgstr " -t, --table=ТÐБЛИЦРвыгрузить только указанную таблицу(Ñ‹)\n" -#: pg_dump.c:899 +#: pg_dump.c:892 #, c-format msgid " -T, --exclude-table=TABLE do NOT dump the named table(s)\n" msgstr " -T, --exclude-table=ТÐБЛИЦРÐЕ выгружать указанную таблицу(Ñ‹)\n" -#: pg_dump.c:900 pg_dumpall.c:566 +#: pg_dump.c:893 pg_dumpall.c:566 #, c-format msgid " -x, --no-privileges do not dump privileges (grant/revoke)\n" msgstr " -x, --no-privileges не выгружать права (назначение/отзыв)\n" -#: pg_dump.c:901 pg_dumpall.c:567 +#: pg_dump.c:894 pg_dumpall.c:567 #, c-format msgid " --binary-upgrade for use by upgrade utilities only\n" msgstr " --binary-upgrade только Ð´Ð»Ñ ÑƒÑ‚Ð¸Ð»Ð¸Ñ‚ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð‘Ð”\n" -#: pg_dump.c:902 pg_dumpall.c:568 +#: pg_dump.c:895 pg_dumpall.c:568 #, c-format msgid "" " --column-inserts dump data as INSERT commands with column " @@ -1664,7 +1659,7 @@ msgstr "" " --column-inserts выгружать данные в виде INSERT Ñ Ð¸Ð¼ÐµÐ½Ð°Ð¼Ð¸ " "Ñтолбцов\n" -#: pg_dump.c:903 pg_dumpall.c:569 +#: pg_dump.c:896 pg_dumpall.c:569 #, c-format msgid "" " --disable-dollar-quoting disable dollar quoting, use SQL standard " @@ -1673,7 +1668,7 @@ msgstr "" " --disable-dollar-quoting отключить ÑпецÑтроки Ñ $, выводить Ñтроки\n" " по Ñтандарту SQL\n" -#: pg_dump.c:904 pg_dumpall.c:570 pg_restore.c:464 +#: pg_dump.c:897 pg_dumpall.c:570 pg_restore.c:464 #, c-format msgid "" " --disable-triggers disable triggers during data-only restore\n" @@ -1681,7 +1676,7 @@ msgstr "" " --disable-triggers отключить триггеры при воÑÑтановлении\n" " только данных, без Ñхемы\n" -#: pg_dump.c:905 +#: pg_dump.c:898 #, c-format msgid "" " --enable-row-security enable row security (dump only content user " @@ -1692,19 +1687,19 @@ msgstr "" "только\n" " те данные, которые доÑтупны пользователю)\n" -#: pg_dump.c:907 +#: pg_dump.c:900 #, c-format msgid "" " --exclude-table-data=TABLE do NOT dump data for the named table(s)\n" msgstr " --exclude-table-data=ТÐБЛИЦРÐЕ выгружать указанную таблицу(Ñ‹)\n" -#: pg_dump.c:908 pg_dumpall.c:571 pg_restore.c:466 +#: pg_dump.c:901 pg_dumpall.c:571 pg_restore.c:466 #, c-format msgid " --if-exists use IF EXISTS when dropping objects\n" msgstr "" " --if-exists применÑть IF EXISTS при удалении объектов\n" -#: pg_dump.c:909 pg_dumpall.c:572 +#: pg_dump.c:902 pg_dumpall.c:572 #, c-format msgid "" " --inserts dump data as INSERT commands, rather than " @@ -1713,13 +1708,13 @@ msgstr "" " --inserts выгрузить данные в виде команд INSERT, не " "COPY\n" -#: pg_dump.c:910 pg_dumpall.c:573 +#: pg_dump.c:903 pg_dumpall.c:573 #, c-format msgid " --no-security-labels do not dump security label assignments\n" msgstr "" " --no-security-labels не выгружать Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¼ÐµÑ‚Ð¾Ðº безопаÑноÑти\n" -#: pg_dump.c:911 +#: pg_dump.c:904 #, c-format msgid "" " --no-synchronized-snapshots do not use synchronized snapshots in parallel " @@ -1728,20 +1723,20 @@ msgstr "" " --no-synchronized-snapshots не иÑпользовать Ñинхронизированные Ñнимки\n" " в параллельных заданиÑÑ…\n" -#: pg_dump.c:912 pg_dumpall.c:574 +#: pg_dump.c:905 pg_dumpall.c:574 #, c-format msgid " --no-tablespaces do not dump tablespace assignments\n" msgstr "" " --no-tablespaces не выгружать Ð½Ð°Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ‡Ð½Ñ‹Ñ… " "проÑтранÑтв\n" -#: pg_dump.c:913 pg_dumpall.c:575 +#: pg_dump.c:906 pg_dumpall.c:575 #, c-format msgid " --no-unlogged-table-data do not dump unlogged table data\n" msgstr "" " --no-unlogged-table-data не выгружать данные нежурналируемых таблиц\n" -#: pg_dump.c:914 pg_dumpall.c:576 +#: pg_dump.c:907 pg_dumpall.c:576 #, c-format msgid "" " --quote-all-identifiers quote all identifiers, even if not key words\n" @@ -1749,7 +1744,7 @@ msgstr "" " --quote-all-identifiers заключать в кавычки вÑе идентификаторы,\n" " а не только ключевые Ñлова\n" -#: pg_dump.c:915 +#: pg_dump.c:908 #, c-format msgid "" " --section=SECTION dump named section (pre-data, data, or post-" @@ -1758,7 +1753,7 @@ msgstr "" " --section=РÐЗДЕЛ выгрузить заданный раздел\n" " (pre-data, data или post-data)\n" -#: pg_dump.c:916 +#: pg_dump.c:909 #, c-format msgid "" " --serializable-deferrable wait until the dump can run without " @@ -1767,13 +1762,13 @@ msgstr "" " --serializable-deferrable дождатьÑÑ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° Ð´Ð»Ñ Ð²Ñ‹Ð³Ñ€ÑƒÐ·ÐºÐ¸ данных без " "аномалий\n" -#: pg_dump.c:917 +#: pg_dump.c:910 #, c-format msgid " --snapshot=SNAPSHOT use given snapshot for the dump\n" msgstr "" " --snapshot=СÐИМОК иÑпользовать при выгрузке заданный Ñнимок\n" -#: pg_dump.c:918 pg_dumpall.c:577 pg_restore.c:472 +#: pg_dump.c:911 pg_dumpall.c:577 pg_restore.c:472 #, c-format msgid "" " --use-set-session-authorization\n" @@ -1785,7 +1780,7 @@ msgstr "" " уÑтанавливать владельца, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹\n" " SET SESSION AUTHORIZATION вмеÑто ALTER OWNER\n" -#: pg_dump.c:922 pg_dumpall.c:581 pg_restore.c:476 +#: pg_dump.c:915 pg_dumpall.c:581 pg_restore.c:476 #, c-format msgid "" "\n" @@ -1794,33 +1789,33 @@ msgstr "" "\n" "Параметры подключениÑ:\n" -#: pg_dump.c:923 +#: pg_dump.c:916 #, c-format msgid " -d, --dbname=DBNAME database to dump\n" msgstr " -d, --dbname=БД Ð¸Ð¼Ñ Ð±Ð°Ð·Ñ‹ данных Ð´Ð»Ñ Ð²Ñ‹Ð³Ñ€ÑƒÐ·ÐºÐ¸\n" -#: pg_dump.c:924 pg_dumpall.c:583 pg_restore.c:477 +#: pg_dump.c:917 pg_dumpall.c:583 pg_restore.c:477 #, c-format msgid " -h, --host=HOSTNAME database server host or socket directory\n" msgstr "" " -h, --host=ИМЯ Ð¸Ð¼Ñ Ñервера баз данных или каталог Ñокетов\n" -#: pg_dump.c:925 pg_dumpall.c:585 pg_restore.c:478 +#: pg_dump.c:918 pg_dumpall.c:585 pg_restore.c:478 #, c-format msgid " -p, --port=PORT database server port number\n" msgstr " -p, --port=ПОРТ номер порта Ñервера БД\n" -#: pg_dump.c:926 pg_dumpall.c:586 pg_restore.c:479 +#: pg_dump.c:919 pg_dumpall.c:586 pg_restore.c:479 #, c-format msgid " -U, --username=NAME connect as specified database user\n" msgstr " -U, --username=ИМЯ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð±Ð°Ð· данных\n" -#: pg_dump.c:927 pg_dumpall.c:587 pg_restore.c:480 +#: pg_dump.c:920 pg_dumpall.c:587 pg_restore.c:480 #, c-format msgid " -w, --no-password never prompt for password\n" msgstr " -w, --no-password не запрашивать пароль\n" -#: pg_dump.c:928 pg_dumpall.c:588 pg_restore.c:481 +#: pg_dump.c:921 pg_dumpall.c:588 pg_restore.c:481 #, c-format msgid "" " -W, --password force password prompt (should happen " @@ -1828,12 +1823,12 @@ msgid "" msgstr "" " -W, --password запрашивать пароль вÑегда (обычно не требуетÑÑ)\n" -#: pg_dump.c:929 pg_dumpall.c:589 +#: pg_dump.c:922 pg_dumpall.c:589 #, c-format msgid " --role=ROLENAME do SET ROLE before dump\n" msgstr " --role=ИМЯ_РОЛИ выполнить SET ROLE перед выгрузкой\n" -#: pg_dump.c:931 +#: pg_dump.c:924 #, c-format msgid "" "\n" @@ -1846,166 +1841,177 @@ msgstr "" "PGDATABASE.\n" "\n" -#: pg_dump.c:933 pg_dumpall.c:593 pg_restore.c:488 +#: pg_dump.c:926 pg_dumpall.c:593 pg_restore.c:488 #, c-format msgid "Report bugs to .\n" msgstr "Об ошибках Ñообщайте по адреÑу .\n" -#: pg_dump.c:953 +#: pg_dump.c:943 #, c-format msgid "invalid client encoding \"%s\" specified\n" msgstr "указана Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ»Ð¸ÐµÐ½Ñ‚ÑÐºÐ°Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²ÐºÐ° \"%s\"\n" -#: pg_dump.c:1138 +#: pg_dump.c:1083 +#, c-format +msgid "" +"Synchronized snapshots are not supported on standby servers.\n" +"Run with --no-synchronized-snapshots instead if you do not need\n" +"synchronized snapshots.\n" +msgstr "" +"Ðа резервных Ñерверах Ñинхронизированные Ñнимки не поддерживаютÑÑ.\n" +"ЕÑли они вам не нужны, укажите при запуÑке ключ\n" +"--no-synchronized-snapshots.\n" + +#: pg_dump.c:1152 #, c-format msgid "invalid output format \"%s\" specified\n" msgstr "указан неверный формат вывода: \"%s\"\n" -#: pg_dump.c:1160 +#: pg_dump.c:1174 #, c-format msgid "server version must be at least 7.3 to use schema selection switches\n" msgstr "" "Ð´Ð»Ñ Ð¸ÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð² выбора Ñхемы нужен Ñервер верÑии 7.3 или новее\n" -#: pg_dump.c:1524 +#: pg_dump.c:1538 #, c-format msgid "dumping contents of table \"%s.%s\"\n" msgstr "выгрузка Ñодержимого таблицы \"%s.%s\"\n" -#: pg_dump.c:1648 +#: pg_dump.c:1662 #, c-format msgid "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n" msgstr "Ошибка выгрузки таблицы \"%s\": Ñбой в PQendcopy().\n" -#: pg_dump.c:1649 pg_dump.c:1659 +#: pg_dump.c:1663 pg_dump.c:1673 #, c-format msgid "Error message from server: %s" msgstr "Сообщение об ошибке Ñ Ñервера: %s" -#: pg_dump.c:1650 pg_dump.c:1660 +#: pg_dump.c:1664 pg_dump.c:1674 #, c-format msgid "The command was: %s\n" msgstr "ВыполнÑлаÑÑŒ команда: %s\n" -#: pg_dump.c:1658 +#: pg_dump.c:1672 #, c-format msgid "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n" msgstr "Ошибка выгрузки таблицы \"%s\": Ñбой в PQgetResult().\n" -#: pg_dump.c:2300 +#: pg_dump.c:2319 #, c-format msgid "saving database definition\n" msgstr "Ñохранение Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных\n" -#: pg_dump.c:2633 +#: pg_dump.c:2652 #, c-format msgid "saving encoding = %s\n" msgstr "Ñохранение кодировки (%s)\n" -#: pg_dump.c:2660 +#: pg_dump.c:2679 #, c-format msgid "saving standard_conforming_strings = %s\n" msgstr "Ñохранение standard_conforming_strings (%s)\n" -#: pg_dump.c:2693 +#: pg_dump.c:2712 #, c-format msgid "reading large objects\n" msgstr "чтение больших объектов\n" -#: pg_dump.c:2825 +#: pg_dump.c:2844 #, c-format msgid "saving large objects\n" msgstr "Ñохранение больших объектов\n" -#: pg_dump.c:2872 +#: pg_dump.c:2891 #, c-format msgid "error reading large object %u: %s" msgstr "ошибка Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¾Ð³Ð¾ объекта %u: %s" -#: pg_dump.c:2924 +#: pg_dump.c:2943 #, c-format msgid "reading row security enabled for table \"%s.%s\"\n" msgstr "чтение информации о защите Ñтрок Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s.%s\"\n" -#: pg_dump.c:2955 +#: pg_dump.c:2974 #, c-format msgid "reading policies for table \"%s.%s\"\n" msgstr "чтение политик таблицы \"%s.%s\"\n" -#: pg_dump.c:3086 +#: pg_dump.c:3105 #, c-format msgid "unexpected policy command type: \"%s\"\n" msgstr "нераÑпознанный тип команды в политике: \"%s\"\n" -#: pg_dump.c:3301 +#: pg_dump.c:3320 #, c-format msgid "could not find parent extension for %s\n" msgstr "не удалоÑÑŒ найти родительÑкое раÑширение Ð´Ð»Ñ %s\n" # TO REVIEW -#: pg_dump.c:3405 +#: pg_dump.c:3424 #, c-format msgid "WARNING: owner of schema \"%s\" appears to be invalid\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: у Ñхемы \"%s\" по-видимому неправильный владелец\n" -#: pg_dump.c:3448 +#: pg_dump.c:3467 #, c-format msgid "schema with OID %u does not exist\n" msgstr "Ñхема Ñ OID %u не ÑущеÑтвует\n" -#: pg_dump.c:3800 +#: pg_dump.c:3819 #, c-format msgid "WARNING: owner of data type \"%s\" appears to be invalid\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: у типа данных \"%s\" по-видимому неправильный владелец\n" -#: pg_dump.c:3912 +#: pg_dump.c:3931 #, c-format msgid "WARNING: owner of operator \"%s\" appears to be invalid\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: у оператора \"%s\" по-видимому неправильный владелец\n" -#: pg_dump.c:4174 +#: pg_dump.c:4193 #, c-format msgid "WARNING: owner of operator class \"%s\" appears to be invalid\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: у клаÑÑа операторов \"%s\" по-видимому неправильный " "владелец\n" -#: pg_dump.c:4263 +#: pg_dump.c:4282 #, c-format msgid "WARNING: owner of operator family \"%s\" appears to be invalid\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: у ÑемейÑтва операторов \"%s\" по-видимому неправильный " "владелец\n" -#: pg_dump.c:4402 +#: pg_dump.c:4421 #, c-format msgid "WARNING: owner of aggregate function \"%s\" appears to be invalid\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: у агрегатной функции \"%s\" по-видимому неправильный " "владелец\n" -#: pg_dump.c:4585 +#: pg_dump.c:4604 #, c-format msgid "WARNING: owner of function \"%s\" appears to be invalid\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: у функции \"%s\" по-видимому неправильный владелец\n" -#: pg_dump.c:5273 +#: pg_dump.c:5292 #, c-format msgid "WARNING: owner of table \"%s\" appears to be invalid\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: у таблицы \"%s\" по-видимому неправильный владелец\n" -#: pg_dump.c:5425 +#: pg_dump.c:5444 #, c-format msgid "reading indexes for table \"%s.%s\"\n" msgstr "чтение индекÑов таблицы \"%s.%s\"\n" -#: pg_dump.c:5792 +#: pg_dump.c:5811 #, c-format msgid "reading foreign key constraints for table \"%s.%s\"\n" msgstr "чтение ограничений внешних ключей таблицы \"%s.%s\"\n" -#: pg_dump.c:6038 +#: pg_dump.c:6057 #, c-format msgid "" "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not " @@ -2014,12 +2020,12 @@ msgstr "" "по OID %u не удалоÑÑŒ найти родительÑкую таблицу Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи pg_rewrite Ñ OID " "%u\n" -#: pg_dump.c:6131 +#: pg_dump.c:6150 #, c-format msgid "reading triggers for table \"%s.%s\"\n" msgstr "чтение триггеров таблицы \"%s.%s\"\n" -#: pg_dump.c:6293 +#: pg_dump.c:6315 #, c-format msgid "" "query produced null referenced table name for foreign key trigger \"%s\" on " @@ -2028,32 +2034,32 @@ msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ вернул Ð¸Ð¼Ñ Ñ†ÐµÐ»ÐµÐ²Ð¾Ð¹ таблицы Ð´Ð»Ñ Ñ‚Ñ€Ð¸Ð³Ð³ÐµÑ€Ð° внешнего ключа \"%s\" в " "таблице \"%s\" (OID целевой таблицы: %u)\n" -#: pg_dump.c:6879 +#: pg_dump.c:6901 #, c-format msgid "finding the columns and types of table \"%s.%s\"\n" msgstr "поиÑк Ñтолбцов и типов таблицы \"%s.%s\"\n" -#: pg_dump.c:7058 +#: pg_dump.c:7080 #, c-format msgid "invalid column numbering in table \"%s\"\n" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð½ÑƒÐ¼ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтолбцов в таблице \"%s\"\n" -#: pg_dump.c:7092 +#: pg_dump.c:7114 #, c-format msgid "finding default expressions of table \"%s.%s\"\n" msgstr "поиÑк выражений по умолчанию Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s.%s\"\n" -#: pg_dump.c:7145 +#: pg_dump.c:7167 #, c-format msgid "invalid adnum value %d for table \"%s\"\n" msgstr "неверное значение adnum (%d) в таблице \"%s\"\n" -#: pg_dump.c:7217 +#: pg_dump.c:7239 #, c-format msgid "finding check constraints for table \"%s.%s\"\n" msgstr "поиÑк ограничений-проверок Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s.%s\"\n" -#: pg_dump.c:7313 +#: pg_dump.c:7335 #, c-format msgid "expected %d check constraint on table \"%s\" but found %d\n" msgid_plural "expected %d check constraints on table \"%s\" but found %d\n" @@ -2064,61 +2070,61 @@ msgstr[1] "" msgstr[2] "" "ожидалоÑÑŒ %d ограничений-проверок Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s\", но найдено: %d\n" -#: pg_dump.c:7317 +#: pg_dump.c:7339 #, c-format msgid "(The system catalogs might be corrupted.)\n" msgstr "(Возможно повреждены ÑиÑтемные каталоги.)\n" -#: pg_dump.c:8707 +#: pg_dump.c:8729 #, c-format msgid "WARNING: typtype of data type \"%s\" appears to be invalid\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: у типа данных \"%s\" по-видимому неправильный тип типа\n" -#: pg_dump.c:10203 +#: pg_dump.c:10225 #, c-format msgid "WARNING: bogus value in proargmodes array\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: неприемлемое значение в маÑÑиве proargmodes\n" -#: pg_dump.c:10555 +#: pg_dump.c:10577 #, c-format msgid "WARNING: could not parse proallargtypes array\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: не удалоÑÑŒ разобрать маÑÑив proallargtypes\n" -#: pg_dump.c:10571 +#: pg_dump.c:10593 #, c-format msgid "WARNING: could not parse proargmodes array\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: не удалоÑÑŒ разобрать маÑÑив proargmodes\n" -#: pg_dump.c:10585 +#: pg_dump.c:10607 #, c-format msgid "WARNING: could not parse proargnames array\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: не удалоÑÑŒ разобрать маÑÑив proargnames\n" -#: pg_dump.c:10596 +#: pg_dump.c:10618 #, c-format msgid "WARNING: could not parse proconfig array\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: не удалоÑÑŒ разобрать маÑÑив proconfig\n" # TO REVEIW -#: pg_dump.c:10667 +#: pg_dump.c:10689 #, c-format msgid "unrecognized provolatile value for function \"%s\"\n" msgstr "недопуÑтимое значение provolatile Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ \"%s\"\n" -#: pg_dump.c:10844 +#: pg_dump.c:10866 #, c-format msgid "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n" msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: неприемлемое значение в поле pg_cast.castfunc или pg_cast." "castmethod\n" -#: pg_dump.c:10847 +#: pg_dump.c:10869 #, c-format msgid "WARNING: bogus value in pg_cast.castmethod field\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: неприемлемое значение в поле pg_cast.castmethod\n" -#: pg_dump.c:10931 +#: pg_dump.c:10953 #, c-format msgid "" "WARNING: bogus transform definition, at least one of trffromsql and trftosql " @@ -2127,22 +2133,22 @@ msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: неприемлемое определение Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ (trffromsql или " "trftosql должно быть ненулевым)\n" -#: pg_dump.c:10948 +#: pg_dump.c:10970 #, c-format msgid "WARNING: bogus value in pg_transform.trffromsql field\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: неприемлемое значение в поле pg_transform.trffromsql\n" -#: pg_dump.c:10969 +#: pg_dump.c:10991 #, c-format msgid "WARNING: bogus value in pg_transform.trftosql field\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: неприемлемое значение в поле pg_transform.trftosql\n" -#: pg_dump.c:11356 +#: pg_dump.c:11378 #, c-format msgid "WARNING: could not find operator with OID %s\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: оператор Ñ OID %s не найден\n" -#: pg_dump.c:12536 +#: pg_dump.c:12513 #, c-format msgid "" "WARNING: aggregate function %s could not be dumped correctly for this " @@ -2151,28 +2157,28 @@ msgstr "" "ПРЕДУПРЕЖДЕÐИЕ: Ð°Ð³Ñ€ÐµÐ³Ð°Ñ‚Ð½Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ %s не может быть правильно выгружена Ð´Ð»Ñ " "Ñтой верÑии базы данных; Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿Ñ€Ð¾Ð¸Ð³Ð½Ð¾Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð°\n" -#: pg_dump.c:13360 +#: pg_dump.c:13337 #, c-format msgid "unrecognized object type in default privileges: %d\n" msgstr "нераÑпознанный тип объекта в определении прав по умолчанию: %d)\n" -#: pg_dump.c:13375 +#: pg_dump.c:13352 #, c-format msgid "could not parse default ACL list (%s)\n" msgstr "не удалоÑÑŒ разобрать ÑпиÑок прав по умолчанию (%s)\n" -#: pg_dump.c:13431 +#: pg_dump.c:13408 #, c-format msgid "could not parse ACL list (%s) for object \"%s\" (%s)\n" msgstr "не удалоÑÑŒ разобрать ÑпиÑок прав (%s) Ð´Ð»Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð° \"%s\" (%s)\n" -#: pg_dump.c:13852 +#: pg_dump.c:13829 #, c-format msgid "query to obtain definition of view \"%s\" returned no data\n" msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° получение Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\" не возвратил данные\n" -#: pg_dump.c:13855 +#: pg_dump.c:13832 #, c-format msgid "" "query to obtain definition of view \"%s\" returned more than one definition\n" @@ -2180,27 +2186,27 @@ msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´ÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\" возвратил неÑколько " "определений\n" -#: pg_dump.c:13862 +#: pg_dump.c:13839 #, c-format msgid "definition of view \"%s\" appears to be empty (length zero)\n" msgstr "определение предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ \"%s\" пуÑтое (длина равна нулю)\n" -#: pg_dump.c:14610 +#: pg_dump.c:14587 #, c-format msgid "invalid column number %d for table \"%s\"\n" msgstr "неверный номер Ñтолбца %d Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s\"\n" -#: pg_dump.c:14736 +#: pg_dump.c:14713 #, c-format msgid "missing index for constraint \"%s\"\n" msgstr "отÑутÑтвует Ð¸Ð½Ð´ÐµÐºÑ Ð´Ð»Ñ Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ \"%s\"\n" -#: pg_dump.c:14927 +#: pg_dump.c:14904 #, c-format msgid "unrecognized constraint type: %c\n" msgstr "нераÑпознанный тип ограничениÑ: %c\n" -#: pg_dump.c:15077 pg_dump.c:15241 +#: pg_dump.c:15054 pg_dump.c:15218 #, c-format msgid "query to get data of sequence \"%s\" returned %d row (expected 1)\n" msgid_plural "" @@ -2215,23 +2221,23 @@ msgstr[2] "" "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° получение данных поÑледовательноÑти \"%s\" вернул %d Ñтрок " "(ожидалаÑÑŒ 1)\n" -#: pg_dump.c:15088 +#: pg_dump.c:15065 #, c-format msgid "query to get data of sequence \"%s\" returned name \"%s\"\n" msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° получение данных поÑледовательноÑти \"%s\" вернул Ð¸Ð¼Ñ \"%s\"\n" -#: pg_dump.c:15337 +#: pg_dump.c:15314 #, c-format msgid "unexpected tgtype value: %d\n" msgstr "неожиданное значение tgtype: %d\n" -#: pg_dump.c:15419 +#: pg_dump.c:15396 #, c-format msgid "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ñтрока аргументов (%s) Ð´Ð»Ñ Ñ‚Ñ€Ð¸Ð³Ð³ÐµÑ€Ð° \"%s\" таблицы \"%s\"\n" -#: pg_dump.c:15608 +#: pg_dump.c:15585 #, c-format msgid "" "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows " @@ -2240,24 +2246,16 @@ msgstr "" "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° получение правила \"%s\" Ð´Ð»Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ‹ \"%s\" возвратил неверное " "чиÑло Ñтрок\n" -#: pg_dump.c:15990 +#: pg_dump.c:15967 #, c-format msgid "reading dependency data\n" msgstr "чтение данных о завиÑимоÑÑ‚ÑÑ…\n" -#: pg_dump.c:16550 +#: pg_dump.c:16527 #, c-format msgid "WARNING: could not parse reloptions array\n" msgstr "ПРЕДУПРЕЖДЕÐИЕ: не удалоÑÑŒ разобрать маÑÑив reloptions\n" -#: pg_dump.c:16614 -#, c-format -msgid "query returned %d row instead of one: %s\n" -msgid_plural "query returned %d rows instead of one: %s\n" -msgstr[0] "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ð½ÑƒÐ» %d Ñтроку вмеÑто одной: %s\n" -msgstr[1] "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ð½ÑƒÐ» %d Ñтроки вмеÑто одной: %s\n" -msgstr[2] "Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð²ÐµÑ€Ð½ÑƒÐ» %d Ñтрок вмеÑто одной: %s\n" - #. translator: this is a module name #: pg_dump_sort.c:23 msgid "sorter" @@ -2278,7 +2276,7 @@ msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð·Ð°Ð²Ð¸ÑимоÑть %d\n" msgid "could not identify dependency loop\n" msgstr "не удалоÑÑŒ определить цикл завиÑимоÑтей\n" -#: pg_dump_sort.c:1250 +#: pg_dump_sort.c:1254 #, c-format msgid "NOTICE: there are circular foreign-key constraints on this table:\n" msgid_plural "" @@ -2290,12 +2288,12 @@ msgstr[1] "" msgstr[2] "" "ЗÐМЕЧÐÐИЕ: в Ñледующих таблицах зациклены Ð¾Ð³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð²Ð½ÐµÑˆÐ½Ð¸Ñ… ключей:\n" -#: pg_dump_sort.c:1254 pg_dump_sort.c:1274 +#: pg_dump_sort.c:1258 pg_dump_sort.c:1278 #, c-format msgid " %s\n" msgstr " %s\n" -#: pg_dump_sort.c:1255 +#: pg_dump_sort.c:1259 #, c-format msgid "" "You might not be able to restore the dump without using --disable-triggers " @@ -2304,7 +2302,7 @@ msgstr "" "Возможно Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ‹ вам потребуетÑÑ Ð¸Ñпользовать --disable-" "triggers или временно удалить ограничениÑ.\n" -#: pg_dump_sort.c:1256 +#: pg_dump_sort.c:1260 #, c-format msgid "" "Consider using a full dump instead of a --data-only dump to avoid this " @@ -2313,7 +2311,7 @@ msgstr "" "Во избежание Ñтой проблемы, вам вероÑтно Ñтоит выгружать вÑÑŽ базу данных, а " "не только данные (--data-only).\n" -#: pg_dump_sort.c:1268 +#: pg_dump_sort.c:1272 #, c-format msgid "WARNING: could not resolve dependency loop among these items:\n" msgstr "" @@ -2788,6 +2786,21 @@ msgstr "" "ввода.\n" "\n" +#~ msgid "could not get relation name for OID %u: %s\n" +#~ msgstr "не удалоÑÑŒ получить Ð¸Ð¼Ñ Ð¾Ñ‚Ð½Ð¾ÑˆÐµÐ½Ð¸Ñ Ñ OID %u: %s\n" + +#~ msgid "terminated by user\n" +#~ msgstr "прервано пользователем\n" + +#~ msgid "error in ListenToWorkers(): %s\n" +#~ msgstr "ошибка в ListenToWorkers(): %s\n" + +#~ msgid "worker is terminating\n" +#~ msgstr "рабочий процеÑÑ Ð¿Ñ€ÐµÑ€Ñ‹Ð²Ð°ÐµÑ‚ÑÑ\n" + +#~ msgid "could not open output file \"%s\" for writing\n" +#~ msgstr "не удалоÑÑŒ открыть выходной файл \"%s\" Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñи\n" + #~ msgid "archive member too large for tar format\n" #~ msgstr "компонент архива Ñлишком велик Ð´Ð»Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð° tar\n" diff --git a/src/bin/pg_resetxlog/po/de.po b/src/bin/pg_resetxlog/po/de.po index 0aa99937aa..57a043e027 100644 --- a/src/bin/pg_resetxlog/po/de.po +++ b/src/bin/pg_resetxlog/po/de.po @@ -1,7 +1,7 @@ # German message translation file for pg_resetxlog # Peter Eisentraut , 2002 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -39,7 +39,7 @@ msgstr "%s: konnte beschränktes Token nicht erzeugen: Fehlercode %lu\n" #: ../../common/restricted_token.c:132 #, c-format msgid "%s: could not start process for command \"%s\": error code %lu\n" -msgstr "%s: konnte Prozess für Befehl „%s“ nicht starten: Fehlercode %lu\n" +msgstr "%s: konnte Prozess für Befehl »%s« nicht starten: Fehlercode %lu\n" #: ../../common/restricted_token.c:170 #, c-format @@ -64,7 +64,7 @@ msgstr "%s: ungültiges Argument für Option %s\n" #: pg_resetxlog.c:265 pg_resetxlog.c:272 pg_resetxlog.c:285 pg_resetxlog.c:293 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: pg_resetxlog.c:146 #, c-format @@ -104,7 +104,7 @@ msgstr "%s: Multitransaktions-Offset (-O) darf nicht -1 sein\n" #: pg_resetxlog.c:283 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: pg_resetxlog.c:292 #, c-format @@ -114,7 +114,7 @@ msgstr "%s: kein Datenverzeichnis angegeben\n" #: pg_resetxlog.c:306 #, c-format msgid "%s: cannot be executed by \"root\"\n" -msgstr "%s: kann nicht von „root“ ausgeführt werden\n" +msgstr "%s: kann nicht von »root« ausgeführt werden\n" #: pg_resetxlog.c:308 #, c-format @@ -124,12 +124,12 @@ msgstr "Sie müssen %s als PostgreSQL-Superuser ausführen.\n" #: pg_resetxlog.c:318 #, c-format msgid "%s: could not change directory to \"%s\": %s\n" -msgstr "%s: konnte nicht in Verzeichnis „%s“ wechseln: %s\n" +msgstr "%s: konnte nicht in Verzeichnis »%s« wechseln: %s\n" #: pg_resetxlog.c:331 pg_resetxlog.c:477 #, c-format msgid "%s: could not open file \"%s\" for reading: %s\n" -msgstr "%s: konnte Datei „%s“ nicht zum Lesen öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht zum Lesen öffnen: %s\n" #: pg_resetxlog.c:338 #, c-format @@ -137,7 +137,7 @@ msgid "" "%s: lock file \"%s\" exists\n" "Is a server running? If not, delete the lock file and try again.\n" msgstr "" -"%s: Sperrdatei „%s“ existiert bereits\n" +"%s: Sperrdatei »%s« existiert bereits\n" "Läuft der Server? Wenn nicht, dann Sperrdatei löschen und nochmal versuchen.\n" #: pg_resetxlog.c:425 @@ -181,7 +181,7 @@ msgstr "" #: pg_resetxlog.c:493 #, c-format msgid "%s: could not read file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht lesen: %s\n" +msgstr "%s: konnte Datei »%s« nicht lesen: %s\n" #: pg_resetxlog.c:516 #, c-format @@ -476,32 +476,32 @@ msgstr "%s: fsync-Fehler: %s\n" #: pg_resetxlog.c:900 pg_resetxlog.c:971 pg_resetxlog.c:1022 #, c-format msgid "%s: could not open directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht öffnen: %s\n" #: pg_resetxlog.c:936 pg_resetxlog.c:993 pg_resetxlog.c:1047 #, c-format msgid "%s: could not read directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht lesen: %s\n" #: pg_resetxlog.c:943 pg_resetxlog.c:1000 pg_resetxlog.c:1054 #, c-format msgid "%s: could not close directory \"%s\": %s\n" -msgstr "%s: konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "%s: konnte Verzeichnis »%s« nicht schließen: %s\n" #: pg_resetxlog.c:984 pg_resetxlog.c:1038 #, c-format msgid "%s: could not delete file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht löschen: %s\n" +msgstr "%s: konnte Datei »%s« nicht löschen: %s\n" #: pg_resetxlog.c:1123 #, c-format msgid "%s: could not open file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht öffnen: %s\n" #: pg_resetxlog.c:1134 pg_resetxlog.c:1148 #, c-format msgid "%s: could not write file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht schreiben: %s\n" +msgstr "%s: konnte Datei »%s« nicht schreiben: %s\n" #: pg_resetxlog.c:1167 #, c-format diff --git a/src/bin/pg_rewind/po/de.po b/src/bin/pg_rewind/po/de.po index 1cfd6305b1..b274e716af 100644 --- a/src/bin/pg_rewind/po/de.po +++ b/src/bin/pg_rewind/po/de.po @@ -51,7 +51,7 @@ msgstr "%s: konnte beschränktes Token nicht erzeugen: Fehlercode %lu\n" #: ../../common/restricted_token.c:132 #, c-format msgid "%s: could not start process for command \"%s\": error code %lu\n" -msgstr "%s: konnte Prozess für Befehl „%s“ nicht starten: Fehlercode %lu\n" +msgstr "%s: konnte Prozess für Befehl »%s« nicht starten: Fehlercode %lu\n" #: ../../common/restricted_token.c:170 #, c-format @@ -66,42 +66,42 @@ msgstr "%s: konnte Statuscode des Subprozesses nicht ermitteln: Fehlercode %lu\n #: copy_fetch.c:64 #, c-format msgid "could not open directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht öffnen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht öffnen: %s\n" #: copy_fetch.c:93 filemap.c:112 filemap.c:267 #, c-format msgid "could not stat file \"%s\": %s\n" -msgstr "konnte „stat“ für Datei „%s“ nicht ausführen: %s\n" +msgstr "konnte »stat« für Datei »%s« nicht ausführen: %s\n" #: copy_fetch.c:122 #, c-format msgid "could not read symbolic link \"%s\": %s\n" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen: %s\n" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen: %s\n" #: copy_fetch.c:125 #, c-format msgid "symbolic link \"%s\" target is too long\n" -msgstr "Ziel für symbolische Verknüpfung „%s“ ist zu lang\n" +msgstr "Ziel für symbolische Verknüpfung »%s« ist zu lang\n" #: copy_fetch.c:140 #, c-format msgid "\"%s\" is a symbolic link, but symbolic links are not supported on this platform\n" -msgstr "„%s“ ist eine symbolische Verknüpfung, aber symbolische Verknüpfungen werden auf dieser Plattform nicht unterstützt\n" +msgstr "»%s« ist eine symbolische Verknüpfung, aber symbolische Verknüpfungen werden auf dieser Plattform nicht unterstützt\n" #: copy_fetch.c:147 #, c-format msgid "could not read directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht lesen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht lesen: %s\n" #: copy_fetch.c:151 #, c-format msgid "could not close directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht schließen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht schließen: %s\n" #: copy_fetch.c:171 #, c-format msgid "could not open source file \"%s\": %s\n" -msgstr "konnte Quelldatei „%s“ nicht öffnen: %s\n" +msgstr "konnte Quelldatei »%s« nicht öffnen: %s\n" #: copy_fetch.c:175 #, c-format @@ -111,37 +111,37 @@ msgstr "konnte Positionszeiger in Quelldatei nicht setzen: %s\n" #: copy_fetch.c:192 file_ops.c:300 #, c-format msgid "could not read file \"%s\": %s\n" -msgstr "konnte Datei „%s“ nicht lesen: %s\n" +msgstr "konnte Datei »%s« nicht lesen: %s\n" #: copy_fetch.c:195 #, c-format msgid "unexpected EOF while reading file \"%s\"\n" -msgstr "unerwartetes EOF beim Lesen der Datei „%s“\n" +msgstr "unerwartetes EOF beim Lesen der Datei »%s«\n" #: copy_fetch.c:202 #, c-format msgid "could not close file \"%s\": %s\n" -msgstr "konnte Datei „%s“ nicht schließen: %s\n" +msgstr "konnte Datei »%s« nicht schließen: %s\n" #: file_ops.c:64 #, c-format msgid "could not open target file \"%s\": %s\n" -msgstr "konnte Zieldatei „%s“ nicht öffnen: %s\n" +msgstr "konnte Zieldatei »%s« nicht öffnen: %s\n" #: file_ops.c:78 #, c-format msgid "could not close target file \"%s\": %s\n" -msgstr "konnte Zieldatei „%s“ nicht schließen: %s\n" +msgstr "konnte Zieldatei »%s« nicht schließen: %s\n" #: file_ops.c:98 #, c-format msgid "could not seek in target file \"%s\": %s\n" -msgstr "konnte Positionszeiger in Zieldatei „%s“ nicht setzen: %s\n" +msgstr "konnte Positionszeiger in Zieldatei »%s« nicht setzen: %s\n" #: file_ops.c:114 #, c-format msgid "could not write file \"%s\": %s\n" -msgstr "konnte Datei „%s“ nicht schreiben: %s\n" +msgstr "konnte Datei »%s« nicht schreiben: %s\n" #: file_ops.c:164 #, c-format @@ -151,62 +151,62 @@ msgstr "ungültige Aktion (CREATE) für normale Datei\n" #: file_ops.c:179 #, c-format msgid "could not remove file \"%s\": %s\n" -msgstr "konnte Datei „%s“ nicht löschen: %s\n" +msgstr "konnte Datei »%s« nicht löschen: %s\n" #: file_ops.c:196 #, c-format msgid "could not open file \"%s\" for truncation: %s\n" -msgstr "konnte Datei „%s“ nicht zum Kürzen öffnen: %s\n" +msgstr "konnte Datei »%s« nicht zum Kürzen öffnen: %s\n" #: file_ops.c:200 #, c-format msgid "could not truncate file \"%s\" to %u: %s\n" -msgstr "konnte Datei „%s“ nicht auf %u kürzen: %s\n" +msgstr "konnte Datei »%s« nicht auf %u kürzen: %s\n" #: file_ops.c:216 #, c-format msgid "could not create directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht erzeugen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht erzeugen: %s\n" #: file_ops.c:230 #, c-format msgid "could not remove directory \"%s\": %s\n" -msgstr "konnte Verzeichnis „%s“ nicht löschen: %s\n" +msgstr "konnte Verzeichnis »%s« nicht löschen: %s\n" #: file_ops.c:244 #, c-format msgid "could not create symbolic link at \"%s\": %s\n" -msgstr "konnte symbolische Verknüpfung „%s“ nicht erstellen: %s\n" +msgstr "konnte symbolische Verknüpfung »%s« nicht erstellen: %s\n" #: file_ops.c:258 #, c-format msgid "could not remove symbolic link \"%s\": %s\n" -msgstr "konnte symbolische Verknüpfung „%s“ nicht löschen: %s\n" +msgstr "konnte symbolische Verknüpfung »%s« nicht löschen: %s\n" #: file_ops.c:288 file_ops.c:292 #, c-format msgid "could not open file \"%s\" for reading: %s\n" -msgstr "konnte Datei „%s“ nicht zum Lesen öffnen: %s\n" +msgstr "konnte Datei »%s« nicht zum Lesen öffnen: %s\n" #: filemap.c:104 #, c-format msgid "data file \"%s\" in source is not a regular file\n" -msgstr "Datendatei „%s“ in der Quelle ist keine normale Datei\n" +msgstr "Datendatei »%s« in der Quelle ist keine normale Datei\n" #: filemap.c:126 #, c-format msgid "\"%s\" is not a directory\n" -msgstr "„%s“ ist kein Verzeichnis\n" +msgstr "»%s« ist kein Verzeichnis\n" #: filemap.c:149 #, c-format msgid "\"%s\" is not a symbolic link\n" -msgstr "„%s“ ist keine symbolische Verknüpfung\n" +msgstr "»%s« ist keine symbolische Verknüpfung\n" #: filemap.c:161 #, c-format msgid "\"%s\" is not a regular file\n" -msgstr "„%s“ ist keine normale Datei\n" +msgstr "»%s« ist keine normale Datei\n" #: filemap.c:279 #, c-format @@ -216,7 +216,7 @@ msgstr "Quelldateiliste ist leer\n" #: filemap.c:401 #, c-format msgid "unexpected page modification for directory or symbolic link \"%s\"\n" -msgstr "unerwartete Seitenänderung für Verzeichnis oder symbolische Verknüpfung „%s“\n" +msgstr "unerwartete Seitenänderung für Verzeichnis oder symbolische Verknüpfung »%s«\n" #: libpq_fetch.c:55 #, c-format @@ -251,7 +251,7 @@ msgstr "Anfrage ergab unerwartete Ergebnismenge\n" #: libpq_fetch.c:123 #, c-format msgid "unrecognized result \"%s\" for current WAL insert location\n" -msgstr "unbekanntes Ergebnis „%s“ für aktuelle WAL-Einfügeposition\n" +msgstr "unbekanntes Ergebnis »%s« für aktuelle WAL-Einfügeposition\n" #: libpq_fetch.c:173 #, c-format @@ -311,27 +311,27 @@ msgstr "unerwartete Ergebnislänge beim Holen von fernen Dateien\n" #: libpq_fetch.c:303 #, c-format msgid "received null value for chunk for file \"%s\", file has been deleted\n" -msgstr "NULL-Wert für Stück von Datei „%s“ empfangen, Datei wurde gelöscht\n" +msgstr "NULL-Wert für Stück von Datei »%s« empfangen, Datei wurde gelöscht\n" #: libpq_fetch.c:310 #, c-format msgid "received chunk for file \"%s\", offset %d, size %d\n" -msgstr "Stück von Datei „%s“ empfangen, Offset %d, Größe %d\n" +msgstr "Stück von Datei »%s« empfangen, Offset %d, Größe %d\n" #: libpq_fetch.c:339 #, c-format msgid "could not fetch remote file \"%s\": %s" -msgstr "konnte ferne Datei „%s“ nicht holen: %s" +msgstr "konnte ferne Datei »%s« nicht holen: %s" #: libpq_fetch.c:344 #, c-format msgid "unexpected result set while fetching remote file \"%s\"\n" -msgstr "unerwartete Ergebnismenge beim Holen der fernen Datei „%s“\n" +msgstr "unerwartete Ergebnismenge beim Holen der fernen Datei »%s«\n" #: libpq_fetch.c:355 #, c-format msgid "fetched file \"%s\", length %d\n" -msgstr "Datei „%s“ geholt, Länge %d\n" +msgstr "Datei »%s« geholt, Länge %d\n" #: libpq_fetch.c:387 #, c-format @@ -390,17 +390,17 @@ msgstr "konnte vorangegangenen WAL-Eintrag bei %X/%X nicht finden\n" #: parsexlog.c:268 #, c-format msgid "could not open file \"%s\": %s\n" -msgstr "konnte Datei „%s“ nicht öffnen: %s\n" +msgstr "konnte Datei »%s« nicht öffnen: %s\n" #: parsexlog.c:282 #, c-format msgid "could not seek in file \"%s\": %s\n" -msgstr "konnte Positionszeiger in Datei „%s“ nicht setzen: %s\n" +msgstr "konnte Positionszeiger in Datei »%s« nicht setzen: %s\n" #: parsexlog.c:289 #, c-format msgid "could not read from file \"%s\": %s\n" -msgstr "konnte nicht aus Datei „%s“ nicht lesen: %s\n" +msgstr "konnte nicht aus Datei »%s« nicht lesen: %s\n" #: parsexlog.c:357 #, c-format @@ -490,7 +490,7 @@ msgstr "" #: pg_rewind.c:126 pg_rewind.c:157 pg_rewind.c:164 pg_rewind.c:172 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: pg_rewind.c:156 #, c-format @@ -505,12 +505,12 @@ msgstr "%s: kein Zielverzeichnis angegeben (--target-pgdata)\n" #: pg_rewind.c:170 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: pg_rewind.c:185 #, c-format msgid "cannot be executed by \"root\"\n" -msgstr "kann nicht von „root“ ausgeführt werden\n" +msgstr "kann nicht von »root« ausgeführt werden\n" #: pg_rewind.c:186 #, c-format @@ -589,7 +589,7 @@ msgstr "die Cluster sind nicht mit dieser Version von pg_rewind kompatibel\n" #: pg_rewind.c:380 #, c-format msgid "target server needs to use either data checksums or \"wal_log_hints = on\"\n" -msgstr "Zielserver muss entweder Datenprüfsummen oder „wal_log_hints = on“ verwenden\n" +msgstr "Zielserver muss entweder Datenprüfsummen oder »wal_log_hints = on« verwenden\n" #: pg_rewind.c:391 #, c-format @@ -628,8 +628,8 @@ msgid "" "not found in the same directory as \"%s\".\n" "Check your installation.\n" msgstr "" -"Das Programm „initdb“ wird von %s benötigt, aber wurde nicht im\n" -"selben Verzeichnis wie „%s“ gefunden.\n" +"Das Programm »initdb« wird von %s benötigt, aber wurde nicht im\n" +"selben Verzeichnis wie »%s« gefunden.\n" "Prüfen Sie Ihre Installation.\n" #: pg_rewind.c:612 @@ -639,7 +639,7 @@ msgid "" "but was not the same version as %s.\n" "Check your installation.\n" msgstr "" -"Das Programm „initdb“ wurde von %s gefunden,\n" +"Das Programm »initdb« wurde von %s gefunden,\n" "aber es hatte nicht die gleiche Version wie %s.\n" "Prüfen Sie Ihre Installation.\n" diff --git a/src/bin/pg_rewind/po/ru.po b/src/bin/pg_rewind/po/ru.po index 6313f94835..d72bc82b2e 100644 --- a/src/bin/pg_rewind/po/ru.po +++ b/src/bin/pg_rewind/po/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: pg_rewind (PostgreSQL) 9.6\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" -"POT-Creation-Date: 2015-10-17 05:43+0000\n" +"POT-Creation-Date: 2016-05-26 20:51+0000\n" "PO-Revision-Date: 2015-10-18 18:13+0400\n" "Last-Translator: Alexander Lakhin \n" "Language-Team: Russian \n" @@ -20,8 +20,7 @@ msgstr "" "X-Generator: Lokalize 2.0\n" #: ../../common/fe_memutils.c:35 ../../common/fe_memutils.c:75 -#: ../../common/fe_memutils.c:98 parsexlog.c:74 parsexlog.c:127 -#: parsexlog.c:179 +#: ../../common/fe_memutils.c:98 parsexlog.c:74 parsexlog.c:127 parsexlog.c:179 #, c-format msgid "out of memory\n" msgstr "нехватка памÑти\n" @@ -117,7 +116,7 @@ msgstr "не удалоÑÑŒ открыть иÑходный файл \"%s\": %s\ msgid "could not seek in source file: %s\n" msgstr "не удалоÑÑŒ перемеÑтитьÑÑ Ð² иÑходном файле: %s\n" -#: copy_fetch.c:192 file_ops.c:301 +#: copy_fetch.c:192 file_ops.c:300 #, c-format msgid "could not read file \"%s\": %s\n" msgstr "не удалоÑÑŒ прочитать файл \"%s\": %s\n" @@ -142,57 +141,57 @@ msgstr "не удалоÑÑŒ открыть целевой файл \"%s\": %s\n" msgid "could not close target file \"%s\": %s\n" msgstr "не удалоÑÑŒ закрыть целевой файл \"%s\": %s\n" -#: file_ops.c:99 +#: file_ops.c:98 #, c-format msgid "could not seek in target file \"%s\": %s\n" msgstr "не удалоÑÑŒ перемеÑтитьÑÑ Ð² целевом файле \"%s\": %s\n" -#: file_ops.c:115 +#: file_ops.c:114 #, c-format msgid "could not write file \"%s\": %s\n" msgstr "не удалоÑÑŒ запиÑать файл \"%s\": %s\n" -#: file_ops.c:165 +#: file_ops.c:164 #, c-format msgid "invalid action (CREATE) for regular file\n" msgstr "неверное дейÑтвие (CREATE) Ð´Ð»Ñ Ð¾Ð±Ñ‹Ñ‡Ð½Ð¾Ð³Ð¾ файла\n" -#: file_ops.c:180 +#: file_ops.c:179 #, c-format msgid "could not remove file \"%s\": %s\n" msgstr "не удалоÑÑŒ Ñтереть файл \"%s\": %s\n" -#: file_ops.c:197 +#: file_ops.c:196 #, c-format msgid "could not open file \"%s\" for truncation: %s\n" msgstr "не удалоÑÑŒ открыть файл \"%s\" Ð´Ð»Ñ ÑƒÑечениÑ: %s\n" -#: file_ops.c:201 +#: file_ops.c:200 #, c-format msgid "could not truncate file \"%s\" to %u: %s\n" msgstr "не удалоÑÑŒ уÑечь файл \"%s\" до нужного размера (%u): %s\n" -#: file_ops.c:217 +#: file_ops.c:216 #, c-format msgid "could not create directory \"%s\": %s\n" msgstr "Ñоздать каталог \"%s\" не удалоÑÑŒ: %s\n" -#: file_ops.c:231 +#: file_ops.c:230 #, c-format msgid "could not remove directory \"%s\": %s\n" msgstr "ошибка при удалении каталога \"%s\": %s\n" -#: file_ops.c:245 +#: file_ops.c:244 #, c-format msgid "could not create symbolic link at \"%s\": %s\n" msgstr "не удалоÑÑŒ Ñоздать ÑимволичеÑкую ÑÑылку \"%s\": %s\n" -#: file_ops.c:259 +#: file_ops.c:258 #, c-format msgid "could not remove symbolic link \"%s\": %s\n" msgstr "ошибка при удалении ÑимволичеÑкой ÑÑылки \"%s\": %s\n" -#: file_ops.c:289 file_ops.c:293 +#: file_ops.c:288 file_ops.c:292 #, c-format msgid "could not open file \"%s\" for reading: %s\n" msgstr "не удалоÑÑŒ открыть файл \"%s\" Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ: %s\n" @@ -427,7 +426,7 @@ msgstr "" "ЗапиÑÑŒ WAL модифицирует отношение, но тип запиÑи не раÑпознан\n" "lsn: %X/%X, rmgr: %s, info: %02X\n" -#: pg_rewind.c:59 +#: pg_rewind.c:60 #, c-format msgid "" "%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n" @@ -436,7 +435,7 @@ msgstr "" "%s Ñинхронизирует клаÑтер PostgreSQL Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¹ копией клаÑтера.\n" "\n" -#: pg_rewind.c:60 +#: pg_rewind.c:61 #, c-format msgid "" "Usage:\n" @@ -447,19 +446,19 @@ msgstr "" " %s [ПÐРÐМЕТР]...\n" "\n" -#: pg_rewind.c:61 +#: pg_rewind.c:62 #, c-format msgid "Options:\n" msgstr "Параметры:\n" -#: pg_rewind.c:62 +#: pg_rewind.c:63 #, c-format msgid " -D, --target-pgdata=DIRECTORY existing data directory to modify\n" msgstr "" " -D, --target-pgdata=КÐТÐЛОГ ÑущеÑтвующий каталог, куда будут запиÑаны " "данные\n" -#: pg_rewind.c:63 +#: pg_rewind.c:64 #, c-format msgid "" " --source-pgdata=DIRECTORY source data directory to synchronize with\n" @@ -467,43 +466,43 @@ msgstr "" " --source-pgdata=КÐТÐЛОГ иÑходный каталог, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼ будет проведена " "ÑинхронизациÑ\n" -#: pg_rewind.c:64 +#: pg_rewind.c:65 #, c-format msgid " --source-server=CONNSTR source server to synchronize with\n" msgstr "" " --source-server=СТР_ПОДКЛ Ñервер, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼ будет проведена " "ÑинхронизациÑ\n" -#: pg_rewind.c:65 +#: pg_rewind.c:66 #, c-format msgid " -n, --dry-run stop before modifying anything\n" msgstr "" " -n, --dry-run оÑтановитьÑÑ Ð´Ð¾ внеÑÐµÐ½Ð¸Ñ ÐºÐ°ÐºÐ¸Ñ…-либо " "изменений\n" -#: pg_rewind.c:66 +#: pg_rewind.c:67 #, c-format msgid " -P, --progress write progress messages\n" msgstr " -P, --progress выводить ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾ ходе процеÑÑа\n" -#: pg_rewind.c:67 +#: pg_rewind.c:68 #, c-format msgid " --debug write a lot of debug messages\n" msgstr "" " --debug выдавать множеÑтво отладочных Ñообщений\n" -#: pg_rewind.c:68 +#: pg_rewind.c:69 #, c-format msgid "" " -V, --version output version information, then exit\n" msgstr " -V, --version показать верÑию и выйти\n" -#: pg_rewind.c:69 +#: pg_rewind.c:70 #, c-format msgid " -?, --help show this help, then exit\n" msgstr " -?, --help показать Ñту Ñправку и выйти\n" -#: pg_rewind.c:70 +#: pg_rewind.c:71 #, c-format msgid "" "\n" @@ -512,81 +511,81 @@ msgstr "" "\n" "Об ошибках Ñообщайте по адреÑу .\n" -#: pg_rewind.c:125 pg_rewind.c:156 pg_rewind.c:163 pg_rewind.c:171 +#: pg_rewind.c:126 pg_rewind.c:157 pg_rewind.c:164 pg_rewind.c:172 #, c-format msgid "Try \"%s --help\" for more information.\n" msgstr "Ð”Ð»Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾Ð¹ информации попробуйте \"%s --help\".\n" -#: pg_rewind.c:155 +#: pg_rewind.c:156 #, c-format msgid "%s: no source specified (--source-pgdata or --source-server)\n" msgstr "" "%s: иÑточник не указан (требуетÑÑ --source-pgdata или --source-server)\n" -#: pg_rewind.c:162 +#: pg_rewind.c:163 #, c-format msgid "%s: no target data directory specified (--target-pgdata)\n" msgstr "%s: целевой каталог данных не указан (--target-pgdata)\n" -#: pg_rewind.c:169 +#: pg_rewind.c:170 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" msgstr "%s: Ñлишком много аргументов командной Ñтроки (первый: \"%s\")\n" -#: pg_rewind.c:184 +#: pg_rewind.c:185 #, c-format msgid "cannot be executed by \"root\"\n" msgstr "программу не должен запуÑкать root\n" -#: pg_rewind.c:185 +#: pg_rewind.c:186 #, c-format msgid "You must run %s as the PostgreSQL superuser.\n" msgstr "ЗапуÑкать %s нужно от имени ÑÑƒÐ¿ÐµÑ€Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ PostgreSQL.\n" -#: pg_rewind.c:215 +#: pg_rewind.c:217 #, c-format msgid "source and target cluster are on the same timeline\n" msgstr "иÑходный и целевой клаÑтер уже на одной линии времени\n" -#: pg_rewind.c:218 +#: pg_rewind.c:223 #, c-format msgid "servers diverged at WAL position %X/%X on timeline %u\n" msgstr "Серверы разошлиÑÑŒ в позиции WAL %X/%X на линии времени %u.\n" -#: pg_rewind.c:253 +#: pg_rewind.c:259 #, c-format msgid "no rewind required\n" msgstr "перемотка не требуетÑÑ.\n" -#: pg_rewind.c:259 +#: pg_rewind.c:265 #, c-format msgid "rewinding from last common checkpoint at %X/%X on timeline %u\n" msgstr "" "перемотка от поÑледней общей контрольной точки в позиции %X/%X на линии " "времени %u\n" -#: pg_rewind.c:267 +#: pg_rewind.c:273 #, c-format msgid "reading source file list\n" msgstr "чтение ÑпиÑка иÑходных файлов\n" -#: pg_rewind.c:269 +#: pg_rewind.c:275 #, c-format msgid "reading target file list\n" msgstr "чтение ÑпиÑка целевых файлов\n" -#: pg_rewind.c:279 +#: pg_rewind.c:285 #, c-format msgid "reading WAL in target\n" msgstr "чтение WAL в целевом клаÑтере\n" -#: pg_rewind.c:296 +#: pg_rewind.c:302 #, c-format msgid "need to copy %lu MB (total source directory size is %lu MB)\n" msgstr "" "требуетÑÑ Ñкопировать %lu МБ (общий размер иÑходного каталога: %lu МБ)\n" -#: pg_rewind.c:313 +#: pg_rewind.c:319 #, c-format msgid "" "\n" @@ -595,22 +594,27 @@ msgstr "" "\n" "Ñоздание метки копии и Ð¼Ð¾Ð´Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑƒÐ¿Ñ€Ð°Ð²Ð»Ñющего файла\n" -#: pg_rewind.c:341 +#: pg_rewind.c:347 +#, c-format +msgid "syncing target data directory\n" +msgstr "ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ†ÐµÐ»ÐµÐ²Ð¾Ð³Ð¾ каталога данных\n" + +#: pg_rewind.c:350 #, c-format msgid "Done!\n" msgstr "Готово!\n" -#: pg_rewind.c:353 +#: pg_rewind.c:362 #, c-format msgid "source and target clusters are from different systems\n" msgstr "иÑходный и целевой клаÑтеры отноÑÑÑ‚ÑÑ Ðº разным ÑиÑтемам\n" -#: pg_rewind.c:361 +#: pg_rewind.c:370 #, c-format msgid "clusters are not compatible with this version of pg_rewind\n" msgstr "клаÑтеры неÑовмеÑтимы Ñ Ñтой верÑией pg_rewind\n" -#: pg_rewind.c:371 +#: pg_rewind.c:380 #, c-format msgid "" "target server needs to use either data checksums or \"wal_log_hints = on\"\n" @@ -618,38 +622,65 @@ msgstr "" "на целевом Ñервере должны быть контрольные Ñуммы данных или \"wal_log_hints " "= on\"\n" -#: pg_rewind.c:381 +#: pg_rewind.c:391 #, c-format msgid "target server must be shut down cleanly\n" msgstr "целевой Ñервер должен быть выключен штатно\n" -#: pg_rewind.c:389 +#: pg_rewind.c:401 #, c-format msgid "source data directory must be shut down cleanly\n" msgstr "работа Ñ Ð¸Ñходным каталогом данных должна быть завершена штатно\n" -#: pg_rewind.c:456 +#: pg_rewind.c:468 #, c-format msgid "" "could not find common ancestor of the source and target cluster's timelines\n" msgstr "" -"не удалоÑÑŒ найти общего предка линий времени иÑходного и целевых клаÑтеров\n" +"не удалоÑÑŒ найти общего предка линий времени иÑходного и целевого клаÑтеров\n" -#: pg_rewind.c:496 +#: pg_rewind.c:508 #, c-format msgid "backup label buffer too small\n" msgstr "буфер Ð´Ð»Ñ Ð¼ÐµÑ‚ÐºÐ¸ копии Ñлишком мал\n" -#: pg_rewind.c:518 +#: pg_rewind.c:531 #, c-format msgid "unexpected control file CRC\n" msgstr "Ð½ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÐºÐ¾Ð½Ñ‚Ñ€Ð¾Ð»ÑŒÐ½Ð°Ñ Ñумма управлÑющего файла\n" -#: pg_rewind.c:528 +#: pg_rewind.c:541 #, c-format msgid "unexpected control file size %d, expected %d\n" msgstr "неверный размер управлÑющего файла (%d), ожидалоÑÑŒ: %d\n" +#: pg_rewind.c:608 +#, c-format +msgid "" +"The program \"initdb\" is needed by %s but was \n" +"not found in the same directory as \"%s\".\n" +"Check your installation.\n" +msgstr "" +"Ð”Ð»Ñ %s необходима программа \"initdb\", но она не найдена\n" +"в каталоге \"%s\".\n" +"Проверьте вашу уÑтановку PostgreSQL.\n" + +#: pg_rewind.c:612 +#, c-format +msgid "" +"The program \"initdb\" was found by \"%s\"\n" +"but was not the same version as %s.\n" +"Check your installation.\n" +msgstr "" +"Программа \"initdb\" найдена в \"%s\",\n" +"но её верÑÐ¸Ñ Ð¾Ñ‚Ð»Ð¸Ñ‡Ð°ÐµÑ‚ÑÑ Ð¾Ñ‚ верÑии %s.\n" +"Проверьте вашу уÑтановку PostgreSQL.\n" + +#: pg_rewind.c:630 +#, c-format +msgid "sync of target directory failed\n" +msgstr "Ñбой Ñинхронизации целевого каталога\n" + #: timeline.c:76 timeline.c:82 #, c-format msgid "syntax error in history file: %s\n" diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c index b079b6de85..11502a9f0e 100644 --- a/src/bin/pg_upgrade/check.c +++ b/src/bin/pg_upgrade/check.c @@ -404,12 +404,17 @@ void create_script_for_cluster_analyze(char **analyze_script_file_name) { FILE *script = NULL; - char *user_specification = ""; + PQExpBufferData user_specification; prep_status("Creating script to analyze new cluster"); + initPQExpBuffer(&user_specification); if (os_info.user_specified) - user_specification = psprintf("-U \"%s\" ", os_info.user); + { + appendPQExpBufferStr(&user_specification, "-U "); + appendShellString(&user_specification, os_info.user); + appendPQExpBufferChar(&user_specification, ' '); + } *analyze_script_file_name = psprintf("%sanalyze_new_cluster.%s", SCRIPT_PREFIX, SCRIPT_EXT); @@ -449,18 +454,18 @@ create_script_for_cluster_analyze(char **analyze_script_file_name) fprintf(script, "echo %sthis script and run:%s\n", ECHO_QUOTE, ECHO_QUOTE); fprintf(script, "echo %s \"%s/vacuumdb\" %s--all %s%s\n", ECHO_QUOTE, - new_cluster.bindir, user_specification, + new_cluster.bindir, user_specification.data, /* Did we copy the free space files? */ (GET_MAJOR_VERSION(old_cluster.major_version) >= 804) ? "--analyze-only" : "--analyze", ECHO_QUOTE); fprintf(script, "echo%s\n\n", ECHO_BLANK); fprintf(script, "\"%s/vacuumdb\" %s--all --analyze-in-stages\n", - new_cluster.bindir, user_specification); + new_cluster.bindir, user_specification.data); /* Did we copy the free space files? */ if (GET_MAJOR_VERSION(old_cluster.major_version) < 804) fprintf(script, "\"%s/vacuumdb\" %s--all\n", new_cluster.bindir, - user_specification); + user_specification.data); fprintf(script, "echo%s\n\n", ECHO_BLANK); fprintf(script, "echo %sDone%s\n", @@ -474,8 +479,7 @@ create_script_for_cluster_analyze(char **analyze_script_file_name) *analyze_script_file_name, getErrorText()); #endif - if (os_info.user_specified) - pg_free(user_specification); + termPQExpBuffer(&user_specification); check_ok(); } diff --git a/src/bin/pg_upgrade/dump.c b/src/bin/pg_upgrade/dump.c index 19e52e2141..dd97891a08 100644 --- a/src/bin/pg_upgrade/dump.c +++ b/src/bin/pg_upgrade/dump.c @@ -46,6 +46,15 @@ generate_old_dump(void) char sql_file_name[MAXPGPATH], log_file_name[MAXPGPATH]; DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum]; + PQExpBufferData connstr, + escaped_connstr; + + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, old_db->db_name); + initPQExpBuffer(&escaped_connstr); + appendShellString(&escaped_connstr, connstr.data); + termPQExpBuffer(&connstr); pg_log(PG_STATUS, "%s", old_db->db_name); snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid); @@ -53,10 +62,12 @@ generate_old_dump(void) parallel_exec_prog(log_file_name, NULL, "\"%s/pg_dump\" %s --schema-only --quote-all-identifiers " - "--binary-upgrade --format=custom %s --file=\"%s\" \"%s\"", + "--binary-upgrade --format=custom %s --file=\"%s\" %s", new_cluster.bindir, cluster_conn_opts(&old_cluster), log_opts.verbose ? "--verbose" : "", - sql_file_name, old_db->db_name); + sql_file_name, escaped_connstr.data); + + termPQExpBuffer(&escaped_connstr); } /* reap all children */ diff --git a/src/bin/pg_upgrade/pg_upgrade.c b/src/bin/pg_upgrade/pg_upgrade.c index 566db9d40c..59ccc67adc 100644 --- a/src/bin/pg_upgrade/pg_upgrade.c +++ b/src/bin/pg_upgrade/pg_upgrade.c @@ -307,6 +307,15 @@ create_new_objects(void) char sql_file_name[MAXPGPATH], log_file_name[MAXPGPATH]; DbInfo *old_db = &old_cluster.dbarr.dbs[dbnum]; + PQExpBufferData connstr, + escaped_connstr; + + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, old_db->db_name); + initPQExpBuffer(&escaped_connstr); + appendShellString(&escaped_connstr, connstr.data); + termPQExpBuffer(&connstr); pg_log(PG_STATUS, "%s", old_db->db_name); snprintf(sql_file_name, sizeof(sql_file_name), DB_DUMP_FILE_MASK, old_db->db_oid); @@ -318,11 +327,13 @@ create_new_objects(void) */ parallel_exec_prog(log_file_name, NULL, - "\"%s/pg_restore\" %s --exit-on-error --verbose --dbname \"%s\" \"%s\"", + "\"%s/pg_restore\" %s --exit-on-error --verbose --dbname %s \"%s\"", new_cluster.bindir, cluster_conn_opts(&new_cluster), - old_db->db_name, + escaped_connstr.data, sql_file_name); + + termPQExpBuffer(&escaped_connstr); } /* reap all children */ diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h index 50660050fb..627ef7aabb 100644 --- a/src/bin/pg_upgrade/pg_upgrade.h +++ b/src/bin/pg_upgrade/pg_upgrade.h @@ -11,6 +11,7 @@ #include #include "libpq-fe.h" +#include "pqexpbuffer.h" /* Use port in the private/dynamic port number range */ #define DEF_PGUPORT 50432 @@ -451,6 +452,9 @@ void check_pghost_envvar(void); /* util.c */ char *quote_identifier(const char *s); +extern void appendShellString(PQExpBuffer buf, const char *str); +extern void appendConnStrVal(PQExpBuffer buf, const char *str); +extern void appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname); int get_user_info(char **user_name_p); void check_ok(void); void report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3); diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c index 8c6b6da515..1437389412 100644 --- a/src/bin/pg_upgrade/server.c +++ b/src/bin/pg_upgrade/server.c @@ -51,18 +51,25 @@ connectToServer(ClusterInfo *cluster, const char *db_name) static PGconn * get_db_conn(ClusterInfo *cluster, const char *db_name) { - char conn_opts[2 * NAMEDATALEN + MAXPGPATH + 100]; + PQExpBufferData conn_opts; + PGconn *conn; + /* Build connection string with proper quoting */ + initPQExpBuffer(&conn_opts); + appendPQExpBufferStr(&conn_opts, "dbname="); + appendConnStrVal(&conn_opts, db_name); + appendPQExpBufferStr(&conn_opts, " user="); + appendConnStrVal(&conn_opts, os_info.user); + appendPQExpBuffer(&conn_opts, " port=%d", cluster->port); if (cluster->sockdir) - snprintf(conn_opts, sizeof(conn_opts), - "dbname = '%s' user = '%s' host = '%s' port = %d", - db_name, os_info.user, cluster->sockdir, cluster->port); - else - snprintf(conn_opts, sizeof(conn_opts), - "dbname = '%s' user = '%s' port = %d", - db_name, os_info.user, cluster->port); + { + appendPQExpBufferStr(&conn_opts, " host="); + appendConnStrVal(&conn_opts, cluster->sockdir); + } - return PQconnectdb(conn_opts); + conn = PQconnectdb(conn_opts.data); + termPQExpBuffer(&conn_opts); + return conn; } @@ -74,23 +81,28 @@ get_db_conn(ClusterInfo *cluster, const char *db_name) * sets, but the utilities we need aren't very consistent about the treatment * of database name options, so we leave that out. * - * Note result is in static storage, so use it right away. + * Result is valid until the next call to this function. */ char * cluster_conn_opts(ClusterInfo *cluster) { - static char conn_opts[MAXPGPATH + NAMEDATALEN + 100]; + static PQExpBuffer buf; - if (cluster->sockdir) - snprintf(conn_opts, sizeof(conn_opts), - "--host \"%s\" --port %d --username \"%s\"", - cluster->sockdir, cluster->port, os_info.user); + if (buf == NULL) + buf = createPQExpBuffer(); else - snprintf(conn_opts, sizeof(conn_opts), - "--port %d --username \"%s\"", - cluster->port, os_info.user); + resetPQExpBuffer(buf); - return conn_opts; + if (cluster->sockdir) + { + appendPQExpBufferStr(buf, "--host "); + appendShellString(buf, cluster->sockdir); + appendPQExpBufferChar(buf, ' '); + } + appendPQExpBuffer(buf, "--port %d --username ", cluster->port); + appendShellString(buf, os_info.user); + + return buf->data; } @@ -174,10 +186,11 @@ start_postmaster(ClusterInfo *cluster, bool throw_error) { char cmd[MAXPGPATH * 4 + 1000]; PGconn *conn; - bool exit_hook_registered = false; bool pg_ctl_return = false; char socket_string[MAXPGPATH + 200]; + static bool exit_hook_registered = false; + if (!exit_hook_registered) { atexit(stop_postmaster_atexit); diff --git a/src/bin/pg_upgrade/test.sh b/src/bin/pg_upgrade/test.sh index aa7f3994ca..bb41419924 100644 --- a/src/bin/pg_upgrade/test.sh +++ b/src/bin/pg_upgrade/test.sh @@ -153,6 +153,20 @@ set -x standard_initdb "$oldbindir"/initdb "$oldbindir"/pg_ctl start -l "$logdir/postmaster1.log" -o "$POSTMASTER_OPTS" -w + +# Create databases with names covering the ASCII bytes other than NUL, BEL, +# LF, or CR. BEL would ring the terminal bell in the course of this test, and +# it is not otherwise a special case. PostgreSQL doesn't support the rest. +dbname1=`awk 'BEGIN { for (i= 1; i < 46; i++) + if (i != 7 && i != 10 && i != 13) printf "%c", i }' = 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z') || + (*p >= '0' && *p <= '9'))) + appendPQExpBufferChar(buf, '^'); + appendPQExpBufferChar(buf, *p); + } + + /* + * Change N backslashes at end of argument to 2N backslashes, because they + * precede the double quote that terminates the argument. + */ + while (backslash_run_length) + { + appendPQExpBufferStr(buf, "^\\"); + backslash_run_length--; + } + appendPQExpBufferStr(buf, "^\""); +#endif /* WIN32 */ +} + + +/* + * Append the given string to the buffer, with suitable quoting for passing + * the string as a value, in a keyword/pair value in a libpq connection + * string + */ +void +appendConnStrVal(PQExpBuffer buf, const char *str) +{ + const char *s; + bool needquotes; + + /* + * If the string is one or more plain ASCII characters, no need to quote + * it. This is quite conservative, but better safe than sorry. + */ + needquotes = true; + for (s = str; *s; s++) + { + if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || *s == '_' || *s == '.')) + { + needquotes = true; + break; + } + needquotes = false; + } + + if (needquotes) + { + appendPQExpBufferChar(buf, '\''); + while (*str) + { + /* ' and \ must be escaped by to \' and \\ */ + if (*str == '\'' || *str == '\\') + appendPQExpBufferChar(buf, '\\'); + + appendPQExpBufferChar(buf, *str); + str++; + } + appendPQExpBufferChar(buf, '\''); + } + else + appendPQExpBufferStr(buf, str); +} + + +/* + * Append a psql meta-command that connects to the given database with the + * then-current connection's user, host and port. + */ +void +appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname) +{ + const char *s; + bool complex; + + /* + * If the name is plain ASCII characters, emit a trivial "\connect "foo"". + * For other names, even many not technically requiring it, skip to the + * general case. No database has a zero-length name. + */ + complex = false; + for (s = dbname; *s; s++) + { + if (*s == '\n' || *s == '\r') + { + fprintf(stderr, + _("database name contains a newline or carriage return: \"%s\"\n"), + dbname); + exit(EXIT_FAILURE); + } + + if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9') || *s == '_' || *s == '.')) + { + complex = true; + } + } + + appendPQExpBufferStr(buf, "\\connect "); + if (complex) + { + PQExpBufferData connstr; + + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, dbname); + + appendPQExpBuffer(buf, "-reuse-previous=on "); + + /* + * As long as the name does not contain a newline, SQL identifier + * quoting satisfies the psql meta-command parser. Prefer not to + * involve psql-interpreted single quotes, which behaved differently + * before PostgreSQL 9.2. + */ + appendPQExpBufferStr(buf, quote_identifier(connstr.data)); + + termPQExpBuffer(&connstr); + } + else + appendPQExpBufferStr(buf, quote_identifier(dbname)); + appendPQExpBufferChar(buf, '\n'); +} + + /* * get_user_info() */ diff --git a/src/bin/pg_upgrade/version.c b/src/bin/pg_upgrade/version.c index b93c414d7a..c215974ea9 100644 --- a/src/bin/pg_upgrade/version.c +++ b/src/bin/pg_upgrade/version.c @@ -48,10 +48,16 @@ new_9_0_populate_pg_largeobject_metadata(ClusterInfo *cluster, bool check_mode) found = true; if (!check_mode) { + PQExpBufferData connectbuf; + if (script == NULL && (script = fopen_priv(output_path, "w")) == NULL) pg_fatal("could not open file \"%s\": %s\n", output_path, getErrorText()); - fprintf(script, "\\connect %s\n", - quote_identifier(active_db->db_name)); + + initPQExpBuffer(&connectbuf); + appendPsqlMetaConnect(&connectbuf, active_db->db_name); + fputs(connectbuf.data, script); + termPQExpBuffer(&connectbuf); + fprintf(script, "SELECT pg_catalog.lo_create(t.loid)\n" "FROM (SELECT DISTINCT loid FROM pg_catalog.pg_largeobject) AS t;\n"); diff --git a/src/bin/pg_xlogdump/pg_xlogdump.c b/src/bin/pg_xlogdump/pg_xlogdump.c index c0a6816784..49e9a34b52 100644 --- a/src/bin/pg_xlogdump/pg_xlogdump.c +++ b/src/bin/pg_xlogdump/pg_xlogdump.c @@ -249,6 +249,7 @@ XLogDumpXLogRead(const char *directory, TimeLineID timeline_id, if (sendFile < 0 || !XLByteInSeg(recptr, sendSegNo)) { char fname[MAXFNAMELEN]; + int tries; /* Switch to another logfile segment */ if (sendFile >= 0) @@ -258,7 +259,30 @@ XLogDumpXLogRead(const char *directory, TimeLineID timeline_id, XLogFileName(fname, timeline_id, sendSegNo); - sendFile = fuzzy_open_file(directory, fname); + /* + * In follow mode there is a short period of time after the + * server has written the end of the previous file before the + * new file is available. So we loop for 5 seconds looking + * for the file to appear before giving up. + */ + for (tries = 0; tries < 10; tries++) + { + sendFile = fuzzy_open_file(directory, fname); + if (sendFile >= 0) + break; + if (errno == ENOENT) + { + int save_errno = errno; + + /* File not there yet, try again */ + pg_usleep(500 * 1000); + + errno = save_errno; + continue; + } + /* Any other error, fall through and fail */ + break; + } if (sendFile < 0) fatal_error("could not find file \"%s\": %s", @@ -855,7 +879,7 @@ main(int argc, char **argv) if (!verify_directory(private.inpath)) { fprintf(stderr, - "%s: path \"%s\" cannot be opened: %s", + "%s: path \"%s\" cannot be opened: %s\n", progname, private.inpath, strerror(errno)); goto bad_argument; } diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 182a9ee161..60a5af8a9b 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -219,6 +219,7 @@ typedef struct Variable *variables; /* array of variable definitions */ int nvariables; int64 txn_scheduled; /* scheduled start time of transaction (usec) */ + int64 sleep_until; /* scheduled start time of next cmd (usec) */ instr_time txn_begin; /* used for measuring schedule lag times */ instr_time stmt_begin; /* used for measuring statement latencies */ int64 txn_latencies; /* cumulated latencies */ @@ -1238,6 +1239,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa } } + st->sleep_until = st->txn_scheduled; st->sleeping = 1; st->throttling = true; st->is_throttled = true; @@ -1253,7 +1255,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa if (INSTR_TIME_IS_ZERO(now)) INSTR_TIME_SET_CURRENT(now); now_us = INSTR_TIME_GET_MICROSEC(now); - if (st->txn_scheduled <= now_us) + if (st->sleep_until <= now_us) { st->sleeping = 0; /* Done sleeping, go ahead with next command */ if (st->throttling) @@ -1721,7 +1723,7 @@ doCustom(TState *thread, CState *st, instr_time *conn_time, FILE *logfile, AggVa usec *= 1000000; INSTR_TIME_SET_CURRENT(now); - st->txn_scheduled = INSTR_TIME_GET_MICROSEC(now) + usec; + st->sleep_until = INSTR_TIME_GET_MICROSEC(now) + usec; st->sleeping = 1; st->listen = 1; @@ -2734,9 +2736,9 @@ printResults(int ttype, int64 normal_xacts, int nclients, } else { - /* only an average latency computed from the duration is available */ + /* no measurement, show average latency computed from run time */ printf("latency average: %.3f ms\n", - 1000.0 * duration * nclients / normal_xacts); + 1000.0 * time_include * nclients / normal_xacts); } if (throttle_delay) diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c index 07d3e6998e..77746a120e 100644 --- a/src/bin/psql/command.c +++ b/src/bin/psql/command.c @@ -56,7 +56,8 @@ static backslashResult exec_command(const char *cmd, PQExpBuffer query_buf); static bool do_edit(const char *filename_arg, PQExpBuffer query_buf, int lineno, bool *edited); -static bool do_connect(char *dbname, char *user, char *host, char *port); +static bool do_connect(enum trivalue reuse_previous_specification, + char *dbname, char *user, char *host, char *port); static bool do_shell(const char *command); static bool do_watch(PQExpBuffer query_buf, long sleep); static bool lookup_function_oid(const char *desc, Oid *foid); @@ -217,12 +218,9 @@ exec_command(const char *cmd, /* * \c or \connect -- connect to database using the specified parameters. * - * \c dbname user host port + * \c [-reuse-previous=BOOL] dbname user host port * - * If any of these parameters are omitted or specified as '-', the current - * value of the parameter will be used instead. If the parameter has no - * current value, the default value for that parameter will be used. Some - * examples: + * Specifying a parameter as '-' is equivalent to omitting it. Examples: * * \c - - hst Connect to current database on current port of host * "hst" as current user. \c - usr - prt Connect to current database on @@ -231,17 +229,31 @@ exec_command(const char *cmd, */ else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0) { + static const char prefix[] = "-reuse-previous="; char *opt1, *opt2, *opt3, *opt4; + enum trivalue reuse_previous; opt1 = read_connect_arg(scan_state); + if (opt1 != NULL && strncmp(opt1, prefix, sizeof(prefix) - 1) == 0) + { + reuse_previous = + ParseVariableBool(opt1 + sizeof(prefix) - 1, prefix) ? + TRI_YES : TRI_NO; + + free(opt1); + opt1 = read_connect_arg(scan_state); + } + else + reuse_previous = TRI_DEFAULT; + opt2 = read_connect_arg(scan_state); opt3 = read_connect_arg(scan_state); opt4 = read_connect_arg(scan_state); - success = do_connect(opt1, opt2, opt3, opt4); + success = do_connect(reuse_previous, opt1, opt2, opt3, opt4); free(opt1); free(opt2); @@ -596,8 +608,11 @@ exec_command(const char *cmd, if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support editing function source.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support editing function source.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!query_buf) @@ -1226,8 +1241,11 @@ exec_command(const char *cmd, OT_WHOLE_LINE, NULL, true); if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support showing function source.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support showing function source.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); status = PSQL_CMD_ERROR; } else if (!func) @@ -1599,22 +1617,26 @@ param_is_newly_set(const char *old_val, const char *new_val) /* * do_connect -- handler for \connect * - * Connects to a database with given parameters. If there exists an - * established connection, NULL values will be replaced with the ones - * in the current connection. Otherwise NULL will be passed for that - * parameter to PQconnectdbParams(), so the libpq defaults will be used. + * Connects to a database with given parameters. Absent an established + * connection, all parameters are required. Given -reuse-previous=off or a + * connection string without -reuse-previous=on, NULL values will pass through + * to PQconnectdbParams(), so the libpq defaults will be used. Otherwise, NULL + * values will be replaced with the ones in the current connection. * * In interactive mode, if connection fails with the given parameters, * the old connection will be kept. */ static bool -do_connect(char *dbname, char *user, char *host, char *port) +do_connect(enum trivalue reuse_previous_specification, + char *dbname, char *user, char *host, char *port) { PGconn *o_conn = pset.db, *n_conn; char *password = NULL; bool keep_password; bool has_connection_string; + bool reuse_previous; + PQExpBufferData connstr; if (!o_conn && (!dbname || !user || !host || !port)) { @@ -1628,17 +1650,36 @@ do_connect(char *dbname, char *user, char *host, char *port) return false; } - /* grab values from the old connection, unless supplied by caller */ - if (!user) + has_connection_string = dbname ? + recognized_connection_string(dbname) : false; + switch (reuse_previous_specification) + { + case TRI_YES: + reuse_previous = true; + break; + case TRI_NO: + reuse_previous = false; + break; + default: + reuse_previous = !has_connection_string; + break; + } + /* Silently ignore arguments subsequent to a connection string. */ + if (has_connection_string) + { + user = NULL; + host = NULL; + port = NULL; + } + + /* grab missing values from the old connection */ + if (!user && reuse_previous) user = PQuser(o_conn); - if (!host) + if (!host && reuse_previous) host = PQhost(o_conn); - if (!port) + if (!port && reuse_previous) port = PQport(o_conn); - has_connection_string = - dbname ? recognized_connection_string(dbname) : false; - /* * Any change in the parameters read above makes us discard the password. * We also discard it if we're to use a conninfo rather than the @@ -1655,11 +1696,19 @@ do_connect(char *dbname, char *user, char *host, char *port) (port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0); /* - * Grab dbname from old connection unless supplied by caller. No password - * discard if this changes: passwords aren't (usually) database-specific. + * Grab missing dbname from old connection. No password discard if this + * changes: passwords aren't (usually) database-specific. */ - if (!dbname) - dbname = PQdb(o_conn); + if (!dbname && reuse_previous) + { + initPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, PQdb(o_conn)); + dbname = connstr.data; + /* has_connection_string=true would be a dead store */ + } + else + connstr.data = NULL; /* * If the user asked to be prompted for a password, ask for one now. If @@ -1689,26 +1738,39 @@ do_connect(char *dbname, char *user, char *host, char *port) #define PARAMS_ARRAY_SIZE 8 const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords)); const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values)); - int paramnum = 0; + int paramnum = -1; - keywords[0] = "dbname"; - values[0] = dbname; + keywords[++paramnum] = "host"; + values[paramnum] = host; + keywords[++paramnum] = "port"; + values[paramnum] = port; + keywords[++paramnum] = "user"; + values[paramnum] = user; - if (!has_connection_string) - { - keywords[++paramnum] = "host"; - values[paramnum] = host; - keywords[++paramnum] = "port"; - values[paramnum] = port; - keywords[++paramnum] = "user"; - values[paramnum] = user; - } + /* + * Position in the array matters when the dbname is a connection + * string, because settings in a connection string override earlier + * array entries only. Thus, user= in the connection string always + * takes effect, but client_encoding= often will not. + * + * If you change this code, also change the initial-connection code in + * main(). For no good reason, a connection string password= takes + * precedence in main() but not here. + */ + keywords[++paramnum] = "dbname"; + values[paramnum] = dbname; keywords[++paramnum] = "password"; values[paramnum] = password; keywords[++paramnum] = "fallback_application_name"; values[paramnum] = pset.progname; keywords[++paramnum] = "client_encoding"; - values[paramnum] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto"; + values[paramnum] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : +#ifdef HAVE_WIN32_LIBEDIT + "UTF8" +#else + "auto" +#endif + ; /* add array terminator */ keywords[++paramnum] = NULL; @@ -1761,8 +1823,12 @@ do_connect(char *dbname, char *user, char *host, char *port) } PQfinish(n_conn); + if (connstr.data) + termPQExpBuffer(&connstr); return false; } + if (connstr.data) + termPQExpBuffer(&connstr); /* * Replace the old connection with the new one, and update @@ -1809,22 +1875,21 @@ connection_warnings(bool in_startup) if (!pset.quiet && !pset.notty) { int client_ver = PG_VERSION_NUM; + char cverbuf[32]; + char sverbuf[32]; if (pset.sversion != client_ver) { const char *server_version; - char server_ver_str[16]; /* Try to get full text form, might include "devel" etc */ server_version = PQparameterStatus(pset.db, "server_version"); + /* Otherwise fall back on pset.sversion */ if (!server_version) { - snprintf(server_ver_str, sizeof(server_ver_str), - "%d.%d.%d", - pset.sversion / 10000, - (pset.sversion / 100) % 100, - pset.sversion % 100); - server_version = server_ver_str; + formatPGVersionNumber(pset.sversion, true, + sverbuf, sizeof(sverbuf)); + server_version = sverbuf; } printf(_("%s (%s, server %s)\n"), @@ -1835,10 +1900,13 @@ connection_warnings(bool in_startup) printf("%s (%s)\n", pset.progname, PG_VERSION); if (pset.sversion / 100 > client_ver / 100) - printf(_("WARNING: %s major version %d.%d, server major version %d.%d.\n" + printf(_("WARNING: %s major version %s, server major version %s.\n" " Some psql features might not work.\n"), - pset.progname, client_ver / 10000, (client_ver / 100) % 100, - pset.sversion / 10000, (pset.sversion / 100) % 100); + pset.progname, + formatPGVersionNumber(client_ver, false, + cverbuf, sizeof(cverbuf)), + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); #ifdef WIN32 checkWin32Codepage(); @@ -1886,6 +1954,11 @@ printSSLInfo(void) static void checkWin32Codepage(void) { +#ifdef HAVE_WIN32_LIBEDIT + if (isatty(fileno(stdout))) + printf(_("WARNING: Unicode mode enabled. " + "You need TTF font in your console window\n")); +#else unsigned int wincp, concp; @@ -1898,6 +1971,7 @@ checkWin32Codepage(void) " page \"Notes for Windows users\" for details.\n"), concp, wincp); } +#endif } #endif diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c index 39c88fce7d..b5c06f1d48 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c @@ -23,6 +23,7 @@ #include "settings.h" #include "command.h" #include "copy.h" +#include "dumputils.h" #include "mbprint.h" @@ -1037,8 +1038,11 @@ SendQuery(const char *query) { if (on_error_rollback_warning == false && pset.sversion < 80000) { - psql_error("The server (version %d.%d) does not support savepoints for ON_ERROR_ROLLBACK.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support savepoints for ON_ERROR_ROLLBACK.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); on_error_rollback_warning = true; } else diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index c42ad0418b..de72b9a5ae 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -141,8 +141,11 @@ describeTablespaces(const char *pattern, bool verbose) if (pset.sversion < 80000) { - psql_error("The server (version %d.%d) does not support tablespaces.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support tablespaces.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -244,8 +247,11 @@ describeFunctions(const char *functypes, const char *pattern, bool verbose, bool if (showWindow && pset.sversion < 80400) { - psql_error("\\df does not take a \"w\" option with server version %d.%d\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("\\df does not take a \"w\" option with server version %s\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -870,8 +876,11 @@ listDefaultACLs(const char *pattern) if (pset.sversion < 90000) { - psql_error("The server (version %d.%d) does not support altering default privileges.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support altering default privileges.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3453,8 +3462,11 @@ listCollations(const char *pattern, bool verbose, bool showSystem) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support collations.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support collations.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3585,8 +3597,11 @@ listTSParsers(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3820,8 +3835,11 @@ listTSDictionaries(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3888,8 +3906,11 @@ listTSTemplates(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -3956,8 +3977,11 @@ listTSConfigs(const char *pattern, bool verbose) if (pset.sversion < 80300) { - psql_error("The server (version %d.%d) does not support full text search.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support full text search.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4154,8 +4178,11 @@ listForeignDataWrappers(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support foreign-data wrappers.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign-data wrappers.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4234,8 +4261,11 @@ listForeignServers(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support foreign servers.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign servers.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4313,8 +4343,11 @@ listUserMappings(const char *pattern, bool verbose) if (pset.sversion < 80400) { - psql_error("The server (version %d.%d) does not support user mappings.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support user mappings.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4371,8 +4404,11 @@ listForeignTables(const char *pattern, bool verbose) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support foreign tables.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support foreign tables.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4446,8 +4482,11 @@ listExtensions(const char *pattern) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support extensions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support extensions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } @@ -4500,8 +4539,11 @@ listExtensionContents(const char *pattern) if (pset.sversion < 90100) { - psql_error("The server (version %d.%d) does not support extensions.\n", - pset.sversion / 10000, (pset.sversion / 100) % 100); + char sverbuf[32]; + + psql_error("The server (version %s) does not support extensions.\n", + formatPGVersionNumber(pset.sversion, false, + sverbuf, sizeof(sverbuf))); return true; } diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c index 355af43359..3f97a81081 100644 --- a/src/bin/psql/help.c +++ b/src/bin/psql/help.c @@ -65,7 +65,7 @@ usage(unsigned short int pager) } } - output = PageOutput(59, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(61, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("psql is the PostgreSQL interactive terminal.\n\n")); fprintf(output, _("Usage:\n")); @@ -159,7 +159,7 @@ slashUsage(unsigned short int pager) currdb = PQdb(pset.db); - output = PageOutput(103, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(107, pager ? &(pset.popt.topt) : NULL); /* if you add/remove a line here, change the row count above */ @@ -306,7 +306,7 @@ helpVariables(unsigned short int pager) { FILE *output; - output = PageOutput(85, pager ? &(pset.popt.topt) : NULL); + output = PageOutput(87, pager ? &(pset.popt.topt) : NULL); fprintf(output, _("List of specially treated variables\n\n")); diff --git a/src/bin/psql/input.c b/src/bin/psql/input.c index 2bc065adcf..17ee1db431 100644 --- a/src/bin/psql/input.c +++ b/src/bin/psql/input.c @@ -218,7 +218,7 @@ gets_fromFile(FILE *source) } /* EOL? */ - if (buffer->data[buffer->len - 1] == '\n') + if (buffer->len > 0 && buffer->data[buffer->len - 1] == '\n') { buffer->data[buffer->len - 1] = '\0'; return pg_strdup(buffer->data); @@ -276,6 +276,8 @@ gets_fromFile(FILE *source) for (VARNAME = current_history(); VARNAME != NULL; \ VARNAME = use_prev_ ? previous_history() : next_history()) \ { \ + if (VARNAME -> line == NULL) \ + continue; \ (void) 0 #define END_ITERATE_HISTORY() \ @@ -344,7 +346,9 @@ initializeInput(int flags) /* these two things must be done in this order: */ initialize_readline(); +#ifndef HAVE_WIN32_LIBEDIT rl_initialize(); +#endif useHistory = true; using_history(); @@ -364,7 +368,11 @@ initializeInput(int flags) if (histfile == NULL) { if (get_home_path(home)) +#ifdef HAVE_WIN32_LIBEDIT + psql_history = psprintf("%s\\%s", home, PSQLHISTORY); +#else psql_history = psprintf("%s/%s", home, PSQLHISTORY); +#endif } else { @@ -448,8 +456,10 @@ saveHistory(char *fname, int max_lines) #else /* don't have append support */ { /* truncate what we have ... */ +#ifndef HAVE_WIN32_LIBEDIT if (max_lines >= 0) stifle_history(max_lines); +#endif /* ... and overwrite file. Tough luck for concurrent sessions. */ errnum = write_history(fname); if (errnum == 0) diff --git a/src/bin/psql/po/de.po b/src/bin/psql/po/de.po index fb265abaa8..db19685ffd 100644 --- a/src/bin/psql/po/de.po +++ b/src/bin/psql/po/de.po @@ -1,7 +1,7 @@ # German message translation file for psql # Peter Eisentraut , 2001 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -25,27 +25,27 @@ msgstr "konnte aktuelles Verzeichnis nicht ermitteln: %s" #: ../../common/exec.c:146 #, c-format msgid "invalid binary \"%s\"" -msgstr "ungültige Programmdatei „%s“" +msgstr "ungültige Programmdatei »%s«" #: ../../common/exec.c:195 #, c-format msgid "could not read binary \"%s\"" -msgstr "konnte Programmdatei „%s“ nicht lesen" +msgstr "konnte Programmdatei »%s« nicht lesen" #: ../../common/exec.c:202 #, c-format msgid "could not find a \"%s\" to execute" -msgstr "konnte kein „%s“ zum Ausführen finden" +msgstr "konnte kein »%s« zum Ausführen finden" #: ../../common/exec.c:257 ../../common/exec.c:293 #, c-format msgid "could not change directory to \"%s\": %s" -msgstr "konnte nicht in Verzeichnis „%s“ wechseln: %s" +msgstr "konnte nicht in Verzeichnis »%s« wechseln: %s" #: ../../common/exec.c:272 #, c-format msgid "could not read symbolic link \"%s\"" -msgstr "konnte symbolische Verknüpfung „%s“ nicht lesen" +msgstr "konnte symbolische Verknüpfung »%s« nicht lesen" #: ../../common/exec.c:523 #, c-format @@ -126,7 +126,7 @@ msgstr "ungültige Anweisung \\%s\n" #: command.c:127 #, c-format msgid "\\%s: extra argument \"%s\" ignored\n" -msgstr "\\%s: überflüssiges Argument „%s“ ignoriert\n" +msgstr "\\%s: überflüssiges Argument »%s« ignoriert\n" #: command.c:271 #, c-format @@ -136,7 +136,7 @@ msgstr "konnte Home-Verzeichnis für Benutzer-ID %ld nicht ermitteln: %s\n" #: command.c:289 #, c-format msgid "\\%s: could not change directory to \"%s\": %s\n" -msgstr "\\%s: konnte nicht in das Verzeichnis „%s“ wechseln: %s\n" +msgstr "\\%s: konnte nicht in das Verzeichnis »%s« wechseln: %s\n" #: command.c:304 common.c:461 common.c:519 common.c:977 #, c-format @@ -146,12 +146,12 @@ msgstr "Sie sind gegenwärtig nicht mit einer Datenbank verbunden.\n" #: command.c:331 #, c-format msgid "You are connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n" -msgstr "Sie sind verbunden mit der Datenbank „%s“ als Benutzer „%s“ via Socket in „%s“ auf Port „%s“.\n" +msgstr "Sie sind verbunden mit der Datenbank »%s« als Benutzer »%s« via Socket in »%s« auf Port »%s«.\n" #: command.c:334 #, c-format msgid "You are connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n" -msgstr "Sie sind verbunden mit der Datenbank „%s“ als Benutzer „%s“ auf Host „%s“ auf Port „%s“.\n" +msgstr "Sie sind verbunden mit der Datenbank »%s« als Benutzer »%s« auf Host »%s« auf Port »%s«.\n" #: command.c:535 command.c:605 command.c:1405 #, c-format @@ -217,12 +217,12 @@ msgstr "Anfragepuffer wurde gelöscht." #: command.c:1122 #, c-format msgid "Wrote history to file \"%s\".\n" -msgstr "Befehlsgeschichte in Datei „%s“ geschrieben.\n" +msgstr "Befehlsgeschichte in Datei »%s« geschrieben.\n" #: command.c:1187 #, c-format msgid "\\%s: environment variable name must not contain \"=\"\n" -msgstr "\\%s: Name der Umgebungsvariable darf kein „=“ enthalten\n" +msgstr "\\%s: Name der Umgebungsvariable darf kein »=« enthalten\n" #: command.c:1229 #, c-format @@ -289,17 +289,17 @@ msgstr "\\connect: %s" #: command.c:1789 #, c-format msgid "You are now connected to database \"%s\" as user \"%s\" via socket in \"%s\" at port \"%s\".\n" -msgstr "Sie sind jetzt verbunden mit der Datenbank „%s“ als Benutzer „%s“ via Socket in „%s“ auf Port „%s“.\n" +msgstr "Sie sind jetzt verbunden mit der Datenbank »%s« als Benutzer »%s« via Socket in »%s« auf Port »%s«.\n" #: command.c:1792 #, c-format msgid "You are now connected to database \"%s\" as user \"%s\" on host \"%s\" at port \"%s\".\n" -msgstr "Sie sind jetzt verbunden mit der Datenbank „%s“ als Benutzer „%s“ auf Host „%s“ auf Port „%s“.\n" +msgstr "Sie sind jetzt verbunden mit der Datenbank »%s« als Benutzer »%s« auf Host »%s« auf Port »%s«.\n" #: command.c:1796 #, c-format msgid "You are now connected to database \"%s\" as user \"%s\".\n" -msgstr "Sie sind jetzt verbunden mit der Datenbank „%s“ als Benutzer „%s“.\n" +msgstr "Sie sind jetzt verbunden mit der Datenbank »%s« als Benutzer »%s«.\n" #: command.c:1830 #, c-format @@ -342,7 +342,7 @@ msgstr "" "Warnung: Konsolencodeseite (%u) unterscheidet sich von der Windows-\n" " Codeseite (%u). 8-Bit-Zeichen funktionieren möglicherweise nicht\n" " richtig. Einzelheiten finden Sie auf der psql-Handbuchseite unter\n" -" „Notes for Windows users“.\n" +" »Notes for Windows users«.\n" #: command.c:1980 #, c-format @@ -352,7 +352,7 @@ msgstr "Umgebungsvariable PSQL_EDITOR_LINENUMBER_ARG muss gesetzt werden, um ein #: command.c:2009 #, c-format msgid "could not start editor \"%s\"\n" -msgstr "konnte Editor „%s“ nicht starten\n" +msgstr "konnte Editor »%s« nicht starten\n" #: command.c:2011 #, c-format @@ -367,7 +367,7 @@ msgstr "konnte temporäres Verzeichnis nicht finden: %s\n" #: command.c:2076 #, c-format msgid "could not open temporary file \"%s\": %s\n" -msgstr "konnte temporäre Datei „%s“ nicht öffnen: %s\n" +msgstr "konnte temporäre Datei »%s« nicht öffnen: %s\n" #: command.c:2380 #, c-format @@ -437,7 +437,7 @@ msgstr "Feldtrennzeichen ist ein Null-Byte.\n" #: command.c:2643 #, c-format msgid "Field separator is \"%s\".\n" -msgstr "Feldtrennzeichen ist „%s“.\n" +msgstr "Feldtrennzeichen ist »%s«.\n" #: command.c:2656 #, c-format @@ -452,7 +452,7 @@ msgstr "Standardfußzeile ist aus.\n" #: command.c:2664 #, c-format msgid "Output format is %s.\n" -msgstr "Ausgabeformat ist „%s“.\n" +msgstr "Ausgabeformat ist »%s«.\n" #: command.c:2670 #, c-format @@ -462,7 +462,7 @@ msgstr "Linienstil ist %s.\n" #: command.c:2677 #, c-format msgid "Null display is \"%s\".\n" -msgstr "Null-Anzeige ist „%s“.\n" +msgstr "Null-Anzeige ist »%s«.\n" #: command.c:2685 #, c-format @@ -509,12 +509,12 @@ msgstr "Satztrennzeichen ist .\n" #: command.c:2718 #, c-format msgid "Record separator is \"%s\".\n" -msgstr "Satztrennzeichen ist „%s“.\n" +msgstr "Satztrennzeichen ist »%s«.\n" #: command.c:2731 #, c-format msgid "Table attributes are \"%s\".\n" -msgstr "Tabellenattribute sind „%s“.\n" +msgstr "Tabellenattribute sind »%s«.\n" #: command.c:2734 #, c-format @@ -524,7 +524,7 @@ msgstr "Tabellenattribute sind nicht gesetzt.\n" #: command.c:2741 #, c-format msgid "Title is \"%s\".\n" -msgstr "Titel ist „%s“.\n" +msgstr "Titel ist »%s«.\n" #: command.c:2743 #, c-format @@ -544,17 +544,17 @@ msgstr "Nur Datenzeilen ist aus.\n" #: command.c:2758 #, c-format msgid "Unicode border line style is \"%s\".\n" -msgstr "Unicode-Rahmenlinienstil ist „%s“.\n" +msgstr "Unicode-Rahmenlinienstil ist »%s«.\n" #: command.c:2764 #, c-format msgid "Unicode column line style is \"%s\".\n" -msgstr "Unicode-Spaltenlinienstil ist „%s“.\n" +msgstr "Unicode-Spaltenlinienstil ist »%s«.\n" #: command.c:2770 #, c-format msgid "Unicode header line style is \"%s\".\n" -msgstr "Unicode-Kopflinienstil ist „%s“.\n" +msgstr "Unicode-Kopflinienstil ist »%s«.\n" #: command.c:2930 #, c-format @@ -627,12 +627,12 @@ msgstr "Zeit: %.3f ms\n" #: common.c:608 #, c-format msgid "Asynchronous notification \"%s\" with payload \"%s\" received from server process with PID %d.\n" -msgstr "Asynchrone Benachrichtigung „%s“ mit Daten „%s“ vom Serverprozess mit PID %d empfangen.\n" +msgstr "Asynchrone Benachrichtigung »%s« mit Daten »%s« vom Serverprozess mit PID %d empfangen.\n" #: common.c:611 #, c-format msgid "Asynchronous notification \"%s\" received from server process with PID %d.\n" -msgstr "Asynchrone Benachrichtigung „%s“ vom Serverprozess mit PID %d empfangen.\n" +msgstr "Asynchrone Benachrichtigung »%s« vom Serverprozess mit PID %d empfangen.\n" #: common.c:669 #, c-format @@ -647,7 +647,7 @@ msgstr "mehr als eine Zeile für \\gset zurückgegeben\n" #: common.c:700 #, c-format msgid "could not set variable \"%s\"\n" -msgstr "konnte Variable „%s“ nicht setzen\n" +msgstr "konnte Variable »%s« nicht setzen\n" #: common.c:985 #, c-format @@ -658,7 +658,7 @@ msgid "" msgstr "" "***(Einzelschrittmodus: Anfrage bestätigen)*************************************\n" "%s\n" -"***(Drücken Sie die Eingabetaste um fortzufahren oder „x“ um abzubrechen)*******\n" +"***(Drücken Sie die Eingabetaste um fortzufahren oder »x« um abzubrechen)*******\n" #: common.c:1036 #, c-format @@ -683,7 +683,7 @@ msgstr "\\copy: benötigt Argumente\n" #: copy.c:253 #, c-format msgid "\\copy: parse error at \"%s\"\n" -msgstr "\\copy: Parse-Fehler bei „%s“\n" +msgstr "\\copy: Parse-Fehler bei »%s«\n" #: copy.c:255 #, c-format @@ -693,12 +693,12 @@ msgstr "\\copy: Parse-Fehler am Zeilenende\n" #: copy.c:328 #, c-format msgid "could not execute command \"%s\": %s\n" -msgstr "konnte Befehl „%s“ nicht ausführen: %s\n" +msgstr "konnte Befehl »%s« nicht ausführen: %s\n" #: copy.c:344 #, c-format msgid "could not stat file \"%s\": %s\n" -msgstr "konnte „stat“ für Datei „%s“ nicht ausführen: %s\n" +msgstr "konnte »stat« für Datei »%s« nicht ausführen: %s\n" #: copy.c:348 #, c-format @@ -817,7 +817,7 @@ msgstr "\\df akzeptiert nur [antwS+] als Optionen\n" #: describe.c:247 #, c-format msgid "\\df does not take a \"w\" option with server version %d.%d\n" -msgstr "\\df akzeptiert die Option „w“ nicht mit Serverversion %d.%d\n" +msgstr "\\df akzeptiert die Option »w« nicht mit Serverversion %d.%d\n" #. translator: "agg" is short for "aggregate" #: describe.c:280 describe.c:326 describe.c:343 @@ -1013,7 +1013,7 @@ msgstr "Objektbeschreibungen" #: describe.c:1169 #, c-format msgid "Did not find any relation named \"%s\".\n" -msgstr "Keine Relationen namens „%s“ gefunden\n" +msgstr "Keine Relationen namens »%s« gefunden\n" #: describe.c:1379 #, c-format @@ -1023,62 +1023,62 @@ msgstr "Keine Relation mit OID %s gefunden.\n" #: describe.c:1485 #, c-format msgid "Unlogged table \"%s.%s\"" -msgstr "Ungeloggte Tabelle „%s.%s“" +msgstr "Ungeloggte Tabelle »%s.%s«" #: describe.c:1488 #, c-format msgid "Table \"%s.%s\"" -msgstr "Tabelle „%s.%s“" +msgstr "Tabelle »%s.%s«" #: describe.c:1492 #, c-format msgid "View \"%s.%s\"" -msgstr "Sicht „%s.%s“" +msgstr "Sicht »%s.%s«" #: describe.c:1497 #, c-format msgid "Unlogged materialized view \"%s.%s\"" -msgstr "Ungeloggte materialisierte Sicht „%s.%s“" +msgstr "Ungeloggte materialisierte Sicht »%s.%s«" #: describe.c:1500 #, c-format msgid "Materialized view \"%s.%s\"" -msgstr "Materialisierte Sicht „%s.%s“" +msgstr "Materialisierte Sicht »%s.%s«" #: describe.c:1504 #, c-format msgid "Sequence \"%s.%s\"" -msgstr "Sequenz „%s.%s“" +msgstr "Sequenz »%s.%s«" #: describe.c:1509 #, c-format msgid "Unlogged index \"%s.%s\"" -msgstr "Ungeloggter Index „%s.%s“" +msgstr "Ungeloggter Index »%s.%s«" #: describe.c:1512 #, c-format msgid "Index \"%s.%s\"" -msgstr "Index „%s.%s“" +msgstr "Index »%s.%s«" #: describe.c:1517 #, c-format msgid "Special relation \"%s.%s\"" -msgstr "Spezielle Relation „%s.%s“" +msgstr "Spezielle Relation »%s.%s«" #: describe.c:1521 #, c-format msgid "TOAST table \"%s.%s\"" -msgstr "TOAST-Tabelle „%s.%s“" +msgstr "TOAST-Tabelle »%s.%s«" #: describe.c:1525 #, c-format msgid "Composite type \"%s.%s\"" -msgstr "Zusammengesetzter Typ „%s.%s“" +msgstr "Zusammengesetzter Typ »%s.%s«" #: describe.c:1529 #, c-format msgid "Foreign table \"%s.%s\"" -msgstr "Fremdtabelle „%s.%s“" +msgstr "Fremdtabelle »%s.%s«" #: describe.c:1540 msgid "Column" @@ -1135,7 +1135,7 @@ msgstr "eindeutig, " #: describe.c:1758 #, c-format msgid "for table \"%s.%s\"" -msgstr "für Tabelle „%s.%s“" +msgstr "für Tabelle »%s.%s«" #: describe.c:1762 #, c-format @@ -1276,14 +1276,14 @@ msgstr "Hat OIDs: ja" #: describe.c:2620 #, c-format msgid "Tablespace: \"%s\"" -msgstr "Tablespace: „%s“" +msgstr "Tablespace: »%s«" #. translator: before this string there's an index description like #. '"foo_pkey" PRIMARY KEY, btree (a)' #: describe.c:2632 #, c-format msgid ", tablespace \"%s\"" -msgstr ", Tablespace „%s“" +msgstr ", Tablespace »%s«" #: describe.c:2722 msgid "List of roles" @@ -1542,7 +1542,7 @@ msgstr "Liste der Textsucheparser" #: describe.c:3665 #, c-format msgid "Did not find any text search parser named \"%s\".\n" -msgstr "Kein Textsucheparser namens „%s“ gefunden\n" +msgstr "Kein Textsucheparser namens »%s« gefunden\n" #: describe.c:3740 msgid "Start parse" @@ -1571,12 +1571,12 @@ msgstr "Tokentypen ermitteln" #: describe.c:3761 #, c-format msgid "Text search parser \"%s.%s\"" -msgstr "Textsucheparser „%s.%s“" +msgstr "Textsucheparser »%s.%s«" #: describe.c:3763 #, c-format msgid "Text search parser \"%s\"" -msgstr "Textsucheparser „%s“" +msgstr "Textsucheparser »%s«" #: describe.c:3782 msgid "Token name" @@ -1585,12 +1585,12 @@ msgstr "Tokenname" #: describe.c:3793 #, c-format msgid "Token types for parser \"%s.%s\"" -msgstr "Tokentypen für Parser „%s.%s“" +msgstr "Tokentypen für Parser »%s.%s«" #: describe.c:3795 #, c-format msgid "Token types for parser \"%s\"" -msgstr "Tokentypen für Parser „%s“" +msgstr "Tokentypen für Parser »%s«" #: describe.c:3845 msgid "Template" @@ -1623,7 +1623,7 @@ msgstr "Liste der Textsuchekonfigurationen" #: describe.c:4037 #, c-format msgid "Did not find any text search configuration named \"%s\".\n" -msgstr "Keine Textsuchekonfiguration namens „%s“ gefunden\n" +msgstr "Keine Textsuchekonfiguration namens »%s« gefunden\n" #: describe.c:4103 msgid "Token" @@ -1636,12 +1636,12 @@ msgstr "Wörterbücher" #: describe.c:4115 #, c-format msgid "Text search configuration \"%s.%s\"" -msgstr "Textsuchekonfiguration „%s.%s“" +msgstr "Textsuchekonfiguration »%s.%s«" #: describe.c:4118 #, c-format msgid "Text search configuration \"%s\"" -msgstr "Textsuchekonfiguration „%s“" +msgstr "Textsuchekonfiguration »%s«" #: describe.c:4122 #, c-format @@ -1650,7 +1650,7 @@ msgid "" "Parser: \"%s.%s\"" msgstr "" "\n" -"Parser: „%s.%s“" +"Parser: »%s.%s«" #: describe.c:4125 #, c-format @@ -1659,7 +1659,7 @@ msgid "" "Parser: \"%s\"" msgstr "" "\n" -"Parser: „%s“" +"Parser: »%s«" #: describe.c:4157 #, c-format @@ -1729,7 +1729,7 @@ msgstr "Liste der installierten Erweiterungen" #: describe.c:4529 #, c-format msgid "Did not find any extension named \"%s\".\n" -msgstr "Keine Erweiterungen namens „%s“ gefunden\n" +msgstr "Keine Erweiterungen namens »%s« gefunden\n" #: describe.c:4532 #, c-format @@ -1743,7 +1743,7 @@ msgstr "Objektbeschreibung" #: describe.c:4585 #, c-format msgid "Objects in extension \"%s\"" -msgstr "Objekte in Erweiterung „%s“" +msgstr "Objekte in Erweiterung »%s«" #: help.c:63 #, c-format @@ -1788,7 +1788,7 @@ msgstr " -c, --command=ANWEISUNG einzelne Anweisung ausführen und beenden\n" msgid " -d, --dbname=DBNAME database name to connect to (default: \"%s\")\n" msgstr "" " -d, --dbname=DBNAME Datenbank, zu der verbunden werden soll\n" -" (Standard: „%s“)\n" +" (Standard: »%s«)\n" #: help.c:81 #, c-format @@ -1827,7 +1827,7 @@ msgid "" " -1 (\"one\"), --single-transaction\n" " execute as a single transaction (if non-interactive)\n" msgstr "" -" -1 („eins“), --single-transaction\n" +" -1 (»eins«), --single-transaction\n" " als eine einzige Transaktion ausführen (wenn nicht\n" " interaktiv)\n" @@ -1931,7 +1931,7 @@ msgid "" msgstr "" " -F, --field-separator=ZEICHEN\n" " Feldtrennzeichen für unausgerichteten Ausgabemodus\n" -" (Standard: „%s“)\n" +" (Standard: »%s«)\n" #: help.c:111 #, c-format @@ -1963,7 +1963,7 @@ msgstr " -t, --tuples-only nur Datenzeilen ausgeben\n" #: help.c:116 #, c-format msgid " -T, --table-attr=TEXT set HTML table tag attributes (e.g., width, border)\n" -msgstr " -T, --table-attr=TEXT HTML „table“-Tag-Attribute setzen (z.B. width, border)\n" +msgstr " -T, --table-attr=TEXT HTML »table«-Tag-Attribute setzen (z.B. width, border)\n" #: help.c:117 #, c-format @@ -2004,7 +2004,7 @@ msgstr "" msgid " -h, --host=HOSTNAME database server host or socket directory (default: \"%s\")\n" msgstr "" " -h, --host=HOSTNAME Hostname des Datenbankservers oder\n" -" Socket-Verzeichnis (Standard: „%s“)\n" +" Socket-Verzeichnis (Standard: »%s«)\n" #: help.c:127 msgid "local socket" @@ -2013,12 +2013,12 @@ msgstr "lokales Socket" #: help.c:130 #, c-format msgid " -p, --port=PORT database server port (default: \"%s\")\n" -msgstr " -p, --port=PORT Port des Datenbankservers (Standard: „%s“)\n" +msgstr " -p, --port=PORT Port des Datenbankservers (Standard: »%s«)\n" #: help.c:136 #, c-format msgid " -U, --username=USERNAME database user name (default: \"%s\")\n" -msgstr " -U, --username=NAME Datenbank-Benutzername (Standard: „%s“)\n" +msgstr " -U, --username=NAME Datenbank-Benutzername (Standard: »%s«)\n" #: help.c:137 #, c-format @@ -2040,8 +2040,8 @@ msgid "" "\n" msgstr "" "\n" -"Für mehr Informationen, geben Sie „\\?“ (für interne Anweisungen) oder\n" -"„\\help“ (für SQL-Anweisungen) in psql ein oder schauen Sie in den psql-\n" +"Für mehr Informationen, geben Sie »\\?« (für interne Anweisungen) oder\n" +"»\\help« (für SQL-Anweisungen) in psql ein oder schauen Sie in den psql-\n" "Abschnitt der PostgreSQL-Dokumentation.\n" "\n" @@ -2457,7 +2457,7 @@ msgid "" " connect to new database (currently \"%s\")\n" msgstr "" " \\c[onnect] {[DBNAME|- BENUTZER|- HOST|- PORT|-] | conninfo}\n" -" mit neuer Datenbank verbinden (aktuell „%s“)\n" +" mit neuer Datenbank verbinden (aktuell »%s«)\n" #: help.c:268 #, c-format @@ -2611,7 +2611,7 @@ msgid "" " if set to \"noexec\", just show without execution\n" msgstr "" " ECHO_HIDDEN wenn gesetzt, interne Anfragen, die von Backslash-Befehlen\n" -" ausgeführt werden, anzeigen; wenn auf „noexec“ gesetzt, nur\n" +" ausgeführt werden, anzeigen; wenn auf »noexec« gesetzt, nur\n" " anzeigen, nicht ausführen\n" #: help.c:325 @@ -2751,7 +2751,7 @@ msgstr " border Rahmenstil (Zahl)\n" #: help.c:351 #, c-format msgid " columns target width for the wrapped format\n" -msgstr " columns Zielbreite für das Format „wrapped“\n" +msgstr " columns Zielbreite für das Format »wrapped«\n" #: help.c:352 #, c-format @@ -2763,7 +2763,7 @@ msgstr " expanded (oder x) erweiterte Ausgabe [on, off, auto]\n" msgid " fieldsep field separator for unaligned output (default \"%s\")\n" msgstr "" " fieldsep Feldtrennzeichen für unausgerichteten Ausgabemodus\n" -" (Standard „%s“)\n" +" (Standard »%s«)\n" #: help.c:354 #, c-format @@ -2828,9 +2828,9 @@ msgid "" " tableattr (or T) specify attributes for table tag in html format or proportional\n" " column widths for left-aligned data types in latex-longtable format\n" msgstr "" -" tableattr (or T) Attribute für das „table“-Tag im Format „html“ oder\n" +" tableattr (or T) Attribute für das »table«-Tag im Format »html« oder\n" " proportionale Spaltenbreite für links ausgerichtete Datentypen\n" -" im Format „latex-longtable“\n" +" im Format »latex-longtable«\n" #: help.c:366 #, c-format @@ -2893,7 +2893,7 @@ msgstr "" #: help.c:382 #, c-format msgid " COLUMNS number of columns for wrapped format\n" -msgstr " COLUMNS Anzahl Spalten im Format „wrapped“\n" +msgstr " COLUMNS Anzahl Spalten im Format »wrapped«\n" #: help.c:383 #, c-format @@ -2903,27 +2903,27 @@ msgstr " PAGER Name des externen Pager-Programms\n" #: help.c:384 #, c-format msgid " PGAPPNAME same as the application_name connection parameter\n" -msgstr " PGAPPNAME wie Verbindungsparameter „application_name“\n" +msgstr " PGAPPNAME wie Verbindungsparameter »application_name«\n" #: help.c:385 #, c-format msgid " PGDATABASE same as the dbname connection parameter\n" -msgstr " PGDATABASE wie Verbindungsparameter „dbname“\n" +msgstr " PGDATABASE wie Verbindungsparameter »dbname«\n" #: help.c:386 #, c-format msgid " PGHOST same as the host connection parameter\n" -msgstr " PGHOST wie Verbindungsparameter „host“\n" +msgstr " PGHOST wie Verbindungsparameter »host«\n" #: help.c:387 #, c-format msgid " PGPORT same as the port connection parameter\n" -msgstr " PGPORT wie Verbindungsparameter „port“\n" +msgstr " PGPORT wie Verbindungsparameter »port«\n" #: help.c:388 #, c-format msgid " PGUSER same as the user connection parameter\n" -msgstr " PGUSER wie Verbindungsparameter „user“\n" +msgstr " PGUSER wie Verbindungsparameter »user«\n" #: help.c:389 #, c-format @@ -2998,7 +2998,7 @@ msgid "" "No help available for \"%s\".\n" "Try \\h with no arguments to see available help.\n" msgstr "" -"Keine Hilfe verfügbar für „%s“.\n" +"Keine Hilfe verfügbar für »%s«.\n" "Versuchen Sie \\h ohne Argumente, um die verfügbare Hilfe zu sehen.\n" #: input.c:205 @@ -3009,7 +3009,7 @@ msgstr "konnte nicht aus Eingabedatei lesen: %s\n" #: input.c:460 input.c:499 #, c-format msgid "could not save history to file \"%s\": %s\n" -msgstr "konnte Befehlsgeschichte nicht in „%s“ speichern: %s\n" +msgstr "konnte Befehlsgeschichte nicht in »%s« speichern: %s\n" #: input.c:519 #, c-format @@ -3042,7 +3042,7 @@ msgstr "Large Objects" #: mainloop.c:161 #, c-format msgid "Use \"\\q\" to leave %s.\n" -msgstr "Verwenden Sie „\\q“, um %s zu verlassen.\n" +msgstr "Verwenden Sie »\\q«, um %s zu verlassen.\n" #: mainloop.c:183 msgid "" @@ -3102,7 +3102,7 @@ msgstr "ungültiges Ausgabeformat (interner Fehler): %d" #: psqlscan.l:751 #, c-format msgid "skipping recursive expansion of variable \"%s\"\n" -msgstr "rekursive Auswertung der Variable „%s“ wird ausgelassen\n" +msgstr "rekursive Auswertung der Variable »%s« wird ausgelassen\n" #: psqlscan.l:1627 #, c-format @@ -5116,7 +5116,7 @@ msgstr "%s: -1 kann nur im nicht interaktiven Modus verwendet werden\n" #: startup.c:278 #, c-format msgid "%s: could not open log file \"%s\": %s\n" -msgstr "%s: konnte Logdatei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Logdatei »%s« nicht öffnen: %s\n" #: startup.c:342 #, c-format @@ -5124,33 +5124,33 @@ msgid "" "Type \"help\" for help.\n" "\n" msgstr "" -"Geben Sie „help“ für Hilfe ein.\n" +"Geben Sie »help« für Hilfe ein.\n" "\n" #: startup.c:490 #, c-format msgid "%s: could not set printing parameter \"%s\"\n" -msgstr "%s: konnte Ausgabeparameter „%s“ nicht setzen\n" +msgstr "%s: konnte Ausgabeparameter »%s« nicht setzen\n" #: startup.c:530 #, c-format msgid "%s: could not delete variable \"%s\"\n" -msgstr "%s: konnte Variable „%s“ nicht löschen\n" +msgstr "%s: konnte Variable »%s« nicht löschen\n" #: startup.c:540 #, c-format msgid "%s: could not set variable \"%s\"\n" -msgstr "%s: konnte Variable „%s“ nicht setzen\n" +msgstr "%s: konnte Variable »%s« nicht setzen\n" #: startup.c:600 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: startup.c:617 #, c-format msgid "%s: warning: extra command-line argument \"%s\" ignored\n" -msgstr "%s: Warnung: überflüssiges Kommandozeilenargument „%s“ ignoriert\n" +msgstr "%s: Warnung: überflüssiges Kommandozeilenargument »%s« ignoriert\n" #: startup.c:639 #, c-format @@ -5160,7 +5160,7 @@ msgstr "%s: konnte eigene Programmdatei nicht finden\n" #: startup.c:761 startup.c:808 startup.c:829 startup.c:866 variables.c:121 #, c-format msgid "unrecognized value \"%s\" for \"%s\"; assuming \"%s\"\n" -msgstr "unbekannter Wert „%s“ für „%s“; „%s“ wird angenommen\n" +msgstr "unbekannter Wert »%s« für »%s«; »%s« wird angenommen\n" #: tab-complete.c:4581 #, c-format diff --git a/src/bin/psql/po/es.po b/src/bin/psql/po/es.po index 51f7583d0f..ed179381be 100644 --- a/src/bin/psql/po/es.po +++ b/src/bin/psql/po/es.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: psql (PostgreSQL 9.5)\n" "Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n" "POT-Creation-Date: 2015-10-04 02:43+0000\n" -"PO-Revision-Date: 2015-10-05 11:40-0300\n" +"PO-Revision-Date: 2016-07-12 09:13-0400\n" "Last-Translator: Ãlvaro Herrera \n" "Language-Team: PgSQL Español \n" "Language: es\n" @@ -539,7 +539,7 @@ msgstr "El título ha sido indefinido.\n" #: command.c:2739 #, c-format msgid "Tuples only is on.\n" -msgstr "Mostrar sólo filas está desactivado.\n" +msgstr "Mostrar sólo filas está activado.\n" #: command.c:2741 #, c-format diff --git a/src/bin/psql/print.c b/src/bin/psql/print.c index c08d5af6bb..7983fa367e 100644 --- a/src/bin/psql/print.c +++ b/src/bin/psql/print.c @@ -316,8 +316,19 @@ format_numeric_locale(const char *my_str) static void fputnbytes(FILE *f, const char *str, size_t n) { + +#ifdef HAVE_WIN32_LIBEDIT + char buffer[1024]; + char *buf = buffer; + if (n>1023) buf=malloc(n+1); + strncpy(buf,str,n); + buf[n]=0; + fputs(buf,f); + if (n>1023) free(buf); +#else while (n-- > 0) fputc(*str++, f); +#endif } diff --git a/src/bin/psql/print.h b/src/bin/psql/print.h index 15a365e7d2..71468e722a 100644 --- a/src/bin/psql/print.h +++ b/src/bin/psql/print.h @@ -196,11 +196,13 @@ extern void printQuery(const PGresult *result, const printQueryOpt *opt, extern void setDecimalLocale(void); extern const printTextFormat *get_line_style(const printTableOpt *opt); extern void refresh_utf8format(const printTableOpt *opt); - +/* Let build system to redefine default pager */ +#ifndef DEFAULT_PAGER #ifndef __CYGWIN__ #define DEFAULT_PAGER "more" #else #define DEFAULT_PAGER "less" #endif +#endif #endif /* PRINT_H */ diff --git a/src/bin/psql/psqlscan.l b/src/bin/psql/psqlscan.l index be059abd8d..dc727f7b71 100644 --- a/src/bin/psql/psqlscan.l +++ b/src/bin/psql/psqlscan.l @@ -1605,7 +1605,8 @@ psql_scan_slash_option(PsqlScanState state, /* Keep the first quote, remove the second */ cp++; } - inquotes = !inquotes; + else + inquotes = !inquotes; /* Collapse out quote at *cp */ memmove(cp, cp + 1, strlen(cp)); mybuf.len--; diff --git a/src/bin/psql/startup.c b/src/bin/psql/startup.c index 8b1777e243..b1192fdae2 100644 --- a/src/bin/psql/startup.c +++ b/src/bin/psql/startup.c @@ -28,6 +28,7 @@ #include "mainloop.h" #include "print.h" #include "settings.h" +#include "mb/pg_wchar.h" @@ -128,7 +129,11 @@ main(int argc, char *argv[]) /* We rely on unmentioned fields of pset.popt to start out 0/false/NULL */ pset.popt.topt.format = PRINT_ALIGNED; pset.popt.topt.border = 1; +#ifdef WIN32 + pset.popt.topt.pager = 0; +#else pset.popt.topt.pager = 1; +#endif pset.popt.topt.pager_min_lines = 0; pset.popt.topt.start_table = true; pset.popt.topt.stop_table = true; @@ -144,7 +149,11 @@ main(int argc, char *argv[]) pset.popt.topt.env_columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 0; pset.notty = (!isatty(fileno(stdin)) || !isatty(fileno(stdout))); - +#ifdef HAVE_WIN32_LIBEDIT + if (!pset.notty && pset.encoding == PG_SQL_ASCII) { + pset.encoding = PG_UTF8; + } +#endif pset.getPassword = TRI_DEFAULT; EstablishVariableSpace(); @@ -215,14 +224,20 @@ main(int argc, char *argv[]) values[2] = options.username; keywords[3] = "password"; values[3] = password; - keywords[4] = "dbname"; + keywords[4] = "dbname"; /* see do_connect() */ values[4] = (options.action == ACT_LIST_DB && options.dbname == NULL) ? "postgres" : options.dbname; keywords[5] = "fallback_application_name"; values[5] = pset.progname; keywords[6] = "client_encoding"; - values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto"; + values[6] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : +#ifdef HAVE_WIN32_LIBEDIT + "UTF8" +#else + "auto" +#endif + ; keywords[7] = NULL; values[7] = NULL; @@ -894,3 +909,4 @@ EstablishVariableSpace(void) SetVariableAssignHook(pset.vars, "PROMPT3", prompt3_hook); SetVariableAssignHook(pset.vars, "VERBOSITY", verbosity_hook); } + diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index e46367252f..8f7d0b7d86 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -861,9 +861,13 @@ initialize_readline(void) { rl_readline_name = (char *) pset.progname; rl_attempted_completion_function = psql_completion; - +#ifndef HAVE_WIN32_LIBEDIT rl_basic_word_break_characters = WORD_BREAKS; + /* In WinLibEdit rl_basic_word_break_characters is constant */ + +#endif + completion_max_records = 1000; /* diff --git a/src/bin/scripts/clusterdb.c b/src/bin/scripts/clusterdb.c index f87a9cee29..75dc051ef1 100644 --- a/src/bin/scripts/clusterdb.c +++ b/src/bin/scripts/clusterdb.c @@ -209,10 +209,10 @@ cluster_one_database(const char *dbname, bool verbose, const char *table, { if (table) fprintf(stderr, _("%s: clustering of table \"%s\" in database \"%s\" failed: %s"), - progname, table, dbname, PQerrorMessage(conn)); + progname, table, PQdb(conn), PQerrorMessage(conn)); else fprintf(stderr, _("%s: clustering of database \"%s\" failed: %s"), - progname, dbname, PQerrorMessage(conn)); + progname, PQdb(conn), PQerrorMessage(conn)); PQfinish(conn); exit(1); } @@ -229,6 +229,7 @@ cluster_all_databases(bool verbose, const char *maintenance_db, { PGconn *conn; PGresult *result; + PQExpBufferData connstr; int i; conn = connectMaintenanceDatabase(maintenance_db, host, port, username, @@ -236,6 +237,7 @@ cluster_all_databases(bool verbose, const char *maintenance_db, result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo); PQfinish(conn); + initPQExpBuffer(&connstr); for (i = 0; i < PQntuples(result); i++) { char *dbname = PQgetvalue(result, i, 0); @@ -246,10 +248,15 @@ cluster_all_databases(bool verbose, const char *maintenance_db, fflush(stdout); } - cluster_one_database(dbname, verbose, NULL, + resetPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, dbname); + + cluster_one_database(connstr.data, verbose, NULL, host, port, username, prompt_password, progname, echo); } + termPQExpBuffer(&connstr); PQclear(result); } diff --git a/src/bin/scripts/createlang.c b/src/bin/scripts/createlang.c index f349624092..74402c3b79 100644 --- a/src/bin/scripts/createlang.c +++ b/src/bin/scripts/createlang.c @@ -192,10 +192,10 @@ main(int argc, char *argv[]) result = executeQuery(conn, sql.data, progname, echo); if (PQntuples(result) > 0) { - PQfinish(conn); fprintf(stderr, _("%s: language \"%s\" is already installed in database \"%s\"\n"), - progname, langname, dbname); + progname, langname, PQdb(conn)); + PQfinish(conn); /* separate exit status for "already installed" */ exit(2); } diff --git a/src/bin/scripts/droplang.c b/src/bin/scripts/droplang.c index e35fdc0092..d281ab691c 100644 --- a/src/bin/scripts/droplang.c +++ b/src/bin/scripts/droplang.c @@ -199,10 +199,10 @@ main(int argc, char *argv[]) result = executeQuery(conn, sql.data, progname, echo); if (PQntuples(result) == 0) { - PQfinish(conn); fprintf(stderr, _("%s: language \"%s\" is not installed in " "database \"%s\"\n"), - progname, langname, dbname); + progname, langname, PQdb(conn)); + PQfinish(conn); exit(1); } PQclear(result); diff --git a/src/bin/scripts/po/de.po b/src/bin/scripts/po/de.po index 96c8f07397..5063e17c61 100644 --- a/src/bin/scripts/po/de.po +++ b/src/bin/scripts/po/de.po @@ -1,7 +1,7 @@ # German message translation file for "scripts". # Peter Eisentraut , 2003 - 2015. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -49,14 +49,14 @@ msgstr "Fehler beim Nachschlagen des Benutzernamens: Fehlercode %lu" #: vacuumdb.c:209 vacuumdb.c:228 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: clusterdb.c:127 createdb.c:136 createlang.c:117 createuser.c:181 #: dropdb.c:109 droplang.c:116 dropuser.c:102 pg_isready.c:105 reindexdb.c:147 #: vacuumdb.c:226 #, c-format msgid "%s: too many command-line arguments (first is \"%s\")\n" -msgstr "%s: zu viele Kommandozeilenargumente (das erste ist „%s“)\n" +msgstr "%s: zu viele Kommandozeilenargumente (das erste ist »%s«)\n" #: clusterdb.c:139 #, c-format @@ -71,17 +71,17 @@ msgstr "%s: kann nicht bestimmte Tabelle(n) in allen Datenbanken clustern\n" #: clusterdb.c:211 #, c-format msgid "%s: clustering of table \"%s\" in database \"%s\" failed: %s" -msgstr "%s: Clustern der Tabelle „%s“ in Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Clustern der Tabelle »%s« in Datenbank »%s« fehlgeschlagen: %s" #: clusterdb.c:214 #, c-format msgid "%s: clustering of database \"%s\" failed: %s" -msgstr "%s: Clustern der Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Clustern der Datenbank »%s« fehlgeschlagen: %s" #: clusterdb.c:245 #, c-format msgid "%s: clustering database \"%s\"\n" -msgstr "%s: clustere Datenbank „%s“\n" +msgstr "%s: clustere Datenbank »%s«\n" #: clusterdb.c:261 #, c-format @@ -271,7 +271,7 @@ msgstr "%s (%s/%s) " #: common.c:292 #, c-format msgid "Please answer \"%s\" or \"%s\".\n" -msgstr "Bitte antworten Sie „%s“ oder „%s“.\n" +msgstr "Bitte antworten Sie »%s« oder »%s«.\n" #: common.c:371 common.c:408 #, c-format @@ -296,7 +296,7 @@ msgstr "%s: --locale und --lc-collate können nicht zusammen angegeben werden\n" #: createdb.c:164 #, c-format msgid "%s: \"%s\" is not a valid encoding name\n" -msgstr "%s: „%s“ ist kein gültiger Kodierungsname\n" +msgstr "%s: »%s« ist kein gültiger Kodierungsname\n" #: createdb.c:213 #, c-format @@ -442,7 +442,7 @@ msgstr "%s: Sprachenname als Argument fehlt\n" #: createlang.c:197 #, c-format msgid "%s: language \"%s\" is already installed in database \"%s\"\n" -msgstr "%s: Sprache „%s“ ist bereits in Datenbank „%s“ installiert\n" +msgstr "%s: Sprache »%s« ist bereits in Datenbank »%s« installiert\n" #: createlang.c:219 #, c-format @@ -643,7 +643,7 @@ msgstr "%s: Datenbankname als Argument fehlt\n" #: dropdb.c:117 #, c-format msgid "Database \"%s\" will be permanently removed.\n" -msgstr "Datenbank „%s“ wird unwiderruflich gelöscht werden.\n" +msgstr "Datenbank »%s« wird unwiderruflich gelöscht werden.\n" #: dropdb.c:118 dropuser.c:123 msgid "Are you sure?" @@ -681,7 +681,7 @@ msgstr " --if-exists keinen Fehler ausgeben, wenn Datenbank nicht #: droplang.c:203 #, c-format msgid "%s: language \"%s\" is not installed in database \"%s\"\n" -msgstr "%s: Sprache „%s“ ist nicht in Datenbank „%s“ installiert\n" +msgstr "%s: Sprache »%s« ist nicht in Datenbank »%s« installiert\n" #: droplang.c:221 #, c-format @@ -716,12 +716,12 @@ msgstr "%s: Rollenname als Argument fehlt\n" #: dropuser.c:122 #, c-format msgid "Role \"%s\" will be permanently removed.\n" -msgstr "Rolle „%s“ wird unwiderruflich gelöscht werden.\n" +msgstr "Rolle »%s« wird unwiderruflich gelöscht werden.\n" #: dropuser.c:140 #, c-format msgid "%s: removal of role \"%s\" failed: %s" -msgstr "%s: Löschen der Rolle „%s“ fehlgeschlagen: %s" +msgstr "%s: Löschen der Rolle »%s« fehlgeschlagen: %s" #: dropuser.c:155 #, c-format @@ -885,27 +885,27 @@ msgstr "%s: kann nicht bestimmte Index und Systemkataloge gleichzeitig reindizie #: reindexdb.c:306 #, c-format msgid "%s: reindexing of table \"%s\" in database \"%s\" failed: %s" -msgstr "%s: Reindizieren der Tabelle „%s“ in Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Reindizieren der Tabelle »%s« in Datenbank »%s« fehlgeschlagen: %s" #: reindexdb.c:309 #, c-format msgid "%s: reindexing of index \"%s\" in database \"%s\" failed: %s" -msgstr "%s: Reindizieren des Index „%s“ in Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Reindizieren des Index »%s« in Datenbank »%s« fehlgeschlagen: %s" #: reindexdb.c:312 #, c-format msgid "%s: reindexing of schema \"%s\" in database \"%s\" failed: %s" -msgstr "%s: Reindizieren des Schemas „%s“ in Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Reindizieren des Schemas »%s« in Datenbank »%s« fehlgeschlagen: %s" #: reindexdb.c:315 #, c-format msgid "%s: reindexing of database \"%s\" failed: %s" -msgstr "%s: Reindizieren der Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Reindizieren der Datenbank »%s« fehlgeschlagen: %s" #: reindexdb.c:346 #, c-format msgid "%s: reindexing database \"%s\"\n" -msgstr "%s: reindiziere Datenbank „%s“\n" +msgstr "%s: reindiziere Datenbank »%s«\n" #: reindexdb.c:379 #, c-format @@ -974,7 +974,7 @@ msgstr "%s: zu viele parallele Jobs angefordert (Maximum: %d)\n" #: vacuumdb.c:236 vacuumdb.c:242 #, c-format msgid "%s: cannot use the \"%s\" option when performing only analyze\n" -msgstr "%s: kann Option „%s“ nicht verwenden, wenn nur Analyze durchgeführt wird\n" +msgstr "%s: kann Option »%s« nicht verwenden, wenn nur Analyze durchgeführt wird\n" #: vacuumdb.c:259 #, c-format @@ -1001,22 +1001,22 @@ msgstr "Erzeuge volle Optimierer-Statistiken" #: vacuumdb.c:374 #, c-format msgid "%s: processing database \"%s\": %s\n" -msgstr "%s: bearbeite Datenbank „%s“: %s\n" +msgstr "%s: bearbeite Datenbank »%s«: %s\n" #: vacuumdb.c:377 #, c-format msgid "%s: vacuuming database \"%s\"\n" -msgstr "%s: führe Vacuum in Datenbank „%s“ aus\n" +msgstr "%s: führe Vacuum in Datenbank »%s« aus\n" #: vacuumdb.c:738 #, c-format msgid "%s: vacuuming of table \"%s\" in database \"%s\" failed: %s" -msgstr "%s: Vacuum der Tabelle „%s“ in Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Vacuum der Tabelle »%s« in Datenbank »%s« fehlgeschlagen: %s" #: vacuumdb.c:741 vacuumdb.c:858 #, c-format msgid "%s: vacuuming of database \"%s\" failed: %s" -msgstr "%s: Vacuum der Datenbank „%s“ fehlgeschlagen: %s" +msgstr "%s: Vacuum der Datenbank »%s« fehlgeschlagen: %s" #: vacuumdb.c:974 #, c-format diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c index b6f3dcbca0..a2aaed1faf 100644 --- a/src/bin/scripts/reindexdb.c +++ b/src/bin/scripts/reindexdb.c @@ -263,7 +263,7 @@ main(int argc, char *argv[]) * specified */ if (indexes.head == NULL && tables.head == NULL && schemas.head == NULL) - reindex_one_database(dbname, dbname, "DATABASE", host, port, + reindex_one_database(NULL, dbname, "DATABASE", host, port, username, prompt_password, progname, echo, verbose); } @@ -280,6 +280,9 @@ reindex_one_database(const char *name, const char *dbname, const char *type, PGconn *conn; + conn = connectDatabase(dbname, host, port, username, prompt_password, + progname, false, false); + initPQExpBuffer(&sql); appendPQExpBufferStr(&sql, "REINDEX"); @@ -294,26 +297,23 @@ reindex_one_database(const char *name, const char *dbname, const char *type, else if (strcmp(type, "SCHEMA") == 0) appendPQExpBuffer(&sql, " SCHEMA %s", name); else if (strcmp(type, "DATABASE") == 0) - appendPQExpBuffer(&sql, " DATABASE %s", fmtId(name)); + appendPQExpBuffer(&sql, " DATABASE %s", fmtId(PQdb(conn))); appendPQExpBufferChar(&sql, ';'); - conn = connectDatabase(dbname, host, port, username, prompt_password, - progname, false, false); - if (!executeMaintenanceCommand(conn, sql.data, echo)) { if (strcmp(type, "TABLE") == 0) fprintf(stderr, _("%s: reindexing of table \"%s\" in database \"%s\" failed: %s"), - progname, name, dbname, PQerrorMessage(conn)); + progname, name, PQdb(conn), PQerrorMessage(conn)); if (strcmp(type, "INDEX") == 0) fprintf(stderr, _("%s: reindexing of index \"%s\" in database \"%s\" failed: %s"), - progname, name, dbname, PQerrorMessage(conn)); + progname, name, PQdb(conn), PQerrorMessage(conn)); if (strcmp(type, "SCHEMA") == 0) fprintf(stderr, _("%s: reindexing of schema \"%s\" in database \"%s\" failed: %s"), - progname, name, dbname, PQerrorMessage(conn)); + progname, name, PQdb(conn), PQerrorMessage(conn)); else fprintf(stderr, _("%s: reindexing of database \"%s\" failed: %s"), - progname, dbname, PQerrorMessage(conn)); + progname, PQdb(conn), PQerrorMessage(conn)); PQfinish(conn); exit(1); } @@ -330,6 +330,7 @@ reindex_all_databases(const char *maintenance_db, { PGconn *conn; PGresult *result; + PQExpBufferData connstr; int i; conn = connectMaintenanceDatabase(maintenance_db, host, port, username, @@ -337,6 +338,7 @@ reindex_all_databases(const char *maintenance_db, result = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1;", progname, echo); PQfinish(conn); + initPQExpBuffer(&connstr); for (i = 0; i < PQntuples(result); i++) { char *dbname = PQgetvalue(result, i, 0); @@ -347,9 +349,15 @@ reindex_all_databases(const char *maintenance_db, fflush(stdout); } - reindex_one_database(dbname, dbname, "DATABASE", host, port, username, - prompt_password, progname, echo, verbose); + resetPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, dbname); + + reindex_one_database(NULL, connstr.data, "DATABASE", host, + port, username, prompt_password, + progname, echo, verbose); } + termPQExpBuffer(&connstr); PQclear(result); } @@ -359,9 +367,11 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port, const char *username, enum trivalue prompt_password, const char *progname, bool echo, bool verbose) { + PGconn *conn; PQExpBufferData sql; - PGconn *conn; + conn = connectDatabase(dbname, host, port, username, prompt_password, + progname, false, false); initPQExpBuffer(&sql); @@ -370,10 +380,8 @@ reindex_system_catalogs(const char *dbname, const char *host, const char *port, if (verbose) appendPQExpBuffer(&sql, " (VERBOSE)"); - appendPQExpBuffer(&sql, " SYSTEM %s;", dbname); + appendPQExpBuffer(&sql, " SYSTEM %s;", fmtId(PQdb(conn))); - conn = connectDatabase(dbname, host, port, username, prompt_password, - progname, false, false); if (!executeMaintenanceCommand(conn, sql.data, echo)) { fprintf(stderr, _("%s: reindexing of system catalogs failed: %s"), diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index 0863c64cbc..2125f42c99 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -12,6 +12,10 @@ #include "postgres_fe.h" +#ifdef HAVE_SYS_SELECT_H +#include +#endif + #include "common.h" #include "dumputils.h" @@ -57,14 +61,12 @@ static void prepare_vacuum_command(PQExpBuffer sql, PGconn *conn, vacuumingOptions *vacopts, const char *table); static void run_vacuum_command(PGconn *conn, const char *sql, bool echo, - const char *dbname, const char *table, - const char *progname, bool async); + const char *table, const char *progname, bool async); static ParallelSlot *GetIdleSlot(ParallelSlot slots[], int numslots, - const char *dbname, const char *progname); + const char *progname); -static bool GetQueryResult(PGconn *conn, const char *dbname, - const char *progname); +static bool GetQueryResult(PGconn *conn, const char *progname); static void DisconnectDatabase(ParallelSlot *slot); @@ -355,19 +357,20 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, Assert(stage == ANALYZE_NO_STAGE || (stage >= 0 && stage < ANALYZE_NUM_STAGES)); + conn = connectDatabase(dbname, host, port, username, prompt_password, + progname, false, true); + if (!quiet) { if (stage != ANALYZE_NO_STAGE) - printf(_("%s: processing database \"%s\": %s\n"), progname, dbname, - stage_messages[stage]); + printf(_("%s: processing database \"%s\": %s\n"), + progname, PQdb(conn), stage_messages[stage]); else - printf(_("%s: vacuuming database \"%s\"\n"), progname, dbname); + printf(_("%s: vacuuming database \"%s\"\n"), + progname, PQdb(conn)); fflush(stdout); } - conn = connectDatabase(dbname, host, port, username, prompt_password, - progname, false, true); - initPQExpBuffer(&sql); /* @@ -473,7 +476,7 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, * Get a free slot, waiting until one becomes free if none * currently is. */ - free_slot = GetIdleSlot(slots, concurrentCons, dbname, progname); + free_slot = GetIdleSlot(slots, concurrentCons, progname); if (!free_slot) { failed = true; @@ -491,7 +494,7 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, * errors in GetQueryResult through GetIdleSlot.) */ run_vacuum_command(free_slot->connection, sql.data, - echo, dbname, tabname, progname, parallel); + echo, tabname, progname, parallel); if (cell) cell = cell->next; @@ -504,7 +507,7 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, for (j = 0; j < concurrentCons; j++) { /* wait for all connection to return the results */ - if (!GetQueryResult((slots + j)->connection, dbname, progname)) + if (!GetQueryResult((slots + j)->connection, progname)) goto finish; (slots + j)->isFree = true; @@ -540,6 +543,7 @@ vacuum_all_databases(vacuumingOptions *vacopts, { PGconn *conn; PGresult *result; + PQExpBufferData connstr; int stage; int i; @@ -550,6 +554,7 @@ vacuum_all_databases(vacuumingOptions *vacopts, progname, echo); PQfinish(conn); + initPQExpBuffer(&connstr); if (analyze_in_stages) { /* @@ -564,10 +569,11 @@ vacuum_all_databases(vacuumingOptions *vacopts, { for (i = 0; i < PQntuples(result); i++) { - const char *dbname; + resetPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, PQgetvalue(result, i, 0)); - dbname = PQgetvalue(result, i, 0); - vacuum_one_database(dbname, vacopts, + vacuum_one_database(connstr.data, vacopts, stage, NULL, host, port, username, prompt_password, @@ -580,10 +586,11 @@ vacuum_all_databases(vacuumingOptions *vacopts, { for (i = 0; i < PQntuples(result); i++) { - const char *dbname; + resetPQExpBuffer(&connstr); + appendPQExpBuffer(&connstr, "dbname="); + appendConnStrVal(&connstr, PQgetvalue(result, i, 0)); - dbname = PQgetvalue(result, i, 0); - vacuum_one_database(dbname, vacopts, + vacuum_one_database(connstr.data, vacopts, ANALYZE_NO_STAGE, NULL, host, port, username, prompt_password, @@ -591,6 +598,7 @@ vacuum_all_databases(vacuumingOptions *vacopts, progname, echo, quiet); } } + termPQExpBuffer(&connstr); PQclear(result); } @@ -672,8 +680,7 @@ prepare_vacuum_command(PQExpBuffer sql, PGconn *conn, vacuumingOptions *vacopts, */ static void run_vacuum_command(PGconn *conn, const char *sql, bool echo, - const char *dbname, const char *table, - const char *progname, bool async) + const char *table, const char *progname, bool async) { bool status; @@ -692,10 +699,10 @@ run_vacuum_command(PGconn *conn, const char *sql, bool echo, if (table) fprintf(stderr, _("%s: vacuuming of table \"%s\" in database \"%s\" failed: %s"), - progname, table, dbname, PQerrorMessage(conn)); + progname, table, PQdb(conn), PQerrorMessage(conn)); else fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"), - progname, dbname, PQerrorMessage(conn)); + progname, PQdb(conn), PQerrorMessage(conn)); if (!async) { @@ -721,7 +728,7 @@ run_vacuum_command(PGconn *conn, const char *sql, bool echo, * If an error occurs, NULL is returned. */ static ParallelSlot * -GetIdleSlot(ParallelSlot slots[], int numslots, const char *dbname, +GetIdleSlot(ParallelSlot slots[], int numslots, const char *progname) { int i; @@ -761,7 +768,7 @@ GetIdleSlot(ParallelSlot slots[], int numslots, const char *dbname, * We set the cancel-receiving connection to the one in the zeroth * slot above, so fetch the error from there. */ - GetQueryResult(slots->connection, dbname, progname); + GetQueryResult(slots->connection, progname); return NULL; } Assert(i != 0); @@ -777,7 +784,7 @@ GetIdleSlot(ParallelSlot slots[], int numslots, const char *dbname, (slots + i)->isFree = true; - if (!GetQueryResult((slots + i)->connection, dbname, progname)) + if (!GetQueryResult((slots + i)->connection, progname)) return NULL; if (firstFree < 0) @@ -796,7 +803,7 @@ GetIdleSlot(ParallelSlot slots[], int numslots, const char *dbname, * reported and subsequently ignored. */ static bool -GetQueryResult(PGconn *conn, const char *dbname, const char *progname) +GetQueryResult(PGconn *conn, const char *progname) { PGresult *result; @@ -812,7 +819,7 @@ GetQueryResult(PGconn *conn, const char *dbname, const char *progname) char *sqlState = PQresultErrorField(result, PG_DIAG_SQLSTATE); fprintf(stderr, _("%s: vacuuming of database \"%s\" failed: %s"), - progname, dbname, PQerrorMessage(conn)); + progname, PQdb(conn), PQerrorMessage(conn)); if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) != 0) { diff --git a/src/common/exec.c b/src/common/exec.c index e5575d5f50..f7c39f6b32 100644 --- a/src/common/exec.c +++ b/src/common/exec.c @@ -441,13 +441,13 @@ pipe_read_line(char *cmd, char *line, int maxsize) /* Let's see if we can read */ if (WaitForSingleObject(childstdoutrddup, 10000) != WAIT_OBJECT_0) break; /* Timeout, but perhaps we got a line already */ - + if (!ReadFile(childstdoutrddup, lineptr, maxsize - (lineptr - line), - &bytesread, NULL)) + &bytesread, NULL)) break; /* Error, but perhaps we got a line already */ - + lineptr += strlen(lineptr); - + if (!bytesread) break; /* EOF */ @@ -578,6 +578,11 @@ set_pglocale_pgservice(const char *argv0, const char *app) bindtextdomain(app, path); textdomain(app); +#if defined(HAVE_WIN32_LIBEDIT) && defined(ENABLE_NLS) + bind_textdomain_codeset(app, "UTF-8"); + bind_textdomain_codeset(PG_TEXTDOMAIN("libpq"), "UTF-8"); +#endif + if (getenv("PGLOCALEDIR") == NULL) { /* set for libpq to use */ diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 4f1a5c33ea..8eac5ebd36 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -105,15 +105,11 @@ typedef struct GISTSTATE * upper index pages; this rule avoids doing extra work during a search that * ends early due to LIMIT. * - * To perform an ordered search, we use an RBTree to manage the distance-order - * queue. Each GISTSearchTreeItem stores all unvisited items of the same - * distance; they are GISTSearchItems chained together via their next fields. - * - * In a non-ordered search (no order-by operators), the RBTree degenerates - * to a single item, which we use as a queue of unvisited index pages only. - * In this case matched heap items from the current index leaf page are - * remembered in GISTScanOpaqueData.pageData[] and returned directly from - * there, instead of building a separate GISTSearchItem for each one. + * To perform an ordered search, we use a pairing heap to manage the + * distance-order queue. In a non-ordered search (no order-by operators), + * we use it to return heap tuples before unvisited index pages, to + * ensure depth-first order, but all entries are otherwise considered + * equal. */ /* Individual heap tuple to be visited */ @@ -288,8 +284,8 @@ typedef struct #define GIST_ROOT_BLKNO 0 /* - * Before PostgreSQL 9.1, we used rely on so-called "invalid tuples" on inner - * pages to finish crash recovery of incomplete page splits. If a crash + * Before PostgreSQL 9.1, we used to rely on so-called "invalid tuples" on + * inner pages to finish crash recovery of incomplete page splits. If a crash * happened in the middle of a page split, so that the downlink pointers were * not yet inserted, crash recovery inserted a special downlink pointer. The * semantics of an invalid tuple was that it if you encounter one in a scan, diff --git a/src/include/access/parallel.h b/src/include/access/parallel.h index 44f0616cb8..4ac46fce57 100644 --- a/src/include/access/parallel.h +++ b/src/include/access/parallel.h @@ -19,7 +19,6 @@ #include "postmaster/bgworker.h" #include "storage/shm_mq.h" #include "storage/shm_toc.h" -#include "utils/elog.h" typedef void (*parallel_worker_main_type) (dsm_segment *seg, shm_toc *toc); @@ -46,7 +45,7 @@ typedef struct ParallelContext ParallelWorkerInfo *worker; } ParallelContext; -extern bool ParallelMessagePending; +extern volatile bool ParallelMessagePending; extern int ParallelWorkerNumber; extern bool InitializingParallelWorker; @@ -54,16 +53,16 @@ extern bool InitializingParallelWorker; extern ParallelContext *CreateParallelContext(parallel_worker_main_type entrypoint, int nworkers); extern ParallelContext *CreateParallelContextForExternalFunction(char *library_name, char *function_name, int nworkers); -extern void InitializeParallelDSM(ParallelContext *); -extern void LaunchParallelWorkers(ParallelContext *); -extern void WaitForParallelWorkersToFinish(ParallelContext *); -extern void DestroyParallelContext(ParallelContext *); +extern void InitializeParallelDSM(ParallelContext *pcxt); +extern void LaunchParallelWorkers(ParallelContext *pcxt); +extern void WaitForParallelWorkersToFinish(ParallelContext *pcxt); +extern void DestroyParallelContext(ParallelContext *pcxt); extern bool ParallelContextActive(void); extern void HandleParallelMessageInterrupt(void); extern void HandleParallelMessages(void); extern void AtEOXact_Parallel(bool isCommit); extern void AtEOSubXact_Parallel(bool isCommit, SubTransactionId mySubId); -extern void ParallelWorkerReportLastRecEnd(XLogRecPtr); +extern void ParallelWorkerReportLastRecEnd(XLogRecPtr last_xlog_end); #endif /* PARALLEL_H */ diff --git a/src/include/access/tuptoaster.h b/src/include/access/tuptoaster.h index 7d18535771..9e16e25656 100644 --- a/src/include/access/tuptoaster.h +++ b/src/include/access/tuptoaster.h @@ -142,7 +142,7 @@ extern HeapTuple toast_insert_or_update(Relation rel, * Called by heap_delete(). * ---------- */ -extern void toast_delete(Relation rel, HeapTuple oldtup); +extern void toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative); /* ---------- * heap_tuple_fetch_attr() - diff --git a/src/include/catalog/pg_statistic.h b/src/include/catalog/pg_statistic.h index 62a00fea38..15ca805110 100644 --- a/src/include/catalog/pg_statistic.h +++ b/src/include/catalog/pg_statistic.h @@ -57,13 +57,14 @@ CATALOG(pg_statistic,2619) BKI_WITHOUT_OIDS * > 0 actual number of distinct values * < 0 negative of multiplier for number of rows * The special negative case allows us to cope with columns that are - * unique (stadistinct = -1) or nearly so (for example, a column in - * which values appear about twice on the average could be represented - * by stadistinct = -0.5). Because the number-of-rows statistic in - * pg_class may be updated more frequently than pg_statistic is, it's - * important to be able to describe such situations as a multiple of - * the number of rows, rather than a fixed number of distinct values. - * But in other cases a fixed number is correct (eg, a boolean column). + * unique (stadistinct = -1) or nearly so (for example, a column in which + * non-null values appear about twice on the average could be represented + * by stadistinct = -0.5 if there are no nulls, or -0.4 if 20% of the + * column is nulls). Because the number-of-rows statistic in pg_class may + * be updated more frequently than pg_statistic is, it's important to be + * able to describe such situations as a multiple of the number of rows, + * rather than a fixed number of distinct values. But in other cases a + * fixed number is correct (eg, a boolean column). * ---------------- */ float4 stadistinct; diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h index 26fcc5b643..2ad3fb87db 100644 --- a/src/include/commands/explain.h +++ b/src/include/commands/explain.h @@ -35,6 +35,8 @@ typedef struct ExplainState bool timing; /* print detailed node timing */ bool summary; /* print total planning and execution timing */ ExplainFormat format; /* output format */ + bool runtime; /* print intermediate state of query execution, + not after completion */ /* other states */ PlannedStmt *pstmt; /* top of plan */ List *rtable; /* range table */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 110bc9317b..8801419bfd 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -95,6 +95,12 @@ extern PGDLLIMPORT ExecutorEnd_hook_type ExecutorEnd_hook; typedef bool (*ExecutorCheckPerms_hook_type) (List *, bool); extern PGDLLIMPORT ExecutorCheckPerms_hook_type ExecutorCheckPerms_hook; +/* Hook for plugins to pre/post process ExecProcNode() */ +typedef void (*PreExecProcNode_hook_type) (PlanState *node); +typedef void (*PostExecProcNode_hook_type) (PlanState *node, TupleTableSlot *result); +extern PGDLLIMPORT PreExecProcNode_hook_type preExecProcNode_hook; +extern PGDLLIMPORT PostExecProcNode_hook_type postExecProcNode_hook; + /* * prototypes from functions in execAmi.c diff --git a/src/include/executor/instrument.h b/src/include/executor/instrument.h index c9a2129c7a..c53517f4bb 100644 --- a/src/include/executor/instrument.h +++ b/src/include/executor/instrument.h @@ -52,14 +52,16 @@ typedef struct Instrumentation instr_time counter; /* Accumulated runtime for this node */ double firsttuple; /* Time for first tuple of this cycle */ double tuplecount; /* Tuples emitted so far this cycle */ + double nfiltered1; /* # tuples removed by scanqual or joinqual */ + double nfiltered2; /* # tuples removed by "other" quals */ BufferUsage bufusage_start; /* Buffer usage at start */ /* Accumulated statistics across all completed cycles: */ double startup; /* Total startup time (in seconds) */ double total; /* Total total time (in seconds) */ double ntuples; /* Total tuples produced */ double nloops; /* # of run cycles for this node */ - double nfiltered1; /* # tuples removed by scanqual or joinqual */ - double nfiltered2; /* # tuples removed by "other" quals */ + double accum_nfiltered1; /* # tuples removed by scanqual or joinqual on previous loops */ + double accum_nfiltered2; /* # tuples removed by "other" quals on previous loops */ BufferUsage bufusage; /* Total buffer usage */ } Instrumentation; diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index efb2dacbba..42ab915712 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -42,7 +42,7 @@ extern PGDLLIMPORT PQcommMethods *PqCommMethods; #define pq_putmessage(msgtype, s, len) \ (PqCommMethods->putmessage(msgtype, s, len)) #define pq_putmessage_noblock(msgtype, s, len) \ - (PqCommMethods->putmessage(msgtype, s, len)) + (PqCommMethods->putmessage_noblock(msgtype, s, len)) #define pq_startcopyout() (PqCommMethods->startcopyout()) #define pq_endcopyout(errorAbort) (PqCommMethods->endcopyout(errorAbort)) diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 7a6a3fea47..cfcb9944f9 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -721,6 +721,8 @@ typedef struct Agg AttrNumber *grpColIdx; /* their indexes in the target list */ Oid *grpOperators; /* equality operators to compare with */ long numGroups; /* estimated number of groups in input */ + Bitmapset *aggParams; /* IDs of Params used in Aggref inputs */ + /* Note: planner provides numGroups & aggParams only in AGG_HASHED case */ List *groupingSets; /* grouping sets to use */ List *chain; /* chained Agg/Sort nodes */ } Agg; diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h index c8b1f907a8..a8a2c4e4e7 100644 --- a/src/include/nodes/primnodes.h +++ b/src/include/nodes/primnodes.h @@ -1076,8 +1076,16 @@ typedef struct XmlExpr * NullTest represents the operation of testing a value for NULLness. * The appropriate test is performed and returned as a boolean Datum. * - * NOTE: the semantics of this for rowtype inputs are noticeably different - * from the scalar case. We provide an "argisrow" flag to reflect that. + * When argisrow is false, this simply represents a test for the null value. + * + * When argisrow is true, the input expression must yield a rowtype, and + * the node implements "row IS [NOT] NULL" per the SQL standard. This + * includes checking individual fields for NULLness when the row datum + * itself isn't NULL. + * + * NOTE: the combination of a rowtype input and argisrow==false does NOT + * correspond to the SQL notation "row IS [NOT] NULL"; instead, this case + * represents the SQL notation "row IS [NOT] DISTINCT FROM NULL". * ---------------- */ @@ -1091,7 +1099,7 @@ typedef struct NullTest Expr xpr; Expr *arg; /* input expression */ NullTestType nulltesttype; /* IS NULL, IS NOT NULL */ - bool argisrow; /* T if input is of a composite type */ + bool argisrow; /* T to perform field-by-field null checks */ int location; /* token location, or -1 if unknown */ } NullTest; diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 893eda6840..c00c6eb4c6 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -84,12 +84,21 @@ /* Define to 1 if you have the `append_history' function. */ #undef HAVE_APPEND_HISTORY +/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */ +#undef HAVE_ASN1_STRING_GET0_DATA + /* Define to 1 if you want to use atomics if available. */ #undef HAVE_ATOMICS /* Define to 1 if you have the header file. */ #undef HAVE_ATOMIC_H +/* Define to 1 if you have the `BIO_get_data' function. */ +#undef HAVE_BIO_GET_DATA + +/* Define to 1 if you have the `BIO_meth_new' function. */ +#undef HAVE_BIO_METH_NEW + /* Define to 1 if you have the `cbrt' function. */ #undef HAVE_CBRT @@ -102,6 +111,9 @@ /* Define to 1 if you have the `crypt' function. */ #undef HAVE_CRYPT +/* Define to 1 if you have the `CRYPTO_lock' function. */ +#undef HAVE_CRYPTO_LOCK + /* Define to 1 if you have the header file. */ #undef HAVE_CRYPT_H @@ -367,6 +379,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NET_IF_H +/* Define to 1 if you have the `OPENSSL_init_ssl' function. */ +#undef HAVE_OPENSSL_INIT_SSL + /* Define to 1 if you have the header file. */ #undef HAVE_OSSP_UUID_H @@ -403,6 +418,9 @@ /* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM +/* Define to 1 if you have the `RAND_OpenSSL' function. */ +#undef HAVE_RAND_OPENSSL + /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_H diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index b4d013986c..090637bdfd 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -563,10 +563,10 @@ #define PACKAGE_NAME "PostgreSQL" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "PostgreSQL 9.5.3" +#define PACKAGE_STRING "PostgreSQL 9.5.4" /* Define to the version of this package. */ -#define PACKAGE_VERSION "9.5.3" +#define PACKAGE_VERSION "9.5.4" /* Define to the name of a signed 128-bit integer type. */ #undef PG_INT128_TYPE @@ -575,16 +575,16 @@ #define PG_INT64_TYPE long long int /* PostgreSQL version as a string */ -#define PG_VERSION "9.5.3" +#define PG_VERSION "9.5.4" /* PostgreSQL version as a number */ -#define PG_VERSION_NUM 90503 +#define PG_VERSION_NUM 90504 #define PGPRO_PACKAGE_NAME "PostgresPro" -#define PGPRO_PACKAGE_VERSION "9.5.3.1" +#define PGPRO_PACKAGE_VERSION "9.5.4.1" -#define PGPRO_PACKAGE_STR "PostgresPro 9.5.3.1" +#define PGPRO_PACKAGE_STR "PostgresPro 9.5.4.1" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "postgrespro" diff --git a/src/include/port.h b/src/include/port.h index 3787cbfb76..f105bdaf01 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -151,6 +151,9 @@ extern unsigned char pg_ascii_tolower(unsigned char ch); #ifdef printf #undef printf #endif +#ifdef fputs +#undef fputs +#endif extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args); extern int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3, 4); @@ -159,6 +162,10 @@ extern int pg_vfprintf(FILE *stream, const char *fmt, va_list args); extern int pg_fprintf(FILE *stream, const char *fmt,...) pg_attribute_printf(2, 3); extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); +#ifdef HAVE_WIN32_LIBEDIT +extern int pg_fputs(const char *s, FILE *stream); +extern int pg_puts(const char *s); +#endif /* * The GCC-specific code below prevents the pg_attribute_printf above from * being replaced, and this is required because gcc doesn't know anything @@ -179,6 +186,11 @@ extern int pg_printf(const char *fmt,...) pg_attribute_printf(1, 2); #define fprintf pg_fprintf #define printf pg_printf #endif +#ifdef HAVE_WIN32_LIBEDIT +/* Catch fputs as well so we can use WriteConsole for table output */ +#define fputs(s,f) pg_fputs(s,f) +#define puts(s) pg_puts(s) +#endif #endif /* USE_REPL_SNPRINTF */ #if defined(WIN32) diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h index 28fc684d24..273836d553 100644 --- a/src/include/storage/latch.h +++ b/src/include/storage/latch.h @@ -52,6 +52,22 @@ * do. Otherwise, if someone sets the latch between the check and the * ResetLatch call, you will miss it and Wait will incorrectly block. * + * Another valid coding pattern looks like: + * + * for (;;) + * { + * if (work to do) + * Do Stuff(); // in particular, exit loop if some condition satisfied + * WaitLatch(); + * ResetLatch(); + * } + * + * This is useful to reduce latch traffic if it's expected that the loop's + * termination condition will often be satisfied in the first iteration; + * the cost is an extra loop iteration before blocking when it is not. + * What must be avoided is placing any checks for asynchronous events after + * WaitLatch and before ResetLatch, as that creates a race condition. + * * To wake up the waiter, you must first set a global flag or something * else that the wait loop tests in the "if (work to do)" part, and call * SetLatch *after* that. SetLatch is designed to return quickly if the diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h index af1a0cd71f..507a63c2d3 100644 --- a/src/include/storage/procsignal.h +++ b/src/include/storage/procsignal.h @@ -17,6 +17,8 @@ #include "storage/backendid.h" +#define NUM_CUSTOM_PROCSIGNALS 64 + /* * Reasons for signalling a Postgres child process (a backend or an auxiliary * process, like checkpointer). We can cope with concurrent signals for different @@ -29,6 +31,8 @@ */ typedef enum { + INVALID_PROCSIGNAL = -1, /* Must be first */ + PROCSIG_CATCHUP_INTERRUPT, /* sinval catchup interrupt */ PROCSIG_NOTIFY_INTERRUPT, /* listen/notify interrupt */ PROCSIG_PARALLEL_MESSAGE, /* message from cooperating parallel backend */ @@ -41,9 +45,20 @@ typedef enum PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, + PROCSIG_CUSTOM_1, + /* + * PROCSIG_CUSTOM_2, + * ..., + * PROCSIG_CUSTOM_N-1, + */ + PROCSIG_CUSTOM_N = PROCSIG_CUSTOM_1 + NUM_CUSTOM_PROCSIGNALS - 1, + NUM_PROCSIGNALS /* Must be last! */ } ProcSignalReason; +/* Handler of custom process signal */ +typedef void (*ProcSignalHandler_type) (void); + /* * prototypes for functions in procsignal.c */ @@ -51,9 +66,15 @@ extern Size ProcSignalShmemSize(void); extern void ProcSignalShmemInit(void); extern void ProcSignalInit(int pss_idx); +extern ProcSignalReason RegisterCustomProcSignalHandler(ProcSignalHandler_type handler); +extern ProcSignalHandler_type AssignCustomProcSignalHandler(ProcSignalReason reason, + ProcSignalHandler_type handler); +extern ProcSignalHandler_type GetCustomProcSignalHandler(ProcSignalReason reason); extern int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId); +extern void CheckAndHandleCustomSignals(void); + extern void procsignal_sigusr1_handler(SIGNAL_ARGS); extern PGDLLIMPORT bool set_latch_on_sigusr1; diff --git a/src/include/utils/array.h b/src/include/utils/array.h index c25b80d272..0f934b6173 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -36,7 +36,7 @@ * * The OIDVECTOR and INT2VECTOR datatypes are storage-compatible with * generic arrays, but they support only one-dimensional arrays with no - * nulls (and no null bitmap). + * nulls (and no null bitmap). They don't support being toasted, either. * * There are also some "fixed-length array" datatypes, such as NAME and * POINT. These are simply a sequence of a fixed number of items each diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 9081624c34..b87e9694f5 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -339,6 +339,8 @@ extern float get_float4_infinity(void); extern double get_float8_nan(void); extern float get_float4_nan(void); extern int is_infinite(double val); +extern int float4_cmp_internal(float4 a, float4 b); +extern int float8_cmp_internal(float8 a, float8 b); extern Datum float4in(PG_FUNCTION_ARGS); extern Datum float4out(PG_FUNCTION_ARGS); diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 3f2b078e3b..248213f0fe 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -204,12 +204,13 @@ extern int getinternalerrposition(void); #else /* !HAVE__BUILTIN_CONSTANT_P */ #define elog(elevel, ...) \ do { \ - int elevel_; \ elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \ - elevel_ = (elevel); \ - elog_finish(elevel_, __VA_ARGS__); \ - if (elevel_ >= ERROR) \ - pg_unreachable(); \ + { \ + const int elevel_ = (elevel); \ + elog_finish(elevel_, __VA_ARGS__); \ + if (elevel_ >= ERROR) \ + pg_unreachable(); \ + } \ } while(0) #endif /* HAVE__BUILTIN_CONSTANT_P */ #else /* !HAVE__VA_ARGS */ diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h index b7451fa2e3..b00abbe6e2 100644 --- a/src/include/utils/numeric.h +++ b/src/include/utils/numeric.h @@ -17,8 +17,9 @@ #include "fmgr.h" /* - * Hardcoded precision limit - arbitrary, but must be small enough that - * dscale values will fit in 14 bits. + * Limit on the precision (and hence scale) specifiable in a NUMERIC typmod. + * Note that the implementation limit on the length of a numeric value is + * much larger --- beware of what you use this for! */ #define NUMERIC_MAX_PRECISION 1000 diff --git a/src/interfaces/ecpg/ecpglib/data.c b/src/interfaces/ecpg/ecpglib/data.c index 82ab4aaf86..23646a9579 100644 --- a/src/interfaces/ecpg/ecpglib/data.c +++ b/src/interfaces/ecpg/ecpglib/data.c @@ -375,8 +375,7 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno, #ifdef HAVE_STRTOULL case ECPGt_unsigned_long_long: *((unsigned long long int *) (var + offset * act_tuple)) = strtoull(pval, &scan_length, 10); - if ((isarray && *scan_length != ',' && *scan_length != '}') - || (!isarray && !(INFORMIX_MODE(compat) && *scan_length == '.') && *scan_length != '\0' && *scan_length != ' ')) /* Garbage left */ + if (garbage_left(isarray, scan_length, compat)) { ecpg_raise(lineno, ECPG_UINT_FORMAT, ECPG_SQLSTATE_DATATYPE_MISMATCH, pval); return (false); diff --git a/src/interfaces/ecpg/ecpglib/po/de.po b/src/interfaces/ecpg/ecpglib/po/de.po index 0c9bf1860f..c320d147ca 100644 --- a/src/interfaces/ecpg/ecpglib/po/de.po +++ b/src/interfaces/ecpg/ecpglib/po/de.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the PostgreSQL package. # Peter Eisentraut, 2009 - 2013. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -39,7 +39,7 @@ msgstr "Speicher aufgebraucht auf Zeile %d" #: error.c:49 #, c-format msgid "unsupported type \"%s\" on line %d" -msgstr "nicht unterstützter Typ „%s“ auf Zeile %d" +msgstr "nicht unterstützter Typ »%s« auf Zeile %d" #: error.c:59 #, c-format @@ -54,22 +54,22 @@ msgstr "zu wenige Argumente auf Zeile %d" #: error.c:79 #, c-format msgid "invalid input syntax for type int: \"%s\", on line %d" -msgstr "ungültige Eingabesyntax für Typ int: „%s“, auf Zeile %d" +msgstr "ungültige Eingabesyntax für Typ int: »%s«, auf Zeile %d" #: error.c:89 #, c-format msgid "invalid input syntax for type unsigned int: \"%s\", on line %d" -msgstr "ungültige Eingabesyntax für Typ unsigned int: „%s“, auf Zeile %d" +msgstr "ungültige Eingabesyntax für Typ unsigned int: »%s«, auf Zeile %d" #: error.c:99 #, c-format msgid "invalid input syntax for floating-point type: \"%s\", on line %d" -msgstr "ungültige Eingabesyntax für Gleitkommatyp: „%s“, auf Zeile %d" +msgstr "ungültige Eingabesyntax für Gleitkommatyp: »%s«, auf Zeile %d" #: error.c:110 #, c-format msgid "invalid syntax for type boolean: \"%s\", on line %d" -msgstr "ungültige Syntax für Typ boolean: „%s“, auf Zeile %d" +msgstr "ungültige Syntax für Typ boolean: »%s«, auf Zeile %d" #: error.c:118 #, c-format @@ -106,22 +106,22 @@ msgstr "" #: error.c:178 #, c-format msgid "connection \"%s\" does not exist on line %d" -msgstr "Verbindung „%s“ existiert nicht auf Zeile %d" +msgstr "Verbindung »%s« existiert nicht auf Zeile %d" #: error.c:188 #, c-format msgid "not connected to connection \"%s\" on line %d" -msgstr "nicht mit Verbindung „%s“ verbunden auf Zeile %d" +msgstr "nicht mit Verbindung »%s« verbunden auf Zeile %d" #: error.c:198 #, c-format msgid "invalid statement name \"%s\" on line %d" -msgstr "ungültiger Anweisungsname „%s“ auf Zeile %d" +msgstr "ungültiger Anweisungsname »%s« auf Zeile %d" #: error.c:208 #, c-format msgid "descriptor \"%s\" not found on line %d" -msgstr "Deskriptor „%s“ nicht gefunden auf Zeile %d" +msgstr "Deskriptor »%s« nicht gefunden auf Zeile %d" #: error.c:218 #, c-format @@ -131,7 +131,7 @@ msgstr "Deskriptorindex außerhalb des gültigen Bereichs auf Zeile %d" #: error.c:228 #, c-format msgid "unrecognized descriptor item \"%s\" on line %d" -msgstr "unbekanntes Deskriptorelement „%s“ auf Zeile %d" +msgstr "unbekanntes Deskriptorelement »%s« auf Zeile %d" #: error.c:238 #, c-format @@ -151,7 +151,7 @@ msgstr "Fehler bei der Transaktionsverarbeitung auf Zeile %d" #: error.c:268 #, c-format msgid "could not connect to database \"%s\" on line %d" -msgstr "konnte nicht mit Datenbank „%s“ verbinden auf Zeile %d" +msgstr "konnte nicht mit Datenbank »%s« verbinden auf Zeile %d" #: error.c:278 #, c-format diff --git a/src/interfaces/ecpg/pgtypeslib/numeric.c b/src/interfaces/ecpg/pgtypeslib/numeric.c index d061616787..120794550d 100644 --- a/src/interfaces/ecpg/pgtypeslib/numeric.c +++ b/src/interfaces/ecpg/pgtypeslib/numeric.c @@ -263,8 +263,7 @@ set_var_from_str(char *str, char **ptr, numeric *dest) return -1; } (*ptr) = endptr; - if (exponent > NUMERIC_MAX_PRECISION || - exponent < -NUMERIC_MAX_PRECISION) + if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2)) { errno = PGTYPES_NUM_BAD_NUMERIC; return -1; diff --git a/src/interfaces/ecpg/preproc/ecpg.c b/src/interfaces/ecpg/preproc/ecpg.c index e8e9d1e5e0..ed01ef7f01 100644 --- a/src/interfaces/ecpg/preproc/ecpg.c +++ b/src/interfaces/ecpg/preproc/ecpg.c @@ -54,7 +54,7 @@ help(const char *progname) " \"no_indicator\", \"prepare\", \"questionmarks\"\n")); printf(_(" --regression run in regression testing mode\n")); printf(_(" -t turn on autocommit of transactions\n")); - printf(_(" --version output version information, then exit\n")); + printf(_(" -V, --version output version information, then exit\n")); printf(_(" -?, --help show this help, then exit\n")); printf(_("\nIf no output file is specified, the name is formed by adding .c to the\n" "input file name, after stripping off .pgc if present.\n")); @@ -111,15 +111,11 @@ add_preprocessor_define(char *define) defines->next = pd; } -#define ECPG_GETOPT_LONG_HELP 1 -#define ECPG_GETOPT_LONG_VERSION 2 -#define ECPG_GETOPT_LONG_REGRESSION 3 +#define ECPG_GETOPT_LONG_REGRESSION 1 int main(int argc, char *const argv[]) { static struct option ecpg_options[] = { - {"help", no_argument, NULL, ECPG_GETOPT_LONG_HELP}, - {"version", no_argument, NULL, ECPG_GETOPT_LONG_VERSION}, {"regression", no_argument, NULL, ECPG_GETOPT_LONG_REGRESSION}, {NULL, 0, NULL, 0} }; @@ -144,33 +140,26 @@ main(int argc, char *const argv[]) return (ILLEGAL_OPTION); } + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) + { + help(progname); + exit(0); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + printf("ecpg (PostgreSQL %s) %d.%d.%d\n", PG_VERSION, + MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); + exit(0); + } + } + output_filename = NULL; - while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h?", ecpg_options, NULL)) != -1) + while ((c = getopt_long(argc, argv, "vcio:I:tD:dC:r:h", ecpg_options, NULL)) != -1) { switch (c) { - case ECPG_GETOPT_LONG_VERSION: - printf("ecpg (PostgreSQL %s) %d.%d.%d\n", PG_VERSION, - MAJOR_VERSION, MINOR_VERSION, PATCHLEVEL); - exit(0); - case ECPG_GETOPT_LONG_HELP: - help(progname); - exit(0); - - /* - * -? is an alternative spelling of --help. However it is also - * returned by getopt_long for unknown options. We can - * distinguish both cases by means of the optopt variable - * which is set to 0 if it was really -? and not an unknown - * option character. - */ - case '?': - if (optopt == 0) - { - help(progname); - exit(0); - } - break; case ECPG_GETOPT_LONG_REGRESSION: regression_mode = true; break; diff --git a/src/interfaces/ecpg/preproc/po/de.po b/src/interfaces/ecpg/preproc/po/de.po index 37f537d8b3..440abcdb28 100644 --- a/src/interfaces/ecpg/preproc/po/de.po +++ b/src/interfaces/ecpg/preproc/po/de.po @@ -3,7 +3,7 @@ # This file is distributed under the same license as the PostgreSQL package. # Peter Eisentraut , 2009-2014. # -# Use these quotes: „%s“ +# Use these quotes: »%s« # msgid "" msgstr "" @@ -22,17 +22,17 @@ msgstr "" #: descriptor.c:64 #, c-format msgid "variable \"%s\" must have a numeric type" -msgstr "Variable „%s“ muss einen numerischen Typ haben" +msgstr "Variable »%s« muss einen numerischen Typ haben" #: descriptor.c:124 descriptor.c:146 #, c-format msgid "descriptor \"%s\" does not exist" -msgstr "Deskriptor „%s“ existiert nicht" +msgstr "Deskriptor »%s« existiert nicht" #: descriptor.c:161 descriptor.c:210 #, c-format msgid "descriptor header item \"%d\" does not exist" -msgstr "Deskriptorkopfelement „%d“ existiert nicht" +msgstr "Deskriptorkopfelement »%d« existiert nicht" #: descriptor.c:182 #, c-format @@ -47,12 +47,12 @@ msgstr "key_member ist immer 0" #: descriptor.c:277 #, c-format msgid "descriptor item \"%s\" is not implemented" -msgstr "Deskriptorelement „%s“ ist nicht implementiert" +msgstr "Deskriptorelement »%s« ist nicht implementiert" #: descriptor.c:287 #, c-format msgid "descriptor item \"%s\" cannot be set" -msgstr "Deskriptorelement „%s“ kann nicht gesetzt werden" +msgstr "Deskriptorelement »%s« kann nicht gesetzt werden" #: ecpg.c:35 #, c-format @@ -95,7 +95,7 @@ msgid "" " \"INFORMIX\", \"INFORMIX_SE\"\n" msgstr "" " -C MODUS Kompatibilitätsmodus setzen; MODUS kann sein:\n" -" „INFORMIX“ oder „INFORMIX_SE“\n" +" »INFORMIX« oder »INFORMIX_SE«\n" #: ecpg.c:46 #, c-format @@ -110,7 +110,7 @@ msgstr " -D SYMBOL SYMBOL definieren\n" #: ecpg.c:49 #, c-format msgid " -h parse a header file, this option includes option \"-c\"\n" -msgstr " -h eine Headerdatei parsen, schließt Option „-c“ ein\n" +msgstr " -h eine Headerdatei parsen, schließt Option »-c« ein\n" #: ecpg.c:50 #, c-format @@ -134,7 +134,7 @@ msgid "" " \"no_indicator\", \"prepare\", \"questionmarks\"\n" msgstr "" " -r OPTION Laufzeitverhalten bestimmen; OPTION kann sein:\n" -" „no_indicator“, „prepare“, „questionmarks“\n" +" »no_indicator«, »prepare«, »questionmarks«\n" #: ecpg.c:55 #, c-format @@ -184,12 +184,12 @@ msgstr "%s: konnte Pfad des eigenen Programs nicht finden\n" #: ecpg.c:186 ecpg.c:337 ecpg.c:347 #, c-format msgid "%s: could not open file \"%s\": %s\n" -msgstr "%s: konnte Datei „%s“ nicht öffnen: %s\n" +msgstr "%s: konnte Datei »%s« nicht öffnen: %s\n" #: ecpg.c:225 ecpg.c:238 ecpg.c:254 ecpg.c:279 #, c-format msgid "Try \"%s --help\" for more information.\n" -msgstr "Versuchen Sie „%s --help“ für weitere Informationen.\n" +msgstr "Versuchen Sie »%s --help« für weitere Informationen.\n" #: ecpg.c:249 #, c-format @@ -219,12 +219,12 @@ msgstr "%s: keine Eingabedateien angegeben\n" #: ecpg.c:470 #, c-format msgid "cursor \"%s\" has been declared but not opened" -msgstr "Cursor „%s“ wurde deklariert aber nicht geöffnet" +msgstr "Cursor »%s« wurde deklariert aber nicht geöffnet" #: ecpg.c:483 preproc.y:125 #, c-format msgid "could not remove output file \"%s\"\n" -msgstr "konnte Ausgabedatei „%s“ nicht entfernen\n" +msgstr "konnte Ausgabedatei »%s« nicht entfernen\n" #: pgc.l:421 #, c-format @@ -274,12 +274,12 @@ msgstr "fehlender Bezeichner im Befehl EXEC SQL UNDEF" #: pgc.l:1006 pgc.l:1020 #, c-format msgid "missing matching \"EXEC SQL IFDEF\" / \"EXEC SQL IFNDEF\"" -msgstr "passendes „EXEC SQL IFDEF“ / „EXEC SQL IFNDEF“ fehlt" +msgstr "passendes »EXEC SQL IFDEF« / »EXEC SQL IFNDEF« fehlt" #: pgc.l:1009 pgc.l:1022 pgc.l:1198 #, c-format msgid "missing \"EXEC SQL ENDIF;\"" -msgstr "„EXEC SQL ENDIF;“ fehlt" +msgstr "»EXEC SQL ENDIF;« fehlt" #: pgc.l:1038 pgc.l:1057 #, c-format @@ -319,12 +319,12 @@ msgstr "interner Fehler: unerreichbarer Zustand; bitte an