From 74fc83869e169470e91363546d945002e71e54ab Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas
Date: Thu, 13 Jul 2017 15:47:02 +0300
Subject: Fix race between GetNewTransactionId and
GetOldestActiveTransactionId.
The race condition goes like this:
1. GetNewTransactionId advances nextXid e.g. from 100 to 101
2. GetOldestActiveTransactionId reads the new nextXid, 101
3. GetOldestActiveTransactionId loops through the proc array. There are no
active XIDs there, so it returns 101 as the oldest active XID.
4. GetNewTransactionid stores XID 100 to MyPgXact->xid
So, GetOldestActiveTransactionId returned XID 101, even though 100 only
just started and is surely still running.
This would be hard to hit in practice, and even harder to spot any ill
effect if it happens. GetOldestActiveTransactionId is only used when
creating a checkpoint in a master server, and the race condition can only
happen on an online checkpoint, as there are no backends running during a
shutdown checkpoint. The oldestActiveXid value of an online checkpoint is
only used when starting up a hot standby server, to determine the starting
point where pg_subtrans is initialized from. For the race condition to
happen, there must be no other XIDs in the proc array that would hold back
the oldest-active XID value, which means that the missed XID must be a top
transaction's XID. However, pg_subtrans is not used for top XIDs, so I
believe an off-by-one error is in fact inconsequential. Nevertheless, let's
fix it, as it's clearly wrong and the fix is simple.
This has been wrong ever since hot standby was introduced, so backport to
all supported versions.
Discussion: https://www.postgresql.org/message-id/e7258662-82b6-7a45-56d4-99b337a32bf7@iki.fi
---
src/backend/storage/ipc/procarray.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 6eb7c72ec3..a7e8cf2d43 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2096,20 +2096,21 @@ GetOldestActiveTransactionId(void)
Assert(!RecoveryInProgress());
- LWLockAcquire(ProcArrayLock, LW_SHARED);
-
/*
- * It's okay to read nextXid without acquiring XidGenLock because (1) we
- * assume TransactionIds can be read atomically and (2) we don't care if
- * we get a slightly stale value. It can't be very stale anyway, because
- * the LWLockAcquire above will have done any necessary memory
- * interlocking.
+ * Read nextXid, as the upper bound of what's still active.
+ *
+ * Reading a TransactionId is atomic, but we must grab the lock to make
+ * sure that all XIDs < nextXid are already present in the proc array (or
+ * have already completed), when we spin over it.
*/
+ LWLockAcquire(XidGenLock, LW_SHARED);
oldestRunningXid = ShmemVariableCache->nextXid;
+ LWLockRelease(XidGenLock);
/*
* Spin over procArray collecting all xids and subxids.
*/
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
for (index = 0; index < arrayP->numProcs; index++)
{
int pgprocno = arrayP->pgprocnos[index];
@@ -2131,7 +2132,6 @@ GetOldestActiveTransactionId(void)
* smaller than oldestRunningXid
*/
}
-
LWLockRelease(ProcArrayLock);
return oldestRunningXid;
--
cgit v1.2.3
From a3ca72ae9ac14acb2b1b9cd207ac0c8a01f1439a Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 13 Jul 2017 19:24:44 -0400
Subject: Fix dumping of FUNCTION RTEs that contain non-function-call
expressions.
The grammar will only accept something syntactically similar to a function
call in a function-in-FROM expression. However, there are various ways
to input something that ruleutils.c won't deparse that way, potentially
leading to a view or rule that fails dump/reload. Fix by inserting a
dummy CAST around anything that isn't going to deparse as a function
(which is one of the ways to get something like that in there in the
first place).
In HEAD, also make use of the infrastructure added by this to avoid
emitting unnecessary parentheses in CREATE INDEX deparsing. I did
not change that in back branches, thinking that people might find it
to be unexpected/unnecessary behavioral change.
In HEAD, also fix incorrect logic for when to add extra parens to
partition key expressions. Somebody apparently thought they could
get away with simpler logic than pg_get_indexdef_worker has, but
they were wrong --- a counterexample is PARTITION BY LIST ((a[1])).
Ignoring the prettyprint flag for partition expressions isn't exactly
a nice solution anyway.
This has been broken all along, so back-patch to all supported branches.
Discussion: https://postgr.es/m/10477.1499970459@sss.pgh.pa.us
---
src/backend/utils/adt/ruleutils.c | 77 +++++++++++++++++++++++++++---
src/test/regress/expected/create_table.out | 2 +-
src/test/regress/expected/create_view.out | 26 ++++++++++
src/test/regress/sql/create_view.sql | 12 +++++
4 files changed, 110 insertions(+), 7 deletions(-)
(limited to 'src')
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5a4adbdc52..5cfb916684 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -416,6 +416,9 @@ static void get_rule_expr(Node *node, deparse_context *context,
bool showimplicit);
static void get_rule_expr_toplevel(Node *node, deparse_context *context,
bool showimplicit);
+static void get_rule_expr_funccall(Node *node, deparse_context *context,
+ bool showimplicit);
+static bool looks_like_function(Node *node);
static void get_oper_expr(OpExpr *expr, deparse_context *context);
static void get_func_expr(FuncExpr *expr, deparse_context *context,
bool showimplicit);
@@ -1308,8 +1311,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
if (!colno || colno == keyno + 1)
{
/* Need parens if it's not a bare function call */
- if (indexkey && IsA(indexkey, FuncExpr) &&
- ((FuncExpr *) indexkey)->funcformat == COERCE_EXPLICIT_CALL)
+ if (looks_like_function(indexkey))
appendStringInfoString(&buf, str);
else
appendStringInfo(&buf, "(%s)", str);
@@ -1698,11 +1700,16 @@ pg_get_partkeydef_worker(Oid relid, int prettyFlags,
elog(ERROR, "too few entries in partexprs list");
partkey = (Node *) lfirst(partexpr_item);
partexpr_item = lnext(partexpr_item);
+
/* Deparse */
str = deparse_expression_pretty(partkey, context, false, false,
- 0, 0);
+ prettyFlags, 0);
+ /* Need parens if it's not a bare function call */
+ if (looks_like_function(partkey))
+ appendStringInfoString(&buf, str);
+ else
+ appendStringInfo(&buf, "(%s)", str);
- appendStringInfoString(&buf, str);
keycoltype = exprType(partkey);
keycolcollation = exprCollation(partkey);
}
@@ -8776,6 +8783,64 @@ get_rule_expr_toplevel(Node *node, deparse_context *context,
get_rule_expr(node, context, showimplicit);
}
+/*
+ * get_rule_expr_funccall - Parse back a function-call expression
+ *
+ * Same as get_rule_expr(), except that we guarantee that the output will
+ * look like a function call, or like one of the things the grammar treats as
+ * equivalent to a function call (see the func_expr_windowless production).
+ * This is needed in places where the grammar uses func_expr_windowless and
+ * you can't substitute a parenthesized a_expr. If what we have isn't going
+ * to look like a function call, wrap it in a dummy CAST() expression, which
+ * will satisfy the grammar --- and, indeed, is likely what the user wrote to
+ * produce such a thing.
+ */
+static void
+get_rule_expr_funccall(Node *node, deparse_context *context,
+ bool showimplicit)
+{
+ if (looks_like_function(node))
+ get_rule_expr(node, context, showimplicit);
+ else
+ {
+ StringInfo buf = context->buf;
+
+ appendStringInfoString(buf, "CAST(");
+ /* no point in showing any top-level implicit cast */
+ get_rule_expr(node, context, false);
+ appendStringInfo(buf, " AS %s)",
+ format_type_with_typemod(exprType(node),
+ exprTypmod(node)));
+ }
+}
+
+/*
+ * Helper function to identify node types that satisfy func_expr_windowless.
+ * If in doubt, "false" is always a safe answer.
+ */
+static bool
+looks_like_function(Node *node)
+{
+ if (node == NULL)
+ return false; /* probably shouldn't happen */
+ switch (nodeTag(node))
+ {
+ case T_FuncExpr:
+ /* OK, unless it's going to deparse as a cast */
+ return (((FuncExpr *) node)->funcformat == COERCE_EXPLICIT_CALL);
+ case T_NullIfExpr:
+ case T_CoalesceExpr:
+ case T_MinMaxExpr:
+ case T_SQLValueFunction:
+ case T_XmlExpr:
+ /* these are all accepted by func_expr_common_subexpr */
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
/*
* get_oper_expr - Parse back an OpExpr node
@@ -9749,7 +9814,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
if (list_length(rte->functions) == 1 &&
(rtfunc1->funccolnames == NIL || !rte->funcordinality))
{
- get_rule_expr(rtfunc1->funcexpr, context, true);
+ get_rule_expr_funccall(rtfunc1->funcexpr, context, true);
/* we'll print the coldeflist below, if it has one */
}
else
@@ -9812,7 +9877,7 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
if (funcno > 0)
appendStringInfoString(buf, ", ");
- get_rule_expr(rtfunc->funcexpr, context, true);
+ get_rule_expr_funccall(rtfunc->funcexpr, context, true);
if (rtfunc->funccolnames != NIL)
{
/* Reconstruct the column definition list */
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index b6f794e1c2..0b2f399cb1 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -434,7 +434,7 @@ Partition key: RANGE (a oid_ops, plusone(b), c, d COLLATE "C")
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
a | integer | | |
-Partition key: LIST ((a + 1))
+Partition key: LIST (((a + 1)))
DROP TABLE partitioned, partitioned2;
--
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index c719262720..79f5dba55f 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1622,6 +1622,32 @@ select pg_get_viewdef('tt19v', true);
'foo'::text = ANY ((( SELECT ARRAY['abc'::text, 'def'::text, 'foo'::text] AS "array"))::text[]) AS c2;
(1 row)
+-- check display of assorted RTE_FUNCTION expressions
+create view tt20v as
+select * from
+ coalesce(1,2) as c,
+ collation for ('x'::text) col,
+ current_date as d,
+ localtimestamp(3) as t,
+ cast(1+2 as int4) as i4,
+ cast(1+2 as int8) as i8;
+select pg_get_viewdef('tt20v', true);
+ pg_get_viewdef
+---------------------------------------------
+ SELECT c.c, +
+ col.col, +
+ d.d, +
+ t.t, +
+ i4.i4, +
+ i8.i8 +
+ FROM COALESCE(1, 2) c(c), +
+ pg_collation_for('x'::text) col(col), +
+ CURRENT_DATE d(d), +
+ LOCALTIMESTAMP(3) t(t), +
+ CAST(1 + 2 AS integer) i4(i4), +
+ CAST((1 + 2)::bigint AS bigint) i8(i8);
+(1 row)
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index d6f50d6105..85c2959d3f 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -547,6 +547,18 @@ select 'foo'::text = any(array['abc','def','foo']::text[]) c1,
'foo'::text = any((select array['abc','def','foo']::text[])::text[]) c2;
select pg_get_viewdef('tt19v', true);
+-- check display of assorted RTE_FUNCTION expressions
+
+create view tt20v as
+select * from
+ coalesce(1,2) as c,
+ collation for ('x'::text) col,
+ current_date as d,
+ localtimestamp(3) as t,
+ cast(1+2 as int4) as i4,
+ cast(1+2 as int8) as i8;
+select pg_get_viewdef('tt20v', true);
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
--
cgit v1.2.3
From 8046465c2ecf6841ad80265f84294edd98aefd8b Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas
Date: Fri, 14 Jul 2017 16:02:53 +0300
Subject: Fix pg_basebackup output to stdout on Windows.
When writing a backup to stdout with pg_basebackup on Windows, put stdout
to binary mode. Any CR bytes in the output will otherwise be output
incorrectly as CR+LF.
In the passing, standardize on using "_setmode" instead of "setmode", for
the sake of consistency. They both do the same thing, but according to
MSDN documentation, setmode is deprecated.
Fixes bug #14634, reported by Henry Boehlert. Patch by Haribabu Kommi.
Backpatch to all supported versions.
Discussion: https://www.postgresql.org/message-id/20170428082818.24366.13134@wrigleys.postgresql.org
---
src/bin/pg_basebackup/pg_basebackup.c | 4 ++++
src/bin/pg_dump/pg_backup_archiver.c | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 3ad06995ec..dfb9b5ddcb 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -954,6 +954,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
*/
if (strcmp(basedir, "-") == 0)
{
+#ifdef WIN32
+ _setmode(fileno(stdout), _O_BINARY);
+#endif
+
#ifdef HAVE_LIBZ
if (compresslevel != 0)
{
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index c24a0f07e2..b9d063aa22 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -2346,9 +2346,9 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
(AH->fSpec == NULL || strcmp(AH->fSpec, "") == 0))
{
if (mode == archModeWrite)
- setmode(fileno(stdout), O_BINARY);
+ _setmode(fileno(stdout), O_BINARY);
else
- setmode(fileno(stdin), O_BINARY);
+ _setmode(fileno(stdin), O_BINARY);
}
#endif
--
cgit v1.2.3
From c95275fc202c231e867d2f0a00e8d18621b67f0d Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 14 Jul 2017 12:26:53 -0400
Subject: Fix broken link-command-line ordering for libpgfeutils.
In the frontend Makefiles that pull in libpgfeutils, we'd generally
done it like this:
LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
That method is badly broken, as seen in bug #14742 from Chris Ruprecht.
The -L flag for src/fe_utils ends up being placed after whatever random
-L flags are in LDFLAGS already. That puts us at risk of pulling in
libpgfeutils.a from some previous installation rather than the freshly
built one in src/fe_utils. Also, the lack of an "override" is hazardous
if someone tries to specify some LDFLAGS on the make command line.
The correct way to do it is like this:
override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
so that libpgfeutils, along with libpq, libpgport, and libpgcommon, are
guaranteed to be pulled in from the build tree and not from any referenced
system directory, because their -L flags will appear first.
In some places we'd been even lazier and done it like this:
LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
which is subtly wrong in an additional way: on platforms where we can't
restrict the symbols exported by libpq.so, it allows libpgfeutils to
latch onto libpgport and libpgcommon symbols from libpq.so, rather than
directly from those static libraries as intended. This carries hazards
like those explained in the comments for the libpq_pgport macro.
In addition to fixing the broken libpgfeutils usages, I tried to
standardize on using $(libpq_pgport) like so:
override LDFLAGS := $(libpq_pgport) $(LDFLAGS)
even where libpgfeutils is not in the picture. This makes no difference
right now but will hopefully discourage future mistakes of the same ilk.
And it's more like the way we handle CPPFLAGS in libpq-using Makefiles.
In passing, just for consistency, make pgbench include PTHREAD_LIBS the
same way everyplace else does, ie just after LIBS rather than in some
random place in the command line. This might have practical effect if
there are -L switches in that macro on some platform.
It looks to me like the MSVC build scripts are not affected by this
error, but someone more familiar with them than I might want to double
check.
Back-patch to 9.6 where libpgfeutils was introduced. In 9.6, the hazard
this error creates is that a reinstallation might link to the prior
installation's copy of libpgfeutils.a and thereby fail to absorb a
minor-version bug fix.
Discussion: https://postgr.es/m/20170714125106.9231.13772@wrigleys.postgresql.org
---
src/bin/initdb/Makefile | 2 +-
src/bin/pg_basebackup/Makefile | 8 ++++----
src/bin/pg_ctl/Makefile | 4 ++--
src/bin/pg_dump/Makefile | 8 ++++----
src/bin/pg_rewind/Makefile | 6 ++----
src/bin/pg_upgrade/Makefile | 4 ++--
src/bin/pgbench/Makefile | 5 +++--
src/bin/psql/Makefile | 4 ++--
src/bin/scripts/Makefile | 4 ++--
src/tools/findoidjoins/Makefile | 3 ++-
10 files changed, 24 insertions(+), 24 deletions(-)
(limited to 'src')
diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile
index eaed05043b..ec26652e82 100644
--- a/src/bin/initdb/Makefile
+++ b/src/bin/initdb/Makefile
@@ -19,7 +19,7 @@ include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -DFRONTEND -I$(libpq_srcdir) -I$(top_srcdir)/src/timezone $(CPPFLAGS)
# note: we need libpq only because fe_utils does
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
# use system timezone data?
ifneq (,$(with_system_tzdata))
diff --git a/src/bin/pg_basebackup/Makefile b/src/bin/pg_basebackup/Makefile
index f0c3be83f3..b707af9d26 100644
--- a/src/bin/pg_basebackup/Makefile
+++ b/src/bin/pg_basebackup/Makefile
@@ -19,20 +19,20 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
OBJS=receivelog.o streamutil.o walmethods.o $(WIN32RES)
all: pg_basebackup pg_receivewal pg_recvlogical
pg_basebackup: pg_basebackup.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) pg_basebackup.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) pg_basebackup.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_receivewal: pg_receivewal.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) pg_receivewal.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) pg_receivewal.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_recvlogical: pg_recvlogical.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) pg_recvlogical.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) pg_recvlogical.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
install: all installdirs
$(INSTALL_PROGRAM) pg_basebackup$(X) '$(DESTDIR)$(bindir)/pg_basebackup$(X)'
diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile
index 03ae8dea76..e734c952a2 100644
--- a/src/bin/pg_ctl/Makefile
+++ b/src/bin/pg_ctl/Makefile
@@ -20,8 +20,8 @@ include $(top_builddir)/src/Makefile.global
# but let's not pull that in on platforms where we don't need it.
ifeq ($(PORTNAME), win32)
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
+override LDFLAGS := $(libpq_pgport) $(LDFLAGS)
SUBMAKE_LIBPQ := submake-libpq
-LIBPQ_PGPORT := $(libpq_pgport)
endif
OBJS= pg_ctl.o $(WIN32RES)
@@ -29,7 +29,7 @@ OBJS= pg_ctl.o $(WIN32RES)
all: pg_ctl
pg_ctl: $(OBJS) | submake-libpgport $(SUBMAKE_LIBPQ)
- $(CC) $(CFLAGS) $(OBJS) $(LIBPQ_PGPORT) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
install: all installdirs
$(INSTALL_PROGRAM) pg_ctl$(X) '$(DESTDIR)$(bindir)/pg_ctl$(X)'
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
index b58636eabf..3700884720 100644
--- a/src/bin/pg_dump/Makefile
+++ b/src/bin/pg_dump/Makefile
@@ -17,7 +17,7 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
pg_backup_null.o pg_backup_tar.o pg_backup_directory.o \
@@ -26,13 +26,13 @@ OBJS= pg_backup_archiver.o pg_backup_db.o pg_backup_custom.o \
all: pg_dump pg_restore pg_dumpall
pg_dump: pg_dump.o common.o pg_dump_sort.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) pg_dump.o common.o pg_dump_sort.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_restore: pg_restore.o $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) pg_restore.o $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) pg_restore.o $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
pg_dumpall: pg_dumpall.o dumputils.o | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(WIN32RES) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) pg_dumpall.o dumputils.o $(WIN32RES) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
install: all installdirs
$(INSTALL_PROGRAM) pg_dump$(X) '$(DESTDIR)$(bindir)'/pg_dump$(X)
diff --git a/src/bin/pg_rewind/Makefile b/src/bin/pg_rewind/Makefile
index 828ae01ef1..e64ad76509 100644
--- a/src/bin/pg_rewind/Makefile
+++ b/src/bin/pg_rewind/Makefile
@@ -15,10 +15,8 @@ subdir = src/bin/pg_rewind
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
-PG_CPPFLAGS = -I$(libpq_srcdir)
-PG_LIBS = $(libpq_pgport)
-
override CPPFLAGS := -I$(libpq_srcdir) -DFRONTEND $(CPPFLAGS)
+override LDFLAGS := $(libpq_pgport) $(LDFLAGS)
OBJS = pg_rewind.o parsexlog.o xlogreader.o datapagemap.o timeline.o \
fetch.o file_ops.o copy_fetch.o libpq_fetch.o filemap.o logging.o \
@@ -29,7 +27,7 @@ EXTRA_CLEAN = xlogreader.c
all: pg_rewind
pg_rewind: $(OBJS) | submake-libpq submake-libpgport
- $(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
xlogreader.c: % : $(top_srcdir)/src/backend/access/transam/%
rm -f $@ && $(LN_S) $< .
diff --git a/src/bin/pg_upgrade/Makefile b/src/bin/pg_upgrade/Makefile
index d252e08d37..1d6ee702c6 100644
--- a/src/bin/pg_upgrade/Makefile
+++ b/src/bin/pg_upgrade/Makefile
@@ -12,13 +12,13 @@ OBJS = check.o controldata.o dump.o exec.o file.o function.o info.o \
tablespace.o util.o version.o $(WIN32RES)
override CPPFLAGS := -DDLSUFFIX=\"$(DLSUFFIX)\" -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
all: pg_upgrade
pg_upgrade: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
install: all installdirs
$(INSTALL_PROGRAM) pg_upgrade$(X) '$(DESTDIR)$(bindir)/pg_upgrade$(X)'
diff --git a/src/bin/pgbench/Makefile b/src/bin/pgbench/Makefile
index 1503d00e12..8a8e516896 100644
--- a/src/bin/pgbench/Makefile
+++ b/src/bin/pgbench/Makefile
@@ -10,17 +10,18 @@ include $(top_builddir)/src/Makefile.global
OBJS = pgbench.o exprparse.o $(WIN32RES)
override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
ifneq ($(PORTNAME), win32)
override CFLAGS += $(PTHREAD_CFLAGS)
endif
+LIBS += $(PTHREAD_LIBS)
all: pgbench
pgbench: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) $^ $(libpq_pgport) $(PTHREAD_LIBS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
# exprscan is compiled as part of exprparse
exprparse.o: exprscan.c
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
index ab2cfa6353..cabfe15f97 100644
--- a/src/bin/psql/Makefile
+++ b/src/bin/psql/Makefile
@@ -19,7 +19,7 @@ include $(top_builddir)/src/Makefile.global
REFDOCDIR= $(top_srcdir)/doc/src/sgml/ref
override CPPFLAGS := -I. -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
OBJS= command.o common.o conditional.o copy.o crosstabview.o \
describe.o help.o input.o large_obj.o mainloop.o \
@@ -31,7 +31,7 @@ OBJS= command.o common.o conditional.o copy.o crosstabview.o \
all: psql
psql: $(OBJS) | submake-libpq submake-libpgport submake-libpgfeutils
- $(CC) $(CFLAGS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
help.o: sql_help.h
diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile
index 45ac492cfd..a9c24a9f83 100644
--- a/src/bin/scripts/Makefile
+++ b/src/bin/scripts/Makefile
@@ -19,12 +19,12 @@ include $(top_builddir)/src/Makefile.global
PROGRAMS = createdb createuser dropdb dropuser clusterdb vacuumdb reindexdb pg_isready
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
-LDFLAGS += -L$(top_builddir)/src/fe_utils -lpgfeutils -lpq
+override LDFLAGS := -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport) $(LDFLAGS)
all: $(PROGRAMS)
%: %.o $(WIN32RES)
- $(CC) $(CFLAGS) $^ $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
createdb: createdb.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
createuser: createuser.o common.o | submake-libpq submake-libpgport submake-libpgfeutils
diff --git a/src/tools/findoidjoins/Makefile b/src/tools/findoidjoins/Makefile
index e37b027dbd..5410d85ec2 100644
--- a/src/tools/findoidjoins/Makefile
+++ b/src/tools/findoidjoins/Makefile
@@ -13,13 +13,14 @@ top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
+override LDFLAGS := $(libpq_pgport) $(LDFLAGS)
OBJS= findoidjoins.o
all: findoidjoins
findoidjoins: findoidjoins.o | submake-libpq submake-libpgport
- $(CC) $(CFLAGS) findoidjoins.o $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+ $(CC) $(CFLAGS) findoidjoins.o $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
clean distclean maintainer-clean:
rm -f findoidjoins$(X) $(OBJS)
--
cgit v1.2.3
From decb08ebdf07f2fea4b6bb43380366ef5defbafb Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 14 Jul 2017 15:25:43 -0400
Subject: Code review for NextValueExpr expression node type.
Add missing infrastructure for this node type, notably in ruleutils.c where
its lack could demonstrably cause EXPLAIN to fail. Add outfuncs/readfuncs
support. (outfuncs support is useful today for debugging purposes. The
readfuncs support may never be needed, since at present it would only
matter for parallel query and NextValueExpr should never appear in a
parallelizable query; but it seems like a bad idea to have a primnode type
that isn't fully supported here.) Teach planner infrastructure that
NextValueExpr is a volatile, parallel-unsafe, non-leaky expression node
with cost cpu_operator_cost. Given its limited scope of usage, there
*might* be no live bug today from the lack of that knowledge, but it's
certainly going to bite us on the rear someday. Teach pg_stat_statements
about the new node type, too.
While at it, also teach cost_qual_eval() that MinMaxExpr, SQLValueFunction,
XmlExpr, and CoerceToDomain should be charged as cpu_operator_cost.
Failing to do this for SQLValueFunction was an oversight in my commit
0bb51aa96. The others are longer-standing oversights, but no time like the
present to fix them. (In principle, CoerceToDomain could have cost much
higher than this, but it doesn't presently seem worth trying to examine the
domain's constraints here.)
Modify execExprInterp.c to execute NextValueExpr as an out-of-line
function; it seems quite unlikely to me that it's worth insisting that
it be inlined in all expression eval methods. Besides, providing the
out-of-line function doesn't stop anyone from inlining if they want to.
Adjust some places where NextValueExpr support had been inserted with the
aid of a dartboard rather than keeping it in the same order as elsewhere.
Discussion: https://postgr.es/m/23862.1499981661@sss.pgh.pa.us
---
contrib/pg_stat_statements/pg_stat_statements.c | 8 +++++
src/backend/catalog/dependency.c | 14 ++++----
src/backend/executor/execExprInterp.c | 46 +++++++++++++++++--------
src/backend/nodes/nodeFuncs.c | 16 ++++-----
src/backend/nodes/outfuncs.c | 12 +++++++
src/backend/nodes/readfuncs.c | 16 +++++++++
src/backend/optimizer/path/costsize.c | 9 +++++
src/backend/optimizer/util/clauses.c | 23 ++++++++++++-
src/backend/utils/adt/ruleutils.c | 17 +++++++++
src/include/executor/execExpr.h | 3 +-
src/include/nodes/nodes.h | 2 +-
src/include/nodes/primnodes.h | 28 +++++++--------
12 files changed, 147 insertions(+), 47 deletions(-)
(limited to 'src')
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index b9d4a93690..fa409d72b7 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -2763,6 +2763,14 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
APP_JUMB(ce->cursor_param);
}
break;
+ case T_NextValueExpr:
+ {
+ NextValueExpr *nve = (NextValueExpr *) node;
+
+ APP_JUMB(nve->seqid);
+ APP_JUMB(nve->typeId);
+ }
+ break;
case T_InferenceElem:
{
InferenceElem *ie = (InferenceElem *) node;
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 1a7645d341..6fffc290fa 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1791,6 +1791,13 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_TYPE, cd->resulttype, 0,
context->addrs);
}
+ else if (IsA(node, NextValueExpr))
+ {
+ NextValueExpr *nve = (NextValueExpr *) node;
+
+ add_object_address(OCLASS_CLASS, nve->seqid, 0,
+ context->addrs);
+ }
else if (IsA(node, OnConflictExpr))
{
OnConflictExpr *onconflict = (OnConflictExpr *) node;
@@ -1942,13 +1949,6 @@ find_expr_references_walker(Node *node,
context->addrs);
/* fall through to examine arguments */
}
- else if (IsA(node, NextValueExpr))
- {
- NextValueExpr *nve = (NextValueExpr *) node;
-
- add_object_address(OCLASS_CLASS, nve->seqid, 0,
- context->addrs);
- }
return expression_tree_walker(node, find_expr_references_walker,
(void *) context);
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index c227d9bdd9..f2a52f6213 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -1232,21 +1232,11 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
EEO_CASE(EEOP_NEXTVALUEEXPR)
{
- switch (op->d.nextvalueexpr.seqtypid)
- {
- case INT2OID:
- *op->resvalue = Int16GetDatum((int16) nextval_internal(op->d.nextvalueexpr.seqid, false));
- break;
- case INT4OID:
- *op->resvalue = Int32GetDatum((int32) nextval_internal(op->d.nextvalueexpr.seqid, false));
- break;
- case INT8OID:
- *op->resvalue = Int64GetDatum((int64) nextval_internal(op->d.nextvalueexpr.seqid, false));
- break;
- default:
- elog(ERROR, "unsupported sequence type %u", op->d.nextvalueexpr.seqtypid);
- }
- *op->resnull = false;
+ /*
+ * Doesn't seem worthwhile to have an inline implementation
+ * efficiency-wise.
+ */
+ ExecEvalNextValueExpr(state, op);
EEO_NEXT();
}
@@ -1989,6 +1979,32 @@ ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op)
errmsg("WHERE CURRENT OF is not supported for this table type")));
}
+/*
+ * Evaluate NextValueExpr.
+ */
+void
+ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op)
+{
+ int64 newval = nextval_internal(op->d.nextvalueexpr.seqid, false);
+
+ switch (op->d.nextvalueexpr.seqtypid)
+ {
+ case INT2OID:
+ *op->resvalue = Int16GetDatum((int16) newval);
+ break;
+ case INT4OID:
+ *op->resvalue = Int32GetDatum((int32) newval);
+ break;
+ case INT8OID:
+ *op->resvalue = Int64GetDatum((int64) newval);
+ break;
+ default:
+ elog(ERROR, "unsupported sequence type %u",
+ op->d.nextvalueexpr.seqtypid);
+ }
+ *op->resnull = false;
+}
+
/*
* Evaluate NullTest / IS NULL for rows.
*/
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index 97ba25fc72..e3eb0c5788 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -1642,10 +1642,10 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
* for themselves, in case additional checks should be made, or because they
* have special rules about which parts of the tree need to be visited.
*
- * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, and CoerceToDomain
- * nodes, because they do not contain SQL function OIDs. However, they can
- * invoke SQL-visible functions, so callers should take thought about how to
- * treat them.
+ * Note: we ignore MinMaxExpr, SQLValueFunction, XmlExpr, CoerceToDomain,
+ * and NextValueExpr nodes, because they do not contain SQL function OIDs.
+ * However, they can invoke SQL-visible functions, so callers should take
+ * thought about how to treat them.
*/
bool
check_functions_in_node(Node *node, check_function_callback checker,
@@ -1865,12 +1865,12 @@ expression_tree_walker(Node *node,
case T_Var:
case T_Const:
case T_Param:
- case T_CoerceToDomainValue:
case T_CaseTestExpr:
+ case T_SQLValueFunction:
+ case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
case T_NextValueExpr:
- case T_SQLValueFunction:
case T_RangeTblRef:
case T_SortGroupClause:
/* primitive node types with no expression subnodes */
@@ -2461,12 +2461,12 @@ expression_tree_mutator(Node *node,
}
break;
case T_Param:
- case T_CoerceToDomainValue:
case T_CaseTestExpr:
+ case T_SQLValueFunction:
+ case T_CoerceToDomainValue:
case T_SetToDefault:
case T_CurrentOfExpr:
case T_NextValueExpr:
- case T_SQLValueFunction:
case T_RangeTblRef:
case T_SortGroupClause:
return (Node *) copyObject(node);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b0abe9ec10..21e39a0b81 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1610,6 +1610,15 @@ _outCurrentOfExpr(StringInfo str, const CurrentOfExpr *node)
WRITE_INT_FIELD(cursor_param);
}
+static void
+_outNextValueExpr(StringInfo str, const NextValueExpr *node)
+{
+ WRITE_NODE_TYPE("NEXTVALUEEXPR");
+
+ WRITE_OID_FIELD(seqid);
+ WRITE_OID_FIELD(typeId);
+}
+
static void
_outInferenceElem(StringInfo str, const InferenceElem *node)
{
@@ -3872,6 +3881,9 @@ outNode(StringInfo str, const void *obj)
case T_CurrentOfExpr:
_outCurrentOfExpr(str, obj);
break;
+ case T_NextValueExpr:
+ _outNextValueExpr(str, obj);
+ break;
case T_InferenceElem:
_outInferenceElem(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 1380703cbc..8ab09d74d6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -1202,6 +1202,20 @@ _readCurrentOfExpr(void)
READ_DONE();
}
+/*
+ * _readNextValueExpr
+ */
+static NextValueExpr *
+_readNextValueExpr(void)
+{
+ READ_LOCALS(NextValueExpr);
+
+ READ_OID_FIELD(seqid);
+ READ_OID_FIELD(typeId);
+
+ READ_DONE();
+}
+
/*
* _readInferenceElem
*/
@@ -2517,6 +2531,8 @@ parseNodeString(void)
return_value = _readSetToDefault();
else if (MATCH("CURRENTOFEXPR", 13))
return_value = _readCurrentOfExpr();
+ else if (MATCH("NEXTVALUEEXPR", 13))
+ return_value = _readNextValueExpr();
else if (MATCH("INFERENCEELEM", 13))
return_value = _readInferenceElem();
else if (MATCH("TARGETENTRY", 11))
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index eb653cf3be..b35acb7bdc 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -3627,6 +3627,15 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
cpu_operator_cost;
}
}
+ else if (IsA(node, MinMaxExpr) ||
+ IsA(node, SQLValueFunction) ||
+ IsA(node, XmlExpr) ||
+ IsA(node, CoerceToDomain) ||
+ IsA(node, NextValueExpr))
+ {
+ /* Treat all these as having cost 1 */
+ context->total.per_tuple += cpu_operator_cost;
+ }
else if (IsA(node, CurrentOfExpr))
{
/* Report high cost to prevent selection of anything but TID scan */
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8961ed88a8..8b4425dcf9 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -902,6 +902,12 @@ contain_mutable_functions_walker(Node *node, void *context)
return true;
}
+ if (IsA(node, NextValueExpr))
+ {
+ /* NextValueExpr is volatile */
+ return true;
+ }
+
/*
* It should be safe to treat MinMaxExpr as immutable, because it will
* depend on a non-cross-type btree comparison function, and those should
@@ -969,6 +975,12 @@ contain_volatile_functions_walker(Node *node, void *context)
context))
return true;
+ if (IsA(node, NextValueExpr))
+ {
+ /* NextValueExpr is volatile */
+ return true;
+ }
+
/*
* See notes in contain_mutable_functions_walker about why we treat
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
@@ -1019,6 +1031,8 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
* See notes in contain_mutable_functions_walker about why we treat
* MinMaxExpr, XmlExpr, and CoerceToDomain as immutable, while
* SQLValueFunction is stable. Hence, none of them are of interest here.
+ * Also, since we're intentionally ignoring nextval(), presumably we
+ * should ignore NextValueExpr.
*/
/* Recurse to check arguments */
@@ -1146,7 +1160,7 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
* contain a parallel-unsafe function; but useful constraints probably
* never would have such, and assuming they do would cripple use of
* parallel query in the presence of domain types.) SQLValueFunction
- * should be safe in all cases.
+ * should be safe in all cases. NextValueExpr is parallel-unsafe.
*/
if (IsA(node, CoerceToDomain))
{
@@ -1154,6 +1168,12 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
return true;
}
+ if (IsA(node, NextValueExpr))
+ {
+ if (max_parallel_hazard_test(PROPARALLEL_UNSAFE, context))
+ return true;
+ }
+
/*
* As a notational convenience for callers, look through RestrictInfo.
*/
@@ -1495,6 +1515,7 @@ contain_leaked_vars_walker(Node *node, void *context)
case T_SQLValueFunction:
case T_NullTest:
case T_BooleanTest:
+ case T_NextValueExpr:
case T_List:
/*
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5cfb916684..d2fb20d564 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -7283,6 +7283,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_MinMaxExpr:
case T_SQLValueFunction:
case T_XmlExpr:
+ case T_NextValueExpr:
case T_NullIfExpr:
case T_Aggref:
case T_WindowFunc:
@@ -8612,6 +8613,22 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
+ case T_NextValueExpr:
+ {
+ NextValueExpr *nvexpr = (NextValueExpr *) node;
+
+ /*
+ * This isn't exactly nextval(), but that seems close enough
+ * for EXPLAIN's purposes.
+ */
+ appendStringInfoString(buf, "nextval(");
+ simple_quote_literal(buf,
+ generate_relation_name(nvexpr->seqid,
+ NIL));
+ appendStringInfoChar(buf, ')');
+ }
+ break;
+
case T_InferenceElem:
{
InferenceElem *iexpr = (InferenceElem *) node;
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index 7a65339f01..8ee0496e01 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -362,7 +362,7 @@ typedef struct ExprEvalStep
SQLValueFunction *svf;
} sqlvaluefunction;
- /* for EEOP_NEXTVALUEXPR */
+ /* for EEOP_NEXTVALUEEXPR */
struct
{
Oid seqid;
@@ -615,6 +615,7 @@ extern void ExecEvalParamExtern(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalSQLValueFunction(ExprState *state, ExprEvalStep *op);
extern void ExecEvalCurrentOfExpr(ExprState *state, ExprEvalStep *op);
+extern void ExecEvalNextValueExpr(ExprState *state, ExprEvalStep *op);
extern void ExecEvalRowNull(ExprState *state, ExprEvalStep *op,
ExprContext *econtext);
extern void ExecEvalRowNotNull(ExprState *state, ExprEvalStep *op,
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 01527399b8..27bd4f3363 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -183,6 +183,7 @@ typedef enum NodeTag
T_CoerceToDomainValue,
T_SetToDefault,
T_CurrentOfExpr,
+ T_NextValueExpr,
T_InferenceElem,
T_TargetEntry,
T_RangeTblRef,
@@ -190,7 +191,6 @@ typedef enum NodeTag
T_FromExpr,
T_OnConflictExpr,
T_IntoClause,
- T_NextValueExpr,
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 38015ed540..8c536a8d38 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1279,6 +1279,20 @@ typedef struct CurrentOfExpr
int cursor_param; /* refcursor parameter number, or 0 */
} CurrentOfExpr;
+/*
+ * NextValueExpr - get next value from sequence
+ *
+ * This has the same effect as calling the nextval() function, but it does not
+ * check permissions on the sequence. This is used for identity columns,
+ * where the sequence is an implicit dependency without its own permissions.
+ */
+typedef struct NextValueExpr
+{
+ Expr xpr;
+ Oid seqid;
+ Oid typeId;
+} NextValueExpr;
+
/*
* InferenceElem - an element of a unique index inference specification
*
@@ -1294,20 +1308,6 @@ typedef struct InferenceElem
Oid inferopclass; /* OID of att opclass, or InvalidOid */
} InferenceElem;
-/*
- * NextValueExpr - get next value from sequence
- *
- * This has the same effect as calling the nextval() function, but it does not
- * check permissions on the sequence. This is used for identity columns,
- * where the sequence is an implicit dependency without its own permissions.
- */
-typedef struct NextValueExpr
-{
- Expr xpr;
- Oid seqid;
- Oid typeId;
-} NextValueExpr;
-
/*--------------------
* TargetEntry -
* a target entry (used in query target lists)
--
cgit v1.2.3
From 837255cc81fb59b12f5a70ac2a8a9850bccf13e0 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Fri, 14 Jul 2017 19:20:21 -0400
Subject: pg_upgrade i18n: Fix "%s server/cluster" wording
The original wording was impossible to translate correctly.
Discussion: https://postgr.es/m/20170523002827.lzc2jkzh2gubclqb@alvherre.pgsql
---
src/bin/pg_upgrade/check.c | 16 ++++++++++++----
src/bin/pg_upgrade/controldata.c | 9 ++++++---
src/bin/pg_upgrade/info.c | 6 +++++-
src/bin/pg_upgrade/option.c | 6 ++++--
src/bin/pg_upgrade/pg_upgrade.h | 2 --
src/bin/pg_upgrade/server.c | 19 ++++++++++++++-----
6 files changed, 41 insertions(+), 17 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 120c9ae265..3d0fb96187 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -770,8 +770,12 @@ check_for_prepared_transactions(ClusterInfo *cluster)
"FROM pg_catalog.pg_prepared_xacts");
if (PQntuples(res) != 0)
- pg_fatal("The %s cluster contains prepared transactions\n",
- CLUSTER_NAME(cluster));
+ {
+ if (cluster == &old_cluster)
+ pg_fatal("The source cluster contains prepared transactions\n");
+ else
+ pg_fatal("The target cluster contains prepared transactions\n");
+ }
PQclear(res);
@@ -1082,8 +1086,12 @@ check_for_pg_role_prefix(ClusterInfo *cluster)
"WHERE rolname ~ '^pg_'");
if (PQntuples(res) != 0)
- pg_fatal("The %s cluster contains roles starting with 'pg_'\n",
- CLUSTER_NAME(cluster));
+ {
+ if (cluster == &old_cluster)
+ pg_fatal("The source cluster contains roles starting with 'pg_'\n");
+ else
+ pg_fatal("The target cluster contains roles starting with 'pg_'\n");
+ }
PQclear(res);
diff --git a/src/bin/pg_upgrade/controldata.c b/src/bin/pg_upgrade/controldata.c
index 3abef16c81..ca3db1a2f6 100644
--- a/src/bin/pg_upgrade/controldata.c
+++ b/src/bin/pg_upgrade/controldata.c
@@ -474,9 +474,12 @@ get_control_data(ClusterInfo *cluster, bool live_check)
cluster->controldata.ctrl_ver >= LARGE_OBJECT_SIZE_PG_CONTROL_VER) ||
!got_date_is_int || !got_data_checksum_version)
{
- pg_log(PG_REPORT,
- "The %s cluster lacks some required control information:\n",
- CLUSTER_NAME(cluster));
+ if (cluster == &old_cluster)
+ pg_log(PG_REPORT,
+ "The source cluster lacks some required control information:\n");
+ else
+ pg_log(PG_REPORT,
+ "The target cluster lacks some required control information:\n");
if (!got_xid)
pg_log(PG_REPORT, " checkpoint next XID\n");
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index 6500302c3d..f7c278b306 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -320,7 +320,11 @@ get_db_and_rel_infos(ClusterInfo *cluster)
for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
get_rel_infos(cluster, &cluster->dbarr.dbs[dbnum]);
- pg_log(PG_VERBOSE, "\n%s databases:\n", CLUSTER_NAME(cluster));
+ if (cluster == &old_cluster)
+ pg_log(PG_VERBOSE, "\nsource databases:\n");
+ else
+ pg_log(PG_VERBOSE, "\ntarget databases:\n");
+
if (log_opts.verbose)
print_db_infos(&cluster->dbarr);
}
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index cb77665cda..bbe364741c 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -405,8 +405,10 @@ adjust_data_dir(ClusterInfo *cluster)
/* Must be a configuration directory, so find the real data directory. */
- prep_status("Finding the real data directory for the %s cluster",
- CLUSTER_NAME(cluster));
+ if (cluster == &old_cluster)
+ prep_status("Finding the real data directory for the source cluster");
+ else
+ prep_status("Finding the real data directory for the target cluster");
/*
* We don't have a data directory yet, so we can't check the PG version,
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index 13f7ebfe5a..dae068ed83 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -94,8 +94,6 @@ extern char *output_files[];
#define ECHO_BLANK "."
#endif
-#define CLUSTER_NAME(cluster) ((cluster) == &old_cluster ? "old" : \
- (cluster) == &new_cluster ? "new" : "none")
/* OID system catalog preservation added during PG 9.0 development */
#define TABLE_SPACE_SUBDIRS_CAT_VER 201001111
diff --git a/src/bin/pg_upgrade/server.c b/src/bin/pg_upgrade/server.c
index 23ba6a2e11..58e3593896 100644
--- a/src/bin/pg_upgrade/server.c
+++ b/src/bin/pg_upgrade/server.c
@@ -285,9 +285,14 @@ start_postmaster(ClusterInfo *cluster, bool throw_error)
PQerrorMessage(conn));
if (conn)
PQfinish(conn);
- pg_fatal("could not connect to %s postmaster started with the command:\n"
- "%s\n",
- CLUSTER_NAME(cluster), cmd);
+ if (cluster == &old_cluster)
+ pg_fatal("could not connect to source postmaster started with the command:\n"
+ "%s\n",
+ cmd);
+ else
+ pg_fatal("could not connect to target postmaster started with the command:\n"
+ "%s\n",
+ cmd);
}
PQfinish(conn);
@@ -297,8 +302,12 @@ start_postmaster(ClusterInfo *cluster, bool throw_error)
* running.
*/
if (!pg_ctl_return)
- pg_fatal("pg_ctl failed to start the %s server, or connection failed\n",
- CLUSTER_NAME(cluster));
+ {
+ if (cluster == &old_cluster)
+ pg_fatal("pg_ctl failed to start the source server, or connection failed\n");
+ else
+ pg_fatal("pg_ctl failed to start the target server, or connection failed\n");
+ }
return true;
}
--
cgit v1.2.3
From e9b64824a067f8180e2553127467d7522516122c Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sat, 15 Jul 2017 14:03:32 -0400
Subject: Improve comments for execExpr.c's isAssignmentIndirectionExpr().
I got confused about why this function doesn't need to recursively
search the expression tree for a CaseTestExpr node. After figuring
that out, add a comment to save the next person some time.
---
src/backend/executor/execExpr.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index a298b92af8..d1c2bbbd44 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2443,14 +2443,14 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
* refassgnexpr is itself a FieldStore or ArrayRef that needs to
* obtain and modify the previous value of the array element or slice
* being replaced. If so, we have to extract that value from the
- * array and pass it down via the CaseTextExpr mechanism. It's safe
+ * array and pass it down via the CaseTestExpr mechanism. It's safe
* to reuse the CASE mechanism because there cannot be a CASE between
* here and where the value would be needed, and an array assignment
* can't be within a CASE either. (So saving and restoring
* innermost_caseval is just paranoia, but let's do it anyway.)
*
* Since fetching the old element might be a nontrivial expense, do it
- * only if the argument appears to actually need it.
+ * only if the argument actually needs it.
*/
if (isAssignmentIndirectionExpr(aref->refassgnexpr))
{
@@ -2506,10 +2506,16 @@ ExecInitArrayRef(ExprEvalStep *scratch, ArrayRef *aref, PlanState *parent,
/*
* Helper for preparing ArrayRef expressions for evaluation: is expr a nested
- * FieldStore or ArrayRef that might need the old element value passed down?
+ * FieldStore or ArrayRef that needs the old element value passed down?
*
* (We could use this in FieldStore too, but in that case passing the old
* value is so cheap there's no need.)
+ *
+ * Note: it might seem that this needs to recurse, but it does not; the
+ * CaseTestExpr, if any, will be directly the arg or refexpr of the top-level
+ * node. Nested-assignment situations give rise to expression trees in which
+ * each level of assignment has its own CaseTestExpr, and the recursive
+ * structure appears within the newvals or refassgnexpr field.
*/
static bool
isAssignmentIndirectionExpr(Expr *expr)
--
cgit v1.2.3
From de2af6e001a3d6aeb2a10a802e73af8c7d1d3405 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sat, 15 Jul 2017 16:57:43 -0400
Subject: Improve comments for execExpr.c's handling of FieldStore
subexpressions.
Given this code's general eagerness to use subexpressions' output variables
as temporary workspace, it's not exactly clear that it is safe for
FieldStore to tell a newval subexpression that it can write into the same
variable that is being supplied as a potential input. Document the chain
of assumptions needed for that to be safe.
---
src/backend/executor/execExpr.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
(limited to 'src')
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index d1c2bbbd44..5267a011bb 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1116,6 +1116,18 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
* field assignment can't be within a CASE either. (So
* saving and restoring innermost_caseval is just
* paranoia, but let's do it anyway.)
+ *
+ * Another non-obvious point is that it's safe to use the
+ * field's values[]/nulls[] entries as both the caseval
+ * source and the result address for this subexpression.
+ * That's okay only because (1) both FieldStore and
+ * ArrayRef evaluate their arg or refexpr inputs first,
+ * and (2) any such CaseTestExpr is directly the arg or
+ * refexpr input. So any read of the caseval will occur
+ * before there's a chance to overwrite it. Also, if
+ * multiple entries in the newvals/fieldnums lists target
+ * the same field, they'll effectively be applied
+ * left-to-right which is what we want.
*/
save_innermost_caseval = state->innermost_caseval;
save_innermost_casenull = state->innermost_casenull;
--
cgit v1.2.3
From fd2487e49f406471c11fc337b3e06dcb8579c809 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan
Date: Sun, 16 Jul 2017 11:24:29 -0400
Subject: Fix vcregress.pl PROVE_FLAGS bug in commit 93b7d9731f
This change didn't adjust the publicly visible taptest function, causing
buildfarm failures on bowerbird.
Backpatch to 9.4 like previous change.
---
src/tools/msvc/vcregress.pl | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
index eeba30ec8b..2ee9e48d3a 100644
--- a/src/tools/msvc/vcregress.pl
+++ b/src/tools/msvc/vcregress.pl
@@ -227,11 +227,20 @@ sub bincheck
sub taptest
{
my $dir = shift;
+ my @args;
+
+ if ($dir =~ /^PROVE_FLAGS=/)
+ {
+ push(@args, $dir);
+ $dir = shift;
+ }
die "no tests found!" unless -d "$topdir/$dir/t";
+ push(@args,"$topdir/$dir);
+
InstallTemp();
- my $status = tap_check("$topdir/$dir");
+ my $status = tap_check(@args);
exit $status if $status;
}
--
cgit v1.2.3
From deb0129a222ec6b189d5d198cf77012591f300d8 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan
Date: Sun, 16 Jul 2017 12:00:23 -0400
Subject: fix typo
---
src/tools/msvc/vcregress.pl | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/tools/msvc/vcregress.pl b/src/tools/msvc/vcregress.pl
index 2ee9e48d3a..5ccd5b36e1 100644
--- a/src/tools/msvc/vcregress.pl
+++ b/src/tools/msvc/vcregress.pl
@@ -237,7 +237,7 @@ sub taptest
die "no tests found!" unless -d "$topdir/$dir/t";
- push(@args,"$topdir/$dir);
+ push(@args,"$topdir/$dir");
InstallTemp();
my $status = tap_check(@args);
--
cgit v1.2.3
From 2f7f45a64badec18ce75e44ca35c078f08e2651e Mon Sep 17 00:00:00 2001
From: Noah Misch
Date: Sun, 16 Jul 2017 23:13:58 -0700
Subject: MSVC: Don't link libpgcommon into pgcrypto.
Doing so was useful in 273c458a2b3a0fb73968020ea5e9e35eb6928967 but
became obsolete when 818fd4a67d610991757b610755e3065fb99d80a5 caused
postgres.exe to provide the relevant symbols. No other loadable module
links to libpgcommon directly.
---
src/tools/msvc/Mkvcbuild.pm | 1 -
1 file changed, 1 deletion(-)
(limited to 'src')
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 621238417d..55a431715e 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -451,7 +451,6 @@ sub mkvcbuild
'imath.c');
}
$pgcrypto->AddReference($postgres);
- $pgcrypto->AddReference($libpgcommon);
$pgcrypto->AddLibrary('ws2_32.lib');
my $mf = Project::read_file('contrib/pgcrypto/Makefile');
GenerateContribSqlFiles('pgcrypto', $mf);
--
cgit v1.2.3
From 09c2e7cd2ff0b884625c37ce8249832820c58710 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Mon, 17 Jul 2017 12:03:35 -0400
Subject: hash: Fix write-ahead logging bugs related to init forks.
One, logging for CREATE INDEX was oblivious to the fact that when
an unlogged table is created, *only* operations on the init fork
should be logged.
Two, init fork buffers need to be flushed after they are written;
otherwise, a filesystem-level copy following recovery may do the
wrong thing. (There may be a better fix for this issue than the
one used here, but this is transposed from the similar logic already
present in XLogReadBufferForRedoExtended, and a broader refactoring
after beta2 seems inadvisable.)
Amit Kapila, reviewed by Ashutosh Sharma, Kyotaro Horiguchi,
and Michael Paquier
Discussion: http://postgr.es/m/CAA4eK1JpcMsEtOL_J7WODumeEfyrPi7FPYHeVdS7fyyrCrgp4w@mail.gmail.com
---
src/backend/access/hash/hash_xlog.c | 27 +++++++++++++++++++++++++++
src/backend/access/hash/hashpage.c | 23 ++++++++++++++++-------
2 files changed, 43 insertions(+), 7 deletions(-)
(limited to 'src')
diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c
index 429af11f4d..67a856c142 100644
--- a/src/backend/access/hash/hash_xlog.c
+++ b/src/backend/access/hash/hash_xlog.c
@@ -33,6 +33,7 @@ hash_xlog_init_meta_page(XLogReaderState *record)
XLogRecPtr lsn = record->EndRecPtr;
Page page;
Buffer metabuf;
+ ForkNumber forknum;
xl_hash_init_meta_page *xlrec = (xl_hash_init_meta_page *) XLogRecGetData(record);
@@ -44,6 +45,17 @@ hash_xlog_init_meta_page(XLogReaderState *record)
page = (Page) BufferGetPage(metabuf);
PageSetLSN(page, lsn);
MarkBufferDirty(metabuf);
+
+ /*
+ * Force the on-disk state of init forks to always be in sync with the
+ * state in shared buffers. See XLogReadBufferForRedoExtended. We need
+ * special handling for init forks as create index operations don't log a
+ * full page image of the metapage.
+ */
+ XLogRecGetBlockTag(record, 0, NULL, &forknum, NULL);
+ if (forknum == INIT_FORKNUM)
+ FlushOneBuffer(metabuf);
+
/* all done */
UnlockReleaseBuffer(metabuf);
}
@@ -60,6 +72,7 @@ hash_xlog_init_bitmap_page(XLogReaderState *record)
Page page;
HashMetaPage metap;
uint32 num_buckets;
+ ForkNumber forknum;
xl_hash_init_bitmap_page *xlrec = (xl_hash_init_bitmap_page *) XLogRecGetData(record);
@@ -70,6 +83,16 @@ hash_xlog_init_bitmap_page(XLogReaderState *record)
_hash_initbitmapbuffer(bitmapbuf, xlrec->bmsize, true);
PageSetLSN(BufferGetPage(bitmapbuf), lsn);
MarkBufferDirty(bitmapbuf);
+
+ /*
+ * Force the on-disk state of init forks to always be in sync with the
+ * state in shared buffers. See XLogReadBufferForRedoExtended. We need
+ * special handling for init forks as create index operations don't log a
+ * full page image of the metapage.
+ */
+ XLogRecGetBlockTag(record, 0, NULL, &forknum, NULL);
+ if (forknum == INIT_FORKNUM)
+ FlushOneBuffer(bitmapbuf);
UnlockReleaseBuffer(bitmapbuf);
/* add the new bitmap page to the metapage's list of bitmaps */
@@ -90,6 +113,10 @@ hash_xlog_init_bitmap_page(XLogReaderState *record)
PageSetLSN(page, lsn);
MarkBufferDirty(metabuf);
+
+ XLogRecGetBlockTag(record, 1, NULL, &forknum, NULL);
+ if (forknum == INIT_FORKNUM)
+ FlushOneBuffer(metabuf);
}
if (BufferIsValid(metabuf))
UnlockReleaseBuffer(metabuf);
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 1cb18a7513..d5b6502775 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -345,12 +345,20 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
int32 ffactor;
uint32 num_buckets;
uint32 i;
+ bool use_wal;
/* safety check */
if (RelationGetNumberOfBlocksInFork(rel, forkNum) != 0)
elog(ERROR, "cannot initialize non-empty hash index \"%s\"",
RelationGetRelationName(rel));
+ /*
+ * WAL log creation of pages if the relation is persistent, or this is the
+ * init fork. Init forks for unlogged relations always need to be WAL
+ * logged.
+ */
+ use_wal = RelationNeedsWAL(rel) || forkNum == INIT_FORKNUM;
+
/*
* Determine the target fill factor (in tuples per bucket) for this index.
* The idea is to make the fill factor correspond to pages about as full
@@ -384,7 +392,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
metap = HashPageGetMeta(pg);
/* XLOG stuff */
- if (RelationNeedsWAL(rel))
+ if (use_wal)
{
xl_hash_init_meta_page xlrec;
XLogRecPtr recptr;
@@ -427,11 +435,12 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
_hash_initbuf(buf, metap->hashm_maxbucket, i, LH_BUCKET_PAGE, false);
MarkBufferDirty(buf);
- log_newpage(&rel->rd_node,
- forkNum,
- blkno,
- BufferGetPage(buf),
- true);
+ if (use_wal)
+ log_newpage(&rel->rd_node,
+ forkNum,
+ blkno,
+ BufferGetPage(buf),
+ true);
_hash_relbuf(rel, buf);
}
@@ -459,7 +468,7 @@ _hash_init(Relation rel, double num_tuples, ForkNumber forkNum)
MarkBufferDirty(metabuf);
/* XLOG stuff */
- if (RelationNeedsWAL(rel))
+ if (use_wal)
{
xl_hash_init_bitmap_page xlrec;
XLogRecPtr recptr;
--
cgit v1.2.3
From 6c6970a280a50434c28ccd461ba864798f5d2a04 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan
Date: Mon, 17 Jul 2017 15:22:37 -0400
Subject: Use usleep instead of select for timeouts in PostgresNode.pm
select() for pure timeouts is not portable, and in particular doesn't
work on Windows.
Discussion: https://postgr.es/m/186943e0-3405-978d-b19d-9d3335427c86@2ndQuadrant.com
---
src/test/perl/PostgresNode.pm | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index bb2f39e508..4f414c3c03 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -93,6 +93,7 @@ use RecursiveCopy;
use Socket;
use Test::More;
use TestLib ();
+use Time::HiRes qw(usleep);
use Scalar::Util qw(blessed);
our @EXPORT = qw(
@@ -1248,7 +1249,7 @@ sub poll_query_until
}
# Wait 0.1 second before retrying.
- select undef, undef, undef, 0.1;
+ usleep(100000);
$attempts++;
}
--
cgit v1.2.3
From a570feaf927b73c5036fa47ea949ca51f2687950 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Mon, 17 Jul 2017 15:28:16 -0400
Subject: Merge large_object.sql test into largeobject.source.
It seems pretty confusing to have tests named both largeobject and
large_object. The latter is of very recent vintage (commit ff992c074),
so get rid of it in favor of merging into the former.
Also, enable the LO comment test that was added by commit 70ad7ed4e,
since the later commit added the then-missing pg_upgrade functionality.
The large_object.sql test case is almost completely redundant with that,
but not quite: it seems like creating a user-defined LO with an OID in
the system range might be an interesting case for pg_upgrade, so let's
keep it.
Like the earlier patch, back-patch to all supported branches.
Discussion: https://postgr.es/m/18665.1500306372@sss.pgh.pa.us
---
src/test/regress/expected/large_object.out | 15 ---------------
src/test/regress/input/largeobject.source | 13 +++++++++----
src/test/regress/output/largeobject.source | 16 ++++++++++++----
src/test/regress/output/largeobject_1.source | 16 ++++++++++++----
src/test/regress/parallel_schedule | 2 +-
src/test/regress/serial_schedule | 3 +--
src/test/regress/sql/large_object.sql | 8 --------
7 files changed, 35 insertions(+), 38 deletions(-)
delete mode 100644 src/test/regress/expected/large_object.out
delete mode 100644 src/test/regress/sql/large_object.sql
(limited to 'src')
diff --git a/src/test/regress/expected/large_object.out b/src/test/regress/expected/large_object.out
deleted file mode 100644
index b00d47cc75..0000000000
--- a/src/test/regress/expected/large_object.out
+++ /dev/null
@@ -1,15 +0,0 @@
--- This is more-or-less DROP IF EXISTS LARGE OBJECT 3001;
-WITH unlink AS (SELECT lo_unlink(loid) FROM pg_largeobject WHERE loid = 3001) SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
--- Test creation of a large object and leave it for testing pg_upgrade
-SELECT lo_create(3001);
- lo_create
------------
- 3001
-(1 row)
-
-COMMENT ON LARGE OBJECT 3001 IS 'testing comments';
diff --git a/src/test/regress/input/largeobject.source b/src/test/regress/input/largeobject.source
index 96d75bccfb..b7a9d052bd 100644
--- a/src/test/regress/input/largeobject.source
+++ b/src/test/regress/input/largeobject.source
@@ -86,10 +86,8 @@ END;
SELECT lo_from_bytea(0, lo_get(loid)) AS newloid FROM lotest_stash_values
\gset
--- Ideally we'd put a comment on this object for pg_dump testing purposes.
--- But since pg_upgrade fails to preserve large object comments, doing so
--- would break pg_upgrade's regression test.
--- COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
+-- Add a comment to it, as well, for pg_dump/pg_upgrade testing.
+COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
-- Read out a portion
BEGIN;
@@ -253,6 +251,13 @@ SELECT lo_from_bytea(0, E'\\xdeadbeef') AS newloid
SET bytea_output TO hex;
SELECT lo_get(:newloid);
+-- Create one more object that we leave behind for testing pg_dump/pg_upgrade;
+-- this one intentionally has an OID in the system range
+SELECT lo_create(3001);
+
+COMMENT ON LARGE OBJECT 3001 IS 'testing comments';
+
+-- Clean up
DROP TABLE lotest_stash_values;
DROP ROLE regress_lo_user;
diff --git a/src/test/regress/output/largeobject.source b/src/test/regress/output/largeobject.source
index 906a24eac4..e29f5423aa 100644
--- a/src/test/regress/output/largeobject.source
+++ b/src/test/regress/output/largeobject.source
@@ -90,10 +90,8 @@ END;
-- it's left behind to help test pg_dump.
SELECT lo_from_bytea(0, lo_get(loid)) AS newloid FROM lotest_stash_values
\gset
--- Ideally we'd put a comment on this object for pg_dump testing purposes.
--- But since pg_upgrade fails to preserve large object comments, doing so
--- would break pg_upgrade's regression test.
--- COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
+-- Add a comment to it, as well, for pg_dump/pg_upgrade testing.
+COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
-- Read out a portion
BEGIN;
UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
@@ -469,5 +467,15 @@ SELECT lo_get(:newloid);
\xdeadbeef
(1 row)
+-- Create one more object that we leave behind for testing pg_dump/pg_upgrade;
+-- this one intentionally has an OID in the system range
+SELECT lo_create(3001);
+ lo_create
+-----------
+ 3001
+(1 row)
+
+COMMENT ON LARGE OBJECT 3001 IS 'testing comments';
+-- Clean up
DROP TABLE lotest_stash_values;
DROP ROLE regress_lo_user;
diff --git a/src/test/regress/output/largeobject_1.source b/src/test/regress/output/largeobject_1.source
index cec35d70d5..6fd8cbe098 100644
--- a/src/test/regress/output/largeobject_1.source
+++ b/src/test/regress/output/largeobject_1.source
@@ -90,10 +90,8 @@ END;
-- it's left behind to help test pg_dump.
SELECT lo_from_bytea(0, lo_get(loid)) AS newloid FROM lotest_stash_values
\gset
--- Ideally we'd put a comment on this object for pg_dump testing purposes.
--- But since pg_upgrade fails to preserve large object comments, doing so
--- would break pg_upgrade's regression test.
--- COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
+-- Add a comment to it, as well, for pg_dump/pg_upgrade testing.
+COMMENT ON LARGE OBJECT :newloid IS 'I Wandered Lonely as a Cloud';
-- Read out a portion
BEGIN;
UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer));
@@ -469,5 +467,15 @@ SELECT lo_get(:newloid);
\xdeadbeef
(1 row)
+-- Create one more object that we leave behind for testing pg_dump/pg_upgrade;
+-- this one intentionally has an OID in the system range
+SELECT lo_create(3001);
+ lo_create
+-----------
+ 3001
+(1 row)
+
+COMMENT ON LARGE OBJECT 3001 IS 'testing comments';
+-- Clean up
DROP TABLE lotest_stash_values;
DROP ROLE regress_lo_user;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 23692615f9..eefdeeacae 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -84,7 +84,7 @@ test: select_into select_distinct select_distinct_on select_implicit select_havi
# ----------
# Another group of parallel tests
# ----------
-test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator large_object password
+test: brin gin gist spgist privileges init_privs security_label collate matview lock replica_identity rowsecurity object_address tablesample groupingsets drop_operator password
# ----------
# Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 5e8b7e94c4..76b0de30a7 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -115,12 +115,11 @@ test: matview
test: lock
test: replica_identity
test: rowsecurity
-test: password
test: object_address
test: tablesample
test: groupingsets
test: drop_operator
-test: large_object
+test: password
test: alter_generic
test: alter_operator
test: misc
diff --git a/src/test/regress/sql/large_object.sql b/src/test/regress/sql/large_object.sql
deleted file mode 100644
index a9e18b7c60..0000000000
--- a/src/test/regress/sql/large_object.sql
+++ /dev/null
@@ -1,8 +0,0 @@
-
--- This is more-or-less DROP IF EXISTS LARGE OBJECT 3001;
-WITH unlink AS (SELECT lo_unlink(loid) FROM pg_largeobject WHERE loid = 3001) SELECT 1;
-
--- Test creation of a large object and leave it for testing pg_upgrade
-SELECT lo_create(3001);
-
-COMMENT ON LARGE OBJECT 3001 IS 'testing comments';
--
cgit v1.2.3
From cde11fa3c003407fc6c4ddc427d57e588ea17d1c Mon Sep 17 00:00:00 2001
From: Andrew Dunstan
Date: Mon, 17 Jul 2017 15:35:19 -0400
Subject: Improve legibility of numeric literal
---
src/test/perl/PostgresNode.pm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 4f414c3c03..d87296af08 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -1249,7 +1249,7 @@ sub poll_query_until
}
# Wait 0.1 second before retrying.
- usleep(100000);
+ usleep(100_000);
$attempts++;
}
--
cgit v1.2.3
From f81a91db4d1c2032632aa5df9fc14be24f5fe5ec Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Mon, 17 Jul 2017 21:29:45 -0400
Subject: Use a real RT index when setting up partition tuple routing.
Before, we always used a dummy value of 1, but that's not right when
the partitioned table being modified is inside of a WITH clause
rather than part of the main query.
Amit Langote, reported and reviewd by Etsuro Fujita, with a comment
change by me.
Discussion: http://postgr.es/m/ee12f648-8907-77b5-afc0-2980bcb0aa37@lab.ntt.co.jp
---
src/backend/commands/copy.c | 1 +
src/backend/executor/execMain.c | 3 ++-
src/backend/executor/nodeModifyTable.c | 1 +
src/include/executor/executor.h | 1 +
src/test/regress/expected/insert.out | 18 ++++++++++++++++++
src/test/regress/sql/insert.sql | 18 ++++++++++++++++++
6 files changed, 41 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index fc5f4f66ea..53e296559a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -1433,6 +1433,7 @@ BeginCopy(ParseState *pstate,
num_partitions;
ExecSetupPartitionTupleRouting(rel,
+ 1,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 0f08283f81..df9302896c 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -3213,6 +3213,7 @@ EvalPlanQualEnd(EPQState *epqstate)
*/
void
ExecSetupPartitionTupleRouting(Relation rel,
+ Index resultRTindex,
PartitionDispatch **pd,
ResultRelInfo **partitions,
TupleConversionMap ***tup_conv_maps,
@@ -3271,7 +3272,7 @@ ExecSetupPartitionTupleRouting(Relation rel,
InitResultRelInfo(leaf_part_rri,
partrel,
- 1, /* dummy */
+ resultRTindex,
rel,
0);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 8d17425abe..77ba15dd90 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1914,6 +1914,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
num_partitions;
ExecSetupPartitionTupleRouting(rel,
+ node->nominalRelation,
&partition_dispatch_info,
&partitions,
&partition_tupconv_maps,
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index e25cfa3aba..59c28b709e 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -207,6 +207,7 @@ extern void EvalPlanQualSetTuple(EPQState *epqstate, Index rti,
HeapTuple tuple);
extern HeapTuple EvalPlanQualGetTuple(EPQState *epqstate, Index rti);
extern void ExecSetupPartitionTupleRouting(Relation rel,
+ Index resultRTindex,
PartitionDispatch **pd,
ResultRelInfo **partitions,
TupleConversionMap ***tup_conv_maps,
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index d1153f410b..dd5dddb20c 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -506,5 +506,23 @@ DETAIL: Failing row contains (2, hi there).
insert into brtrigpartcon1 values (1, 'hi there');
ERROR: new row for relation "brtrigpartcon1" violates partition constraint
DETAIL: Failing row contains (2, hi there).
+-- check that the message shows the appropriate column description in a
+-- situation where the partitioned table is not the primary ModifyTable node
+create table inserttest3 (f1 text default 'foo', f2 text default 'bar', f3 int);
+create role regress_coldesc_role;
+grant insert on inserttest3 to regress_coldesc_role;
+grant insert on brtrigpartcon to regress_coldesc_role;
+revoke select on brtrigpartcon from regress_coldesc_role;
+set role regress_coldesc_role;
+with result as (insert into brtrigpartcon values (1, 'hi there') returning 1)
+ insert into inserttest3 (f3) select * from result;
+ERROR: new row for relation "brtrigpartcon1" violates partition constraint
+DETAIL: Failing row contains (a, b) = (2, hi there).
+reset role;
+-- cleanup
+revoke all on inserttest3 from regress_coldesc_role;
+revoke all on brtrigpartcon from regress_coldesc_role;
+drop role regress_coldesc_role;
+drop table inserttest3;
drop table brtrigpartcon;
drop function brtrigpartcon1trigf();
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index 83c3ad8f53..fe63020768 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -340,5 +340,23 @@ create or replace function brtrigpartcon1trigf() returns trigger as $$begin new.
create trigger brtrigpartcon1trig before insert on brtrigpartcon1 for each row execute procedure brtrigpartcon1trigf();
insert into brtrigpartcon values (1, 'hi there');
insert into brtrigpartcon1 values (1, 'hi there');
+
+-- check that the message shows the appropriate column description in a
+-- situation where the partitioned table is not the primary ModifyTable node
+create table inserttest3 (f1 text default 'foo', f2 text default 'bar', f3 int);
+create role regress_coldesc_role;
+grant insert on inserttest3 to regress_coldesc_role;
+grant insert on brtrigpartcon to regress_coldesc_role;
+revoke select on brtrigpartcon from regress_coldesc_role;
+set role regress_coldesc_role;
+with result as (insert into brtrigpartcon values (1, 'hi there') returning 1)
+ insert into inserttest3 (f3) select * from result;
+reset role;
+
+-- cleanup
+revoke all on inserttest3 from regress_coldesc_role;
+revoke all on brtrigpartcon from regress_coldesc_role;
+drop role regress_coldesc_role;
+drop table inserttest3;
drop table brtrigpartcon;
drop function brtrigpartcon1trigf();
--
cgit v1.2.3
From c85ec643ff2586e2d144374f51f93bfa215088a2 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Mon, 17 Jul 2017 21:56:31 -0400
Subject: Reverse-convert row types in ExecWithCheckOptions.
Just as we already do in ExecConstraints, and for the same reason:
to improve the quality of error messages.
Etsuro Fujita, reviewed by Amit Langote
Discussion: http://postgr.es/m/56e0baa8-e458-2bbb-7936-367f7d832e43@lab.ntt.co.jp
---
src/backend/executor/execMain.c | 19 +++++++++++++++++++
src/test/regress/expected/updatable_views.out | 2 +-
2 files changed, 20 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index df9302896c..b22de78516 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -2097,6 +2097,25 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
* USING policy.
*/
case WCO_VIEW_CHECK:
+ /* See the comment in ExecConstraints(). */
+ if (resultRelInfo->ri_PartitionRoot)
+ {
+ HeapTuple tuple = ExecFetchSlotTuple(slot);
+ TupleDesc old_tupdesc = RelationGetDescr(rel);
+ TupleConversionMap *map;
+
+ rel = resultRelInfo->ri_PartitionRoot;
+ tupdesc = RelationGetDescr(rel);
+ /* a reverse map */
+ map = convert_tuples_by_name(old_tupdesc, tupdesc,
+ gettext_noop("could not convert row type"));
+ if (map != NULL)
+ {
+ tuple = do_convert_tuple(tuple, map);
+ ExecStoreTuple(tuple, slot, InvalidBuffer, false);
+ }
+ }
+
insertedCols = GetInsertedColumns(resultRelInfo, estate);
updatedCols = GetUpdatedColumns(resultRelInfo, estate);
modifiedCols = bms_union(insertedCols, updatedCols);
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 971dddd01c..caca81a70b 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -2424,6 +2424,6 @@ select tableoid::regclass, * from pt;
create view ptv_wco as select * from pt where a = 0 with check option;
insert into ptv_wco values (1, 2);
ERROR: new row violates check option for view "ptv_wco"
-DETAIL: Failing row contains (2, 1).
+DETAIL: Failing row contains (1, 2).
drop view ptv, ptv_wco;
drop table pt, pt1, pt11;
--
cgit v1.2.3
From b4c6d31c0be0f5c42a75d50afcf13bdd392db4a1 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 18 Jul 2017 12:45:51 -0400
Subject: Fix serious performance problems in json(b) to_tsvector().
In an off-list followup to bug #14745, Bob Jones complained that
to_tsvector() on a 2MB jsonb value took an unreasonable amount of
time and space --- enough to draw the wrath of the OOM killer on
his machine. On my machine, his example proved to require upwards
of 18 seconds and 4GB, which seemed pretty bogus considering that
to_tsvector() on the same data treated as text took just a couple
hundred msec and 10 or so MB.
On investigation, the problem is that the implementation scans each
string element of the json(b) and converts it to tsvector separately,
then applies tsvector_concat() to join those separate tsvectors.
The unreasonable memory usage came from leaking every single one of
the transient tsvectors --- but even without that mistake, this is an
O(N^2) or worse algorithm, because tsvector_concat() has to repeatedly
process the words coming from earlier elements.
We can fix it by accumulating all the lexeme data and applying
make_tsvector() just once. As a side benefit, that also makes the
desired adjustment of lexeme positions far cheaper, because we can
just tweak the running "pos" counter between JSON elements.
In passing, try to make the explanation of that tweak more intelligible.
(I didn't think that a barely-readable comment far removed from the
actual code was helpful.) And do some minor other code beautification.
---
src/backend/tsearch/to_tsany.c | 120 ++++++++++++++++++++---------------------
src/include/tsearch/ts_type.h | 9 ----
2 files changed, 58 insertions(+), 71 deletions(-)
(limited to 'src')
diff --git a/src/backend/tsearch/to_tsany.c b/src/backend/tsearch/to_tsany.c
index 6400440756..b410a49908 100644
--- a/src/backend/tsearch/to_tsany.c
+++ b/src/backend/tsearch/to_tsany.c
@@ -28,11 +28,11 @@ typedef struct MorphOpaque
typedef struct TSVectorBuildState
{
ParsedText *prs;
- TSVector result;
Oid cfgId;
} TSVectorBuildState;
-static void add_to_tsvector(void *state, char *elem_value, int elem_len);
+static void add_to_tsvector(void *_state, char *elem_value, int elem_len);
+
Datum
get_current_ts_config(PG_FUNCTION_ARGS)
@@ -270,34 +270,33 @@ jsonb_to_tsvector_byid(PG_FUNCTION_ARGS)
{
Oid cfgId = PG_GETARG_OID(0);
Jsonb *jb = PG_GETARG_JSONB(1);
+ TSVector result;
TSVectorBuildState state;
- ParsedText *prs = (ParsedText *) palloc(sizeof(ParsedText));
+ ParsedText prs;
- prs->words = NULL;
- state.result = NULL;
+ prs.words = NULL;
+ prs.curwords = 0;
+ state.prs = &prs;
state.cfgId = cfgId;
- state.prs = prs;
- iterate_jsonb_string_values(jb, &state, (JsonIterateStringValuesAction) add_to_tsvector);
+ iterate_jsonb_string_values(jb, &state, add_to_tsvector);
- PG_FREE_IF_COPY(jb, 1);
-
- if (state.result == NULL)
+ if (prs.curwords > 0)
+ result = make_tsvector(&prs);
+ else
{
/*
- * There weren't any string elements in jsonb, so wee need to return
- * an empty vector
+ * There weren't any string elements in jsonb, so we need to return an
+ * empty vector
*/
-
- if (prs->words != NULL)
- pfree(prs->words);
-
- state.result = palloc(CALCDATASIZE(0, 0));
- SET_VARSIZE(state.result, CALCDATASIZE(0, 0));
- state.result->size = 0;
+ result = palloc(CALCDATASIZE(0, 0));
+ SET_VARSIZE(result, CALCDATASIZE(0, 0));
+ result->size = 0;
}
- PG_RETURN_TSVECTOR(state.result);
+ PG_FREE_IF_COPY(jb, 1);
+
+ PG_RETURN_TSVECTOR(result);
}
Datum
@@ -317,33 +316,33 @@ json_to_tsvector_byid(PG_FUNCTION_ARGS)
{
Oid cfgId = PG_GETARG_OID(0);
text *json = PG_GETARG_TEXT_P(1);
+ TSVector result;
TSVectorBuildState state;
- ParsedText *prs = (ParsedText *) palloc(sizeof(ParsedText));
+ ParsedText prs;
- prs->words = NULL;
- state.result = NULL;
+ prs.words = NULL;
+ prs.curwords = 0;
+ state.prs = &prs;
state.cfgId = cfgId;
- state.prs = prs;
- iterate_json_string_values(json, &state, (JsonIterateStringValuesAction) add_to_tsvector);
+ iterate_json_string_values(json, &state, add_to_tsvector);
- PG_FREE_IF_COPY(json, 1);
- if (state.result == NULL)
+ if (prs.curwords > 0)
+ result = make_tsvector(&prs);
+ else
{
/*
- * There weren't any string elements in json, so wee need to return an
+ * There weren't any string elements in json, so we need to return an
* empty vector
*/
-
- if (prs->words != NULL)
- pfree(prs->words);
-
- state.result = palloc(CALCDATASIZE(0, 0));
- SET_VARSIZE(state.result, CALCDATASIZE(0, 0));
- state.result->size = 0;
+ result = palloc(CALCDATASIZE(0, 0));
+ SET_VARSIZE(result, CALCDATASIZE(0, 0));
+ result->size = 0;
}
- PG_RETURN_TSVECTOR(state.result);
+ PG_FREE_IF_COPY(json, 1);
+
+ PG_RETURN_TSVECTOR(result);
}
Datum
@@ -359,45 +358,42 @@ json_to_tsvector(PG_FUNCTION_ARGS)
}
/*
- * Extend current TSVector from _state with a new one,
- * build over a json(b) element.
+ * Parse lexemes in an element of a json(b) value, add to TSVectorBuildState.
*/
static void
add_to_tsvector(void *_state, char *elem_value, int elem_len)
{
TSVectorBuildState *state = (TSVectorBuildState *) _state;
ParsedText *prs = state->prs;
- TSVector item_vector;
- int i;
+ int32 prevwords;
- prs->lenwords = elem_len / 6;
- if (prs->lenwords == 0)
- prs->lenwords = 2;
+ if (prs->words == NULL)
+ {
+ /*
+ * First time through: initialize words array to a reasonable size.
+ * (parsetext() will realloc it bigger as needed.)
+ */
+ prs->lenwords = Max(elem_len / 6, 64);
+ prs->words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs->lenwords);
+ prs->curwords = 0;
+ prs->pos = 0;
+ }
- prs->words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs->lenwords);
- prs->curwords = 0;
- prs->pos = 0;
+ prevwords = prs->curwords;
parsetext(state->cfgId, prs, elem_value, elem_len);
- if (prs->curwords)
- {
- if (state->result != NULL)
- {
- for (i = 0; i < prs->curwords; i++)
- prs->words[i].pos.pos = prs->words[i].pos.pos + TS_JUMP;
-
- item_vector = make_tsvector(prs);
-
- state->result = (TSVector) DirectFunctionCall2(tsvector_concat,
- TSVectorGetDatum(state->result),
- PointerGetDatum(item_vector));
- }
- else
- state->result = make_tsvector(prs);
- }
+ /*
+ * If we extracted any words from this JSON element, advance pos to create
+ * an artificial break between elements. This is because we don't want
+ * phrase searches to think that the last word in this element is adjacent
+ * to the first word in the next one.
+ */
+ if (prs->curwords > prevwords)
+ prs->pos += 1;
}
+
/*
* to_tsquery
*/
diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h
index 2885bc0153..30d7c4bccd 100644
--- a/src/include/tsearch/ts_type.h
+++ b/src/include/tsearch/ts_type.h
@@ -86,15 +86,6 @@ typedef struct
#define MAXNUMPOS (256)
#define LIMITPOS(x) ( ( (x) >= MAXENTRYPOS ) ? (MAXENTRYPOS-1) : (x) )
-/*
- * In case if a TSVector contains several parts and we want to treat them as
- * separate, it's necessary to add an artificial increment to position of each
- * lexeme from every next part. It's required to avoid the situation when
- * tsquery can find a phrase consisting of lexemes from two of such parts.
- * TS_JUMP defined a value of this increment.
- */
-#define TS_JUMP 1
-
/* This struct represents a complete tsvector datum */
typedef struct
{
--
cgit v1.2.3
From 04a2c7f412d01da8100de79b13df4fd39e15ce25 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 18 Jul 2017 13:13:47 -0400
Subject: Improve make_tsvector() to handle empty input, and simplify its
callers.
It seemed a bit silly that each caller of make_tsvector() was laboriously
special-casing the situation where no lexemes were found, when it would
be easy and much more bullet-proof to make make_tsvector() handle that.
---
src/backend/tsearch/to_tsany.c | 58 ++++++++++++-------------------------
src/backend/utils/adt/tsvector_op.c | 31 ++++++--------------
2 files changed, 28 insertions(+), 61 deletions(-)
(limited to 'src')
diff --git a/src/backend/tsearch/to_tsany.c b/src/backend/tsearch/to_tsany.c
index b410a49908..35d9ab276c 100644
--- a/src/backend/tsearch/to_tsany.c
+++ b/src/backend/tsearch/to_tsany.c
@@ -149,6 +149,8 @@ uniqueWORD(ParsedWord *a, int32 l)
/*
* make value of tsvector, given parsed text
+ *
+ * Note: frees prs->words and subsidiary data.
*/
TSVector
make_tsvector(ParsedText *prs)
@@ -162,7 +164,11 @@ make_tsvector(ParsedText *prs)
char *str;
int stroff;
- prs->curwords = uniqueWORD(prs->words, prs->curwords);
+ /* Merge duplicate words */
+ if (prs->curwords > 0)
+ prs->curwords = uniqueWORD(prs->words, prs->curwords);
+
+ /* Determine space needed */
for (i = 0; i < prs->curwords; i++)
{
lenstr += prs->words[i].len;
@@ -217,7 +223,10 @@ make_tsvector(ParsedText *prs)
ptr->haspos = 0;
ptr++;
}
- pfree(prs->words);
+
+ if (prs->words)
+ pfree(prs->words);
+
return in;
}
@@ -231,26 +240,19 @@ to_tsvector_byid(PG_FUNCTION_ARGS)
prs.lenwords = VARSIZE_ANY_EXHDR(in) / 6; /* just estimation of word's
* number */
- if (prs.lenwords == 0)
+ if (prs.lenwords < 2)
prs.lenwords = 2;
prs.curwords = 0;
prs.pos = 0;
prs.words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs.lenwords);
parsetext(cfgId, &prs, VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));
+
PG_FREE_IF_COPY(in, 1);
- if (prs.curwords)
- out = make_tsvector(&prs);
- else
- {
- pfree(prs.words);
- out = palloc(CALCDATASIZE(0, 0));
- SET_VARSIZE(out, CALCDATASIZE(0, 0));
- out->size = 0;
- }
+ out = make_tsvector(&prs);
- PG_RETURN_POINTER(out);
+ PG_RETURN_TSVECTOR(out);
}
Datum
@@ -281,21 +283,10 @@ jsonb_to_tsvector_byid(PG_FUNCTION_ARGS)
iterate_jsonb_string_values(jb, &state, add_to_tsvector);
- if (prs.curwords > 0)
- result = make_tsvector(&prs);
- else
- {
- /*
- * There weren't any string elements in jsonb, so we need to return an
- * empty vector
- */
- result = palloc(CALCDATASIZE(0, 0));
- SET_VARSIZE(result, CALCDATASIZE(0, 0));
- result->size = 0;
- }
-
PG_FREE_IF_COPY(jb, 1);
+ result = make_tsvector(&prs);
+
PG_RETURN_TSVECTOR(result);
}
@@ -327,21 +318,10 @@ json_to_tsvector_byid(PG_FUNCTION_ARGS)
iterate_json_string_values(json, &state, add_to_tsvector);
- if (prs.curwords > 0)
- result = make_tsvector(&prs);
- else
- {
- /*
- * There weren't any string elements in json, so we need to return an
- * empty vector
- */
- result = palloc(CALCDATASIZE(0, 0));
- SET_VARSIZE(result, CALCDATASIZE(0, 0));
- result->size = 0;
- }
-
PG_FREE_IF_COPY(json, 1);
+ result = make_tsvector(&prs);
+
PG_RETURN_TSVECTOR(result);
}
diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c
index 2d7407c29c..822520299e 100644
--- a/src/backend/utils/adt/tsvector_op.c
+++ b/src/backend/utils/adt/tsvector_op.c
@@ -2579,28 +2579,15 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
}
/* make tsvector value */
- if (prs.curwords)
- {
- datum = PointerGetDatum(make_tsvector(&prs));
- isnull = false;
- rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att,
- 1, &tsvector_attr_num,
- &datum, &isnull);
- pfree(DatumGetPointer(datum));
- }
- else
- {
- TSVector out = palloc(CALCDATASIZE(0, 0));
-
- SET_VARSIZE(out, CALCDATASIZE(0, 0));
- out->size = 0;
- datum = PointerGetDatum(out);
- isnull = false;
- rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att,
- 1, &tsvector_attr_num,
- &datum, &isnull);
- pfree(prs.words);
- }
+ datum = TSVectorGetDatum(make_tsvector(&prs));
+ isnull = false;
+
+ /* and insert it into tuple */
+ rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att,
+ 1, &tsvector_attr_num,
+ &datum, &isnull);
+
+ pfree(DatumGetPointer(datum));
return PointerGetDatum(rettuple);
}
--
cgit v1.2.3
From 3cb29c42f990522131535eea75c691fb23191685 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Wed, 19 Jul 2017 16:16:57 -0400
Subject: Add static assertions about pg_control fitting into one disk sector.
When pg_control was first designed, sizeof(ControlFileData) was small
enough that a comment seemed like plenty to document the assumption that
it'd fit into one disk sector. Now it's nearly 300 bytes, raising the
possibility that somebody would carelessly add enough stuff to create
a problem. Let's add a StaticAssertStmt() to ensure that the situation
doesn't pass unnoticed if it ever occurs.
While at it, rename PG_CONTROL_SIZE to PG_CONTROL_FILE_SIZE to make it
clearer what that symbol means, and convert the existing runtime
comparisons of sizeof(ControlFileData) vs. PG_CONTROL_FILE_SIZE to be
static asserts --- we didn't have that technology when this code was
first written.
Discussion: https://postgr.es/m/9192.1500490591@sss.pgh.pa.us
---
src/backend/access/transam/xlog.c | 22 ++++++++++++++--------
src/bin/pg_resetwal/pg_resetwal.c | 31 ++++++++++++++++---------------
src/bin/pg_rewind/pg_rewind.c | 23 ++++++++++++++++-------
src/include/catalog/pg_control.h | 19 ++++++++++++-------
4 files changed, 58 insertions(+), 37 deletions(-)
(limited to 'src')
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 5b6cec8dee..3654543919 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4376,7 +4376,16 @@ static void
WriteControlFile(void)
{
int fd;
- char buffer[PG_CONTROL_SIZE]; /* need not be aligned */
+ char buffer[PG_CONTROL_FILE_SIZE]; /* need not be aligned */
+
+ /*
+ * Ensure that the size of the pg_control data structure is sane. See the
+ * comments for these symbols in pg_control.h.
+ */
+ StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
+ "pg_control is too large for atomic disk writes");
+ StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
+ "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
/*
* Initialize version and compatibility-check fields
@@ -4409,16 +4418,13 @@ WriteControlFile(void)
FIN_CRC32C(ControlFile->crc);
/*
- * We write out PG_CONTROL_SIZE bytes into pg_control, zero-padding the
- * excess over sizeof(ControlFileData). This reduces the odds of
+ * We write out PG_CONTROL_FILE_SIZE bytes into pg_control, zero-padding
+ * the excess over sizeof(ControlFileData). This reduces the odds of
* premature-EOF errors when reading pg_control. We'll still fail when we
* check the contents of the file, but hopefully with a more specific
* error than "couldn't read pg_control".
*/
- if (sizeof(ControlFileData) > PG_CONTROL_SIZE)
- elog(PANIC, "sizeof(ControlFileData) is larger than PG_CONTROL_SIZE; fix either one");
-
- memset(buffer, 0, PG_CONTROL_SIZE);
+ memset(buffer, 0, PG_CONTROL_FILE_SIZE);
memcpy(buffer, ControlFile, sizeof(ControlFileData));
fd = BasicOpenFile(XLOG_CONTROL_FILE,
@@ -4432,7 +4438,7 @@ WriteControlFile(void)
errno = 0;
pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE);
- if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
+ if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index d4dd1d49ca..ac67831779 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -552,9 +552,9 @@ ReadControlFile(void)
}
/* Use malloc to ensure we have a maxaligned buffer */
- buffer = (char *) pg_malloc(PG_CONTROL_SIZE);
+ buffer = (char *) pg_malloc(PG_CONTROL_FILE_SIZE);
- len = read(fd, buffer, PG_CONTROL_SIZE);
+ len = read(fd, buffer, PG_CONTROL_FILE_SIZE);
if (len < 0)
{
fprintf(stderr, _("%s: could not read file \"%s\": %s\n"),
@@ -834,7 +834,16 @@ static void
RewriteControlFile(void)
{
int fd;
- char buffer[PG_CONTROL_SIZE]; /* need not be aligned */
+ char buffer[PG_CONTROL_FILE_SIZE]; /* need not be aligned */
+
+ /*
+ * For good luck, apply the same static assertions as in backend's
+ * WriteControlFile().
+ */
+ StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
+ "pg_control is too large for atomic disk writes");
+ StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
+ "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
/*
* Adjust fields as needed to force an empty XLOG starting at
@@ -878,21 +887,13 @@ RewriteControlFile(void)
FIN_CRC32C(ControlFile.crc);
/*
- * We write out PG_CONTROL_SIZE bytes into pg_control, zero-padding the
- * excess over sizeof(ControlFileData). This reduces the odds of
+ * We write out PG_CONTROL_FILE_SIZE bytes into pg_control, zero-padding
+ * the excess over sizeof(ControlFileData). This reduces the odds of
* premature-EOF errors when reading pg_control. We'll still fail when we
* check the contents of the file, but hopefully with a more specific
* error than "couldn't read pg_control".
*/
- if (sizeof(ControlFileData) > PG_CONTROL_SIZE)
- {
- fprintf(stderr,
- _("%s: internal error -- sizeof(ControlFileData) is too large ... fix PG_CONTROL_SIZE\n"),
- progname);
- exit(1);
- }
-
- memset(buffer, 0, PG_CONTROL_SIZE);
+ memset(buffer, 0, PG_CONTROL_FILE_SIZE);
memcpy(buffer, &ControlFile, sizeof(ControlFileData));
unlink(XLOG_CONTROL_FILE);
@@ -908,7 +909,7 @@ RewriteControlFile(void)
}
errno = 0;
- if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
+ if (write(fd, buffer, PG_CONTROL_FILE_SIZE) != PG_CONTROL_FILE_SIZE)
{
/* if write didn't set errno, assume problem is no disk space */
if (errno == 0)
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 6c75b56992..4bd1a75973 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -625,9 +625,9 @@ checkControlFile(ControlFileData *ControlFile)
static void
digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
{
- if (size != PG_CONTROL_SIZE)
+ if (size != PG_CONTROL_FILE_SIZE)
pg_fatal("unexpected control file size %d, expected %d\n",
- (int) size, PG_CONTROL_SIZE);
+ (int) size, PG_CONTROL_FILE_SIZE);
memcpy(ControlFile, src, sizeof(ControlFileData));
@@ -641,7 +641,16 @@ digestControlFile(ControlFileData *ControlFile, char *src, size_t size)
static void
updateControlFile(ControlFileData *ControlFile)
{
- char buffer[PG_CONTROL_SIZE];
+ char buffer[PG_CONTROL_FILE_SIZE];
+
+ /*
+ * For good luck, apply the same static assertions as in backend's
+ * WriteControlFile().
+ */
+ StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_MAX_SAFE_SIZE,
+ "pg_control is too large for atomic disk writes");
+ StaticAssertStmt(sizeof(ControlFileData) <= PG_CONTROL_FILE_SIZE,
+ "sizeof(ControlFileData) exceeds PG_CONTROL_FILE_SIZE");
/* Recalculate CRC of control file */
INIT_CRC32C(ControlFile->crc);
@@ -651,16 +660,16 @@ updateControlFile(ControlFileData *ControlFile)
FIN_CRC32C(ControlFile->crc);
/*
- * Write out PG_CONTROL_SIZE bytes into pg_control by zero-padding the
- * excess over sizeof(ControlFileData) to avoid premature EOF related
+ * Write out PG_CONTROL_FILE_SIZE bytes into pg_control by zero-padding
+ * the excess over sizeof(ControlFileData), to avoid premature EOF related
* errors when reading it.
*/
- memset(buffer, 0, PG_CONTROL_SIZE);
+ memset(buffer, 0, PG_CONTROL_FILE_SIZE);
memcpy(buffer, ControlFile, sizeof(ControlFileData));
open_target_file("global/pg_control", false);
- write_target_range(buffer, 0, PG_CONTROL_SIZE);
+ write_target_range(buffer, 0, PG_CONTROL_FILE_SIZE);
close_target_file();
}
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 84327c9da6..1ec03caf5f 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -20,11 +20,12 @@
#include "port/pg_crc32c.h"
-#define MOCK_AUTH_NONCE_LEN 32
-
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 1002
+/* Nonce key length, see below */
+#define MOCK_AUTH_NONCE_LEN 32
+
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
@@ -94,10 +95,6 @@ typedef enum DBState
/*
* Contents of pg_control.
- *
- * NOTE: try to keep this under 512 bytes so that it will fit on one physical
- * sector of typical disk drives. This reduces the odds of corruption due to
- * power failure midway through a write.
*/
typedef struct ControlFileData
@@ -235,6 +232,14 @@ typedef struct ControlFileData
pg_crc32c crc;
} ControlFileData;
+/*
+ * Maximum safe value of sizeof(ControlFileData). For reliability's sake,
+ * it's critical that pg_control updates be atomic writes. That generally
+ * means the active data can't be more than one disk sector, which is 512
+ * bytes on common hardware. Be very careful about raising this limit.
+ */
+#define PG_CONTROL_MAX_SAFE_SIZE 512
+
/*
* Physical size of the pg_control file. Note that this is considerably
* bigger than the actually used size (ie, sizeof(ControlFileData)).
@@ -242,6 +247,6 @@ typedef struct ControlFileData
* changes, so that ReadControlFile will deliver a suitable wrong-version
* message instead of a read error if it's looking at an incompatible file.
*/
-#define PG_CONTROL_SIZE 8192
+#define PG_CONTROL_FILE_SIZE 8192
#endif /* PG_CONTROL_H */
--
cgit v1.2.3
From eb145fdfea91ee5dc6d7aad0309527f810f7c90a Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 20 Jul 2017 11:29:36 -0400
Subject: Fix dumping of outer joins with empty qual lists.
Normally, a JoinExpr would have empty "quals" only if it came from CROSS
JOIN syntax. However, it's possible to get to this state by specifying
NATURAL JOIN between two tables with no common column names, and there
might be other ways too. The code previously printed no ON clause if
"quals" was empty; that's right for CROSS JOIN but syntactically invalid
if it's some type of outer join. Fix by printing ON TRUE in that case.
This got broken by commit 2ffa740be, which stopped using NATURAL JOIN
syntax in ruleutils output due to its brittleness in the face of
column renamings. Back-patch to 9.3 where that commit appeared.
Per report from Tushar Ahuja.
Discussion: https://postgr.es/m/98b283cd-6dda-5d3f-f8ac-87db8c76a3da@enterprisedb.com
---
src/backend/utils/adt/ruleutils.c | 5 +++++
src/test/regress/expected/create_view.out | 29 +++++++++++++++++++++++++++++
src/test/regress/sql/create_view.sql | 10 ++++++++++
3 files changed, 44 insertions(+)
(limited to 'src')
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index d2fb20d564..23000281bb 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -10082,6 +10082,11 @@ get_from_clause_item(Node *jtnode, Query *query, deparse_context *context)
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
}
+ else if (j->jointype != JOIN_INNER)
+ {
+ /* If we didn't say CROSS JOIN above, we must provide an ON */
+ appendStringInfoString(buf, " ON TRUE");
+ }
if (!PRETTY_PAREN(context) || j->alias != NULL)
appendStringInfoChar(buf, ')');
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 79f5dba55f..c2da9add97 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1648,6 +1648,35 @@ select pg_get_viewdef('tt20v', true);
CAST((1 + 2)::bigint AS bigint) i8(i8);
(1 row)
+-- corner cases with empty join conditions
+create view tt21v as
+select * from tt5 natural inner join tt6;
+select pg_get_viewdef('tt21v', true);
+ pg_get_viewdef
+----------------------
+ SELECT tt5.a, +
+ tt5.b, +
+ tt5.cc, +
+ tt6.c, +
+ tt6.d +
+ FROM tt5 +
+ CROSS JOIN tt6;
+(1 row)
+
+create view tt22v as
+select * from tt5 natural left join tt6;
+select pg_get_viewdef('tt22v', true);
+ pg_get_viewdef
+-----------------------------
+ SELECT tt5.a, +
+ tt5.b, +
+ tt5.cc, +
+ tt6.c, +
+ tt6.d +
+ FROM tt5 +
+ LEFT JOIN tt6 ON TRUE;
+(1 row)
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 85c2959d3f..6e7463cf14 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -559,6 +559,16 @@ select * from
cast(1+2 as int8) as i8;
select pg_get_viewdef('tt20v', true);
+-- corner cases with empty join conditions
+
+create view tt21v as
+select * from tt5 natural inner join tt6;
+select pg_get_viewdef('tt21v', true);
+
+create view tt22v as
+select * from tt5 natural left join tt6;
+select pg_get_viewdef('tt22v', true);
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
--
cgit v1.2.3
From d363d42bb9a4399a0207bd3b371c966e22e06bd3 Mon Sep 17 00:00:00 2001
From: Dean Rasheed
Date: Fri, 21 Jul 2017 09:20:47 +0100
Subject: Use MINVALUE/MAXVALUE instead of UNBOUNDED for range partition
bounds.
Previously, UNBOUNDED meant no lower bound when used in the FROM list,
and no upper bound when used in the TO list, which was OK for
single-column range partitioning, but problematic with multiple
columns. For example, an upper bound of (10.0, UNBOUNDED) would not be
collocated with a lower bound of (10.0, UNBOUNDED), thus making it
difficult or impossible to define contiguous multi-column range
partitions in some cases.
Fix this by using MINVALUE and MAXVALUE instead of UNBOUNDED to
represent a partition column that is unbounded below or above
respectively. This syntax removes any ambiguity, and ensures that if
one partition's lower bound equals another partition's upper bound,
then the partitions are contiguous.
Also drop the constraint prohibiting finite values after an unbounded
column, and just document the fact that any values after MINVALUE or
MAXVALUE are ignored. Previously it was necessary to repeat UNBOUNDED
multiple times, which was needlessly verbose.
Note: Forces a post-PG 10 beta2 initdb.
Report by Amul Sul, original patch by Amit Langote with some
additional hacking by me.
Discussion: https://postgr.es/m/CAAJ_b947mowpLdxL3jo3YLKngRjrq9+Ej4ymduQTfYR+8=YAYQ@mail.gmail.com
---
doc/src/sgml/ref/create_table.sgml | 61 +++++++--
src/backend/catalog/partition.c | 211 ++++++++++++++---------------
src/backend/nodes/copyfuncs.c | 2 +-
src/backend/nodes/equalfuncs.c | 2 +-
src/backend/nodes/outfuncs.c | 2 +-
src/backend/nodes/readfuncs.c | 2 +-
src/backend/parser/gram.y | 16 ++-
src/backend/parser/parse_utilcmd.c | 34 -----
src/backend/utils/adt/ruleutils.c | 12 +-
src/include/catalog/catversion.h | 2 +-
src/include/nodes/parsenodes.h | 16 ++-
src/test/regress/expected/create_table.out | 41 +++---
src/test/regress/expected/inherit.out | 6 +-
src/test/regress/expected/insert.out | 130 +++++++++++++++++-
src/test/regress/sql/create_table.sql | 31 ++---
src/test/regress/sql/inherit.sql | 6 +-
src/test/regress/sql/insert.sql | 39 +++++-
src/tools/pgindent/typedefs.list | 1 +
18 files changed, 377 insertions(+), 237 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index b15c19d3d0..e9c2c49533 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -87,8 +87,8 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
and partition_bound_spec is:
IN ( { numeric_literal | string_literal | NULL } [, ...] ) |
-FROM ( { numeric_literal | string_literal | UNBOUNDED } [, ...] )
- TO ( { numeric_literal | string_literal | UNBOUNDED } [, ...] )
+FROM ( { numeric_literal | string_literal | MINVALUE | MAXVALUE } [, ...] )
+ TO ( { numeric_literal | string_literal | MINVALUE | MAXVALUE } [, ...] )
index_parameters in UNIQUE, PRIMARY KEY, and EXCLUDE constraints are:
@@ -269,10 +269,10 @@ FROM ( { numeric_literal |
Each of the values specified in
the partition_bound_spec> is
- a literal, NULL, or UNBOUNDED.
- Each literal value must be either a numeric constant that is coercible
- to the corresponding partition key column's type, or a string literal
- that is valid input for that type.
+ a literal, NULL, MINVALUE, or
+ MAXVALUE. Each literal value must be either a
+ numeric constant that is coercible to the corresponding partition key
+ column's type, or a string literal that is valid input for that type.
@@ -300,13 +300,46 @@ FROM ( { numeric_literal |
- Writing UNBOUNDED in FROM
- signifies -infinity as the lower bound of the
- corresponding column, whereas when written in TO,
- it signifies +infinity as the upper bound.
- All items following an UNBOUNDED item within
- a FROM or TO list must also
- be UNBOUNDED.
+ The special values MINVALUE> and MAXVALUE>
+ may be used when creating a range partition to indicate that there
+ is no lower or upper bound on the column's value. For example, a
+ partition defined using FROM (MINVALUE) TO (10)> allows
+ any values less than 10, and a partition defined using
+ FROM (10) TO (MAXVALUE)> allows any values greater than
+ or equal to 10.
+
+
+
+ When creating a range partition involving more than one column, it
+ can also make sense to use MAXVALUE> as part of the lower
+ bound, and MINVALUE> as part of the upper bound. For
+ example, a partition defined using
+ FROM (0, MAXVALUE) TO (10, MAXVALUE)> allows any rows
+ where the first partition key column is greater than 0 and less than
+ or equal to 10. Similarly, a partition defined using
+ FROM ('a', MINVALUE) TO ('b', MINVALUE)> allows any rows
+ where the first partition key column starts with "a".
+
+
+
+ Note that any values after MINVALUE> or
+ MAXVALUE> in a partition bound are ignored; so the bound
+ (10, MINVALUE, 0)> is equivalent to
+ (10, MINVALUE, 10)> and (10, MINVALUE, MINVALUE)>
+ and (10, MINVALUE, MAXVALUE)>.
+
+
+
+ Also note that some element types, such as timestamp>,
+ have a notion of "infinity", which is just another value that can
+ be stored. This is different from MINVALUE> and
+ MAXVALUE>, which are not real values that can be stored,
+ but rather they are ways of saying that the value is unbounded.
+ MAXVALUE> can be thought of as being greater than any
+ other value, including "infinity" and MINVALUE> as being
+ less than any other value, including "minus infinity". Thus the range
+ FROM ('infinity') TO (MAXVALUE)> is not an empty range; it
+ allows precisely one value to be stored — "infinity".
@@ -1610,7 +1643,7 @@ CREATE TABLE measurement_y2016m07
CREATE TABLE measurement_ym_older
PARTITION OF measurement_year_month
- FOR VALUES FROM (unbounded, unbounded) TO (2016, 11);
+ FOR VALUES FROM (MINVALUE, 0) TO (2016, 11);
CREATE TABLE measurement_ym_y2016m11
PARTITION OF measurement_year_month
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 43b8924261..74736e0ea1 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -67,23 +67,14 @@
* is an upper bound.
*/
-/* Ternary value to represent what's contained in a range bound datum */
-typedef enum RangeDatumContent
-{
- RANGE_DATUM_FINITE = 0, /* actual datum stored elsewhere */
- RANGE_DATUM_NEG_INF, /* negative infinity */
- RANGE_DATUM_POS_INF /* positive infinity */
-} RangeDatumContent;
-
typedef struct PartitionBoundInfoData
{
char strategy; /* list or range bounds? */
int ndatums; /* Length of the datums following array */
Datum **datums; /* Array of datum-tuples with key->partnatts
* datums each */
- RangeDatumContent **content; /* what's contained in each range bound
- * datum? (see the above enum); NULL for
- * list partitioned tables */
+ PartitionRangeDatumKind **kind; /* The kind of each range bound datum;
+ * NULL for list partitioned tables */
int *indexes; /* Partition indexes; one entry per member of
* the datums array (plus one if range
* partitioned table) */
@@ -110,7 +101,7 @@ typedef struct PartitionRangeBound
{
int index;
Datum *datums; /* range bound datums */
- RangeDatumContent *content; /* what's contained in each datum? */
+ PartitionRangeDatumKind *kind; /* the kind of each datum */
bool lower; /* this is the lower (vs upper) bound */
} PartitionRangeBound;
@@ -136,10 +127,10 @@ static List *generate_partition_qual(Relation rel);
static PartitionRangeBound *make_one_range_bound(PartitionKey key, int index,
List *datums, bool lower);
static int32 partition_rbound_cmp(PartitionKey key,
- Datum *datums1, RangeDatumContent *content1, bool lower1,
- PartitionRangeBound *b2);
+ Datum *datums1, PartitionRangeDatumKind *kind1,
+ bool lower1, PartitionRangeBound *b2);
static int32 partition_rbound_datum_cmp(PartitionKey key,
- Datum *rb_datums, RangeDatumContent *rb_content,
+ Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
Datum *tuple_datums);
static int32 partition_bound_cmp(PartitionKey key,
@@ -366,29 +357,25 @@ RelationBuildPartitionDesc(Relation rel)
bool is_distinct = false;
int j;
- /* Is current bound is distinct from the previous? */
+ /* Is the current bound distinct from the previous one? */
for (j = 0; j < key->partnatts; j++)
{
Datum cmpval;
- if (prev == NULL)
+ if (prev == NULL || cur->kind[j] != prev->kind[j])
{
is_distinct = true;
break;
}
/*
- * If either of them has infinite element, we can't equate
- * them. Even when both are infinite, they'd have
- * opposite signs, because only one of cur and prev is a
- * lower bound).
+ * If the bounds are both MINVALUE or MAXVALUE, stop now
+ * and treat them as equal, since any values after this
+ * point must be ignored.
*/
- if (cur->content[j] != RANGE_DATUM_FINITE ||
- prev->content[j] != RANGE_DATUM_FINITE)
- {
- is_distinct = true;
+ if (cur->kind[j] != PARTITION_RANGE_DATUM_VALUE)
break;
- }
+
cmpval = FunctionCall2Coll(&key->partsupfunc[j],
key->partcollation[j],
cur->datums[j],
@@ -513,8 +500,9 @@ RelationBuildPartitionDesc(Relation rel)
case PARTITION_STRATEGY_RANGE:
{
- boundinfo->content = (RangeDatumContent **) palloc(ndatums *
- sizeof(RangeDatumContent *));
+ boundinfo->kind = (PartitionRangeDatumKind **)
+ palloc(ndatums *
+ sizeof(PartitionRangeDatumKind *));
boundinfo->indexes = (int *) palloc((ndatums + 1) *
sizeof(int));
@@ -524,18 +512,17 @@ RelationBuildPartitionDesc(Relation rel)
boundinfo->datums[i] = (Datum *) palloc(key->partnatts *
sizeof(Datum));
- boundinfo->content[i] = (RangeDatumContent *)
+ boundinfo->kind[i] = (PartitionRangeDatumKind *)
palloc(key->partnatts *
- sizeof(RangeDatumContent));
+ sizeof(PartitionRangeDatumKind));
for (j = 0; j < key->partnatts; j++)
{
- if (rbounds[i]->content[j] == RANGE_DATUM_FINITE)
+ if (rbounds[i]->kind[j] == PARTITION_RANGE_DATUM_VALUE)
boundinfo->datums[i][j] =
datumCopy(rbounds[i]->datums[j],
key->parttypbyval[j],
key->parttyplen[j]);
- /* Remember, we are storing the tri-state value. */
- boundinfo->content[i][j] = rbounds[i]->content[j];
+ boundinfo->kind[i][j] = rbounds[i]->kind[j];
}
/*
@@ -617,17 +604,14 @@ partition_bounds_equal(PartitionKey key,
for (j = 0; j < key->partnatts; j++)
{
/* For range partitions, the bounds might not be finite. */
- if (b1->content != NULL)
+ if (b1->kind != NULL)
{
- /*
- * A finite bound always differs from an infinite bound, and
- * different kinds of infinities differ from each other.
- */
- if (b1->content[i][j] != b2->content[i][j])
+ /* The different kinds of bound all differ from each other */
+ if (b1->kind[i][j] != b2->kind[i][j])
return false;
/* Non-finite bounds are equal without further examination. */
- if (b1->content[i][j] != RANGE_DATUM_FINITE)
+ if (b1->kind[i][j] != PARTITION_RANGE_DATUM_VALUE)
continue;
}
@@ -736,7 +720,7 @@ check_new_partition_bound(char *relname, Relation parent,
* First check if the resulting range would be empty with
* specified lower and upper bounds
*/
- if (partition_rbound_cmp(key, lower->datums, lower->content, true,
+ if (partition_rbound_cmp(key, lower->datums, lower->kind, true,
upper) >= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
@@ -754,18 +738,18 @@ check_new_partition_bound(char *relname, Relation parent,
/*
* Test whether the new lower bound (which is treated
- * inclusively as part of the new partition) lies inside an
- * existing partition, or in a gap.
+ * inclusively as part of the new partition) lies inside
+ * an existing partition, or in a gap.
*
* If it's inside an existing partition, the bound at
* offset + 1 will be the upper bound of that partition,
* and its index will be >= 0.
*
* If it's in a gap, the bound at offset + 1 will be the
- * lower bound of the next partition, and its index will be
- * -1. This is also true if there is no next partition,
- * since the index array is initialised with an extra -1 at
- * the end.
+ * lower bound of the next partition, and its index will
+ * be -1. This is also true if there is no next partition,
+ * since the index array is initialised with an extra -1
+ * at the end.
*/
offset = partition_bound_bsearch(key, boundinfo, lower,
true, &equal);
@@ -774,9 +758,9 @@ check_new_partition_bound(char *relname, Relation parent,
{
/*
* Check that the new partition will fit in the gap.
- * For it to fit, the new upper bound must be less than
- * or equal to the lower bound of the next partition,
- * if there is one.
+ * For it to fit, the new upper bound must be less
+ * than or equal to the lower bound of the next
+ * partition, if there is one.
*/
if (offset + 1 < boundinfo->ndatums)
{
@@ -788,8 +772,9 @@ check_new_partition_bound(char *relname, Relation parent,
if (cmpval < 0)
{
/*
- * The new partition overlaps with the existing
- * partition between offset + 1 and offset + 2.
+ * The new partition overlaps with the
+ * existing partition between offset + 1 and
+ * offset + 2.
*/
overlap = true;
with = boundinfo->indexes[offset + 2];
@@ -1399,8 +1384,8 @@ get_qual_for_list(PartitionKey key, PartitionBoundSpec *spec)
*
* Constructs an Expr for the key column (returned in *keyCol) and Consts
* for the lower and upper range limits (returned in *lower_val and
- * *upper_val). For UNBOUNDED limits, NULL is returned instead of a Const.
- * All of these structures are freshly palloc'd.
+ * *upper_val). For MINVALUE/MAXVALUE limits, NULL is returned instead of
+ * a Const. All of these structures are freshly palloc'd.
*
* *partexprs_item points to the cell containing the next expression in
* the key->partexprs list, or NULL. It may be advanced upon return.
@@ -1432,12 +1417,12 @@ get_range_key_properties(PartitionKey key, int keynum,
}
/* Get appropriate Const nodes for the bounds */
- if (!ldatum->infinite)
+ if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
*lower_val = castNode(Const, copyObject(ldatum->value));
else
*lower_val = NULL;
- if (!udatum->infinite)
+ if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
*upper_val = castNode(Const, copyObject(udatum->value));
else
*upper_val = NULL;
@@ -1471,18 +1456,16 @@ get_range_key_properties(PartitionKey key, int keynum,
* AND
* (b < bu) OR (b = bu AND c < cu))
*
- * If cu happens to be UNBOUNDED, we need not emit any expression for it, so
- * the last line would be:
+ * If a bound datum is either MINVALUE or MAXVALUE, these expressions are
+ * simplified using the fact that any value is greater than MINVALUE and less
+ * than MAXVALUE. So, for example, if cu = MAXVALUE, c < cu is automatically
+ * true, and we need not emit any expression for it, and the last line becomes
*
* (b < bu) OR (b = bu), which is simplified to (b <= bu)
*
* In most common cases with only one partition column, say a, the following
* expression tree will be generated: a IS NOT NULL AND a >= al AND a < au
*
- * If all values of both lower and upper bounds are UNBOUNDED, the partition
- * does not really have a constraint, except the IS NOT NULL constraint for
- * partition keys.
- *
* If we end up with an empty result list, we return a single-member list
* containing a constant TRUE, because callers expect a non-empty list.
*/
@@ -1585,9 +1568,10 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
&lower_val, &upper_val);
/*
- * If either or both of lower_val and upper_val is NULL, they are
- * unequal, because being NULL means the column is unbounded in the
- * respective direction.
+ * If either value is NULL, the corresponding partition bound is
+ * either MINVALUE or MAXVALUE, and we treat them as unequal, because
+ * even if they're the same, there is no common value to equate the
+ * key column with.
*/
if (!lower_val || !upper_val)
break;
@@ -1668,12 +1652,15 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
/*
* For the non-last columns of this arm, use the EQ operator.
- * For the last or the last finite-valued column, use GE.
+ * For the last column of this arm, use GT, unless this is the
+ * last column of the whole bound check, or the next bound
+ * datum is MINVALUE, in which case use GE.
*/
if (j - i < current_or_arm)
strategy = BTEqualStrategyNumber;
- else if ((ldatum_next && ldatum_next->infinite) ||
- j == key->partnatts - 1)
+ else if (j == key->partnatts - 1 ||
+ (ldatum_next &&
+ ldatum_next->kind == PARTITION_RANGE_DATUM_MINVALUE))
strategy = BTGreaterEqualStrategyNumber;
else
strategy = BTGreaterStrategyNumber;
@@ -1691,11 +1678,13 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
/*
* For the non-last columns of this arm, use the EQ operator.
- * For the last finite-valued column, use LE.
+ * For the last column of this arm, use LT, unless the next
+ * bound datum is MAXVALUE, in which case use LE.
*/
if (j - i < current_or_arm)
strategy = BTEqualStrategyNumber;
- else if (udatum_next && udatum_next->infinite)
+ else if (udatum_next &&
+ udatum_next->kind == PARTITION_RANGE_DATUM_MAXVALUE)
strategy = BTLessEqualStrategyNumber;
else
strategy = BTLessStrategyNumber;
@@ -1716,11 +1705,15 @@ get_qual_for_range(PartitionKey key, PartitionBoundSpec *spec)
if (j - i > current_or_arm)
{
/*
- * We need not emit the next arm if the new column that will
- * be considered is unbounded.
+ * We must not emit any more arms if the new column that will
+ * be considered is unbounded, or this one was.
*/
- need_next_lower_arm = ldatum_next && !ldatum_next->infinite;
- need_next_upper_arm = udatum_next && !udatum_next->infinite;
+ if (!lower_val || !ldatum_next ||
+ ldatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
+ need_next_lower_arm = false;
+ if (!upper_val || !udatum_next ||
+ udatum_next->kind != PARTITION_RANGE_DATUM_VALUE)
+ need_next_upper_arm = false;
break;
}
}
@@ -2092,8 +2085,8 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
bound->index = index;
bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
- bound->content = (RangeDatumContent *) palloc0(key->partnatts *
- sizeof(RangeDatumContent));
+ bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
+ sizeof(PartitionRangeDatumKind));
bound->lower = lower;
i = 0;
@@ -2102,12 +2095,9 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
PartitionRangeDatum *datum = castNode(PartitionRangeDatum, lfirst(lc));
/* What's contained in this range datum? */
- bound->content[i] = !datum->infinite
- ? RANGE_DATUM_FINITE
- : (lower ? RANGE_DATUM_NEG_INF
- : RANGE_DATUM_POS_INF);
+ bound->kind[i] = datum->kind;
- if (bound->content[i] == RANGE_DATUM_FINITE)
+ if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
{
Const *val = castNode(Const, datum->value);
@@ -2130,7 +2120,7 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
PartitionKey key = (PartitionKey) arg;
- return partition_rbound_cmp(key, b1->datums, b1->content, b1->lower, b2);
+ return partition_rbound_cmp(key, b1->datums, b1->kind, b1->lower, b2);
}
/*
@@ -2148,13 +2138,13 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
*/
static int32
partition_rbound_cmp(PartitionKey key,
- Datum *datums1, RangeDatumContent *content1, bool lower1,
- PartitionRangeBound *b2)
+ Datum *datums1, PartitionRangeDatumKind *kind1,
+ bool lower1, PartitionRangeBound *b2)
{
int32 cmpval = 0; /* placate compiler */
int i;
Datum *datums2 = b2->datums;
- RangeDatumContent *content2 = b2->content;
+ PartitionRangeDatumKind *kind2 = b2->kind;
bool lower2 = b2->lower;
for (i = 0; i < key->partnatts; i++)
@@ -2162,28 +2152,21 @@ partition_rbound_cmp(PartitionKey key,
/*
* First, handle cases where the column is unbounded, which should not
* invoke the comparison procedure, and should not consider any later
- * columns.
+ * columns. Note that the PartitionRangeDatumKind enum elements
+ * compare the same way as the values they represent.
*/
- if (content1[i] != RANGE_DATUM_FINITE ||
- content2[i] != RANGE_DATUM_FINITE)
- {
+ if (kind1[i] < kind2[i])
+ return -1;
+ else if (kind1[i] > kind2[i])
+ return 1;
+ else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
+
/*
- * If the bound values are equal, fall through and compare whether
- * they are upper or lower bounds.
+ * The column bounds are both MINVALUE or both MAXVALUE. No later
+ * columns should be considered, but we still need to compare
+ * whether they are upper or lower bounds.
*/
- if (content1[i] == content2[i])
- break;
-
- /* Otherwise, one bound is definitely larger than the other */
- if (content1[i] == RANGE_DATUM_NEG_INF)
- return -1;
- else if (content1[i] == RANGE_DATUM_POS_INF)
- return 1;
- else if (content2[i] == RANGE_DATUM_NEG_INF)
- return 1;
- else if (content2[i] == RANGE_DATUM_POS_INF)
- return -1;
- }
+ break;
cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
key->partcollation[i],
@@ -2208,12 +2191,12 @@ partition_rbound_cmp(PartitionKey key,
/*
* partition_rbound_datum_cmp
*
- * Return whether range bound (specified in rb_datums, rb_content, and
- * rb_lower) <=, =, >= partition key of tuple (tuple_datums)
+ * Return whether range bound (specified in rb_datums, rb_kind, and rb_lower)
+ * is <, =, or > partition key of tuple (tuple_datums)
*/
static int32
partition_rbound_datum_cmp(PartitionKey key,
- Datum *rb_datums, RangeDatumContent *rb_content,
+ Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
Datum *tuple_datums)
{
int i;
@@ -2221,8 +2204,10 @@ partition_rbound_datum_cmp(PartitionKey key,
for (i = 0; i < key->partnatts; i++)
{
- if (rb_content[i] != RANGE_DATUM_FINITE)
- return rb_content[i] == RANGE_DATUM_NEG_INF ? -1 : 1;
+ if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
+ return -1;
+ else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
+ return 1;
cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
key->partcollation[i],
@@ -2238,7 +2223,7 @@ partition_rbound_datum_cmp(PartitionKey key,
/*
* partition_bound_cmp
*
- * Return whether the bound at offset in boundinfo is <=, =, >= the argument
+ * Return whether the bound at offset in boundinfo is <, =, or > the argument
* specified in *probe.
*/
static int32
@@ -2259,7 +2244,7 @@ partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
case PARTITION_STRATEGY_RANGE:
{
- RangeDatumContent *content = boundinfo->content[offset];
+ PartitionRangeDatumKind *kind = boundinfo->kind[offset];
if (probe_is_bound)
{
@@ -2271,12 +2256,12 @@ partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
bool lower = boundinfo->indexes[offset] < 0;
cmpval = partition_rbound_cmp(key,
- bound_datums, content, lower,
+ bound_datums, kind, lower,
(PartitionRangeBound *) probe);
}
else
cmpval = partition_rbound_datum_cmp(key,
- bound_datums, content,
+ bound_datums, kind,
(Datum *) probe);
break;
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 67ac8145a0..45a04b0b27 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -4458,7 +4458,7 @@ _copyPartitionRangeDatum(const PartitionRangeDatum *from)
{
PartitionRangeDatum *newnode = makeNode(PartitionRangeDatum);
- COPY_SCALAR_FIELD(infinite);
+ COPY_SCALAR_FIELD(kind);
COPY_NODE_FIELD(value);
COPY_LOCATION_FIELD(location);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 91d64b7331..8d92c03633 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2849,7 +2849,7 @@ _equalPartitionBoundSpec(const PartitionBoundSpec *a, const PartitionBoundSpec *
static bool
_equalPartitionRangeDatum(const PartitionRangeDatum *a, const PartitionRangeDatum *b)
{
- COMPARE_SCALAR_FIELD(infinite);
+ COMPARE_SCALAR_FIELD(kind);
COMPARE_NODE_FIELD(value);
COMPARE_LOCATION_FIELD(location);
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 21e39a0b81..379d92a2b0 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -3582,7 +3582,7 @@ _outPartitionRangeDatum(StringInfo str, const PartitionRangeDatum *node)
{
WRITE_NODE_TYPE("PARTITIONRANGEDATUM");
- WRITE_BOOL_FIELD(infinite);
+ WRITE_ENUM_FIELD(kind, PartitionRangeDatumKind);
WRITE_NODE_FIELD(value);
WRITE_LOCATION_FIELD(location);
}
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 8ab09d74d6..86c811de49 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -2404,7 +2404,7 @@ _readPartitionRangeDatum(void)
{
READ_LOCALS(PartitionRangeDatum);
- READ_BOOL_FIELD(infinite);
+ READ_ENUM_FIELD(kind, PartitionRangeDatumKind);
READ_NODE_FIELD(value);
READ_LOCATION_FIELD(location);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0f3998ff89..4b1ce09c44 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2696,11 +2696,21 @@ range_datum_list:
;
PartitionRangeDatum:
- UNBOUNDED
+ MINVALUE
{
PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
- n->infinite = true;
+ n->kind = PARTITION_RANGE_DATUM_MINVALUE;
+ n->value = NULL;
+ n->location = @1;
+
+ $$ = (Node *) n;
+ }
+ | MAXVALUE
+ {
+ PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
+
+ n->kind = PARTITION_RANGE_DATUM_MAXVALUE;
n->value = NULL;
n->location = @1;
@@ -2710,7 +2720,7 @@ PartitionRangeDatum:
{
PartitionRangeDatum *n = makeNode(PartitionRangeDatum);
- n->infinite = false;
+ n->kind = PARTITION_RANGE_DATUM_VALUE;
n->value = $1;
n->location = @1;
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index ee5f3a3a52..9f37f1b920 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3365,7 +3365,6 @@ transformPartitionBound(ParseState *pstate, Relation parent,
*cell2;
int i,
j;
- bool seen_unbounded;
if (spec->strategy != PARTITION_STRATEGY_RANGE)
ereport(ERROR,
@@ -3382,39 +3381,6 @@ transformPartitionBound(ParseState *pstate, Relation parent,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("TO must specify exactly one value per partitioning column")));
- /*
- * Check that no finite value follows an UNBOUNDED item in either of
- * lower and upper bound lists.
- */
- seen_unbounded = false;
- foreach(cell1, spec->lowerdatums)
- {
- PartitionRangeDatum *ldatum = castNode(PartitionRangeDatum,
- lfirst(cell1));
-
- if (ldatum->infinite)
- seen_unbounded = true;
- else if (seen_unbounded)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot specify finite value after UNBOUNDED"),
- parser_errposition(pstate, exprLocation((Node *) ldatum))));
- }
- seen_unbounded = false;
- foreach(cell1, spec->upperdatums)
- {
- PartitionRangeDatum *rdatum = castNode(PartitionRangeDatum,
- lfirst(cell1));
-
- if (rdatum->infinite)
- seen_unbounded = true;
- else if (seen_unbounded)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot specify finite value after UNBOUNDED"),
- parser_errposition(pstate, exprLocation((Node *) rdatum))));
- }
-
/* Transform all the constants */
i = j = 0;
result_spec->lowerdatums = result_spec->upperdatums = NIL;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 23000281bb..493ba924a4 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8715,8 +8715,10 @@ get_rule_expr(Node *node, deparse_context *context,
castNode(PartitionRangeDatum, lfirst(cell));
appendStringInfoString(buf, sep);
- if (datum->infinite)
- appendStringInfoString(buf, "UNBOUNDED");
+ if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
+ appendStringInfoString(buf, "MINVALUE");
+ else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
+ appendStringInfoString(buf, "MAXVALUE");
else
{
Const *val = castNode(Const, datum->value);
@@ -8733,8 +8735,10 @@ get_rule_expr(Node *node, deparse_context *context,
castNode(PartitionRangeDatum, lfirst(cell));
appendStringInfoString(buf, sep);
- if (datum->infinite)
- appendStringInfoString(buf, "UNBOUNDED");
+ if (datum->kind == PARTITION_RANGE_DATUM_MINVALUE)
+ appendStringInfoString(buf, "MINVALUE");
+ else if (datum->kind == PARTITION_RANGE_DATUM_MAXVALUE)
+ appendStringInfoString(buf, "MAXVALUE");
else
{
Const *val = castNode(Const, datum->value);
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 405e8e303b..0dafd6bf2a 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201706241
+#define CATALOG_VERSION_NO 201707211
#endif
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 1d96169d34..5f2a4a75da 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -809,16 +809,24 @@ typedef struct PartitionBoundSpec
} PartitionBoundSpec;
/*
- * PartitionRangeDatum - can be either a value or UNBOUNDED
+ * PartitionRangeDatum - one of the values in a range partition bound
*
- * "value" is an A_Const in raw grammar output, a Const after analysis
+ * This can be MINVALUE, MAXVALUE or a specific bounded value.
*/
+typedef enum PartitionRangeDatumKind
+{
+ PARTITION_RANGE_DATUM_MINVALUE = -1, /* less than any other value */
+ PARTITION_RANGE_DATUM_VALUE = 0, /* a specific (bounded) value */
+ PARTITION_RANGE_DATUM_MAXVALUE = 1 /* greater than any other value */
+} PartitionRangeDatumKind;
+
typedef struct PartitionRangeDatum
{
NodeTag type;
- bool infinite; /* true if UNBOUNDED */
- Node *value; /* null if UNBOUNDED */
+ PartitionRangeDatumKind kind;
+ Node *value; /* Const (or A_Const in raw tree), if kind is
+ * PARTITION_RANGE_DATUM_VALUE, else NULL */
int location; /* token location, or -1 if unknown */
} PartitionRangeDatum;
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 0b2f399cb1..aa44c11273 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -512,15 +512,8 @@ ERROR: FROM must specify exactly one value per partitioning column
CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a') TO ('z', 1);
ERROR: TO must specify exactly one value per partitioning column
-- cannot specify null values in range bounds
-CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (unbounded);
+CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (maxvalue);
ERROR: cannot specify NULL in range bound
--- cannot specify finite values after UNBOUNDED has been specified
-CREATE TABLE range_parted_multicol (a int, b int, c int) PARTITION BY RANGE (a, b, c);
-CREATE TABLE fail_part PARTITION OF range_parted_multicol FOR VALUES FROM (1, UNBOUNDED, 1) TO (UNBOUNDED, 1, 1);
-ERROR: cannot specify finite value after UNBOUNDED
-LINE 1: ...ge_parted_multicol FOR VALUES FROM (1, UNBOUNDED, 1) TO (UNB...
- ^
-DROP TABLE range_parted_multicol;
-- check if compatible with the specified parent
-- cannot create as partition of a non-partitioned table
CREATE TABLE unparted (
@@ -578,11 +571,11 @@ ERROR: cannot create range partition with empty range
-- note that the range '[1, 1)' has no elements
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (1);
ERROR: cannot create range partition with empty range
-CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (1);
-CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (2);
+CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (1);
+CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (2);
ERROR: partition "fail_part" would overlap partition "part0"
CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10);
-CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (unbounded);
+CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (maxvalue);
ERROR: partition "fail_part" would overlap partition "part1"
CREATE TABLE part2 PARTITION OF range_parted2 FOR VALUES FROM (20) TO (30);
CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40);
@@ -595,18 +588,18 @@ CREATE TABLE range_parted3 (
a int,
b int
) PARTITION BY RANGE (a, (b+1));
-CREATE TABLE part00 PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, unbounded);
-CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, 1);
+CREATE TABLE part00 PARTITION OF range_parted3 FOR VALUES FROM (0, minvalue) TO (0, maxvalue);
+CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (0, minvalue) TO (0, 1);
ERROR: partition "fail_part" would overlap partition "part00"
-CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, 1);
+CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, minvalue) TO (1, 1);
CREATE TABLE part11 PARTITION OF range_parted3 FOR VALUES FROM (1, 1) TO (1, 10);
-CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, unbounded);
+CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, maxvalue);
CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, 20);
ERROR: partition "fail_part" would overlap partition "part12"
-- cannot create a partition that says column b is allowed to range
-- from -infinity to +infinity, while there exist partitions that have
-- more specific ranges
-CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, unbounded);
+CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, minvalue) TO (1, maxvalue);
ERROR: partition "fail_part" would overlap partition "part10"
-- check schema propagation from parent
CREATE TABLE parted (
@@ -708,7 +701,7 @@ Number of partitions: 3 (Use \d+ to list them.)
-- check that we get the expected partition constraints
CREATE TABLE range_parted4 (a int, b int, c int) PARTITION BY RANGE (abs(a), abs(b), c);
-CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (UNBOUNDED, UNBOUNDED, UNBOUNDED) TO (UNBOUNDED, UNBOUNDED, UNBOUNDED);
+CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0);
\d+ unbounded_range_part
Table "public.unbounded_range_part"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
@@ -716,11 +709,11 @@ CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (UN
a | integer | | | | plain | |
b | integer | | | | plain | |
c | integer | | | | plain | |
-Partition of: range_parted4 FOR VALUES FROM (UNBOUNDED, UNBOUNDED, UNBOUNDED) TO (UNBOUNDED, UNBOUNDED, UNBOUNDED)
+Partition of: range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0)
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL))
DROP TABLE unbounded_range_part;
-CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (UNBOUNDED, UNBOUNDED, UNBOUNDED) TO (1, UNBOUNDED, UNBOUNDED);
+CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0);
\d+ range_parted4_1
Table "public.range_parted4_1"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
@@ -728,10 +721,10 @@ CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (UNBOUND
a | integer | | | | plain | |
b | integer | | | | plain | |
c | integer | | | | plain | |
-Partition of: range_parted4 FOR VALUES FROM (UNBOUNDED, UNBOUNDED, UNBOUNDED) TO (1, UNBOUNDED, UNBOUNDED)
+Partition of: range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0)
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND (abs(a) <= 1))
-CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, UNBOUNDED);
+CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
\d+ range_parted4_2
Table "public.range_parted4_2"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
@@ -739,10 +732,10 @@ CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5
a | integer | | | | plain | |
b | integer | | | | plain | |
c | integer | | | | plain | |
-Partition of: range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, UNBOUNDED)
+Partition of: range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE)
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 3) OR ((abs(a) = 3) AND (abs(b) > 4)) OR ((abs(a) = 3) AND (abs(b) = 4) AND (c >= 5))) AND ((abs(a) < 6) OR ((abs(a) = 6) AND (abs(b) <= 7))))
-CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, UNBOUNDED) TO (9, UNBOUNDED, UNBOUNDED);
+CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0);
\d+ range_parted4_3
Table "public.range_parted4_3"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
@@ -750,7 +743,7 @@ CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, U
a | integer | | | | plain | |
b | integer | | | | plain | |
c | integer | | | | plain | |
-Partition of: range_parted4 FOR VALUES FROM (6, 8, UNBOUNDED) TO (9, UNBOUNDED, UNBOUNDED)
+Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0)
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 6) OR ((abs(a) = 6) AND (abs(b) >= 8))) AND (abs(a) <= 9))
DROP TABLE range_parted4;
diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out
index 35d182d599..1fa9650ec9 100644
--- a/src/test/regress/expected/inherit.out
+++ b/src/test/regress/expected/inherit.out
@@ -1718,7 +1718,7 @@ create table part_10_20_cd partition of part_10_20 for values in ('cd');
create table part_21_30 partition of range_list_parted for values from (21) to (30) partition by list (b);
create table part_21_30_ab partition of part_21_30 for values in ('ab');
create table part_21_30_cd partition of part_21_30 for values in ('cd');
-create table part_40_inf partition of range_list_parted for values from (40) to (unbounded) partition by list (b);
+create table part_40_inf partition of range_list_parted for values from (40) to (maxvalue) partition by list (b);
create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
@@ -1831,12 +1831,12 @@ drop table range_list_parted;
-- check that constraint exclusion is able to cope with the partition
-- constraint emitted for multi-column range partitioned tables
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (unbounded, unbounded, unbounded) to (1, 1, 1);
+create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, 1, 1);
create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
-create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (unbounded, unbounded, unbounded);
+create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, 0, 0);
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0
QUERY PLAN
------------------------------
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index dd5dddb20c..ae3e6c034c 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -288,7 +288,7 @@ select tableoid::regclass, * from list_parted;
-- some more tests to exercise tuple-routing with multi-level partitioning
create table part_gg partition of list_parted for values in ('gg') partition by range (b);
-create table part_gg1 partition of part_gg for values from (unbounded) to (1);
+create table part_gg1 partition of part_gg for values from (minvalue) to (1);
create table part_gg2 partition of part_gg for values from (1) to (10) partition by range (b);
create table part_gg2_1 partition of part_gg2 for values from (1) to (5);
create table part_gg2_2 partition of part_gg2 for values from (5) to (10);
@@ -439,12 +439,12 @@ drop table key_desc, key_desc_1;
-- check multi-column range partitioning expression enforces the same
-- constraint as what tuple-routing would determine it to be
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (unbounded, unbounded, unbounded) to (1, unbounded, unbounded);
-create table mcrparted1 partition of mcrparted for values from (2, 1, unbounded) to (10, 5, 10);
-create table mcrparted2 partition of mcrparted for values from (10, 6, unbounded) to (10, unbounded, unbounded);
+create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, 0);
+create table mcrparted1 partition of mcrparted for values from (2, 1, minvalue) to (10, 5, 10);
+create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, 0);
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
-create table mcrparted4 partition of mcrparted for values from (21, unbounded, unbounded) to (30, 20, unbounded);
-create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (unbounded, unbounded, unbounded);
+create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, maxvalue);
+create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, 0, 0);
-- routed to mcrparted0
insert into mcrparted values (0, 1, 1);
insert into mcrparted0 values (0, 1, 1);
@@ -526,3 +526,121 @@ drop role regress_coldesc_role;
drop table inserttest3;
drop table brtrigpartcon;
drop function brtrigpartcon1trigf();
+-- check multi-column range partitioning with minvalue/maxvalue constraints
+create table mcrparted (a text, b int) partition by range(a, b);
+create table mcrparted_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
+create table mcrparted_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
+create table mcrparted_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
+create table mcrparted_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
+create table mcrparted_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
+create table mcrparted_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
+create table mcrparted_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
+create table mcrparted_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
+\d+ mcrparted
+ Table "public.mcrparted"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition key: RANGE (a, b)
+Partitions: mcrparted_b FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE),
+ mcrparted_common_0_to_10 FOR VALUES FROM ('common', 0) TO ('common', 10),
+ mcrparted_common_ge_10 FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE),
+ mcrparted_common_lt_0 FOR VALUES FROM ('common', MINVALUE) TO ('common', 0),
+ mcrparted_c_to_common FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE),
+ mcrparted_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0),
+ mcrparted_gt_common_lt_d FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE),
+ mcrparted_lt_b FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE)
+
+\d+ mcrparted_lt_b
+ Table "public.mcrparted_lt_b"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
+
+\d+ mcrparted_b
+ Table "public.mcrparted_b"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'b'::text) AND (a < 'c'::text))
+
+\d+ mcrparted_c_to_common
+ Table "public.mcrparted_c_to_common"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'c'::text) AND (a < 'common'::text))
+
+\d+ mcrparted_common_lt_0
+ Table "public.mcrparted_common_lt_0"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('common', MINVALUE) TO ('common', 0)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b < 0))
+
+\d+ mcrparted_common_0_to_10
+ Table "public.mcrparted_common_0_to_10"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('common', 0) TO ('common', 10)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b >= 0) AND (b < 10))
+
+\d+ mcrparted_common_ge_10
+ Table "public.mcrparted_common_ge_10"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b >= 10))
+
+\d+ mcrparted_gt_common_lt_d
+ Table "public.mcrparted_gt_common_lt_d"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a > 'common'::text) AND (a < 'd'::text))
+
+\d+ mcrparted_ge_d
+ Table "public.mcrparted_ge_d"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a | text | | | | extended | |
+ b | integer | | | | plain | |
+Partition of: mcrparted FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0)
+Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'd'::text))
+
+insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
+ ('comm', -10), ('common', -10), ('common', 0), ('common', 10),
+ ('commons', 0), ('d', -10), ('e', 0);
+select tableoid::regclass, * from mcrparted order by a, b;
+ tableoid | a | b
+--------------------------+---------+-----
+ mcrparted_lt_b | aaa | 0
+ mcrparted_b | b | 0
+ mcrparted_b | bz | 10
+ mcrparted_c_to_common | c | -10
+ mcrparted_c_to_common | comm | -10
+ mcrparted_common_lt_0 | common | -10
+ mcrparted_common_0_to_10 | common | 0
+ mcrparted_common_ge_10 | common | 10
+ mcrparted_gt_common_lt_d | commons | 0
+ mcrparted_ge_d | d | -10
+ mcrparted_ge_d | e | 0
+(11 rows)
+
+drop table mcrparted;
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index cb7aa5bbc6..1c0ce92763 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -483,12 +483,7 @@ CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a', 1) TO ('z
CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM ('a') TO ('z', 1);
-- cannot specify null values in range bounds
-CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (unbounded);
-
--- cannot specify finite values after UNBOUNDED has been specified
-CREATE TABLE range_parted_multicol (a int, b int, c int) PARTITION BY RANGE (a, b, c);
-CREATE TABLE fail_part PARTITION OF range_parted_multicol FOR VALUES FROM (1, UNBOUNDED, 1) TO (UNBOUNDED, 1, 1);
-DROP TABLE range_parted_multicol;
+CREATE TABLE fail_part PARTITION OF range_parted FOR VALUES FROM (null) TO (maxvalue);
-- check if compatible with the specified parent
@@ -542,10 +537,10 @@ CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (0);
-- note that the range '[1, 1)' has no elements
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (1) TO (1);
-CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (1);
-CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (unbounded) TO (2);
+CREATE TABLE part0 PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (1);
+CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (minvalue) TO (2);
CREATE TABLE part1 PARTITION OF range_parted2 FOR VALUES FROM (1) TO (10);
-CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (unbounded);
+CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (9) TO (maxvalue);
CREATE TABLE part2 PARTITION OF range_parted2 FOR VALUES FROM (20) TO (30);
CREATE TABLE part3 PARTITION OF range_parted2 FOR VALUES FROM (30) TO (40);
CREATE TABLE fail_part PARTITION OF range_parted2 FOR VALUES FROM (10) TO (30);
@@ -557,18 +552,18 @@ CREATE TABLE range_parted3 (
b int
) PARTITION BY RANGE (a, (b+1));
-CREATE TABLE part00 PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, unbounded);
-CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (0, unbounded) TO (0, 1);
+CREATE TABLE part00 PARTITION OF range_parted3 FOR VALUES FROM (0, minvalue) TO (0, maxvalue);
+CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (0, minvalue) TO (0, 1);
-CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, 1);
+CREATE TABLE part10 PARTITION OF range_parted3 FOR VALUES FROM (1, minvalue) TO (1, 1);
CREATE TABLE part11 PARTITION OF range_parted3 FOR VALUES FROM (1, 1) TO (1, 10);
-CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, unbounded);
+CREATE TABLE part12 PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, maxvalue);
CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, 10) TO (1, 20);
-- cannot create a partition that says column b is allowed to range
-- from -infinity to +infinity, while there exist partitions that have
-- more specific ranges
-CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, unbounded) TO (1, unbounded);
+CREATE TABLE fail_part PARTITION OF range_parted3 FOR VALUES FROM (1, minvalue) TO (1, maxvalue);
-- check schema propagation from parent
@@ -626,14 +621,14 @@ CREATE TABLE part_c_1_10 PARTITION OF part_c FOR VALUES FROM (1) TO (10);
-- check that we get the expected partition constraints
CREATE TABLE range_parted4 (a int, b int, c int) PARTITION BY RANGE (abs(a), abs(b), c);
-CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (UNBOUNDED, UNBOUNDED, UNBOUNDED) TO (UNBOUNDED, UNBOUNDED, UNBOUNDED);
+CREATE TABLE unbounded_range_part PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (MAXVALUE, 0, 0);
\d+ unbounded_range_part
DROP TABLE unbounded_range_part;
-CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (UNBOUNDED, UNBOUNDED, UNBOUNDED) TO (1, UNBOUNDED, UNBOUNDED);
+CREATE TABLE range_parted4_1 PARTITION OF range_parted4 FOR VALUES FROM (MINVALUE, 0, 0) TO (1, MAXVALUE, 0);
\d+ range_parted4_1
-CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, UNBOUNDED);
+CREATE TABLE range_parted4_2 PARTITION OF range_parted4 FOR VALUES FROM (3, 4, 5) TO (6, 7, MAXVALUE);
\d+ range_parted4_2
-CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, UNBOUNDED) TO (9, UNBOUNDED, UNBOUNDED);
+CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, 0);
\d+ range_parted4_3
DROP TABLE range_parted4;
diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql
index 70fe971d51..c96580cd81 100644
--- a/src/test/regress/sql/inherit.sql
+++ b/src/test/regress/sql/inherit.sql
@@ -623,7 +623,7 @@ create table part_10_20_cd partition of part_10_20 for values in ('cd');
create table part_21_30 partition of range_list_parted for values from (21) to (30) partition by list (b);
create table part_21_30_ab partition of part_21_30 for values in ('ab');
create table part_21_30_cd partition of part_21_30 for values in ('cd');
-create table part_40_inf partition of range_list_parted for values from (40) to (unbounded) partition by list (b);
+create table part_40_inf partition of range_list_parted for values from (40) to (maxvalue) partition by list (b);
create table part_40_inf_ab partition of part_40_inf for values in ('ab');
create table part_40_inf_cd partition of part_40_inf for values in ('cd');
create table part_40_inf_null partition of part_40_inf for values in (null);
@@ -647,12 +647,12 @@ drop table range_list_parted;
-- check that constraint exclusion is able to cope with the partition
-- constraint emitted for multi-column range partitioned tables
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (unbounded, unbounded, unbounded) to (1, 1, 1);
+create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, 1, 1);
create table mcrparted1 partition of mcrparted for values from (1, 1, 1) to (10, 5, 10);
create table mcrparted2 partition of mcrparted for values from (10, 5, 10) to (10, 10, 10);
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
create table mcrparted4 partition of mcrparted for values from (20, 10, 10) to (20, 20, 20);
-create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (unbounded, unbounded, unbounded);
+create table mcrparted5 partition of mcrparted for values from (20, 20, 20) to (maxvalue, 0, 0);
explain (costs off) select * from mcrparted where a = 0; -- scans mcrparted0
explain (costs off) select * from mcrparted where a = 10 and abs(b) < 5; -- scans mcrparted1
explain (costs off) select * from mcrparted where a = 10 and abs(b) = 5; -- scans mcrparted1, mcrparted2
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index fe63020768..a07d2d06e4 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -169,7 +169,7 @@ select tableoid::regclass, * from list_parted;
-- some more tests to exercise tuple-routing with multi-level partitioning
create table part_gg partition of list_parted for values in ('gg') partition by range (b);
-create table part_gg1 partition of part_gg for values from (unbounded) to (1);
+create table part_gg1 partition of part_gg for values from (minvalue) to (1);
create table part_gg2 partition of part_gg for values from (1) to (10) partition by range (b);
create table part_gg2_1 partition of part_gg2 for values from (1) to (5);
create table part_gg2_2 partition of part_gg2 for values from (5) to (10);
@@ -293,12 +293,12 @@ drop table key_desc, key_desc_1;
-- check multi-column range partitioning expression enforces the same
-- constraint as what tuple-routing would determine it to be
create table mcrparted (a int, b int, c int) partition by range (a, abs(b), c);
-create table mcrparted0 partition of mcrparted for values from (unbounded, unbounded, unbounded) to (1, unbounded, unbounded);
-create table mcrparted1 partition of mcrparted for values from (2, 1, unbounded) to (10, 5, 10);
-create table mcrparted2 partition of mcrparted for values from (10, 6, unbounded) to (10, unbounded, unbounded);
+create table mcrparted0 partition of mcrparted for values from (minvalue, 0, 0) to (1, maxvalue, 0);
+create table mcrparted1 partition of mcrparted for values from (2, 1, minvalue) to (10, 5, 10);
+create table mcrparted2 partition of mcrparted for values from (10, 6, minvalue) to (10, maxvalue, 0);
create table mcrparted3 partition of mcrparted for values from (11, 1, 1) to (20, 10, 10);
-create table mcrparted4 partition of mcrparted for values from (21, unbounded, unbounded) to (30, 20, unbounded);
-create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (unbounded, unbounded, unbounded);
+create table mcrparted4 partition of mcrparted for values from (21, minvalue, 0) to (30, 20, maxvalue);
+create table mcrparted5 partition of mcrparted for values from (30, 21, 20) to (maxvalue, 0, 0);
-- routed to mcrparted0
insert into mcrparted values (0, 1, 1);
@@ -360,3 +360,30 @@ drop role regress_coldesc_role;
drop table inserttest3;
drop table brtrigpartcon;
drop function brtrigpartcon1trigf();
+
+-- check multi-column range partitioning with minvalue/maxvalue constraints
+create table mcrparted (a text, b int) partition by range(a, b);
+create table mcrparted_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
+create table mcrparted_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
+create table mcrparted_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
+create table mcrparted_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
+create table mcrparted_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
+create table mcrparted_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
+create table mcrparted_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
+create table mcrparted_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
+
+\d+ mcrparted
+\d+ mcrparted_lt_b
+\d+ mcrparted_b
+\d+ mcrparted_c_to_common
+\d+ mcrparted_common_lt_0
+\d+ mcrparted_common_0_to_10
+\d+ mcrparted_common_ge_10
+\d+ mcrparted_gt_common_lt_d
+\d+ mcrparted_ge_d
+
+insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
+ ('comm', -10), ('common', -10), ('common', 0), ('common', 10),
+ ('commons', 0), ('d', -10), ('e', 0);
+select tableoid::regclass, * from mcrparted order by a, b;
+drop table mcrparted;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 23a4bbd8de..951d80a7fb 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1562,6 +1562,7 @@ PartitionKey
PartitionListValue
PartitionRangeBound
PartitionRangeDatum
+PartitionRangeDatumKind
PartitionSpec
PartitionedChildRelInfo
PasswordType
--
cgit v1.2.3
From 68f785fd522bca9372cce965ac10cbd8c239c076 Mon Sep 17 00:00:00 2001
From: Dean Rasheed
Date: Fri, 21 Jul 2017 10:18:01 +0100
Subject: Make the new partition regression tests locale-independent.
The order of partitions listed by \d+ is in general locale-dependent.
Rename the partitions in the test added by d363d42bb9 to force them to
be listed in a consistent order.
---
src/test/regress/expected/insert.out | 90 ++++++++++++++++++------------------
src/test/regress/sql/insert.sql | 32 ++++++-------
2 files changed, 61 insertions(+), 61 deletions(-)
(limited to 'src')
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index ae3e6c034c..c608ce377f 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -528,14 +528,14 @@ drop table brtrigpartcon;
drop function brtrigpartcon1trigf();
-- check multi-column range partitioning with minvalue/maxvalue constraints
create table mcrparted (a text, b int) partition by range(a, b);
-create table mcrparted_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
-create table mcrparted_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
-create table mcrparted_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
-create table mcrparted_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
-create table mcrparted_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
-create table mcrparted_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
-create table mcrparted_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
-create table mcrparted_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
+create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
+create table mcrparted2_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
+create table mcrparted3_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
+create table mcrparted4_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
+create table mcrparted5_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
+create table mcrparted6_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
+create table mcrparted7_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
+create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
\d+ mcrparted
Table "public.mcrparted"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
@@ -543,17 +543,17 @@ create table mcrparted_ge_d partition of mcrparted for values from ('d', minvalu
a | text | | | | extended | |
b | integer | | | | plain | |
Partition key: RANGE (a, b)
-Partitions: mcrparted_b FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE),
- mcrparted_common_0_to_10 FOR VALUES FROM ('common', 0) TO ('common', 10),
- mcrparted_common_ge_10 FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE),
- mcrparted_common_lt_0 FOR VALUES FROM ('common', MINVALUE) TO ('common', 0),
- mcrparted_c_to_common FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE),
- mcrparted_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0),
- mcrparted_gt_common_lt_d FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE),
- mcrparted_lt_b FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE)
+Partitions: mcrparted1_lt_b FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE),
+ mcrparted2_b FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE),
+ mcrparted3_c_to_common FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE),
+ mcrparted4_common_lt_0 FOR VALUES FROM ('common', MINVALUE) TO ('common', 0),
+ mcrparted5_common_0_to_10 FOR VALUES FROM ('common', 0) TO ('common', 10),
+ mcrparted6_common_ge_10 FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE),
+ mcrparted7_gt_common_lt_d FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE),
+ mcrparted8_ge_d FOR VALUES FROM ('d', MINVALUE) TO (MAXVALUE, 0)
-\d+ mcrparted_lt_b
- Table "public.mcrparted_lt_b"
+\d+ mcrparted1_lt_b
+ Table "public.mcrparted1_lt_b"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -561,8 +561,8 @@ Partitions: mcrparted_b FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE),
Partition of: mcrparted FOR VALUES FROM (MINVALUE, 0) TO ('b', MINVALUE)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
-\d+ mcrparted_b
- Table "public.mcrparted_b"
+\d+ mcrparted2_b
+ Table "public.mcrparted2_b"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -570,8 +570,8 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a < 'b'::text))
Partition of: mcrparted FOR VALUES FROM ('b', MINVALUE) TO ('c', MINVALUE)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'b'::text) AND (a < 'c'::text))
-\d+ mcrparted_c_to_common
- Table "public.mcrparted_c_to_common"
+\d+ mcrparted3_c_to_common
+ Table "public.mcrparted3_c_to_common"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -579,8 +579,8 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'b'::text)
Partition of: mcrparted FOR VALUES FROM ('c', MINVALUE) TO ('common', MINVALUE)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'c'::text) AND (a < 'common'::text))
-\d+ mcrparted_common_lt_0
- Table "public.mcrparted_common_lt_0"
+\d+ mcrparted4_common_lt_0
+ Table "public.mcrparted4_common_lt_0"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -588,8 +588,8 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a >= 'c'::text)
Partition of: mcrparted FOR VALUES FROM ('common', MINVALUE) TO ('common', 0)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b < 0))
-\d+ mcrparted_common_0_to_10
- Table "public.mcrparted_common_0_to_10"
+\d+ mcrparted5_common_0_to_10
+ Table "public.mcrparted5_common_0_to_10"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -597,8 +597,8 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::te
Partition of: mcrparted FOR VALUES FROM ('common', 0) TO ('common', 10)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b >= 0) AND (b < 10))
-\d+ mcrparted_common_ge_10
- Table "public.mcrparted_common_ge_10"
+\d+ mcrparted6_common_ge_10
+ Table "public.mcrparted6_common_ge_10"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -606,8 +606,8 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::te
Partition of: mcrparted FOR VALUES FROM ('common', 10) TO ('common', MAXVALUE)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::text) AND (b >= 10))
-\d+ mcrparted_gt_common_lt_d
- Table "public.mcrparted_gt_common_lt_d"
+\d+ mcrparted7_gt_common_lt_d
+ Table "public.mcrparted7_gt_common_lt_d"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -615,8 +615,8 @@ Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a = 'common'::te
Partition of: mcrparted FOR VALUES FROM ('common', MAXVALUE) TO ('d', MINVALUE)
Partition constraint: ((a IS NOT NULL) AND (b IS NOT NULL) AND (a > 'common'::text) AND (a < 'd'::text))
-\d+ mcrparted_ge_d
- Table "public.mcrparted_ge_d"
+\d+ mcrparted8_ge_d
+ Table "public.mcrparted8_ge_d"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------+-----------+----------+---------+----------+--------------+-------------
a | text | | | | extended | |
@@ -628,19 +628,19 @@ insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
('comm', -10), ('common', -10), ('common', 0), ('common', 10),
('commons', 0), ('d', -10), ('e', 0);
select tableoid::regclass, * from mcrparted order by a, b;
- tableoid | a | b
---------------------------+---------+-----
- mcrparted_lt_b | aaa | 0
- mcrparted_b | b | 0
- mcrparted_b | bz | 10
- mcrparted_c_to_common | c | -10
- mcrparted_c_to_common | comm | -10
- mcrparted_common_lt_0 | common | -10
- mcrparted_common_0_to_10 | common | 0
- mcrparted_common_ge_10 | common | 10
- mcrparted_gt_common_lt_d | commons | 0
- mcrparted_ge_d | d | -10
- mcrparted_ge_d | e | 0
+ tableoid | a | b
+---------------------------+---------+-----
+ mcrparted1_lt_b | aaa | 0
+ mcrparted2_b | b | 0
+ mcrparted2_b | bz | 10
+ mcrparted3_c_to_common | c | -10
+ mcrparted3_c_to_common | comm | -10
+ mcrparted4_common_lt_0 | common | -10
+ mcrparted5_common_0_to_10 | common | 0
+ mcrparted6_common_ge_10 | common | 10
+ mcrparted7_gt_common_lt_d | commons | 0
+ mcrparted8_ge_d | d | -10
+ mcrparted8_ge_d | e | 0
(11 rows)
drop table mcrparted;
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index a07d2d06e4..7666a7d6ca 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -363,24 +363,24 @@ drop function brtrigpartcon1trigf();
-- check multi-column range partitioning with minvalue/maxvalue constraints
create table mcrparted (a text, b int) partition by range(a, b);
-create table mcrparted_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
-create table mcrparted_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
-create table mcrparted_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
-create table mcrparted_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
-create table mcrparted_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
-create table mcrparted_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
-create table mcrparted_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
-create table mcrparted_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
+create table mcrparted1_lt_b partition of mcrparted for values from (minvalue, 0) to ('b', minvalue);
+create table mcrparted2_b partition of mcrparted for values from ('b', minvalue) to ('c', minvalue);
+create table mcrparted3_c_to_common partition of mcrparted for values from ('c', minvalue) to ('common', minvalue);
+create table mcrparted4_common_lt_0 partition of mcrparted for values from ('common', minvalue) to ('common', 0);
+create table mcrparted5_common_0_to_10 partition of mcrparted for values from ('common', 0) to ('common', 10);
+create table mcrparted6_common_ge_10 partition of mcrparted for values from ('common', 10) to ('common', maxvalue);
+create table mcrparted7_gt_common_lt_d partition of mcrparted for values from ('common', maxvalue) to ('d', minvalue);
+create table mcrparted8_ge_d partition of mcrparted for values from ('d', minvalue) to (maxvalue, 0);
\d+ mcrparted
-\d+ mcrparted_lt_b
-\d+ mcrparted_b
-\d+ mcrparted_c_to_common
-\d+ mcrparted_common_lt_0
-\d+ mcrparted_common_0_to_10
-\d+ mcrparted_common_ge_10
-\d+ mcrparted_gt_common_lt_d
-\d+ mcrparted_ge_d
+\d+ mcrparted1_lt_b
+\d+ mcrparted2_b
+\d+ mcrparted3_c_to_common
+\d+ mcrparted4_common_lt_0
+\d+ mcrparted5_common_0_to_10
+\d+ mcrparted6_common_ge_10
+\d+ mcrparted7_gt_common_lt_d
+\d+ mcrparted8_ge_d
insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
('comm', -10), ('common', -10), ('common', 0), ('common', 10),
--
cgit v1.2.3
From 7e1fb4c59e4ac86de2640d0f3453fde270ec1ff8 Mon Sep 17 00:00:00 2001
From: Teodor Sigaev
Date: Fri, 21 Jul 2017 13:31:20 +0300
Subject: Fix double shared memory allocation.
SLRU buffer lwlocks are allocated twice by oversight in commit
fe702a7b3f9f2bc5bf6d173166d7d55226af82c8 where that locks were moved to
separate tranche. The bug doesn't have user-visible effects except small
overspending of shared memory.
Backpatch to 9.6 where it was introduced.
Alexander Korotkov with small editorization by me.
---
src/backend/access/transam/slru.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 93ec653dd6..d037c369a7 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -205,15 +205,16 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->page_lru_count = (int *) (ptr + offset);
offset += MAXALIGN(nslots * sizeof(int));
+ /* Initialize LWLocks */
+ shared->buffer_locks = (LWLockPadded *) (ptr + offset);
+ offset += MAXALIGN(nslots * sizeof(LWLockPadded));
+
if (nlsns > 0)
{
shared->group_lsn = (XLogRecPtr *) (ptr + offset);
offset += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));
}
- /* Initialize LWLocks */
- shared->buffer_locks = (LWLockPadded *) ShmemAlloc(sizeof(LWLockPadded) * nslots);
-
Assert(strlen(name) + 1 < SLRU_MAX_NAME_LENGTH);
strlcpy(shared->lwlock_tranche_name, name, SLRU_MAX_NAME_LENGTH);
shared->lwlock_tranche_id = tranche_id;
@@ -230,6 +231,9 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
shared->page_lru_count[slotno] = 0;
ptr += BLCKSZ;
}
+
+ /* Should fit to estimated shmem size */
+ Assert(ptr - (char *) shared <= SimpleLruShmemSize(nslots, nlsns));
}
else
Assert(found);
--
cgit v1.2.3
From 063ff9210c54928a2d19f9e826486621809e1b82 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Fri, 21 Jul 2017 12:48:22 -0400
Subject: pg_rewind: Fix busted sanity check.
As written, the code would only fail the sanity check if none of the
columns returned by the server were of the expected type, but we want
it to fail if even one column is not of the expected type.
Discussion: http://postgr.es/m/CA+TgmoYuY5zW7JEs+1hSS1D=V5K8h1SQuESrq=bMNeo0B71Sfw@mail.gmail.com
---
src/bin/pg_rewind/libpq_fetch.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c
index c25367fc49..cf3f64c3aa 100644
--- a/src/bin/pg_rewind/libpq_fetch.c
+++ b/src/bin/pg_rewind/libpq_fetch.c
@@ -269,8 +269,8 @@ receiveFileChunks(const char *sql)
if (PQnfields(res) != 3 || PQntuples(res) != 1)
pg_fatal("unexpected result set size while fetching remote files\n");
- if (PQftype(res, 0) != TEXTOID &&
- PQftype(res, 1) != INT4OID &&
+ if (PQftype(res, 0) != TEXTOID ||
+ PQftype(res, 1) != INT4OID ||
PQftype(res, 2) != BYTEAOID)
{
pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u\n",
--
cgit v1.2.3
From a46fe6e8be02421ea7e80c5a6d5e388417904fd4 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Fri, 21 Jul 2017 14:25:36 -0400
Subject: pg_rewind: Fix some problems when copying files >2GB.
When incrementally updating a file larger than 2GB, the old code could
either fail outright (if the client asked the server for bytes beyond
the 2GB boundary) or fail to copy all the blocks that had actually
been modified (if the server reported a file size to the client in
excess of 2GB), resulting in data corruption. Generally, such files
won't occur anyway, but they might if using a non-default segment size
or if there the directory contains stray files unrelated to
PostgreSQL. Fix by a more prudent choice of data types.
Even with these improvements, this code still uses a mix of different
types (off_t, size_t, uint64, int64) to represent file sizes and
offsets, not all of which necessarily have the same width or
signedness, so further cleanup might be in order here. However, at
least now they all have the potential to be 64 bits wide on 64-bit
platforms.
Kuntal Ghosh and Michael Paquier, with a tweak by me.
Discussion: http://postgr.es/m/CAGz5QC+8gbkz=Brp0TgoKNqHWTzonbPtPex80U0O6Uh_bevbaA@mail.gmail.com
---
src/bin/pg_rewind/libpq_fetch.c | 47 ++++++++++++++++++++++++++++++-----------
1 file changed, 35 insertions(+), 12 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c
index cf3f64c3aa..6b4c8dd04e 100644
--- a/src/bin/pg_rewind/libpq_fetch.c
+++ b/src/bin/pg_rewind/libpq_fetch.c
@@ -194,7 +194,7 @@ libpqProcessFileList(void)
for (i = 0; i < PQntuples(res); i++)
{
char *path = PQgetvalue(res, i, 0);
- int filesize = atoi(PQgetvalue(res, i, 1));
+ int64 filesize = atol(PQgetvalue(res, i, 1));
bool isdir = (strcmp(PQgetvalue(res, i, 2), "t") == 0);
char *link_target = PQgetvalue(res, i, 3);
file_type_t type;
@@ -220,13 +220,35 @@ libpqProcessFileList(void)
PQclear(res);
}
+/*
+ * Converts an int64 from network byte order to native format.
+ */
+static int64
+pg_recvint64(int64 value)
+{
+ union
+ {
+ int64 i64;
+ uint32 i32[2];
+ } swap;
+ int64 result;
+
+ swap.i64 = value;
+
+ result = (uint32) ntohl(swap.i32[0]);
+ result <<= 32;
+ result |= (uint32) ntohl(swap.i32[1]);
+
+ return result;
+}
+
/*----
* Runs a query, which returns pieces of files from the remote source data
* directory, and overwrites the corresponding parts of target files with
* the received parts. The result set is expected to be of format:
*
* path text -- path in the data directory, e.g "base/1/123"
- * begin int4 -- offset within the file
+ * begin int8 -- offset within the file
* chunk bytea -- file content
*----
*/
@@ -247,7 +269,7 @@ receiveFileChunks(const char *sql)
{
char *filename;
int filenamelen;
- int chunkoff;
+ int64 chunkoff;
int chunksize;
char *chunk;
@@ -270,7 +292,7 @@ receiveFileChunks(const char *sql)
pg_fatal("unexpected result set size while fetching remote files\n");
if (PQftype(res, 0) != TEXTOID ||
- PQftype(res, 1) != INT4OID ||
+ PQftype(res, 1) != INT8OID ||
PQftype(res, 2) != BYTEAOID)
{
pg_fatal("unexpected data types in result set while fetching remote files: %u %u %u\n",
@@ -290,12 +312,12 @@ receiveFileChunks(const char *sql)
pg_fatal("unexpected null values in result while fetching remote files\n");
}
- if (PQgetlength(res, 0, 1) != sizeof(int32))
+ if (PQgetlength(res, 0, 1) != sizeof(int64))
pg_fatal("unexpected result length while fetching remote files\n");
/* Read result set to local variables */
- memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int32));
- chunkoff = ntohl(chunkoff);
+ memcpy(&chunkoff, PQgetvalue(res, 0, 1), sizeof(int64));
+ chunkoff = pg_recvint64(chunkoff);
chunksize = PQgetlength(res, 0, 2);
filenamelen = PQgetlength(res, 0, 0);
@@ -320,7 +342,7 @@ receiveFileChunks(const char *sql)
continue;
}
- pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %d, size %d\n",
+ pg_log(PG_DEBUG, "received chunk for file \"%s\", offset " INT64_FORMAT ", size %d\n",
filename, chunkoff, chunksize);
open_target_file(filename, false);
@@ -380,7 +402,7 @@ libpqGetFile(const char *filename, size_t *filesize)
* function to actually fetch the data.
*/
static void
-fetch_file_range(const char *path, unsigned int begin, unsigned int end)
+fetch_file_range(const char *path, uint64 begin, uint64 end)
{
char linebuf[MAXPGPATH + 23];
@@ -389,12 +411,13 @@ fetch_file_range(const char *path, unsigned int begin, unsigned int end)
{
unsigned int len;
+ /* Fine as long as CHUNKSIZE is not bigger than UINT32_MAX */
if (end - begin > CHUNKSIZE)
len = CHUNKSIZE;
else
- len = end - begin;
+ len = (unsigned int) (end - begin);
- snprintf(linebuf, sizeof(linebuf), "%s\t%u\t%u\n", path, begin, len);
+ snprintf(linebuf, sizeof(linebuf), "%s\t" UINT64_FORMAT "\t%u\n", path, begin, len);
if (PQputCopyData(conn, linebuf, strlen(linebuf)) != 1)
pg_fatal("could not send COPY data: %s",
@@ -419,7 +442,7 @@ libpq_executeFileMap(filemap_t *map)
* First create a temporary table, and load it with the blocks that we
* need to fetch.
*/
- sql = "CREATE TEMPORARY TABLE fetchchunks(path text, begin int4, len int4);";
+ sql = "CREATE TEMPORARY TABLE fetchchunks(path text, begin int8, len int4);";
res = PQexec(conn, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
--
cgit v1.2.3
From de38489b926e3e5af84f22cf4788fe4498e13c72 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Mon, 17 Jul 2017 09:51:42 -0400
Subject: Fix typo in comment
Commit fd31cd265138 renamed the variable to skipping_blocks, but forgot
to update this comment.
Noticed while inspecting code.
---
src/backend/commands/vacuumlazy.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 30a0050ae1..fabb2f8d52 100644
--- a/src/backend/commands/vacuumlazy.c
+++ b/src/backend/commands/vacuumlazy.c
@@ -639,8 +639,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
/*
* We know we can't skip the current block. But set up
- * skipping_all_visible_blocks to do the right thing at the
- * following blocks.
+ * skipping_blocks to do the right thing at the following blocks.
*/
if (next_unskippable_block - blkno > SKIP_PAGES_THRESHOLD)
skipping_blocks = true;
--
cgit v1.2.3
From 991c8b04fc5d61a308bb00ea34a7ff710051c53f Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sat, 22 Jul 2017 12:15:19 -0400
Subject: Update expected results for collate.linux.utf8 regression test.
I believe this changed as a consequence of commit 54baa4813: trying to
clone the "C" collation now produces a true clone with collencoding -1,
hence the error message if it's duplicate no longer specifies an encoding.
Per buildfarm member crake, which apparently hadn't been running this
test for the last few weeks.
---
src/test/regress/expected/collate.linux.utf8.out | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/test/regress/expected/collate.linux.utf8.out b/src/test/regress/expected/collate.linux.utf8.out
index 26275c3fb3..6b7318613a 100644
--- a/src/test/regress/expected/collate.linux.utf8.out
+++ b/src/test/regress/expected/collate.linux.utf8.out
@@ -996,9 +996,9 @@ BEGIN
END
$$;
CREATE COLLATION test0 FROM "C"; -- fail, duplicate name
-ERROR: collation "test0" for encoding "UTF8" already exists
+ERROR: collation "test0" already exists
CREATE COLLATION IF NOT EXISTS test0 FROM "C"; -- ok, skipped
-NOTICE: collation "test0" for encoding "UTF8" already exists, skipping
+NOTICE: collation "test0" already exists, skipping
CREATE COLLATION IF NOT EXISTS test0 (locale = 'foo'); -- ok, skipped
NOTICE: collation "test0" for encoding "UTF8" already exists, skipping
do $$
--
cgit v1.2.3
From ab2324fd468c4bc6d8b012552550ed951d97339a Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sat, 22 Jul 2017 18:02:26 -0400
Subject: Improve comments about partitioned hash table freelists.
While I couldn't find any live bugs in commit 44ca4022f, the comments
seemed pretty far from adequate; in particular it was not made plain that
"borrowing" entries from other freelists is critical for correctness.
Try to improve the commentary. A couple of very minor code style
tweaks, as well.
Discussion: https://postgr.es/m/10593.1500670709@sss.pgh.pa.us
---
src/backend/utils/hash/dynahash.c | 105 +++++++++++++++++++++++++-------------
1 file changed, 70 insertions(+), 35 deletions(-)
(limited to 'src')
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index ebd55da997..a58a479ae5 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -15,7 +15,8 @@
* to hash_create. This prevents any attempt to split buckets on-the-fly.
* Therefore, each hash bucket chain operates independently, and no fields
* of the hash header change after init except nentries and freeList.
- * A partitioned table uses spinlocks to guard changes of those fields.
+ * (A partitioned table uses multiple copies of those fields, guarded by
+ * spinlocks, for additional concurrency.)
* This lets any subset of the hash buckets be treated as a separately
* lockable partition. We expect callers to use the low-order bits of a
* lookup key's hash value as a partition number --- this will work because
@@ -121,15 +122,27 @@ typedef HASHELEMENT *HASHBUCKET;
typedef HASHBUCKET *HASHSEGMENT;
/*
- * Using array of FreeListData instead of separate arrays of mutexes, nentries
- * and freeLists prevents, at least partially, sharing one cache line between
- * different mutexes (see below).
+ * Per-freelist data.
+ *
+ * In a partitioned hash table, each freelist is associated with a specific
+ * set of hashcodes, as determined by the FREELIST_IDX() macro below.
+ * nentries tracks the number of live hashtable entries having those hashcodes
+ * (NOT the number of entries in the freelist, as you might expect).
+ *
+ * The coverage of a freelist might be more or less than one partition, so it
+ * needs its own lock rather than relying on caller locking. Relying on that
+ * wouldn't work even if the coverage was the same, because of the occasional
+ * need to "borrow" entries from another freelist; see get_hash_entry().
+ *
+ * Using an array of FreeListData instead of separate arrays of mutexes,
+ * nentries and freeLists helps to reduce sharing of cache lines between
+ * different mutexes.
*/
typedef struct
{
- slock_t mutex; /* spinlock */
- long nentries; /* number of entries */
- HASHELEMENT *freeList; /* list of free elements */
+ slock_t mutex; /* spinlock for this freelist */
+ long nentries; /* number of entries in associated buckets */
+ HASHELEMENT *freeList; /* chain of free elements */
} FreeListData;
/*
@@ -143,12 +156,14 @@ typedef struct
struct HASHHDR
{
/*
- * The freelist can become a point of contention on high-concurrency hash
- * tables, so we use an array of freelist, each with its own mutex and
- * nentries count, instead of just a single one.
+ * The freelist can become a point of contention in high-concurrency hash
+ * tables, so we use an array of freelists, each with its own mutex and
+ * nentries count, instead of just a single one. Although the freelists
+ * normally operate independently, we will scavenge entries from freelists
+ * other than a hashcode's default freelist when necessary.
*
- * If hash table is not partitioned only freeList[0] is used and spinlocks
- * are not used at all.
+ * If the hash table is not partitioned, only freeList[0] is used and its
+ * spinlock is not used at all; callers' locking is assumed sufficient.
*/
FreeListData freeList[NUM_FREELISTS];
@@ -184,7 +199,7 @@ struct HASHHDR
#define IS_PARTITIONED(hctl) ((hctl)->num_partitions != 0)
#define FREELIST_IDX(hctl, hashcode) \
- (IS_PARTITIONED(hctl) ? hashcode % NUM_FREELISTS : 0)
+ (IS_PARTITIONED(hctl) ? (hashcode) % NUM_FREELISTS : 0)
/*
* Top control structure for a hashtable --- in a shared table, each backend
@@ -506,8 +521,8 @@ hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
nelem_alloc_first;
/*
- * If hash table is partitioned all freeLists have equal number of
- * elements. Otherwise only freeList[0] is used.
+ * If hash table is partitioned, give each freelist an equal share of
+ * the initial allocation. Otherwise only freeList[0] is used.
*/
if (IS_PARTITIONED(hashp->hctl))
freelist_partitions = NUM_FREELISTS;
@@ -515,10 +530,13 @@ hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
freelist_partitions = 1;
nelem_alloc = nelem / freelist_partitions;
- if (nelem_alloc == 0)
+ if (nelem_alloc <= 0)
nelem_alloc = 1;
- /* Make sure all memory will be used */
+ /*
+ * Make sure we'll allocate all the requested elements; freeList[0]
+ * gets the excess if the request isn't divisible by NUM_FREELISTS.
+ */
if (nelem_alloc * freelist_partitions < nelem)
nelem_alloc_first =
nelem - nelem_alloc * (freelist_partitions - 1);
@@ -620,7 +638,7 @@ init_htab(HTAB *hashp, long nelem)
int i;
/*
- * initialize mutex if it's a partitioned table
+ * initialize mutexes if it's a partitioned table
*/
if (IS_PARTITIONED(hctl))
for (i = 0; i < NUM_FREELISTS; i++)
@@ -902,6 +920,7 @@ hash_search_with_hash_value(HTAB *hashp,
bool *foundPtr)
{
HASHHDR *hctl = hashp->hctl;
+ int freelist_idx = FREELIST_IDX(hctl, hashvalue);
Size keysize;
uint32 bucket;
long segment_num;
@@ -910,7 +929,6 @@ hash_search_with_hash_value(HTAB *hashp,
HASHBUCKET currBucket;
HASHBUCKET *prevBucketPtr;
HashCompareFunc match;
- int freelist_idx = FREELIST_IDX(hctl, hashvalue);
#if HASH_STATISTICS
hash_accesses++;
@@ -993,13 +1011,14 @@ hash_search_with_hash_value(HTAB *hashp,
if (IS_PARTITIONED(hctl))
SpinLockAcquire(&(hctl->freeList[freelist_idx].mutex));
+ /* delete the record from the appropriate nentries counter. */
Assert(hctl->freeList[freelist_idx].nentries > 0);
hctl->freeList[freelist_idx].nentries--;
/* remove record from hash bucket's chain. */
*prevBucketPtr = currBucket->link;
- /* add the record to the freelist for this table. */
+ /* add the record to the appropriate freelist. */
currBucket->link = hctl->freeList[freelist_idx].freeList;
hctl->freeList[freelist_idx].freeList = currBucket;
@@ -1220,14 +1239,15 @@ hash_update_hash_key(HTAB *hashp,
}
/*
- * create a new entry if possible
+ * Allocate a new hashtable entry if possible; return NULL if out of memory.
+ * (Or, if the underlying space allocator throws error for out-of-memory,
+ * we won't return at all.)
*/
static HASHBUCKET
get_hash_entry(HTAB *hashp, int freelist_idx)
{
HASHHDR *hctl = hashp->hctl;
HASHBUCKET newElement;
- int borrow_from_idx;
for (;;)
{
@@ -1244,19 +1264,32 @@ get_hash_entry(HTAB *hashp, int freelist_idx)
if (IS_PARTITIONED(hctl))
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
- /* no free elements. allocate another chunk of buckets */
+ /*
+ * No free elements in this freelist. In a partitioned table, there
+ * might be entries in other freelists, but to reduce contention we
+ * prefer to first try to get another chunk of buckets from the main
+ * shmem allocator. If that fails, though, we *MUST* root through all
+ * the other freelists before giving up. There are multiple callers
+ * that assume that they can allocate every element in the initially
+ * requested table size, or that deleting an element guarantees they
+ * can insert a new element, even if shared memory is entirely full.
+ * Failing because the needed element is in a different freelist is
+ * not acceptable.
+ */
if (!element_alloc(hashp, hctl->nelem_alloc, freelist_idx))
{
+ int borrow_from_idx;
+
if (!IS_PARTITIONED(hctl))
return NULL; /* out of memory */
- /* try to borrow element from another partition */
+ /* try to borrow element from another freelist */
borrow_from_idx = freelist_idx;
for (;;)
{
borrow_from_idx = (borrow_from_idx + 1) % NUM_FREELISTS;
if (borrow_from_idx == freelist_idx)
- break;
+ break; /* examined all freelists, fail */
SpinLockAcquire(&(hctl->freeList[borrow_from_idx].mutex));
newElement = hctl->freeList[borrow_from_idx].freeList;
@@ -1266,17 +1299,19 @@ get_hash_entry(HTAB *hashp, int freelist_idx)
hctl->freeList[borrow_from_idx].freeList = newElement->link;
SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex));
+ /* careful: count the new element in its proper freelist */
SpinLockAcquire(&hctl->freeList[freelist_idx].mutex);
hctl->freeList[freelist_idx].nentries++;
SpinLockRelease(&hctl->freeList[freelist_idx].mutex);
- break;
+ return newElement;
}
SpinLockRelease(&(hctl->freeList[borrow_from_idx].mutex));
}
- return newElement;
+ /* no elements available to borrow either, so out of memory */
+ return NULL;
}
}
@@ -1300,15 +1335,15 @@ hash_get_num_entries(HTAB *hashp)
long sum = hashp->hctl->freeList[0].nentries;
/*
- * We currently don't bother with the mutex; it's only sensible to call
- * this function if you've got lock on all partitions of the table.
+ * We currently don't bother with acquiring the mutexes; it's only
+ * sensible to call this function if you've got lock on all partitions of
+ * the table.
*/
-
- if (!IS_PARTITIONED(hashp->hctl))
- return sum;
-
- for (i = 1; i < NUM_FREELISTS; i++)
- sum += hashp->hctl->freeList[i].nentries;
+ if (IS_PARTITIONED(hashp->hctl))
+ {
+ for (i = 1; i < NUM_FREELISTS; i++)
+ sum += hashp->hctl->freeList[i].nentries;
+ }
return sum;
}
--
cgit v1.2.3
From 93f039b4944fdf806f029ed46cf192bc9021d8e7 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sat, 22 Jul 2017 20:20:09 -0400
Subject: Fix pg_dump's handling of event triggers.
pg_dump with the --clean option failed to emit DROP EVENT TRIGGER
commands for event triggers. In a closely related oversight,
it also did not emit ALTER OWNER commands for event triggers.
Since only superusers can create event triggers, the latter oversight
is of little practical consequence ... but if we're going to record
an owner for event triggers, then surely pg_dump should preserve it.
Per complaint from Greg Atkins. Back-patch to 9.3 where event triggers
were introduced.
Discussion: https://postgr.es/m/20170722191142.yi4e7tzcg3iacclg@gmail.com
---
src/bin/pg_dump/pg_backup_archiver.c | 6 ++++--
src/bin/pg_dump/pg_dump.c | 14 +++++++++++--
src/bin/pg_dump/t/002_pg_dump.pl | 40 ++++++++++++++++++------------------
3 files changed, 36 insertions(+), 24 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index b9d063aa22..f461692d45 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -3313,6 +3313,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
strcmp(type, "DATABASE") == 0 ||
strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
strcmp(type, "SCHEMA") == 0 ||
+ strcmp(type, "EVENT TRIGGER") == 0 ||
strcmp(type, "FOREIGN DATA WRAPPER") == 0 ||
strcmp(type, "SERVER") == 0 ||
strcmp(type, "PUBLICATION") == 0 ||
@@ -3359,7 +3360,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
return;
}
- write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
+ write_msg(modulename, "WARNING: don't know how to set owner for object type \"%s\"\n",
type);
}
@@ -3518,6 +3519,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass)
strcmp(te->desc, "OPERATOR FAMILY") == 0 ||
strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
strcmp(te->desc, "SCHEMA") == 0 ||
+ strcmp(te->desc, "EVENT TRIGGER") == 0 ||
strcmp(te->desc, "TABLE") == 0 ||
strcmp(te->desc, "TYPE") == 0 ||
strcmp(te->desc, "VIEW") == 0 ||
@@ -3556,7 +3558,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass)
}
else
{
- write_msg(modulename, "WARNING: don't know how to set owner for object type %s\n",
+ write_msg(modulename, "WARNING: don't know how to set owner for object type \"%s\"\n",
te->desc);
}
}
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 502d5eb7af..8e9454885a 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -16844,6 +16844,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
{
DumpOptions *dopt = fout->dopt;
PQExpBuffer query;
+ PQExpBuffer delqry;
PQExpBuffer labelq;
/* Skip if not to be dumped */
@@ -16851,6 +16852,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
return;
query = createPQExpBuffer();
+ delqry = createPQExpBuffer();
labelq = createPQExpBuffer();
appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
@@ -16890,14 +16892,21 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
}
appendPQExpBufferStr(query, ";\n");
}
+
+ appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
+ fmtId(evtinfo->dobj.name));
+
appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
fmtId(evtinfo->dobj.name));
if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
- evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
+ evtinfo->dobj.name, NULL, NULL,
+ evtinfo->evtowner, false,
"EVENT TRIGGER", SECTION_POST_DATA,
- query->data, "", NULL, NULL, 0, NULL, NULL);
+ query->data, delqry->data, NULL,
+ NULL, 0,
+ NULL, NULL);
if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
dumpComment(fout, labelq->data,
@@ -16905,6 +16914,7 @@ dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
destroyPQExpBuffer(query);
+ destroyPQExpBuffer(delqry);
destroyPQExpBuffer(labelq);
}
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index a8000db336..4c6201be61 100644
--- a/src/bin/pg_dump/t/002_pg_dump.pl
+++ b/src/bin/pg_dump/t/002_pg_dump.pl
@@ -466,7 +466,7 @@ my %tests = (
'ALTER COLLATION test0 OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER COLLATION test0 OWNER TO .*;/m,
collation => 1,
like => {
@@ -493,7 +493,7 @@ my %tests = (
'ALTER FOREIGN DATA WRAPPER dummy OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER FOREIGN DATA WRAPPER dummy OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -520,7 +520,7 @@ my %tests = (
'ALTER SERVER s1 OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER SERVER s1 OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -547,7 +547,7 @@ my %tests = (
'ALTER FUNCTION dump_test.pltestlang_call_handler() OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^
\QALTER FUNCTION dump_test.pltestlang_call_handler() \E
\QOWNER TO \E
@@ -576,7 +576,7 @@ my %tests = (
'ALTER OPERATOR FAMILY dump_test.op_family OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^
\QALTER OPERATOR FAMILY dump_test.op_family USING btree \E
\QOWNER TO \E
@@ -655,7 +655,7 @@ my %tests = (
'ALTER OPERATOR CLASS dump_test.op_class OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^
\QALTER OPERATOR CLASS dump_test.op_class USING btree \E
\QOWNER TO \E
@@ -746,7 +746,7 @@ my %tests = (
'ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -772,7 +772,7 @@ my %tests = (
'ALTER SCHEMA dump_test OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -798,7 +798,7 @@ my %tests = (
'ALTER SCHEMA dump_test_second_schema OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1193,7 +1193,7 @@ my %tests = (
'ALTER TABLE test_table OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER TABLE test_table OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1251,7 +1251,7 @@ my %tests = (
'ALTER TABLE test_second_table OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1278,7 +1278,7 @@ my %tests = (
'ALTER TABLE test_third_table OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1305,7 +1305,7 @@ my %tests = (
'ALTER TABLE measurement OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER TABLE measurement OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1332,7 +1332,7 @@ my %tests = (
'ALTER TABLE measurement_y2006m2 OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER TABLE measurement_y2006m2 OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1359,7 +1359,7 @@ my %tests = (
'ALTER FOREIGN TABLE foreign_table OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp => qr/^ALTER FOREIGN TABLE foreign_table OWNER TO .*;/m,
like => {
binary_upgrade => 1,
@@ -1386,7 +1386,7 @@ my %tests = (
'ALTER TEXT SEARCH CONFIGURATION alt_ts_conf1 OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp =>
qr/^ALTER TEXT SEARCH CONFIGURATION alt_ts_conf1 OWNER TO .*;/m,
like => {
@@ -1414,7 +1414,7 @@ my %tests = (
'ALTER TEXT SEARCH DICTIONARY alt_ts_dict1 OWNER TO' => {
all_runs => 1,
catch_all =>
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)',
+ 'ALTER ... OWNER commands (except post-data objects)',
regexp =>
qr/^ALTER TEXT SEARCH DICTIONARY alt_ts_dict1 OWNER TO .*;/m,
like => {
@@ -1439,11 +1439,11 @@ my %tests = (
only_dump_test_table => 1,
role => 1, }, },
- # catch-all for ALTER ... OWNER (except LARGE OBJECTs and PUBLICATIONs)
- 'ALTER ... OWNER commands (except LARGE OBJECTs and PUBLICATIONs)' => {
+ # catch-all for ALTER ... OWNER (except post-data objects)
+ 'ALTER ... OWNER commands (except post-data objects)' => {
all_runs => 0, # catch-all
regexp =>
-qr/^ALTER (?!LARGE OBJECT|PUBLICATION|SUBSCRIPTION)(.*) OWNER TO .*;/m,
+qr/^ALTER (?!EVENT TRIGGER|LARGE OBJECT|PUBLICATION|SUBSCRIPTION)(.*) OWNER TO .*;/m,
like => {}, # use more-specific options above
unlike => {
column_inserts => 1,
--
cgit v1.2.3
From 71ad8000da5d836c9ca117a164c38d84284a336f Mon Sep 17 00:00:00 2001
From: Noah Misch
Date: Sun, 23 Jul 2017 23:53:27 -0700
Subject: MSVC: Accept tcl86.lib in addition to tcl86t.lib.
ActiveTcl8.6.4.1.299124-win32-x86_64-threaded.exe ships just tcl86.lib.
Back-patch to 9.2, like the commit recognizing tcl86t.lib.
---
src/tools/msvc/Mkvcbuild.pm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 55a431715e..e0bf60797f 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -209,7 +209,7 @@ sub mkvcbuild
$pltcl->AddIncludeDir($solution->{options}->{tcl} . '/include');
$pltcl->AddReference($postgres);
- for my $tclver (qw(86t 85 84))
+ for my $tclver (qw(86t 86 85 84))
{
my $tcllib = $solution->{options}->{tcl} . "/lib/tcl$tclver.lib";
if (-e $tcllib)
--
cgit v1.2.3
From bbbd9121e63f9f7cf8cc86025d5d848fba477eb4 Mon Sep 17 00:00:00 2001
From: Noah Misch
Date: Mon, 24 Jul 2017 00:13:23 -0700
Subject: MSVC: Finish clean.bat build artifact coverage.
With this, "git clean -dnx" is clear after a "clean dist" following a
build. Preserve sql_help.h in non-dist cleans, like the Makefile does.
---
src/tools/msvc/clean.bat | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/tools/msvc/clean.bat b/src/tools/msvc/clean.bat
index e50f228d9e..0a88b52536 100755
--- a/src/tools/msvc/clean.bat
+++ b/src/tools/msvc/clean.bat
@@ -34,6 +34,7 @@ if exist src\timezone\win32ver.rc del /q src\timezone\win32ver.rc
for /d %%f in (src\interfaces\ecpg\*) do if exist %%f\win32ver.rc del /q %%f\win32ver.rc
for /d %%f in (contrib\*) do if exist %%f\win32ver.rc del /q %%f\win32ver.rc
for /d %%f in (src\backend\utils\mb\conversion_procs\*) do if exist %%f\win32ver.rc del /q %%f\win32ver.rc
+for /d %%f in (src\test\modules\*) do if exist %%f\win32ver.rc del /q %%f\win32ver.rc
REM Delete files created with GenerateFiles() in Solution.pm
if exist src\include\pg_config.h del /q src\include\pg_config.h
@@ -44,11 +45,24 @@ if %DIST%==1 if exist src\backend\parser\gram.h del /q src\backend\parser\gram.h
if exist src\include\utils\errcodes.h del /q src\include\utils\errcodes.h
if exist src\include\utils\fmgroids.h del /q src\include\utils\fmgroids.h
if exist src\include\utils\fmgrprotos.h del /q src\include\utils\fmgrprotos.h
+if exist src\include\storage\lwlocknames.h del /q src\include\storage\lwlocknames.h
if exist src\include\utils\probes.h del /q src\include\utils\probes.h
+if exist src\include\catalog\schemapg.h del /q src\include\catalog\schemapg.h
+if exist doc\src\sgml\version.sgml del /q doc\src\sgml\version.sgml
if %DIST%==1 if exist src\backend\utils\fmgroids.h del /q src\backend\utils\fmgroids.h
if %DIST%==1 if exist src\backend\utils\fmgrprotos.h del /q src\backend\utils\fmgrprotos.h
if %DIST%==1 if exist src\backend\utils\fmgrtab.c del /q src\backend\utils\fmgrtab.c
+if %DIST%==1 if exist src\backend\storage\lmgr\lwlocknames.c del /q src\backend\storage\lmgr\lwlocknames.c
+if %DIST%==1 if exist src\backend\storage\lmgr\lwlocknames.h del /q src\backend\storage\lmgr\lwlocknames.h
+if %DIST%==1 if exist src\pl\plpython\spiexceptions.h del /q src\pl\plpython\spiexceptions.h
+if %DIST%==1 if exist src\backend\utils\errcodes.h del /q src\backend\utils\errcodes.h
+if %DIST%==1 if exist src\pl\plpgsql\src\plerrcodes.h del /q src\pl\plpgsql\src\plerrcodes.h
+if %DIST%==1 if exist src\pl\tcl\pltclerrcodes.h del /q src\pl\tcl\pltclerrcodes.h
+if %DIST%==1 if exist src\backend\utils\sort\qsort_tuple.c del /q src\backend\utils\sort\qsort_tuple.c
+if %DIST%==1 if exist src\bin\psql\sql_help.c del /q src\bin\psql\sql_help.c
+if %DIST%==1 if exist src\bin\psql\sql_help.h del /q src\bin\psql\sql_help.h
+if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.y del /q src\interfaces\ecpg\preproc\preproc.y
if %DIST%==1 if exist src\backend\catalog\postgres.bki del /q src\backend\catalog\postgres.bki
if %DIST%==1 if exist src\backend\catalog\postgres.description del /q src\backend\catalog\postgres.description
if %DIST%==1 if exist src\backend\catalog\postgres.shdescription del /q src\backend\catalog\postgres.shdescription
@@ -58,10 +72,12 @@ if %DIST%==1 if exist src\backend\parser\gram.c del /q src\backend\parser\gram.c
if %DIST%==1 if exist src\backend\bootstrap\bootscanner.c del /q src\backend\bootstrap\bootscanner.c
if %DIST%==1 if exist src\backend\bootstrap\bootparse.c del /q src\backend\bootstrap\bootparse.c
if %DIST%==1 if exist src\backend\utils\misc\guc-file.c del /q src\backend\utils\misc\guc-file.c
+if %DIST%==1 if exist src\backend\replication\repl_scanner.c del /q src\backend\replication\repl_scanner.c
+if %DIST%==1 if exist src\backend\replication\repl_gram.c del /q src\backend\replication\repl_gram.c
+if %DIST%==1 if exist src\backend\replication\syncrep_scanner.c del /q src\backend\replication\syncrep_scanner.c
+if %DIST%==1 if exist src\backend\replication\syncrep_gram.c del /q src\backend\replication\syncrep_gram.c
-if exist src\bin\psql\sql_help.h del /q src\bin\psql\sql_help.h
-
if exist src\interfaces\libpq\libpq.rc del /q src\interfaces\libpq\libpq.rc
if exist src\interfaces\libpq\libpqdll.def del /q src\interfaces\libpq\libpqdll.def
if exist src\interfaces\ecpg\compatlib\compatlib.def del /q src\interfaces\ecpg\compatlib\compatlib.def
@@ -74,12 +90,17 @@ if %DIST%==1 if exist src\interfaces\ecpg\preproc\preproc.h del /q src\interface
if exist src\port\pg_config_paths.h del /q src\port\pg_config_paths.h
-if exist src\pl\plperl\spi.c del /q src\pl\plperl\spi.c
+if exist src\pl\plperl\SPI.c del /q src\pl\plperl\SPI.c
+if exist src\pl\plperl\Util.c del /q src\pl\plperl\Util.c
+if exist src\pl\plperl\perlchunks.h del /q src\pl\plperl\perlchunks.h
+if exist src\pl\plperl\plperl_opmask.h del /q src\pl\plperl\plperl_opmask.h
if %DIST%==1 if exist src\pl\plpgsql\src\pl_gram.c del /q src\pl\plpgsql\src\pl_gram.c
if %DIST%==1 if exist src\pl\plpgsql\src\pl_gram.h del /q src\pl\plpgsql\src\pl_gram.h
if %DIST%==1 if exist src\fe_utils\psqlscan.c del /q src\fe_utils\psqlscan.c
if %DIST%==1 if exist src\bin\psql\psqlscanslash.c del /q src\bin\psql\psqlscanslash.c
+if %DIST%==1 if exist src\bin\pgbench\exprscan.c del /q src\bin\pgbench\exprscan.c
+if %DIST%==1 if exist src\bin\pgbench\exprparse.c del /q src\bin\pgbench\exprparse.c
if %DIST%==1 if exist contrib\cube\cubescan.c del /q contrib\cube\cubescan.c
if %DIST%==1 if exist contrib\cube\cubeparse.c del /q contrib\cube\cubeparse.c
@@ -92,6 +113,8 @@ if exist contrib\spi\autoinc.dll del /q contrib\spi\autoinc.dll
if exist src\test\regress\regress.dll del /q src\test\regress\regress.dll
if exist src\test\regress\refint.dll del /q src\test\regress\refint.dll
if exist src\test\regress\autoinc.dll del /q src\test\regress\autoinc.dll
+if %DIST%==1 if exist src\test\isolation\specscanner.c del /q src\test\isolation\specscanner.c
+if %DIST%==1 if exist src\test\isolation\specparse.c del /q src\test\isolation\specparse.c
if exist src\bin\initdb\tmp_check rd /s /q src\bin\initdb\tmp_check
if exist src\bin\pg_basebackup\tmp_check rd /s /q src\bin\pg_basebackup\tmp_check
--
cgit v1.2.3
From 278cb4341103e967189997985b09981a73e23a34 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Mon, 24 Jul 2017 11:23:27 -0400
Subject: Be more consistent about errors for opfamily member lookup failures.
Add error checks in some places that were calling get_opfamily_member
or get_opfamily_proc and just assuming that the call could never fail.
Also, standardize the wording for such errors in some other places.
None of these errors are expected in normal use, hence they're just
elog not ereport. But they may be handy for diagnosing omissions in
custom opclasses.
Rushabh Lathia found the oversight in RelationBuildPartitionKey();
I found the others by grepping for all callers of these functions.
Discussion: https://postgr.es/m/CAGPqQf2R9Nk8htpv0FFi+FP776EwMyGuORpc9zYkZKC8sFQE3g@mail.gmail.com
---
src/backend/catalog/index.c | 4 ++++
src/backend/catalog/partition.c | 7 ++++---
src/backend/executor/execExpr.c | 3 +++
src/backend/executor/execReplication.c | 3 +--
src/backend/executor/nodeIndexscan.c | 3 +++
src/backend/optimizer/path/indxpath.c | 4 ++--
src/backend/optimizer/path/pathkeys.c | 4 ++--
src/backend/optimizer/plan/createplan.c | 7 ++++---
src/backend/utils/cache/relcache.c | 4 ++++
9 files changed, 27 insertions(+), 12 deletions(-)
(limited to 'src')
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 027abd56b0..d25b39bb54 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1738,6 +1738,10 @@ BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii)
index->rd_opcintype[i],
index->rd_opcintype[i],
ii->ii_UniqueStrats[i]);
+ if (!OidIsValid(ii->ii_UniqueOps[i]))
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
+ ii->ii_UniqueStrats[i], index->rd_opcintype[i],
+ index->rd_opcintype[i], index->rd_opfamily[i]);
ii->ii_UniqueProcs[i] = get_opcode(ii->ii_UniqueOps[i]);
}
}
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 74736e0ea1..e20ddce2db 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1187,14 +1187,15 @@ get_partition_operator(PartitionKey key, int col, StrategyNumber strategy,
key->partopcintype[col],
key->partopcintype[col],
strategy);
+ if (!OidIsValid(operoid))
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
+ strategy, key->partopcintype[col], key->partopcintype[col],
+ key->partopfamily[col]);
*need_relabel = true;
}
else
*need_relabel = false;
- if (!OidIsValid(operoid))
- elog(ERROR, "could not find operator for partitioning");
-
return operoid;
}
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 5267a011bb..7496189fab 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -1640,6 +1640,9 @@ ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state,
lefttype,
righttype,
BTORDER_PROC);
+ if (!OidIsValid(proc))
+ elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
+ BTORDER_PROC, lefttype, righttype, opfamily);
/* Set up the primary fmgr lookup information */
finfo = palloc0(sizeof(FmgrInfo));
diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c
index bc53d07c7d..3819de28ad 100644
--- a/src/backend/executor/execReplication.c
+++ b/src/backend/executor/execReplication.c
@@ -81,9 +81,8 @@ build_replindex_scan_key(ScanKey skey, Relation rel, Relation idxrel,
operator = get_opfamily_member(opfamily, optype,
optype,
BTEqualStrategyNumber);
-
if (!OidIsValid(operator))
- elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
BTEqualStrategyNumber, optype, optype, opfamily);
regop = get_opcode(operator);
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index d8aceb1f2c..75b10115f5 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -1367,6 +1367,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
op_lefttype,
op_righttype,
BTORDER_PROC);
+ if (!RegProcedureIsValid(opfuncid))
+ elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
+ BTORDER_PROC, op_lefttype, op_righttype, opfamily);
inputcollation = lfirst_oid(collids_cell);
collids_cell = lnext(collids_cell);
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index dedb9f521d..f35380391a 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -3978,13 +3978,13 @@ adjust_rowcompare_for_index(RowCompareExpr *clause,
expr_op = get_opfamily_member(opfam, lefttype, righttype,
op_strategy);
if (!OidIsValid(expr_op)) /* should not happen */
- elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
op_strategy, lefttype, righttype, opfam);
if (!var_on_left)
{
expr_op = get_commutator(expr_op);
if (!OidIsValid(expr_op)) /* should not happen */
- elog(ERROR, "could not find commutator of member %d(%u,%u) of opfamily %u",
+ elog(ERROR, "could not find commutator of operator %d(%u,%u) of opfamily %u",
op_strategy, lefttype, righttype, opfam);
}
new_ops = lappend_oid(new_ops, expr_op);
diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c
index 37cfa098d4..9d83a5ca62 100644
--- a/src/backend/optimizer/path/pathkeys.c
+++ b/src/backend/optimizer/path/pathkeys.c
@@ -197,8 +197,8 @@ make_pathkey_from_sortinfo(PlannerInfo *root,
opcintype,
BTEqualStrategyNumber);
if (!OidIsValid(equality_op)) /* shouldn't happen */
- elog(ERROR, "could not find equality operator for opfamily %u",
- opfamily);
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
+ BTEqualStrategyNumber, opcintype, opcintype, opfamily);
opfamilies = get_mergejoin_opfamilies(equality_op);
if (!opfamilies) /* certainly should find some */
elog(ERROR, "could not find opfamilies for equality operator %u",
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index e589d92c80..9d838e4f39 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -2634,7 +2634,8 @@ create_indexscan_plan(PlannerInfo *root,
exprtype,
pathkey->pk_strategy);
if (!OidIsValid(sortop))
- elog(ERROR, "failed to find sort operator for ORDER BY expression");
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
+ pathkey->pk_strategy, exprtype, exprtype, pathkey->pk_opfamily);
indexorderbyops = lappend_oid(indexorderbyops, sortop);
}
}
@@ -5738,7 +5739,7 @@ prepare_sort_from_pathkeys(Plan *lefttree, List *pathkeys,
pk_datatype,
pathkey->pk_strategy);
if (!OidIsValid(sortop)) /* should not happen */
- elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
pathkey->pk_strategy, pk_datatype, pk_datatype,
pathkey->pk_opfamily);
@@ -6216,7 +6217,7 @@ make_unique_from_pathkeys(Plan *lefttree, List *pathkeys, int numCols)
pk_datatype,
BTEqualStrategyNumber);
if (!OidIsValid(eqop)) /* should not happen */
- elog(ERROR, "could not find member %d(%u,%u) of opfamily %u",
+ elog(ERROR, "missing operator %d(%u,%u) in opfamily %u",
BTEqualStrategyNumber, pk_datatype, pk_datatype,
pathkey->pk_opfamily);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 43238dd8cb..6bd93b03d0 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -945,6 +945,10 @@ RelationBuildPartitionKey(Relation relation)
opclassform->opcintype,
opclassform->opcintype,
BTORDER_PROC);
+ if (!OidIsValid(funcid)) /* should not happen */
+ elog(ERROR, "missing support function %d(%u,%u) in opfamily %u",
+ BTORDER_PROC, opclassform->opcintype, opclassform->opcintype,
+ opclassform->opcfamily);
fmgr_info(funcid, &key->partsupfunc[i]);
--
cgit v1.2.3
From b4af9e3f378ef56fa48b98a0bfb641900b0280dc Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Mon, 24 Jul 2017 15:16:31 -0400
Subject: Ensure that pg_get_ruledef()'s output matches pg_get_viewdef()'s.
Various cases involving renaming of view columns are handled by having
make_viewdef pass down the view's current relation tupledesc to
get_query_def, which then takes care to use the column names from the
tupledesc for the output column names of the SELECT. For some reason
though, we'd missed teaching make_ruledef to do similarly when it is
printing an ON SELECT rule, even though this is exactly the same case.
The results from pg_get_ruledef would then be different and arguably wrong.
In particular, this breaks pre-v10 versions of pg_dump, which in some
situations would define views by means of emitting a CREATE RULE ... ON
SELECT command. Third-party tools might not be happy either.
In passing, clean up some crufty code in make_viewdef; we'd apparently
modernized the equivalent code in make_ruledef somewhere along the way,
and missed this copy.
Per report from Gilles Darold. Back-patch to all supported versions.
Discussion: https://postgr.es/m/ec05659a-40ff-4510-fc45-ca9d965d0838@dalibo.com
---
src/backend/utils/adt/ruleutils.c | 25 ++++++++++++++++++++-----
src/test/regress/expected/create_view.out | 29 +++++++++++++++++++++++++++++
src/test/regress/sql/create_view.sql | 11 +++++++++++
3 files changed, 60 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 493ba924a4..d83377d1d8 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -4590,6 +4590,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
char *ev_qual;
char *ev_action;
List *actions = NIL;
+ Relation ev_relation;
+ TupleDesc viewResultDesc = NULL;
int fno;
Datum dat;
bool isnull;
@@ -4626,6 +4628,8 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
if (ev_action != NULL)
actions = (List *) stringToNode(ev_action);
+ ev_relation = heap_open(ev_class, AccessShareLock);
+
/*
* Build the rules definition text
*/
@@ -4642,6 +4646,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
{
case '1':
appendStringInfoString(buf, "SELECT");
+ viewResultDesc = RelationGetDescr(ev_relation);
break;
case '2':
@@ -4731,7 +4736,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
foreach(action, actions)
{
query = (Query *) lfirst(action);
- get_query_def(query, buf, NIL, NULL,
+ get_query_def(query, buf, NIL, viewResultDesc,
prettyFlags, WRAP_COLUMN_DEFAULT, 0);
if (prettyFlags)
appendStringInfoString(buf, ";\n");
@@ -4749,10 +4754,12 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
Query *query;
query = (Query *) linitial(actions);
- get_query_def(query, buf, NIL, NULL,
+ get_query_def(query, buf, NIL, viewResultDesc,
prettyFlags, WRAP_COLUMN_DEFAULT, 0);
appendStringInfoChar(buf, ';');
}
+
+ heap_close(ev_relation, AccessShareLock);
}
@@ -4774,20 +4781,28 @@ make_viewdef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
List *actions = NIL;
Relation ev_relation;
int fno;
+ Datum dat;
bool isnull;
/*
* Get the attribute values from the rules tuple
*/
fno = SPI_fnumber(rulettc, "ev_type");
- ev_type = (char) SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ Assert(!isnull);
+ ev_type = DatumGetChar(dat);
fno = SPI_fnumber(rulettc, "ev_class");
- ev_class = (Oid) SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ Assert(!isnull);
+ ev_class = DatumGetObjectId(dat);
fno = SPI_fnumber(rulettc, "is_instead");
- is_instead = (bool) SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ dat = SPI_getbinval(ruletup, rulettc, fno, &isnull);
+ Assert(!isnull);
+ is_instead = DatumGetBool(dat);
+ /* these could be nulls */
fno = SPI_fnumber(rulettc, "ev_qual");
ev_qual = SPI_getvalue(ruletup, rulettc, fno);
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index c2da9add97..34f0b7641d 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1677,6 +1677,35 @@ select pg_get_viewdef('tt22v', true);
LEFT JOIN tt6 ON TRUE;
(1 row)
+-- check handling of views with immediately-renamed columns
+create view tt23v (col_a, col_b) as
+select q1 as other_name1, q2 as other_name2 from int8_tbl
+union
+select 42, 43;
+select pg_get_viewdef('tt23v', true);
+ pg_get_viewdef
+-------------------------------
+ SELECT int8_tbl.q1 AS col_a,+
+ int8_tbl.q2 AS col_b +
+ FROM int8_tbl +
+ UNION +
+ SELECT 42 AS col_a, +
+ 43 AS col_b;
+(1 row)
+
+select pg_get_ruledef(oid, true) from pg_rewrite
+ where ev_class = 'tt23v'::regclass and ev_type = '1';
+ pg_get_ruledef
+-----------------------------------------------------------------
+ CREATE RULE "_RETURN" AS +
+ ON SELECT TO tt23v DO INSTEAD SELECT int8_tbl.q1 AS col_a,+
+ int8_tbl.q2 AS col_b +
+ FROM int8_tbl +
+ UNION +
+ SELECT 42 AS col_a, +
+ 43 AS col_b;
+(1 row)
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 6e7463cf14..04941671dd 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -569,6 +569,17 @@ create view tt22v as
select * from tt5 natural left join tt6;
select pg_get_viewdef('tt22v', true);
+-- check handling of views with immediately-renamed columns
+
+create view tt23v (col_a, col_b) as
+select q1 as other_name1, q2 as other_name2 from int8_tbl
+union
+select 42, 43;
+
+select pg_get_viewdef('tt23v', true);
+select pg_get_ruledef(oid, true) from pg_rewrite
+ where ev_class = 'tt23v'::regclass and ev_type = '1';
+
-- clean up all the random objects we made above
set client_min_messages = warning;
DROP SCHEMA temp_view_test CASCADE;
--
cgit v1.2.3
From 7086be6e3627c1ad797e32ebbdd232905b5f577f Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Mon, 24 Jul 2017 15:57:24 -0400
Subject: When WCOs are present, disable direct foreign table modification.
If the user modifies a view that has CHECK OPTIONs and this gets
translated into a modification to an underlying relation which happens
to be a foreign table, the check options should be enforced. In the
normal code path, that was happening properly, but it was not working
properly for "direct" modification because the whole operation gets
pushed to the remote side in that case and we never have an option to
enforce the constraint against individual tuples. Fix by disabling
direct modification when there is a need to enforce CHECK OPTIONs.
Etsuro Fujita, reviewed by Kyotaro Horiguchi and by me.
Discussion: http://postgr.es/m/f8a48f54-6f02-9c8a-5250-9791603171ee@lab.ntt.co.jp
---
contrib/postgres_fdw/expected/postgres_fdw.out | 60 ++++++++++++++++++++++++++
contrib/postgres_fdw/sql/postgres_fdw.sql | 24 +++++++++++
doc/src/sgml/postgres-fdw.sgml | 6 ++-
src/backend/optimizer/plan/createplan.c | 7 ++-
4 files changed, 93 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 5bb3d97401..c19b3318c7 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -5894,6 +5894,66 @@ INSERT INTO ft1(c1, c2) VALUES(1111, 2);
UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
-- ===================================================================
+-- test WITH CHECK OPTION constraints
+-- ===================================================================
+CREATE TABLE base_tbl (a int, b int);
+CREATE FOREIGN TABLE foreign_tbl (a int, b int)
+ SERVER loopback OPTIONS(table_name 'base_tbl');
+CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
+ WHERE a < b WITH CHECK OPTION;
+\d+ rw_view
+ View "public.rw_view"
+ Column | Type | Collation | Nullable | Default | Storage | Description
+--------+---------+-----------+----------+---------+---------+-------------
+ a | integer | | | | plain |
+ b | integer | | | | plain |
+View definition:
+ SELECT foreign_tbl.a,
+ foreign_tbl.b
+ FROM foreign_tbl
+ WHERE foreign_tbl.a < foreign_tbl.b;
+Options: check_option=cascaded
+
+INSERT INTO rw_view VALUES (0, 10); -- ok
+INSERT INTO rw_view VALUES (10, 0); -- should fail
+ERROR: new row violates check option for view "rw_view"
+DETAIL: Failing row contains (10, 0).
+EXPLAIN (VERBOSE, COSTS OFF)
+UPDATE rw_view SET b = 20 WHERE a = 0; -- not pushed down
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------
+ Update on public.foreign_tbl
+ Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1
+ -> Foreign Scan on public.foreign_tbl
+ Output: foreign_tbl.a, 20, foreign_tbl.ctid
+ Remote SQL: SELECT a, ctid FROM public.base_tbl WHERE ((a < b)) AND ((a = 0)) FOR UPDATE
+(5 rows)
+
+UPDATE rw_view SET b = 20 WHERE a = 0; -- ok
+EXPLAIN (VERBOSE, COSTS OFF)
+UPDATE rw_view SET b = -20 WHERE a = 0; -- not pushed down
+ QUERY PLAN
+--------------------------------------------------------------------------------------------------
+ Update on public.foreign_tbl
+ Remote SQL: UPDATE public.base_tbl SET b = $2 WHERE ctid = $1
+ -> Foreign Scan on public.foreign_tbl
+ Output: foreign_tbl.a, '-20'::integer, foreign_tbl.ctid
+ Remote SQL: SELECT a, ctid FROM public.base_tbl WHERE ((a < b)) AND ((a = 0)) FOR UPDATE
+(5 rows)
+
+UPDATE rw_view SET b = -20 WHERE a = 0; -- should fail
+ERROR: new row violates check option for view "rw_view"
+DETAIL: Failing row contains (0, -20).
+SELECT * FROM foreign_tbl;
+ a | b
+---+----
+ 0 | 20
+(1 row)
+
+DROP FOREIGN TABLE foreign_tbl CASCADE;
+NOTICE: drop cascades to view rw_view
+DROP TABLE base_tbl;
+-- ===================================================================
-- test serial columns (ie, sequence-based defaults)
-- ===================================================================
create table loc1 (f1 serial, f2 text);
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index bb92189b0e..5f65d9d966 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -1180,6 +1180,30 @@ INSERT INTO ft1(c1, c2) VALUES(1111, 2);
UPDATE ft1 SET c2 = c2 + 1 WHERE c1 = 1;
ALTER FOREIGN TABLE ft1 DROP CONSTRAINT ft1_c2negative;
+-- ===================================================================
+-- test WITH CHECK OPTION constraints
+-- ===================================================================
+
+CREATE TABLE base_tbl (a int, b int);
+CREATE FOREIGN TABLE foreign_tbl (a int, b int)
+ SERVER loopback OPTIONS(table_name 'base_tbl');
+CREATE VIEW rw_view AS SELECT * FROM foreign_tbl
+ WHERE a < b WITH CHECK OPTION;
+\d+ rw_view
+
+INSERT INTO rw_view VALUES (0, 10); -- ok
+INSERT INTO rw_view VALUES (10, 0); -- should fail
+EXPLAIN (VERBOSE, COSTS OFF)
+UPDATE rw_view SET b = 20 WHERE a = 0; -- not pushed down
+UPDATE rw_view SET b = 20 WHERE a = 0; -- ok
+EXPLAIN (VERBOSE, COSTS OFF)
+UPDATE rw_view SET b = -20 WHERE a = 0; -- not pushed down
+UPDATE rw_view SET b = -20 WHERE a = 0; -- should fail
+SELECT * FROM foreign_tbl;
+
+DROP FOREIGN TABLE foreign_tbl CASCADE;
+DROP TABLE base_tbl;
+
-- ===================================================================
-- test serial columns (ie, sequence-based defaults)
-- ===================================================================
diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml
index 23558e7ec0..d83fc9e52b 100644
--- a/doc/src/sgml/postgres-fdw.sgml
+++ b/doc/src/sgml/postgres-fdw.sgml
@@ -498,8 +498,10 @@
postgres_fdw> attempts to optimize the query execution by
sending the whole query to the remote server if there are no query
WHERE> clauses that cannot be sent to the remote server,
- no local joins for the query, and no row-level local BEFORE> or
- AFTER> triggers on the target table. In UPDATE>,
+ no local joins for the query, no row-level local BEFORE> or
+ AFTER> triggers on the target table, and no
+ CHECK OPTION> constraints from parent views.
+ In UPDATE>,
expressions to assign to target columns must use only built-in data types,
IMMUTABLE> operators, or IMMUTABLE> functions,
to reduce the risk of misexecution of the query.
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 9d838e4f39..5c934f223d 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -6500,8 +6500,10 @@ make_modifytable(PlannerInfo *root,
}
/*
- * If the target foreign table has any row-level triggers, we can't
- * modify the foreign table directly.
+ * Try to modify the foreign table directly if (1) the FDW provides
+ * callback functions needed for that, (2) there are no row-level
+ * triggers on the foreign table, and (3) there are no WITH CHECK
+ * OPTIONs from parent views.
*/
direct_modify = false;
if (fdwroutine != NULL &&
@@ -6509,6 +6511,7 @@ make_modifytable(PlannerInfo *root,
fdwroutine->BeginDirectModify != NULL &&
fdwroutine->IterateDirectModify != NULL &&
fdwroutine->EndDirectModify != NULL &&
+ withCheckOptionLists == NIL &&
!has_row_triggers(root, rti, operation))
direct_modify = fdwroutine->PlanDirectModify(root, node, rti, i);
if (direct_modify)
--
cgit v1.2.3
From e2c8100e60729368c84e9a49ada9b44df5a1b851 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Mon, 24 Jul 2017 16:45:46 -0400
Subject: Fix race condition in predicate-lock init code in EXEC_BACKEND
builds.
Trading a little too heavily on letting the code path be the same whether
we were creating shared data structures or only attaching to them,
InitPredicateLocks() inserted the "scratch" PredicateLockTargetHash entry
unconditionally. This is just wrong if we're in a postmaster child,
which would only reach this code in EXEC_BACKEND builds. Most of the
time, the hash_search(HASH_ENTER) call would simply report that the
entry already existed, causing no visible effect since the code did not
bother to check for that possibility. However, if this happened while
some other backend had transiently removed the "scratch" entry, then
that other backend's eventual RestoreScratchTarget would suffer an
assert failure; this appears to be the explanation for a recent failure
on buildfarm member culicidae. In non-assert builds, there would be
no visible consequences there either. But nonetheless this is a pretty
bad bug for EXEC_BACKEND builds, for two reasons:
1. Each new backend would perform the hash_search(HASH_ENTER) call
without holding any lock that would prevent concurrent access to the
PredicateLockTargetHash hash table. This creates a low but certainly
nonzero risk of corruption of that hash table.
2. In the event that the race condition occurred, by reinserting the
scratch entry too soon, we were defeating the entire purpose of the
scratch entry, namely to guarantee that transaction commit could move
hash table entries around with no risk of out-of-memory failure.
The odds of an actual OOM failure are quite low, but not zero, and if
it did happen it would again result in corruption of the hash table.
The user-visible symptoms of such corruption are a little hard to predict,
but would presumably amount to misbehavior of SERIALIZABLE transactions
that'd require a crash or postmaster restart to fix.
To fix, just skip the hash insertion if IsUnderPostmaster. I also
inserted a bunch of assertions that the expected things happen
depending on whether IsUnderPostmaster is true. That might be overkill,
since most comparable code in other functions isn't quite that paranoid,
but once burnt twice shy.
In passing, also move a couple of lines to places where they seemed
to make more sense.
Diagnosis of problem by Thomas Munro, patch by me. Back-patch to
all supported branches.
Discussion: https://postgr.es/m/10593.1500670709@sss.pgh.pa.us
---
src/backend/storage/lmgr/predicate.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index a4cb4d33ad..74e4b35837 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -815,6 +815,7 @@ OldSerXidInit(void)
oldSerXidControl = (OldSerXidControl)
ShmemInitStruct("OldSerXidControlData", sizeof(OldSerXidControlData), &found);
+ Assert(found == IsUnderPostmaster);
if (!found)
{
/*
@@ -1109,6 +1110,10 @@ InitPredicateLocks(void)
Size requestSize;
bool found;
+#ifndef EXEC_BACKEND
+ Assert(!IsUnderPostmaster);
+#endif
+
/*
* Compute size of predicate lock target hashtable. Note these
* calculations must agree with PredicateLockShmemSize!
@@ -1131,16 +1136,22 @@ InitPredicateLocks(void)
HASH_ELEM | HASH_BLOBS |
HASH_PARTITION | HASH_FIXED_SIZE);
- /* Assume an average of 2 xacts per target */
- max_table_size *= 2;
-
/*
* Reserve a dummy entry in the hash table; we use it to make sure there's
* always one entry available when we need to split or combine a page,
* because running out of space there could mean aborting a
* non-serializable transaction.
*/
- hash_search(PredicateLockTargetHash, &ScratchTargetTag, HASH_ENTER, NULL);
+ if (!IsUnderPostmaster)
+ {
+ (void) hash_search(PredicateLockTargetHash, &ScratchTargetTag,
+ HASH_ENTER, &found);
+ Assert(!found);
+ }
+
+ /* Pre-calculate the hash and partition lock of the scratch entry */
+ ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
+ ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
/*
* Allocate hash table for PREDICATELOCK structs. This stores per
@@ -1152,6 +1163,9 @@ InitPredicateLocks(void)
info.hash = predicatelock_hash;
info.num_partitions = NUM_PREDICATELOCK_PARTITIONS;
+ /* Assume an average of 2 xacts per target */
+ max_table_size *= 2;
+
PredicateLockHash = ShmemInitHash("PREDICATELOCK hash",
max_table_size,
max_table_size,
@@ -1178,6 +1192,7 @@ InitPredicateLocks(void)
PredXact = ShmemInitStruct("PredXactList",
PredXactListDataSize,
&found);
+ Assert(found == IsUnderPostmaster);
if (!found)
{
int i;
@@ -1250,6 +1265,7 @@ InitPredicateLocks(void)
RWConflictPool = ShmemInitStruct("RWConflictPool",
RWConflictPoolHeaderDataSize,
&found);
+ Assert(found == IsUnderPostmaster);
if (!found)
{
int i;
@@ -1275,6 +1291,7 @@ InitPredicateLocks(void)
ShmemInitStruct("FinishedSerializableTransactions",
sizeof(SHM_QUEUE),
&found);
+ Assert(found == IsUnderPostmaster);
if (!found)
SHMQueueInit(FinishedSerializableTransactions);
@@ -1283,10 +1300,6 @@ InitPredicateLocks(void)
* transactions.
*/
OldSerXidInit();
-
- /* Pre-calculate the hash and partition lock of the scratch entry */
- ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
- ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
}
/*
--
cgit v1.2.3
From 4132dbec69dd4d437e132e57a74a98a40cdcf776 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Mon, 24 Jul 2017 18:08:08 -0400
Subject: Fix partitioning crashes during error reporting.
In various places where we reverse-map a tuple before calling
ExecBuildSlotValueDescription, we neglected to ensure that the
slot descriptor matched the tuple stored in it.
Amit Langote and Amit Khandekar, reviewed by Etsuro Fujita
Discussion: http://postgr.es/m/CAJ3gD9cqpP=WvJj=dv1ONkPWjy8ZuUaOM4_x86i3uQPas=0_jg@mail.gmail.com
---
src/backend/executor/execMain.c | 4 ++++
src/test/regress/expected/insert.out | 15 +++++++++++++++
src/test/regress/expected/updatable_views.out | 15 ++++++++-------
src/test/regress/sql/insert.sql | 12 ++++++++++++
src/test/regress/sql/updatable_views.sql | 4 ++--
5 files changed, 41 insertions(+), 9 deletions(-)
(limited to 'src')
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index b22de78516..78cbcd1a32 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1879,6 +1879,7 @@ ExecPartitionCheck(ResultRelInfo *resultRelInfo, TupleTableSlot *slot,
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
+ ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
@@ -1956,6 +1957,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
+ ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
@@ -2003,6 +2005,7 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
+ ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
@@ -2112,6 +2115,7 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
if (map != NULL)
{
tuple = do_convert_tuple(tuple, map);
+ ExecSetSlotDescriptor(slot, tupdesc);
ExecStoreTuple(tuple, slot, InvalidBuffer, false);
}
}
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index c608ce377f..0dcc86fef4 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -410,6 +410,21 @@ with ins (a, b, c) as
mlparted4 | 1 | 30 | 39
(5 rows)
+alter table mlparted add c text;
+create table mlparted5 (c text, a int not null, b int not null) partition by list (c);
+create table mlparted5a (a int not null, c text, b int not null);
+alter table mlparted5 attach partition mlparted5a for values in ('a');
+alter table mlparted attach partition mlparted5 for values from (1, 40) to (1, 50);
+alter table mlparted add constraint check_b check (a = 1 and b < 45);
+insert into mlparted values (1, 45, 'a');
+ERROR: new row for relation "mlparted5a" violates check constraint "check_b"
+DETAIL: Failing row contains (1, 45, a).
+create function mlparted5abrtrig_func() returns trigger as $$ begin new.c = 'b'; return new; end; $$ language plpgsql;
+create trigger mlparted5abrtrig before insert on mlparted5a for each row execute procedure mlparted5abrtrig_func();
+insert into mlparted5 (a, b, c) values (1, 40, 'a');
+ERROR: new row for relation "mlparted5a" violates partition constraint
+DETAIL: Failing row contains (b, 1, 40).
+drop table mlparted5;
-- check that message shown after failure to find a partition shows the
-- appropriate key description (or none) in various situations
create table key_desc (a int, b int) partition by list ((a+0));
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index caca81a70b..eab5c0334c 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -2368,8 +2368,8 @@ DETAIL: Failing row contains (-1, invalid).
DROP VIEW v1;
DROP TABLE t1;
-- check that an auto-updatable view on a partitioned table works correctly
-create table pt (a int, b int) partition by range (a, b);
-create table pt1 (b int not null, a int not null) partition by range (b);
+create table pt (a int, b int, v varchar) partition by range (a, b);
+create table pt1 (b int not null, v varchar, a int not null) partition by range (b);
create table pt11 (like pt1);
alter table pt11 drop a;
alter table pt11 add a int;
@@ -2412,18 +2412,19 @@ select table_name, column_name, is_updatable
------------+-------------+--------------
ptv | a | YES
ptv | b | YES
-(2 rows)
+ ptv | v | YES
+(3 rows)
insert into ptv values (1, 2);
select tableoid::regclass, * from pt;
- tableoid | a | b
-----------+---+---
- pt11 | 1 | 2
+ tableoid | a | b | v
+----------+---+---+---
+ pt11 | 1 | 2 |
(1 row)
create view ptv_wco as select * from pt where a = 0 with check option;
insert into ptv_wco values (1, 2);
ERROR: new row violates check option for view "ptv_wco"
-DETAIL: Failing row contains (1, 2).
+DETAIL: Failing row contains (1, 2, null).
drop view ptv, ptv_wco;
drop table pt, pt1, pt11;
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index 7666a7d6ca..6adf25da40 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -263,6 +263,18 @@ with ins (a, b, c) as
(insert into mlparted (b, a) select s.a, 1 from generate_series(2, 39) s(a) returning tableoid::regclass, *)
select a, b, min(c), max(c) from ins group by a, b order by 1;
+alter table mlparted add c text;
+create table mlparted5 (c text, a int not null, b int not null) partition by list (c);
+create table mlparted5a (a int not null, c text, b int not null);
+alter table mlparted5 attach partition mlparted5a for values in ('a');
+alter table mlparted attach partition mlparted5 for values from (1, 40) to (1, 50);
+alter table mlparted add constraint check_b check (a = 1 and b < 45);
+insert into mlparted values (1, 45, 'a');
+create function mlparted5abrtrig_func() returns trigger as $$ begin new.c = 'b'; return new; end; $$ language plpgsql;
+create trigger mlparted5abrtrig before insert on mlparted5a for each row execute procedure mlparted5abrtrig_func();
+insert into mlparted5 (a, b, c) values (1, 40, 'a');
+drop table mlparted5;
+
-- check that message shown after failure to find a partition shows the
-- appropriate key description (or none) in various situations
create table key_desc (a int, b int) partition by list ((a+0));
diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql
index 6a9958d38b..2ede44c02b 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -1114,8 +1114,8 @@ DROP VIEW v1;
DROP TABLE t1;
-- check that an auto-updatable view on a partitioned table works correctly
-create table pt (a int, b int) partition by range (a, b);
-create table pt1 (b int not null, a int not null) partition by range (b);
+create table pt (a int, b int, v varchar) partition by range (a, b);
+create table pt1 (b int not null, v varchar, a int not null) partition by range (b);
create table pt11 (like pt1);
alter table pt11 drop a;
alter table pt11 add a int;
--
cgit v1.2.3
From 9915de6c1cb2c9b87f5f504c97832cdf3a809753 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Tue, 25 Jul 2017 13:26:49 -0400
Subject: Fix race conditions in replication slot operations
It is relatively easy to get a replication slot to look as still active
while one process is in the process of getting rid of it; when some
other process tries to "acquire" the slot, it would fail with an error
message of "replication slot XYZ is active for PID N".
The error message in itself is fine, except that when the intention is
to drop the slot, it is unhelpful: the useful behavior would be to wait
until the slot is no longer acquired, so that the drop can proceed. To
implement this, we use a condition variable so that slot acquisition can
be told to wait on that condition variable if the slot is already
acquired, and we make any change in active_pid broadcast a signal on the
condition variable. Thus, as soon as the slot is released, the drop
will proceed properly.
Reported by: Tom Lane
Discussion: https://postgr.es/m/11904.1499039688@sss.pgh.pa.us
Authors: Petr Jelínek, Álvaro Herrera
---
src/backend/replication/logical/logicalfuncs.c | 2 +-
src/backend/replication/slot.c | 122 ++++++++++++++++++-------
src/backend/replication/slotfuncs.c | 34 ++++---
src/backend/replication/walsender.c | 6 +-
src/include/replication/slot.h | 10 +-
5 files changed, 118 insertions(+), 56 deletions(-)
(limited to 'src')
diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c
index 363ca82cb0..a3ba2b1266 100644
--- a/src/backend/replication/logical/logicalfuncs.c
+++ b/src/backend/replication/logical/logicalfuncs.c
@@ -244,7 +244,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
else
end_of_wal = GetXLogReplayRecPtr(&ThisTimeLineID);
- ReplicationSlotAcquire(NameStr(*name));
+ ReplicationSlotAcquire(NameStr(*name), true);
PG_TRY();
{
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index dc7de20e11..08c0b1b285 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -157,6 +157,7 @@ ReplicationSlotsShmemInit(void)
/* everything else is zeroed by the memset above */
SpinLockInit(&slot->mutex);
LWLockInitialize(&slot->io_in_progress_lock, LWTRANCHE_REPLICATION_SLOT_IO_IN_PROGRESS);
+ ConditionVariableInit(&slot->active_cv);
}
}
}
@@ -313,25 +314,35 @@ ReplicationSlotCreate(const char *name, bool db_specific,
LWLockRelease(ReplicationSlotControlLock);
/*
- * Now that the slot has been marked as in_use and in_active, it's safe to
+ * Now that the slot has been marked as in_use and active, it's safe to
* let somebody else try to allocate a slot.
*/
LWLockRelease(ReplicationSlotAllocationLock);
+
+ /* Let everybody know we've modified this slot */
+ ConditionVariableBroadcast(&slot->active_cv);
}
/*
* Find a previously created slot and mark it as used by this backend.
*/
void
-ReplicationSlotAcquire(const char *name)
+ReplicationSlotAcquire(const char *name, bool nowait)
{
- ReplicationSlot *slot = NULL;
+ ReplicationSlot *slot;
+ int active_pid;
int i;
- int active_pid = 0; /* Keep compiler quiet */
+retry:
Assert(MyReplicationSlot == NULL);
- /* Search for the named slot and mark it active if we find it. */
+ /*
+ * Search for the named slot and mark it active if we find it. If the
+ * slot is already active, we exit the loop with active_pid set to the PID
+ * of the backend that owns it.
+ */
+ active_pid = 0;
+ slot = NULL;
LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
for (i = 0; i < max_replication_slots; i++)
{
@@ -339,35 +350,66 @@ ReplicationSlotAcquire(const char *name)
if (s->in_use && strcmp(name, NameStr(s->data.name)) == 0)
{
+ /*
+ * This is the slot we want. We don't know yet if it's active,
+ * so get ready to sleep on it in case it is. (We may end up not
+ * sleeping, but we don't want to do this while holding the
+ * spinlock.)
+ */
+ ConditionVariablePrepareToSleep(&s->active_cv);
+
SpinLockAcquire(&s->mutex);
+
active_pid = s->active_pid;
if (active_pid == 0)
active_pid = s->active_pid = MyProcPid;
+
SpinLockRelease(&s->mutex);
slot = s;
+
break;
}
}
LWLockRelease(ReplicationSlotControlLock);
- /* If we did not find the slot or it was already active, error out. */
+ /* If we did not find the slot, error out. */
if (slot == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("replication slot \"%s\" does not exist", name)));
+
+ /*
+ * If we found the slot but it's already active in another backend, we
+ * either error out or retry after a short wait, as caller specified.
+ */
if (active_pid != MyProcPid)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_IN_USE),
- errmsg("replication slot \"%s\" is active for PID %d",
- name, active_pid)));
+ {
+ if (nowait)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_IN_USE),
+ errmsg("replication slot \"%s\" is active for PID %d",
+ name, active_pid)));
+
+ /* Wait here until we get signaled, and then restart */
+ ConditionVariableSleep(&slot->active_cv, PG_WAIT_LOCK);
+ ConditionVariableCancelSleep();
+ goto retry;
+ }
+ else
+ ConditionVariableCancelSleep(); /* no sleep needed after all */
+
+ /* Let everybody know we've modified this slot */
+ ConditionVariableBroadcast(&slot->active_cv);
/* We made this slot active, so it's ours now. */
MyReplicationSlot = slot;
}
/*
- * Release a replication slot, this or another backend can ReAcquire it
- * later. Resources this slot requires will be preserved.
+ * Release the replication slot that this backend considers to own.
+ *
+ * This or another backend can re-acquire the slot later.
+ * Resources this slot requires will be preserved.
*/
void
ReplicationSlotRelease(void)
@@ -385,17 +427,6 @@ ReplicationSlotRelease(void)
*/
ReplicationSlotDropAcquired();
}
- else if (slot->data.persistency == RS_PERSISTENT)
- {
- /*
- * Mark persistent slot inactive. We're not freeing it, just
- * disconnecting.
- */
- SpinLockAcquire(&slot->mutex);
- slot->active_pid = 0;
- SpinLockRelease(&slot->mutex);
- }
-
/*
* If slot needed to temporarily restrain both data and catalog xmin to
@@ -412,6 +443,18 @@ ReplicationSlotRelease(void)
ReplicationSlotsComputeRequiredXmin(false);
}
+ if (slot->data.persistency == RS_PERSISTENT)
+ {
+ /*
+ * Mark persistent slot inactive. We're not freeing it, just
+ * disconnecting, but wake up others that may be waiting for it.
+ */
+ SpinLockAcquire(&slot->mutex);
+ slot->active_pid = 0;
+ SpinLockRelease(&slot->mutex);
+ ConditionVariableBroadcast(&slot->active_cv);
+ }
+
MyReplicationSlot = NULL;
/* might not have been set when we've been a plain slot */
@@ -430,32 +473,43 @@ ReplicationSlotCleanup(void)
Assert(MyReplicationSlot == NULL);
- /*
- * No need for locking as we are only interested in slots active in
- * current process and those are not touched by other processes.
- */
+restart:
+ LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
for (i = 0; i < max_replication_slots; i++)
{
ReplicationSlot *s = &ReplicationSlotCtl->replication_slots[i];
+ if (!s->in_use)
+ continue;
+
+ SpinLockAcquire(&s->mutex);
if (s->active_pid == MyProcPid)
{
- Assert(s->in_use && s->data.persistency == RS_TEMPORARY);
+ Assert(s->data.persistency == RS_TEMPORARY);
+ SpinLockRelease(&s->mutex);
+ LWLockRelease(ReplicationSlotControlLock); /* avoid deadlock */
ReplicationSlotDropPtr(s);
+
+ ConditionVariableBroadcast(&s->active_cv);
+ goto restart;
}
+ else
+ SpinLockRelease(&s->mutex);
}
+
+ LWLockRelease(ReplicationSlotControlLock);
}
/*
* Permanently drop replication slot identified by the passed in name.
*/
void
-ReplicationSlotDrop(const char *name)
+ReplicationSlotDrop(const char *name, bool nowait)
{
Assert(MyReplicationSlot == NULL);
- ReplicationSlotAcquire(name);
+ ReplicationSlotAcquire(name, nowait);
ReplicationSlotDropAcquired();
}
@@ -527,6 +581,9 @@ ReplicationSlotDropPtr(ReplicationSlot *slot)
slot->active_pid = 0;
SpinLockRelease(&slot->mutex);
+ /* wake up anyone waiting on this slot */
+ ConditionVariableBroadcast(&slot->active_cv);
+
ereport(fail_softly ? WARNING : ERROR,
(errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\": %m",
@@ -535,15 +592,18 @@ ReplicationSlotDropPtr(ReplicationSlot *slot)
/*
* The slot is definitely gone. Lock out concurrent scans of the array
- * long enough to kill it. It's OK to clear the active flag here without
+ * long enough to kill it. It's OK to clear the active PID here without
* grabbing the mutex because nobody else can be scanning the array here,
* and nobody can be attached to this slot and thus access it without
* scanning the array.
+ *
+ * Also wake up processes waiting for it.
*/
LWLockAcquire(ReplicationSlotControlLock, LW_EXCLUSIVE);
slot->active_pid = 0;
slot->in_use = false;
LWLockRelease(ReplicationSlotControlLock);
+ ConditionVariableBroadcast(&slot->active_cv);
/*
* Slot is dead and doesn't prevent resource removal anymore, recompute
diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c
index 6dc808874d..d4cbd83bde 100644
--- a/src/backend/replication/slotfuncs.c
+++ b/src/backend/replication/slotfuncs.c
@@ -171,7 +171,7 @@ pg_drop_replication_slot(PG_FUNCTION_ARGS)
CheckSlotRequirements();
- ReplicationSlotDrop(NameStr(*name));
+ ReplicationSlotDrop(NameStr(*name), false);
PG_RETURN_VOID();
}
@@ -221,6 +221,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext);
+ LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
for (slotno = 0; slotno < max_replication_slots; slotno++)
{
ReplicationSlot *slot = &ReplicationSlotCtl->replication_slots[slotno];
@@ -238,25 +239,21 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
NameData plugin;
int i;
- SpinLockAcquire(&slot->mutex);
if (!slot->in_use)
- {
- SpinLockRelease(&slot->mutex);
continue;
- }
- else
- {
- xmin = slot->data.xmin;
- catalog_xmin = slot->data.catalog_xmin;
- database = slot->data.database;
- restart_lsn = slot->data.restart_lsn;
- confirmed_flush_lsn = slot->data.confirmed_flush;
- namecpy(&slot_name, &slot->data.name);
- namecpy(&plugin, &slot->data.plugin);
-
- active_pid = slot->active_pid;
- persistency = slot->data.persistency;
- }
+
+ SpinLockAcquire(&slot->mutex);
+
+ xmin = slot->data.xmin;
+ catalog_xmin = slot->data.catalog_xmin;
+ database = slot->data.database;
+ restart_lsn = slot->data.restart_lsn;
+ confirmed_flush_lsn = slot->data.confirmed_flush;
+ namecpy(&slot_name, &slot->data.name);
+ namecpy(&plugin, &slot->data.plugin);
+ active_pid = slot->active_pid;
+ persistency = slot->data.persistency;
+
SpinLockRelease(&slot->mutex);
memset(nulls, 0, sizeof(nulls));
@@ -309,6 +306,7 @@ pg_get_replication_slots(PG_FUNCTION_ARGS)
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
+ LWLockRelease(ReplicationSlotControlLock);
tuplestore_donestoring(tupstore);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 002143b26a..9a2babef1e 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -541,7 +541,7 @@ StartReplication(StartReplicationCmd *cmd)
if (cmd->slotname)
{
- ReplicationSlotAcquire(cmd->slotname);
+ ReplicationSlotAcquire(cmd->slotname, true);
if (SlotIsLogical(MyReplicationSlot))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -1028,7 +1028,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
static void
DropReplicationSlot(DropReplicationSlotCmd *cmd)
{
- ReplicationSlotDrop(cmd->slotname);
+ ReplicationSlotDrop(cmd->slotname, false);
EndCommand("DROP_REPLICATION_SLOT", DestRemote);
}
@@ -1046,7 +1046,7 @@ StartLogicalReplication(StartReplicationCmd *cmd)
Assert(!MyReplicationSlot);
- ReplicationSlotAcquire(cmd->slotname);
+ ReplicationSlotAcquire(cmd->slotname, true);
/*
* Force a disconnect, so that the decoding code doesn't need to care
diff --git a/src/include/replication/slot.h b/src/include/replication/slot.h
index a283f4e2b8..0bf2611fe9 100644
--- a/src/include/replication/slot.h
+++ b/src/include/replication/slot.h
@@ -12,6 +12,7 @@
#include "fmgr.h"
#include "access/xlog.h"
#include "access/xlogreader.h"
+#include "storage/condition_variable.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/spin.h"
@@ -19,7 +20,7 @@
/*
* Behaviour of replication slots, upon release or crash.
*
- * Slots marked as PERSISTENT are crashsafe and will not be dropped when
+ * Slots marked as PERSISTENT are crash-safe and will not be dropped when
* released. Slots marked as EPHEMERAL will be dropped when released or after
* restarts.
*
@@ -117,6 +118,9 @@ typedef struct ReplicationSlot
/* is somebody performing io on this slot? */
LWLock io_in_progress_lock;
+ /* Condition variable signalled when active_pid changes */
+ ConditionVariable active_cv;
+
/* all the remaining data is only used for logical slots */
/*
@@ -162,9 +166,9 @@ extern void ReplicationSlotsShmemInit(void);
extern void ReplicationSlotCreate(const char *name, bool db_specific,
ReplicationSlotPersistency p);
extern void ReplicationSlotPersist(void);
-extern void ReplicationSlotDrop(const char *name);
+extern void ReplicationSlotDrop(const char *name, bool nowait);
-extern void ReplicationSlotAcquire(const char *name);
+extern void ReplicationSlotAcquire(const char *name, bool nowait);
extern void ReplicationSlotRelease(void);
extern void ReplicationSlotCleanup(void);
extern void ReplicationSlotSave(void);
--
cgit v1.2.3
From 54dacc746628799a3a09ebb78876b0a8d2742d23 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Tue, 25 Jul 2017 18:39:44 -0400
Subject: Make PostgresNode easily subclassable
This module becomes much more useful if we allow it to be used as base
class for external projects. To achieve this, change the exported
get_new_node function into a class method instead, and use the standard
Perl idiom of accepting the class as first argument. This method works
as expected for subclasses. The standalone function is kept for
backwards compatibility, though it could be removed in pg11.
Author: Chap Flackman, based on an earlier patch from Craig Ringer
Discussion: https://postgr.es/m/CAMsr+YF8kO+4+K-_U4PtN==2FndJ+5Bn6A19XHhMiBykEwv0wA@mail.gmail.com
---
src/test/perl/PostgresNode.pm | 20 ++++++++++++--------
src/test/perl/README | 2 +-
2 files changed, 13 insertions(+), 9 deletions(-)
(limited to 'src')
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index d87296af08..bf982101a5 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -9,7 +9,7 @@ PostgresNode - class representing PostgreSQL server instance
use PostgresNode;
- my $node = get_new_node('mynode');
+ my $node = PostgresNode->get_new_node('mynode');
# Create a data directory with initdb
$node->init();
@@ -855,20 +855,24 @@ sub _update_pid
=pod
-=item get_new_node(node_name)
+=item PostgresNode->get_new_node(node_name)
-Build a new PostgresNode object, assigning a free port number. Standalone
-function that's automatically imported.
+Build a new object of class C (or of a subclass, if you have
+one), assigning a free port number. Remembers the node, to prevent its port
+number from being reused for another node, and to ensure that it gets
+shut down when the test script exits.
-Remembers the node, to prevent its port number from being reused for another
-node, and to ensure that it gets shut down when the test script exits.
+You should generally use this instead of C.
-You should generally use this instead of PostgresNode::new(...).
+For backwards compatibility, it is also exported as a standalone function,
+which can only create objects of class C.
=cut
sub get_new_node
{
+ my $class = 'PostgresNode';
+ $class = shift if 1 < scalar @_;
my $name = shift;
my $found = 0;
my $port = $last_port_assigned;
@@ -913,7 +917,7 @@ sub get_new_node
print "# Found free port $port\n";
# Lock port number found by creating a new node
- my $node = new PostgresNode($name, $test_pghost, $port);
+ my $node = $class->new($name, $test_pghost, $port);
# Add node to list of nodes
push(@all_nodes, $node);
diff --git a/src/test/perl/README b/src/test/perl/README
index cc6edfb383..c61c3f5e94 100644
--- a/src/test/perl/README
+++ b/src/test/perl/README
@@ -48,7 +48,7 @@ Each test script should begin with:
then it will generally need to set up one or more nodes, run commands
against them and evaluate the results. For example:
- my $node = get_new_node('master');
+ my $node = PostgresNode->get_new_node('master');
$node->init;
$node->start;
--
cgit v1.2.3
From c28e4f4dc6aeb75cf35f1339cbe3387263e0e69b Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Wed, 26 Jul 2017 11:40:39 -0400
Subject: Remove obsolete comments about functional dependencies
Initial submitted versions of the functional dependencies patch ignored
row groups that were smaller than a configured size. However, that
consideration was removed in late stages of the patch just before
commit, but some comments referring to it remained. Remove them to
avoid confusion.
Author: Atsushi Torikoshi
Discussion: https://postgr.es/m/7cfb23fc-4493-9c02-5da9-e505fd0115d2@lab.ntt.co.jp
---
src/backend/statistics/README.dependencies | 4 ----
src/backend/statistics/dependencies.c | 8 --------
2 files changed, 12 deletions(-)
(limited to 'src')
diff --git a/src/backend/statistics/README.dependencies b/src/backend/statistics/README.dependencies
index 702d34e3f8..6c446bde27 100644
--- a/src/backend/statistics/README.dependencies
+++ b/src/backend/statistics/README.dependencies
@@ -71,10 +71,6 @@ To count the rows consistent with the dependency (a => b):
(c) If there's a single distinct value in 'b', the rows are consistent with
the functional dependency, otherwise they contradict it.
-The algorithm also requires a minimum size of the group to consider it
-consistent (currently 3 rows in the sample). Small groups make it less likely
-to break the consistency.
-
Clause reduction (planner/optimizer)
------------------------------------
diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c
index 89dece3350..2e7c0ad6ba 100644
--- a/src/backend/statistics/dependencies.c
+++ b/src/backend/statistics/dependencies.c
@@ -286,14 +286,6 @@ dependency_degree(int numrows, HeapTuple *rows, int k, AttrNumber *dependency,
* first (k-1) columns. If there's a single value in the last column, we
* count the group as 'supporting' the functional dependency. Otherwise we
* count it as contradicting.
- *
- * We also require a group to have a minimum number of rows to be
- * considered useful for supporting the dependency. Contradicting groups
- * may be of any size, though.
- *
- * XXX The minimum size requirement makes it impossible to identify case
- * when both columns are unique (or nearly unique), and therefore
- * trivially functionally dependent.
*/
/* start with the first row forming a group */
--
cgit v1.2.3
From 459c64d3227f878c72ef0145a67e80e17728c556 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Wed, 26 Jul 2017 17:24:16 -0400
Subject: Fix concurrent locking of tuple update chain
If several sessions are concurrently locking a tuple update chain with
nonconflicting lock modes using an old snapshot, and they all succeed,
it may happen that some of them fail because of restarting the loop (due
to a concurrent Xmax change) and getting an error in the subsequent pass
while trying to obtain a tuple lock that they already have in some tuple
version.
This can only happen with very high concurrency (where a row is being
both updated and FK-checked by multiple transactions concurrently), but
it's been observed in the field and can have unpleasant consequences
such as an FK check failing to see a tuple that definitely exists:
ERROR: insert or update on table "child_table" violates foreign key constraint "fk_constraint_name"
DETAIL: Key (keyid)=(123456) is not present in table "parent_table".
(where the key is observably present in the table).
Discussion: https://postgr.es/m/20170714210011.r25mrff4nxjhmf3g@alvherre.pgsql
---
src/backend/access/heap/heapam.c | 41 ++++++++++++++++++++++++++++++++++++----
1 file changed, 37 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 011f2b9c54..479c3843f0 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -5524,8 +5524,10 @@ l5:
* with the given xid, does the current transaction need to wait, fail, or can
* it continue if it wanted to acquire a lock of the given mode? "needwait"
* is set to true if waiting is necessary; if it can continue, then
- * HeapTupleMayBeUpdated is returned. In case of a conflict, a different
- * HeapTupleSatisfiesUpdate return code is returned.
+ * HeapTupleMayBeUpdated is returned. If the lock is already held by the
+ * current transaction, return HeapTupleSelfUpdated. In case of a conflict
+ * with another transaction, a different HeapTupleSatisfiesUpdate return code
+ * is returned.
*
* The held status is said to be hypothetical because it might correspond to a
* lock held by a single Xid, i.e. not a real MultiXactId; we express it this
@@ -5548,8 +5550,9 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid,
if (TransactionIdIsCurrentTransactionId(xid))
{
/*
- * Updated by our own transaction? Just return failure. This
- * shouldn't normally happen.
+ * The tuple has already been locked by our own transaction. This is
+ * very rare but can happen if multiple transactions are trying to
+ * lock an ancient version of the same tuple.
*/
return HeapTupleSelfUpdated;
}
@@ -5748,6 +5751,22 @@ l4:
members[i].xid,
mode, &needwait);
+ /*
+ * If the tuple was already locked by ourselves in a
+ * previous iteration of this (say heap_lock_tuple was
+ * forced to restart the locking loop because of a change
+ * in xmax), then we hold the lock already on this tuple
+ * version and we don't need to do anything; and this is
+ * not an error condition either. We just need to skip
+ * this tuple and continue locking the next version in the
+ * update chain.
+ */
+ if (result == HeapTupleSelfUpdated)
+ {
+ pfree(members);
+ goto next;
+ }
+
if (needwait)
{
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -5808,6 +5827,19 @@ l4:
result = test_lockmode_for_conflict(status, rawxmax, mode,
&needwait);
+
+ /*
+ * If the tuple was already locked by ourselves in a previous
+ * iteration of this (say heap_lock_tuple was forced to
+ * restart the locking loop because of a change in xmax), then
+ * we hold the lock already on this tuple version and we don't
+ * need to do anything; and this is not an error condition
+ * either. We just need to skip this tuple and continue
+ * locking the next version in the update chain.
+ */
+ if (result == HeapTupleSelfUpdated)
+ goto next;
+
if (needwait)
{
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -5868,6 +5900,7 @@ l4:
END_CRIT_SECTION();
+next:
/* if we find the end of update chain, we're done. */
if (mytup.t_data->t_infomask & HEAP_XMAX_INVALID ||
ItemPointerEquals(&mytup.t_self, &mytup.t_data->t_ctid) ||
--
cgit v1.2.3
From 5e3254f0865d2e3372cfd29249063bdaedfa4b00 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Wed, 26 Jul 2017 18:17:18 -0400
Subject: Update copyright in recently added files
---
src/backend/replication/logical/proto.c | 2 +-
src/common/sha2.c | 2 +-
src/common/sha2_openssl.c | 2 +-
src/include/common/sha2.h | 2 +-
src/include/replication/logicalproto.h | 2 +-
src/include/replication/pgoutput.h | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index e3230e1fa2..94dfee0b24 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -3,7 +3,7 @@
* proto.c
* logical replication protocol functions
*
- * Copyright (c) 2015, PostgreSQL Global Development Group
+ * Copyright (c) 2015-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/backend/replication/logical/proto.c
diff --git a/src/common/sha2.c b/src/common/sha2.c
index 7c6f1b49ad..d7992f1d20 100644
--- a/src/common/sha2.c
+++ b/src/common/sha2.c
@@ -6,7 +6,7 @@
* This is the set of in-core functions used when there are no other
* alternative options like OpenSSL.
*
- * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/common/sha2.c
diff --git a/src/common/sha2_openssl.c b/src/common/sha2_openssl.c
index bcc3442633..b8e2e1139f 100644
--- a/src/common/sha2_openssl.c
+++ b/src/common/sha2_openssl.c
@@ -6,7 +6,7 @@
*
* This should only be used if code is compiled with OpenSSL support.
*
- * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/common/sha2_openssl.c
diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h
index 6358ca3c56..a31b3979d8 100644
--- a/src/include/common/sha2.h
+++ b/src/include/common/sha2.h
@@ -3,7 +3,7 @@
* sha2.h
* Generic headers for SHA224, 256, 384 AND 512 functions of PostgreSQL.
*
- * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/include/common/sha2.h
diff --git a/src/include/replication/logicalproto.h b/src/include/replication/logicalproto.h
index 191b03772f..a9736e1bf6 100644
--- a/src/include/replication/logicalproto.h
+++ b/src/include/replication/logicalproto.h
@@ -3,7 +3,7 @@
* logicalproto.h
* logical replication protocol
*
- * Copyright (c) 2015, PostgreSQL Global Development Group
+ * Copyright (c) 2015-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* src/include/replication/logicalproto.h
diff --git a/src/include/replication/pgoutput.h b/src/include/replication/pgoutput.h
index bfe8448ba9..1ec4500d9d 100644
--- a/src/include/replication/pgoutput.h
+++ b/src/include/replication/pgoutput.h
@@ -3,7 +3,7 @@
* pgoutput.h
* Logical Replication output plugin
*
- * Copyright (c) 2015, PostgreSQL Global Development Group
+ * Copyright (c) 2015-2017, PostgreSQL Global Development Group
*
* IDENTIFICATION
* pgoutput.h
--
cgit v1.2.3
From 50d2426f5a6d6a47da9ea67be55c3e89069e7bec Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Wed, 26 Jul 2017 19:35:35 -0400
Subject: Clean up SQL emitted by psql/describe.c.
Fix assorted places that had not bothered with the convention of
prefixing catalog and function names with "pg_catalog.". That
could possibly result in query failure when running with a nondefault
search_path. Also fix two places that weren't quoting OID literals.
I think the latter hasn't mattered much since about 7.3, but it's still
a bad idea to be doing it in 99 places and not in 2 others.
Also remove a useless EXISTS sub-select that someone had stuck into
describeOneTableDetails' queries for child tables. We just got the OID
out of pg_class, so I hardly see how checking that it exists in pg_class
was doing anything helpful.
In passing, try to improve the emitted formatting of a couple of
these queries, though I didn't work really hard on that. And merge
unnecessarily duplicative coding in some other places.
Much of this was new in HEAD, but some was quite old; back-patch
as appropriate.
---
src/bin/psql/describe.c | 166 ++++++++++++++++++++++--------------------------
1 file changed, 75 insertions(+), 91 deletions(-)
(limited to 'src')
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index e6833eced5..bd6870bcf1 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1594,17 +1594,17 @@ describeOneTableDetails(const char *schemaname,
else
appendPQExpBufferStr(&buf, "\n NULL AS attcollation");
if (pset.sversion >= 100000)
- appendPQExpBufferStr(&buf, ", a.attidentity");
+ appendPQExpBufferStr(&buf, ",\n a.attidentity");
else
- appendPQExpBufferStr(&buf, ", ''::\"char\" AS attidentity");
+ appendPQExpBufferStr(&buf, ",\n ''::pg_catalog.char AS attidentity");
if (tableinfo.relkind == RELKIND_INDEX)
appendPQExpBufferStr(&buf, ",\n pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE) AS indexdef");
else
appendPQExpBufferStr(&buf, ",\n NULL AS indexdef");
if (tableinfo.relkind == RELKIND_FOREIGN_TABLE && pset.sversion >= 90200)
appendPQExpBufferStr(&buf, ",\n CASE WHEN attfdwoptions IS NULL THEN '' ELSE "
- " '(' || array_to_string(ARRAY(SELECT quote_ident(option_name) || ' ' || quote_literal(option_value) FROM "
- " pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
+ " '(' || pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(option_name) || ' ' || pg_catalog.quote_literal(option_value) FROM "
+ " pg_catalog.pg_options_to_table(attfdwoptions)), ', ') || ')' END AS attfdwoptions");
else
appendPQExpBufferStr(&buf, ",\n NULL AS attfdwoptions");
if (verbose)
@@ -1854,30 +1854,24 @@ describeOneTableDetails(const char *schemaname,
/* Make footers */
if (pset.sversion >= 100000)
{
- /* Get the partition information */
+ /* Get the partition information */
PGresult *result;
char *parent_name;
char *partdef;
char *partconstraintdef = NULL;
+ printfPQExpBuffer(&buf,
+ "SELECT inhparent::pg_catalog.regclass,\n"
+ " pg_catalog.pg_get_expr(c.relpartbound, inhrelid)");
/* If verbose, also request the partition constraint definition */
if (verbose)
- printfPQExpBuffer(&buf,
- "SELECT inhparent::pg_catalog.regclass,"
- " pg_get_expr(c.relpartbound, inhrelid),"
- " pg_get_partition_constraintdef(inhrelid)"
- " FROM pg_catalog.pg_class c"
- " JOIN pg_catalog.pg_inherits"
- " ON c.oid = inhrelid"
- " WHERE c.oid = '%s' AND c.relispartition;", oid);
- else
- printfPQExpBuffer(&buf,
- "SELECT inhparent::pg_catalog.regclass,"
- " pg_get_expr(c.relpartbound, inhrelid)"
- " FROM pg_catalog.pg_class c"
- " JOIN pg_catalog.pg_inherits"
- " ON c.oid = inhrelid"
- " WHERE c.oid = '%s' AND c.relispartition;", oid);
+ appendPQExpBuffer(&buf,
+ ",\n pg_catalog.pg_get_partition_constraintdef(inhrelid)");
+ appendPQExpBuffer(&buf,
+ "\nFROM pg_catalog.pg_class c"
+ " JOIN pg_catalog.pg_inherits i"
+ " ON c.oid = inhrelid"
+ "\nWHERE c.oid = '%s' AND c.relispartition;", oid);
result = PSQLexec(buf.data);
if (!result)
goto error_return;
@@ -2041,7 +2035,7 @@ describeOneTableDetails(const char *schemaname,
"\n a.attnum=d.refobjsubid)"
"\nWHERE d.classid='pg_catalog.pg_class'::pg_catalog.regclass"
"\n AND d.refclassid='pg_catalog.pg_class'::pg_catalog.regclass"
- "\n AND d.objid=%s"
+ "\n AND d.objid='%s'"
"\n AND d.deptype IN ('a', 'i')",
oid);
@@ -2285,36 +2279,26 @@ describeOneTableDetails(const char *schemaname,
/* print any row-level policies */
if (pset.sversion >= 90500)
{
+ printfPQExpBuffer(&buf, "SELECT pol.polname,");
if (pset.sversion >= 100000)
- printfPQExpBuffer(&buf,
- "SELECT pol.polname, pol.polpermissive,\n"
- "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
- "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
- "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
- "CASE pol.polcmd\n"
- "WHEN 'r' THEN 'SELECT'\n"
- "WHEN 'a' THEN 'INSERT'\n"
- "WHEN 'w' THEN 'UPDATE'\n"
- "WHEN 'd' THEN 'DELETE'\n"
- "END AS cmd\n"
- "FROM pg_catalog.pg_policy pol\n"
- "WHERE pol.polrelid = '%s' ORDER BY 1;",
- oid);
+ appendPQExpBuffer(&buf,
+ " pol.polpermissive,\n");
else
- printfPQExpBuffer(&buf,
- "SELECT pol.polname, 't' as polpermissive,\n"
- "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
- "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
- "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
- "CASE pol.polcmd\n"
- "WHEN 'r' THEN 'SELECT'\n"
- "WHEN 'a' THEN 'INSERT'\n"
- "WHEN 'w' THEN 'UPDATE'\n"
- "WHEN 'd' THEN 'DELETE'\n"
- "END AS cmd\n"
- "FROM pg_catalog.pg_policy pol\n"
- "WHERE pol.polrelid = '%s' ORDER BY 1;",
- oid);
+ appendPQExpBuffer(&buf,
+ " 't' as polpermissive,\n");
+ appendPQExpBuffer(&buf,
+ " CASE WHEN pol.polroles = '{0}' THEN NULL ELSE pg_catalog.array_to_string(array(select rolname from pg_catalog.pg_roles where oid = any (pol.polroles) order by 1),',') END,\n"
+ " pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n"
+ " pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n"
+ " CASE pol.polcmd\n"
+ " WHEN 'r' THEN 'SELECT'\n"
+ " WHEN 'a' THEN 'INSERT'\n"
+ " WHEN 'w' THEN 'UPDATE'\n"
+ " WHEN 'd' THEN 'DELETE'\n"
+ " END AS cmd\n"
+ "FROM pg_catalog.pg_policy pol\n"
+ "WHERE pol.polrelid = '%s' ORDER BY 1;",
+ oid);
result = PSQLexec(buf.data);
if (!result)
@@ -2543,7 +2527,7 @@ describeOneTableDetails(const char *schemaname,
"UNION ALL\n"
"SELECT pubname\n"
"FROM pg_catalog.pg_publication p\n"
- "WHERE p.puballtables AND pg_relation_is_publishable('%s')\n"
+ "WHERE p.puballtables AND pg_catalog.pg_relation_is_publishable('%s')\n"
"ORDER BY 1;",
oid, oid);
@@ -2764,13 +2748,13 @@ describeOneTableDetails(const char *schemaname,
/* Footer information about foreign table */
printfPQExpBuffer(&buf,
"SELECT s.srvname,\n"
- " array_to_string(ARRAY(SELECT "
- " quote_ident(option_name) || ' ' || "
- " quote_literal(option_value) FROM "
- " pg_options_to_table(ftoptions)), ', ') "
+ " pg_catalog.array_to_string(ARRAY(\n"
+ " SELECT pg_catalog.quote_ident(option_name)"
+ " || ' ' || pg_catalog.quote_literal(option_value)\n"
+ " FROM pg_catalog.pg_options_to_table(ftoptions)), ', ')\n"
"FROM pg_catalog.pg_foreign_table f,\n"
" pg_catalog.pg_foreign_server s\n"
- "WHERE f.ftrelid = %s AND s.oid = f.ftserver;",
+ "WHERE f.ftrelid = '%s' AND s.oid = f.ftserver;",
oid);
result = PSQLexec(buf.data);
if (!result)
@@ -2834,22 +2818,22 @@ describeOneTableDetails(const char *schemaname,
/* print child tables (with additional info if partitions) */
if (pset.sversion >= 100000)
printfPQExpBuffer(&buf,
- "SELECT c.oid::pg_catalog.regclass, pg_get_expr(c.relpartbound, c.oid)"
+ "SELECT c.oid::pg_catalog.regclass, pg_catalog.pg_get_expr(c.relpartbound, c.oid)"
" FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i"
- " WHERE c.oid=i.inhrelid AND"
- " i.inhparent = '%s' AND"
- " EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = '%s')"
- " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid, oid);
+ " WHERE c.oid=i.inhrelid AND i.inhparent = '%s'"
+ " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
else if (pset.sversion >= 80300)
printfPQExpBuffer(&buf,
"SELECT c.oid::pg_catalog.regclass"
" FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i"
- " WHERE c.oid=i.inhrelid AND"
- " i.inhparent = '%s' AND"
- " EXISTS (SELECT 1 FROM pg_class c WHERE c.oid = '%s')"
- " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid, oid);
+ " WHERE c.oid=i.inhrelid AND i.inhparent = '%s'"
+ " ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;", oid);
else
- printfPQExpBuffer(&buf, "SELECT c.oid::pg_catalog.regclass FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i WHERE c.oid=i.inhrelid AND i.inhparent = '%s' ORDER BY c.relname;", oid);
+ printfPQExpBuffer(&buf,
+ "SELECT c.oid::pg_catalog.regclass"
+ " FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i"
+ " WHERE c.oid=i.inhrelid AND i.inhparent = '%s'"
+ " ORDER BY c.relname;", oid);
result = PSQLexec(buf.data);
if (!result)
@@ -3234,16 +3218,16 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
"pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
- "FROM pg_db_role_setting AS s\n"
- "LEFT JOIN pg_database ON pg_database.oid = setdatabase\n"
- "LEFT JOIN pg_roles ON pg_roles.oid = setrole\n",
+ "FROM pg_catalog.pg_db_role_setting s\n"
+ "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
+ "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
gettext_noop("Role"),
gettext_noop("Database"),
gettext_noop("Settings"));
havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
- NULL, "pg_roles.rolname", NULL, NULL);
+ NULL, "r.rolname", NULL, NULL);
processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
- NULL, "pg_database.datname", NULL, NULL);
+ NULL, "d.datname", NULL, NULL);
appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
}
else
@@ -3475,13 +3459,13 @@ listLanguages(const char *pattern, bool verbose, bool showSystem)
{
appendPQExpBuffer(&buf,
",\n NOT l.lanispl AS \"%s\",\n"
- " l.lanplcallfoid::regprocedure AS \"%s\",\n"
- " l.lanvalidator::regprocedure AS \"%s\",\n ",
+ " l.lanplcallfoid::pg_catalog.regprocedure AS \"%s\",\n"
+ " l.lanvalidator::pg_catalog.regprocedure AS \"%s\",\n ",
gettext_noop("Internal language"),
gettext_noop("Call handler"),
gettext_noop("Validator"));
if (pset.sversion >= 90000)
- appendPQExpBuffer(&buf, "l.laninline::regprocedure AS \"%s\",\n ",
+ appendPQExpBuffer(&buf, "l.laninline::pg_catalog.regprocedure AS \"%s\",\n ",
gettext_noop("Inline handler"));
printACLColumn(&buf, "l.lanacl");
}
@@ -4611,10 +4595,10 @@ listForeignDataWrappers(const char *pattern, bool verbose)
printACLColumn(&buf, "fdwacl");
appendPQExpBuffer(&buf,
",\n CASE WHEN fdwoptions IS NULL THEN '' ELSE "
- " '(' || array_to_string(ARRAY(SELECT "
- " quote_ident(option_name) || ' ' || "
- " quote_literal(option_value) FROM "
- " pg_options_to_table(fdwoptions)), ', ') || ')' "
+ " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
+ " pg_catalog.quote_ident(option_name) || ' ' || "
+ " pg_catalog.quote_literal(option_value) FROM "
+ " pg_catalog.pg_options_to_table(fdwoptions)), ', ') || ')' "
" END AS \"%s\"",
gettext_noop("FDW options"));
@@ -4692,10 +4676,10 @@ listForeignServers(const char *pattern, bool verbose)
" s.srvtype AS \"%s\",\n"
" s.srvversion AS \"%s\",\n"
" CASE WHEN srvoptions IS NULL THEN '' ELSE "
- " '(' || array_to_string(ARRAY(SELECT "
- " quote_ident(option_name) || ' ' || "
- " quote_literal(option_value) FROM "
- " pg_options_to_table(srvoptions)), ', ') || ')' "
+ " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
+ " pg_catalog.quote_ident(option_name) || ' ' || "
+ " pg_catalog.quote_literal(option_value) FROM "
+ " pg_catalog.pg_options_to_table(srvoptions)), ', ') || ')' "
" END AS \"%s\",\n"
" d.description AS \"%s\"",
gettext_noop("Type"),
@@ -4710,7 +4694,7 @@ listForeignServers(const char *pattern, bool verbose)
if (verbose)
appendPQExpBufferStr(&buf,
- "LEFT JOIN pg_description d\n "
+ "LEFT JOIN pg_catalog.pg_description d\n "
"ON d.classoid = s.tableoid AND d.objoid = s.oid "
"AND d.objsubid = 0\n");
@@ -4766,10 +4750,10 @@ listUserMappings(const char *pattern, bool verbose)
if (verbose)
appendPQExpBuffer(&buf,
",\n CASE WHEN umoptions IS NULL THEN '' ELSE "
- " '(' || array_to_string(ARRAY(SELECT "
- " quote_ident(option_name) || ' ' || "
- " quote_literal(option_value) FROM "
- " pg_options_to_table(umoptions)), ', ') || ')' "
+ " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
+ " pg_catalog.quote_ident(option_name) || ' ' || "
+ " pg_catalog.quote_literal(option_value) FROM "
+ " pg_catalog.pg_options_to_table(umoptions)), ', ') || ')' "
" END AS \"%s\"",
gettext_noop("FDW options"));
@@ -4829,10 +4813,10 @@ listForeignTables(const char *pattern, bool verbose)
if (verbose)
appendPQExpBuffer(&buf,
",\n CASE WHEN ftoptions IS NULL THEN '' ELSE "
- " '(' || array_to_string(ARRAY(SELECT "
- " quote_ident(option_name) || ' ' || "
- " quote_literal(option_value) FROM "
- " pg_options_to_table(ftoptions)), ', ') || ')' "
+ " '(' || pg_catalog.array_to_string(ARRAY(SELECT "
+ " pg_catalog.quote_ident(option_name) || ' ' || "
+ " pg_catalog.quote_literal(option_value) FROM "
+ " pg_catalog.pg_options_to_table(ftoptions)), ', ') || ')' "
" END AS \"%s\",\n"
" d.description AS \"%s\"",
gettext_noop("FDW options"),
--
cgit v1.2.3
From efd7f8e36553cd32e445061cbbc80d32028f4248 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan
Date: Wed, 26 Jul 2017 17:15:59 -0400
Subject: Work around Msys weakness in Testlib.pm's command_like()
When output of IPC::Run::run () is redirected to scalar references, in
certain circumstances the Msys perl does not correctly detect that the
end of file has been seen, making the test hang indefinitely. One such
circumstance is when the command is 'pg_ctl start', and such a change
was made in commit f13ea95f9e. The workaround, which only applies on
MSys, is to redirect the output to temporary files and then read them in
when the process has finished.
Patch by me, reviewed and tweaked by Tom Lane.
---
src/bin/pg_ctl/t/001_start_stop.pl | 14 +++++++++++---
src/test/perl/TestLib.pm | 19 +++++++++++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_ctl/t/001_start_stop.pl b/src/bin/pg_ctl/t/001_start_stop.pl
index 9c3551f1a5..3acc80e204 100644
--- a/src/bin/pg_ctl/t/001_start_stop.pl
+++ b/src/bin/pg_ctl/t/001_start_stop.pl
@@ -32,9 +32,17 @@ else
print $conf "listen_addresses = '127.0.0.1'\n";
}
close $conf;
-command_like([ 'pg_ctl', 'start', '-D', "$tempdir/data",
- '-l', "$TestLib::log_path/001_start_stop_server.log" ],
- qr/done.*server started/s, 'pg_ctl start');
+my $ctlcmd = [ 'pg_ctl', 'start', '-D', "$tempdir/data",
+ '-l', "$TestLib::log_path/001_start_stop_server.log" ];
+if ($Config{osname} ne 'msys')
+{
+ command_like($ctlcmd, qr/done.*server started/s, 'pg_ctl start');
+}
+else
+{
+ # use the version of command_like that doesn't hang on Msys here
+ command_like_safe($ctlcmd, qr/done.*server started/s, 'pg_ctl start');
+}
# sleep here is because Windows builds can't check postmaster.pid exactly,
# so they may mistake a pre-existing postmaster.pid for one created by the
diff --git a/src/test/perl/TestLib.pm b/src/test/perl/TestLib.pm
index fe09689fec..bff6b3aed2 100644
--- a/src/test/perl/TestLib.pm
+++ b/src/test/perl/TestLib.pm
@@ -37,6 +37,7 @@ our @EXPORT = qw(
program_version_ok
program_options_handling_ok
command_like
+ command_like_safe
command_fails_like
$windows_os
@@ -300,6 +301,24 @@ sub command_like
like($stdout, $expected_stdout, "$test_name: matches");
}
+sub command_like_safe
+{
+ # Doesn't rely on detecting end of file on the file descriptors,
+ # which can fail, causing the process to hang, notably on Msys
+ # when used with 'pg_ctl start'
+ my ($cmd, $expected_stdout, $test_name) = @_;
+ my ($stdout, $stderr);
+ my $stdoutfile = File::Temp->new();
+ my $stderrfile = File::Temp->new();
+ print("# Running: " . join(" ", @{$cmd}) . "\n");
+ my $result = IPC::Run::run $cmd, '>', $stdoutfile, '2>', $stderrfile;
+ $stdout = slurp_file($stdoutfile);
+ $stderr = slurp_file($stderrfile);
+ ok($result, "$test_name: exit code 0");
+ is($stderr, '', "$test_name: no stderr");
+ like($stdout, $expected_stdout, "$test_name: matches");
+}
+
sub command_fails_like
{
my ($cmd, $expected_stderr, $test_name) = @_;
--
cgit v1.2.3
From dc4da3dc84c7c0d1a58275f78f0e3401385e3700 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 27 Jul 2017 11:10:38 -0400
Subject: Fix very minor memory leaks in psql's command.c.
\drds leaked its second pattern argument if any, and \connect leaked
any empty-string or "-" arguments. These are old bugs, but it's hard
to imagine any real use-case where the leaks could amount to anything
meaningful, so not bothering with a back-patch.
Daniel Gustafsson and Tom Lane
Discussion: https://postgr.es/m/3641F19B-336A-431A-86CE-A80562505C5E@yesql.se
---
src/bin/psql/command.c | 8 ++++++++
1 file changed, 8 insertions(+)
(limited to 'src')
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 14c64208ca..4e04459d45 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -806,6 +806,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
pattern2 = psql_scan_slash_option(scan_state,
OT_NORMAL, NULL, true);
success = listDbRoleSettings(pattern, pattern2);
+
+ if (pattern2)
+ free(pattern2);
}
else
status = PSQL_CMD_UNKNOWN;
@@ -2725,6 +2728,8 @@ exec_command_slash_command_help(PsqlScanState scan_state, bool active_branch)
/*
* Read and interpret an argument to the \connect slash command.
+ *
+ * Returns a malloc'd string, or NULL if no/empty argument.
*/
static char *
read_connect_arg(PsqlScanState scan_state)
@@ -2750,7 +2755,10 @@ read_connect_arg(PsqlScanState scan_state)
return result;
if (*result == '\0' || strcmp(result, "-") == 0)
+ {
+ free(result);
return NULL;
+ }
return result;
}
--
cgit v1.2.3
From b884f629dcbac002a703ccaf0990d9467ae69a19 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 27 Jul 2017 11:57:29 -0400
Subject: Sync listDbRoleSettings() with the rest of the world.
listDbRoleSettings() handled its server version check randomly differently
from every other comparable function in describe.c, not only as to code
layout but also message wording. It also leaked memory, because its
PQExpBuffer management was also unlike everyplace else (and wrong).
Also fix an error-case leak in add_tablespace_footer().
In passing, standardize the format of function header comments in
describe.c --- we usually put "/*" alone on a line.
Daniel Gustafsson, memory leak fixes by me
Discussion: https://postgr.es/m/3641F19B-336A-431A-86CE-A80562505C5E@yesql.se
---
src/bin/psql/describe.c | 77 ++++++++++++++++++++++++++++---------------------
1 file changed, 44 insertions(+), 33 deletions(-)
(limited to 'src')
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index bd6870bcf1..03ef1b070c 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -54,7 +54,8 @@ static bool listOneExtensionContents(const char *extname, const char *oid);
*/
-/* \da
+/*
+ * \da
* Takes an optional regexp to select particular aggregates
*/
bool
@@ -131,7 +132,8 @@ describeAggregates(const char *pattern, bool verbose, bool showSystem)
return true;
}
-/* \dA
+/*
+ * \dA
* Takes an optional regexp to select particular access methods
*/
bool
@@ -198,7 +200,8 @@ describeAccessMethods(const char *pattern, bool verbose)
return true;
}
-/* \db
+/*
+ * \db
* Takes an optional regexp to select particular tablespaces
*/
bool
@@ -283,7 +286,8 @@ describeTablespaces(const char *pattern, bool verbose)
}
-/* \df
+/*
+ * \df
* Takes an optional regexp to select particular functions.
*
* As with \d, you can specify the kinds of functions you want:
@@ -696,7 +700,8 @@ describeTypes(const char *pattern, bool verbose, bool showSystem)
}
-/* \do
+/*
+ * \do
* Describe operators
*/
bool
@@ -2997,7 +3002,10 @@ add_tablespace_footer(printTableContent *const cont, char relkind,
"WHERE oid = '%u';", tablespace);
result = PSQLexec(buf.data);
if (!result)
+ {
+ termPQExpBuffer(&buf);
return;
+ }
/* Should always be the case, but.... */
if (PQntuples(result) > 0)
{
@@ -3209,35 +3217,36 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
+ bool havewhere;
- initPQExpBuffer(&buf);
-
- if (pset.sversion >= 90000)
- {
- bool havewhere;
-
- printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
- "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
- "FROM pg_catalog.pg_db_role_setting s\n"
- "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
- "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
- gettext_noop("Role"),
- gettext_noop("Database"),
- gettext_noop("Settings"));
- havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
- NULL, "r.rolname", NULL, NULL);
- processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
- NULL, "d.datname", NULL, NULL);
- appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
- }
- else
+ if (pset.sversion < 90000)
{
- fprintf(pset.queryFout,
- _("No per-database role settings support in this server version.\n"));
- return false;
+ char sverbuf[32];
+
+ psql_error("The server (version %s) does not support per-database role settings.\n",
+ formatPGVersionNumber(pset.sversion, false,
+ sverbuf, sizeof(sverbuf)));
+ return true;
}
+ initPQExpBuffer(&buf);
+
+ printfPQExpBuffer(&buf, "SELECT rolname AS \"%s\", datname AS \"%s\",\n"
+ "pg_catalog.array_to_string(setconfig, E'\\n') AS \"%s\"\n"
+ "FROM pg_catalog.pg_db_role_setting s\n"
+ "LEFT JOIN pg_catalog.pg_database d ON d.oid = setdatabase\n"
+ "LEFT JOIN pg_catalog.pg_roles r ON r.oid = setrole\n",
+ gettext_noop("Role"),
+ gettext_noop("Database"),
+ gettext_noop("Settings"));
+ havewhere = processSQLNamePattern(pset.db, &buf, pattern, false, false,
+ NULL, "r.rolname", NULL, NULL);
+ processSQLNamePattern(pset.db, &buf, pattern2, havewhere, false,
+ NULL, "d.datname", NULL, NULL);
+ appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
+
res = PSQLexec(buf.data);
+ termPQExpBuffer(&buf);
if (!res)
return false;
@@ -3258,7 +3267,6 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
}
PQclear(res);
- resetPQExpBuffer(&buf);
return true;
}
@@ -5024,7 +5032,8 @@ listOneExtensionContents(const char *extname, const char *oid)
return true;
}
-/* \dRp
+/*
+ * \dRp
* Lists publications.
*
* Takes an optional regexp to select particular publications
@@ -5090,7 +5099,8 @@ listPublications(const char *pattern)
return true;
}
-/* \dRp+
+/*
+ * \dRp+
* Describes publications including the contents.
*
* Takes an optional regexp to select particular publications
@@ -5211,7 +5221,8 @@ describePublications(const char *pattern)
return true;
}
-/* \dRs
+/*
+ * \dRs
* Describes subscriptions.
*
* Takes an optional regexp to select particular subscriptions
--
cgit v1.2.3
From 1e2f941db1671909ba3bde447c224bb64d1c002a Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 27 Jul 2017 12:12:37 -0400
Subject: Avoid use of sprintf/snprintf in describe.c.
Most places were already using the PQExpBuffer library for constructing
variable-length strings; bring the two stragglers into line.
describeOneTSParser was living particularly dangerously since it wasn't
even using snprintf().
Daniel Gustafsson
Discussion: https://postgr.es/m/3641F19B-336A-431A-86CE-A80562505C5E@yesql.se
---
src/bin/psql/describe.c | 26 ++++++++++++++++----------
1 file changed, 16 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 03ef1b070c..4f4790cc5c 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -4113,7 +4113,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
{
PQExpBufferData buf;
PGresult *res;
- char title[1024];
+ PQExpBufferData title;
printQueryOpt myopt = pset.popt;
static const bool translate_columns[] = {true, false, false};
@@ -4169,11 +4169,13 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
return false;
myopt.nullPrint = NULL;
+ initPQExpBuffer(&title);
if (nspname)
- sprintf(title, _("Text search parser \"%s.%s\""), nspname, prsname);
+ printfPQExpBuffer(&title, _("Text search parser \"%s.%s\""),
+ nspname, prsname);
else
- sprintf(title, _("Text search parser \"%s\""), prsname);
- myopt.title = title;
+ printfPQExpBuffer(&title, _("Text search parser \"%s\""), prsname);
+ myopt.title = title.data;
myopt.footers = NULL;
myopt.topt.default_footer = false;
myopt.translate_header = true;
@@ -4202,10 +4204,11 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
myopt.nullPrint = NULL;
if (nspname)
- sprintf(title, _("Token types for parser \"%s.%s\""), nspname, prsname);
+ printfPQExpBuffer(&title, _("Token types for parser \"%s.%s\""),
+ nspname, prsname);
else
- sprintf(title, _("Token types for parser \"%s\""), prsname);
- myopt.title = title;
+ printfPQExpBuffer(&title, _("Token types for parser \"%s\""), prsname);
+ myopt.title = title.data;
myopt.footers = NULL;
myopt.topt.default_footer = true;
myopt.translate_header = true;
@@ -4214,6 +4217,7 @@ describeOneTSParser(const char *oid, const char *nspname, const char *prsname)
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ termPQExpBuffer(&title);
PQclear(res);
return true;
}
@@ -5004,7 +5008,7 @@ listOneExtensionContents(const char *extname, const char *oid)
{
PQExpBufferData buf;
PGresult *res;
- char title[1024];
+ PQExpBufferData title;
printQueryOpt myopt = pset.popt;
initPQExpBuffer(&buf);
@@ -5022,12 +5026,14 @@ listOneExtensionContents(const char *extname, const char *oid)
return false;
myopt.nullPrint = NULL;
- snprintf(title, sizeof(title), _("Objects in extension \"%s\""), extname);
- myopt.title = title;
+ initPQExpBuffer(&title);
+ printfPQExpBuffer(&title, _("Objects in extension \"%s\""), extname);
+ myopt.title = title.data;
myopt.translate_header = true;
printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+ termPQExpBuffer(&title);
PQclear(res);
return true;
}
--
cgit v1.2.3
From 77cb4a1d6730a69906baf0b052aae7dc11f07764 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 27 Jul 2017 13:30:59 -0400
Subject: Standardize describe.c's behavior for no-matching-objects a bit more.
Most functions in this file are content to print an empty table if there
are no matching objects. In some, the behavior is to loop over all
matching objects and print a table for each one; therefore, without any
extra logic, nothing at all would be printed if no objects match.
We accept that outcome in QUIET mode, but in normal mode it seems better
to print a helpful message. The new \dRp+ command had not gotten that
memo; fix it.
listDbRoleSettings() is out of step on this, but I think it's better for
it to print a custom message rather than an empty table, because of the
possibility that the user is confused about what the pattern arguments mean
or which is which. The original message wording was entirely useless for
clarifying that, though, not to mention being unlike the wordings used
elsewhere. Improve the text, and also print the messages with psql_error
as is the general custom here.
listTables() is also out in left field, but since it's such a heavily
used function, I'm hesitant to change its behavior so much as to print
an empty table rather than a custom message. People are probably used
to getting a message. But we can make the wording more standardized and
helpful, and print it with psql_error rather than printing to stdout.
In both listDbRoleSettings and listTables, we play dumb and emit an
empty table, not a custom message, in QUIET mode. That was true before
and I see no need to change it.
Several of the places printing such messages risked dumping core if
no pattern string had been provided; make them more wary. (This case
is presently unreachable in describeTableDetails; but it shouldn't be
assuming that command.c will never pass it a null. The text search
functions would only reach the case if a database contained no text
search objects, which is also currently impossible since we pin the
built-in objects, but again it seems unwise to assume that here.)
Daniel Gustafsson, tweaked a bit by me
Discussion: https://postgr.es/m/3641F19B-336A-431A-86CE-A80562505C5E@yesql.se
---
src/bin/psql/describe.c | 69 +++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 58 insertions(+), 11 deletions(-)
(limited to 'src')
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 4f4790cc5c..78e9d895f0 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -1322,8 +1322,13 @@ describeTableDetails(const char *pattern, bool verbose, bool showSystem)
if (PQntuples(res) == 0)
{
if (!pset.quiet)
- psql_error("Did not find any relation named \"%s\".\n",
- pattern);
+ {
+ if (pattern)
+ psql_error("Did not find any relation named \"%s\".\n",
+ pattern);
+ else
+ psql_error("Did not find any relations.\n");
+ }
PQclear(res);
return false;
}
@@ -3250,12 +3255,22 @@ listDbRoleSettings(const char *pattern, const char *pattern2)
if (!res)
return false;
+ /*
+ * Most functions in this file are content to print an empty table when
+ * there are no matching objects. We intentionally deviate from that
+ * here, but only in !quiet mode, because of the possibility that the user
+ * is confused about what the two pattern arguments mean.
+ */
if (PQntuples(res) == 0 && !pset.quiet)
{
- if (pattern)
- fprintf(pset.queryFout, _("No matching settings found.\n"));
+ if (pattern && pattern2)
+ psql_error("Did not find any settings for role \"%s\" and database \"%s\".\n",
+ pattern, pattern2);
+ else if (pattern)
+ psql_error("Did not find any settings for role \"%s\".\n",
+ pattern);
else
- fprintf(pset.queryFout, _("No settings found.\n"));
+ psql_error("Did not find any settings.\n");
}
else
{
@@ -3414,12 +3429,18 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
if (!res)
return false;
+ /*
+ * Most functions in this file are content to print an empty table when
+ * there are no matching objects. We intentionally deviate from that
+ * here, but only in !quiet mode, for historical reasons.
+ */
if (PQntuples(res) == 0 && !pset.quiet)
{
if (pattern)
- fprintf(pset.queryFout, _("No matching relations found.\n"));
+ psql_error("Did not find any relation named \"%s\".\n",
+ pattern);
else
- fprintf(pset.queryFout, _("No relations found.\n"));
+ psql_error("Did not find any relations.\n");
}
else
{
@@ -4074,8 +4095,13 @@ listTSParsersVerbose(const char *pattern)
if (PQntuples(res) == 0)
{
if (!pset.quiet)
- psql_error("Did not find any text search parser named \"%s\".\n",
- pattern);
+ {
+ if (pattern)
+ psql_error("Did not find any text search parser named \"%s\".\n",
+ pattern);
+ else
+ psql_error("Did not find any text search parsers.\n");
+ }
PQclear(res);
return false;
}
@@ -4459,8 +4485,13 @@ listTSConfigsVerbose(const char *pattern)
if (PQntuples(res) == 0)
{
if (!pset.quiet)
- psql_error("Did not find any text search configuration named \"%s\".\n",
- pattern);
+ {
+ if (pattern)
+ psql_error("Did not find any text search configuration named \"%s\".\n",
+ pattern);
+ else
+ psql_error("Did not find any text search configurations.\n");
+ }
PQclear(res);
return false;
}
@@ -5148,6 +5179,22 @@ describePublications(const char *pattern)
return false;
}
+ if (PQntuples(res) == 0)
+ {
+ if (!pset.quiet)
+ {
+ if (pattern)
+ psql_error("Did not find any publication named \"%s\".\n",
+ pattern);
+ else
+ psql_error("Did not find any publications.\n");
+ }
+
+ termPQExpBuffer(&buf);
+ PQclear(res);
+ return false;
+ }
+
for (i = 0; i < PQntuples(res); i++)
{
const char align = 'l';
--
cgit v1.2.3
From 8d304072a2573f0bfbdf893cc79197aeecdb5242 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 27 Jul 2017 14:13:15 -0400
Subject: Fix psql tab completion for CREATE USER MAPPING.
After typing CREATE USER M..., it would not fill in MAPPING FOR,
even though that was clearly intended behavior.
Jeff Janes
Discussion: https://postgr.es/m/CAMkU=1wo2iQ6jWnN=egqOb5NxEPn0PpANEtKHr3uPooQ+nYPtw@mail.gmail.com
---
src/bin/psql/tab-complete.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index e9fdc908c7..e34922dd73 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1056,7 +1056,7 @@ static const pgsql_thing_t words_after_create[] = {
* INDEX ... */
{"UNLOGGED", NULL, NULL, THING_NO_DROP | THING_NO_ALTER}, /* for CREATE UNLOGGED
* TABLE ... */
- {"USER", Query_for_list_of_roles},
+ {"USER", Query_for_list_of_roles " UNION SELECT 'MAPPING FOR'"},
{"USER MAPPING FOR", NULL, NULL},
{"VIEW", NULL, &Query_for_list_of_views},
{NULL} /* end of list */
--
cgit v1.2.3
From bebe174bb4462ef079a1d7eeafb82ff969f160a4 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 28 Jul 2017 12:25:43 -0400
Subject: PL/Perl portability fix: avoid including XSUB.h in plperl.c.
In Perl builds that define PERL_IMPLICIT_SYS, XSUB.h defines macros
that replace a whole lot of basic libc functions with Perl functions.
We can't tolerate that in plperl.c; it breaks at least PG_TRY and
probably other stuff. The core idea of this patch is to include XSUB.h
only in the .xs files where it's really needed, and to move any code
broken by PERL_IMPLICIT_SYS out of the .xs files and into plperl.c.
The reason this hasn't been a problem before is that our build techniques
did not result in PERL_IMPLICIT_SYS appearing as a #define in PL/Perl,
even on some platforms where Perl thinks it is defined. That's about to
change in order to fix a nasty portability issue, so we need this work to
make the code safe for that.
Rather unaccountably, the Perl people chose XSUB.h as the place to provide
the versions of the aTHX/aTHX_ macros that are needed by code that's not
explicitly aware of the MULTIPLICITY API conventions. Hence, just removing
XSUB.h from plperl.c fails miserably. But we can work around that by
defining PERL_NO_GET_CONTEXT (which would make the relevant stanza of
XSUB.h a no-op anyway). As explained in perlguts.pod, that means we need
to add a "dTHX" macro call in every C function that calls a Perl API
function. In most of them we just add this at the top; but since the
macro fetches the current Perl interpreter pointer, more care is needed
in functions that switch the active interpreter. Lack of the macro is
easily recognized since it results in bleats about "my_perl" not being
defined.
(A nice side benefit of this is that it significantly reduces the number
of fetches of the current interpreter pointer. On my machine, plperl.so
gets more than 10% smaller, and there's probably some performance win too.
We could reduce the number of fetches still more by decorating the code
with pTHX_/aTHX_ macros to pass the interpreter pointer around, as
explained by perlguts.pod; but that's a task for another day.)
Formatting note: pgindent seems happy to treat "dTHX;" as a declaration
so long as it's the first thing after the left brace, as we'd already
observed with respect to the similar macro "dSP;". If you try to put
it later in a set of declarations, pgindent puts ugly extra space
around it.
Having removed XSUB.h from plperl.c, we need only move the support
functions for spi_return_next and util_elog (both of which use PG_TRY)
out of the .xs files and into plperl.c. This seems sufficient to
avoid the known problems caused by PERL_IMPLICIT_SYS, although we
could move more code if additional issues emerge.
This will need to be back-patched, but first let's see what the
buildfarm makes of it.
Patch by me, with some help from Ashutosh Sharma
Discussion: https://postgr.es/m/CANFyU97OVQ3+Mzfmt3MhuUm5NwPU=-FtbNH5Eb7nZL9ua8=rcA@mail.gmail.com
---
contrib/hstore_plperl/hstore_plperl.c | 6 +-
src/pl/plperl/SPI.xs | 32 +----
src/pl/plperl/Util.xs | 44 +-----
src/pl/plperl/plperl.c | 244 +++++++++++++++++++++++++---------
src/pl/plperl/plperl.h | 17 ++-
src/pl/plperl/plperl_helpers.h | 4 +
6 files changed, 210 insertions(+), 137 deletions(-)
(limited to 'src')
diff --git a/contrib/hstore_plperl/hstore_plperl.c b/contrib/hstore_plperl/hstore_plperl.c
index 480212f341..cc46a525f6 100644
--- a/contrib/hstore_plperl/hstore_plperl.c
+++ b/contrib/hstore_plperl/hstore_plperl.c
@@ -67,6 +67,7 @@ PG_FUNCTION_INFO_V1(hstore_to_plperl);
Datum
hstore_to_plperl(PG_FUNCTION_ARGS)
{
+ dTHX;
HStore *in = PG_GETARG_HS(0);
int i;
int count = HS_COUNT(in);
@@ -99,7 +100,8 @@ PG_FUNCTION_INFO_V1(plperl_to_hstore);
Datum
plperl_to_hstore(PG_FUNCTION_ARGS)
{
- HV *hv;
+ dTHX;
+ HV *hv = (HV *) SvRV((SV *) PG_GETARG_POINTER(0));
HE *he;
int32 buflen;
int32 i;
@@ -107,8 +109,6 @@ plperl_to_hstore(PG_FUNCTION_ARGS)
HStore *out;
Pairs *pairs;
- hv = (HV *) SvRV((SV *) PG_GETARG_POINTER(0));
-
pcount = hv_iterinit(hv);
pairs = palloc(pcount * sizeof(Pairs));
diff --git a/src/pl/plperl/SPI.xs b/src/pl/plperl/SPI.xs
index 0447c50df1..d9e6f579d4 100644
--- a/src/pl/plperl/SPI.xs
+++ b/src/pl/plperl/SPI.xs
@@ -9,44 +9,16 @@
/* this must be first: */
#include "postgres.h"
-#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */
/* Defined by Perl */
#undef _
/* perl stuff */
+#define PG_NEED_PERL_XSUB_H
#include "plperl.h"
#include "plperl_helpers.h"
-/*
- * Interface routine to catch ereports and punt them to Perl
- */
-static void
-do_plperl_return_next(SV *sv)
-{
- MemoryContext oldcontext = CurrentMemoryContext;
-
- PG_TRY();
- {
- plperl_return_next(sv);
- }
- PG_CATCH();
- {
- ErrorData *edata;
-
- /* Must reset elog.c's state */
- MemoryContextSwitchTo(oldcontext);
- edata = CopyErrorData();
- FlushErrorState();
-
- /* Punt the error to Perl */
- croak_cstr(edata->message);
- }
- PG_END_TRY();
-}
-
-
MODULE = PostgreSQL::InServer::SPI PREFIX = spi_
PROTOTYPES: ENABLE
@@ -76,7 +48,7 @@ void
spi_return_next(rv)
SV *rv;
CODE:
- do_plperl_return_next(rv);
+ plperl_return_next(rv);
SV *
spi_spi_query(sv)
diff --git a/src/pl/plperl/Util.xs b/src/pl/plperl/Util.xs
index dbba0d7b87..686513d2e8 100644
--- a/src/pl/plperl/Util.xs
+++ b/src/pl/plperl/Util.xs
@@ -15,53 +15,15 @@
#include "fmgr.h"
#include "utils/builtins.h"
#include "utils/bytea.h" /* for byteain & byteaout */
-#include "mb/pg_wchar.h" /* for GetDatabaseEncoding */
+
/* Defined by Perl */
#undef _
/* perl stuff */
+#define PG_NEED_PERL_XSUB_H
#include "plperl.h"
#include "plperl_helpers.h"
-/*
- * Implementation of plperl's elog() function
- *
- * If the error level is less than ERROR, we'll just emit the message and
- * return. When it is ERROR, elog() will longjmp, which we catch and
- * turn into a Perl croak(). Note we are assuming that elog() can't have
- * any internal failures that are so bad as to require a transaction abort.
- *
- * This is out-of-line to suppress "might be clobbered by longjmp" warnings.
- */
-static void
-do_util_elog(int level, SV *msg)
-{
- MemoryContext oldcontext = CurrentMemoryContext;
- char * volatile cmsg = NULL;
-
- PG_TRY();
- {
- cmsg = sv2cstr(msg);
- elog(level, "%s", cmsg);
- pfree(cmsg);
- }
- PG_CATCH();
- {
- ErrorData *edata;
-
- /* Must reset elog.c's state */
- MemoryContextSwitchTo(oldcontext);
- edata = CopyErrorData();
- FlushErrorState();
-
- if (cmsg)
- pfree(cmsg);
-
- /* Punt the error to Perl */
- croak_cstr(edata->message);
- }
- PG_END_TRY();
-}
static text *
sv2text(SV *sv)
@@ -105,7 +67,7 @@ util_elog(level, msg)
level = ERROR;
if (level < DEBUG5)
level = DEBUG5;
- do_util_elog(level, msg);
+ plperl_util_elog(level, msg);
SV *
util_quote_literal(sv)
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 5a45e3e0aa..b10b4434aa 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -6,6 +6,7 @@
**********************************************************************/
#include "postgres.h"
+
/* Defined by Perl */
#undef _
@@ -285,6 +286,7 @@ static void plperl_init_shared_libs(pTHX);
static void plperl_trusted_init(void);
static void plperl_untrusted_init(void);
static HV *plperl_spi_execute_fetch_result(SPITupleTable *, uint64, int);
+static void plperl_return_next_internal(SV *sv);
static char *hek2cstr(HE *he);
static SV **hv_store_string(HV *hv, const char *key, SV *val);
static SV **hv_fetch_string(HV *hv, const char *key);
@@ -302,12 +304,27 @@ static void activate_interpreter(plperl_interp_desc *interp_desc);
static char *setlocale_perl(int category, char *locale);
#endif
+/*
+ * Decrement the refcount of the given SV within the active Perl interpreter
+ *
+ * This is handy because it reloads the active-interpreter pointer, saving
+ * some notation in callers that switch the active interpreter.
+ */
+static inline void
+SvREFCNT_dec_current(SV *sv)
+{
+ dTHX;
+
+ SvREFCNT_dec(sv);
+}
+
/*
* convert a HE (hash entry) key to a cstr in the current database encoding
*/
static char *
hek2cstr(HE *he)
{
+ dTHX;
char *ret;
SV *sv;
@@ -641,15 +658,19 @@ select_perl_context(bool trusted)
* to the database AFTER on_*_init code has run. See
* http://archives.postgresql.org/pgsql-hackers/2010-01/msg02669.php
*/
- newXS("PostgreSQL::InServer::SPI::bootstrap",
- boot_PostgreSQL__InServer__SPI, __FILE__);
+ {
+ dTHX;
- eval_pv("PostgreSQL::InServer::SPI::bootstrap()", FALSE);
- if (SvTRUE(ERRSV))
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
- errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
- errcontext("while executing PostgreSQL::InServer::SPI::bootstrap")));
+ newXS("PostgreSQL::InServer::SPI::bootstrap",
+ boot_PostgreSQL__InServer__SPI, __FILE__);
+
+ eval_pv("PostgreSQL::InServer::SPI::bootstrap()", FALSE);
+ if (SvTRUE(ERRSV))
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+ errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
+ errcontext("while executing PostgreSQL::InServer::SPI::bootstrap")));
+ }
/* Fully initialized, so mark the hashtable entry valid */
interp_desc->interp = interp;
@@ -792,53 +813,62 @@ plperl_init_interp(void)
PERL_SET_CONTEXT(plperl);
perl_construct(plperl);
- /* run END blocks in perl_destruct instead of perl_run */
- PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
-
/*
- * Record the original function for the 'require' and 'dofile' opcodes.
- * (They share the same implementation.) Ensure it's used for new
- * interpreters.
+ * Run END blocks in perl_destruct instead of perl_run. Note that dTHX
+ * loads up a pointer to the current interpreter, so we have to postpone
+ * it to here rather than put it at the function head.
*/
- if (!pp_require_orig)
- pp_require_orig = PL_ppaddr[OP_REQUIRE];
- else
{
- PL_ppaddr[OP_REQUIRE] = pp_require_orig;
- PL_ppaddr[OP_DOFILE] = pp_require_orig;
- }
+ dTHX;
+
+ PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
+
+ /*
+ * Record the original function for the 'require' and 'dofile'
+ * opcodes. (They share the same implementation.) Ensure it's used
+ * for new interpreters.
+ */
+ if (!pp_require_orig)
+ pp_require_orig = PL_ppaddr[OP_REQUIRE];
+ else
+ {
+ PL_ppaddr[OP_REQUIRE] = pp_require_orig;
+ PL_ppaddr[OP_DOFILE] = pp_require_orig;
+ }
#ifdef PLPERL_ENABLE_OPMASK_EARLY
- /*
- * For regression testing to prove that the PLC_PERLBOOT and PLC_TRUSTED
- * code doesn't even compile any unsafe ops. In future there may be a
- * valid need for them to do so, in which case this could be softened
- * (perhaps moved to plperl_trusted_init()) or removed.
- */
- PL_op_mask = plperl_opmask;
+ /*
+ * For regression testing to prove that the PLC_PERLBOOT and
+ * PLC_TRUSTED code doesn't even compile any unsafe ops. In future
+ * there may be a valid need for them to do so, in which case this
+ * could be softened (perhaps moved to plperl_trusted_init()) or
+ * removed.
+ */
+ PL_op_mask = plperl_opmask;
#endif
- if (perl_parse(plperl, plperl_init_shared_libs,
- nargs, embedding, NULL) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
- errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
- errcontext("while parsing Perl initialization")));
+ if (perl_parse(plperl, plperl_init_shared_libs,
+ nargs, embedding, NULL) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+ errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
+ errcontext("while parsing Perl initialization")));
- if (perl_run(plperl) != 0)
- ereport(ERROR,
- (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
- errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
- errcontext("while running Perl initialization")));
+ if (perl_run(plperl) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
+ errmsg("%s", strip_trailing_ws(sv2cstr(ERRSV))),
+ errcontext("while running Perl initialization")));
#ifdef PLPERL_RESTORE_LOCALE
- PLPERL_RESTORE_LOCALE(LC_COLLATE, save_collate);
- PLPERL_RESTORE_LOCALE(LC_CTYPE, save_ctype);
- PLPERL_RESTORE_LOCALE(LC_MONETARY, save_monetary);
- PLPERL_RESTORE_LOCALE(LC_NUMERIC, save_numeric);
- PLPERL_RESTORE_LOCALE(LC_TIME, save_time);
+ PLPERL_RESTORE_LOCALE(LC_COLLATE, save_collate);
+ PLPERL_RESTORE_LOCALE(LC_CTYPE, save_ctype);
+ PLPERL_RESTORE_LOCALE(LC_MONETARY, save_monetary);
+ PLPERL_RESTORE_LOCALE(LC_NUMERIC, save_numeric);
+ PLPERL_RESTORE_LOCALE(LC_TIME, save_time);
#endif
+ }
return plperl;
}
@@ -904,6 +934,7 @@ plperl_destroy_interp(PerlInterpreter **interp)
* public API so isn't portably available.) Meanwhile END blocks can
* be used to perform manual cleanup.
*/
+ dTHX;
/* Run END blocks - based on perl's perl_destruct() */
if (PL_exit_flags & PERL_EXIT_DESTRUCT_END)
@@ -930,6 +961,7 @@ plperl_destroy_interp(PerlInterpreter **interp)
static void
plperl_trusted_init(void)
{
+ dTHX;
HV *stash;
SV *sv;
char *key;
@@ -1010,6 +1042,8 @@ plperl_trusted_init(void)
static void
plperl_untrusted_init(void)
{
+ dTHX;
+
/*
* Nothing to do except execute plperl.on_plperlu_init
*/
@@ -1045,6 +1079,7 @@ strip_trailing_ws(const char *msg)
static HeapTuple
plperl_build_tuple_result(HV *perlhash, TupleDesc td)
{
+ dTHX;
Datum *values;
bool *nulls;
HE *he;
@@ -1106,6 +1141,8 @@ plperl_hash_to_datum(SV *src, TupleDesc td)
static SV *
get_perl_array_ref(SV *sv)
{
+ dTHX;
+
if (SvOK(sv) && SvROK(sv))
{
if (SvTYPE(SvRV(sv)) == SVt_PVAV)
@@ -1134,6 +1171,7 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate,
Oid arraytypid, Oid elemtypid, int32 typmod,
FmgrInfo *finfo, Oid typioparam)
{
+ dTHX;
int i;
int len = av_len(av) + 1;
@@ -1205,6 +1243,7 @@ array_to_datum_internal(AV *av, ArrayBuildState *astate,
static Datum
plperl_array_to_datum(SV *src, Oid typid, int32 typmod)
{
+ dTHX;
ArrayBuildState *astate;
Oid elemtypid;
FmgrInfo finfo;
@@ -1407,6 +1446,7 @@ plperl_sv_to_literal(SV *sv, char *fqtypename)
static SV *
plperl_ref_from_pg_array(Datum arg, Oid typid)
{
+ dTHX;
ArrayType *ar = DatumGetArrayTypeP(arg);
Oid elementtype = ARR_ELEMTYPE(ar);
int16 typlen;
@@ -1485,6 +1525,7 @@ plperl_ref_from_pg_array(Datum arg, Oid typid)
static SV *
split_array(plperl_array_info *info, int first, int last, int nest)
{
+ dTHX;
int i;
AV *result;
@@ -1518,6 +1559,7 @@ split_array(plperl_array_info *info, int first, int last, int nest)
static SV *
make_array_ref(plperl_array_info *info, int first, int last)
{
+ dTHX;
int i;
AV *result = newAV();
@@ -1555,6 +1597,7 @@ make_array_ref(plperl_array_info *info, int first, int last)
static SV *
plperl_trigger_build_args(FunctionCallInfo fcinfo)
{
+ dTHX;
TriggerData *tdata;
TupleDesc tupdesc;
int i;
@@ -1661,6 +1704,7 @@ plperl_trigger_build_args(FunctionCallInfo fcinfo)
static SV *
plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
{
+ dTHX;
EventTriggerData *tdata;
HV *hv;
@@ -1678,6 +1722,7 @@ plperl_event_trigger_build_args(FunctionCallInfo fcinfo)
static HeapTuple
plperl_modify_tuple(HV *hvTD, TriggerData *tdata, HeapTuple otup)
{
+ dTHX;
SV **svp;
HV *hvNew;
HE *he;
@@ -1874,7 +1919,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
perlret = plperl_call_perl_func(&desc, &fake_fcinfo);
- SvREFCNT_dec(perlret);
+ SvREFCNT_dec_current(perlret);
if (SPI_finish() != SPI_OK_FINISH)
elog(ERROR, "SPI_finish() failed");
@@ -1882,7 +1927,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
PG_CATCH();
{
if (desc.reference)
- SvREFCNT_dec(desc.reference);
+ SvREFCNT_dec_current(desc.reference);
current_call_data = save_call_data;
activate_interpreter(oldinterp);
PG_RE_THROW();
@@ -1890,7 +1935,7 @@ plperl_inline_handler(PG_FUNCTION_ARGS)
PG_END_TRY();
if (desc.reference)
- SvREFCNT_dec(desc.reference);
+ SvREFCNT_dec_current(desc.reference);
current_call_data = save_call_data;
activate_interpreter(oldinterp);
@@ -2018,6 +2063,7 @@ plperlu_validator(PG_FUNCTION_ARGS)
static void
plperl_create_sub(plperl_proc_desc *prodesc, char *s, Oid fn_oid)
{
+ dTHX;
dSP;
char subname[NAMEDATALEN + 40];
HV *pragma_hv = newHV();
@@ -2104,6 +2150,7 @@ plperl_init_shared_libs(pTHX)
static SV *
plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
{
+ dTHX;
dSP;
SV *retval;
int i;
@@ -2197,6 +2244,7 @@ static SV *
plperl_call_perl_trigger_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo,
SV *td)
{
+ dTHX;
dSP;
SV *retval,
*TDsv;
@@ -2265,6 +2313,7 @@ plperl_call_perl_event_trigger_func(plperl_proc_desc *desc,
FunctionCallInfo fcinfo,
SV *td)
{
+ dTHX;
dSP;
SV *retval,
*TDsv;
@@ -2384,13 +2433,14 @@ plperl_func_handler(PG_FUNCTION_ARGS)
sav = get_perl_array_ref(perlret);
if (sav)
{
+ dTHX;
int i = 0;
SV **svp = 0;
AV *rav = (AV *) SvRV(sav);
while ((svp = av_fetch(rav, i, FALSE)) != NULL)
{
- plperl_return_next(*svp);
+ plperl_return_next_internal(*svp);
i++;
}
}
@@ -2427,7 +2477,7 @@ plperl_func_handler(PG_FUNCTION_ARGS)
/* Restore the previous error callback */
error_context_stack = pl_error_context.previous;
- SvREFCNT_dec(perlret);
+ SvREFCNT_dec_current(perlret);
return retval;
}
@@ -2538,9 +2588,9 @@ plperl_trigger_handler(PG_FUNCTION_ARGS)
/* Restore the previous error callback */
error_context_stack = pl_error_context.previous;
- SvREFCNT_dec(svTD);
+ SvREFCNT_dec_current(svTD);
if (perlret)
- SvREFCNT_dec(perlret);
+ SvREFCNT_dec_current(perlret);
return retval;
}
@@ -2579,9 +2629,7 @@ plperl_event_trigger_handler(PG_FUNCTION_ARGS)
/* Restore the previous error callback */
error_context_stack = pl_error_context.previous;
- SvREFCNT_dec(svTD);
-
- return;
+ SvREFCNT_dec_current(svTD);
}
@@ -2624,7 +2672,7 @@ free_plperl_function(plperl_proc_desc *prodesc)
plperl_interp_desc *oldinterp = plperl_active_interp;
activate_interpreter(prodesc->interp);
- SvREFCNT_dec(prodesc->reference);
+ SvREFCNT_dec_current(prodesc->reference);
activate_interpreter(oldinterp);
}
/* Release all PG-owned data for this proc */
@@ -2949,6 +2997,7 @@ plperl_hash_from_datum(Datum attr)
static SV *
plperl_hash_from_tuple(HeapTuple tuple, TupleDesc tupdesc)
{
+ dTHX;
HV *hv;
int i;
@@ -3094,6 +3143,7 @@ static HV *
plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed,
int status)
{
+ dTHX;
HV *result;
check_spi_usage_allowed();
@@ -3137,15 +3187,40 @@ plperl_spi_execute_fetch_result(SPITupleTable *tuptable, uint64 processed,
/*
- * Note: plperl_return_next is called both in Postgres and Perl contexts.
- * We report any errors in Postgres fashion (via ereport). If called in
- * Perl context, it is SPI.xs's responsibility to catch the error and
- * convert to a Perl error. We assume (perhaps without adequate justification)
- * that we need not abort the current transaction if the Perl code traps the
- * error.
+ * plperl_return_next catches any error and converts it to a Perl error.
+ * We assume (perhaps without adequate justification) that we need not abort
+ * the current transaction if the Perl code traps the error.
*/
void
plperl_return_next(SV *sv)
+{
+ MemoryContext oldcontext = CurrentMemoryContext;
+
+ PG_TRY();
+ {
+ plperl_return_next_internal(sv);
+ }
+ PG_CATCH();
+ {
+ ErrorData *edata;
+
+ /* Must reset elog.c's state */
+ MemoryContextSwitchTo(oldcontext);
+ edata = CopyErrorData();
+ FlushErrorState();
+
+ /* Punt the error to Perl */
+ croak_cstr(edata->message);
+ }
+ PG_END_TRY();
+}
+
+/*
+ * plperl_return_next_internal reports any errors in Postgres fashion
+ * (via ereport).
+ */
+static void
+plperl_return_next_internal(SV *sv)
{
plperl_proc_desc *prodesc;
FunctionCallInfo fcinfo;
@@ -3336,6 +3411,7 @@ plperl_spi_fetchrow(char *cursor)
PG_TRY();
{
+ dTHX;
Portal p = SPI_cursor_find(cursor);
if (!p)
@@ -3577,6 +3653,8 @@ plperl_spi_exec_prepared(char *query, HV *attr, int argc, SV **argv)
PG_TRY();
{
+ dTHX;
+
/************************************************************
* Fetch the saved plan descriptor, see if it's o.k.
************************************************************/
@@ -3821,6 +3899,47 @@ plperl_spi_freeplan(char *query)
SPI_freeplan(plan);
}
+/*
+ * Implementation of plperl's elog() function
+ *
+ * If the error level is less than ERROR, we'll just emit the message and
+ * return. When it is ERROR, elog() will longjmp, which we catch and
+ * turn into a Perl croak(). Note we are assuming that elog() can't have
+ * any internal failures that are so bad as to require a transaction abort.
+ *
+ * The main reason this is out-of-line is to avoid conflicts between XSUB.h
+ * and the PG_TRY macros.
+ */
+void
+plperl_util_elog(int level, SV *msg)
+{
+ MemoryContext oldcontext = CurrentMemoryContext;
+ char *volatile cmsg = NULL;
+
+ PG_TRY();
+ {
+ cmsg = sv2cstr(msg);
+ elog(level, "%s", cmsg);
+ pfree(cmsg);
+ }
+ PG_CATCH();
+ {
+ ErrorData *edata;
+
+ /* Must reset elog.c's state */
+ MemoryContextSwitchTo(oldcontext);
+ edata = CopyErrorData();
+ FlushErrorState();
+
+ if (cmsg)
+ pfree(cmsg);
+
+ /* Punt the error to Perl */
+ croak_cstr(edata->message);
+ }
+ PG_END_TRY();
+}
+
/*
* Store an SV into a hash table under a key that is a string assumed to be
* in the current database's encoding.
@@ -3828,6 +3947,7 @@ plperl_spi_freeplan(char *query)
static SV **
hv_store_string(HV *hv, const char *key, SV *val)
{
+ dTHX;
int32 hlen;
char *hkey;
SV **ret;
@@ -3854,6 +3974,7 @@ hv_store_string(HV *hv, const char *key, SV *val)
static SV **
hv_fetch_string(HV *hv, const char *key)
{
+ dTHX;
int32 hlen;
char *hkey;
SV **ret;
@@ -3912,6 +4033,7 @@ plperl_inline_callback(void *arg)
static char *
setlocale_perl(int category, char *locale)
{
+ dTHX;
char *RETVAL = setlocale(category, locale);
if (RETVAL)
@@ -3976,4 +4098,4 @@ setlocale_perl(int category, char *locale)
return RETVAL;
}
-#endif
+#endif /* WIN32 */
diff --git a/src/pl/plperl/plperl.h b/src/pl/plperl/plperl.h
index eecd192802..c4e06d089f 100644
--- a/src/pl/plperl/plperl.h
+++ b/src/pl/plperl/plperl.h
@@ -24,7 +24,7 @@
#ifdef isnan
#undef isnan
#endif
-#endif
+#endif /* WIN32 */
/*
* Supply a value of PERL_UNUSED_DECL that will satisfy gcc - the one
@@ -43,10 +43,22 @@
#endif
-/* required for perl API */
+/*
+ * Get the basic Perl API. We use PERL_NO_GET_CONTEXT mode so that our code
+ * can compile against MULTIPLICITY Perl builds without including XSUB.h.
+ */
+#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
+
+/*
+ * We want to include XSUB.h only within .xs files, because on some platforms
+ * it undesirably redefines a lot of libc functions. But it must appear
+ * before ppport.h, so use a #define flag to control inclusion here.
+ */
+#ifdef PG_NEED_PERL_XSUB_H
#include "XSUB.h"
+#endif
/* put back our snprintf and vsnprintf */
#ifdef USE_REPL_SNPRINTF
@@ -106,5 +118,6 @@ SV *plperl_spi_query_prepared(char *, int, SV **);
void plperl_spi_freeplan(char *);
void plperl_spi_cursor_close(char *);
char *plperl_sv_to_literal(SV *, char *);
+void plperl_util_elog(int level, SV *msg);
#endif /* PL_PERL_H */
diff --git a/src/pl/plperl/plperl_helpers.h b/src/pl/plperl/plperl_helpers.h
index 76124edc07..65b85a27ae 100644
--- a/src/pl/plperl/plperl_helpers.h
+++ b/src/pl/plperl/plperl_helpers.h
@@ -50,6 +50,7 @@ utf_e2u(const char *str)
static inline char *
sv2cstr(SV *sv)
{
+ dTHX;
char *val,
*res;
STRLEN len;
@@ -107,6 +108,7 @@ sv2cstr(SV *sv)
static inline SV *
cstr2sv(const char *str)
{
+ dTHX;
SV *sv;
char *utf8_str;
@@ -134,6 +136,8 @@ cstr2sv(const char *str)
static inline void
croak_cstr(const char *str)
{
+ dTHX;
+
#ifdef croak_sv
/* Use sv_2mortal() to be sure the transient SV gets freed */
croak_sv(sv_2mortal(cstr2sv(str)));
--
cgit v1.2.3
From 3c163a7fc76debbbdad1bdd3c43721cffe72f4db Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 28 Jul 2017 14:25:28 -0400
Subject: PL/Perl portability fix: absorb relevant -D switches from Perl.
The Perl documentation is very clear that stuff calling libperl should
be built with the compiler switches shown by Perl's $Config{ccflags}.
We'd been ignoring that up to now, and mostly getting away with it,
but recent Perl versions contain ABI compatibility cross-checks that
fail on some builds because of this omission. In particular the
sizeof(PerlInterpreter) can come out different due to some fields being
added or removed; which means we have a live ABI hazard that we'd better
fix rather than continuing to sweep it under the rug.
However, it still seems like a bad idea to just absorb $Config{ccflags}
verbatim. In some environments Perl was built with a different compiler
that doesn't even use the same switch syntax. -D switch syntax is pretty
universal though, and absorbing Perl's -D switches really ought to be
enough to fix the problem.
Furthermore, Perl likes to inject stuff like -D_LARGEFILE_SOURCE and
-D_FILE_OFFSET_BITS=64 into $Config{ccflags}, which affect libc ABIs on
platforms where they're relevant. Adopting those seems dangerous too.
It's unclear whether a build wherein Perl and Postgres have different ideas
of sizeof(off_t) etc would work, or whether anyone would care about making
it work. But it's dead certain that having different stdio ABIs in
core Postgres and PL/Perl will not work; we've seen that movie before.
Therefore, let's also ignore -D switches for symbols beginning with
underscore. The symbols that we actually need to import should be the ones
mentioned in perl.h's PL_bincompat_options stanza, and none of those start
with underscore, so this seems likely to work. (If it turns out not to
work everywhere, we could consider intersecting the symbols mentioned in
PL_bincompat_options with the -D switches. But that will be much more
complicated, so let's try this way first.)
This will need to be back-patched, but first let's see what the
buildfarm makes of it.
Ashutosh Sharma, some adjustments by me
Discussion: https://postgr.es/m/CANFyU97OVQ3+Mzfmt3MhuUm5NwPU=-FtbNH5Eb7nZL9ua8=rcA@mail.gmail.com
---
config/perl.m4 | 25 +++++++++++++++++++++++++
configure | 13 +++++++++++++
configure.in | 1 +
contrib/hstore_plperl/Makefile | 2 +-
src/Makefile.global.in | 1 +
src/pl/plperl/GNUmakefile | 6 +++++-
src/tools/msvc/Mkvcbuild.pm | 27 +++++++++++++++++++++++++--
7 files changed, 71 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/config/perl.m4 b/config/perl.m4
index bed2eae57f..9706c4de6a 100644
--- a/config/perl.m4
+++ b/config/perl.m4
@@ -49,6 +49,31 @@ AC_DEFUN([PGAC_CHECK_PERL_CONFIGS],
[m4_foreach([pgac_item], [$1], [PGAC_CHECK_PERL_CONFIG(pgac_item)])])
+# PGAC_CHECK_PERL_EMBED_CCFLAGS
+# -----------------------------
+# We selectively extract stuff from $Config{ccflags}. We don't really need
+# anything except -D switches, and other sorts of compiler switches can
+# actively break things if Perl was compiled with a different compiler.
+# Moreover, although Perl likes to put stuff like -D_LARGEFILE_SOURCE and
+# -D_FILE_OFFSET_BITS=64 here, it would be fatal to try to compile PL/Perl
+# to a different libc ABI than core Postgres uses. The available information
+# says that all the symbols that affect Perl's own ABI begin with letters,
+# so it should be sufficient to adopt -D switches for symbols not beginning
+# with underscore.
+# For debugging purposes, let's have the configure output report the raw
+# ccflags value as well as the set of flags we chose to adopt.
+AC_DEFUN([PGAC_CHECK_PERL_EMBED_CCFLAGS],
+[AC_REQUIRE([PGAC_PATH_PERL])
+AC_MSG_CHECKING([for CFLAGS recommended by Perl])
+perl_ccflags=`$PERL -MConfig -e ['print $Config{ccflags}']`
+AC_MSG_RESULT([$perl_ccflags])
+AC_MSG_CHECKING([for CFLAGS to compile embedded Perl])
+perl_embed_ccflags=`$PERL -MConfig -e ['foreach $f (split(" ",$Config{ccflags})) {print $f, " " if ($f =~ /^-D[^_]/)}']`
+AC_SUBST(perl_embed_ccflags)dnl
+AC_MSG_RESULT([$perl_embed_ccflags])
+])# PGAC_CHECK_PERL_EMBED_CCFLAGS
+
+
# PGAC_CHECK_PERL_EMBED_LDFLAGS
# -----------------------------
# We are after Embed's ldopts, but without the subset mentioned in
diff --git a/configure b/configure
index aff72eb008..a16e4f42d8 100755
--- a/configure
+++ b/configure
@@ -668,6 +668,7 @@ python_version
python_majorversion
PYTHON
perl_embed_ldflags
+perl_embed_ccflags
perl_useshrplib
perl_privlibexp
perl_archlibexp
@@ -7767,6 +7768,18 @@ documentation for details. Use --without-perl to disable building
PL/Perl." "$LINENO" 5
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLAGS recommended by Perl" >&5
+$as_echo_n "checking for CFLAGS recommended by Perl... " >&6; }
+perl_ccflags=`$PERL -MConfig -e 'print $Config{ccflags}'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $perl_ccflags" >&5
+$as_echo "$perl_ccflags" >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CFLAGS to compile embedded Perl" >&5
+$as_echo_n "checking for CFLAGS to compile embedded Perl... " >&6; }
+perl_embed_ccflags=`$PERL -MConfig -e 'foreach $f (split(" ",$Config{ccflags})) {print $f, " " if ($f =~ /^-D[^_]/)}'`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $perl_embed_ccflags" >&5
+$as_echo "$perl_embed_ccflags" >&6; }
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for flags to link embedded Perl" >&5
$as_echo_n "checking for flags to link embedded Perl... " >&6; }
if test "$PORTNAME" = "win32" ; then
diff --git a/configure.in b/configure.in
index 72e5b17ea7..13c69d6fbd 100644
--- a/configure.in
+++ b/configure.in
@@ -938,6 +938,7 @@ You might have to rebuild your Perl installation. Refer to the
documentation for details. Use --without-perl to disable building
PL/Perl.])
fi
+ PGAC_CHECK_PERL_EMBED_CCFLAGS
PGAC_CHECK_PERL_EMBED_LDFLAGS
fi
diff --git a/contrib/hstore_plperl/Makefile b/contrib/hstore_plperl/Makefile
index 34e1e137f7..c0906db1f5 100644
--- a/contrib/hstore_plperl/Makefile
+++ b/contrib/hstore_plperl/Makefile
@@ -38,4 +38,4 @@ endif
# last, probably because it sometimes contains some header files with names
# that clash with some of ours, or with some that we include, notably on
# Windows.
-override CPPFLAGS := $(CPPFLAGS) -I$(perl_archlibexp)/CORE
+override CPPFLAGS := $(CPPFLAGS) $(perl_embed_ccflags) -I$(perl_archlibexp)/CORE
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index dc8a89af8e..0d3f8ca950 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -304,6 +304,7 @@ else
endif
perl_archlibexp = @perl_archlibexp@
perl_privlibexp = @perl_privlibexp@
+perl_embed_ccflags = @perl_embed_ccflags@
perl_embed_ldflags = @perl_embed_ldflags@
# Miscellaneous
diff --git a/src/pl/plperl/GNUmakefile b/src/pl/plperl/GNUmakefile
index b8e3585254..191f74067a 100644
--- a/src/pl/plperl/GNUmakefile
+++ b/src/pl/plperl/GNUmakefile
@@ -12,7 +12,11 @@ override CPPFLAGS += -DPLPERL_HAVE_UID_GID
override CPPFLAGS += -Wno-comment
endif
-override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) -I$(perl_archlibexp)/CORE
+# Note: we need to make sure that the CORE directory is included last,
+# probably because it sometimes contains some header files with names
+# that clash with some of ours, or with some that we include, notably on
+# Windows.
+override CPPFLAGS := -I. -I$(srcdir) $(CPPFLAGS) $(perl_embed_ccflags) -I$(perl_archlibexp)/CORE
rpathdir = $(perl_archlibexp)/CORE
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index e0bf60797f..a7e3a014d7 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -517,7 +517,26 @@ sub mkvcbuild
my $plperl =
$solution->AddProject('plperl', 'dll', 'PLs', 'src/pl/plperl');
$plperl->AddIncludeDir($solution->{options}->{perl} . '/lib/CORE');
- $plperl->AddDefine('PLPERL_HAVE_UID_GID');
+
+ # Add defines from Perl's ccflags; see PGAC_CHECK_PERL_EMBED_CCFLAGS
+ my @perl_embed_ccflags;
+ foreach my $f (split(" ",$Config{ccflags}))
+ {
+ if ($f =~ /^-D[^_]/)
+ {
+ $f =~ s/\-D//;
+ push(@perl_embed_ccflags, $f);
+ }
+ }
+
+ # XXX this probably is redundant now?
+ push(@perl_embed_ccflags, 'PLPERL_HAVE_UID_GID');
+
+ foreach my $f (@perl_embed_ccflags)
+ {
+ $plperl->AddDefine($f);
+ }
+
foreach my $xs ('SPI.xs', 'Util.xs')
{
(my $xsc = $xs) =~ s/\.xs/.c/;
@@ -601,7 +620,11 @@ sub mkvcbuild
'hstore_plperl', 'contrib/hstore_plperl',
'plperl', 'src/pl/plperl',
'hstore', 'contrib/hstore');
- $hstore_plperl->AddDefine('PLPERL_HAVE_UID_GID');
+
+ foreach my $f (@perl_embed_ccflags)
+ {
+ $hstore_plperl->AddDefine($f);
+ }
}
$mf =
--
cgit v1.2.3
From 9dea962b3ef48f6e96172653b7cf80cb5f53e6b6 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 28 Jul 2017 17:44:48 -0400
Subject: Include publication owner's name in the output of \dRp+.
Without this, \dRp prints information that \dRp+ does not, which
seems pretty odd.
Daniel Gustafsson
Discussion: https://postgr.es/m/3641F19B-336A-431A-86CE-A80562505C5E@yesql.se
---
src/bin/psql/describe.c | 11 ++++---
src/test/regress/expected/publication.out | 48 +++++++++++++++----------------
2 files changed, 31 insertions(+), 28 deletions(-)
(limited to 'src')
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 78e9d895f0..798e71045f 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -5162,8 +5162,9 @@ describePublications(const char *pattern)
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
- "SELECT oid, pubname, puballtables, pubinsert,\n"
- " pubupdate, pubdelete\n"
+ "SELECT oid, pubname,\n"
+ " pg_catalog.pg_get_userbyid(pubowner) AS owner,\n"
+ " puballtables, pubinsert, pubupdate, pubdelete\n"
"FROM pg_catalog.pg_publication\n");
processSQLNamePattern(pset.db, &buf, pattern, false, false,
@@ -5198,13 +5199,13 @@ describePublications(const char *pattern)
for (i = 0; i < PQntuples(res); i++)
{
const char align = 'l';
- int ncols = 4;
+ int ncols = 5;
int nrows = 1;
int tables = 0;
PGresult *tabres;
char *pubid = PQgetvalue(res, i, 0);
char *pubname = PQgetvalue(res, i, 1);
- bool puballtables = strcmp(PQgetvalue(res, i, 2), "t") == 0;
+ bool puballtables = strcmp(PQgetvalue(res, i, 3), "t") == 0;
int j;
PQExpBufferData title;
printTableOpt myopt = pset.popt.topt;
@@ -5214,6 +5215,7 @@ describePublications(const char *pattern)
printfPQExpBuffer(&title, _("Publication %s"), pubname);
printTableInit(&cont, &myopt, title.data, ncols, nrows);
+ printTableAddHeader(&cont, gettext_noop("Owner"), true, align);
printTableAddHeader(&cont, gettext_noop("All tables"), true, align);
printTableAddHeader(&cont, gettext_noop("Inserts"), true, align);
printTableAddHeader(&cont, gettext_noop("Updates"), true, align);
@@ -5223,6 +5225,7 @@ describePublications(const char *pattern)
printTableAddCell(&cont, PQgetvalue(res, i, 3), false, false);
printTableAddCell(&cont, PQgetvalue(res, i, 4), false, false);
printTableAddCell(&cont, PQgetvalue(res, i, 5), false, false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 6), false, false);
if (!puballtables)
{
diff --git a/src/test/regress/expected/publication.out b/src/test/regress/expected/publication.out
index 50592c63a9..b101331d69 100644
--- a/src/test/regress/expected/publication.out
+++ b/src/test/regress/expected/publication.out
@@ -76,10 +76,10 @@ Publications:
"testpub_foralltables"
\dRp+ testpub_foralltables
- Publication testpub_foralltables
- All tables | Inserts | Updates | Deletes
-------------+---------+---------+---------
- t | t | t | f
+ Publication testpub_foralltables
+ Owner | All tables | Inserts | Updates | Deletes
+--------------------------+------------+---------+---------+---------
+ regress_publication_user | t | t | t | f
(1 row)
DROP TABLE testpub_tbl2;
@@ -89,19 +89,19 @@ CREATE TABLE testpub_tbl3a (b text) INHERITS (testpub_tbl3);
CREATE PUBLICATION testpub3 FOR TABLE testpub_tbl3;
CREATE PUBLICATION testpub4 FOR TABLE ONLY testpub_tbl3;
\dRp+ testpub3
- Publication testpub3
- All tables | Inserts | Updates | Deletes
-------------+---------+---------+---------
- f | t | t | t
+ Publication testpub3
+ Owner | All tables | Inserts | Updates | Deletes
+--------------------------+------------+---------+---------+---------
+ regress_publication_user | f | t | t | t
Tables:
"public.testpub_tbl3"
"public.testpub_tbl3a"
\dRp+ testpub4
- Publication testpub4
- All tables | Inserts | Updates | Deletes
-------------+---------+---------+---------
- f | t | t | t
+ Publication testpub4
+ Owner | All tables | Inserts | Updates | Deletes
+--------------------------+------------+---------+---------+---------
+ regress_publication_user | f | t | t | t
Tables:
"public.testpub_tbl3"
@@ -119,10 +119,10 @@ ERROR: relation "testpub_tbl1" is already member of publication "testpub_fortbl
CREATE PUBLICATION testpub_fortbl FOR TABLE testpub_tbl1;
ERROR: publication "testpub_fortbl" already exists
\dRp+ testpub_fortbl
- Publication testpub_fortbl
- All tables | Inserts | Updates | Deletes
-------------+---------+---------+---------
- f | t | t | t
+ Publication testpub_fortbl
+ Owner | All tables | Inserts | Updates | Deletes
+--------------------------+------------+---------+---------+---------
+ regress_publication_user | f | t | t | t
Tables:
"pub_test.testpub_nopk"
"public.testpub_tbl1"
@@ -165,10 +165,10 @@ Publications:
"testpub_fortbl"
\dRp+ testpub_default
- Publication testpub_default
- All tables | Inserts | Updates | Deletes
-------------+---------+---------+---------
- f | t | t | t
+ Publication testpub_default
+ Owner | All tables | Inserts | Updates | Deletes
+--------------------------+------------+---------+---------+---------
+ regress_publication_user | f | t | t | t
Tables:
"pub_test.testpub_nopk"
"public.testpub_tbl1"
@@ -210,10 +210,10 @@ DROP TABLE testpub_parted;
DROP VIEW testpub_view;
DROP TABLE testpub_tbl1;
\dRp+ testpub_default
- Publication testpub_default
- All tables | Inserts | Updates | Deletes
-------------+---------+---------+---------
- f | t | t | t
+ Publication testpub_default
+ Owner | All tables | Inserts | Updates | Deletes
+--------------------------+------------+---------+---------+---------
+ regress_publication_user | f | t | t | t
(1 row)
-- fail - must be owner of publication
--
cgit v1.2.3
From d47cfef7116fb36349949f5c757aa2112c249804 Mon Sep 17 00:00:00 2001
From: Andres Freund
Date: Tue, 25 Jul 2017 17:37:17 -0700
Subject: Move interrupt checking from ExecProcNode() to executor nodes.
In a followup commit ExecProcNode(), and especially the large switch
it contains, will largely be replaced by a function pointer directly
to the correct node. The node functions will then get invoked by a
thin inline function wrapper. To avoid having to include miscadmin.h
in headers - CHECK_FOR_INTERRUPTS() - move the interrupt checks into
the individual executor routines.
While looking through all executor nodes, I noticed a number of
arguably missing interrupt checks, add these too.
Author: Andres Freund, Tom Lane
Reviewed-By: Tom Lane
Discussion:
https://postgr.es/m/22833.1490390175@sss.pgh.pa.us
---
src/backend/executor/execProcnode.c | 2 --
src/backend/executor/nodeAgg.c | 8 ++++++++
src/backend/executor/nodeAppend.c | 3 +++
src/backend/executor/nodeBitmapHeapscan.c | 3 +++
src/backend/executor/nodeCustom.c | 3 +++
src/backend/executor/nodeGather.c | 4 ++++
src/backend/executor/nodeGatherMerge.c | 4 ++++
src/backend/executor/nodeGroup.c | 3 +++
src/backend/executor/nodeHash.c | 6 ++++++
src/backend/executor/nodeHashjoin.c | 15 ++++++++-------
src/backend/executor/nodeIndexonlyscan.c | 3 +++
src/backend/executor/nodeIndexscan.c | 7 +++++++
src/backend/executor/nodeLimit.c | 3 +++
src/backend/executor/nodeLockRows.c | 3 +++
src/backend/executor/nodeMaterial.c | 2 ++
src/backend/executor/nodeMergeAppend.c | 4 +++-
src/backend/executor/nodeMergejoin.c | 3 +++
src/backend/executor/nodeModifyTable.c | 2 ++
src/backend/executor/nodeNestloop.c | 3 +++
src/backend/executor/nodeProjectSet.c | 3 +++
src/backend/executor/nodeRecursiveunion.c | 2 ++
src/backend/executor/nodeResult.c | 3 +++
src/backend/executor/nodeSetOp.c | 5 +++++
src/backend/executor/nodeSort.c | 2 ++
src/backend/executor/nodeSubplan.c | 5 +++++
src/backend/executor/nodeTableFuncscan.c | 2 ++
src/backend/executor/nodeTidscan.c | 3 +++
src/backend/executor/nodeUnique.c | 3 +++
src/backend/executor/nodeWindowAgg.c | 5 +++++
29 files changed, 104 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 294ad2cff9..20fd9f822e 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -399,8 +399,6 @@ ExecProcNode(PlanState *node)
{
TupleTableSlot *result;
- CHECK_FOR_INTERRUPTS();
-
if (node->chgParam != NULL) /* something changed */
ExecReScan(node); /* let ReScan handle this */
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index de9a18e71c..377916dae7 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -677,6 +677,8 @@ fetch_input_tuple(AggState *aggstate)
if (aggstate->sort_in)
{
+ /* make sure we check for interrupts in either path through here */
+ CHECK_FOR_INTERRUPTS();
if (!tuplesort_gettupleslot(aggstate->sort_in, true, false,
aggstate->sort_slot, NULL))
return NULL;
@@ -1414,6 +1416,8 @@ process_ordered_aggregate_multi(AggState *aggstate,
while (tuplesort_gettupleslot(pertrans->sortstates[aggstate->current_set],
true, true, slot1, &newAbbrevVal))
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Extract the first numTransInputs columns as datums to pass to the
* transfn. (This will help execTuplesMatch too, so we do it
@@ -2100,6 +2104,8 @@ ExecAgg(AggState *node)
{
TupleTableSlot *result = NULL;
+ CHECK_FOR_INTERRUPTS();
+
if (!node->agg_done)
{
/* Dispatch based on strategy */
@@ -2563,6 +2569,8 @@ agg_retrieve_hash_table(AggState *aggstate)
TupleTableSlot *hashslot = perhash->hashslot;
int i;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Find the next entry in the hash table
*/
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index aae5e3fa63..58045e05e5 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -59,6 +59,7 @@
#include "executor/execdebug.h"
#include "executor/nodeAppend.h"
+#include "miscadmin.h"
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -204,6 +205,8 @@ ExecAppend(AppendState *node)
PlanState *subnode;
TupleTableSlot *result;
+ CHECK_FOR_INTERRUPTS();
+
/*
* figure out which subplan we are currently processing
*/
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index 7e0ba030b7..cf109d5049 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -41,6 +41,7 @@
#include "access/transam.h"
#include "executor/execdebug.h"
#include "executor/nodeBitmapHeapscan.h"
+#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
@@ -192,6 +193,8 @@ BitmapHeapNext(BitmapHeapScanState *node)
Page dp;
ItemId lp;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Get next page of results if needed
*/
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index 69e27047f1..fc15974a2d 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -15,6 +15,7 @@
#include "executor/nodeCustom.h"
#include "nodes/execnodes.h"
#include "nodes/plannodes.h"
+#include "miscadmin.h"
#include "parser/parsetree.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
@@ -104,6 +105,8 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
TupleTableSlot *
ExecCustomScan(CustomScanState *node)
{
+ CHECK_FOR_INTERRUPTS();
+
Assert(node->methods->ExecCustomScan != NULL);
return node->methods->ExecCustomScan(node);
}
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index f83cd584d7..5dbe19c056 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -128,6 +128,8 @@ ExecGather(GatherState *node)
TupleTableSlot *slot;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
/*
* Initialize the parallel context and workers on first execution. We do
* this on first execution rather than during node initialization, as it
@@ -247,6 +249,8 @@ gather_getnext(GatherState *gatherstate)
while (gatherstate->reader != NULL || gatherstate->need_to_scan_locally)
{
+ CHECK_FOR_INTERRUPTS();
+
if (gatherstate->reader != NULL)
{
MemoryContext oldContext;
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 80ee1fc89b..0aff3798f7 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -164,6 +164,8 @@ ExecGatherMerge(GatherMergeState *node)
ExprContext *econtext;
int i;
+ CHECK_FOR_INTERRUPTS();
+
/*
* As with Gather, we don't launch workers until this node is actually
* executed.
@@ -393,6 +395,8 @@ gather_merge_init(GatherMergeState *gm_state)
reread:
for (i = 0; i < nreaders + 1; i++)
{
+ CHECK_FOR_INTERRUPTS();
+
if (!gm_state->gm_tuple_buffers[i].done &&
(TupIsNull(gm_state->gm_slots[i]) ||
gm_state->gm_slots[i]->tts_isempty))
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index af9ba4905e..fc5e0e59bc 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -24,6 +24,7 @@
#include "executor/executor.h"
#include "executor/nodeGroup.h"
+#include "miscadmin.h"
/*
@@ -40,6 +41,8 @@ ExecGroup(GroupState *node)
TupleTableSlot *firsttupleslot;
TupleTableSlot *outerslot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get state info from node
*/
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index 075f4ed11c..fbeb562489 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -810,6 +810,9 @@ ExecHashIncreaseNumBuckets(HashJoinTable hashtable)
idx += MAXALIGN(HJTUPLE_OVERHEAD +
HJTUPLE_MINTUPLE(hashTuple)->t_len);
}
+
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
}
}
@@ -1192,6 +1195,9 @@ ExecScanHashTableForUnmatched(HashJoinState *hjstate, ExprContext *econtext)
hashTuple = hashTuple->next;
}
+
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
}
/*
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 668ed871e1..252960c81c 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -92,6 +92,14 @@ ExecHashJoin(HashJoinState *node)
*/
for (;;)
{
+ /*
+ * It's possible to iterate this loop many times before returning a
+ * tuple, in some pathological cases such as needing to move much of
+ * the current batch to a later batch. So let's check for interrupts
+ * each time through.
+ */
+ CHECK_FOR_INTERRUPTS();
+
switch (node->hj_JoinState)
{
case HJ_BUILD_HASHTABLE:
@@ -246,13 +254,6 @@ ExecHashJoin(HashJoinState *node)
case HJ_SCAN_BUCKET:
- /*
- * We check for interrupts here because this corresponds to
- * where we'd fetch a row from a child plan node in other join
- * types.
- */
- CHECK_FOR_INTERRUPTS();
-
/*
* Scan the selected hash bucket for matches to current outer
*/
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index 890e54416a..e2000764a4 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -34,6 +34,7 @@
#include "executor/execdebug.h"
#include "executor/nodeIndexonlyscan.h"
#include "executor/nodeIndexscan.h"
+#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/predicate.h"
#include "utils/memutils.h"
@@ -117,6 +118,8 @@ IndexOnlyNext(IndexOnlyScanState *node)
{
HeapTuple tuple = NULL;
+ CHECK_FOR_INTERRUPTS();
+
/*
* We can skip the heap fetch if the TID references a heap page on
* which all tuples are known visible to everybody. In any case,
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 75b10115f5..6704ede995 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -34,6 +34,7 @@
#include "executor/execdebug.h"
#include "executor/nodeIndexscan.h"
#include "lib/pairingheap.h"
+#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "utils/array.h"
@@ -131,6 +132,8 @@ IndexNext(IndexScanState *node)
*/
while ((tuple = index_getnext(scandesc, direction)) != NULL)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Store the scanned tuple in the scan tuple slot of the scan state.
* Note: we pass 'false' because tuples returned by amgetnext are
@@ -233,6 +236,8 @@ IndexNextWithReorder(IndexScanState *node)
for (;;)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Check the reorder queue first. If the topmost tuple in the queue
* has an ORDER BY value smaller than (or equal to) the value last
@@ -299,6 +304,8 @@ next_indextuple:
{
/* Fails recheck, so drop it and loop back for another */
InstrCountFiltered2(node, 1);
+ /* allow this loop to be cancellable */
+ CHECK_FOR_INTERRUPTS();
goto next_indextuple;
}
}
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index abd060d75f..2ed3523257 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -23,6 +23,7 @@
#include "executor/executor.h"
#include "executor/nodeLimit.h"
+#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
static void recompute_limits(LimitState *node);
@@ -43,6 +44,8 @@ ExecLimit(LimitState *node)
TupleTableSlot *slot;
PlanState *outerPlan;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index f519794cf3..dd4e2c5f2f 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -26,6 +26,7 @@
#include "executor/executor.h"
#include "executor/nodeLockRows.h"
#include "foreign/fdwapi.h"
+#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "utils/rel.h"
#include "utils/tqual.h"
@@ -44,6 +45,8 @@ ExecLockRows(LockRowsState *node)
bool epq_needed;
ListCell *lc;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 32b7269cda..3342949590 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -45,6 +45,8 @@ ExecMaterial(MaterialState *node)
bool eof_tuplestore;
TupleTableSlot *slot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get state info from node
*/
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index fef83dbdbd..d41def1350 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -40,8 +40,8 @@
#include "executor/execdebug.h"
#include "executor/nodeMergeAppend.h"
-
#include "lib/binaryheap.h"
+#include "miscadmin.h"
/*
* We have one slot for each item in the heap array. We use SlotNumber
@@ -175,6 +175,8 @@ ExecMergeAppend(MergeAppendState *node)
TupleTableSlot *result;
SlotNumber i;
+ CHECK_FOR_INTERRUPTS();
+
if (!node->ms_initialized)
{
/*
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 6a145ee33a..324b61b8c0 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -95,6 +95,7 @@
#include "access/nbtree.h"
#include "executor/execdebug.h"
#include "executor/nodeMergejoin.h"
+#include "miscadmin.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
@@ -610,6 +611,8 @@ ExecMergeJoin(MergeJoinState *node)
bool doFillOuter;
bool doFillInner;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from node
*/
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 77ba15dd90..637a582e1c 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1551,6 +1551,8 @@ ExecModifyTable(ModifyTableState *node)
HeapTupleData oldtupdata;
HeapTuple oldtuple;
+ CHECK_FOR_INTERRUPTS();
+
/*
* This should NOT get called during EvalPlanQual; we should have passed a
* subplan tree to EvalPlanQual, instead. Use a runtime test not just
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 0065fe601e..bedc374ef0 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -23,6 +23,7 @@
#include "executor/execdebug.h"
#include "executor/nodeNestloop.h"
+#include "miscadmin.h"
#include "utils/memutils.h"
@@ -69,6 +70,8 @@ ExecNestLoop(NestLoopState *node)
ExprContext *econtext;
ListCell *lc;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 01048cc826..3b69c7adee 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -24,6 +24,7 @@
#include "executor/executor.h"
#include "executor/nodeProjectSet.h"
+#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "utils/memutils.h"
@@ -46,6 +47,8 @@ ExecProjectSet(ProjectSetState *node)
PlanState *outerPlan;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
econtext = node->ps.ps_ExprContext;
/*
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index fc1c00d68f..2802fffa2b 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -75,6 +75,8 @@ ExecRecursiveUnion(RecursiveUnionState *node)
TupleTableSlot *slot;
bool isnew;
+ CHECK_FOR_INTERRUPTS();
+
/* 1. Evaluate non-recursive term */
if (!node->recursing)
{
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index a753a53419..f007f46784 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -47,6 +47,7 @@
#include "executor/executor.h"
#include "executor/nodeResult.h"
+#include "miscadmin.h"
#include "utils/memutils.h"
@@ -70,6 +71,8 @@ ExecResult(ResultState *node)
PlanState *outerPlan;
ExprContext *econtext;
+ CHECK_FOR_INTERRUPTS();
+
econtext = node->ps.ps_ExprContext;
/*
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 9c7812e519..56c5643f17 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -47,6 +47,7 @@
#include "access/htup_details.h"
#include "executor/executor.h"
#include "executor/nodeSetOp.h"
+#include "miscadmin.h"
#include "utils/memutils.h"
@@ -185,6 +186,8 @@ ExecSetOp(SetOpState *node)
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* If the previously-returned tuple needs to be returned more than once,
* keep returning it.
@@ -428,6 +431,8 @@ setop_retrieve_hash_table(SetOpState *setopstate)
*/
while (!setopstate->setop_done)
{
+ CHECK_FOR_INTERRUPTS();
+
/*
* Find the next entry in the hash table
*/
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 924b458df8..799a4e9204 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -43,6 +43,8 @@ ExecSort(SortState *node)
Tuplesortstate *tuplesortstate;
TupleTableSlot *slot;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get state info from node
*/
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e8fa4c8547..fe10e809df 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -33,6 +33,7 @@
#include "executor/executor.h"
#include "executor/nodeSubplan.h"
#include "nodes/makefuncs.h"
+#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "utils/array.h"
#include "utils/lsyscache.h"
@@ -65,6 +66,8 @@ ExecSubPlan(SubPlanState *node,
{
SubPlan *subplan = node->subplan;
+ CHECK_FOR_INTERRUPTS();
+
/* Set non-null as default */
*isNull = false;
@@ -618,6 +621,8 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
InitTupleHashIterator(hashtable, &hashiter);
while ((entry = ScanTupleHashTable(hashtable, &hashiter)) != NULL)
{
+ CHECK_FOR_INTERRUPTS();
+
ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
if (!execTuplesUnequal(slot, hashtable->tableslot,
numCols, keyColIdx,
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index bb016ec8f6..2859363fe2 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -440,6 +440,8 @@ tfuncLoadRows(TableFuncScanState *tstate, ExprContext *econtext)
ListCell *cell = list_head(tstate->coldefexprs);
int colno;
+ CHECK_FOR_INTERRUPTS();
+
ExecClearTuple(tstate->ss.ss_ScanTupleSlot);
/*
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index 96af2d21d9..c122473bdf 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -26,6 +26,7 @@
#include "catalog/pg_type.h"
#include "executor/execdebug.h"
#include "executor/nodeTidscan.h"
+#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "storage/bufmgr.h"
#include "utils/array.h"
@@ -400,6 +401,8 @@ TidNext(TidScanState *node)
node->tss_TidPtr--;
else
node->tss_TidPtr++;
+
+ CHECK_FOR_INTERRUPTS();
}
/*
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index 28cc1e90f8..db78c88368 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -35,6 +35,7 @@
#include "executor/executor.h"
#include "executor/nodeUnique.h"
+#include "miscadmin.h"
#include "utils/memutils.h"
@@ -50,6 +51,8 @@ ExecUnique(UniqueState *node)
TupleTableSlot *slot;
PlanState *outerPlan;
+ CHECK_FOR_INTERRUPTS();
+
/*
* get information from the node
*/
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 8f13fe0c73..9da35ac506 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1594,6 +1594,8 @@ ExecWindowAgg(WindowAggState *winstate)
int i;
int numfuncs;
+ CHECK_FOR_INTERRUPTS();
+
if (winstate->all_done)
return NULL;
@@ -2371,6 +2373,9 @@ window_gettupleslot(WindowObject winobj, int64 pos, TupleTableSlot *slot)
WindowAggState *winstate = winobj->winstate;
MemoryContext oldcontext;
+ /* often called repeatedly in a row */
+ CHECK_FOR_INTERRUPTS();
+
/* Don't allow passing -1 to spool_tuples here */
if (pos < 0)
return false;
--
cgit v1.2.3
From cc9f08b6b813e30789100b6b34110d8be1090ba0 Mon Sep 17 00:00:00 2001
From: Andres Freund
Date: Mon, 17 Jul 2017 00:33:49 -0700
Subject: Move ExecProcNode from dispatch to function pointer based model.
This allows us to add stack-depth checks the first time an executor
node is called, and skip that overhead on following
calls. Additionally it yields a nice speedup.
While it'd probably have been a good idea to have that check all
along, it has become more important after the new expression
evaluation framework in b8d7f053c5c2bf2a7e - there's no stack depth
check in common paths anymore now. We previously relied on
ExecEvalExpr() being executed somewhere.
We should move towards that model for further routines, but as this is
required for v10, it seems better to only do the necessary (which
already is quite large).
Author: Andres Freund, Tom Lane
Reported-By: Julien Rouhaud
Discussion:
https://postgr.es/m/22833.1490390175@sss.pgh.pa.us
https://postgr.es/m/b0af9eaa-130c-60d0-9e4e-7a135b1e0c76@dalibo.com
---
src/backend/executor/execProcnode.c | 252 +++++++------------------
src/backend/executor/nodeAgg.c | 6 +-
src/backend/executor/nodeAppend.c | 8 +-
src/backend/executor/nodeBitmapAnd.c | 14 ++
src/backend/executor/nodeBitmapHeapscan.c | 7 +-
src/backend/executor/nodeBitmapIndexscan.c | 14 ++
src/backend/executor/nodeBitmapOr.c | 14 ++
src/backend/executor/nodeCtescan.c | 7 +-
src/backend/executor/nodeCustom.c | 11 +-
src/backend/executor/nodeForeignscan.c | 9 +-
src/backend/executor/nodeFunctionscan.c | 7 +-
src/backend/executor/nodeGather.c | 7 +-
src/backend/executor/nodeGatherMerge.c | 7 +-
src/backend/executor/nodeGroup.c | 6 +-
src/backend/executor/nodeHash.c | 5 +-
src/backend/executor/nodeHashjoin.c | 6 +-
src/backend/executor/nodeIndexonlyscan.c | 7 +-
src/backend/executor/nodeIndexscan.c | 7 +-
src/backend/executor/nodeLimit.c | 6 +-
src/backend/executor/nodeLockRows.c | 6 +-
src/backend/executor/nodeMaterial.c | 6 +-
src/backend/executor/nodeMergeAppend.c | 7 +-
src/backend/executor/nodeMergejoin.c | 6 +-
src/backend/executor/nodeModifyTable.c | 6 +-
src/backend/executor/nodeNamedtuplestorescan.c | 7 +-
src/backend/executor/nodeNestloop.c | 6 +-
src/backend/executor/nodeProjectSet.c | 6 +-
src/backend/executor/nodeRecursiveunion.c | 6 +-
src/backend/executor/nodeResult.c | 6 +-
src/backend/executor/nodeSamplescan.c | 9 +-
src/backend/executor/nodeSeqscan.c | 9 +-
src/backend/executor/nodeSetOp.c | 6 +-
src/backend/executor/nodeSort.c | 6 +-
src/backend/executor/nodeSubqueryscan.c | 7 +-
src/backend/executor/nodeTableFuncscan.c | 7 +-
src/backend/executor/nodeTidscan.c | 7 +-
src/backend/executor/nodeUnique.c | 6 +-
src/backend/executor/nodeValuesscan.c | 7 +-
src/backend/executor/nodeWindowAgg.c | 6 +-
src/backend/executor/nodeWorktablescan.c | 7 +-
src/include/executor/executor.h | 21 ++-
src/include/executor/nodeAgg.h | 1 -
src/include/executor/nodeAppend.h | 1 -
src/include/executor/nodeBitmapHeapscan.h | 1 -
src/include/executor/nodeCtescan.h | 1 -
src/include/executor/nodeCustom.h | 1 -
src/include/executor/nodeForeignscan.h | 1 -
src/include/executor/nodeFunctionscan.h | 1 -
src/include/executor/nodeGather.h | 1 -
src/include/executor/nodeGatherMerge.h | 1 -
src/include/executor/nodeGroup.h | 1 -
src/include/executor/nodeHash.h | 1 -
src/include/executor/nodeHashjoin.h | 1 -
src/include/executor/nodeIndexonlyscan.h | 1 -
src/include/executor/nodeIndexscan.h | 1 -
src/include/executor/nodeLimit.h | 1 -
src/include/executor/nodeLockRows.h | 1 -
src/include/executor/nodeMaterial.h | 1 -
src/include/executor/nodeMergeAppend.h | 1 -
src/include/executor/nodeMergejoin.h | 1 -
src/include/executor/nodeModifyTable.h | 1 -
src/include/executor/nodeNamedtuplestorescan.h | 1 -
src/include/executor/nodeNestloop.h | 1 -
src/include/executor/nodeProjectSet.h | 1 -
src/include/executor/nodeRecursiveunion.h | 1 -
src/include/executor/nodeResult.h | 1 -
src/include/executor/nodeSamplescan.h | 1 -
src/include/executor/nodeSeqscan.h | 1 -
src/include/executor/nodeSetOp.h | 1 -
src/include/executor/nodeSort.h | 1 -
src/include/executor/nodeSubqueryscan.h | 1 -
src/include/executor/nodeTableFuncscan.h | 1 -
src/include/executor/nodeTidscan.h | 1 -
src/include/executor/nodeUnique.h | 1 -
src/include/executor/nodeValuesscan.h | 1 -
src/include/executor/nodeWindowAgg.h | 1 -
src/include/executor/nodeWorktablescan.h | 1 -
src/include/nodes/execnodes.h | 16 ++
78 files changed, 313 insertions(+), 299 deletions(-)
(limited to 'src')
diff --git a/src/backend/executor/execProcnode.c b/src/backend/executor/execProcnode.c
index 20fd9f822e..396920c0a2 100644
--- a/src/backend/executor/execProcnode.c
+++ b/src/backend/executor/execProcnode.c
@@ -17,15 +17,10 @@
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * ExecInitNode - initialize a plan node and its subplans
- * ExecProcNode - get a tuple by executing the plan node
- * ExecEndNode - shut down a plan node and its subplans
- *
* NOTES
* This used to be three files. It is now all combined into
- * one file so that it is easier to keep ExecInitNode, ExecProcNode,
- * and ExecEndNode in sync when new nodes are added.
+ * one file so that it is easier to keep the dispatch routines
+ * in sync when new nodes are added.
*
* EXAMPLE
* Suppose we want the age of the manager of the shoe department and
@@ -122,6 +117,10 @@
#include "miscadmin.h"
+static TupleTableSlot *ExecProcNodeFirst(PlanState *node);
+static TupleTableSlot *ExecProcNodeInstr(PlanState *node);
+
+
/* ------------------------------------------------------------------------
* ExecInitNode
*
@@ -149,6 +148,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
if (node == NULL)
return NULL;
+ /*
+ * Make sure there's enough stack available. Need to check here, in
+ * addition to ExecProcNode() (via ExecProcNodeFirst()), to ensure the
+ * stack isn't overrun while initializing the node tree.
+ */
+ check_stack_depth();
+
switch (nodeTag(node))
{
/*
@@ -364,6 +370,13 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
break;
}
+ /*
+ * Add a wrapper around the ExecProcNode callback that checks stack depth
+ * during the first execution.
+ */
+ result->ExecProcNodeReal = result->ExecProcNode;
+ result->ExecProcNode = ExecProcNodeFirst;
+
/*
* Initialize any initPlans present in this node. The planner put them in
* a separate list for us.
@@ -388,195 +401,51 @@ ExecInitNode(Plan *node, EState *estate, int eflags)
}
-/* ----------------------------------------------------------------
- * ExecProcNode
- *
- * Execute the given node to return a(nother) tuple.
- * ----------------------------------------------------------------
+/*
+ * ExecProcNode wrapper that performs some one-time checks, before calling
+ * the relevant node method (possibly via an instrumentation wrapper).
*/
-TupleTableSlot *
-ExecProcNode(PlanState *node)
+static TupleTableSlot *
+ExecProcNodeFirst(PlanState *node)
{
- TupleTableSlot *result;
-
- if (node->chgParam != NULL) /* something changed */
- ExecReScan(node); /* let ReScan handle this */
+ /*
+ * Perform stack depth check during the first execution of the node. We
+ * only do so the first time round because it turns out to not be cheap on
+ * some common architectures (eg. x86). This relies on the assumption that
+ * ExecProcNode calls for a given plan node will always be made at roughly
+ * the same stack depth.
+ */
+ check_stack_depth();
+ /*
+ * If instrumentation is required, change the wrapper to one that just
+ * does instrumentation. Otherwise we can dispense with all wrappers and
+ * have ExecProcNode() directly call the relevant function from now on.
+ */
if (node->instrument)
- InstrStartNode(node->instrument);
-
- switch (nodeTag(node))
- {
- /*
- * control nodes
- */
- case T_ResultState:
- result = ExecResult((ResultState *) node);
- break;
-
- case T_ProjectSetState:
- result = ExecProjectSet((ProjectSetState *) node);
- break;
-
- case T_ModifyTableState:
- result = ExecModifyTable((ModifyTableState *) node);
- break;
-
- case T_AppendState:
- result = ExecAppend((AppendState *) node);
- break;
-
- case T_MergeAppendState:
- result = ExecMergeAppend((MergeAppendState *) node);
- break;
-
- case T_RecursiveUnionState:
- result = ExecRecursiveUnion((RecursiveUnionState *) node);
- break;
-
- /* BitmapAndState does not yield tuples */
-
- /* BitmapOrState does not yield tuples */
-
- /*
- * scan nodes
- */
- case T_SeqScanState:
- result = ExecSeqScan((SeqScanState *) node);
- break;
-
- case T_SampleScanState:
- result = ExecSampleScan((SampleScanState *) node);
- break;
-
- case T_IndexScanState:
- result = ExecIndexScan((IndexScanState *) node);
- break;
-
- case T_IndexOnlyScanState:
- result = ExecIndexOnlyScan((IndexOnlyScanState *) node);
- break;
-
- /* BitmapIndexScanState does not yield tuples */
-
- case T_BitmapHeapScanState:
- result = ExecBitmapHeapScan((BitmapHeapScanState *) node);
- break;
-
- case T_TidScanState:
- result = ExecTidScan((TidScanState *) node);
- break;
-
- case T_SubqueryScanState:
- result = ExecSubqueryScan((SubqueryScanState *) node);
- break;
-
- case T_FunctionScanState:
- result = ExecFunctionScan((FunctionScanState *) node);
- break;
-
- case T_TableFuncScanState:
- result = ExecTableFuncScan((TableFuncScanState *) node);
- break;
-
- case T_ValuesScanState:
- result = ExecValuesScan((ValuesScanState *) node);
- break;
-
- case T_CteScanState:
- result = ExecCteScan((CteScanState *) node);
- break;
-
- case T_NamedTuplestoreScanState:
- result = ExecNamedTuplestoreScan((NamedTuplestoreScanState *) node);
- break;
-
- case T_WorkTableScanState:
- result = ExecWorkTableScan((WorkTableScanState *) node);
- break;
-
- case T_ForeignScanState:
- result = ExecForeignScan((ForeignScanState *) node);
- break;
-
- case T_CustomScanState:
- result = ExecCustomScan((CustomScanState *) node);
- break;
-
- /*
- * join nodes
- */
- case T_NestLoopState:
- result = ExecNestLoop((NestLoopState *) node);
- break;
-
- case T_MergeJoinState:
- result = ExecMergeJoin((MergeJoinState *) node);
- break;
-
- case T_HashJoinState:
- result = ExecHashJoin((HashJoinState *) node);
- break;
-
- /*
- * materialization nodes
- */
- case T_MaterialState:
- result = ExecMaterial((MaterialState *) node);
- break;
-
- case T_SortState:
- result = ExecSort((SortState *) node);
- break;
-
- case T_GroupState:
- result = ExecGroup((GroupState *) node);
- break;
+ node->ExecProcNode = ExecProcNodeInstr;
+ else
+ node->ExecProcNode = node->ExecProcNodeReal;
- case T_AggState:
- result = ExecAgg((AggState *) node);
- break;
-
- case T_WindowAggState:
- result = ExecWindowAgg((WindowAggState *) node);
- break;
-
- case T_UniqueState:
- result = ExecUnique((UniqueState *) node);
- break;
-
- case T_GatherState:
- result = ExecGather((GatherState *) node);
- break;
-
- case T_GatherMergeState:
- result = ExecGatherMerge((GatherMergeState *) node);
- break;
-
- case T_HashState:
- result = ExecHash((HashState *) node);
- break;
+ return node->ExecProcNode(node);
+}
- case T_SetOpState:
- result = ExecSetOp((SetOpState *) node);
- break;
- case T_LockRowsState:
- result = ExecLockRows((LockRowsState *) node);
- break;
+/*
+ * ExecProcNode wrapper that performs instrumentation calls. By keeping
+ * this a separate function, we avoid overhead in the normal case where
+ * no instrumentation is wanted.
+ */
+static TupleTableSlot *
+ExecProcNodeInstr(PlanState *node)
+{
+ TupleTableSlot *result;
- case T_LimitState:
- result = ExecLimit((LimitState *) node);
- break;
+ InstrStartNode(node->instrument);
- default:
- elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
- result = NULL;
- break;
- }
+ result = node->ExecProcNodeReal(node);
- if (node->instrument)
- InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
+ InstrStopNode(node->instrument, TupIsNull(result) ? 0.0 : 1.0);
return result;
}
@@ -600,6 +469,8 @@ MultiExecProcNode(PlanState *node)
{
Node *result;
+ check_stack_depth();
+
CHECK_FOR_INTERRUPTS();
if (node->chgParam != NULL) /* something changed */
@@ -657,6 +528,13 @@ ExecEndNode(PlanState *node)
if (node == NULL)
return;
+ /*
+ * Make sure there's enough stack available. Need to check here, in
+ * addition to ExecProcNode() (via ExecProcNodeFirst()), because it's not
+ * guaranteed that ExecProcNode() is reached for all nodes.
+ */
+ check_stack_depth();
+
if (node->chgParam != NULL)
{
bms_free(node->chgParam);
@@ -855,6 +733,8 @@ ExecShutdownNode(PlanState *node)
if (node == NULL)
return false;
+ check_stack_depth();
+
planstate_tree_walker(node, ExecShutdownNode, NULL);
switch (nodeTag(node))
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 377916dae7..6a26773a49 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -2099,9 +2099,10 @@ lookup_hash_entries(AggState *aggstate)
* stored in the expression context to be used when ExecProject evaluates
* the result tuple.
*/
-TupleTableSlot *
-ExecAgg(AggState *node)
+static TupleTableSlot *
+ExecAgg(PlanState *pstate)
{
+ AggState *node = castNode(AggState, pstate);
TupleTableSlot *result = NULL;
CHECK_FOR_INTERRUPTS();
@@ -2695,6 +2696,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
aggstate = makeNode(AggState);
aggstate->ss.ps.plan = (Plan *) node;
aggstate->ss.ps.state = estate;
+ aggstate->ss.ps.ExecProcNode = ExecAgg;
aggstate->aggs = NIL;
aggstate->numaggs = 0;
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 58045e05e5..bed9bb8713 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -61,6 +61,7 @@
#include "executor/nodeAppend.h"
#include "miscadmin.h"
+static TupleTableSlot *ExecAppend(PlanState *pstate);
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -147,6 +148,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
*/
appendstate->ps.plan = (Plan *) node;
appendstate->ps.state = estate;
+ appendstate->ps.ExecProcNode = ExecAppend;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
@@ -197,9 +199,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecAppend(AppendState *node)
+static TupleTableSlot *
+ExecAppend(PlanState *pstate)
{
+ AppendState *node = castNode(AppendState, pstate);
+
for (;;)
{
PlanState *subnode;
diff --git a/src/backend/executor/nodeBitmapAnd.c b/src/backend/executor/nodeBitmapAnd.c
index e4eb028ff9..1c5c312c95 100644
--- a/src/backend/executor/nodeBitmapAnd.c
+++ b/src/backend/executor/nodeBitmapAnd.c
@@ -32,6 +32,19 @@
#include "executor/nodeBitmapAnd.h"
+/* ----------------------------------------------------------------
+ * ExecBitmapAnd
+ *
+ * stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapAnd(PlanState *pstate)
+{
+ elog(ERROR, "BitmapAnd node does not support ExecProcNode call convention");
+ return NULL;
+}
+
/* ----------------------------------------------------------------
* ExecInitBitmapAnd
*
@@ -63,6 +76,7 @@ ExecInitBitmapAnd(BitmapAnd *node, EState *estate, int eflags)
*/
bitmapandstate->ps.plan = (Plan *) node;
bitmapandstate->ps.state = estate;
+ bitmapandstate->ps.ExecProcNode = ExecBitmapAnd;
bitmapandstate->bitmapplans = bitmapplanstates;
bitmapandstate->nplans = nplans;
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index cf109d5049..79f534e4e9 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -665,9 +665,11 @@ BitmapHeapRecheck(BitmapHeapScanState *node, TupleTableSlot *slot)
* ExecBitmapHeapScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecBitmapHeapScan(BitmapHeapScanState *node)
+static TupleTableSlot *
+ExecBitmapHeapScan(PlanState *pstate)
{
+ BitmapHeapScanState *node = castNode(BitmapHeapScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) BitmapHeapNext,
(ExecScanRecheckMtd) BitmapHeapRecheck);
@@ -815,6 +817,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
scanstate = makeNode(BitmapHeapScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecBitmapHeapScan;
scanstate->tbm = NULL;
scanstate->tbmiterator = NULL;
diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c
index 2411a2e5c1..6feb70f4ae 100644
--- a/src/backend/executor/nodeBitmapIndexscan.c
+++ b/src/backend/executor/nodeBitmapIndexscan.c
@@ -28,6 +28,19 @@
#include "utils/memutils.h"
+/* ----------------------------------------------------------------
+ * ExecBitmapIndexScan
+ *
+ * stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapIndexScan(PlanState *pstate)
+{
+ elog(ERROR, "BitmapIndexScan node does not support ExecProcNode call convention");
+ return NULL;
+}
+
/* ----------------------------------------------------------------
* MultiExecBitmapIndexScan(node)
* ----------------------------------------------------------------
@@ -208,6 +221,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags)
indexstate = makeNode(BitmapIndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecBitmapIndexScan;
/* normally we don't make the result bitmap till runtime */
indexstate->biss_result = NULL;
diff --git a/src/backend/executor/nodeBitmapOr.c b/src/backend/executor/nodeBitmapOr.c
index 4f0ddc6dff..66a7a89a8b 100644
--- a/src/backend/executor/nodeBitmapOr.c
+++ b/src/backend/executor/nodeBitmapOr.c
@@ -33,6 +33,19 @@
#include "miscadmin.h"
+/* ----------------------------------------------------------------
+ * ExecBitmapOr
+ *
+ * stub for pro forma compliance
+ * ----------------------------------------------------------------
+ */
+static TupleTableSlot *
+ExecBitmapOr(PlanState *pstate)
+{
+ elog(ERROR, "BitmapOr node does not support ExecProcNode call convention");
+ return NULL;
+}
+
/* ----------------------------------------------------------------
* ExecInitBitmapOr
*
@@ -64,6 +77,7 @@ ExecInitBitmapOr(BitmapOr *node, EState *estate, int eflags)
*/
bitmaporstate->ps.plan = (Plan *) node;
bitmaporstate->ps.state = estate;
+ bitmaporstate->ps.ExecProcNode = ExecBitmapOr;
bitmaporstate->bitmapplans = bitmapplanstates;
bitmaporstate->nplans = nplans;
diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c
index bed7949c5a..79676ca978 100644
--- a/src/backend/executor/nodeCtescan.c
+++ b/src/backend/executor/nodeCtescan.c
@@ -149,9 +149,11 @@ CteScanRecheck(CteScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecCteScan(CteScanState *node)
+static TupleTableSlot *
+ExecCteScan(PlanState *pstate)
{
+ CteScanState *node = castNode(CteScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) CteScanNext,
(ExecScanRecheckMtd) CteScanRecheck);
@@ -191,6 +193,7 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags)
scanstate = makeNode(CteScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecCteScan;
scanstate->eflags = eflags;
scanstate->cte_table = NULL;
scanstate->eof_cte = false;
diff --git a/src/backend/executor/nodeCustom.c b/src/backend/executor/nodeCustom.c
index fc15974a2d..fb7645b1f4 100644
--- a/src/backend/executor/nodeCustom.c
+++ b/src/backend/executor/nodeCustom.c
@@ -21,6 +21,10 @@
#include "utils/memutils.h"
#include "utils/rel.h"
+
+static TupleTableSlot *ExecCustomScan(PlanState *pstate);
+
+
CustomScanState *
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
{
@@ -45,6 +49,7 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
/* fill up fields of ScanState */
css->ss.ps.plan = &cscan->scan.plan;
css->ss.ps.state = estate;
+ css->ss.ps.ExecProcNode = ExecCustomScan;
/* create expression context for node */
ExecAssignExprContext(estate, &css->ss.ps);
@@ -102,9 +107,11 @@ ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
return css;
}
-TupleTableSlot *
-ExecCustomScan(CustomScanState *node)
+static TupleTableSlot *
+ExecCustomScan(PlanState *pstate)
{
+ CustomScanState *node = castNode(CustomScanState, pstate);
+
CHECK_FOR_INTERRUPTS();
Assert(node->methods->ExecCustomScan != NULL);
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 9cde112554..140e82ef5e 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -113,10 +113,12 @@ ForeignRecheck(ForeignScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecForeignScan(ForeignScanState *node)
+static TupleTableSlot *
+ExecForeignScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ ForeignScanState *node = castNode(ForeignScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) ForeignNext,
(ExecScanRecheckMtd) ForeignRecheck);
}
@@ -144,6 +146,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
scanstate = makeNode(ForeignScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecForeignScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 3217d641d7..9f87a7e5cd 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -262,9 +262,11 @@ FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecFunctionScan(FunctionScanState *node)
+static TupleTableSlot *
+ExecFunctionScan(PlanState *pstate)
{
+ FunctionScanState *node = castNode(FunctionScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) FunctionNext,
(ExecScanRecheckMtd) FunctionRecheck);
@@ -299,6 +301,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
scanstate = makeNode(FunctionScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecFunctionScan;
scanstate->eflags = eflags;
/*
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 5dbe19c056..e8d94ee6f3 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -43,6 +43,7 @@
#include "utils/rel.h"
+static TupleTableSlot *ExecGather(PlanState *pstate);
static TupleTableSlot *gather_getnext(GatherState *gatherstate);
static HeapTuple gather_readnext(GatherState *gatherstate);
static void ExecShutdownGatherWorkers(GatherState *node);
@@ -69,6 +70,7 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
gatherstate = makeNode(GatherState);
gatherstate->ps.plan = (Plan *) node;
gatherstate->ps.state = estate;
+ gatherstate->ps.ExecProcNode = ExecGather;
gatherstate->need_to_scan_locally = !node->single_copy;
/*
@@ -120,9 +122,10 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGather(GatherState *node)
+static TupleTableSlot *
+ExecGather(PlanState *pstate)
{
+ GatherState *node = castNode(GatherState, pstate);
TupleTableSlot *fslot = node->funnel_slot;
int i;
TupleTableSlot *slot;
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 0aff3798f7..9a81e22510 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -44,6 +44,7 @@ typedef struct GMReaderTupleBuffer
*/
#define MAX_TUPLE_STORE 10
+static TupleTableSlot *ExecGatherMerge(PlanState *pstate);
static int32 heap_compare_slots(Datum a, Datum b, void *arg);
static TupleTableSlot *gather_merge_getnext(GatherMergeState *gm_state);
static HeapTuple gm_readnext_tuple(GatherMergeState *gm_state, int nreader,
@@ -75,6 +76,7 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
gm_state = makeNode(GatherMergeState);
gm_state->ps.plan = (Plan *) node;
gm_state->ps.state = estate;
+ gm_state->ps.ExecProcNode = ExecGatherMerge;
/*
* Miscellaneous initialization
@@ -157,9 +159,10 @@ ExecInitGatherMerge(GatherMerge *node, EState *estate, int eflags)
* the next qualifying tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecGatherMerge(GatherMergeState *node)
+static TupleTableSlot *
+ExecGatherMerge(PlanState *pstate)
{
+ GatherMergeState *node = castNode(GatherMergeState, pstate);
TupleTableSlot *slot;
ExprContext *econtext;
int i;
diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c
index fc5e0e59bc..ab4ae24a6b 100644
--- a/src/backend/executor/nodeGroup.c
+++ b/src/backend/executor/nodeGroup.c
@@ -32,9 +32,10 @@
*
* Return one tuple for each group of matching input tuples.
*/
-TupleTableSlot *
-ExecGroup(GroupState *node)
+static TupleTableSlot *
+ExecGroup(PlanState *pstate)
{
+ GroupState *node = castNode(GroupState, pstate);
ExprContext *econtext;
int numCols;
AttrNumber *grpColIdx;
@@ -175,6 +176,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags)
grpstate = makeNode(GroupState);
grpstate->ss.ps.plan = (Plan *) node;
grpstate->ss.ps.state = estate;
+ grpstate->ss.ps.ExecProcNode = ExecGroup;
grpstate->grp_done = FALSE;
/*
diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c
index fbeb562489..d10d94ccc2 100644
--- a/src/backend/executor/nodeHash.c
+++ b/src/backend/executor/nodeHash.c
@@ -56,8 +56,8 @@ static void *dense_alloc(HashJoinTable hashtable, Size size);
* stub for pro forma compliance
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecHash(HashState *node)
+static TupleTableSlot *
+ExecHash(PlanState *pstate)
{
elog(ERROR, "Hash node does not support ExecProcNode call convention");
return NULL;
@@ -172,6 +172,7 @@ ExecInitHash(Hash *node, EState *estate, int eflags)
hashstate = makeNode(HashState);
hashstate->ps.plan = (Plan *) node;
hashstate->ps.state = estate;
+ hashstate->ps.ExecProcNode = ExecHash;
hashstate->hashtable = NULL;
hashstate->hashkeys = NIL; /* will be set by parent HashJoin */
diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c
index 252960c81c..ab1632cc13 100644
--- a/src/backend/executor/nodeHashjoin.c
+++ b/src/backend/executor/nodeHashjoin.c
@@ -58,9 +58,10 @@ static bool ExecHashJoinNewBatch(HashJoinState *hjstate);
* the other one is "outer".
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecHashJoin(HashJoinState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecHashJoin(PlanState *pstate)
{
+ HashJoinState *node = castNode(HashJoinState, pstate);
PlanState *outerNode;
HashState *hashNode;
ExprState *joinqual;
@@ -399,6 +400,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags)
hjstate = makeNode(HashJoinState);
hjstate->js.ps.plan = (Plan *) node;
hjstate->js.ps.state = estate;
+ hjstate->js.ps.ExecProcNode = ExecHashJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeIndexonlyscan.c b/src/backend/executor/nodeIndexonlyscan.c
index e2000764a4..fe7ba3f1a4 100644
--- a/src/backend/executor/nodeIndexonlyscan.c
+++ b/src/backend/executor/nodeIndexonlyscan.c
@@ -306,9 +306,11 @@ IndexOnlyRecheck(IndexOnlyScanState *node, TupleTableSlot *slot)
* ExecIndexOnlyScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexOnlyScan(IndexOnlyScanState *node)
+static TupleTableSlot *
+ExecIndexOnlyScan(PlanState *pstate)
{
+ IndexOnlyScanState *node = castNode(IndexOnlyScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -476,6 +478,7 @@ ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexOnlyScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexOnlyScan;
indexstate->ioss_HeapFetches = 0;
/*
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 6704ede995..404076d593 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -542,9 +542,11 @@ reorderqueue_pop(IndexScanState *node)
* ExecIndexScan(node)
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecIndexScan(IndexScanState *node)
+static TupleTableSlot *
+ExecIndexScan(PlanState *pstate)
{
+ IndexScanState *node = castNode(IndexScanState, pstate);
+
/*
* If we have runtime keys and they've not already been set up, do it now.
*/
@@ -910,6 +912,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate = makeNode(IndexScanState);
indexstate->ss.ps.plan = (Plan *) node;
indexstate->ss.ps.state = estate;
+ indexstate->ss.ps.ExecProcNode = ExecIndexScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index 2ed3523257..ac5a2ff0e6 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -37,9 +37,10 @@ static void pass_down_bound(LimitState *node, PlanState *child_node);
* filtering on the stream of tuples returned by a subplan.
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecLimit(LimitState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLimit(PlanState *pstate)
{
+ LimitState *node = castNode(LimitState, pstate);
ScanDirection direction;
TupleTableSlot *slot;
PlanState *outerPlan;
@@ -378,6 +379,7 @@ ExecInitLimit(Limit *node, EState *estate, int eflags)
limitstate = makeNode(LimitState);
limitstate->ps.plan = (Plan *) node;
limitstate->ps.state = estate;
+ limitstate->ps.ExecProcNode = ExecLimit;
limitstate->lstate = LIMIT_INITIAL;
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index dd4e2c5f2f..93895600a5 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -36,9 +36,10 @@
* ExecLockRows
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecLockRows(LockRowsState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecLockRows(PlanState *pstate)
{
+ LockRowsState *node = castNode(LockRowsState, pstate);
TupleTableSlot *slot;
EState *estate;
PlanState *outerPlan;
@@ -364,6 +365,7 @@ ExecInitLockRows(LockRows *node, EState *estate, int eflags)
lrstate = makeNode(LockRowsState);
lrstate->ps.plan = (Plan *) node;
lrstate->ps.state = estate;
+ lrstate->ps.ExecProcNode = ExecLockRows;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeMaterial.c b/src/backend/executor/nodeMaterial.c
index 3342949590..91178f1019 100644
--- a/src/backend/executor/nodeMaterial.c
+++ b/src/backend/executor/nodeMaterial.c
@@ -35,9 +35,10 @@
*
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* result tuple from subplan */
-ExecMaterial(MaterialState *node)
+static TupleTableSlot * /* result tuple from subplan */
+ExecMaterial(PlanState *pstate)
{
+ MaterialState *node = castNode(MaterialState, pstate);
EState *estate;
ScanDirection dir;
bool forward;
@@ -173,6 +174,7 @@ ExecInitMaterial(Material *node, EState *estate, int eflags)
matstate = makeNode(MaterialState);
matstate->ss.ps.plan = (Plan *) node;
matstate->ss.ps.state = estate;
+ matstate->ss.ps.ExecProcNode = ExecMaterial;
/*
* We must have a tuplestore buffering the subplan output to do backward
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index d41def1350..6bf490bd70 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -50,6 +50,7 @@
*/
typedef int32 SlotNumber;
+static TupleTableSlot *ExecMergeAppend(PlanState *pstate);
static int heap_compare_slots(Datum a, Datum b, void *arg);
@@ -89,6 +90,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
*/
mergestate->ps.plan = (Plan *) node;
mergestate->ps.state = estate;
+ mergestate->ps.ExecProcNode = ExecMergeAppend;
mergestate->mergeplans = mergeplanstates;
mergestate->ms_nplans = nplans;
@@ -169,9 +171,10 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
* Handles iteration over multiple subplans.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeAppend(MergeAppendState *node)
+static TupleTableSlot *
+ExecMergeAppend(PlanState *pstate)
{
+ MergeAppendState *node = castNode(MergeAppendState, pstate);
TupleTableSlot *result;
SlotNumber i;
diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c
index 324b61b8c0..925b4cf553 100644
--- a/src/backend/executor/nodeMergejoin.c
+++ b/src/backend/executor/nodeMergejoin.c
@@ -596,9 +596,10 @@ ExecMergeTupleDump(MergeJoinState *mergestate)
* ExecMergeJoin
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecMergeJoin(MergeJoinState *node)
+static TupleTableSlot *
+ExecMergeJoin(PlanState *pstate)
{
+ MergeJoinState *node = castNode(MergeJoinState, pstate);
ExprState *joinqual;
ExprState *otherqual;
bool qualResult;
@@ -1448,6 +1449,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags)
mergestate = makeNode(MergeJoinState);
mergestate->js.ps.plan = (Plan *) node;
mergestate->js.ps.state = estate;
+ mergestate->js.ps.ExecProcNode = ExecMergeJoin;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 637a582e1c..0dde0ed6eb 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1535,9 +1535,10 @@ ExecSetupTransitionCaptureState(ModifyTableState *mtstate, EState *estate)
* if needed.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecModifyTable(ModifyTableState *node)
+static TupleTableSlot *
+ExecModifyTable(PlanState *pstate)
{
+ ModifyTableState *node = castNode(ModifyTableState, pstate);
EState *estate = node->ps.state;
CmdType operation = node->operation;
ResultRelInfo *saved_resultRelInfo;
@@ -1806,6 +1807,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate = makeNode(ModifyTableState);
mtstate->ps.plan = (Plan *) node;
mtstate->ps.state = estate;
+ mtstate->ps.ExecProcNode = ExecModifyTable;
mtstate->operation = operation;
mtstate->canSetTag = node->canSetTag;
diff --git a/src/backend/executor/nodeNamedtuplestorescan.c b/src/backend/executor/nodeNamedtuplestorescan.c
index 62234869ab..3a65b9f5dc 100644
--- a/src/backend/executor/nodeNamedtuplestorescan.c
+++ b/src/backend/executor/nodeNamedtuplestorescan.c
@@ -63,9 +63,11 @@ NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNamedTuplestoreScan(NamedTuplestoreScanState *node)
+static TupleTableSlot *
+ExecNamedTuplestoreScan(PlanState *pstate)
{
+ NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) NamedTuplestoreScanNext,
(ExecScanRecheckMtd) NamedTuplestoreScanRecheck);
@@ -97,6 +99,7 @@ ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflag
scanstate = makeNode(NamedTuplestoreScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan;
enr = get_ENR(estate->es_queryEnv, node->enrname);
if (!enr)
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index bedc374ef0..4447b7c051 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -57,9 +57,10 @@
* are prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecNestLoop(NestLoopState *node)
+static TupleTableSlot *
+ExecNestLoop(PlanState *pstate)
{
+ NestLoopState *node = castNode(NestLoopState, pstate);
NestLoop *nl;
PlanState *innerPlan;
PlanState *outerPlan;
@@ -275,6 +276,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags)
nlstate = makeNode(NestLoopState);
nlstate->js.ps.plan = (Plan *) node;
nlstate->js.ps.state = estate;
+ nlstate->js.ps.ExecProcNode = ExecNestLoop;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeProjectSet.c b/src/backend/executor/nodeProjectSet.c
index 3b69c7adee..d93462c542 100644
--- a/src/backend/executor/nodeProjectSet.c
+++ b/src/backend/executor/nodeProjectSet.c
@@ -39,9 +39,10 @@ static TupleTableSlot *ExecProjectSRF(ProjectSetState *node, bool continuing);
* returning functions).
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecProjectSet(ProjectSetState *node)
+static TupleTableSlot *
+ExecProjectSet(PlanState *pstate)
{
+ ProjectSetState *node = castNode(ProjectSetState, pstate);
TupleTableSlot *outerTupleSlot;
TupleTableSlot *resultSlot;
PlanState *outerPlan;
@@ -215,6 +216,7 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
state = makeNode(ProjectSetState);
state->ps.plan = (Plan *) node;
state->ps.state = estate;
+ state->ps.ExecProcNode = ExecProjectSet;
state->pending_srf_tuples = false;
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 2802fffa2b..a64dd1397a 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -66,9 +66,10 @@ build_hash_table(RecursiveUnionState *rustate)
* 2.6 go back to 2.2
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecRecursiveUnion(RecursiveUnionState *node)
+static TupleTableSlot *
+ExecRecursiveUnion(PlanState *pstate)
{
+ RecursiveUnionState *node = castNode(RecursiveUnionState, pstate);
PlanState *outerPlan = outerPlanState(node);
PlanState *innerPlan = innerPlanState(node);
RecursiveUnion *plan = (RecursiveUnion *) node->ps.plan;
@@ -172,6 +173,7 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags)
rustate = makeNode(RecursiveUnionState);
rustate->ps.plan = (Plan *) node;
rustate->ps.state = estate;
+ rustate->ps.ExecProcNode = ExecRecursiveUnion;
rustate->eqfunctions = NULL;
rustate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeResult.c b/src/backend/executor/nodeResult.c
index f007f46784..4c879d8765 100644
--- a/src/backend/executor/nodeResult.c
+++ b/src/backend/executor/nodeResult.c
@@ -64,9 +64,10 @@
* 'nil' if the constant qualification is not satisfied.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecResult(ResultState *node)
+static TupleTableSlot *
+ExecResult(PlanState *pstate)
{
+ ResultState *node = castNode(ResultState, pstate);
TupleTableSlot *outerTupleSlot;
PlanState *outerPlan;
ExprContext *econtext;
@@ -191,6 +192,7 @@ ExecInitResult(Result *node, EState *estate, int eflags)
resstate = makeNode(ResultState);
resstate->ps.plan = (Plan *) node;
resstate->ps.state = estate;
+ resstate->ps.ExecProcNode = ExecResult;
resstate->rs_done = false;
resstate->rs_checkqual = (node->resconstantqual == NULL) ? false : true;
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index b710ef7edf..9c74a836e4 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -96,10 +96,12 @@ SampleRecheck(SampleScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSampleScan(SampleScanState *node)
+static TupleTableSlot *
+ExecSampleScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ SampleScanState *node = castNode(SampleScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) SampleNext,
(ExecScanRecheckMtd) SampleRecheck);
}
@@ -153,6 +155,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
scanstate = makeNode(SampleScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSampleScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 307df87c82..5c49d4ca8a 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -121,10 +121,12 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSeqScan(SeqScanState *node)
+static TupleTableSlot *
+ExecSeqScan(PlanState *pstate)
{
- return ExecScan((ScanState *) node,
+ SeqScanState *node = castNode(SeqScanState, pstate);
+
+ return ExecScan(&node->ss,
(ExecScanAccessMtd) SeqNext,
(ExecScanRecheckMtd) SeqRecheck);
}
@@ -177,6 +179,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
scanstate = makeNode(SeqScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecSeqScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index 56c5643f17..571cbf86b1 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -180,9 +180,10 @@ set_output_count(SetOpState *setopstate, SetOpStatePerGroup pergroup)
* ExecSetOp
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecSetOp(SetOpState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecSetOp(PlanState *pstate)
{
+ SetOpState *node = castNode(SetOpState, pstate);
SetOp *plannode = (SetOp *) node->ps.plan;
TupleTableSlot *resultTupleSlot = node->ps.ps_ResultTupleSlot;
@@ -485,6 +486,7 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags)
setopstate = makeNode(SetOpState);
setopstate->ps.plan = (Plan *) node;
setopstate->ps.state = estate;
+ setopstate->ps.ExecProcNode = ExecSetOp;
setopstate->eqfunctions = NULL;
setopstate->hashfunctions = NULL;
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index 799a4e9204..aae4150e2c 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -35,9 +35,10 @@
* -- the outer child is prepared to return the first tuple.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSort(SortState *node)
+static TupleTableSlot *
+ExecSort(PlanState *pstate)
{
+ SortState *node = castNode(SortState, pstate);
EState *estate;
ScanDirection dir;
Tuplesortstate *tuplesortstate;
@@ -165,6 +166,7 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
+ sortstate->ss.ps.ExecProcNode = ExecSort;
/*
* We must have random access to the sort output to do backward scan or
diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c
index ae184700a6..088c92992e 100644
--- a/src/backend/executor/nodeSubqueryscan.c
+++ b/src/backend/executor/nodeSubqueryscan.c
@@ -79,9 +79,11 @@ SubqueryRecheck(SubqueryScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecSubqueryScan(SubqueryScanState *node)
+static TupleTableSlot *
+ExecSubqueryScan(PlanState *pstate)
{
+ SubqueryScanState *node = castNode(SubqueryScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) SubqueryNext,
(ExecScanRecheckMtd) SubqueryRecheck);
@@ -109,6 +111,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
subquerystate = makeNode(SubqueryScanState);
subquerystate->ss.ps.plan = (Plan *) node;
subquerystate->ss.ps.state = estate;
+ subquerystate->ss.ps.ExecProcNode = ExecSubqueryScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index 2859363fe2..b03d2ef762 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -93,9 +93,11 @@ TableFuncRecheck(TableFuncScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTableFuncScan(TableFuncScanState *node)
+static TupleTableSlot *
+ExecTableFuncScan(PlanState *pstate)
{
+ TableFuncScanState *node = castNode(TableFuncScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TableFuncNext,
(ExecScanRecheckMtd) TableFuncRecheck);
@@ -128,6 +130,7 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
scanstate = makeNode(TableFuncScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecTableFuncScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c
index c122473bdf..0ee76e7d25 100644
--- a/src/backend/executor/nodeTidscan.c
+++ b/src/backend/executor/nodeTidscan.c
@@ -445,9 +445,11 @@ TidRecheck(TidScanState *node, TupleTableSlot *slot)
* -- tidPtr is -1.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecTidScan(TidScanState *node)
+static TupleTableSlot *
+ExecTidScan(PlanState *pstate)
{
+ TidScanState *node = castNode(TidScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) TidNext,
(ExecScanRecheckMtd) TidRecheck);
@@ -519,6 +521,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
tidstate = makeNode(TidScanState);
tidstate->ss.ps.plan = (Plan *) node;
tidstate->ss.ps.state = estate;
+ tidstate->ss.ps.ExecProcNode = ExecTidScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeUnique.c b/src/backend/executor/nodeUnique.c
index db78c88368..621fdd9b9c 100644
--- a/src/backend/executor/nodeUnique.c
+++ b/src/backend/executor/nodeUnique.c
@@ -43,9 +43,10 @@
* ExecUnique
* ----------------------------------------------------------------
*/
-TupleTableSlot * /* return: a tuple or NULL */
-ExecUnique(UniqueState *node)
+static TupleTableSlot * /* return: a tuple or NULL */
+ExecUnique(PlanState *pstate)
{
+ UniqueState *node = castNode(UniqueState, pstate);
Unique *plannode = (Unique *) node->ps.plan;
TupleTableSlot *resultTupleSlot;
TupleTableSlot *slot;
@@ -125,6 +126,7 @@ ExecInitUnique(Unique *node, EState *estate, int eflags)
uniquestate = makeNode(UniqueState);
uniquestate->ps.plan = (Plan *) node;
uniquestate->ps.state = estate;
+ uniquestate->ps.ExecProcNode = ExecUnique;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c
index 9ee776c4c3..6eacaed8bb 100644
--- a/src/backend/executor/nodeValuesscan.c
+++ b/src/backend/executor/nodeValuesscan.c
@@ -185,9 +185,11 @@ ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecValuesScan(ValuesScanState *node)
+static TupleTableSlot *
+ExecValuesScan(PlanState *pstate)
{
+ ValuesScanState *node = castNode(ValuesScanState, pstate);
+
return ExecScan(&node->ss,
(ExecScanAccessMtd) ValuesNext,
(ExecScanRecheckMtd) ValuesRecheck);
@@ -218,6 +220,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
scanstate = makeNode(ValuesScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecValuesScan;
/*
* Miscellaneous initialization
diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c
index 9da35ac506..80be46029f 100644
--- a/src/backend/executor/nodeWindowAgg.c
+++ b/src/backend/executor/nodeWindowAgg.c
@@ -1587,9 +1587,10 @@ update_frametailpos(WindowObject winobj, TupleTableSlot *slot)
* returned rows is exactly the same as its outer subplan's result.
* -----------------
*/
-TupleTableSlot *
-ExecWindowAgg(WindowAggState *winstate)
+static TupleTableSlot *
+ExecWindowAgg(PlanState *pstate)
{
+ WindowAggState *winstate = castNode(WindowAggState, pstate);
ExprContext *econtext;
int i;
int numfuncs;
@@ -1790,6 +1791,7 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
winstate = makeNode(WindowAggState);
winstate->ss.ps.plan = (Plan *) node;
winstate->ss.ps.state = estate;
+ winstate->ss.ps.ExecProcNode = ExecWindowAgg;
/*
* Create expression contexts. We need two, one for per-input-tuple
diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c
index d7616be065..d5ffadda3e 100644
--- a/src/backend/executor/nodeWorktablescan.c
+++ b/src/backend/executor/nodeWorktablescan.c
@@ -77,9 +77,11 @@ WorkTableScanRecheck(WorkTableScanState *node, TupleTableSlot *slot)
* access method functions.
* ----------------------------------------------------------------
*/
-TupleTableSlot *
-ExecWorkTableScan(WorkTableScanState *node)
+static TupleTableSlot *
+ExecWorkTableScan(PlanState *pstate)
{
+ WorkTableScanState *node = castNode(WorkTableScanState, pstate);
+
/*
* On the first call, find the ancestor RecursiveUnion's state via the
* Param slot reserved for it. (We can't do this during node init because
@@ -144,6 +146,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags)
scanstate = makeNode(WorkTableScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
+ scanstate->ss.ps.ExecProcNode = ExecWorkTableScan;
scanstate->rustate = NULL; /* we'll set this later */
/*
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 59c28b709e..60326f9d03 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -225,14 +225,31 @@ extern void EvalPlanQualBegin(EPQState *epqstate, EState *parentestate);
extern void EvalPlanQualEnd(EPQState *epqstate);
/*
- * prototypes from functions in execProcnode.c
+ * functions in execProcnode.c
*/
extern PlanState *ExecInitNode(Plan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProcNode(PlanState *node);
extern Node *MultiExecProcNode(PlanState *node);
extern void ExecEndNode(PlanState *node);
extern bool ExecShutdownNode(PlanState *node);
+
+/* ----------------------------------------------------------------
+ * ExecProcNode
+ *
+ * Execute the given node to return a(nother) tuple.
+ * ----------------------------------------------------------------
+ */
+#ifndef FRONTEND
+static inline TupleTableSlot *
+ExecProcNode(PlanState *node)
+{
+ if (node->chgParam != NULL) /* something changed? */
+ ExecReScan(node); /* let ReScan handle this */
+
+ return node->ExecProcNode(node);
+}
+#endif
+
/*
* prototypes from functions in execExpr.c
*/
diff --git a/src/include/executor/nodeAgg.h b/src/include/executor/nodeAgg.h
index fa11ba93a6..eff5af9c2a 100644
--- a/src/include/executor/nodeAgg.h
+++ b/src/include/executor/nodeAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AggState *ExecInitAgg(Agg *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecAgg(AggState *node);
extern void ExecEndAgg(AggState *node);
extern void ExecReScanAgg(AggState *node);
diff --git a/src/include/executor/nodeAppend.h b/src/include/executor/nodeAppend.h
index ee0b6ad23d..4e38a1380e 100644
--- a/src/include/executor/nodeAppend.h
+++ b/src/include/executor/nodeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern AppendState *ExecInitAppend(Append *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecAppend(AppendState *node);
extern void ExecEndAppend(AppendState *node);
extern void ExecReScanAppend(AppendState *node);
diff --git a/src/include/executor/nodeBitmapHeapscan.h b/src/include/executor/nodeBitmapHeapscan.h
index f477d1c772..c77694cf22 100644
--- a/src/include/executor/nodeBitmapHeapscan.h
+++ b/src/include/executor/nodeBitmapHeapscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern BitmapHeapScanState *ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecEndBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecReScanBitmapHeapScan(BitmapHeapScanState *node);
extern void ExecBitmapHeapEstimate(BitmapHeapScanState *node,
diff --git a/src/include/executor/nodeCtescan.h b/src/include/executor/nodeCtescan.h
index 397bdfdd1c..d2fbcbd586 100644
--- a/src/include/executor/nodeCtescan.h
+++ b/src/include/executor/nodeCtescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern CteScanState *ExecInitCteScan(CteScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecCteScan(CteScanState *node);
extern void ExecEndCteScan(CteScanState *node);
extern void ExecReScanCteScan(CteScanState *node);
diff --git a/src/include/executor/nodeCustom.h b/src/include/executor/nodeCustom.h
index e81bcf7f21..a1cc63ae1f 100644
--- a/src/include/executor/nodeCustom.h
+++ b/src/include/executor/nodeCustom.h
@@ -21,7 +21,6 @@
*/
extern CustomScanState *ExecInitCustomScan(CustomScan *custom_scan,
EState *estate, int eflags);
-extern TupleTableSlot *ExecCustomScan(CustomScanState *node);
extern void ExecEndCustomScan(CustomScanState *node);
extern void ExecReScanCustomScan(CustomScanState *node);
diff --git a/src/include/executor/nodeForeignscan.h b/src/include/executor/nodeForeignscan.h
index 3ff4ecd8c9..0b662597d8 100644
--- a/src/include/executor/nodeForeignscan.h
+++ b/src/include/executor/nodeForeignscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern ForeignScanState *ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecForeignScan(ForeignScanState *node);
extern void ExecEndForeignScan(ForeignScanState *node);
extern void ExecReScanForeignScan(ForeignScanState *node);
diff --git a/src/include/executor/nodeFunctionscan.h b/src/include/executor/nodeFunctionscan.h
index 5e830ebdea..aaa9d8c316 100644
--- a/src/include/executor/nodeFunctionscan.h
+++ b/src/include/executor/nodeFunctionscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern FunctionScanState *ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecFunctionScan(FunctionScanState *node);
extern void ExecEndFunctionScan(FunctionScanState *node);
extern void ExecReScanFunctionScan(FunctionScanState *node);
diff --git a/src/include/executor/nodeGather.h b/src/include/executor/nodeGather.h
index b0006934d4..189bd70041 100644
--- a/src/include/executor/nodeGather.h
+++ b/src/include/executor/nodeGather.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GatherState *ExecInitGather(Gather *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGather(GatherState *node);
extern void ExecEndGather(GatherState *node);
extern void ExecShutdownGather(GatherState *node);
extern void ExecReScanGather(GatherState *node);
diff --git a/src/include/executor/nodeGatherMerge.h b/src/include/executor/nodeGatherMerge.h
index 14b31a086c..0154d73312 100644
--- a/src/include/executor/nodeGatherMerge.h
+++ b/src/include/executor/nodeGatherMerge.h
@@ -19,7 +19,6 @@
extern GatherMergeState *ExecInitGatherMerge(GatherMerge *node,
EState *estate,
int eflags);
-extern TupleTableSlot *ExecGatherMerge(GatherMergeState *node);
extern void ExecEndGatherMerge(GatherMergeState *node);
extern void ExecReScanGatherMerge(GatherMergeState *node);
extern void ExecShutdownGatherMerge(GatherMergeState *node);
diff --git a/src/include/executor/nodeGroup.h b/src/include/executor/nodeGroup.h
index 7358b61707..b0d7e312c9 100644
--- a/src/include/executor/nodeGroup.h
+++ b/src/include/executor/nodeGroup.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern GroupState *ExecInitGroup(Group *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecGroup(GroupState *node);
extern void ExecEndGroup(GroupState *node);
extern void ExecReScanGroup(GroupState *node);
diff --git a/src/include/executor/nodeHash.h b/src/include/executor/nodeHash.h
index 8052f27d0b..3ae556fb6c 100644
--- a/src/include/executor/nodeHash.h
+++ b/src/include/executor/nodeHash.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern HashState *ExecInitHash(Hash *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecHash(HashState *node);
extern Node *MultiExecHash(HashState *node);
extern void ExecEndHash(HashState *node);
extern void ExecReScanHash(HashState *node);
diff --git a/src/include/executor/nodeHashjoin.h b/src/include/executor/nodeHashjoin.h
index 541c81edc7..7469bfbf60 100644
--- a/src/include/executor/nodeHashjoin.h
+++ b/src/include/executor/nodeHashjoin.h
@@ -18,7 +18,6 @@
#include "storage/buffile.h"
extern HashJoinState *ExecInitHashJoin(HashJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecHashJoin(HashJoinState *node);
extern void ExecEndHashJoin(HashJoinState *node);
extern void ExecReScanHashJoin(HashJoinState *node);
diff --git a/src/include/executor/nodeIndexonlyscan.h b/src/include/executor/nodeIndexonlyscan.h
index cf227daae0..c8a709c26e 100644
--- a/src/include/executor/nodeIndexonlyscan.h
+++ b/src/include/executor/nodeIndexonlyscan.h
@@ -18,7 +18,6 @@
#include "access/parallel.h"
extern IndexOnlyScanState *ExecInitIndexOnlyScan(IndexOnlyScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecIndexOnlyScan(IndexOnlyScanState *node);
extern void ExecEndIndexOnlyScan(IndexOnlyScanState *node);
extern void ExecIndexOnlyMarkPos(IndexOnlyScanState *node);
extern void ExecIndexOnlyRestrPos(IndexOnlyScanState *node);
diff --git a/src/include/executor/nodeIndexscan.h b/src/include/executor/nodeIndexscan.h
index 0118234eca..1668e347ee 100644
--- a/src/include/executor/nodeIndexscan.h
+++ b/src/include/executor/nodeIndexscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern IndexScanState *ExecInitIndexScan(IndexScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecIndexScan(IndexScanState *node);
extern void ExecEndIndexScan(IndexScanState *node);
extern void ExecIndexMarkPos(IndexScanState *node);
extern void ExecIndexRestrPos(IndexScanState *node);
diff --git a/src/include/executor/nodeLimit.h b/src/include/executor/nodeLimit.h
index 7bb20d9978..db65b5524c 100644
--- a/src/include/executor/nodeLimit.h
+++ b/src/include/executor/nodeLimit.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LimitState *ExecInitLimit(Limit *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecLimit(LimitState *node);
extern void ExecEndLimit(LimitState *node);
extern void ExecReScanLimit(LimitState *node);
diff --git a/src/include/executor/nodeLockRows.h b/src/include/executor/nodeLockRows.h
index 6b90756e4c..c9d05b87f1 100644
--- a/src/include/executor/nodeLockRows.h
+++ b/src/include/executor/nodeLockRows.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern LockRowsState *ExecInitLockRows(LockRows *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecLockRows(LockRowsState *node);
extern void ExecEndLockRows(LockRowsState *node);
extern void ExecReScanLockRows(LockRowsState *node);
diff --git a/src/include/executor/nodeMaterial.h b/src/include/executor/nodeMaterial.h
index f69abbca82..4b3c2578c9 100644
--- a/src/include/executor/nodeMaterial.h
+++ b/src/include/executor/nodeMaterial.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MaterialState *ExecInitMaterial(Material *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMaterial(MaterialState *node);
extern void ExecEndMaterial(MaterialState *node);
extern void ExecMaterialMarkPos(MaterialState *node);
extern void ExecMaterialRestrPos(MaterialState *node);
diff --git a/src/include/executor/nodeMergeAppend.h b/src/include/executor/nodeMergeAppend.h
index 3cc6ef549b..a0ccbae965 100644
--- a/src/include/executor/nodeMergeAppend.h
+++ b/src/include/executor/nodeMergeAppend.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeAppendState *ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMergeAppend(MergeAppendState *node);
extern void ExecEndMergeAppend(MergeAppendState *node);
extern void ExecReScanMergeAppend(MergeAppendState *node);
diff --git a/src/include/executor/nodeMergejoin.h b/src/include/executor/nodeMergejoin.h
index 32df25ae8b..d20e41505d 100644
--- a/src/include/executor/nodeMergejoin.h
+++ b/src/include/executor/nodeMergejoin.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern MergeJoinState *ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecMergeJoin(MergeJoinState *node);
extern void ExecEndMergeJoin(MergeJoinState *node);
extern void ExecReScanMergeJoin(MergeJoinState *node);
diff --git a/src/include/executor/nodeModifyTable.h b/src/include/executor/nodeModifyTable.h
index 5a406f236d..a2e7af98de 100644
--- a/src/include/executor/nodeModifyTable.h
+++ b/src/include/executor/nodeModifyTable.h
@@ -16,7 +16,6 @@
#include "nodes/execnodes.h"
extern ModifyTableState *ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecModifyTable(ModifyTableState *node);
extern void ExecEndModifyTable(ModifyTableState *node);
extern void ExecReScanModifyTable(ModifyTableState *node);
diff --git a/src/include/executor/nodeNamedtuplestorescan.h b/src/include/executor/nodeNamedtuplestorescan.h
index 7f72fbe98a..395d978f62 100644
--- a/src/include/executor/nodeNamedtuplestorescan.h
+++ b/src/include/executor/nodeNamedtuplestorescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NamedTuplestoreScanState *ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecEndNamedTuplestoreScan(NamedTuplestoreScanState *node);
extern void ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node);
diff --git a/src/include/executor/nodeNestloop.h b/src/include/executor/nodeNestloop.h
index 8e0fcc1922..0d6486cc57 100644
--- a/src/include/executor/nodeNestloop.h
+++ b/src/include/executor/nodeNestloop.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern NestLoopState *ExecInitNestLoop(NestLoop *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecNestLoop(NestLoopState *node);
extern void ExecEndNestLoop(NestLoopState *node);
extern void ExecReScanNestLoop(NestLoopState *node);
diff --git a/src/include/executor/nodeProjectSet.h b/src/include/executor/nodeProjectSet.h
index 2f6999e8db..a0b0521f8d 100644
--- a/src/include/executor/nodeProjectSet.h
+++ b/src/include/executor/nodeProjectSet.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ProjectSetState *ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecProjectSet(ProjectSetState *node);
extern void ExecEndProjectSet(ProjectSetState *node);
extern void ExecReScanProjectSet(ProjectSetState *node);
diff --git a/src/include/executor/nodeRecursiveunion.h b/src/include/executor/nodeRecursiveunion.h
index f0eba05bee..e6ce1b4783 100644
--- a/src/include/executor/nodeRecursiveunion.h
+++ b/src/include/executor/nodeRecursiveunion.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern RecursiveUnionState *ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecRecursiveUnion(RecursiveUnionState *node);
extern void ExecEndRecursiveUnion(RecursiveUnionState *node);
extern void ExecReScanRecursiveUnion(RecursiveUnionState *node);
diff --git a/src/include/executor/nodeResult.h b/src/include/executor/nodeResult.h
index 61d3cb2cc2..20e0063410 100644
--- a/src/include/executor/nodeResult.h
+++ b/src/include/executor/nodeResult.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ResultState *ExecInitResult(Result *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecResult(ResultState *node);
extern void ExecEndResult(ResultState *node);
extern void ExecResultMarkPos(ResultState *node);
extern void ExecResultRestrPos(ResultState *node);
diff --git a/src/include/executor/nodeSamplescan.h b/src/include/executor/nodeSamplescan.h
index ed06e77e4e..607bbd9412 100644
--- a/src/include/executor/nodeSamplescan.h
+++ b/src/include/executor/nodeSamplescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SampleScanState *ExecInitSampleScan(SampleScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSampleScan(SampleScanState *node);
extern void ExecEndSampleScan(SampleScanState *node);
extern void ExecReScanSampleScan(SampleScanState *node);
diff --git a/src/include/executor/nodeSeqscan.h b/src/include/executor/nodeSeqscan.h
index 06e0686b0b..0fba79f8de 100644
--- a/src/include/executor/nodeSeqscan.h
+++ b/src/include/executor/nodeSeqscan.h
@@ -18,7 +18,6 @@
#include "nodes/execnodes.h"
extern SeqScanState *ExecInitSeqScan(SeqScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSeqScan(SeqScanState *node);
extern void ExecEndSeqScan(SeqScanState *node);
extern void ExecReScanSeqScan(SeqScanState *node);
diff --git a/src/include/executor/nodeSetOp.h b/src/include/executor/nodeSetOp.h
index af85977183..c15f945046 100644
--- a/src/include/executor/nodeSetOp.h
+++ b/src/include/executor/nodeSetOp.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SetOpState *ExecInitSetOp(SetOp *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSetOp(SetOpState *node);
extern void ExecEndSetOp(SetOpState *node);
extern void ExecReScanSetOp(SetOpState *node);
diff --git a/src/include/executor/nodeSort.h b/src/include/executor/nodeSort.h
index 1d2b7130b3..ed0e9dbb53 100644
--- a/src/include/executor/nodeSort.h
+++ b/src/include/executor/nodeSort.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SortState *ExecInitSort(Sort *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSort(SortState *node);
extern void ExecEndSort(SortState *node);
extern void ExecSortMarkPos(SortState *node);
extern void ExecSortRestrPos(SortState *node);
diff --git a/src/include/executor/nodeSubqueryscan.h b/src/include/executor/nodeSubqueryscan.h
index c852e2947f..710e050285 100644
--- a/src/include/executor/nodeSubqueryscan.h
+++ b/src/include/executor/nodeSubqueryscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern SubqueryScanState *ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecSubqueryScan(SubqueryScanState *node);
extern void ExecEndSubqueryScan(SubqueryScanState *node);
extern void ExecReScanSubqueryScan(SubqueryScanState *node);
diff --git a/src/include/executor/nodeTableFuncscan.h b/src/include/executor/nodeTableFuncscan.h
index c58156e99c..c4672c0ac0 100644
--- a/src/include/executor/nodeTableFuncscan.h
+++ b/src/include/executor/nodeTableFuncscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TableFuncScanState *ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTableFuncScan(TableFuncScanState *node);
extern void ExecEndTableFuncScan(TableFuncScanState *node);
extern void ExecReScanTableFuncScan(TableFuncScanState *node);
diff --git a/src/include/executor/nodeTidscan.h b/src/include/executor/nodeTidscan.h
index d07ed7c864..e68aaf3829 100644
--- a/src/include/executor/nodeTidscan.h
+++ b/src/include/executor/nodeTidscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern TidScanState *ExecInitTidScan(TidScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecTidScan(TidScanState *node);
extern void ExecEndTidScan(TidScanState *node);
extern void ExecReScanTidScan(TidScanState *node);
diff --git a/src/include/executor/nodeUnique.h b/src/include/executor/nodeUnique.h
index 3d0ac9dde1..008774ae0f 100644
--- a/src/include/executor/nodeUnique.h
+++ b/src/include/executor/nodeUnique.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern UniqueState *ExecInitUnique(Unique *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecUnique(UniqueState *node);
extern void ExecEndUnique(UniqueState *node);
extern void ExecReScanUnique(UniqueState *node);
diff --git a/src/include/executor/nodeValuesscan.h b/src/include/executor/nodeValuesscan.h
index c28bb1acce..772a5e9705 100644
--- a/src/include/executor/nodeValuesscan.h
+++ b/src/include/executor/nodeValuesscan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern ValuesScanState *ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecValuesScan(ValuesScanState *node);
extern void ExecEndValuesScan(ValuesScanState *node);
extern void ExecReScanValuesScan(ValuesScanState *node);
diff --git a/src/include/executor/nodeWindowAgg.h b/src/include/executor/nodeWindowAgg.h
index db1ad60677..1c177309ae 100644
--- a/src/include/executor/nodeWindowAgg.h
+++ b/src/include/executor/nodeWindowAgg.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WindowAggState *ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecWindowAgg(WindowAggState *node);
extern void ExecEndWindowAgg(WindowAggState *node);
extern void ExecReScanWindowAgg(WindowAggState *node);
diff --git a/src/include/executor/nodeWorktablescan.h b/src/include/executor/nodeWorktablescan.h
index c222d9f6b4..df05e75111 100644
--- a/src/include/executor/nodeWorktablescan.h
+++ b/src/include/executor/nodeWorktablescan.h
@@ -17,7 +17,6 @@
#include "nodes/execnodes.h"
extern WorkTableScanState *ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags);
-extern TupleTableSlot *ExecWorkTableScan(WorkTableScanState *node);
extern void ExecEndWorkTableScan(WorkTableScanState *node);
extern void ExecReScanWorkTableScan(WorkTableScanState *node);
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 85fac8ab91..35c28a6143 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -818,6 +818,18 @@ typedef struct DomainConstraintState
* ----------------------------------------------------------------
*/
+struct PlanState;
+
+/* ----------------
+ * ExecProcNodeMtd
+ *
+ * This is the method called by ExecProcNode to return the next tuple
+ * from an executor node. It returns NULL, or an empty TupleTableSlot,
+ * if no more tuples are available.
+ * ----------------
+ */
+typedef TupleTableSlot *(*ExecProcNodeMtd) (struct PlanState *pstate);
+
/* ----------------
* PlanState node
*
@@ -835,6 +847,10 @@ typedef struct PlanState
* nodes point to one EState for the whole
* top-level plan */
+ ExecProcNodeMtd ExecProcNode; /* function to return next tuple */
+ ExecProcNodeMtd ExecProcNodeReal; /* actual function, if above is a
+ * wrapper */
+
Instrumentation *instrument; /* Optional runtime stats for this node */
WorkerInstrumentation *worker_instrument; /* per-worker instrumentation */
--
cgit v1.2.3
From 9fe63092b541e48aebb1190179b47249672a8560 Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii
Date: Mon, 31 Jul 2017 10:46:32 +0900
Subject: Add missing comment in postgresql.conf.
max_logical_replication_workers requires to restart server to reflect
the new value. Per Yugo Nagata. Minor editing by me.
---
src/backend/utils/misc/postgresql.conf.sample | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 2b1ebb797e..e33a4ef74b 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -277,6 +277,7 @@
# These settings are ignored on a publisher.
#max_logical_replication_workers = 4 # taken from max_worker_processes
+ # (change requires restart)
#max_sync_workers_per_subscription = 2 # taken from max_logical_replication_workers
--
cgit v1.2.3
From 8b015dd723ffc1ae7123758dda90d0bf0fa9b464 Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii
Date: Mon, 31 Jul 2017 11:06:37 +0900
Subject: Add missing comment in postgresql.conf.
dynamic_shared_memory_type requires to restart server to reflect
the new value. Per Yugo Nagata and Masahiko Sawada.
Back pached to 9.4 and beyond.
---
src/backend/utils/misc/postgresql.conf.sample | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index e33a4ef74b..96f48d9e52 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -130,6 +130,7 @@
# windows
# mmap
# use none to disable dynamic shared memory
+ # (change requires restart)
# - Disk -
--
cgit v1.2.3
From 393d47ed0f5b764341c7733ef60e8442d3e9bdc2 Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii
Date: Mon, 31 Jul 2017 11:24:51 +0900
Subject: Add missing comment in postgresql.conf.
current_source requires to restart server to reflect the new
value. Per Yugo Nagata and Masahiko Sawada.
Back patched to 9.2 and beyond.
---
src/backend/utils/misc/postgresql.conf.sample | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 96f48d9e52..1906b5a33c 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -379,6 +379,7 @@
#syslog_split_messages = on
# This is only relevant when logging to eventlog (win32):
+# (change requires restart)
#event_source = 'PostgreSQL'
# - When to Log -
--
cgit v1.2.3
From d2a51e3efcbab5b288bbadba1a7dfa123a50ba5b Mon Sep 17 00:00:00 2001
From: Stephen Frost
Date: Mon, 31 Jul 2017 10:37:08 -0400
Subject: Fix function comment for dumpACL()
The comment for dumpACL() got neglected when initacls and initracls were
added and the discussion of what 'racls' is wasn't very clear either.
Per complaint from Tom.
---
src/bin/pg_dump/pg_dump.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 8e9454885a..393b9e25a9 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -14435,10 +14435,20 @@ dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
* 'tag' is the tag for the archive entry (typ. unquoted name of object).
* 'nspname' is the namespace the object is in (NULL if none).
* 'owner' is the owner, NULL if there is no owner (for languages).
- * 'acls' is the string read out of the fooacl system catalog field;
- * it will be parsed here.
- * 'racls' contains any initial ACLs that the object had which have now been
- * revoked by the user, it will also be parsed here.
+ * 'acls' contains the ACL string of the object from the appropriate system
+ * catalog field; it will be passed to buildACLCommands for building the
+ * appropriate GRANT commands.
+ * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
+ * object; it will be passed to buildACLCommands for building the
+ * appropriate REVOKE commands.
+ * 'initacls' In binary-upgrade mode, ACL string of the object's initial
+ * privileges, to be recorded into pg_init_privs
+ * 'initracls' In binary-upgrade mode, ACL string of the object's
+ * revoked-from-default privileges, to be recorded into pg_init_privs
+ *
+ * NB: initacls/initracls are needed because extensions can set privileges on
+ * an object during the extension's script file and we record those into
+ * pg_init_privs as that object's initial privileges.
*----------
*/
static void
--
cgit v1.2.3
From b4cc35fbb709bd6fcae8998f041fd731c9acbf42 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Mon, 31 Jul 2017 11:33:46 -0400
Subject: Tighten coding for non-composite case in plperl's return_next.
Coverity complained about this code's practice of using scalar variables
as single-element arrays. While that's really just nitpicking, it probably
is more readable to declare them as arrays, so let's do that. A more
important point is that the code was just blithely assuming that the
result tupledesc has exactly one column; if it doesn't, we'd likely get
a crash of some sort in tuplestore_putvalues. Since the tupledesc is
manufactured outside of plperl, that seems like an uncomfortably long
chain of assumptions. We can nail it down at little cost with a sanity
check earlier in the function.
---
src/pl/plperl/plperl.c | 28 +++++++++++++++++-----------
1 file changed, 17 insertions(+), 11 deletions(-)
(limited to 'src')
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index b10b4434aa..afebec910d 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -3247,12 +3247,18 @@ plperl_return_next_internal(SV *sv)
/*
* This is the first call to return_next in the current PL/Perl
- * function call, so memoize some lookups
+ * function call, so identify the output tuple descriptor and create a
+ * tuplestore to hold the result rows.
*/
if (prodesc->fn_retistuple)
(void) get_call_result_type(fcinfo, NULL, &tupdesc);
else
+ {
tupdesc = rsi->expectedDesc;
+ /* Protect assumption below that we return exactly one column */
+ if (tupdesc == NULL || tupdesc->natts != 1)
+ elog(ERROR, "expected single-column result descriptor for non-composite SETOF result");
+ }
/*
* Make sure the tuple_store and ret_tdesc are sufficiently
@@ -3300,20 +3306,20 @@ plperl_return_next_internal(SV *sv)
}
else
{
- Datum ret;
- bool isNull;
+ Datum ret[1];
+ bool isNull[1];
- ret = plperl_sv_to_datum(sv,
- prodesc->result_oid,
- -1,
- fcinfo,
- &prodesc->result_in_func,
- prodesc->result_typioparam,
- &isNull);
+ ret[0] = plperl_sv_to_datum(sv,
+ prodesc->result_oid,
+ -1,
+ fcinfo,
+ &prodesc->result_in_func,
+ prodesc->result_typioparam,
+ &isNull[0]);
tuplestore_putvalues(current_call_data->tuple_store,
current_call_data->ret_tdesc,
- &ret, &isNull);
+ ret, isNull);
}
MemoryContextSwitchTo(old_cxt);
--
cgit v1.2.3
From c0a15e07cd718cb6e455e68328f522ac076a0e4b Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas
Date: Mon, 31 Jul 2017 22:36:09 +0300
Subject: Always use 2048 bit DH parameters for OpenSSL ephemeral DH ciphers.
1024 bits is considered weak these days, but OpenSSL always passes 1024 as
the key length to the tmp_dh callback. All the code to handle other key
lengths is, in fact, dead.
To remedy those issues:
* Only include hard-coded 2048-bit parameters.
* Set the parameters directly with SSL_CTX_set_tmp_dh(), without the
callback
* The name of the file containing the DH parameters is now a GUC. This
replaces the old hardcoded "dh1024.pem" filename. (The files for other
key lengths, dh512.pem, dh2048.pem, etc. were never actually used.)
This is not a new problem, but it doesn't seem worth the risk and churn to
backport. If you care enough about the strength of the DH parameters on
old versions, you can create custom DH parameters, with as many bits as you
wish, and put them in the "dh1024.pem" file.
Per report by Nicolas Guini and Damian Quiroga. Reviewed by Michael Paquier.
Discussion: https://www.postgresql.org/message-id/CAMxBoUyjOOautVozN6ofzym828aNrDjuCcOTcCquxjwS-L2hGQ@mail.gmail.com
---
doc/src/sgml/config.sgml | 24 +++
src/backend/libpq/be-secure-openssl.c | 264 +++++++++-----------------
src/backend/libpq/be-secure.c | 1 +
src/backend/utils/misc/guc.c | 11 ++
src/backend/utils/misc/postgresql.conf.sample | 1 +
src/include/libpq/libpq.h | 1 +
6 files changed, 133 insertions(+), 169 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b45b7f7f69..c33d6a0349 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1203,6 +1203,30 @@ include_dir 'conf.d'
+
+ ssl_dh_params_file (string)
+
+ ssl_dh_params_file> configuration parameter
+
+
+
+
+ Specifies the name of the file containing Diffie-Hellman parameters
+ used for so-called ephemeral DH family of SSL ciphers. The default is
+ empty, in which case compiled-in default DH parameters used. Using
+ custom DH parameters reduces the exposure if an attacker manages to
+ crack the well-known compiled-in DH parameters. You can create your own
+ DH parameters file with the command
+ openssl dhparam -out dhparams.pem 2048.
+
+
+
+ This parameter can only be set in the postgresql.conf>
+ file or on the server command line.
+
+
+
+
krb_server_keyfile (string)
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 67145e9412..dc307c101f 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -61,6 +61,7 @@
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "pgstat.h"
+#include "storage/fd.h"
#include "storage/latch.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
@@ -71,13 +72,12 @@ static int my_sock_write(BIO *h, const char *buf, int size);
static BIO_METHOD *my_BIO_s_socket(void);
static int my_SSL_set_fd(Port *port, int fd);
-static DH *load_dh_file(int keylength);
+static DH *load_dh_file(char *filename, bool isServerStart);
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 ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);
static int verify_cb(int, X509_STORE_CTX *);
static void info_cb(const SSL *ssl, int type, int args);
+static bool initialize_dh(SSL_CTX *context, bool isServerStart);
static bool initialize_ecdh(SSL_CTX *context, bool isServerStart);
static const char *SSLerrmessage(unsigned long ecode);
@@ -96,17 +96,14 @@ static bool ssl_passwd_cb_called = false;
* As discussed above, EDH protects the confidentiality of
* sessions even if the static private key is compromised,
* so we are *highly* motivated to ensure that we can use
- * EDH even if the DBA... or an attacker... deletes the
- * $DataDir/dh*.pem files.
+ * EDH even if the DBA has not provided custom DH parameters.
*
* We could refuse SSL connections unless a good DH parameter
* file exists, but some clients may quietly renegotiate an
* unsecured connection without fully informing the user.
- * Very uncool.
- *
- * Alternatively, the backend could attempt to load these files
- * on startup if SSL is enabled - and refuse to start if any
- * do not exist - but this would tend to piss off DBAs.
+ * Very uncool. Alternatively, the system could refuse to start
+ * if a DH parameters is not specified, but this would tend to
+ * piss off DBAs.
*
* If you want to create your own hardcoded DH parameters
* for fun and profit, review "Assigned Number for SKIP
@@ -114,19 +111,6 @@ static bool ssl_passwd_cb_called = false;
* for suggestions.
*/
-static const char file_dh512[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\
-XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\
------END DH PARAMETERS-----\n";
-
-static const char file_dh1024[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\
-jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\
-ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\
------END DH PARAMETERS-----\n";
-
static const char file_dh2048[] =
"-----BEGIN DH PARAMETERS-----\n\
MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\
@@ -137,21 +121,6 @@ Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\
CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\
-----END DH PARAMETERS-----\n";
-static const char file_dh4096[] =
-"-----BEGIN DH PARAMETERS-----\n\
-MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\
-l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\
-Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\
-Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\
-VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\
-alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\
-sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\
-ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\
-OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\
-AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\
-KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
------END DH PARAMETERS-----\n";
-
/* ------------------------------------------------------------ */
/* Public interface */
@@ -316,13 +285,14 @@ be_tls_init(bool isServerStart)
goto error;
}
- /* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
- SSL_CTX_set_tmp_dh_callback(context, tmp_dh_cb);
+ /* disallow SSL v2/v3 */
SSL_CTX_set_options(context,
SSL_OP_SINGLE_DH_USE |
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
- /* set up ephemeral ECDH keys */
+ /* set up ephemeral DH and ECDH keys */
+ if (!initialize_dh(context, isServerStart))
+ goto error;
if (!initialize_ecdh(context, isServerStart))
goto error;
@@ -918,53 +888,57 @@ err:
* what we expect it to contain.
*/
static DH *
-load_dh_file(int keylength)
+load_dh_file(char *filename, bool isServerStart)
{
FILE *fp;
- char fnbuf[MAXPGPATH];
DH *dh = NULL;
int codes;
/* attempt to open file. It's not an error if it doesn't exist. */
- snprintf(fnbuf, sizeof(fnbuf), "dh%d.pem", keylength);
- if ((fp = fopen(fnbuf, "r")) == NULL)
+ if ((fp = AllocateFile(filename, "r")) == NULL)
+ {
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode_for_file_access(),
+ errmsg("could not open DH parameters file \"%s\": %m",
+ filename)));
return NULL;
+ }
-/* flock(fileno(fp), LOCK_SH); */
dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
-/* flock(fileno(fp), LOCK_UN); */
- fclose(fp);
+ FreeFile(fp);
- /* is the prime the correct size? */
- if (dh != NULL && 8 * DH_size(dh) < keylength)
+ if (dh == NULL)
{
- elog(LOG, "DH errors (%s): %d bits expected, %d bits found",
- fnbuf, keylength, 8 * DH_size(dh));
- dh = NULL;
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("could not load DH parameters file: %s",
+ SSLerrmessage(ERR_get_error()))));
+ return NULL;
}
/* make sure the DH parameters are usable */
- if (dh != NULL)
+ if (DH_check(dh, &codes) == 0)
{
- if (DH_check(dh, &codes) == 0)
- {
- elog(LOG, "DH_check error (%s): %s", fnbuf,
- SSLerrmessage(ERR_get_error()));
- return NULL;
- }
- if (codes & DH_CHECK_P_NOT_PRIME)
- {
- elog(LOG, "DH error (%s): p is not prime", fnbuf);
- return NULL;
- }
- if ((codes & DH_NOT_SUITABLE_GENERATOR) &&
- (codes & DH_CHECK_P_NOT_SAFE_PRIME))
- {
- elog(LOG,
- "DH error (%s): neither suitable generator or safe prime",
- fnbuf);
- return NULL;
- }
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("invalid DH parameters: %s",
+ SSLerrmessage(ERR_get_error()))));
+ return NULL;
+ }
+ if (codes & DH_CHECK_P_NOT_PRIME)
+ {
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("invalid DH parameters: p is not prime")));
+ return NULL;
+ }
+ if ((codes & DH_NOT_SUITABLE_GENERATOR) &&
+ (codes & DH_CHECK_P_NOT_SAFE_PRIME))
+ {
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("invalid DH parameters: neither suitable generator or safe prime")));
+ return NULL;
}
return dh;
@@ -995,102 +969,6 @@ 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)
-{
- 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;
-}
-
-/*
- * Generate an ephemeral DH key. Because this can take a long
- * time to compute, we can use precomputed parameters of the
- * common key sizes.
- *
- * Since few sites will bother to precompute these parameter
- * files, we also provide a fallback to the parameters provided
- * by the OpenSSL project.
- *
- * These values can be static (once loaded or computed) since
- * the OpenSSL library can efficiently generate random keys from
- * the information provided.
- */
-static DH *
-tmp_dh_cb(SSL *s, int is_export, int keylength)
-{
- DH *r = NULL;
- static DH *dh = NULL;
- static DH *dh512 = NULL;
- static DH *dh1024 = NULL;
- static DH *dh2048 = NULL;
- static DH *dh4096 = NULL;
-
- switch (keylength)
- {
- case 512:
- if (dh512 == NULL)
- dh512 = load_dh_file(keylength);
- if (dh512 == NULL)
- dh512 = load_dh_buffer(file_dh512, sizeof file_dh512);
- r = dh512;
- break;
-
- case 1024:
- if (dh1024 == NULL)
- dh1024 = load_dh_file(keylength);
- if (dh1024 == NULL)
- dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024);
- r = dh1024;
- break;
-
- case 2048:
- if (dh2048 == NULL)
- dh2048 = load_dh_file(keylength);
- if (dh2048 == NULL)
- dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048);
- r = dh2048;
- break;
-
- case 4096:
- if (dh4096 == NULL)
- dh4096 = load_dh_file(keylength);
- if (dh4096 == NULL)
- dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096);
- r = dh4096;
- break;
-
- default:
- if (dh == NULL)
- dh = load_dh_file(keylength);
- r = dh;
- }
-
- /* this may take a long time, but it may be necessary... */
- if (r == NULL || 8 * DH_size(r) < keylength)
- {
- ereport(DEBUG2,
- (errmsg_internal("DH: generating parameters (%d bits)",
- keylength)));
- r = generate_dh_parameters(keylength, DH_GENERATOR_2);
- }
-
- return r;
-}
-
/*
* Passphrase collection callback
*
@@ -1172,6 +1050,54 @@ info_cb(const SSL *ssl, int type, int args)
}
}
+/*
+ * Set DH parameters for generating ephemeral DH keys. The
+ * DH parameters can take a long time to compute, so they must be
+ * precomputed.
+ *
+ * Since few sites will bother to create a parameter file, we also
+ * also provide a fallback to the parameters provided by the
+ * OpenSSL project.
+ *
+ * These values can be static (once loaded or computed) since the
+ * OpenSSL library can efficiently generate random keys from the
+ * information provided.
+ */
+static bool
+initialize_dh(SSL_CTX *context, bool isServerStart)
+{
+ DH *dh = NULL;
+
+ SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
+
+ if (ssl_dh_params_file[0])
+ dh = load_dh_file(ssl_dh_params_file, isServerStart);
+ if (!dh)
+ dh = load_dh_buffer(file_dh2048, sizeof file_dh2048);
+ if (!dh)
+ {
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ (errmsg("DH: could not load DH parameters"))));
+ return false;
+ }
+
+ if (SSL_CTX_set_tmp_dh(context, dh) != 1)
+ {
+ ereport(isServerStart ? FATAL : LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ (errmsg("DH: could not set DH parameters: %s",
+ SSLerrmessage(ERR_get_error())))));
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Set ECDH parameters for generating ephemeral Elliptic Curve DH
+ * keys. This is much simpler than the DH parameters, as we just
+ * need to provide the name of the curve to OpenSSL.
+ */
static bool
initialize_ecdh(SSL_CTX *context, bool isServerStart)
{
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 785dadb6c2..53fefd1b29 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -44,6 +44,7 @@ char *ssl_cert_file;
char *ssl_key_file;
char *ssl_ca_file;
char *ssl_crl_file;
+char *ssl_dh_params_file;
#ifdef USE_SSL
bool ssl_loaded_verify_locations = false;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 82e54c084b..246fea8693 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3606,6 +3606,17 @@ static struct config_string ConfigureNamesString[] =
NULL, NULL, NULL
},
+ {
+ {"ssl_dh_params_file", PGC_SIGHUP, CONN_AUTH_SECURITY,
+ gettext_noop("Location of the SSL DH params file."),
+ NULL,
+ GUC_SUPERUSER_ONLY
+ },
+ &ssl_dh_params_file,
+ "",
+ NULL, NULL, NULL
+ },
+
{
{"application_name", PGC_USERSET, LOGGING_WHAT,
gettext_noop("Sets the application name to be reported in statistics and logs."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 1906b5a33c..df5d2f3f22 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -80,6 +80,7 @@
#ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL' # allowed SSL ciphers
#ssl_prefer_server_ciphers = on
#ssl_ecdh_curve = 'prime256v1'
+#ssl_dh_params_file = ''
#ssl_cert_file = 'server.crt'
#ssl_key_file = 'server.key'
#ssl_ca_file = ''
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index 78851b1060..fd2dd5853c 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -79,6 +79,7 @@ extern char *ssl_cert_file;
extern char *ssl_key_file;
extern char *ssl_ca_file;
extern char *ssl_crl_file;
+extern char *ssl_dh_params_file;
extern int secure_initialize(bool isServerStart);
extern bool secure_loaded_verify_locations(void);
--
cgit v1.2.3
From f40254a799f7057a415917dacb5ba7eab5b17a99 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 31 Jul 2017 17:08:14 -0400
Subject: Fix typo
Author: Etsuro Fujita
---
src/backend/executor/execMain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 78cbcd1a32..c11aa4fe21 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -3334,7 +3334,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
/*
* First check the root table's partition constraint, if any. No point in
- * routing the tuple it if it doesn't belong in the root table itself.
+ * routing the tuple if it doesn't belong in the root table itself.
*/
if (resultRelInfo->ri_PartitionCheck)
ExecPartitionCheck(resultRelInfo, slot, estate);
--
cgit v1.2.3
From 0b02e3f1289e0454d313e6add45f43a287ebaf8b Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 31 Jul 2017 17:22:47 -0400
Subject: Fix typo
Author: Masahiko Sawada
---
src/bin/pg_upgrade/info.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index f7c278b306..0b14998f4b 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -210,7 +210,7 @@ create_rel_filename_map(const char *old_data, const char *new_data,
/* new_relfilenode will match old and new pg_class.oid */
map->new_relfilenode = new_rel->relfilenode;
- /* used only for logging and error reporing, old/new are identical */
+ /* used only for logging and error reporting, old/new are identical */
map->nspname = old_rel->nspname;
map->relname = old_rel->relname;
}
--
cgit v1.2.3
From e662ef0f2e95d9da3df705ddaaff36b0c01c7acc Mon Sep 17 00:00:00 2001
From: Tatsuo Ishii
Date: Tue, 1 Aug 2017 08:00:11 +0900
Subject: Fix comment.
XLByteToSeg and XLByteToPrevSeg calculate only a segment number. The
definition of these macros were modified by commit
dfda6ebaec6763090fb78b458a979b558c50b39b but the comment remain
unchanged.
Patch by Yugo Nagata. Back patched to 9.3 and beyond.
---
src/include/access/xlog_internal.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index a661ec0180..7453dcbd0e 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -96,7 +96,7 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
(dest) = (segno) * XLOG_SEG_SIZE + (offset)
/*
- * Compute ID and segment from an XLogRecPtr.
+ * Compute a segment number from an XLogRecPtr.
*
* For XLByteToSeg, do the computation at face value. For XLByteToPrevSeg,
* a boundary byte is taken to be in the previous segment. This is suitable
--
cgit v1.2.3
From 4de6216877a32e869fe1cf168c1fe1ffb8c3d576 Mon Sep 17 00:00:00 2001
From: Dean Rasheed
Date: Tue, 1 Aug 2017 09:40:45 +0100
Subject: Comment fix for partition_rbound_cmp().
This was an oversight in d363d42.
Beena Emerson
---
src/backend/catalog/partition.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index e20ddce2db..9d50efb6a0 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -2128,7 +2128,7 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
* partition_rbound_cmp
*
* Return for two range bounds whether the 1st one (specified in datum1,
- * content1, and lower1) is <, =, or > the bound specified in *b2.
+ * kind1, and lower1) is <, =, or > the bound specified in *b2.
*
* Note that if the values of the two range bounds compare equal, then we take
* into account whether they are upper or lower bounds, and an upper bound is
--
cgit v1.2.3
From f97256570f45c33abf695a189ab11b25e6cd7985 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 1 Aug 2017 13:51:05 -0400
Subject: Allow creation of C/POSIX collations without depending on libc
behavior.
Most of our collations code has special handling for the locale names
"C" and "POSIX", allowing those collations to be used whether or not
the system libraries think those locale names are valid, or indeed
whether said libraries even have any locale support. But we missed
handling things that way in CREATE COLLATION. This meant you couldn't
clone the C/POSIX collations, nor explicitly define a new collation
using those locale names, unless the libraries allow it. That's pretty
pointless, as well as being a violation of pg_newlocale_from_collation's
API specification.
The practical effect of this change is quite limited: it allows creating
such collations even on platforms that don't HAVE_LOCALE_T, and it allows
making "POSIX" collation objects on Windows, which before this would only
let you make "C" collation objects. Hence, even though this is a bug fix
IMO, it doesn't seem worth the trouble to back-patch.
In passing, suppress the DROP CASCADE detail messages at the end of the
collation regression test. I'm surprised we've never been bit by
message ordering issues there.
Per report from Murtuza Zabuawala.
Discussion: https://postgr.es/m/CAKKotZS-wcDcofXDCH=sidiuajE+nqHn2CGjLLX78anyDmi3gQ@mail.gmail.com
---
src/backend/commands/collationcmds.c | 12 ++++++++----
src/test/regress/expected/collate.out | 29 +++++++++++++----------------
src/test/regress/sql/collate.sql | 12 ++++++++++++
3 files changed, 33 insertions(+), 20 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index b6c14c920d..d19a384f9c 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -214,11 +214,15 @@ DefineCollation(ParseState *pstate, List *names, List *parameters, bool if_not_e
if (!OidIsValid(newoid))
return InvalidObjectAddress;
- ObjectAddressSet(address, CollationRelationId, newoid);
-
- /* check that the locales can be loaded */
+ /*
+ * Check that the locales can be loaded. NB: pg_newlocale_from_collation
+ * is only supposed to be called on non-C-equivalent locales.
+ */
CommandCounterIncrement();
- (void) pg_newlocale_from_collation(newoid);
+ if (!lc_collate_is_c(newoid) || !lc_ctype_is_c(newoid))
+ (void) pg_newlocale_from_collation(newoid);
+
+ ObjectAddressSet(address, CollationRelationId, newoid);
return address;
}
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index d667ae1714..b0025c0a87 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -622,6 +622,17 @@ EXPLAIN (COSTS OFF)
-> Seq Scan on collate_test10
(3 rows)
+-- CREATE/DROP COLLATION
+CREATE COLLATION mycoll1 FROM "C";
+CREATE COLLATION mycoll2 ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
+CREATE COLLATION mycoll3 FROM "default"; -- intentionally unsupported
+ERROR: collation "default" cannot be copied
+DROP COLLATION mycoll1;
+CREATE TABLE collate_test23 (f1 text collate mycoll2);
+DROP COLLATION mycoll2; -- fail
+ERROR: cannot drop collation mycoll2 because other objects depend on it
+DETAIL: table collate_test23 column f1 depends on collation mycoll2
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
CREATE TEMP TABLE vctable (f1 varchar(25));
INSERT INTO vctable VALUES ('foo' COLLATE "C");
@@ -650,20 +661,6 @@ SELECT collation for ((SELECT b FROM collate_test1 LIMIT 1));
-- trying to run any platform-specific collation tests later, so we
-- must get rid of them.
--
+\set VERBOSITY terse
DROP SCHEMA collate_tests CASCADE;
-NOTICE: drop cascades to 15 other objects
-DETAIL: drop cascades to table collate_test1
-drop cascades to table collate_test_like
-drop cascades to table collate_test2
-drop cascades to type testdomain_p
-drop cascades to table collate_test4
-drop cascades to table collate_test5
-drop cascades to table collate_test10
-drop cascades to view collview1
-drop cascades to view collview2
-drop cascades to view collview3
-drop cascades to type testdomain
-drop cascades to function dup(anyelement)
-drop cascades to table collate_test20
-drop cascades to table collate_test21
-drop cascades to table collate_test22
+NOTICE: drop cascades to 17 other objects
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index e8ca0856e3..698f577490 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -229,6 +229,17 @@ EXPLAIN (COSTS OFF)
SELECT * FROM collate_test10 ORDER BY x DESC, y COLLATE "C" ASC NULLS FIRST;
+-- CREATE/DROP COLLATION
+
+CREATE COLLATION mycoll1 FROM "C";
+CREATE COLLATION mycoll2 ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
+CREATE COLLATION mycoll3 FROM "default"; -- intentionally unsupported
+
+DROP COLLATION mycoll1;
+CREATE TABLE collate_test23 (f1 text collate mycoll2);
+DROP COLLATION mycoll2; -- fail
+
+
-- 9.1 bug with useless COLLATE in an expression subject to length coercion
CREATE TEMP TABLE vctable (f1 varchar(25));
@@ -246,4 +257,5 @@ SELECT collation for ((SELECT b FROM collate_test1 LIMIT 1));
-- trying to run any platform-specific collation tests later, so we
-- must get rid of them.
--
+\set VERBOSITY terse
DROP SCHEMA collate_tests CASCADE;
--
cgit v1.2.3
From 1e165d05fe06a9072867607886f818bc255507db Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 1 Aug 2017 16:11:51 -0400
Subject: Try to deliver a sane message for _create_locale() failure on
Windows.
We were just printing errno, which is certainly not gonna work on
Windows. Now, it's not entirely clear from Microsoft's documentation
whether _create_locale() adheres to standard Windows error reporting
conventions, but let's assume it does and try to map the GetLastError
result to an errno. If this turns out not to work, probably the best
thing to do will be to assume the error is always ENOENT on Windows.
This is a longstanding bug, but given the lack of previous field
complaints, I'm not excited about back-patching it.
Per report from Murtuza Zabuawala.
Discussion: https://postgr.es/m/CAKKotZS-wcDcofXDCH=sidiuajE+nqHn2CGjLLX78anyDmi3gQ@mail.gmail.com
---
src/backend/utils/adt/pg_locale.c | 9 +++++++--
src/test/regress/expected/collate.out | 3 +++
src/test/regress/sql/collate.sql | 1 +
3 files changed, 11 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 12419fc8df..9500c6b39f 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -1227,13 +1227,18 @@ lc_ctype_is_c(Oid collation)
static void
report_newlocale_failure(const char *localename)
{
- /* copy errno in case one of the ereport auxiliary functions changes it */
- int save_errno = errno;
+ int save_errno;
+
+ /* On Windows, transform _create_locale() error to errno */
+#ifdef WIN32
+ _dosmaperr(GetLastError());
+#endif
/*
* ENOENT means "no such locale", not "no such file", so clarify that
* errno with an errdetail message.
*/
+ save_errno = errno; /* auxiliary funcs might change errno */
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not create locale \"%s\": %m",
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index b0025c0a87..70866df000 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -627,6 +627,9 @@ CREATE COLLATION mycoll1 FROM "C";
CREATE COLLATION mycoll2 ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
CREATE COLLATION mycoll3 FROM "default"; -- intentionally unsupported
ERROR: collation "default" cannot be copied
+CREATE COLLATION mycoll4 ( LOCALE = "no_such_locale" ); -- fail
+ERROR: could not create locale "no_such_locale": No such file or directory
+DETAIL: The operating system could not find any locale data for the locale name "no_such_locale".
DROP COLLATION mycoll1;
CREATE TABLE collate_test23 (f1 text collate mycoll2);
DROP COLLATION mycoll2; -- fail
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index 698f577490..f095ae08be 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -234,6 +234,7 @@ EXPLAIN (COSTS OFF)
CREATE COLLATION mycoll1 FROM "C";
CREATE COLLATION mycoll2 ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
CREATE COLLATION mycoll3 FROM "default"; -- intentionally unsupported
+CREATE COLLATION mycoll4 ( LOCALE = "no_such_locale" ); -- fail
DROP COLLATION mycoll1;
CREATE TABLE collate_test23 (f1 text collate mycoll2);
--
cgit v1.2.3
From 8e7537261c4b7d296fc10513b93bd67dc3d415b0 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 1 Aug 2017 16:49:23 -0400
Subject: Suppress less info in regression tests using DROP CASCADE.
DROP CASCADE doesn't currently promise to visit dependent objects in
a fixed order, so when the regression tests use it, we typically need
to suppress the details of which objects get dropped in order to have
predictable test output. Traditionally we've done that by setting
client_min_messages higher than NOTICE, but there's a better way:
we can "\set VERBOSITY terse" in psql. That suppresses the DETAIL
message with the object list, but we still get the basic notice telling
how many objects were dropped. So at least the test case can verify
that the expected number of objects were dropped.
The VERBOSITY method was already in use in a few places, but run
around and use it wherever it makes sense.
Discussion: https://postgr.es/m/10766.1501608885@sss.pgh.pa.us
---
src/test/regress/expected/alter_generic.out | 6 +++++-
src/test/regress/expected/create_index.out | 4 ++--
src/test/regress/expected/create_view.out | 4 +++-
src/test/regress/expected/object_address.out | 4 +++-
src/test/regress/expected/privileges.out | 9 +++++----
src/test/regress/expected/rowsecurity.out | 18 +++++++++---------
src/test/regress/expected/rules.out | 5 +++--
src/test/regress/expected/stats_ext.out | 6 ++++--
src/test/regress/expected/typed_table.out | 4 ----
src/test/regress/sql/alter_generic.sql | 2 +-
src/test/regress/sql/create_index.sql | 3 +--
src/test/regress/sql/create_view.sql | 2 +-
src/test/regress/sql/object_address.sql | 2 +-
src/test/regress/sql/privileges.sql | 8 ++++----
src/test/regress/sql/rowsecurity.sql | 16 ++++++----------
src/test/regress/sql/rules.sql | 4 ++--
src/test/regress/sql/stats_ext.sql | 4 ++--
src/test/regress/sql/typed_table.sql | 7 -------
18 files changed, 52 insertions(+), 56 deletions(-)
(limited to 'src')
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 62347bc47e..9f6ad4de33 100644
--- a/src/test/regress/expected/alter_generic.out
+++ b/src/test/regress/expected/alter_generic.out
@@ -673,13 +673,17 @@ SELECT nspname, prsname
---
--- Cleanup resources
---
-set client_min_messages to warning; -- suppress cascade notices
+\set VERBOSITY terse \\ -- suppress cascade details
DROP FOREIGN DATA WRAPPER alt_fdw2 CASCADE;
+NOTICE: drop cascades to server alt_fserv2
DROP FOREIGN DATA WRAPPER alt_fdw3 CASCADE;
+NOTICE: drop cascades to server alt_fserv3
DROP LANGUAGE alt_lang2 CASCADE;
DROP LANGUAGE alt_lang3 CASCADE;
DROP SCHEMA alt_nsp1 CASCADE;
+NOTICE: drop cascades to 28 other objects
DROP SCHEMA alt_nsp2 CASCADE;
+NOTICE: drop cascades to 9 other objects
DROP USER regress_alter_user1;
DROP USER regress_alter_user2;
DROP USER regress_alter_user3;
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 26cd05933c..064adb4640 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -3064,6 +3064,6 @@ ERROR: must be owner of schema schema_to_reindex
-- Clean up
RESET ROLE;
DROP ROLE regress_reindexuser;
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA schema_to_reindex CASCADE;
-RESET client_min_messages;
+NOTICE: drop cascades to 6 other objects
diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out
index 34f0b7641d..f909a3cefe 100644
--- a/src/test/regress/expected/create_view.out
+++ b/src/test/regress/expected/create_view.out
@@ -1707,6 +1707,8 @@ select pg_get_ruledef(oid, true) from pg_rewrite
(1 row)
-- clean up all the random objects we made above
-set client_min_messages = warning;
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA temp_view_test CASCADE;
+NOTICE: drop cascades to 27 other objects
DROP SCHEMA testviewschm2 CASCADE;
+NOTICE: drop cascades to 62 other objects
diff --git a/src/test/regress/expected/object_address.out b/src/test/regress/expected/object_address.out
index 3f23a48972..1fdadbc9ef 100644
--- a/src/test/regress/expected/object_address.out
+++ b/src/test/regress/expected/object_address.out
@@ -474,10 +474,12 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)).*,
---
--- Cleanup resources
---
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP FOREIGN DATA WRAPPER addr_fdw CASCADE;
+NOTICE: drop cascades to 4 other objects
DROP PUBLICATION addr_pub;
DROP SUBSCRIPTION addr_sub;
DROP SCHEMA addr_nsp CASCADE;
+NOTICE: drop cascades to 12 other objects
DROP OWNED BY regress_addr_user;
DROP USER regress_addr_user;
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index 3262aa1d10..da37c4faed 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -1620,9 +1620,10 @@ SELECT has_function_privilege('regress_user1', 'testns.testfunc(int)', 'EXECUTE'
f
(1 row)
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA testns CASCADE;
-RESET client_min_messages;
+NOTICE: drop cascades to 3 other objects
+\set VERBOSITY default
-- Change owner of the schema & and rename of new schema owner
\c -
CREATE ROLE regress_schemauser1 superuser login;
@@ -1644,9 +1645,9 @@ SELECT nspname, rolname FROM pg_namespace, pg_roles WHERE pg_namespace.nspname =
(1 row)
set session role regress_schemauser_renamed;
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA testns CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
-- clean up
\c -
DROP ROLE regress_schemauser1;
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 26d28f248b..de2ee4d2c9 100644
--- a/src/test/regress/expected/rowsecurity.out
+++ b/src/test/regress/expected/rowsecurity.out
@@ -1393,10 +1393,10 @@ ERROR: infinite recursion detected in policy for relation "rec1"
-- Mutual recursion via .s.b views
--
SET SESSION AUTHORIZATION regress_rls_bob;
--- Suppress NOTICE messages when doing a cascaded drop.
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP VIEW rec1v, rec2v CASCADE;
-RESET client_min_messages;
+NOTICE: drop cascades to 2 other objects
+\set VERBOSITY default
CREATE VIEW rec1v WITH (security_barrier) AS SELECT * FROM rec1;
CREATE VIEW rec2v WITH (security_barrier) AS SELECT * FROM rec2;
SET SESSION AUTHORIZATION regress_rls_alice;
@@ -2775,10 +2775,10 @@ DROP TABLE test_qual_pushdown;
-- Plancache invalidate on user change.
--
RESET SESSION AUTHORIZATION;
--- Suppress NOTICE messages when doing a cascaded drop.
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP TABLE t1 CASCADE;
-RESET client_min_messages;
+NOTICE: drop cascades to 2 other objects
+\set VERBOSITY default
CREATE TABLE t1 (a integer);
GRANT SELECT ON t1 TO regress_rls_bob, regress_rls_carol;
CREATE POLICY p1 ON t1 TO regress_rls_bob USING ((a % 2) = 0);
@@ -3902,10 +3902,10 @@ DROP USER regress_rls_dob_role2;
-- Clean up objects
--
RESET SESSION AUTHORIZATION;
--- Suppress NOTICE messages when doing a cascaded drop.
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA regress_rls_schema CASCADE;
-RESET client_min_messages;
+NOTICE: drop cascades to 29 other objects
+\set VERBOSITY default
DROP USER regress_rls_alice;
DROP USER regress_rls_bob;
DROP USER regress_rls_carol;
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 2e42b9ec05..05adfa2376 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2622,9 +2622,10 @@ select * from id_ordered;
6 | Test 6
(6 rows)
-set client_min_messages to warning; -- suppress cascade notices
+\set VERBOSITY terse \\ -- suppress cascade details
drop table id cascade;
-reset client_min_messages;
+NOTICE: drop cascades to 4 other objects
+\set VERBOSITY default
--
-- check corner case where an entirely-dummy subplan is created by
-- constraint exclusion
diff --git a/src/test/regress/expected/stats_ext.out b/src/test/regress/expected/stats_ext.out
index 085dce7fd7..441cfaa411 100644
--- a/src/test/regress/expected/stats_ext.out
+++ b/src/test/regress/expected/stats_ext.out
@@ -122,10 +122,12 @@ EXCEPTION WHEN wrong_object_type THEN
END;
$$;
NOTICE: stats on toast table not created
-SET client_min_messages TO warning;
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA tststats CASCADE;
+NOTICE: drop cascades to 7 other objects
DROP FOREIGN DATA WRAPPER extstats_dummy_fdw CASCADE;
-RESET client_min_messages;
+NOTICE: drop cascades to server extstats_dummy_srv
+\set VERBOSITY default
-- n-distinct tests
CREATE TABLE ndistinct (
filler1 TEXT,
diff --git a/src/test/regress/expected/typed_table.out b/src/test/regress/expected/typed_table.out
index 5cdd019244..2e47ecbcf5 100644
--- a/src/test/regress/expected/typed_table.out
+++ b/src/test/regress/expected/typed_table.out
@@ -1,7 +1,3 @@
--- Clean up in case a prior regression run failed
-SET client_min_messages TO 'warning';
-DROP TYPE IF EXISTS person_type CASCADE;
-RESET client_min_messages;
CREATE TABLE ttable1 OF nothing;
ERROR: type "nothing" does not exist
CREATE TYPE person_type AS (id int, name text);
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 342f82856e..311812e351 100644
--- a/src/test/regress/sql/alter_generic.sql
+++ b/src/test/regress/sql/alter_generic.sql
@@ -573,7 +573,7 @@ SELECT nspname, prsname
---
--- Cleanup resources
---
-set client_min_messages to warning; -- suppress cascade notices
+\set VERBOSITY terse \\ -- suppress cascade details
DROP FOREIGN DATA WRAPPER alt_fdw2 CASCADE;
DROP FOREIGN DATA WRAPPER alt_fdw3 CASCADE;
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index 1648072568..67470db918 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -1083,6 +1083,5 @@ REINDEX SCHEMA schema_to_reindex;
-- Clean up
RESET ROLE;
DROP ROLE regress_reindexuser;
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA schema_to_reindex CASCADE;
-RESET client_min_messages;
diff --git a/src/test/regress/sql/create_view.sql b/src/test/regress/sql/create_view.sql
index 04941671dd..b4e7a8793c 100644
--- a/src/test/regress/sql/create_view.sql
+++ b/src/test/regress/sql/create_view.sql
@@ -581,6 +581,6 @@ select pg_get_ruledef(oid, true) from pg_rewrite
where ev_class = 'tt23v'::regclass and ev_type = '1';
-- clean up all the random objects we made above
-set client_min_messages = warning;
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA temp_view_test CASCADE;
DROP SCHEMA testviewschm2 CASCADE;
diff --git a/src/test/regress/sql/object_address.sql b/src/test/regress/sql/object_address.sql
index ca7ed46e41..63821b8008 100644
--- a/src/test/regress/sql/object_address.sql
+++ b/src/test/regress/sql/object_address.sql
@@ -201,7 +201,7 @@ SELECT (pg_identify_object(addr1.classid, addr1.objid, addr1.objsubid)).*,
---
--- Cleanup resources
---
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP FOREIGN DATA WRAPPER addr_fdw CASCADE;
DROP PUBLICATION addr_pub;
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index fe83709e1b..5bc47bcd13 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -981,9 +981,9 @@ REVOKE ALL ON ALL FUNCTIONS IN SCHEMA testns FROM PUBLIC;
SELECT has_function_privilege('regress_user1', 'testns.testfunc(int)', 'EXECUTE'); -- false
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA testns CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
-- Change owner of the schema & and rename of new schema owner
@@ -1002,9 +1002,9 @@ ALTER ROLE regress_schemauser2 RENAME TO regress_schemauser_renamed;
SELECT nspname, rolname FROM pg_namespace, pg_roles WHERE pg_namespace.nspname = 'testns' AND pg_namespace.nspowner = pg_roles.oid;
set session role regress_schemauser_renamed;
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA testns CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
-- clean up
\c -
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index ba8fed40f5..e03a7ab65f 100644
--- a/src/test/regress/sql/rowsecurity.sql
+++ b/src/test/regress/sql/rowsecurity.sql
@@ -517,11 +517,10 @@ SELECT * FROM rec1; -- fail, mutual recursion via views
-- Mutual recursion via .s.b views
--
SET SESSION AUTHORIZATION regress_rls_bob;
--- Suppress NOTICE messages when doing a cascaded drop.
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP VIEW rec1v, rec2v CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
CREATE VIEW rec1v WITH (security_barrier) AS SELECT * FROM rec1;
CREATE VIEW rec2v WITH (security_barrier) AS SELECT * FROM rec2;
@@ -1026,11 +1025,10 @@ DROP TABLE test_qual_pushdown;
-- Plancache invalidate on user change.
--
RESET SESSION AUTHORIZATION;
--- Suppress NOTICE messages when doing a cascaded drop.
-SET client_min_messages TO 'warning';
+\set VERBOSITY terse \\ -- suppress cascade details
DROP TABLE t1 CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
CREATE TABLE t1 (a integer);
@@ -1762,11 +1760,9 @@ DROP USER regress_rls_dob_role2;
--
RESET SESSION AUTHORIZATION;
--- Suppress NOTICE messages when doing a cascaded drop.
-SET client_min_messages TO 'warning';
-
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA regress_rls_schema CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
DROP USER regress_rls_alice;
DROP USER regress_rls_bob;
diff --git a/src/test/regress/sql/rules.sql b/src/test/regress/sql/rules.sql
index 38751bb881..0ded0f01d2 100644
--- a/src/test/regress/sql/rules.sql
+++ b/src/test/regress/sql/rules.sql
@@ -936,9 +936,9 @@ update id_ordered set name = 'update 4' where id = 4;
update id_ordered set name = 'update 5' where id = 5;
select * from id_ordered;
-set client_min_messages to warning; -- suppress cascade notices
+\set VERBOSITY terse \\ -- suppress cascade details
drop table id cascade;
-reset client_min_messages;
+\set VERBOSITY default
--
-- check corner case where an entirely-dummy subplan is created by
diff --git a/src/test/regress/sql/stats_ext.sql b/src/test/regress/sql/stats_ext.sql
index d1ff3a8583..46acaadb39 100644
--- a/src/test/regress/sql/stats_ext.sql
+++ b/src/test/regress/sql/stats_ext.sql
@@ -89,10 +89,10 @@ EXCEPTION WHEN wrong_object_type THEN
END;
$$;
-SET client_min_messages TO warning;
+\set VERBOSITY terse \\ -- suppress cascade details
DROP SCHEMA tststats CASCADE;
DROP FOREIGN DATA WRAPPER extstats_dummy_fdw CASCADE;
-RESET client_min_messages;
+\set VERBOSITY default
-- n-distinct tests
CREATE TABLE ndistinct (
diff --git a/src/test/regress/sql/typed_table.sql b/src/test/regress/sql/typed_table.sql
index 1cdceef363..9ef0cdfcc7 100644
--- a/src/test/regress/sql/typed_table.sql
+++ b/src/test/regress/sql/typed_table.sql
@@ -1,10 +1,3 @@
--- Clean up in case a prior regression run failed
-SET client_min_messages TO 'warning';
-
-DROP TYPE IF EXISTS person_type CASCADE;
-
-RESET client_min_messages;
-
CREATE TABLE ttable1 OF nothing;
CREATE TYPE person_type AS (id int, name text);
--
cgit v1.2.3
From 514f6132935d5bda84a475d4b70fe2bcfe116766 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 1 Aug 2017 17:17:20 -0400
Subject: Second try at getting useful errors out of newlocale/_create_locale.
The early buildfarm returns for commit 1e165d05f are pretty awful:
not only does Windows not return a useful error, but it looks like
a lot of Unix-ish platforms don't either. Given the number of
different errnos seen so far, guess that what's really going on is
that some newlocale() implementations fail to set errno at all.
Hence, let's try zeroing errno just before newlocale() and then
if it's still zero report as though it's ENOENT. That should cover
the Windows case too.
It's clear that we'll have to drop the regression test case, unless
we want to maintain a separate expected-file for platforms without
HAVE_LOCALE_T. But I'll leave it there awhile longer to see if this
actually improves matters or not.
Discussion: https://postgr.es/m/CAKKotZS-wcDcofXDCH=sidiuajE+nqHn2CGjLLX78anyDmi3gQ@mail.gmail.com
---
src/backend/utils/adt/pg_locale.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/backend/utils/adt/pg_locale.c b/src/backend/utils/adt/pg_locale.c
index 9500c6b39f..13e7625b20 100644
--- a/src/backend/utils/adt/pg_locale.c
+++ b/src/backend/utils/adt/pg_locale.c
@@ -1229,10 +1229,15 @@ report_newlocale_failure(const char *localename)
{
int save_errno;
- /* On Windows, transform _create_locale() error to errno */
-#ifdef WIN32
- _dosmaperr(GetLastError());
-#endif
+ /*
+ * Windows doesn't provide any useful error indication from
+ * _create_locale(), and BSD-derived platforms don't seem to feel they
+ * need to set errno either (even though POSIX is pretty clear that
+ * newlocale should do so). So, if errno hasn't been set, assume ENOENT
+ * is what to report.
+ */
+ if (errno == 0)
+ errno = ENOENT;
/*
* ENOENT means "no such locale", not "no such file", so clarify that
@@ -1311,6 +1316,7 @@ pg_newlocale_from_collation(Oid collid)
if (strcmp(collcollate, collctype) == 0)
{
/* Normal case where they're the same */
+ errno = 0;
#ifndef WIN32
loc = newlocale(LC_COLLATE_MASK | LC_CTYPE_MASK, collcollate,
NULL);
@@ -1326,9 +1332,11 @@ pg_newlocale_from_collation(Oid collid)
/* We need two newlocale() steps */
locale_t loc1;
+ errno = 0;
loc1 = newlocale(LC_COLLATE_MASK, collcollate, NULL);
if (!loc1)
report_newlocale_failure(collcollate);
+ errno = 0;
loc = newlocale(LC_CTYPE_MASK, collctype, loc1);
if (!loc)
report_newlocale_failure(collctype);
--
cgit v1.2.3
From 32ca22b02da9d8088b58b3dc64ad78464c7513a3 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Tue, 1 Aug 2017 20:15:10 -0400
Subject: Revert test case added by commit
1e165d05fe06a9072867607886f818bc255507db.
The buildfarm is still showing at least three distinct behaviors for
a bad locale name in CREATE COLLATION. Although this test was helpful
for getting the error reporting code into some usable shape, it doesn't
seem worth carrying multiple expected-files in order to support the
test in perpetuity. So pull it back out.
Discussion: https://postgr.es/m/CAKKotZS-wcDcofXDCH=sidiuajE+nqHn2CGjLLX78anyDmi3gQ@mail.gmail.com
---
src/test/regress/expected/collate.out | 3 ---
src/test/regress/sql/collate.sql | 1 -
2 files changed, 4 deletions(-)
(limited to 'src')
diff --git a/src/test/regress/expected/collate.out b/src/test/regress/expected/collate.out
index 70866df000..b0025c0a87 100644
--- a/src/test/regress/expected/collate.out
+++ b/src/test/regress/expected/collate.out
@@ -627,9 +627,6 @@ CREATE COLLATION mycoll1 FROM "C";
CREATE COLLATION mycoll2 ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
CREATE COLLATION mycoll3 FROM "default"; -- intentionally unsupported
ERROR: collation "default" cannot be copied
-CREATE COLLATION mycoll4 ( LOCALE = "no_such_locale" ); -- fail
-ERROR: could not create locale "no_such_locale": No such file or directory
-DETAIL: The operating system could not find any locale data for the locale name "no_such_locale".
DROP COLLATION mycoll1;
CREATE TABLE collate_test23 (f1 text collate mycoll2);
DROP COLLATION mycoll2; -- fail
diff --git a/src/test/regress/sql/collate.sql b/src/test/regress/sql/collate.sql
index f095ae08be..698f577490 100644
--- a/src/test/regress/sql/collate.sql
+++ b/src/test/regress/sql/collate.sql
@@ -234,7 +234,6 @@ EXPLAIN (COSTS OFF)
CREATE COLLATION mycoll1 FROM "C";
CREATE COLLATION mycoll2 ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" );
CREATE COLLATION mycoll3 FROM "default"; -- intentionally unsupported
-CREATE COLLATION mycoll4 ( LOCALE = "no_such_locale" ); -- fail
DROP COLLATION mycoll1;
CREATE TABLE collate_test23 (f1 text collate mycoll2);
--
cgit v1.2.3
From 41cefbb6db58c574e086efef2773a978f108d717 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Wed, 2 Aug 2017 10:40:32 -0400
Subject: Fix OBJECT_TYPE/OBJECT_DOMAIN confusion
This doesn't have a significant impact except that now SECURITY LABEL ON
DOMAIN rejects types that are not domains.
Reported-by: 高增琦
---
src/backend/parser/gram.y | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 4b1ce09c44..62092ff7ec 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6507,7 +6507,7 @@ SecLabelStmt:
{
SecLabelStmt *n = makeNode(SecLabelStmt);
n->provider = $3;
- n->objtype = OBJECT_TYPE;
+ n->objtype = OBJECT_DOMAIN;
n->object = (Node *) $6;
n->label = $8;
$$ = (Node *) n;
--
cgit v1.2.3
From f352f91cbf2f662c4f043d3650010b02da0cde1c Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Wed, 2 Aug 2017 11:28:46 -0400
Subject: Remove duplicate setting of SSL_OP_SINGLE_DH_USE option.
Commit c0a15e07c moved the setting of OpenSSL's SSL_OP_SINGLE_DH_USE option
into a new subroutine initialize_dh(), but forgot to remove it from where
it was. SSL_CTX_set_options() is a trivial function, amounting indeed to
just "ctx->options |= op", hence there's no reason to contort the code or
break separation of concerns to avoid calling it twice. So separating the
DH setup from disabling of old protocol versions is a good change, but we
need to finish the job.
Noted while poking into the question of SSL session tickets.
---
src/backend/libpq/be-secure-openssl.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index dc307c101f..694f76afa6 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -286,9 +286,7 @@ be_tls_init(bool isServerStart)
}
/* disallow SSL v2/v3 */
- SSL_CTX_set_options(context,
- SSL_OP_SINGLE_DH_USE |
- SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
/* set up ephemeral DH and ECDH keys */
if (!initialize_dh(context, isServerStart))
--
cgit v1.2.3
From cf652018332819716b10c9de9ce80c81284d6815 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Wed, 2 Aug 2017 10:59:01 -0400
Subject: Get a snapshot before COPY in table sync
This fixes a crash if the local table has a function index and the
function makes non-immutable calls.
Reported-by: Scott Milliken
Author: Masahiko Sawada
---
src/backend/replication/logical/tablesync.c | 2 ++
1 file changed, 2 insertions(+)
(limited to 'src')
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index 32abf5b368..4cca0f1a85 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -917,7 +917,9 @@ LogicalRepSyncTableStart(XLogRecPtr *origin_startpos)
walrcv_create_slot(wrconn, slotname, true,
CRS_USE_SNAPSHOT, origin_startpos);
+ PushActiveSnapshot(GetTransactionSnapshot());
copy_table(rel);
+ PopActiveSnapshot();
res = walrcv_exec(wrconn, "COMMIT", 0, NULL);
if (res->status != WALRCV_OK_COMMAND)
--
cgit v1.2.3
From 9d4e56699957b261390c50dcda7f947470017484 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Wed, 2 Aug 2017 12:16:50 -0400
Subject: Remove broken and useless entry-count printing in HASH_DEBUG code.
init_htab(), with #define HASH_DEBUG, prints a bunch of hashtable
parameters. It used to also print nentries, but commit 44ca4022f changed
that to "hash_get_num_entries(hctl)", which is wrong (the parameter should
be "hashp").
Rather than correct the coding, though, let's just remove that field from
the printout. The table must be empty, since we just finished building
it, so expensively calculating the number of entries is rather pointless.
Moreover hash_get_num_entries makes assumptions (about not needing locks)
which we could do without in debugging code.
Noted by Choi Doo-Won in bug #14764. Back-patch to 9.6 where the
faulty code was introduced.
Discussion: https://postgr.es/m/20170802032353.8424.12274@wrigleys.postgresql.org
---
src/backend/utils/hash/dynahash.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index a58a479ae5..6f6b03c815 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -703,7 +703,7 @@ init_htab(HTAB *hashp, long nelem)
hctl->nelem_alloc = choose_nelem_alloc(hctl->entrysize);
#if HASH_DEBUG
- fprintf(stderr, "init_htab:\n%s%p\n%s%ld\n%s%ld\n%s%d\n%s%ld\n%s%u\n%s%x\n%s%x\n%s%ld\n%s%ld\n",
+ fprintf(stderr, "init_htab:\n%s%p\n%s%ld\n%s%ld\n%s%d\n%s%ld\n%s%u\n%s%x\n%s%x\n%s%ld\n",
"TABLE POINTER ", hashp,
"DIRECTORY SIZE ", hctl->dsize,
"SEGMENT SIZE ", hctl->ssize,
@@ -712,8 +712,7 @@ init_htab(HTAB *hashp, long nelem)
"MAX BUCKET ", hctl->max_bucket,
"HIGH MASK ", hctl->high_mask,
"LOW MASK ", hctl->low_mask,
- "NSEGS ", hctl->nsegs,
- "NENTRIES ", hash_get_num_entries(hctl));
+ "NSEGS ", hctl->nsegs);
#endif
return true;
}
--
cgit v1.2.3
From 4d57e83816778c6f61ea35c697f937a6f9c3c3de Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Wed, 2 Aug 2017 18:26:26 -0400
Subject: Fix pg_dump's errno checking for zlib I/O
Some error reports were reporting strerror(errno), which for some error
conditions coming from zlib are wrong, resulting in confusing reports
such as
pg_restore: [compress_io] could not read from input file: Success
which makes no sense. To correctly extract the error message we need to
use gzerror(), so let's do that.
This isn't as comprehensive or as neat as I would like, but at least it
should improve things in many common cases. The zlib abstraction in
compress_io does not seem to be applied consistently enough; we could
perhaps improve that, but it seems master-only material, not a bug fix
for back-patching.
This problem goes back all the way, but I decided to apply back to 9.4
only, because older branches don't contain commit 14ea89366 which this
change depends on.
Authors: Vladimir Kunschikov, Álvaro Herrera
Discussion: https://postgr.es/m/1498120508308.9826@infotecs.ru
---
src/bin/pg_dump/compress_io.c | 24 +++++++++++++++++++++++-
src/bin/pg_dump/compress_io.h | 1 +
src/bin/pg_dump/pg_backup_directory.c | 10 +++++++---
src/bin/pg_dump/pg_backup_tar.c | 8 +++++++-
4 files changed, 38 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_dump/compress_io.c b/src/bin/pg_dump/compress_io.c
index 991fe11e8a..e94f7d3274 100644
--- a/src/bin/pg_dump/compress_io.c
+++ b/src/bin/pg_dump/compress_io.c
@@ -592,8 +592,14 @@ cfread(void *ptr, int size, cfp *fp)
{
ret = gzread(fp->compressedfp, ptr, size);
if (ret != size && !gzeof(fp->compressedfp))
+ {
+ int errnum;
+ const char *errmsg = gzerror(fp->compressedfp, &errnum);
+
exit_horribly(modulename,
- "could not read from input file: %s\n", strerror(errno));
+ "could not read from input file: %s\n",
+ errnum == Z_ERRNO ? strerror(errno) : errmsg);
+ }
}
else
#endif
@@ -695,6 +701,22 @@ cfeof(cfp *fp)
return feof(fp->uncompressedfp);
}
+const char *
+get_cfp_error(cfp *fp)
+{
+#ifdef HAVE_LIBZ
+ if (fp->compressedfp)
+ {
+ int errnum;
+ const char *errmsg = gzerror(fp->compressedfp, &errnum);
+
+ if (errnum != Z_ERRNO)
+ return errmsg;
+ }
+#endif
+ return strerror(errno);
+}
+
#ifdef HAVE_LIBZ
static int
hasSuffix(const char *filename, const char *suffix)
diff --git a/src/bin/pg_dump/compress_io.h b/src/bin/pg_dump/compress_io.h
index 8f2e752cba..f42eb84007 100644
--- a/src/bin/pg_dump/compress_io.h
+++ b/src/bin/pg_dump/compress_io.h
@@ -65,5 +65,6 @@ extern int cfgetc(cfp *fp);
extern char *cfgets(cfp *fp, char *buf, int len);
extern int cfclose(cfp *fp);
extern int cfeof(cfp *fp);
+extern const char *get_cfp_error(cfp *fp);
#endif
diff --git a/src/bin/pg_dump/pg_backup_directory.c b/src/bin/pg_dump/pg_backup_directory.c
index 79922da8ba..112fbb0f0c 100644
--- a/src/bin/pg_dump/pg_backup_directory.c
+++ b/src/bin/pg_dump/pg_backup_directory.c
@@ -352,7 +352,9 @@ _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
lclContext *ctx = (lclContext *) AH->formatData;
if (dLen > 0 && cfwrite(data, dLen, ctx->dataFH) != dLen)
- WRITE_ERROR_EXIT;
+ exit_horribly(modulename, "could not write to output file: %s\n",
+ get_cfp_error(ctx->dataFH));
+
return;
}
@@ -490,7 +492,8 @@ _WriteByte(ArchiveHandle *AH, const int i)
lclContext *ctx = (lclContext *) AH->formatData;
if (cfwrite(&c, 1, ctx->dataFH) != 1)
- WRITE_ERROR_EXIT;
+ exit_horribly(modulename, "could not write to output file: %s\n",
+ get_cfp_error(ctx->dataFH));
return 1;
}
@@ -519,7 +522,8 @@ _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
lclContext *ctx = (lclContext *) AH->formatData;
if (cfwrite(buf, len, ctx->dataFH) != len)
- WRITE_ERROR_EXIT;
+ exit_horribly(modulename, "could not write to output file: %s\n",
+ get_cfp_error(ctx->dataFH));
return;
}
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index f839712945..3c41d40a93 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -555,8 +555,14 @@ _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
{
res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
if (res != len && !GZEOF(th->zFH))
+ {
+ int errnum;
+ const char *errmsg = gzerror(th->zFH, &errnum);
+
exit_horribly(modulename,
- "could not read from input file: %s\n", strerror(errno));
+ "could not read from input file: %s\n",
+ errnum == Z_ERRNO ? strerror(errno) : errmsg);
+ }
}
else
{
--
cgit v1.2.3
From 5ff3d73813ebcc3ff80be77c30b458d728951036 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Wed, 2 Aug 2017 22:44:46 -0400
Subject: Add new files to nls.mk and add translation markers
---
src/bin/pg_basebackup/nls.mk | 4 ++--
src/bin/pg_basebackup/walmethods.c | 2 +-
src/interfaces/libpq/nls.mk | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_basebackup/nls.mk b/src/bin/pg_basebackup/nls.mk
index 2a6de08a64..d5f87e8438 100644
--- a/src/bin/pg_basebackup/nls.mk
+++ b/src/bin/pg_basebackup/nls.mk
@@ -1,5 +1,5 @@
# src/bin/pg_basebackup/nls.mk
CATALOG_NAME = pg_basebackup
AVAIL_LANGUAGES = de es fr it ko pl pt_BR ru zh_CN
-GETTEXT_FILES = pg_basebackup.c pg_receivewal.c pg_recvlogical.c receivelog.c streamutil.c ../../common/fe_memutils.c ../../common/file_utils.c
-GETTEXT_TRIGGERS = simple_prompt
+GETTEXT_FILES = pg_basebackup.c pg_receivewal.c pg_recvlogical.c receivelog.c streamutil.c walmethods.c ../../common/fe_memutils.c ../../common/file_utils.c
+GETTEXT_TRIGGERS = simple_prompt tar_set_error
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 06d8ab5bc2..2ab5ae93e0 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -404,7 +404,7 @@ typedef struct TarMethodData
static TarMethodData *tar_data = NULL;
#define tar_clear_error() tar_data->lasterror[0] = '\0'
-#define tar_set_error(msg) strlcpy(tar_data->lasterror, msg, sizeof(tar_data->lasterror))
+#define tar_set_error(msg) strlcpy(tar_data->lasterror, _(msg), sizeof(tar_data->lasterror))
static const char *
tar_getlasterror(void)
diff --git a/src/interfaces/libpq/nls.mk b/src/interfaces/libpq/nls.mk
index 1e2a7a872c..1329b37bcc 100644
--- a/src/interfaces/libpq/nls.mk
+++ b/src/interfaces/libpq/nls.mk
@@ -1,6 +1,6 @@
# src/interfaces/libpq/nls.mk
CATALOG_NAME = libpq
AVAIL_LANGUAGES = cs de es fr it ja ko pl pt_BR ru tr zh_CN zh_TW
-GETTEXT_FILES = fe-auth.c fe-connect.c fe-exec.c fe-lobj.c fe-misc.c fe-protocol2.c fe-protocol3.c fe-secure.c fe-secure-openssl.c win32.c
+GETTEXT_FILES = fe-auth.c fe-auth-scram.c fe-connect.c fe-exec.c fe-lobj.c fe-misc.c fe-protocol2.c fe-protocol3.c fe-secure.c fe-secure-openssl.c win32.c
GETTEXT_TRIGGERS = libpq_gettext pqInternalNotice:2
GETTEXT_FLAGS = libpq_gettext:1:pass-c-format pqInternalNotice:2:c-format
--
cgit v1.2.3
From 610e8ebb0fadd7a738c2ad07fef6c5ea86b11f8d Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Thu, 3 Aug 2017 11:21:29 -0400
Subject: Teach map_partition_varattnos to handle whole-row expressions.
Otherwise, partitioned tables with RETURNING expressions or subject
to a WITH CHECK OPTION do not work properly.
Amit Langote, reviewed by Amit Khandekar and Etsuro Fujita. A few
comment changes by me.
Discussion: http://postgr.es/m/9a39df80-871e-6212-0684-f93c83be4097@lab.ntt.co.jp
---
src/backend/catalog/partition.c | 21 ++++++++----
src/backend/commands/tablecmds.c | 12 +++++--
src/backend/executor/nodeModifyTable.c | 4 +--
src/backend/parser/parse_utilcmd.c | 6 ++--
src/backend/rewrite/rewriteManip.c | 47 ++++++++++++++++++++++-----
src/include/catalog/partition.h | 3 +-
src/include/rewrite/rewriteManip.h | 2 +-
src/test/regress/expected/insert.out | 21 ++++++++++++
src/test/regress/expected/updatable_views.out | 26 +++++++++++++++
src/test/regress/sql/insert.sql | 13 ++++++++
src/test/regress/sql/updatable_views.sql | 27 +++++++++++++++
11 files changed, 157 insertions(+), 25 deletions(-)
(limited to 'src')
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 9d50efb6a0..dcc7f8af27 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -898,16 +898,20 @@ get_qual_from_partbound(Relation rel, Relation parent,
* We must allow for cases where physical attnos of a partition can be
* different from the parent's.
*
+ * If found_whole_row is not NULL, *found_whole_row returns whether a
+ * whole-row variable was found in the input expression.
+ *
* Note: this will work on any node tree, so really the argument and result
* should be declared "Node *". But a substantial majority of the callers
* are working on Lists, so it's less messy to do the casts internally.
*/
List *
map_partition_varattnos(List *expr, int target_varno,
- Relation partrel, Relation parent)
+ Relation partrel, Relation parent,
+ bool *found_whole_row)
{
AttrNumber *part_attnos;
- bool found_whole_row;
+ bool my_found_whole_row;
if (expr == NIL)
return NIL;
@@ -919,10 +923,10 @@ map_partition_varattnos(List *expr, int target_varno,
target_varno, 0,
part_attnos,
RelationGetDescr(parent)->natts,
- &found_whole_row);
- /* There can never be a whole-row reference here */
+ RelationGetForm(partrel)->reltype,
+ &my_found_whole_row);
if (found_whole_row)
- elog(ERROR, "unexpected whole-row reference found in partition key");
+ *found_whole_row = my_found_whole_row;
return expr;
}
@@ -1783,6 +1787,7 @@ generate_partition_qual(Relation rel)
List *my_qual = NIL,
*result = NIL;
Relation parent;
+ bool found_whole_row;
/* Guard against stack overflow due to overly deep partition tree */
check_stack_depth();
@@ -1825,7 +1830,11 @@ generate_partition_qual(Relation rel)
* in it to bear this relation's attnos. It's safe to assume varno = 1
* here.
*/
- result = map_partition_varattnos(result, 1, rel, parent);
+ result = map_partition_varattnos(result, 1, rel, parent,
+ &found_whole_row);
+ /* There can never be a whole-row reference here */
+ if (found_whole_row)
+ elog(ERROR, "unexpected whole-row reference found in partition key");
/* Save a copy in the relcache */
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index bb00858ad1..b58c92d846 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1989,7 +1989,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
expr = map_variable_attnos(stringToNode(check[i].ccbin),
1, 0,
newattno, tupleDesc->natts,
- &found_whole_row);
+ InvalidOid, &found_whole_row);
/*
* For the moment we have to reject whole-row variables. We
@@ -8874,7 +8874,7 @@ ATPrepAlterColumnType(List **wqueue,
map_variable_attnos(def->cooked_default,
1, 0,
attmap, RelationGetDescr(rel)->natts,
- &found_whole_row);
+ InvalidOid, &found_whole_row);
if (found_whole_row)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -13713,6 +13713,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
Oid part_relid = lfirst_oid(lc);
Relation part_rel;
Expr *constr;
+ bool found_whole_row;
/* Lock already taken */
if (part_relid != RelationGetRelid(attachRel))
@@ -13738,7 +13739,12 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
constr = linitial(partConstraint);
tab->partition_constraint = (Expr *)
map_partition_varattnos((List *) constr, 1,
- part_rel, rel);
+ part_rel, rel,
+ &found_whole_row);
+ /* There can never be a whole-row reference here */
+ if (found_whole_row)
+ elog(ERROR, "unexpected whole-row reference found in partition key");
+
/* keep our lock until commit */
if (part_rel != attachRel)
heap_close(part_rel, NoLock);
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 0dde0ed6eb..435aed3b8b 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1996,7 +1996,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
mapped_wcoList = map_partition_varattnos(wcoList,
node->nominalRelation,
- partrel, rel);
+ partrel, rel, NULL);
foreach(ll, mapped_wcoList)
{
WithCheckOption *wco = castNode(WithCheckOption, lfirst(ll));
@@ -2069,7 +2069,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/* varno = node->nominalRelation */
rlist = map_partition_varattnos(returningList,
node->nominalRelation,
- partrel, rel);
+ partrel, rel, NULL);
resultRelInfo->ri_projectReturning =
ExecBuildProjectionInfo(rlist, econtext, slot, &mtstate->ps,
resultRelInfo->ri_RelationDesc->rd_att);
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 9f37f1b920..a86c2341f5 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1107,7 +1107,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
ccbin_node = map_variable_attnos(stringToNode(ccbin),
1, 0,
attmap, tupleDesc->natts,
- &found_whole_row);
+ InvalidOid, &found_whole_row);
/*
* We reject whole-row variables because the whole point of LIKE
@@ -1463,7 +1463,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
indexkey = map_variable_attnos(indexkey,
1, 0,
attmap, attmap_length,
- &found_whole_row);
+ InvalidOid, &found_whole_row);
/* As in transformTableLikeClause, reject whole-row variables */
if (found_whole_row)
@@ -1539,7 +1539,7 @@ generateClonedIndexStmt(CreateStmtContext *cxt, Relation source_idx,
pred_tree = map_variable_attnos(pred_tree,
1, 0,
attmap, attmap_length,
- &found_whole_row);
+ InvalidOid, &found_whole_row);
/* As in transformTableLikeClause, reject whole-row variables */
if (found_whole_row)
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index b89b435da0..ba706b25b4 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1203,14 +1203,12 @@ replace_rte_variables_mutator(Node *node,
* appear in the expression.
*
* If the expression tree contains a whole-row Var for the target RTE,
- * the Var is not changed but *found_whole_row is returned as TRUE.
- * For most callers this is an error condition, but we leave it to the caller
- * to report the error so that useful context can be provided. (In some
- * usages it would be appropriate to modify the Var's vartype and insert a
- * ConvertRowtypeExpr node to map back to the original vartype. We might
- * someday extend this function's API to support that. For now, the only
- * concession to that future need is that this function is a tree mutator
- * not just a walker.)
+ * *found_whole_row is returned as TRUE. In addition, if to_rowtype is
+ * not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
+ * to map back to the orignal rowtype. Callers that don't provide to_rowtype
+ * should report an error if *found_row_type is true; we don't do that here
+ * because we don't know exactly what wording for the error message would
+ * be most appropriate. The caller will be aware of the context.
*
* This could be built using replace_rte_variables and a callback function,
* but since we don't ever need to insert sublinks, replace_rte_variables is
@@ -1223,6 +1221,8 @@ typedef struct
int sublevels_up; /* (current) nesting depth */
const AttrNumber *attno_map; /* map array for user attnos */
int map_length; /* number of entries in attno_map[] */
+ /* Target type when converting whole-row vars */
+ Oid to_rowtype;
bool *found_whole_row; /* output flag */
} map_variable_attnos_context;
@@ -1257,6 +1257,34 @@ map_variable_attnos_mutator(Node *node,
{
/* whole-row variable, warn caller */
*(context->found_whole_row) = true;
+
+ /* If the callers expects us to convert the same, do so. */
+ if (OidIsValid(context->to_rowtype))
+ {
+ /* No support for RECORDOID. */
+ Assert(var->vartype != RECORDOID);
+
+ /* Don't convert unless necessary. */
+ if (context->to_rowtype != var->vartype)
+ {
+ ConvertRowtypeExpr *r;
+
+ /* Var itself is converted to the requested type. */
+ newvar->vartype = context->to_rowtype;
+
+ /*
+ * And a conversion node on top to convert back to the
+ * original type.
+ */
+ r = makeNode(ConvertRowtypeExpr);
+ r->arg = (Expr *) newvar;
+ r->resulttype = var->vartype;
+ r->convertformat = COERCE_IMPLICIT_CAST;
+ r->location = -1;
+
+ return (Node *) r;
+ }
+ }
}
return (Node *) newvar;
}
@@ -1283,7 +1311,7 @@ Node *
map_variable_attnos(Node *node,
int target_varno, int sublevels_up,
const AttrNumber *attno_map, int map_length,
- bool *found_whole_row)
+ Oid to_rowtype, bool *found_whole_row)
{
map_variable_attnos_context context;
@@ -1291,6 +1319,7 @@ map_variable_attnos(Node *node,
context.sublevels_up = sublevels_up;
context.attno_map = attno_map;
context.map_length = map_length;
+ context.to_rowtype = to_rowtype;
context.found_whole_row = found_whole_row;
*found_whole_row = false;
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index f10879a162..434ded37d7 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -80,7 +80,8 @@ extern Oid get_partition_parent(Oid relid);
extern List *get_qual_from_partbound(Relation rel, Relation parent,
PartitionBoundSpec *spec);
extern List *map_partition_varattnos(List *expr, int target_varno,
- Relation partrel, Relation parent);
+ Relation partrel, Relation parent,
+ bool *found_whole_row);
extern List *RelationGetPartitionQual(Relation rel);
extern Expr *get_partition_qual_relid(Oid relid);
diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h
index 282ff9967f..f0a7a8b2cd 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -72,7 +72,7 @@ extern Node *replace_rte_variables_mutator(Node *node,
extern Node *map_variable_attnos(Node *node,
int target_varno, int sublevels_up,
const AttrNumber *attno_map, int map_length,
- bool *found_whole_row);
+ Oid to_rowtype, bool *found_whole_row);
extern Node *ReplaceVarsFromTargetList(Node *node,
int target_varno, int sublevels_up,
diff --git a/src/test/regress/expected/insert.out b/src/test/regress/expected/insert.out
index 0dcc86fef4..a2d9469592 100644
--- a/src/test/regress/expected/insert.out
+++ b/src/test/regress/expected/insert.out
@@ -659,3 +659,24 @@ select tableoid::regclass, * from mcrparted order by a, b;
(11 rows)
drop table mcrparted;
+-- check that wholerow vars in the RETURNING list work with partitioned tables
+create table returningwrtest (a int) partition by list (a);
+create table returningwrtest1 partition of returningwrtest for values in (1);
+insert into returningwrtest values (1) returning returningwrtest;
+ returningwrtest
+-----------------
+ (1)
+(1 row)
+
+-- check also that the wholerow vars in RETURNING list are converted as needed
+alter table returningwrtest add b text;
+create table returningwrtest2 (b text, c int, a int);
+alter table returningwrtest2 drop c;
+alter table returningwrtest attach partition returningwrtest2 for values in (2);
+insert into returningwrtest values (2, 'foo') returning returningwrtest;
+ returningwrtest
+-----------------
+ (2,foo)
+(1 row)
+
+drop table returningwrtest;
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index eab5c0334c..2090a411fe 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -2428,3 +2428,29 @@ ERROR: new row violates check option for view "ptv_wco"
DETAIL: Failing row contains (1, 2, null).
drop view ptv, ptv_wco;
drop table pt, pt1, pt11;
+-- check that wholerow vars appearing in WITH CHECK OPTION constraint expressions
+-- work fine with partitioned tables
+create table wcowrtest (a int) partition by list (a);
+create table wcowrtest1 partition of wcowrtest for values in (1);
+create view wcowrtest_v as select * from wcowrtest where wcowrtest = '(2)'::wcowrtest with check option;
+insert into wcowrtest_v values (1);
+ERROR: new row violates check option for view "wcowrtest_v"
+DETAIL: Failing row contains (1).
+alter table wcowrtest add b text;
+create table wcowrtest2 (b text, c int, a int);
+alter table wcowrtest2 drop c;
+alter table wcowrtest attach partition wcowrtest2 for values in (2);
+create table sometable (a int, b text);
+insert into sometable values (1, 'a'), (2, 'b');
+create view wcowrtest_v2 as
+ select *
+ from wcowrtest r
+ where r in (select s from sometable s where r.a = s.a)
+with check option;
+-- WITH CHECK qual will be processed with wcowrtest2's
+-- rowtype after tuple-routing
+insert into wcowrtest_v2 values (2, 'no such row in sometable');
+ERROR: new row violates check option for view "wcowrtest_v2"
+DETAIL: Failing row contains (2, no such row in sometable).
+drop view wcowrtest_v, wcowrtest_v2;
+drop table wcowrtest, sometable;
diff --git a/src/test/regress/sql/insert.sql b/src/test/regress/sql/insert.sql
index 6adf25da40..6f17872087 100644
--- a/src/test/regress/sql/insert.sql
+++ b/src/test/regress/sql/insert.sql
@@ -399,3 +399,16 @@ insert into mcrparted values ('aaa', 0), ('b', 0), ('bz', 10), ('c', -10),
('commons', 0), ('d', -10), ('e', 0);
select tableoid::regclass, * from mcrparted order by a, b;
drop table mcrparted;
+
+-- check that wholerow vars in the RETURNING list work with partitioned tables
+create table returningwrtest (a int) partition by list (a);
+create table returningwrtest1 partition of returningwrtest for values in (1);
+insert into returningwrtest values (1) returning returningwrtest;
+
+-- check also that the wholerow vars in RETURNING list are converted as needed
+alter table returningwrtest add b text;
+create table returningwrtest2 (b text, c int, a int);
+alter table returningwrtest2 drop c;
+alter table returningwrtest attach partition returningwrtest2 for values in (2);
+insert into returningwrtest values (2, 'foo') returning returningwrtest;
+drop table returningwrtest;
diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql
index 2ede44c02b..a6ba5aad9e 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -1141,3 +1141,30 @@ create view ptv_wco as select * from pt where a = 0 with check option;
insert into ptv_wco values (1, 2);
drop view ptv, ptv_wco;
drop table pt, pt1, pt11;
+
+-- check that wholerow vars appearing in WITH CHECK OPTION constraint expressions
+-- work fine with partitioned tables
+create table wcowrtest (a int) partition by list (a);
+create table wcowrtest1 partition of wcowrtest for values in (1);
+create view wcowrtest_v as select * from wcowrtest where wcowrtest = '(2)'::wcowrtest with check option;
+insert into wcowrtest_v values (1);
+
+alter table wcowrtest add b text;
+create table wcowrtest2 (b text, c int, a int);
+alter table wcowrtest2 drop c;
+alter table wcowrtest attach partition wcowrtest2 for values in (2);
+
+create table sometable (a int, b text);
+insert into sometable values (1, 'a'), (2, 'b');
+create view wcowrtest_v2 as
+ select *
+ from wcowrtest r
+ where r in (select s from sometable s where r.a = s.a)
+with check option;
+
+-- WITH CHECK qual will be processed with wcowrtest2's
+-- rowtype after tuple-routing
+insert into wcowrtest_v2 values (2, 'no such row in sometable');
+
+drop view wcowrtest_v, wcowrtest_v2;
+drop table wcowrtest, sometable;
--
cgit v1.2.3
From 12a34f59bf8bc5babf375c95f5192d208dca1739 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Thu, 3 Aug 2017 12:47:00 -0400
Subject: Improve ExecModifyTable comments.
Some of these comments wrongly implied that only an AFTER ROW trigger
will cause a 'wholerow' attribute to be present for a foreign table,
but a BEFORE ROW trigger can have the same effect. Others implied
that it would always be present for a foreign table, but that's not
true either.
Etsuro Fujita and Robert Haas
Discussion: http://postgr.es/m/10026bc7-1403-ef85-9e43-c6100c1cc0e3@lab.ntt.co.jp
---
src/backend/executor/nodeModifyTable.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 435aed3b8b..30add8e3c7 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1696,7 +1696,7 @@ ExecModifyTable(PlanState *pstate)
* the old relation tuple.
*
* Foreign table updates have a wholerow attribute when the
- * relation has an AFTER ROW trigger. Note that the wholerow
+ * relation has a row-level trigger. Note that the wholerow
* attribute does not carry system columns. Foreign table
* triggers miss seeing those, except that we know enough here
* to set t_tableOid. Quite separately from this, the FDW may
@@ -2182,8 +2182,11 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
/*
* Initialize the junk filter(s) if needed. INSERT queries need a filter
* if there are any junk attrs in the tlist. UPDATE and DELETE always
- * need a filter, since there's always a junk 'ctid' or 'wholerow'
- * attribute present --- no need to look first.
+ * need a filter, since there's always at least one junk attribute present
+ * --- no need to look first. Typically, this will be a 'ctid' or
+ * 'wholerow' attribute, but in the case of a foreign data wrapper it
+ * might be a set of junk attributes sufficient to identify the remote
+ * row.
*
* If there are multiple result relations, each one needs its own junk
* filter. Note multiple rels are only possible for UPDATE/DELETE, so we
@@ -2251,7 +2254,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
else if (relkind == RELKIND_FOREIGN_TABLE)
{
/*
- * When there is an AFTER trigger, there should be a
+ * When there is a row-level trigger, there should be a
* wholerow attribute.
*/
j->jf_junkAttNo = ExecFindJunkAttribute(j, "wholerow");
--
cgit v1.2.3
From 86705aa8c3f3ec78c0b8e66cd8a4b0768e51adeb Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Thu, 3 Aug 2017 13:09:15 -0400
Subject: Allow a foreign table CHECK constraint to be initially NOT VALID.
For a table, the constraint can be considered validated immediately,
because the table must be empty. But for a foreign table this is
not necessarily the case.
Fixes a bug in commit f27a6b15e6566fba7748d0d9a3fc5bcfd52c4a1b.
Amit Langote, with some changes by me.
Discussion: http://postgr.es/m/d2b7419f-4a71-cf86-cc99-bfd0f359a1ea@lab.ntt.co.jp
---
src/backend/parser/parse_utilcmd.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index a86c2341f5..87cb4188a3 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -165,6 +165,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
Oid existing_relid;
ParseCallbackState pcbstate;
bool like_found = false;
+ bool is_foreign_table = IsA(stmt, CreateForeignTableStmt);
/*
* We must not scribble on the passed-in CreateStmt, so copy it. (This is
@@ -330,7 +331,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
/*
* Postprocess check constraints.
*/
- transformCheckConstraints(&cxt, true);
+ transformCheckConstraints(&cxt, !is_foreign_table ? true : false);
/*
* Output results.
@@ -2129,9 +2130,9 @@ transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
return;
/*
- * If creating a new table, we can safely skip validation of check
- * constraints, and nonetheless mark them valid. (This will override any
- * user-supplied NOT VALID flag.)
+ * If creating a new table (but not a foreign table), we can safely skip
+ * validation of check constraints, and nonetheless mark them valid.
+ * (This will override any user-supplied NOT VALID flag.)
*/
if (skipValidation)
{
--
cgit v1.2.3
From 583df3b5c56258df2a03e08e3ef00aabe0cf306d Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Thu, 3 Aug 2017 14:16:33 -0400
Subject: Code beautification for ATExecAttachPartition.
Amit Langote
Discussion: http://postgr.es/m/CAFjFpReT_kq_uwU_B8aWDxR7jNGE=P0iELycdq5oupi=xSQTOw@mail.gmail.com
---
src/backend/commands/tablecmds.c | 125 +++++++++++++++++++--------------------
1 file changed, 61 insertions(+), 64 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b58c92d846..3c42e160b2 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13419,10 +13419,10 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
static ObjectAddress
ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
{
- Relation attachRel,
+ Relation attachrel,
catalog;
- List *childrels;
- TupleConstr *attachRel_constr;
+ List *attachrel_children;
+ TupleConstr *attachrel_constr;
List *partConstraint,
*existConstraint;
SysScanDesc scan;
@@ -13434,22 +13434,22 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
ObjectAddress address;
const char *trigger_name;
- attachRel = heap_openrv(cmd->name, AccessExclusiveLock);
+ attachrel = heap_openrv(cmd->name, AccessExclusiveLock);
/*
* Must be owner of both parent and source table -- parent was checked by
* ATSimplePermissions call in ATPrepCmd
*/
- ATSimplePermissions(attachRel, ATT_TABLE | ATT_FOREIGN_TABLE);
+ ATSimplePermissions(attachrel, ATT_TABLE | ATT_FOREIGN_TABLE);
/* A partition can only have one parent */
- if (attachRel->rd_rel->relispartition)
+ if (attachrel->rd_rel->relispartition)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is already a partition",
- RelationGetRelationName(attachRel))));
+ RelationGetRelationName(attachrel))));
- if (OidIsValid(attachRel->rd_rel->reloftype))
+ if (OidIsValid(attachrel->rd_rel->reloftype))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot attach a typed table as partition")));
@@ -13462,7 +13462,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
ScanKeyInit(&skey,
Anum_pg_inherits_inhrelid,
BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(attachRel)));
+ ObjectIdGetDatum(RelationGetRelid(attachrel)));
scan = systable_beginscan(catalog, InheritsRelidSeqnoIndexId, true,
NULL, 1, &skey);
if (HeapTupleIsValid(systable_getnext(scan)))
@@ -13475,11 +13475,11 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
ScanKeyInit(&skey,
Anum_pg_inherits_inhparent,
BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(attachRel)));
+ ObjectIdGetDatum(RelationGetRelid(attachrel)));
scan = systable_beginscan(catalog, InheritsParentIndexId, true, NULL,
1, &skey);
if (HeapTupleIsValid(systable_getnext(scan)) &&
- attachRel->rd_rel->relkind == RELKIND_RELATION)
+ attachrel->rd_rel->relkind == RELKIND_RELATION)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot attach inheritance parent as partition")));
@@ -13487,22 +13487,22 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
heap_close(catalog, AccessShareLock);
/*
- * Prevent circularity by seeing if rel is a partition of attachRel. (In
+ * Prevent circularity by seeing if rel is a partition of attachrel. (In
* particular, this disallows making a rel a partition of itself.)
*/
- childrels = find_all_inheritors(RelationGetRelid(attachRel),
- AccessShareLock, NULL);
- if (list_member_oid(childrels, RelationGetRelid(rel)))
+ attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
+ AccessShareLock, NULL);
+ if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_TABLE),
errmsg("circular inheritance not allowed"),
errdetail("\"%s\" is already a child of \"%s\".",
RelationGetRelationName(rel),
- RelationGetRelationName(attachRel))));
+ RelationGetRelationName(attachrel))));
/* Temp parent cannot have a partition that is itself not a temp */
if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
- attachRel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
+ attachrel->rd_rel->relpersistence != RELPERSISTENCE_TEMP)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot attach a permanent relation as partition of temporary relation \"%s\"",
@@ -13516,30 +13516,30 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
errmsg("cannot attach as partition of temporary relation of another session")));
/* Ditto for the partition */
- if (attachRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
- !attachRel->rd_islocaltemp)
+ if (attachrel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
+ !attachrel->rd_islocaltemp)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot attach temporary relation of another session as partition")));
/* If parent has OIDs then child must have OIDs */
- if (rel->rd_rel->relhasoids && !attachRel->rd_rel->relhasoids)
+ if (rel->rd_rel->relhasoids && !attachrel->rd_rel->relhasoids)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot attach table \"%s\" without OIDs as partition of"
- " table \"%s\" with OIDs", RelationGetRelationName(attachRel),
+ " table \"%s\" with OIDs", RelationGetRelationName(attachrel),
RelationGetRelationName(rel))));
- /* OTOH, if parent doesn't have them, do not allow in attachRel either */
- if (attachRel->rd_rel->relhasoids && !rel->rd_rel->relhasoids)
+ /* OTOH, if parent doesn't have them, do not allow in attachrel either */
+ if (attachrel->rd_rel->relhasoids && !rel->rd_rel->relhasoids)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot attach table \"%s\" with OIDs as partition of table"
- " \"%s\" without OIDs", RelationGetRelationName(attachRel),
+ " \"%s\" without OIDs", RelationGetRelationName(attachrel),
RelationGetRelationName(rel))));
- /* Check if there are any columns in attachRel that aren't in the parent */
- tupleDesc = RelationGetDescr(attachRel);
+ /* Check if there are any columns in attachrel that aren't in the parent */
+ tupleDesc = RelationGetDescr(attachrel);
natts = tupleDesc->natts;
for (attno = 1; attno <= natts; attno++)
{
@@ -13557,7 +13557,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("table \"%s\" contains column \"%s\" not found in parent \"%s\"",
- RelationGetRelationName(attachRel), attributeName,
+ RelationGetRelationName(attachrel), attributeName,
RelationGetRelationName(rel)),
errdetail("New partition should contain only the columns present in parent.")));
}
@@ -13567,34 +13567,34 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
* currently don't allow it to become a partition. See also prohibitions
* in ATExecAddInherit() and CreateTrigger().
*/
- trigger_name = FindTriggerIncompatibleWithInheritance(attachRel->trigdesc);
+ trigger_name = FindTriggerIncompatibleWithInheritance(attachrel->trigdesc);
if (trigger_name != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("trigger \"%s\" prevents table \"%s\" from becoming a partition",
- trigger_name, RelationGetRelationName(attachRel)),
+ trigger_name, RelationGetRelationName(attachrel)),
errdetail("ROW triggers with transition tables are not supported on partitions")));
/* OK to create inheritance. Rest of the checks performed there */
- CreateInheritance(attachRel, rel);
+ CreateInheritance(attachrel, rel);
/*
* Check that the new partition's bound is valid and does not overlap any
* of existing partitions of the parent - note that it does not return on
* error.
*/
- check_new_partition_bound(RelationGetRelationName(attachRel), rel,
+ check_new_partition_bound(RelationGetRelationName(attachrel), rel,
cmd->bound);
/* Update the pg_class entry. */
- StorePartitionBound(attachRel, rel, cmd->bound);
+ StorePartitionBound(attachrel, rel, cmd->bound);
/*
* Generate partition constraint from the partition bound specification.
* If the parent itself is a partition, make sure to include its
* constraint as well.
*/
- partConstraint = list_concat(get_qual_from_partbound(attachRel, rel,
+ partConstraint = list_concat(get_qual_from_partbound(attachrel, rel,
cmd->bound),
RelationGetPartitionQual(rel));
partConstraint = (List *) eval_const_expressions(NULL,
@@ -13612,20 +13612,20 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
* There is a case in which we cannot rely on just the result of the
* proof.
*/
- attachRel_constr = tupleDesc->constr;
+ attachrel_constr = tupleDesc->constr;
existConstraint = NIL;
- if (attachRel_constr != NULL)
+ if (attachrel_constr != NULL)
{
- int num_check = attachRel_constr->num_check;
+ int num_check = attachrel_constr->num_check;
int i;
- if (attachRel_constr->has_not_null)
+ if (attachrel_constr->has_not_null)
{
- int natts = attachRel->rd_att->natts;
+ int natts = attachrel->rd_att->natts;
for (i = 1; i <= natts; i++)
{
- Form_pg_attribute att = attachRel->rd_att->attrs[i - 1];
+ Form_pg_attribute att = attachrel->rd_att->attrs[i - 1];
if (att->attnotnull && !att->attisdropped)
{
@@ -13659,10 +13659,10 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
* If this constraint hasn't been fully validated yet, we must
* ignore it here.
*/
- if (!attachRel_constr->check[i].ccvalid)
+ if (!attachrel_constr->check[i].ccvalid)
continue;
- cexpr = stringToNode(attachRel_constr->check[i].ccbin);
+ cexpr = stringToNode(attachrel_constr->check[i].ccbin);
/*
* Run each expression through const-simplification and
@@ -13684,28 +13684,25 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
skip_validate = true;
}
- /* It's safe to skip the validation scan after all */
if (skip_validate)
+ {
+ /* No need to scan the table after all. */
ereport(INFO,
(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
- RelationGetRelationName(attachRel))));
-
- /*
- * Set up to have the table be scanned to validate the partition
- * constraint (see partConstraint above). If it's a partitioned table, we
- * instead schedule its leaf partitions to be scanned.
- */
- if (!skip_validate)
+ RelationGetRelationName(attachrel))));
+ }
+ else
{
+ /* Constraints proved insufficient, so we need to scan the table. */
List *all_parts;
ListCell *lc;
/* Take an exclusive lock on the partitions to be checked */
- if (attachRel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- all_parts = find_all_inheritors(RelationGetRelid(attachRel),
+ if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ all_parts = find_all_inheritors(RelationGetRelid(attachrel),
AccessExclusiveLock, NULL);
else
- all_parts = list_make1_oid(RelationGetRelid(attachRel));
+ all_parts = list_make1_oid(RelationGetRelid(attachrel));
foreach(lc, all_parts)
{
@@ -13716,23 +13713,23 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
bool found_whole_row;
/* Lock already taken */
- if (part_relid != RelationGetRelid(attachRel))
+ if (part_relid != RelationGetRelid(attachrel))
part_rel = heap_open(part_relid, NoLock);
else
- part_rel = attachRel;
+ part_rel = attachrel;
/*
- * Skip if it's a partitioned table. Only RELKIND_RELATION
- * relations (ie, leaf partitions) need to be scanned.
+ * Skip if the partition is itself a partitioned table. We can
+ * only ever scan RELKIND_RELATION relations.
*/
- if (part_rel != attachRel &&
- part_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ if (part_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
{
- heap_close(part_rel, NoLock);
+ if (part_rel != attachrel)
+ heap_close(part_rel, NoLock);
continue;
}
- /* Grab a work queue entry */
+ /* Grab a work queue entry. */
tab = ATGetQueueEntry(wqueue, part_rel);
/* Adjust constraint to match this partition */
@@ -13746,15 +13743,15 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
elog(ERROR, "unexpected whole-row reference found in partition key");
/* keep our lock until commit */
- if (part_rel != attachRel)
+ if (part_rel != attachrel)
heap_close(part_rel, NoLock);
}
}
- ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachRel));
+ ObjectAddressSet(address, RelationRelationId, RelationGetRelid(attachrel));
/* keep our lock until commit */
- heap_close(attachRel, NoLock);
+ heap_close(attachrel, NoLock);
return address;
}
--
cgit v1.2.3
From 972b6ec20bf090a18145624f8092d2cb1715ab83 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Thu, 3 Aug 2017 14:21:00 -0400
Subject: Fix lock upgrade hazard in ATExecAttachPartition.
Amit Langote
Discussion: http://postgr.es/m/CAFjFpReT_kq_uwU_B8aWDxR7jNGE=P0iELycdq5oupi=xSQTOw@mail.gmail.com
---
src/backend/commands/tablecmds.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3c42e160b2..7859ef13ac 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13489,9 +13489,20 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
/*
* Prevent circularity by seeing if rel is a partition of attachrel. (In
* particular, this disallows making a rel a partition of itself.)
+ *
+ * We do that by checking if rel is a member of the list of attachRel's
+ * partitions provided the latter is partitioned at all. We want to avoid
+ * having to construct this list again, so we request the strongest lock
+ * on all partitions. We need the strongest lock, because we may decide
+ * to scan them if we find out that the table being attached (or its leaf
+ * partitions) may contain rows that violate the partition constraint.
+ * If the table has a constraint that would prevent such rows, which by
+ * definition is present in all the partitions, we need not scan the
+ * table, nor its partitions. But we cannot risk a deadlock by taking a
+ * weaker lock now and the stronger one only when needed.
*/
attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
- AccessShareLock, NULL);
+ AccessExclusiveLock, NULL);
if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_TABLE),
@@ -13694,17 +13705,9 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
else
{
/* Constraints proved insufficient, so we need to scan the table. */
- List *all_parts;
ListCell *lc;
- /* Take an exclusive lock on the partitions to be checked */
- if (attachrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
- all_parts = find_all_inheritors(RelationGetRelid(attachrel),
- AccessExclusiveLock, NULL);
- else
- all_parts = list_make1_oid(RelationGetRelid(attachrel));
-
- foreach(lc, all_parts)
+ foreach(lc, attachrel_children)
{
AlteredTableInfo *tab;
Oid part_relid = lfirst_oid(lc);
--
cgit v1.2.3
From 9a3b5d3ad0f1c19c47e2ee65b372344cb0616c9a Mon Sep 17 00:00:00 2001
From: Alvaro Herrera
Date: Thu, 3 Aug 2017 14:48:54 -0400
Subject: Fix build on zlib-less environments
Commit 4d57e8381677 added support for getting I/O errors out of zlib,
but it introduced a portability problem for systems without zlib.
Repair by wrapping the zlib call inside #ifdef and restore the original
code in the other branch.
This serves to illustrate the inadequacy of the zlib abstraction in
pg_backup_archiver: there is no way to call gzerror() in that
abstraction. This means that the several places that call GZREAD and
GZWRITE are currently doing error reporting wrongly, but ENOTIME to get
it fixed before next week's release set.
Backpatch to 9.4, like the commit that introduced the problem.
---
src/bin/pg_dump/pg_backup_tar.c | 6 ++++++
1 file changed, 6 insertions(+)
(limited to 'src')
diff --git a/src/bin/pg_dump/pg_backup_tar.c b/src/bin/pg_dump/pg_backup_tar.c
index 3c41d40a93..2339d659bc 100644
--- a/src/bin/pg_dump/pg_backup_tar.c
+++ b/src/bin/pg_dump/pg_backup_tar.c
@@ -556,12 +556,18 @@ _tarReadRaw(ArchiveHandle *AH, void *buf, size_t len, TAR_MEMBER *th, FILE *fh)
res = GZREAD(&((char *) buf)[used], 1, len, th->zFH);
if (res != len && !GZEOF(th->zFH))
{
+#ifdef HAVE_LIBZ
int errnum;
const char *errmsg = gzerror(th->zFH, &errnum);
exit_horribly(modulename,
"could not read from input file: %s\n",
errnum == Z_ERRNO ? strerror(errno) : errmsg);
+#else
+ exit_horribly(modulename,
+ "could not read from input file: %s\n",
+ strerror(errno));
+#endif
}
}
else
--
cgit v1.2.3
From 3eb9a5e7c4c9f10178815b569dbc0058eb50c05a Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Thu, 3 Aug 2017 17:36:23 -0400
Subject: Fix pg_dump/pg_restore to emit REFRESH MATERIALIZED VIEW commands
last.
Because we push all ACL (i.e. GRANT/REVOKE) restore steps to the end,
materialized view refreshes were occurring while the permissions on
referenced objects were still at defaults. This led to failures if,
say, an MV owned by user A reads from a table owned by user B, even
if B had granted the necessary privileges to A. We've had multiple
complaints about that type of restore failure, most recently from
Jordan Gigov.
The ideal fix for this would be to start treating ACLs as dependency-
sortable objects, rather than hard-wiring anything about their dump order
(the existing approach is a messy kluge dating to commit dc0e76ca3).
But that's going to be a rather major change, and it certainly wouldn't
lead to a back-patchable fix. As a short-term solution, convert the
existing two-pass hack (ie, normal objects then ACLs) to a three-pass hack,
ie, normal objects then ACLs then matview refreshes. Because this happens
in RestoreArchive(), it will also fix the problem when restoring from an
existing archive-format dump.
(Note this means that if a matview refresh would have failed under the
permissions prevailing at dump time, it'll fail during restore as well.
We'll define that as user error rather than something we should try
to work around.)
To avoid performance loss in parallel restore, we need the matview
refreshes to still be parallelizable. Hence, clean things up enough
so that both ACLs and matviews are handled by the parallel restore
infrastructure, instead of reverting back to serial restore for ACLs.
There is still a final serial step, but it shouldn't normally have to
do anything; it's only there to try to recover if we get stuck due to
some problem like unresolved circular dependencies.
Patch by me, but it owes something to an earlier attempt by Kevin Grittner.
Back-patch to 9.3 where materialized views were introduced.
Discussion: https://postgr.es/m/28572.1500912583@sss.pgh.pa.us
---
src/bin/pg_dump/pg_backup_archiver.c | 368 +++++++++++++++++++++++------------
src/bin/pg_dump/pg_backup_archiver.h | 25 +++
2 files changed, 264 insertions(+), 129 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index f461692d45..4cfb71c013 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -58,7 +58,7 @@ static ArchiveHandle *_allocAH(const char *FileSpec, const ArchiveFormat fmt,
SetupWorkerPtrType setupWorkerPtr);
static void _getObjectDescription(PQExpBuffer buf, TocEntry *te,
ArchiveHandle *AH);
-static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass);
+static void _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData);
static char *replace_line_endings(const char *str);
static void _doSetFixedOutputState(ArchiveHandle *AH);
static void _doSetSessionAuth(ArchiveHandle *AH, const char *user);
@@ -71,6 +71,7 @@ static void _selectTablespace(ArchiveHandle *AH, const char *tablespace);
static void processEncodingEntry(ArchiveHandle *AH, TocEntry *te);
static void processStdStringsEntry(ArchiveHandle *AH, TocEntry *te);
static teReqs _tocEntryRequired(TocEntry *te, teSection curSection, RestoreOptions *ropt);
+static RestorePass _tocEntryRestorePass(TocEntry *te);
static bool _tocEntryIsACL(TocEntry *te);
static void _disableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te);
static void _enableTriggersIfNecessary(ArchiveHandle *AH, TocEntry *te);
@@ -86,13 +87,18 @@ static OutputContext SaveOutput(ArchiveHandle *AH);
static void RestoreOutput(ArchiveHandle *AH, OutputContext savedContext);
static int restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel);
-static void restore_toc_entries_prefork(ArchiveHandle *AH);
-static void restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
+static void restore_toc_entries_prefork(ArchiveHandle *AH,
+ TocEntry *pending_list);
+static void restore_toc_entries_parallel(ArchiveHandle *AH,
+ ParallelState *pstate,
+ TocEntry *pending_list);
+static void restore_toc_entries_postfork(ArchiveHandle *AH,
TocEntry *pending_list);
-static void restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list);
static void par_list_header_init(TocEntry *l);
static void par_list_append(TocEntry *l, TocEntry *te);
static void par_list_remove(TocEntry *te);
+static void move_to_ready_list(TocEntry *pending_list, TocEntry *ready_list,
+ RestorePass pass);
static TocEntry *get_next_work_item(ArchiveHandle *AH,
TocEntry *ready_list,
ParallelState *pstate);
@@ -625,20 +631,18 @@ RestoreArchive(Archive *AHX)
AH->currSchema = NULL;
}
- /*
- * In serial mode, we now process each non-ACL TOC entry.
- *
- * In parallel mode, turn control over to the parallel-restore logic.
- */
if (parallel_mode)
{
+ /*
+ * In parallel mode, turn control over to the parallel-restore logic.
+ */
ParallelState *pstate;
TocEntry pending_list;
par_list_header_init(&pending_list);
/* This runs PRE_DATA items and then disconnects from the database */
- restore_toc_entries_prefork(AH);
+ restore_toc_entries_prefork(AH, &pending_list);
Assert(AH->connection == NULL);
/* ParallelBackupStart() will actually fork the processes */
@@ -652,28 +656,51 @@ RestoreArchive(Archive *AHX)
}
else
{
+ /*
+ * In serial mode, process everything in three phases: normal items,
+ * then ACLs, then matview refresh items. We might be able to skip
+ * one or both extra phases in some cases, eg data-only restores.
+ */
+ bool haveACL = false;
+ bool haveRefresh = false;
+
for (te = AH->toc->next; te != AH->toc; te = te->next)
- (void) restore_toc_entry(AH, te, false);
- }
+ {
+ if ((te->reqs & (REQ_SCHEMA | REQ_DATA)) == 0)
+ continue; /* ignore if not to be dumped at all */
- /*
- * Scan TOC again to output ownership commands and ACLs
- */
- for (te = AH->toc->next; te != AH->toc; te = te->next)
- {
- AH->currentTE = te;
+ switch (_tocEntryRestorePass(te))
+ {
+ case RESTORE_PASS_MAIN:
+ (void) restore_toc_entry(AH, te, false);
+ break;
+ case RESTORE_PASS_ACL:
+ haveACL = true;
+ break;
+ case RESTORE_PASS_REFRESH:
+ haveRefresh = true;
+ break;
+ }
+ }
- /* Both schema and data objects might now have ownership/ACLs */
- if ((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0)
+ if (haveACL)
{
- /* Show namespace if available */
- if (te->namespace)
- ahlog(AH, 1, "setting owner and privileges for %s \"%s.%s\"\n",
- te->desc, te->namespace, te->tag);
- else
- ahlog(AH, 1, "setting owner and privileges for %s \"%s\"\n",
- te->desc, te->tag);
- _printTocEntry(AH, te, false, true);
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
+ {
+ if ((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0 &&
+ _tocEntryRestorePass(te) == RESTORE_PASS_ACL)
+ (void) restore_toc_entry(AH, te, false);
+ }
+ }
+
+ if (haveRefresh)
+ {
+ for (te = AH->toc->next; te != AH->toc; te = te->next)
+ {
+ if ((te->reqs & (REQ_SCHEMA | REQ_DATA)) != 0 &&
+ _tocEntryRestorePass(te) == RESTORE_PASS_REFRESH)
+ (void) restore_toc_entry(AH, te, false);
+ }
}
}
@@ -720,10 +747,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
AH->currentTE = te;
/* Work out what, if anything, we want from this entry */
- if (_tocEntryIsACL(te))
- reqs = 0; /* ACLs are never restored here */
- else
- reqs = te->reqs;
+ reqs = te->reqs;
/*
* Ignore DATABASE entry unless we should create it. We must check this
@@ -744,17 +768,19 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
defnDumped = false;
- if ((reqs & REQ_SCHEMA) != 0) /* We want the schema */
+ /*
+ * If it has a schema component that we want, then process that
+ */
+ if ((reqs & REQ_SCHEMA) != 0)
{
- /* Show namespace if available */
+ /* Show namespace in log message if available */
if (te->namespace)
ahlog(AH, 1, "creating %s \"%s.%s\"\n",
te->desc, te->namespace, te->tag);
else
ahlog(AH, 1, "creating %s \"%s\"\n", te->desc, te->tag);
-
- _printTocEntry(AH, te, false, false);
+ _printTocEntry(AH, te, false);
defnDumped = true;
if (strcmp(te->desc, "TABLE") == 0)
@@ -810,7 +836,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
}
/*
- * If we have a data component, then process it
+ * If it has a data component that we want, then process that
*/
if ((reqs & REQ_DATA) != 0)
{
@@ -826,7 +852,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
*/
if (AH->PrintTocDataPtr != NULL)
{
- _printTocEntry(AH, te, true, false);
+ _printTocEntry(AH, te, true);
if (strcmp(te->desc, "BLOBS") == 0 ||
strcmp(te->desc, "BLOB COMMENTS") == 0)
@@ -914,7 +940,7 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
{
/* If we haven't already dumped the defn part, do so now */
ahlog(AH, 1, "executing %s %s\n", te->desc, te->tag);
- _printTocEntry(AH, te, false, false);
+ _printTocEntry(AH, te, false);
}
}
@@ -2943,8 +2969,30 @@ _tocEntryRequired(TocEntry *te, teSection curSection, RestoreOptions *ropt)
return res;
}
+/*
+ * Identify which pass we should restore this TOC entry in.
+ *
+ * See notes with the RestorePass typedef in pg_backup_archiver.h.
+ */
+static RestorePass
+_tocEntryRestorePass(TocEntry *te)
+{
+ /* "ACL LANGUAGE" was a crock emitted only in PG 7.4 */
+ if (strcmp(te->desc, "ACL") == 0 ||
+ strcmp(te->desc, "ACL LANGUAGE") == 0 ||
+ strcmp(te->desc, "DEFAULT ACL") == 0)
+ return RESTORE_PASS_ACL;
+ if (strcmp(te->desc, "MATERIALIZED VIEW DATA") == 0)
+ return RESTORE_PASS_REFRESH;
+ return RESTORE_PASS_MAIN;
+}
+
/*
* Identify TOC entries that are ACLs.
+ *
+ * Note: it seems worth duplicating some code here to avoid a hard-wired
+ * assumption that these are exactly the same entries that we restore during
+ * the RESTORE_PASS_ACL phase.
*/
static bool
_tocEntryIsACL(TocEntry *te)
@@ -3364,23 +3412,18 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
type);
}
+/*
+ * Emit the SQL commands to create the object represented by a TOC entry
+ *
+ * This now also includes issuing an ALTER OWNER command to restore the
+ * object's ownership, if wanted. But note that the object's permissions
+ * will remain at default, until the matching ACL TOC entry is restored.
+ */
static void
-_printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass)
+_printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData)
{
RestoreOptions *ropt = AH->public.ropt;
- /* ACLs are dumped only during acl pass */
- if (acl_pass)
- {
- if (!_tocEntryIsACL(te))
- return;
- }
- else
- {
- if (_tocEntryIsACL(te))
- return;
- }
-
/*
* Avoid dumping the public schema, as it will already be created ...
* unless we are using --clean mode (and *not* --create mode), in which
@@ -3567,7 +3610,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, bool isData, bool acl_pass)
* If it's an ACL entry, it might contain SET SESSION AUTHORIZATION
* commands, so we can no longer assume we know the current auth setting.
*/
- if (acl_pass)
+ if (_tocEntryIsACL(te))
{
if (AH->currUser)
free(AH->currUser);
@@ -3597,6 +3640,9 @@ replace_line_endings(const char *str)
return result;
}
+/*
+ * Write the file header for a custom-format archive
+ */
void
WriteHead(ArchiveHandle *AH)
{
@@ -3772,16 +3818,14 @@ dumpTimestamp(ArchiveHandle *AH, const char *msg, time_t tim)
/*
* Main engine for parallel restore.
*
- * Work is done in three phases.
- * First we process all SECTION_PRE_DATA tocEntries, in a single connection,
- * just as for a standard restore. Second we process the remaining non-ACL
- * steps in parallel worker children (threads on Windows, processes on Unix),
- * each of which connects separately to the database. Finally we process all
- * the ACL entries in a single connection (that happens back in
- * RestoreArchive).
+ * Parallel restore is done in three phases. In this first phase,
+ * we'll process all SECTION_PRE_DATA TOC entries that are allowed to be
+ * processed in the RESTORE_PASS_MAIN pass. (In practice, that's all
+ * PRE_DATA items other than ACLs.) Entries we can't process now are
+ * added to the pending_list for later phases to deal with.
*/
static void
-restore_toc_entries_prefork(ArchiveHandle *AH)
+restore_toc_entries_prefork(ArchiveHandle *AH, TocEntry *pending_list)
{
bool skipped_some;
TocEntry *next_work_item;
@@ -3799,23 +3843,31 @@ restore_toc_entries_prefork(ArchiveHandle *AH)
* about showing all the dependencies of SECTION_PRE_DATA items, so we do
* not risk trying to process them out-of-order.
*
+ * Stuff that we can't do immediately gets added to the pending_list.
+ * Note: we don't yet filter out entries that aren't going to be restored.
+ * They might participate in dependency chains connecting entries that
+ * should be restored, so we treat them as live until we actually process
+ * them.
+ *
* Note: as of 9.2, it should be guaranteed that all PRE_DATA items appear
* before DATA items, and all DATA items before POST_DATA items. That is
* not certain to be true in older archives, though, so this loop is coded
* to not assume it.
*/
+ AH->restorePass = RESTORE_PASS_MAIN;
skipped_some = false;
for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next)
{
- /* NB: process-or-continue logic must be the inverse of loop below */
+ bool do_now = true;
+
if (next_work_item->section != SECTION_PRE_DATA)
{
/* DATA and POST_DATA items are just ignored for now */
if (next_work_item->section == SECTION_DATA ||
next_work_item->section == SECTION_POST_DATA)
{
+ do_now = false;
skipped_some = true;
- continue;
}
else
{
@@ -3826,18 +3878,35 @@ restore_toc_entries_prefork(ArchiveHandle *AH)
* comment's dependencies are satisfied, so skip it for now.
*/
if (skipped_some)
- continue;
+ do_now = false;
}
}
- ahlog(AH, 1, "processing item %d %s %s\n",
- next_work_item->dumpId,
- next_work_item->desc, next_work_item->tag);
+ /*
+ * Also skip items that need to be forced into later passes. We need
+ * not set skipped_some in this case, since by assumption no main-pass
+ * items could depend on these.
+ */
+ if (_tocEntryRestorePass(next_work_item) != RESTORE_PASS_MAIN)
+ do_now = false;
+
+ if (do_now)
+ {
+ /* OK, restore the item and update its dependencies */
+ ahlog(AH, 1, "processing item %d %s %s\n",
+ next_work_item->dumpId,
+ next_work_item->desc, next_work_item->tag);
- (void) restore_toc_entry(AH, next_work_item, false);
+ (void) restore_toc_entry(AH, next_work_item, false);
- /* there should be no touch of ready_list here, so pass NULL */
- reduce_dependencies(AH, next_work_item, NULL);
+ /* there should be no touch of ready_list here, so pass NULL */
+ reduce_dependencies(AH, next_work_item, NULL);
+ }
+ else
+ {
+ /* Nope, so add it to pending_list */
+ par_list_append(pending_list, next_work_item);
+ }
}
/*
@@ -3863,89 +3932,60 @@ restore_toc_entries_prefork(ArchiveHandle *AH)
/*
* Main engine for parallel restore.
*
- * Work is done in three phases.
- * First we process all SECTION_PRE_DATA tocEntries, in a single connection,
- * just as for a standard restore. This is done in restore_toc_entries_prefork().
- * Second we process the remaining non-ACL steps in parallel worker children
- * (threads on Windows, processes on Unix), these fork off and set up their
- * connections before we call restore_toc_entries_parallel_forked.
- * Finally we process all the ACL entries in a single connection (that happens
- * back in RestoreArchive).
+ * Parallel restore is done in three phases. In this second phase,
+ * we process entries by dispatching them to parallel worker children
+ * (processes on Unix, threads on Windows), each of which connects
+ * separately to the database. Inter-entry dependencies are respected,
+ * and so is the RestorePass multi-pass structure. When we can no longer
+ * make any entries ready to process, we exit. Normally, there will be
+ * nothing left to do; but if there is, the third phase will mop up.
*/
static void
restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
TocEntry *pending_list)
{
- bool skipped_some;
TocEntry ready_list;
TocEntry *next_work_item;
ahlog(AH, 2, "entering restore_toc_entries_parallel\n");
/*
- * Initialize the lists of ready items, the list for pending items has
- * already been initialized in the caller. After this setup, the pending
- * list is everything that needs to be done but is blocked by one or more
- * dependencies, while the ready list contains items that have no
- * remaining dependencies. Note: we don't yet filter out entries that
- * aren't going to be restored. They might participate in dependency
- * chains connecting entries that should be restored, so we treat them as
- * live until we actually process them.
+ * The pending_list contains all items that we need to restore. Move all
+ * items that are available to process immediately into the ready_list.
+ * After this setup, the pending list is everything that needs to be done
+ * but is blocked by one or more dependencies, while the ready list
+ * contains items that have no remaining dependencies and are OK to
+ * process in the current restore pass.
*/
par_list_header_init(&ready_list);
- skipped_some = false;
- for (next_work_item = AH->toc->next; next_work_item != AH->toc; next_work_item = next_work_item->next)
- {
- /* NB: process-or-continue logic must be the inverse of loop above */
- if (next_work_item->section == SECTION_PRE_DATA)
- {
- /* All PRE_DATA items were dealt with above */
- continue;
- }
- if (next_work_item->section == SECTION_DATA ||
- next_work_item->section == SECTION_POST_DATA)
- {
- /* set this flag at same point that previous loop did */
- skipped_some = true;
- }
- else
- {
- /* SECTION_NONE items must be processed if previous loop didn't */
- if (!skipped_some)
- continue;
- }
-
- if (next_work_item->depCount > 0)
- par_list_append(pending_list, next_work_item);
- else
- par_list_append(&ready_list, next_work_item);
- }
+ AH->restorePass = RESTORE_PASS_MAIN;
+ move_to_ready_list(pending_list, &ready_list, AH->restorePass);
/*
* main parent loop
*
* Keep going until there is no worker still running AND there is no work
- * left to be done.
+ * left to be done. Note invariant: at top of loop, there should always
+ * be at least one worker available to dispatch a job to.
*/
-
ahlog(AH, 1, "entering main parallel loop\n");
- while ((next_work_item = get_next_work_item(AH, &ready_list, pstate)) != NULL ||
- !IsEveryWorkerIdle(pstate))
+ for (;;)
{
+ /* Look for an item ready to be dispatched to a worker */
+ next_work_item = get_next_work_item(AH, &ready_list, pstate);
if (next_work_item != NULL)
{
/* If not to be restored, don't waste time launching a worker */
- if ((next_work_item->reqs & (REQ_SCHEMA | REQ_DATA)) == 0 ||
- _tocEntryIsACL(next_work_item))
+ if ((next_work_item->reqs & (REQ_SCHEMA | REQ_DATA)) == 0)
{
ahlog(AH, 1, "skipping item %d %s %s\n",
next_work_item->dumpId,
next_work_item->desc, next_work_item->tag);
-
+ /* Drop it from ready_list, and update its dependencies */
par_list_remove(next_work_item);
reduce_dependencies(AH, next_work_item, &ready_list);
-
+ /* Loop around to see if anything else can be dispatched */
continue;
}
@@ -3953,14 +3993,34 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
next_work_item->dumpId,
next_work_item->desc, next_work_item->tag);
+ /* Remove it from ready_list, and dispatch to some worker */
par_list_remove(next_work_item);
DispatchJobForTocEntry(AH, pstate, next_work_item, ACT_RESTORE,
mark_restore_job_done, &ready_list);
}
+ else if (IsEveryWorkerIdle(pstate))
+ {
+ /*
+ * Nothing is ready and no worker is running, so we're done with
+ * the current pass or maybe with the whole process.
+ */
+ if (AH->restorePass == RESTORE_PASS_LAST)
+ break; /* No more parallel processing is possible */
+
+ /* Advance to next restore pass */
+ AH->restorePass++;
+ /* That probably allows some stuff to be made ready */
+ move_to_ready_list(pending_list, &ready_list, AH->restorePass);
+ /* Loop around to see if anything's now ready */
+ continue;
+ }
else
{
- /* at least one child is working and we have nothing ready. */
+ /*
+ * We have nothing ready, but at least one child is working, so
+ * wait for some subjob to finish.
+ */
}
/*
@@ -3980,9 +4040,21 @@ restore_toc_entries_parallel(ArchiveHandle *AH, ParallelState *pstate,
next_work_item ? WFW_ONE_IDLE : WFW_GOT_STATUS);
}
+ /* There should now be nothing in ready_list. */
+ Assert(ready_list.par_next == &ready_list);
+
ahlog(AH, 1, "finished main parallel loop\n");
}
+/*
+ * Main engine for parallel restore.
+ *
+ * Parallel restore is done in three phases. In this third phase,
+ * we mop up any remaining TOC entries by processing them serially.
+ * This phase normally should have nothing to do, but if we've somehow
+ * gotten stuck due to circular dependencies or some such, this provides
+ * at least some chance of completing the restore successfully.
+ */
static void
restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
{
@@ -4002,9 +4074,10 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
_doSetFixedOutputState(AH);
/*
- * Make sure there is no non-ACL work left due to, say, circular
- * dependencies, or some other pathological condition. If so, do it in the
- * single parent connection.
+ * Make sure there is no work left due to, say, circular dependencies, or
+ * some other pathological condition. If so, do it in the single parent
+ * connection. We don't sweat about RestorePass ordering; it's likely we
+ * already violated that.
*/
for (te = pending_list->par_next; te != pending_list; te = te->par_next)
{
@@ -4012,8 +4085,6 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
te->dumpId, te->desc, te->tag);
(void) restore_toc_entry(AH, te, false);
}
-
- /* The ACLs will be handled back in RestoreArchive. */
}
/*
@@ -4072,6 +4143,36 @@ par_list_remove(TocEntry *te)
}
+/*
+ * Move all immediately-ready items from pending_list to ready_list.
+ *
+ * Items are considered ready if they have no remaining dependencies and
+ * they belong in the current restore pass. (See also reduce_dependencies,
+ * which applies the same logic one-at-a-time.)
+ */
+static void
+move_to_ready_list(TocEntry *pending_list, TocEntry *ready_list,
+ RestorePass pass)
+{
+ TocEntry *te;
+ TocEntry *next_te;
+
+ for (te = pending_list->par_next; te != pending_list; te = next_te)
+ {
+ /* must save list link before possibly moving te to other list */
+ next_te = te->par_next;
+
+ if (te->depCount == 0 &&
+ _tocEntryRestorePass(te) == pass)
+ {
+ /* Remove it from pending_list ... */
+ par_list_remove(te);
+ /* ... and add to ready_list */
+ par_list_append(ready_list, te);
+ }
+ }
+}
+
/*
* Find the next work item (if any) that is capable of being run now.
*
@@ -4457,8 +4558,17 @@ reduce_dependencies(ArchiveHandle *AH, TocEntry *te, TocEntry *ready_list)
{
TocEntry *otherte = AH->tocsByDumpId[te->revDeps[i]];
+ Assert(otherte->depCount > 0);
otherte->depCount--;
- if (otherte->depCount == 0 && otherte->par_prev != NULL)
+
+ /*
+ * It's ready if it has no remaining dependencies and it belongs in
+ * the current restore pass. However, don't move it if it has not yet
+ * been put into the pending list.
+ */
+ if (otherte->depCount == 0 &&
+ _tocEntryRestorePass(otherte) == AH->restorePass &&
+ otherte->par_prev != NULL)
{
/* It must be in the pending list, so remove it ... */
par_list_remove(otherte);
diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h
index 6123859132..fd0d01b506 100644
--- a/src/bin/pg_dump/pg_backup_archiver.h
+++ b/src/bin/pg_dump/pg_backup_archiver.h
@@ -203,6 +203,30 @@ typedef enum
OUTPUT_OTHERDATA /* writing data as INSERT commands */
} ArchiverOutput;
+/*
+ * For historical reasons, ACL items are interspersed with everything else in
+ * a dump file's TOC; typically they're right after the object they're for.
+ * However, we need to restore data before ACLs, as otherwise a read-only
+ * table (ie one where the owner has revoked her own INSERT privilege) causes
+ * data restore failures. On the other hand, matview REFRESH commands should
+ * come out after ACLs, as otherwise non-superuser-owned matviews might not
+ * be able to execute. (If the permissions at the time of dumping would not
+ * allow a REFRESH, too bad; we won't fix that for you.) These considerations
+ * force us to make three passes over the TOC, restoring the appropriate
+ * subset of items in each pass. We assume that the dependency sort resulted
+ * in an appropriate ordering of items within each subset.
+ * XXX This mechanism should be superseded by tracking dependencies on ACLs
+ * properly; but we'll still need it for old dump files even after that.
+ */
+typedef enum
+{
+ RESTORE_PASS_MAIN = 0, /* Main pass (most TOC item types) */
+ RESTORE_PASS_ACL, /* ACL item types */
+ RESTORE_PASS_REFRESH /* Matview REFRESH items */
+
+#define RESTORE_PASS_LAST RESTORE_PASS_REFRESH
+} RestorePass;
+
typedef enum
{
REQ_SCHEMA = 0x01, /* want schema */
@@ -329,6 +353,7 @@ struct _archiveHandle
int noTocComments;
ArchiverStage stage;
ArchiverStage lastErrorStage;
+ RestorePass restorePass; /* used only during parallel restore */
struct _tocEntry *currentTE;
struct _tocEntry *lastErrorTE;
};
--
cgit v1.2.3
From b3744812215de458c80629c3a9c57f00833de8a9 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 31 Jul 2017 20:36:32 -0400
Subject: Further unify ROLE and USER command grammar rules
ALTER USER ... SET did not support all the syntax variants of ALTER ROLE
... SET. Fix that, and to avoid further deviations of this kind, unify
many the grammar rules for ROLE/USER/GROUP commands.
Reported-by: Pavel Golub
---
doc/src/sgml/ref/alter_user.sgml | 8 +--
src/backend/parser/gram.y | 105 +++++++++++---------------------
src/test/regress/expected/rolenames.out | 10 +--
3 files changed, 43 insertions(+), 80 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 9b8a39b376..411a6dcc38 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -38,10 +38,10 @@ ALTER USER role_specification [ WIT
ALTER USER name RENAME TO new_name
-ALTER USER role_specification SET configuration_parameter { TO | = } { value | DEFAULT }
-ALTER USER role_specification SET configuration_parameter FROM CURRENT
-ALTER USER role_specification RESET configuration_parameter
-ALTER USER role_specification RESET ALL
+ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT }
+ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT
+ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] RESET configuration_parameter
+ALTER USER { role_specification | ALL } [ IN DATABASE database_name ] RESET ALL
where role_specification can be:
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 62092ff7ec..7d0de99baf 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -250,7 +250,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
AlterObjectDependsStmt AlterObjectSchemaStmt AlterOwnerStmt
AlterOperatorStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
- AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
+ AlterCompositeTypeStmt AlterUserMappingStmt
AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
AlterDefaultPrivilegesStmt DefACLAction
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
@@ -262,9 +262,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
CreateAssertStmt CreateTransformStmt CreateTrigStmt CreateEventTrigStmt
CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreatePolicyStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
- DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
+ DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropCastStmt DropRoleStmt
- DropUserStmt DropdbStmt DropTableSpaceStmt
+ DropdbStmt DropTableSpaceStmt
DropTransformStmt
DropUserMappingStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt ImportForeignSchemaStmt IndexStmt InsertStmt
@@ -841,8 +841,6 @@ stmt :
| AlterTSConfigurationStmt
| AlterTSDictionaryStmt
| AlterUserMappingStmt
- | AlterUserSetStmt
- | AlterUserStmt
| AnalyzeStmt
| CheckPointStmt
| ClosePortalStmt
@@ -890,7 +888,6 @@ stmt :
| DoStmt
| DropAssertStmt
| DropCastStmt
- | DropGroupStmt
| DropOpClassStmt
| DropOpFamilyStmt
| DropOwnedStmt
@@ -900,7 +897,6 @@ stmt :
| DropTableSpaceStmt
| DropTransformStmt
| DropRoleStmt
- | DropUserStmt
| DropUserMappingStmt
| DropdbStmt
| ExecuteStmt
@@ -1130,6 +1126,14 @@ AlterRoleStmt:
n->options = $5;
$$ = (Node *)n;
}
+ | ALTER USER RoleSpec opt_with AlterOptRoleList
+ {
+ AlterRoleStmt *n = makeNode(AlterRoleStmt);
+ n->role = $3;
+ n->action = +1; /* add, if there are members */
+ n->options = $5;
+ $$ = (Node *)n;
+ }
;
opt_in_database:
@@ -1154,37 +1158,23 @@ AlterRoleSetStmt:
n->setstmt = $5;
$$ = (Node *)n;
}
- ;
-
-
-/*****************************************************************************
- *
- * Alter a postgresql DBMS user
- *
- *****************************************************************************/
-
-AlterUserStmt:
- ALTER USER RoleSpec opt_with AlterOptRoleList
- {
- AlterRoleStmt *n = makeNode(AlterRoleStmt);
+ | ALTER USER RoleSpec opt_in_database SetResetClause
+ {
+ AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->action = +1; /* add, if there are members */
- n->options = $5;
+ n->database = $4;
+ n->setstmt = $5;
$$ = (Node *)n;
- }
- ;
-
-
-AlterUserSetStmt:
- ALTER USER RoleSpec SetResetClause
+ }
+ | ALTER USER ALL opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
- n->role = $3;
- n->database = NULL;
- n->setstmt = $4;
+ n->role = NULL;
+ n->database = $4;
+ n->setstmt = $5;
$$ = (Node *)n;
}
- ;
+ ;
/*****************************************************************************
@@ -1211,17 +1201,7 @@ DropRoleStmt:
n->roles = $5;
$$ = (Node *)n;
}
- ;
-
-/*****************************************************************************
- *
- * Drop a postgresql DBMS user
- *
- * XXX As with DROP ROLE, no CASCADE/RESTRICT here.
- *****************************************************************************/
-
-DropUserStmt:
- DROP USER role_list
+ | DROP USER role_list
{
DropRoleStmt *n = makeNode(DropRoleStmt);
n->missing_ok = FALSE;
@@ -1235,6 +1215,20 @@ DropUserStmt:
n->missing_ok = TRUE;
$$ = (Node *)n;
}
+ | DROP GROUP_P role_list
+ {
+ DropRoleStmt *n = makeNode(DropRoleStmt);
+ n->missing_ok = FALSE;
+ n->roles = $3;
+ $$ = (Node *)n;
+ }
+ | DROP GROUP_P IF_P EXISTS role_list
+ {
+ DropRoleStmt *n = makeNode(DropRoleStmt);
+ n->missing_ok = TRUE;
+ n->roles = $5;
+ $$ = (Node *)n;
+ }
;
@@ -1279,31 +1273,6 @@ add_drop: ADD_P { $$ = +1; }
;
-/*****************************************************************************
- *
- * Drop a postgresql group
- *
- * XXX As with DROP ROLE, no CASCADE/RESTRICT here.
- *****************************************************************************/
-
-DropGroupStmt:
- DROP GROUP_P role_list
- {
- DropRoleStmt *n = makeNode(DropRoleStmt);
- n->missing_ok = FALSE;
- n->roles = $3;
- $$ = (Node *)n;
- }
- | DROP GROUP_P IF_P EXISTS role_list
- {
- DropRoleStmt *n = makeNode(DropRoleStmt);
- n->missing_ok = TRUE;
- n->roles = $5;
- $$ = (Node *)n;
- }
- ;
-
-
/*****************************************************************************
*
* Manipulate a schema
diff --git a/src/test/regress/expected/rolenames.out b/src/test/regress/expected/rolenames.out
index fd058e4f7d..dce82f5de7 100644
--- a/src/test/regress/expected/rolenames.out
+++ b/src/test/regress/expected/rolenames.out
@@ -310,9 +310,9 @@ ERROR: syntax error at or near "CURRENT_ROLE"
LINE 1: ALTER USER CURRENT_ROLE WITH LOGIN;
^
ALTER USER ALL WITH REPLICATION; -- error
-ERROR: syntax error at or near "ALL"
+ERROR: syntax error at or near "WITH"
LINE 1: ALTER USER ALL WITH REPLICATION;
- ^
+ ^
ALTER USER SESSION_ROLE WITH NOREPLICATION; -- error
ERROR: role "session_role" does not exist
ALTER USER PUBLIC WITH NOREPLICATION; -- error
@@ -392,9 +392,6 @@ ALTER USER SESSION_USER SET application_name to 'BAR';
ALTER USER "current_user" SET application_name to 'FOOFOO';
ALTER USER "Public" SET application_name to 'BARBAR';
ALTER USER ALL SET application_name to 'SLAP';
-ERROR: syntax error at or near "ALL"
-LINE 1: ALTER USER ALL SET application_name to 'SLAP';
- ^
SELECT * FROM chksetconfig();
db | role | rolkeyword | setconfig
-----+------------------+--------------+---------------------------
@@ -419,9 +416,6 @@ ALTER USER SESSION_USER RESET application_name;
ALTER USER "current_user" RESET application_name;
ALTER USER "Public" RESET application_name;
ALTER USER ALL RESET application_name;
-ERROR: syntax error at or near "ALL"
-LINE 1: ALTER USER ALL RESET application_name;
- ^
SELECT * FROM chksetconfig();
db | role | rolkeyword | setconfig
----+------+------------+-----------
--
cgit v1.2.3
From 97d3a0b0900a30fc51823c2d806ab621299f1b07 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 4 Aug 2017 11:07:10 -0400
Subject: Disallow SSL session tickets.
We don't actually support session tickets, since we do not create an SSL
session identifier. But it seems that OpenSSL will issue a session ticket
on-demand anyway, which will then fail when used. This results in
reconnection failures when using ticket-aware client-side SSL libraries
(such as the Npgsql .NET driver), as reported by Shay Rojansky.
To fix, just tell OpenSSL not to issue tickets. At some point in the
far future, we might consider enabling tickets instead. But the security
implications of that aren't entirely clear; and besides it would have
little benefit except for very short-lived database connections, which is
Something We're Bad At anyhow. It would take a lot of other work to get
to a point where that would really be an exciting thing to do.
While at it, also tell OpenSSL not to use a session cache. This doesn't
really do anything, since a backend would never populate the cache anyway,
but it might gain some micro-efficiencies and/or reduce security
exposures.
Patch by me, per discussion with Heikki Linnakangas and Shay Rojansky.
Back-patch to all supported versions.
Discussion: https://postgr.es/m/CADT4RqBU8N-csyZuzaook-c795dt22Zcwg1aHWB6tfVdAkodZA@mail.gmail.com
---
src/backend/libpq/be-secure-openssl.c | 8 ++++++++
1 file changed, 8 insertions(+)
(limited to 'src')
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index 694f76afa6..00f17f7843 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -288,6 +288,14 @@ be_tls_init(bool isServerStart)
/* disallow SSL v2/v3 */
SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+ /* disallow SSL session tickets */
+#ifdef SSL_OP_NO_TICKET /* added in openssl 0.9.8f */
+ SSL_CTX_set_options(context, SSL_OP_NO_TICKET);
+#endif
+
+ /* disallow SSL session caching, too */
+ SSL_CTX_set_session_cache_mode(context, SSL_SESS_CACHE_OFF);
+
/* set up ephemeral DH and ECDH keys */
if (!initialize_dh(context, isServerStart))
goto error;
--
cgit v1.2.3
From c30f1770a93db1492755934048656ea809c1f569 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Fri, 4 Aug 2017 11:45:18 -0400
Subject: Apply ALTER ... SET NOT NULL recursively in ALTER ... ADD PRIMARY
KEY.
If you do ALTER COLUMN SET NOT NULL against an inheritance parent table,
it will recurse to mark all the child columns as NOT NULL as well. This
is necessary for consistency: if the column is labeled NOT NULL then
reading it should never produce nulls.
However, that didn't happen in the case where ALTER ... ADD PRIMARY KEY
marks a target column NOT NULL that wasn't before. That was questionable
from the beginning, and now Tushar Ahuja points out that it can lead to
dump/restore failures in some cases. So let's make that case recurse too.
Although this is meant to fix a bug, it's enough of a behavioral change
that I'm pretty hesitant to back-patch, especially in view of the lack
of similar field complaints. It doesn't seem to be too late to put it
into v10 though.
Michael Paquier, editorialized on slightly by me
Discussion: https://postgr.es/m/b8794d6a-38f0-9d7c-ad4b-e85adf860fc9@enterprisedb.com
---
src/backend/catalog/index.c | 9 ++++-----
src/test/regress/expected/alter_table.out | 2 +-
2 files changed, 5 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d25b39bb54..25c5bead9f 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -185,6 +185,9 @@ relationHasPrimaryKey(Relation rel)
* created NOT NULL during CREATE TABLE), do an ALTER SET NOT NULL to mark
* them so --- or fail if they are not in fact nonnull.
*
+ * As of PG v10, the SET NOT NULL is applied to child tables as well, so
+ * that the behavior is like a manual SET NOT NULL.
+ *
* Caller had better have at least ShareLock on the table, else the not-null
* checking isn't trustworthy.
*/
@@ -253,17 +256,13 @@ index_check_primary_key(Relation heapRel,
}
/*
- * XXX: Shouldn't the ALTER TABLE .. SET NOT NULL cascade to child tables?
- * Currently, since the PRIMARY KEY itself doesn't cascade, we don't
- * cascade the notnull constraint(s) either; but this is pretty debatable.
- *
* XXX: possible future improvement: when being called from ALTER TABLE,
* it would be more efficient to merge this with the outer ALTER TABLE, so
* as to avoid two scans. But that seems to complicate DefineIndex's API
* unduly.
*/
if (cmds)
- AlterTableInternal(RelationGetRelid(heapRel), cmds, false);
+ AlterTableInternal(RelationGetRelid(heapRel), cmds, true);
}
/*
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index 13d6a4b747..e9fd1aacce 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -328,7 +328,7 @@ Number of child tables: 1 (Use \d+ to list them.)
Table "public.constraint_rename_test2"
Column | Type | Collation | Nullable | Default
--------+---------+-----------+----------+---------
- a | integer | | |
+ a | integer | | not null |
b | integer | | |
c | integer | | |
d | integer | | |
--
cgit v1.2.3
From 620b49a16d2a16ce6f9edf072a88111f981919d0 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Fri, 4 Aug 2017 15:29:26 -0400
Subject: hash: Increase the number of possible overflow bitmaps by 8x.
Per a report from AP, it's not that hard to exhaust the supply of
bitmap pages if you create a table with a hash index and then insert a
few billion rows - and then you start getting errors when you try to
insert additional rows. In the particular case reported by AP,
there's another fix that we can make to improve recycling of overflow
pages, which is another way to avoid the error, but there may be other
cases where this problem happens and that fix won't help. So let's
buy ourselves as much headroom as we can without rearchitecting
anything.
The comments claim that the old limit was 64GB, but it was really
only 32GB, because we didn't use all the bits in the page for bitmap
bits - only the largest power of 2 that could fit after deducting
space for the page header and so forth. Thus, we have 4kB per page
for bitmap bits, not 8kB. The new limit is thus actually 8 times the
old *real* limit but only 4 times the old *purported* limit.
Since this breaks on-disk compatibility, bump HASH_VERSION. We've
already done this earlier in this release cycle, so this doesn't cause
any incremental inconvenience for people using pg_upgrade from
releases prior to v10. However, users who use pg_upgrade to reach
10beta3 or later from 10beta2 or earlier will need to REINDEX any hash
indexes again.
Amit Kapila and Robert Haas
Discussion: http://postgr.es/m/20170704105728.mwb72jebfmok2nm2@zip.com.au
---
contrib/pageinspect/expected/hash.out | 6 +++---
contrib/pgstattuple/expected/pgstattuple.out | 4 ++--
doc/src/sgml/pageinspect.sgml | 13 +++++++++----
doc/src/sgml/pgstattuple.sgml | 2 +-
src/include/access/hash.h | 9 ++++-----
5 files changed, 19 insertions(+), 15 deletions(-)
(limited to 'src')
diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out
index 39374158b1..75d7bcfad5 100644
--- a/contrib/pageinspect/expected/hash.out
+++ b/contrib/pageinspect/expected/hash.out
@@ -43,9 +43,9 @@ ERROR: invalid overflow block number 5
SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
hash_metapage_info(get_raw_page('test_hash_a_idx', 0));
--[ RECORD 1 ]----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+-[ RECORD 1 ]--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
magic | 105121344
-version | 3
+version | 4
ntuples | 1
bsize | 8152
bmsize | 4096
@@ -58,7 +58,7 @@ firstfree | 0
nmaps | 1
procid | 450
spares | {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
-mapp | {5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
+mapp | {5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask,
lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM
diff --git a/contrib/pgstattuple/expected/pgstattuple.out b/contrib/pgstattuple/expected/pgstattuple.out
index c7c1732827..20b5585d03 100644
--- a/contrib/pgstattuple/expected/pgstattuple.out
+++ b/contrib/pgstattuple/expected/pgstattuple.out
@@ -134,7 +134,7 @@ create index test_hashidx on test using hash (b);
select * from pgstathashindex('test_hashidx');
version | bucket_pages | overflow_pages | bitmap_pages | unused_pages | live_items | dead_items | free_percent
---------+--------------+----------------+--------------+--------------+------------+------------+--------------
- 3 | 4 | 0 | 1 | 0 | 0 | 0 | 100
+ 4 | 4 | 0 | 1 | 0 | 0 | 0 | 100
(1 row)
-- these should error with the wrong type
@@ -235,7 +235,7 @@ select pgstatindex('test_partition_idx');
select pgstathashindex('test_partition_hash_idx');
pgstathashindex
---------------------
- (3,8,0,1,0,0,0,100)
+ (4,8,0,1,0,0,0,100)
(1 row)
drop table test_partitioned;
diff --git a/doc/src/sgml/pageinspect.sgml b/doc/src/sgml/pageinspect.sgml
index ccdaf3e0ac..e46f5ca6bc 100644
--- a/doc/src/sgml/pageinspect.sgml
+++ b/doc/src/sgml/pageinspect.sgml
@@ -687,8 +687,13 @@ test=# SELECT * FROM hash_bitmap_info('con_hash_index', 2052);
hash_metapage_info returns information stored
in meta page of a HASH index. For example:
-test=# SELECT * FROM hash_metapage_info(get_raw_page('con_hash_index', 0));
--[ RECORD 1 ]-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+test=# SELECT magic, version, ntuples, ffactor, bsize, bmsize, bmshift,
+test-# maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid,
+test-# regexp_replace(spares::text, '(,0)*}', '}') as spares,
+test-# regexp_replace(mapp::text, '(,0)*}', '}') as mapp
+test-# FROM hash_metapage_info(get_raw_page('con_hash_index', 0));
+-[ RECORD 1 ]-------------------------------------------------------------------------------
+spares | {0,0,0,0,0,0,1,1,1,1,1,1,1,1,3,4,4,4,45,55,58,59,508,567,628,704,1193,1202,1204}
magic | 105121344
version | 3
ntuples | 500500
@@ -703,8 +708,8 @@ ovflpoint | 28
firstfree | 1204
nmaps | 1
procid | 450
-spares | {0,0,0,0,0,0,1,1,1,1,1,1,1,1,3,4,4,4,45,55,58,59,508,567,628,704,1193,1202,1204,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
-mapp | {65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
+spares | {0,0,0,0,0,0,1,1,1,1,1,1,1,1,3,4,4,4,45,55,58,59,508,567,628,704,1193,1202,1204}
+mapp | {65}
diff --git a/doc/src/sgml/pgstattuple.sgml b/doc/src/sgml/pgstattuple.sgml
index e98e04fa2f..a7c67ae645 100644
--- a/doc/src/sgml/pgstattuple.sgml
+++ b/doc/src/sgml/pgstattuple.sgml
@@ -368,7 +368,7 @@ pending_tuples | 0
test=> select * from pgstathashindex('con_hash_index');
-[ RECORD 1 ]--+-----------------
-version | 2
+version | 4
bucket_pages | 33081
overflow_pages | 0
bitmap_pages | 1
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 7fa868b556..72fce3038c 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -158,8 +158,7 @@ typedef HashScanOpaqueData *HashScanOpaque;
#define HASH_METAPAGE 0 /* metapage is always block 0 */
#define HASH_MAGIC 0x6440640
-#define HASH_VERSION 3 /* 3 signifies multi-phased bucket allocation
- * to reduce doubling */
+#define HASH_VERSION 4
/*
* spares[] holds the number of overflow pages currently allocated at or
@@ -182,10 +181,10 @@ typedef HashScanOpaqueData *HashScanOpaque;
* after HASH_SPLITPOINT_GROUPS_WITH_ONE_PHASE).
*
* There is no particular upper limit on the size of mapp[], other than
- * needing to fit into the metapage. (With 8K block size, 128 bitmaps
- * limit us to 64 GB of overflow space...)
+ * needing to fit into the metapage. (With 8K block size, 1024 bitmaps
+ * limit us to 256 GB of overflow space...)
*/
-#define HASH_MAX_BITMAPS 128
+#define HASH_MAX_BITMAPS 1024
#define HASH_SPLITPOINT_PHASE_BITS 2
#define HASH_SPLITPOINT_PHASES_PER_GRP (1 << HASH_SPLITPOINT_PHASE_BITS)
--
cgit v1.2.3
From 26d40ada3fa5d2671a16c34b2283448832630c86 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Fri, 4 Aug 2017 18:31:01 -0400
Subject: Message style improvements
---
src/bin/pg_archivecleanup/pg_archivecleanup.c | 8 ++++----
src/bin/pg_basebackup/pg_receivewal.c | 2 +-
src/bin/pg_basebackup/receivelog.c | 6 ++++--
src/bin/pg_basebackup/walmethods.c | 20 ++++++++++----------
src/interfaces/libpq/fe-auth-scram.c | 2 +-
src/pl/plpython/expected/plpython_types.out | 3 ++-
src/pl/plpython/expected/plpython_types_3.out | 3 ++-
src/pl/plpython/plpy_typeio.c | 10 +++++-----
8 files changed, 29 insertions(+), 25 deletions(-)
(limited to 'src')
diff --git a/src/bin/pg_archivecleanup/pg_archivecleanup.c b/src/bin/pg_archivecleanup/pg_archivecleanup.c
index c5e344f3cf..d017f5793b 100644
--- a/src/bin/pg_archivecleanup/pg_archivecleanup.c
+++ b/src/bin/pg_archivecleanup/pg_archivecleanup.c
@@ -245,7 +245,7 @@ SetWALFileNameForCleanup(void)
if (!fnameOK)
{
- fprintf(stderr, _("%s: invalid filename input\n"), progname);
+ fprintf(stderr, _("%s: invalid file name argument\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(2);
}
@@ -350,14 +350,14 @@ main(int argc, char **argv)
}
else
{
- fprintf(stderr, _("%s: must specify restartfilename\n"), progname);
+ fprintf(stderr, _("%s: must specify oldest kept WAL file\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(2);
}
if (optind < argc)
{
- fprintf(stderr, _("%s: too many parameters\n"), progname);
+ fprintf(stderr, _("%s: too many command-line arguments\n"), progname);
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(2);
}
@@ -376,7 +376,7 @@ main(int argc, char **argv)
{
snprintf(WALFilePath, MAXPGPATH, "%s/%s",
archiveLocation, exclusiveCleanupFileName);
- fprintf(stderr, _("%s: keep WAL file \"%s\" and later\n"),
+ fprintf(stderr, _("%s: keeping WAL file \"%s\" and later\n"),
progname, WALFilePath);
}
diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c
index f3c7668d50..9ea61d5a5d 100644
--- a/src/bin/pg_basebackup/pg_receivewal.c
+++ b/src/bin/pg_basebackup/pg_receivewal.c
@@ -280,7 +280,7 @@ FindStreamingStart(uint32 *tli)
}
if (lseek(fd, (off_t) (-4), SEEK_END) < 0)
{
- fprintf(stderr, _("%s: could not seek compressed file \"%s\": %s\n"),
+ fprintf(stderr, _("%s: could not seek in compressed file \"%s\": %s\n"),
progname, fullpath, strerror(errno));
disconnect_and_exit(1);
}
diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c
index 15932c60b5..888458f4a9 100644
--- a/src/bin/pg_basebackup/receivelog.c
+++ b/src/bin/pg_basebackup/receivelog.c
@@ -136,7 +136,7 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
if (stream->walmethod->sync(f) != 0)
{
fprintf(stderr,
- _("%s: could not sync existing write-ahead log file \"%s\": %s\n"),
+ _("%s: could not fsync existing write-ahead log file \"%s\": %s\n"),
progname, fn, stream->walmethod->getlasterror());
stream->walmethod->close(f, CLOSE_UNLINK);
return false;
@@ -151,7 +151,9 @@ open_walfile(StreamCtl *stream, XLogRecPtr startpoint)
if (errno == 0)
errno = ENOSPC;
fprintf(stderr,
- _("%s: write-ahead log file \"%s\" has %d bytes, should be 0 or %d\n"),
+ ngettext("%s: write-ahead log file \"%s\" has %d byte, should be 0 or %d\n",
+ "%s: write-ahead log file \"%s\" has %d bytes, should be 0 or %d\n",
+ size),
progname, fn, (int) size, XLogSegSize);
return false;
}
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 2ab5ae93e0..02d368b242 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -432,7 +432,7 @@ tar_write_compressed_data(void *buf, size_t count, bool flush)
r = deflate(tar_data->zp, flush ? Z_FINISH : Z_NO_FLUSH);
if (r == Z_STREAM_ERROR)
{
- tar_set_error("deflate failed");
+ tar_set_error("could not compress data");
return false;
}
@@ -456,7 +456,7 @@ tar_write_compressed_data(void *buf, size_t count, bool flush)
/* Reset the stream for writing */
if (deflateReset(tar_data->zp) != Z_OK)
{
- tar_set_error("deflateReset failed");
+ tar_set_error("could not reset compression stream");
return false;
}
}
@@ -557,7 +557,7 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
{
pg_free(tar_data->zp);
tar_data->zp = NULL;
- tar_set_error("deflateInit2 failed");
+ tar_set_error("could not initialize compression library");
return NULL;
}
}
@@ -569,7 +569,7 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
Assert(tar_data->currentfile == NULL);
if (tar_data->currentfile != NULL)
{
- tar_set_error("implementation error: tar files can't have more than one open file\n");
+ tar_set_error("implementation error: tar files can't have more than one open file");
return NULL;
}
@@ -597,7 +597,7 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
/* Turn off compression for header */
if (deflateParams(tar_data->zp, 0, 0) != Z_OK)
{
- tar_set_error("deflateParams failed");
+ tar_set_error("could not change compression parameters");
return NULL;
}
}
@@ -635,7 +635,7 @@ tar_open_for_write(const char *pathname, const char *temp_suffix, size_t pad_to_
/* Re-enable compression for the rest of the file */
if (deflateParams(tar_data->zp, tar_data->compression, 0) != Z_OK)
{
- tar_set_error("deflateParams failed");
+ tar_set_error("could not change compression parameters");
return NULL;
}
}
@@ -824,7 +824,7 @@ tar_close(Walfile f, WalCloseMethod method)
/* Turn off compression */
if (deflateParams(tar_data->zp, 0, 0) != Z_OK)
{
- tar_set_error("deflateParams failed");
+ tar_set_error("could not change compression parameters");
return -1;
}
@@ -835,7 +835,7 @@ tar_close(Walfile f, WalCloseMethod method)
/* Turn compression back on */
if (deflateParams(tar_data->zp, tar_data->compression, 0) != Z_OK)
{
- tar_set_error("deflateParams failed");
+ tar_set_error("could not change compression parameters");
return -1;
}
}
@@ -901,7 +901,7 @@ tar_finish(void)
if (r == Z_STREAM_ERROR)
{
- tar_set_error("deflate failed");
+ tar_set_error("could not compress data");
return false;
}
if (tar_data->zp->avail_out < ZLIB_OUT_SIZE)
@@ -917,7 +917,7 @@ tar_finish(void)
if (deflateEnd(tar_data->zp) != Z_OK)
{
- tar_set_error("deflateEnd failed");
+ tar_set_error("could not close compression stream");
return false;
}
}
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
index 8c5c3148c5..d1c7037101 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -308,7 +308,7 @@ build_client_first_message(fe_scram_state *state, PQExpBuffer errormessage)
if (!pg_frontend_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
{
printfPQExpBuffer(errormessage,
- libpq_gettext("failed to generate nonce\n"));
+ libpq_gettext("could not generate nonce\n"));
return NULL;
}
diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out
index 10f7125d84..893de301dd 100644
--- a/src/pl/plpython/expected/plpython_types.out
+++ b/src/pl/plpython/expected/plpython_types.out
@@ -691,7 +691,8 @@ CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
return [[1,2,3],[4,5]]
$$ LANGUAGE plpythonu;
SELECT * FROM test_type_conversion_mdarray_malformed();
-ERROR: multidimensional arrays must have array expressions with matching dimensions. PL/Python function return value has sequence length 2 while expected 3
+ERROR: wrong length of inner sequence: has length 2, but 3 was expected
+DETAIL: To construct a multidimensional array, the inner sequences must all have the same length.
CONTEXT: while creating return value
PL/Python function "test_type_conversion_mdarray_malformed"
CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$
diff --git a/src/pl/plpython/expected/plpython_types_3.out b/src/pl/plpython/expected/plpython_types_3.out
index f7f0d31fef..2d853bd573 100644
--- a/src/pl/plpython/expected/plpython_types_3.out
+++ b/src/pl/plpython/expected/plpython_types_3.out
@@ -691,7 +691,8 @@ CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$
return [[1,2,3],[4,5]]
$$ LANGUAGE plpython3u;
SELECT * FROM test_type_conversion_mdarray_malformed();
-ERROR: multidimensional arrays must have array expressions with matching dimensions. PL/Python function return value has sequence length 2 while expected 3
+ERROR: wrong length of inner sequence: has length 2, but 3 was expected
+DETAIL: To construct a multidimensional array, the inner sequences must all have the same length.
CONTEXT: while creating return value
PL/Python function "test_type_conversion_mdarray_malformed"
CREATE FUNCTION test_type_conversion_mdarray_toodeep() RETURNS int[] AS $$
diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c
index 4dfa3e8f91..91ddcaa7b9 100644
--- a/src/pl/plpython/plpy_typeio.c
+++ b/src/pl/plpython/plpy_typeio.c
@@ -1002,7 +1002,7 @@ PLySequence_ToArray(PLyObToDatum *arg, int32 typmod, PyObject *plrv, bool inarra
dims[ndim] = PySequence_Length(pyptr);
if (dims[ndim] < 0)
- PLy_elog(ERROR, "cannot determine sequence length for function return value");
+ PLy_elog(ERROR, "could not determine sequence length for function return value");
if (dims[ndim] > MaxAllocSize)
PLy_elog(ERROR, "array size exceeds the maximum allowed");
@@ -1087,10 +1087,10 @@ PLySequence_ToArray_recurse(PLyObToDatum *elm, PyObject *list,
int i;
if (PySequence_Length(list) != dims[dim])
- PLy_elog(ERROR,
- "multidimensional arrays must have array expressions with matching dimensions. "
- "PL/Python function return value has sequence length %d while expected %d",
- (int) PySequence_Length(list), dims[dim]);
+ ereport(ERROR,
+ (errmsg("wrong length of inner sequence: has length %d, but %d was expected",
+ (int) PySequence_Length(list), dims[dim]),
+ (errdetail("To construct a multidimensional array, the inner sequences must all have the same length."))));
if (dim < ndim - 1)
{
--
cgit v1.2.3
From ff98a5e1e49de061600feb6b4de5ce0a22d386af Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Fri, 4 Aug 2017 19:33:01 -0400
Subject: hash: Immediately after a bucket split, try to clean the old bucket.
If it works, then we won't be storing two copies of all the tuples
that were just moved. If not, VACUUM will still take care of it
eventually. Per a report from AP and analysis from Amit Kapila, it
seems that a bulk load can cause splits fast enough that VACUUM won't
deal with the problem in time to prevent bloat.
Amit Kapila; I rewrote the comment.
Discussion: http://postgr.es/m/20170704105728.mwb72jebfmok2nm2@zip.com.au
---
src/backend/access/hash/hashpage.c | 45 ++++++++++++++++++++++++++++----------
1 file changed, 34 insertions(+), 11 deletions(-)
(limited to 'src')
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index d5b6502775..08eaf1d7bf 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -956,9 +956,9 @@ restart_expand:
buf_oblkno, buf_nblkno, NULL,
maxbucket, highmask, lowmask);
- /* all done, now release the locks and pins on primary buckets. */
- _hash_relbuf(rel, buf_oblkno);
- _hash_relbuf(rel, buf_nblkno);
+ /* all done, now release the pins on primary buckets. */
+ _hash_dropbuf(rel, buf_oblkno);
+ _hash_dropbuf(rel, buf_nblkno);
return;
@@ -1068,10 +1068,11 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
* while a split is in progress.
*
* In addition, the caller must have created the new bucket's base page,
- * which is passed in buffer nbuf, pinned and write-locked. That lock and
- * pin are released here. (The API is set up this way because we must do
- * _hash_getnewbuf() before releasing the metapage write lock. So instead of
- * passing the new bucket's start block number, we pass an actual buffer.)
+ * which is passed in buffer nbuf, pinned and write-locked. The lock will be
+ * released here and pin must be released by the caller. (The API is set up
+ * this way because we must do _hash_getnewbuf() before releasing the metapage
+ * write lock. So instead of passing the new bucket's start block number, we
+ * pass an actual buffer.)
*/
static void
_hash_splitbucket(Relation rel,
@@ -1280,8 +1281,9 @@ _hash_splitbucket(Relation rel,
/*
* After the split is finished, mark the old bucket to indicate that it
- * contains deletable tuples. Vacuum will clear split-cleanup flag after
- * deleting such tuples.
+ * contains deletable tuples. We will clear split-cleanup flag after
+ * deleting such tuples either at the end of split or at the next split
+ * from old bucket or at the time of vacuum.
*/
oopaque->hasho_flag |= LH_BUCKET_NEEDS_SPLIT_CLEANUP;
@@ -1314,6 +1316,28 @@ _hash_splitbucket(Relation rel,
}
END_CRIT_SECTION();
+
+ /*
+ * If possible, clean up the old bucket. We might not be able to do this
+ * if someone else has a pin on it, but if not then we can go ahead. This
+ * isn't absolutely necessary, but it reduces bloat; if we don't do it now,
+ * VACUUM will do it eventually, but maybe not until new overflow pages
+ * have been allocated. Note that there's no need to clean up the new
+ * bucket.
+ */
+ if (IsBufferCleanupOK(bucket_obuf))
+ {
+ LockBuffer(bucket_nbuf, BUFFER_LOCK_UNLOCK);
+ hashbucketcleanup(rel, obucket, bucket_obuf,
+ BufferGetBlockNumber(bucket_obuf), NULL,
+ maxbucket, highmask, lowmask, NULL, NULL, true,
+ NULL, NULL);
+ }
+ else
+ {
+ LockBuffer(bucket_nbuf, BUFFER_LOCK_UNLOCK);
+ LockBuffer(bucket_obuf, BUFFER_LOCK_UNLOCK);
+ }
}
/*
@@ -1434,8 +1458,7 @@ _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket,
nbucket, obuf, bucket_nbuf, tidhtab,
maxbucket, highmask, lowmask);
- _hash_relbuf(rel, bucket_nbuf);
- LockBuffer(obuf, BUFFER_LOCK_UNLOCK);
+ _hash_dropbuf(rel, bucket_nbuf);
hash_destroy(tidhtab);
}
--
cgit v1.2.3
From 7e174fa793a2df89fe03d002a5087ef67abcdde8 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Fri, 4 Aug 2017 21:14:35 -0400
Subject: Only kill sync workers at commit time in subscription DDL
This allows a transaction abort to avoid killing those workers.
Author: Petr Jelinek
---
src/backend/access/transam/xact.c | 9 ++++
src/backend/commands/subscriptioncmds.c | 28 ++++++++--
src/backend/replication/logical/launcher.c | 83 +++++++++++++++++++++++++++++-
src/include/replication/logicallauncher.h | 1 +
src/include/replication/worker_internal.h | 2 +
5 files changed, 117 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b0aa69fe4b..50c3c3b5e5 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -2277,6 +2277,15 @@ PrepareTransaction(void)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot PREPARE a transaction that has exported snapshots")));
+ /*
+ * Don't allow PREPARE but for transaction that has/might kill logical
+ * replication workers.
+ */
+ if (XactManipulatesLogicalReplicationWorkers())
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot PREPARE a transaction that has manipulated logical replication workers")));
+
/* Prevent cancel/die interrupt while cleaning up */
HOLD_INTERRUPTS();
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 6dc3f6ee00..87824b8fec 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -597,7 +597,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
RemoveSubscriptionRel(sub->oid, relid);
- logicalrep_worker_stop(sub->oid, relid);
+ logicalrep_worker_stop_at_commit(sub->oid, relid);
namespace = get_namespace_name(get_rel_namespace(relid));
ereport(NOTICE,
@@ -819,6 +819,8 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
char *subname;
char *conninfo;
char *slotname;
+ List *subworkers;
+ ListCell *lc;
char originname[NAMEDATALEN];
char *err = NULL;
RepOriginId originid;
@@ -909,15 +911,33 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel)
ReleaseSysCache(tup);
+ /*
+ * If we are dropping the replication slot, stop all the subscription
+ * workers immediately, so that the slot becomes accessible. Otherwise
+ * just schedule the stopping for the end of the transaction.
+ *
+ * New workers won't be started because we hold an exclusive lock on the
+ * subscription till the end of the transaction.
+ */
+ LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
+ subworkers = logicalrep_workers_find(subid, false);
+ LWLockRelease(LogicalRepWorkerLock);
+ foreach (lc, subworkers)
+ {
+ LogicalRepWorker *w = (LogicalRepWorker *) lfirst(lc);
+ if (slotname)
+ logicalrep_worker_stop(w->subid, w->relid);
+ else
+ logicalrep_worker_stop_at_commit(w->subid, w->relid);
+ }
+ list_free(subworkers);
+
/* Clean up dependencies */
deleteSharedDependencyRecordsFor(SubscriptionRelationId, subid, 0);
/* Remove any associated relation synchronization states. */
RemoveSubscriptionRel(subid, InvalidOid);
- /* Kill the apply worker so that the slot becomes accessible. */
- logicalrep_worker_stop(subid, InvalidOid);
-
/* Remove the origin tracking if exists. */
snprintf(originname, sizeof(originname), "pg_%u", subid);
originid = replorigin_by_name(originname, true);
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index d165d518e1..0f9e5755b9 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -73,6 +73,14 @@ typedef struct LogicalRepCtxStruct
LogicalRepCtxStruct *LogicalRepCtx;
+typedef struct LogicalRepWorkerId
+{
+ Oid subid;
+ Oid relid;
+} LogicalRepWorkerId;
+
+static List *on_commit_stop_workers = NIL;
+
static void ApplyLauncherWakeup(void);
static void logicalrep_launcher_onexit(int code, Datum arg);
static void logicalrep_worker_onexit(int code, Datum arg);
@@ -249,6 +257,30 @@ logicalrep_worker_find(Oid subid, Oid relid, bool only_running)
return res;
}
+/*
+ * Similar to logicalrep_worker_find(), but returns list of all workers for
+ * the subscription, instead just one.
+ */
+List *
+logicalrep_workers_find(Oid subid, bool only_running)
+{
+ int i;
+ List *res = NIL;
+
+ Assert(LWLockHeldByMe(LogicalRepWorkerLock));
+
+ /* Search for attached worker for a given subscription id. */
+ for (i = 0; i < max_logical_replication_workers; i++)
+ {
+ LogicalRepWorker *w = &LogicalRepCtx->workers[i];
+
+ if (w->in_use && w->subid == subid && (!only_running || w->proc))
+ res = lappend(res, w);
+ }
+
+ return res;
+}
+
/*
* Start new apply background worker.
*/
@@ -513,6 +545,27 @@ logicalrep_worker_stop(Oid subid, Oid relid)
LWLockRelease(LogicalRepWorkerLock);
}
+/*
+ * Request worker for specified sub/rel to be stopped on commit.
+ */
+void
+logicalrep_worker_stop_at_commit(Oid subid, Oid relid)
+{
+ LogicalRepWorkerId *wid;
+ MemoryContext oldctx;
+
+ /* Make sure we store the info in context that survives until commit. */
+ oldctx = MemoryContextSwitchTo(TopTransactionContext);
+
+ wid = palloc(sizeof(LogicalRepWorkerId));
+ wid->subid = subid;
+ wid->relid = relid;
+
+ on_commit_stop_workers = lappend(on_commit_stop_workers, wid);
+
+ MemoryContextSwitchTo(oldctx);
+}
+
/*
* Wake up (using latch) any logical replication worker for specified sub/rel.
*/
@@ -753,15 +806,41 @@ ApplyLauncherShmemInit(void)
}
}
+/*
+ * Check whether current transaction has manipulated logical replication
+ * workers.
+ */
+bool
+XactManipulatesLogicalReplicationWorkers(void)
+{
+ return (on_commit_stop_workers != NIL);
+}
+
/*
* Wakeup the launcher on commit if requested.
*/
void
AtEOXact_ApplyLauncher(bool isCommit)
{
- if (isCommit && on_commit_launcher_wakeup)
- ApplyLauncherWakeup();
+ if (isCommit)
+ {
+ ListCell *lc;
+ foreach (lc, on_commit_stop_workers)
+ {
+ LogicalRepWorkerId *wid = lfirst(lc);
+ logicalrep_worker_stop(wid->subid, wid->relid);
+ }
+
+ if (on_commit_launcher_wakeup)
+ ApplyLauncherWakeup();
+ }
+
+ /*
+ * No need to pfree on_commit_stop_workers. It was allocated in
+ * transaction memory context, which is going to be cleaned soon.
+ */
+ on_commit_stop_workers = NIL;
on_commit_launcher_wakeup = false;
}
diff --git a/src/include/replication/logicallauncher.h b/src/include/replication/logicallauncher.h
index aac7d326e2..78016c448f 100644
--- a/src/include/replication/logicallauncher.h
+++ b/src/include/replication/logicallauncher.h
@@ -22,6 +22,7 @@ extern Size ApplyLauncherShmemSize(void);
extern void ApplyLauncherShmemInit(void);
extern void ApplyLauncherWakeupAtCommit(void);
+extern bool XactManipulatesLogicalReplicationWorkers(void);
extern void AtEOXact_ApplyLauncher(bool isCommit);
extern bool IsLogicalLauncher(void);
diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h
index 494a3a3d08..7b8728cced 100644
--- a/src/include/replication/worker_internal.h
+++ b/src/include/replication/worker_internal.h
@@ -71,9 +71,11 @@ extern bool in_remote_transaction;
extern void logicalrep_worker_attach(int slot);
extern LogicalRepWorker *logicalrep_worker_find(Oid subid, Oid relid,
bool only_running);
+extern List *logicalrep_workers_find(Oid subid, bool only_running);
extern void logicalrep_worker_launch(Oid dbid, Oid subid, const char *subname,
Oid userid, Oid relid);
extern void logicalrep_worker_stop(Oid subid, Oid relid);
+extern void logicalrep_worker_stop_at_commit(Oid subid, Oid relid);
extern void logicalrep_worker_wakeup(Oid subid, Oid relid);
extern void logicalrep_worker_wakeup_ptr(LogicalRepWorker *worker);
--
cgit v1.2.3
From f85f88bcc270cf12defc34f143456834d8d8c6f8 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Fri, 4 Aug 2017 21:54:28 -0400
Subject: Fix bug in deciding whether to scan newly-attached partition.
If the table being attached had different attribute numbers than the
parent, the old code could incorrectly decide it needed to be scanned.
Amit Langote, reviewed by Ashutosh Bapat
Discussion: http://postgr.es/m/CA+TgmobexgbBr2+Utw-pOMw9uxaBRKRjMW_-mmzKKx9PejPLMg@mail.gmail.com
---
src/backend/commands/tablecmds.c | 40 ++++++++++++++++++---------
src/test/regress/expected/alter_table.out | 45 +++++++++++++++++++++++++++++++
src/test/regress/sql/alter_table.sql | 38 ++++++++++++++++++++++++++
3 files changed, 111 insertions(+), 12 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 7859ef13ac..1b8d4b3d17 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13433,6 +13433,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
bool skip_validate = false;
ObjectAddress address;
const char *trigger_name;
+ bool found_whole_row;
attachrel = heap_openrv(cmd->name, AccessExclusiveLock);
@@ -13613,6 +13614,16 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
partConstraint = (List *) canonicalize_qual((Expr *) partConstraint);
partConstraint = list_make1(make_ands_explicit(partConstraint));
+ /*
+ * Adjust the generated constraint to match this partition's attribute
+ * numbers.
+ */
+ partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
+ rel, &found_whole_row);
+ /* There can never be a whole-row reference here */
+ if (found_whole_row)
+ elog(ERROR, "unexpected whole-row reference found in partition key");
+
/*
* Check if we can do away with having to scan the table being attached to
* validate the partition constraint, by *proving* that the existing
@@ -13712,8 +13723,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
AlteredTableInfo *tab;
Oid part_relid = lfirst_oid(lc);
Relation part_rel;
- Expr *constr;
- bool found_whole_row;
+ List *my_partconstr = partConstraint;
/* Lock already taken */
if (part_relid != RelationGetRelid(attachrel))
@@ -13732,18 +13742,24 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
continue;
}
+ if (part_rel != attachrel)
+ {
+ /*
+ * Adjust the constraint that we constructed above for
+ * attachRel so that it matches this partition's attribute
+ * numbers.
+ */
+ my_partconstr = map_partition_varattnos(my_partconstr, 1,
+ part_rel, attachrel,
+ &found_whole_row);
+ /* There can never be a whole-row reference here */
+ if (found_whole_row)
+ elog(ERROR, "unexpected whole-row reference found in partition key");
+ }
+
/* Grab a work queue entry. */
tab = ATGetQueueEntry(wqueue, part_rel);
-
- /* Adjust constraint to match this partition */
- constr = linitial(partConstraint);
- tab->partition_constraint = (Expr *)
- map_partition_varattnos((List *) constr, 1,
- part_rel, rel,
- &found_whole_row);
- /* There can never be a whole-row reference here */
- if (found_whole_row)
- elog(ERROR, "unexpected whole-row reference found in partition key");
+ tab->partition_constraint = (Expr *) linitial(my_partconstr);
/* keep our lock until commit */
if (part_rel != attachrel)
diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out
index e9fd1aacce..58192d2c6a 100644
--- a/src/test/regress/expected/alter_table.out
+++ b/src/test/regress/expected/alter_table.out
@@ -3347,6 +3347,51 @@ ALTER TABLE part_5 DROP CONSTRAINT check_a;
ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a SET NOT NULL;
ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);
INFO: partition constraint for table "part_5" is implied by existing constraints
+-- Check the case where attnos of the partitioning columns in the table being
+-- attached differs from the parent. It should not affect the constraint-
+-- checking logic that allows to skip the scan.
+CREATE TABLE part_6 (
+ c int,
+ LIKE list_parted2,
+ CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 6)
+);
+ALTER TABLE part_6 DROP c;
+ALTER TABLE list_parted2 ATTACH PARTITION part_6 FOR VALUES IN (6);
+INFO: partition constraint for table "part_6" is implied by existing constraints
+-- Similar to above, but the table being attached is a partitioned table
+-- whose partition has still different attnos for the root partitioning
+-- columns.
+CREATE TABLE part_7 (
+ LIKE list_parted2,
+ CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
+) PARTITION BY LIST (b);
+CREATE TABLE part_7_a_null (
+ c int,
+ d int,
+ e int,
+ LIKE list_parted2, -- 'a' will have attnum = 4
+ CONSTRAINT check_b CHECK (b IS NULL OR b = 'a'),
+ CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
+);
+ALTER TABLE part_7_a_null DROP c, DROP d, DROP e;
+ALTER TABLE part_7 ATTACH PARTITION part_7_a_null FOR VALUES IN ('a', null);
+INFO: partition constraint for table "part_7_a_null" is implied by existing constraints
+ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);
+INFO: partition constraint for table "part_7" is implied by existing constraints
+-- Same example, but check this time that the constraint correctly detects
+-- violating rows
+ALTER TABLE list_parted2 DETACH PARTITION part_7;
+ALTER TABLE part_7 DROP CONSTRAINT check_a; -- thusly, scan won't be skipped
+INSERT INTO part_7 (a, b) VALUES (8, null), (9, 'a');
+SELECT tableoid::regclass, a, b FROM part_7 order by a;
+ tableoid | a | b
+---------------+---+---
+ part_7_a_null | 8 |
+ part_7_a_null | 9 | a
+(2 rows)
+
+ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);
+ERROR: partition constraint is violated by some row
-- check that the table being attached is not already a partition
ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2);
ERROR: "part_2" is already a partition
diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql
index 5dd1402ea6..9a20dd141a 100644
--- a/src/test/regress/sql/alter_table.sql
+++ b/src/test/regress/sql/alter_table.sql
@@ -2178,6 +2178,44 @@ ALTER TABLE part_5 DROP CONSTRAINT check_a;
ALTER TABLE part_5 ADD CONSTRAINT check_a CHECK (a IN (5)), ALTER a SET NOT NULL;
ALTER TABLE list_parted2 ATTACH PARTITION part_5 FOR VALUES IN (5);
+-- Check the case where attnos of the partitioning columns in the table being
+-- attached differs from the parent. It should not affect the constraint-
+-- checking logic that allows to skip the scan.
+CREATE TABLE part_6 (
+ c int,
+ LIKE list_parted2,
+ CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 6)
+);
+ALTER TABLE part_6 DROP c;
+ALTER TABLE list_parted2 ATTACH PARTITION part_6 FOR VALUES IN (6);
+
+-- Similar to above, but the table being attached is a partitioned table
+-- whose partition has still different attnos for the root partitioning
+-- columns.
+CREATE TABLE part_7 (
+ LIKE list_parted2,
+ CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
+) PARTITION BY LIST (b);
+CREATE TABLE part_7_a_null (
+ c int,
+ d int,
+ e int,
+ LIKE list_parted2, -- 'a' will have attnum = 4
+ CONSTRAINT check_b CHECK (b IS NULL OR b = 'a'),
+ CONSTRAINT check_a CHECK (a IS NOT NULL AND a = 7)
+);
+ALTER TABLE part_7_a_null DROP c, DROP d, DROP e;
+ALTER TABLE part_7 ATTACH PARTITION part_7_a_null FOR VALUES IN ('a', null);
+ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);
+
+-- Same example, but check this time that the constraint correctly detects
+-- violating rows
+ALTER TABLE list_parted2 DETACH PARTITION part_7;
+ALTER TABLE part_7 DROP CONSTRAINT check_a; -- thusly, scan won't be skipped
+INSERT INTO part_7 (a, b) VALUES (8, null), (9, 'a');
+SELECT tableoid::regclass, a, b FROM part_7 order by a;
+ALTER TABLE list_parted2 ATTACH PARTITION part_7 FOR VALUES IN (7);
+
-- check that the table being attached is not already a partition
ALTER TABLE list_parted2 ATTACH PARTITION part_2 FOR VALUES IN (2);
--
cgit v1.2.3
From eccead9ed43dc6e653c76dce1d2f455d251bb00c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Tue, 1 Aug 2017 10:49:55 -0400
Subject: Add support for ICU 4.2
Supporting ICU 4.2 seems useful because it ships with CentOS 6.
Versions before ICU 4.6 don't support pkg-config, so document an
installation method without using pkg-config.
In ICU 4.2, ucol_getKeywordsForLocale() sometimes returns values that
will not be accepted by uloc_toLanguageTag(). Skip loading keyword
variants in that version.
Reported-by: Victor Wagner
---
doc/src/sgml/installation.sgml | 22 +++++++++++++++++++---
src/backend/commands/collationcmds.c | 11 +++++++++++
2 files changed, 30 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index fa0d05efe6..12866b4bf7 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -774,10 +774,26 @@ su - postgres
Build with support for
the ICUICU>>
library. This requires the ICU4C package
- as well
- as pkg-configpkg-config>>
to be installed. The minimum required version
- of ICU4C is currently 4.6.
+ of ICU4C is currently 4.2.
+
+
+
+ By default,
+ pkg-configpkg-config>>
+ will be used to find the required compilation options. This is
+ supported for ICU4C version 4.6 and later.
+ For older versions, or if pkg-config is
+ not available, the variables ICU_CFLAGS
+ and ICU_LIBS can be specified
+ to configure, like in this example:
+
+./configure ... --with-icu ICU_CFLAGS='-I/some/where/include' ICU_LIBS='-L/some/where/lib -licui18n -licuuc -licudata'
+
+ (If ICU4C is in the default search path
+ for the compiler, then you still need to specify a nonempty string in
+ order to avoid use of pkg-config, for
+ example, ICU_CFLAGS=' '.)
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index d19a384f9c..ea257a3786 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -722,7 +722,17 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
/*
* Add keyword variants
+ *
+ * In ICU 4.2, ucol_getKeywordsForLocale() sometimes returns
+ * values that will not be accepted by uloc_toLanguageTag(). Skip
+ * loading keyword variants in that version. (Both
+ * ucol_getKeywordValuesForLocale() and uloc_toLanguageTag() are
+ * new in ICU 4.2, so older versions are not supported at all.)
+ *
+ * XXX We have no information about ICU 4.3 through 4.7, but we
+ * know the below works with 4.8.
*/
+#if U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM > 2)
status = U_ZERO_ERROR;
en = ucol_getKeywordValuesForLocale("collation", name, TRUE, &status);
if (U_FAILURE(status))
@@ -769,6 +779,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
(errmsg("could not get keyword values for locale \"%s\": %s",
name, u_errorName(status))));
uenum_close(en);
+#endif /* ICU >4.2 */
}
}
#endif /* USE_ICU */
--
cgit v1.2.3
From 52f8a59dd953c6820baf153e97cf07d31b8ac1d6 Mon Sep 17 00:00:00 2001
From: Robert Haas
Date: Sat, 5 Aug 2017 10:49:26 -0400
Subject: Make pg_stop_backup's wait_for_archive flag work on standbys.
Previously, it had no effect. Now, if archive_mode=always, it will
work, and if not, you'll get a warning.
Masahiko Sawada, Michael Paquier, and Robert Haas. The patch as
submitted also changed the behavior so that we would write and remove
history files on standbys, but that seems like material for a separate
patch to me.
Discussion: http://postgr.es/m/CAD21AoC2Xw6M=ZJyejq_9d_iDkReC_=rpvQRw5QsyzKQdfYpkw@mail.gmail.com
---
doc/src/sgml/backup.sgml | 13 ++--
doc/src/sgml/func.sgml | 7 ++-
src/backend/access/transam/xlog.c | 128 ++++++++++++++++++++------------------
3 files changed, 81 insertions(+), 67 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 7820de931c..0e7c6e2051 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1012,10 +1012,15 @@ SELECT pg_start_backup('label', true);
SELECT pg_stop_backup();
- This terminates the backup mode and performs an automatic switch to
- the next WAL segment. The reason for the switch is to arrange for
- the last WAL segment file written during the backup interval to be
- ready to archive.
+ This function, when called on a primary, terminates the backup mode and
+ performs an automatic switch to the next WAL segment. The reason for the
+ switch is to arrange for the last WAL segment written during the backup
+ interval to be ready to archive. When called on a standby, this function
+ only terminates backup mode. A subsequent WAL segment switch will be
+ needed in order to ensure that all WAL files needed to restore the backup
+ can be archived; if the primary does not have sufficient write activity
+ to trigger one, pg_switch_wal should be executed on
+ the primary.
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 36319222e6..b43ec30a4e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18597,7 +18597,12 @@ postgres=# select pg_start_backup('label_goes_here');
WAL to be archived. This behavior is only useful for backup
software which independently monitors WAL archiving. Otherwise, WAL
required to make the backup consistent might be missing and make the backup
- useless.
+ useless. When this parameter is set to true, pg_stop_backup>
+ will wait for WAL to be archived when archiving is enabled; on the standby,
+ this means that it will wait only when archive_mode = always>.
+ If write activity on the primary is low, it may be useful to run
+ pg_switch_wal> on the primary in order to trigger
+ an immediate segment switch.
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 3654543919..df4843f409 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10880,11 +10880,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* backup. We have no way of checking if pg_control wasn't backed up last
* however.
*
- * We don't force a switch to new WAL file and wait for all the required
- * files to be archived. This is okay if we use the backup to start the
- * standby. But, if it's for an archive recovery, to ensure all the
- * required files are available, a user should wait for them to be
- * archived, or include them into the backup.
+ * We don't force a switch to new WAL file but it is still possible to
+ * wait for all the required files to be archived if waitforarchive is
+ * true. This is okay if we use the backup to start a standby and fetch
+ * the missing WAL using streaming replication. But in the case of an
+ * archive recovery, a user should set waitforarchive to true and wait for
+ * them to be archived to ensure that all the required files are
+ * available.
*
* We return the current minimum recovery point as the backup end
* location. Note that it can be greater than the exact backup end
@@ -10924,66 +10926,65 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
stoppoint = ControlFile->minRecoveryPoint;
stoptli = ControlFile->minRecoveryPointTLI;
LWLockRelease(ControlFileLock);
-
- if (stoptli_p)
- *stoptli_p = stoptli;
- return stoppoint;
}
+ else
+ {
+ /*
+ * Write the backup-end xlog record
+ */
+ XLogBeginInsert();
+ XLogRegisterData((char *) (&startpoint), sizeof(startpoint));
+ stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
+ stoptli = ThisTimeLineID;
- /*
- * Write the backup-end xlog record
- */
- XLogBeginInsert();
- XLogRegisterData((char *) (&startpoint), sizeof(startpoint));
- stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
- stoptli = ThisTimeLineID;
-
- /*
- * Force a switch to a new xlog segment file, so that the backup is valid
- * as soon as archiver moves out the current segment file.
- */
- RequestXLogSwitch(false);
+ /*
+ * Force a switch to a new xlog segment file, so that the backup is
+ * valid as soon as archiver moves out the current segment file.
+ */
+ RequestXLogSwitch(false);
- XLByteToPrevSeg(stoppoint, _logSegNo);
- XLogFileName(stopxlogfilename, ThisTimeLineID, _logSegNo);
+ XLByteToPrevSeg(stoppoint, _logSegNo);
+ XLogFileName(stopxlogfilename, stoptli, _logSegNo);
- /* Use the log timezone here, not the session timezone */
- stamp_time = (pg_time_t) time(NULL);
- pg_strftime(strfbuf, sizeof(strfbuf),
- "%Y-%m-%d %H:%M:%S %Z",
- pg_localtime(&stamp_time, log_timezone));
+ /* Use the log timezone here, not the session timezone */
+ stamp_time = (pg_time_t) time(NULL);
+ pg_strftime(strfbuf, sizeof(strfbuf),
+ "%Y-%m-%d %H:%M:%S %Z",
+ pg_localtime(&stamp_time, log_timezone));
- /*
- * Write the backup history file
- */
- XLByteToSeg(startpoint, _logSegNo);
- BackupHistoryFilePath(histfilepath, ThisTimeLineID, _logSegNo,
- (uint32) (startpoint % XLogSegSize));
- fp = AllocateFile(histfilepath, "w");
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- histfilepath)));
- fprintf(fp, "START WAL LOCATION: %X/%X (file %s)\n",
- (uint32) (startpoint >> 32), (uint32) startpoint, startxlogfilename);
- fprintf(fp, "STOP WAL LOCATION: %X/%X (file %s)\n",
- (uint32) (stoppoint >> 32), (uint32) stoppoint, stopxlogfilename);
- /* transfer remaining lines from label to history file */
- fprintf(fp, "%s", remaining);
- fprintf(fp, "STOP TIME: %s\n", strfbuf);
- if (fflush(fp) || ferror(fp) || FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- histfilepath)));
+ /*
+ * Write the backup history file
+ */
+ XLByteToSeg(startpoint, _logSegNo);
+ BackupHistoryFilePath(histfilepath, stoptli, _logSegNo,
+ (uint32) (startpoint % XLogSegSize));
+ fp = AllocateFile(histfilepath, "w");
+ if (!fp)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not create file \"%s\": %m",
+ histfilepath)));
+ fprintf(fp, "START WAL LOCATION: %X/%X (file %s)\n",
+ (uint32) (startpoint >> 32), (uint32) startpoint, startxlogfilename);
+ fprintf(fp, "STOP WAL LOCATION: %X/%X (file %s)\n",
+ (uint32) (stoppoint >> 32), (uint32) stoppoint, stopxlogfilename);
+ /* transfer remaining lines from label to history file */
+ fprintf(fp, "%s", remaining);
+ fprintf(fp, "STOP TIME: %s\n", strfbuf);
+ if (fflush(fp) || ferror(fp) || FreeFile(fp))
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not write file \"%s\": %m",
+ histfilepath)));
- /*
- * Clean out any no-longer-needed history files. As a side effect, this
- * will post a .ready file for the newly created history file, notifying
- * the archiver that history file may be archived immediately.
- */
- CleanupBackupHistory();
+ /*
+ * Clean out any no-longer-needed history files. As a side effect,
+ * this will post a .ready file for the newly created history file,
+ * notifying the archiver that history file may be archived
+ * immediately.
+ */
+ CleanupBackupHistory();
+ }
/*
* If archiving is enabled, wait for all the required WAL files to be
@@ -11005,13 +11006,16 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* or you can set statement_timeout. Also, some notices are issued to
* clue in anyone who might be doing this interactively.
*/
- if (waitforarchive && XLogArchivingActive())
+
+ if (waitforarchive &&
+ ((!backup_started_in_recovery && XLogArchivingActive()) ||
+ (backup_started_in_recovery && XLogArchivingAlways())))
{
XLByteToPrevSeg(stoppoint, _logSegNo);
- XLogFileName(lastxlogfilename, ThisTimeLineID, _logSegNo);
+ XLogFileName(lastxlogfilename, stoptli, _logSegNo);
XLByteToSeg(startpoint, _logSegNo);
- BackupHistoryFileName(histfilename, ThisTimeLineID, _logSegNo,
+ BackupHistoryFileName(histfilename, stoptli, _logSegNo,
(uint32) (startpoint % XLogSegSize));
seconds_before_warning = 60;
--
cgit v1.2.3
From e9f4ac1389d9fe6b996937e5d308f5ec462cf69a Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sat, 5 Aug 2017 11:48:32 -0400
Subject: Suppress unused-variable warnings when building with ICU 4.2.
Tidy-up for commit eccead9ed.
---
src/backend/commands/collationcmds.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index ea257a3786..ed5ffb6594 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -678,14 +678,30 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
*/
for (i = -1; i < ucol_countAvailable(); i++)
{
+ /*
+ * In ICU 4.2, ucol_getKeywordsForLocale() sometimes returns
+ * values that will not be accepted by uloc_toLanguageTag(). Skip
+ * loading keyword variants in that version. (Both
+ * ucol_getKeywordValuesForLocale() and uloc_toLanguageTag() are
+ * new in ICU 4.2, so older versions are not supported at all.)
+ *
+ * XXX We have no information about ICU 4.3 through 4.7, but we
+ * know the code below works with 4.8.
+ */
+#if U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM > 2)
+#define LOAD_ICU_KEYWORD_VARIANTS
+#endif
+
const char *name;
char *langtag;
char *icucomment;
const char *collcollate;
+ Oid collid;
+#ifdef LOAD_ICU_KEYWORD_VARIANTS
UEnumeration *en;
UErrorCode status;
const char *val;
- Oid collid;
+#endif
if (i == -1)
name = ""; /* ICU root locale */
@@ -721,18 +737,9 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
}
/*
- * Add keyword variants
- *
- * In ICU 4.2, ucol_getKeywordsForLocale() sometimes returns
- * values that will not be accepted by uloc_toLanguageTag(). Skip
- * loading keyword variants in that version. (Both
- * ucol_getKeywordValuesForLocale() and uloc_toLanguageTag() are
- * new in ICU 4.2, so older versions are not supported at all.)
- *
- * XXX We have no information about ICU 4.3 through 4.7, but we
- * know the below works with 4.8.
+ * Add keyword variants, if enabled.
*/
-#if U_ICU_VERSION_MAJOR_NUM > 4 || (U_ICU_VERSION_MAJOR_NUM == 4 && U_ICU_VERSION_MINOR_NUM > 2)
+#ifdef LOAD_ICU_KEYWORD_VARIANTS
status = U_ZERO_ERROR;
en = ucol_getKeywordValuesForLocale("collation", name, TRUE, &status);
if (U_FAILURE(status))
@@ -779,7 +786,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
(errmsg("could not get keyword values for locale \"%s\": %s",
name, u_errorName(status))));
uenum_close(en);
-#endif /* ICU >4.2 */
+#endif /* LOAD_ICU_KEYWORD_VARIANTS */
}
}
#endif /* USE_ICU */
--
cgit v1.2.3
From 5af4456a56472e1928e838c893eb0022f7ab28fb Mon Sep 17 00:00:00 2001
From: Andres Freund
Date: Sat, 5 Aug 2017 20:52:53 -0700
Subject: Fix thinko introduced in 2bef06d516460 et al.
The callers for GetOldestSafeDecodingTransactionId() all inverted the
argument for the argument introduced in 2bef06d516460. Luckily this
appears to be inconsequential for the moment, as we wait for
concurrent in-progress transaction when assembling a
snapshot. Additionally this could only make a difference when adding a
second logical slot, because only a pre-existing slot could cause an
issue by lowering the returned xid dangerously much.
Reported-By: Antonin Houska
Discussion: https://postgr.es/m/32704.1496993134@localhost
Backport: 9.4-, where 2bef06d516460 was backpatched to.
---
src/backend/replication/logical/logical.c | 2 +-
src/backend/replication/logical/snapbuild.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 85721ead3e..efb9785f25 100644
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -288,7 +288,7 @@ CreateInitDecodingContext(char *plugin,
*/
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- xmin_horizon = GetOldestSafeDecodingTransactionId(need_full_snapshot);
+ xmin_horizon = GetOldestSafeDecodingTransactionId(!need_full_snapshot);
slot->effective_catalog_xmin = xmin_horizon;
slot->data.catalog_xmin = xmin_horizon;
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 281b7ab869..153d1712ef 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -574,7 +574,7 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
TransactionId safeXid;
LWLockAcquire(ProcArrayLock, LW_SHARED);
- safeXid = GetOldestSafeDecodingTransactionId(true);
+ safeXid = GetOldestSafeDecodingTransactionId(false);
LWLockRelease(ProcArrayLock);
Assert(TransactionIdPrecedesOrEquals(safeXid, snap->xmin));
--
cgit v1.2.3
From 655727d93bbaf2569281eea07e38b1955bb627b7 Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Sun, 6 Aug 2017 23:26:09 -0400
Subject: Update RELEASE_CHANGES' example of branch name format.
We're planning to put an underscore before the major version number in
branch names for v10 and later. Make sure the recipe in RELEASE_CHANGES
reflects that.
In passing, add a reminder to consider doing pgindent right before
the branch.
Discussion: https://postgr.es/m/E1dAkjZ-0003MG-0U@gemulon.postgresql.org
---
src/tools/RELEASE_CHANGES | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/tools/RELEASE_CHANGES b/src/tools/RELEASE_CHANGES
index dc1b300a35..b7963c2449 100644
--- a/src/tools/RELEASE_CHANGES
+++ b/src/tools/RELEASE_CHANGES
@@ -68,12 +68,14 @@ For Major Releases
Starting a New Development Cycle
================================
+* Typically, we do pgindent and perltidy runs just before branching
+
* Create a branch in git for maintenance of the previous release
o on master branch, do:
git pull # be sure you have the latest "master"
git push origin master:refs/heads/"new-branch-name"
for example,
- git push origin master:refs/heads/REL9_2_STABLE
+ git push origin master:refs/heads/REL_10_STABLE
* Add new branch's name to list in src/tools/git_changelog
--
cgit v1.2.3
From 6f81306e4d1716bdf19aa8629b4004966918c56e Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 7 Aug 2017 09:16:03 -0400
Subject: Downgrade subscription refresh messages to DEBUG1
The NOTICE messages about tables being added or removed during
subscription refresh would be incorrect and possibly confusing if the
transaction rolls back, so silence them but keep them available for
debugging.
Discussion: https://www.postgresql.org/message-id/CAD21AoAvaXizc2h7aiNyK_i0FQSa-tmhpdOGwbhh7Jy544Ad4Q%40mail.gmail.com
---
src/backend/commands/subscriptioncmds.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 87824b8fec..318612f867 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -572,7 +572,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
SetSubscriptionRelState(sub->oid, relid,
copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY,
InvalidXLogRecPtr, false);
- ereport(NOTICE,
+ ereport(DEBUG1,
(errmsg("added subscription for table %s.%s",
quote_identifier(rv->schemaname),
quote_identifier(rv->relname))));
@@ -600,7 +600,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
logicalrep_worker_stop_at_commit(sub->oid, relid);
namespace = get_namespace_name(get_rel_namespace(relid));
- ereport(NOTICE,
+ ereport(DEBUG1,
(errmsg("removed subscription for table %s.%s",
quote_identifier(namespace),
quote_identifier(get_rel_name(relid)))));
--
cgit v1.2.3
From ad2ca3cba6e14dbd7b9f388b1e101cd5e2a2c210 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 7 Aug 2017 09:40:12 -0400
Subject: Improve wording of subscription refresh debug messages
Reported-by: Yugo Nagata
---
src/backend/commands/subscriptioncmds.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
(limited to 'src')
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 318612f867..3593712791 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -573,9 +573,8 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
copy_data ? SUBREL_STATE_INIT : SUBREL_STATE_READY,
InvalidXLogRecPtr, false);
ereport(DEBUG1,
- (errmsg("added subscription for table %s.%s",
- quote_identifier(rv->schemaname),
- quote_identifier(rv->relname))));
+ (errmsg("table \"%s.%s\" added to subscription \"%s\"",
+ rv->schemaname, rv->relname, sub->name)));
}
}
@@ -593,17 +592,15 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data)
if (!bsearch(&relid, pubrel_local_oids,
list_length(pubrel_names), sizeof(Oid), oid_cmp))
{
- char *namespace;
-
RemoveSubscriptionRel(sub->oid, relid);
logicalrep_worker_stop_at_commit(sub->oid, relid);
- namespace = get_namespace_name(get_rel_namespace(relid));
ereport(DEBUG1,
- (errmsg("removed subscription for table %s.%s",
- quote_identifier(namespace),
- quote_identifier(get_rel_name(relid)))));
+ (errmsg("table \"%s.%s\" removed from subscription \"%s\"",
+ get_namespace_name(get_rel_namespace(relid)),
+ get_rel_name(relid),
+ sub->name)));
}
}
}
--
cgit v1.2.3
From 86524f038799db9e18c86df0ea6fb40c8102c0ab Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 7 Aug 2017 09:49:55 -0400
Subject: Fix function name in code comment
Reported-by: Peter Geoghegan
---
src/backend/commands/collationcmds.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index ed5ffb6594..96a6bc9bf0 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -679,7 +679,7 @@ pg_import_system_collations(PG_FUNCTION_ARGS)
for (i = -1; i < ucol_countAvailable(); i++)
{
/*
- * In ICU 4.2, ucol_getKeywordsForLocale() sometimes returns
+ * In ICU 4.2, ucol_getKeywordValuesForLocale() sometimes returns
* values that will not be accepted by uloc_toLanguageTag(). Skip
* loading keyword variants in that version. (Both
* ucol_getKeywordValuesForLocale() and uloc_toLanguageTag() are
--
cgit v1.2.3
From bf6b9e94445610a3d84cf9521032fab993f96fd6 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas
Date: Mon, 7 Aug 2017 17:03:42 +0300
Subject: Don't allow logging in with empty password.
Some authentication methods allowed it, others did not. In the client-side,
libpq does not even try to authenticate with an empty password, which makes
using empty passwords hazardous: an administrator might think that an
account with an empty password cannot be used to log in, because psql
doesn't allow it, and not realize that a different client would in fact
allow it. To clear that confusion and to be be consistent, disallow empty
passwords in all authentication methods.
All the authentication methods that used plaintext authentication over the
wire, except for BSD authentication, already checked that the password
received from the user was not empty. To avoid forgetting it in the future
again, move the check to the recv_password_packet function. That only
forbids using an empty password with plaintext authentication, however.
MD5 and SCRAM need a different fix:
* In stable branches, check that the MD5 hash stored for the user does not
not correspond to an empty string. This adds some overhead to MD5
authentication, because the server needs to compute an extra MD5 hash, but
it is not noticeable in practice.
* In HEAD, modify CREATE and ALTER ROLE to clear the password if an empty
string, or a password hash that corresponds to an empty string, is
specified. The user-visible behavior is the same as in the stable branches,
the user cannot log in, but it seems better to stop the empty password from
entering the system in the first place. Secondly, it is fairly expensive to
check that a SCRAM hash doesn't correspond to an empty string, because
computing a SCRAM hash is much more expensive than an MD5 hash by design,
so better avoid doing that on every authentication.
We could clear the password on CREATE/ALTER ROLE also in stable branches,
but we would still need to check at authentication time, because even if we
prevent empty passwords from being stored in pg_authid, there might be
existing ones there already.
Reported by Jeroen van der Ham, Ben de Graaff and Jelte Fennema.
Security: CVE-2017-7546
---
doc/src/sgml/ref/create_role.sgml | 11 +++++++
src/backend/commands/user.c | 55 +++++++++++++++++++++++++------
src/backend/libpq/auth.c | 60 ++++++++++++++++++++++------------
src/backend/libpq/crypt.c | 8 -----
src/test/regress/expected/password.out | 14 ++++++++
src/test/regress/sql/password.sql | 7 ++++
6 files changed, 117 insertions(+), 38 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/ref/create_role.sgml b/doc/src/sgml/ref/create_role.sgml
index 43f2303b48..4881e54439 100644
--- a/doc/src/sgml/ref/create_role.sgml
+++ b/doc/src/sgml/ref/create_role.sgml
@@ -219,6 +219,17 @@ CREATE ROLE name [ [ WITH ] PASSWORD NULL.
+
+
+ Specifying an empty string will also set the password to null,
+ but that was not the case before PostgreSQL>
+ version 10. In earlier versions, an empty string could be used,
+ or not, depending on the authentication method and the exact
+ version, and libpq would refuse to use it in any case.
+ To avoid the ambiguity, specifying an empty string should be
+ avoided.
+
+
The password is always stored encrypted in the system catalogs. The
ENCRYPTED> keyword has no effect, but is accepted for
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 0a72c2ecb3..f2941352d7 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -384,13 +384,36 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
if (password)
{
- /* Encrypt the password to the requested format. */
char *shadow_pass;
+ char *logdetail;
- shadow_pass = encrypt_password(Password_encryption, stmt->role,
- password);
- new_record[Anum_pg_authid_rolpassword - 1] =
- CStringGetTextDatum(shadow_pass);
+ /*
+ * Don't allow an empty password. Libpq treats an empty password the
+ * same as no password at all, and won't even try to authenticate. But
+ * other clients might, so allowing it would be confusing. By clearing
+ * the password when an empty string is specified, the account is
+ * consistently locked for all clients.
+ *
+ * Note that this only covers passwords stored in the database itself.
+ * There are also checks in the authentication code, to forbid an
+ * empty password from being used with authentication methods that
+ * fetch the password from an external system, like LDAP or PAM.
+ */
+ if (password[0] == '\0' ||
+ plain_crypt_verify(stmt->role, password, "", &logdetail) == STATUS_OK)
+ {
+ ereport(NOTICE,
+ (errmsg("empty string is not a valid password, clearing password")));
+ new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
+ }
+ else
+ {
+ /* Encrypt the password to the requested format. */
+ shadow_pass = encrypt_password(Password_encryption, stmt->role,
+ password);
+ new_record[Anum_pg_authid_rolpassword - 1] =
+ CStringGetTextDatum(shadow_pass);
+ }
}
else
new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
@@ -782,13 +805,25 @@ AlterRole(AlterRoleStmt *stmt)
/* password */
if (password)
{
- /* Encrypt the password to the requested format. */
char *shadow_pass;
+ char *logdetail;
- shadow_pass = encrypt_password(Password_encryption, rolename,
- password);
- new_record[Anum_pg_authid_rolpassword - 1] =
- CStringGetTextDatum(shadow_pass);
+ /* Like in CREATE USER, don't allow an empty password. */
+ if (password[0] == '\0' ||
+ plain_crypt_verify(rolename, password, "", &logdetail) == STATUS_OK)
+ {
+ ereport(NOTICE,
+ (errmsg("empty string is not a valid password, clearing password")));
+ new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
+ }
+ else
+ {
+ /* Encrypt the password to the requested format. */
+ shadow_pass = encrypt_password(Password_encryption, rolename,
+ password);
+ new_record[Anum_pg_authid_rolpassword - 1] =
+ CStringGetTextDatum(shadow_pass);
+ }
new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
}
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index dd7de7c3a4..cb30fc7b71 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -688,6 +688,24 @@ recv_password_packet(Port *port)
(errcode(ERRCODE_PROTOCOL_VIOLATION),
errmsg("invalid password packet size")));
+ /*
+ * Don't allow an empty password. Libpq treats an empty password the same
+ * as no password at all, and won't even try to authenticate. But other
+ * clients might, so allowing it would be confusing.
+ *
+ * Note that this only catches an empty password sent by the client in
+ * plaintext. There's also a check in CREATE/ALTER USER that prevents an
+ * empty string from being stored as a user's password in the first place.
+ * We rely on that for MD5 and SCRAM authentication, but we still need
+ * this check here, to prevent an empty password from being used with
+ * authentication methods that check the password against an external
+ * system, like PAM, LDAP and RADIUS.
+ */
+ if (buf.len == 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PASSWORD),
+ errmsg("empty password returned by client")));
+
/* Do not echo password to logs, for security. */
elog(DEBUG5, "received password packet");
@@ -2081,12 +2099,6 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message **msg,
*/
goto fail;
}
- if (strlen(passwd) == 0)
- {
- ereport(LOG,
- (errmsg("empty password returned by client")));
- goto fail;
- }
}
if ((reply[i].resp = strdup(passwd)) == NULL)
goto fail;
@@ -2277,6 +2289,8 @@ CheckBSDAuth(Port *port, char *user)
*/
retval = auth_userokay(user, NULL, "auth-postgresql", passwd);
+ pfree(passwd);
+
if (!retval)
return STATUS_ERROR;
@@ -2407,16 +2421,12 @@ CheckLDAPAuth(Port *port)
if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */
- if (strlen(passwd) == 0)
- {
- ereport(LOG,
- (errmsg("empty password returned by client")));
- return STATUS_ERROR;
- }
-
if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
+ {
/* Error message already sent */
+ pfree(passwd);
return STATUS_ERROR;
+ }
if (port->hba->ldapbasedn)
{
@@ -2448,6 +2458,7 @@ CheckLDAPAuth(Port *port)
{
ereport(LOG,
(errmsg("invalid character in user name for LDAP authentication")));
+ pfree(passwd);
return STATUS_ERROR;
}
}
@@ -2464,6 +2475,7 @@ CheckLDAPAuth(Port *port)
ereport(LOG,
(errmsg("could not perform initial LDAP bind for ldapbinddn \"%s\" on server \"%s\": %s",
port->hba->ldapbinddn, port->hba->ldapserver, ldap_err2string(r))));
+ pfree(passwd);
return STATUS_ERROR;
}
@@ -2488,6 +2500,7 @@ CheckLDAPAuth(Port *port)
ereport(LOG,
(errmsg("could not search LDAP for filter \"%s\" on server \"%s\": %s",
filter, port->hba->ldapserver, ldap_err2string(r))));
+ pfree(passwd);
pfree(filter);
return STATUS_ERROR;
}
@@ -2508,6 +2521,7 @@ CheckLDAPAuth(Port *port)
count,
filter, port->hba->ldapserver, count)));
+ pfree(passwd);
pfree(filter);
ldap_msgfree(search_message);
return STATUS_ERROR;
@@ -2523,6 +2537,7 @@ CheckLDAPAuth(Port *port)
ereport(LOG,
(errmsg("could not get dn for the first entry matching \"%s\" on server \"%s\": %s",
filter, port->hba->ldapserver, ldap_err2string(error))));
+ pfree(passwd);
pfree(filter);
ldap_msgfree(search_message);
return STATUS_ERROR;
@@ -2543,6 +2558,7 @@ CheckLDAPAuth(Port *port)
ereport(LOG,
(errmsg("could not unbind after searching for user \"%s\" on server \"%s\": %s",
fulluser, port->hba->ldapserver, ldap_err2string(error))));
+ pfree(passwd);
pfree(fulluser);
return STATUS_ERROR;
}
@@ -2553,6 +2569,7 @@ CheckLDAPAuth(Port *port)
*/
if (InitializeLDAPConnection(port, &ldap) == STATUS_ERROR)
{
+ pfree(passwd);
pfree(fulluser);
/* Error message already sent */
@@ -2573,10 +2590,12 @@ CheckLDAPAuth(Port *port)
ereport(LOG,
(errmsg("LDAP login failed for user \"%s\" on server \"%s\": %s",
fulluser, port->hba->ldapserver, ldap_err2string(r))));
+ pfree(passwd);
pfree(fulluser);
return STATUS_ERROR;
}
+ pfree(passwd);
pfree(fulluser);
return STATUS_OK;
@@ -2720,17 +2739,11 @@ CheckRADIUSAuth(Port *port)
if (passwd == NULL)
return STATUS_EOF; /* client wouldn't send password */
- if (strlen(passwd) == 0)
- {
- ereport(LOG,
- (errmsg("empty password returned by client")));
- return STATUS_ERROR;
- }
-
if (strlen(passwd) > RADIUS_MAX_PASSWORD_LENGTH)
{
ereport(LOG,
(errmsg("RADIUS authentication does not support passwords longer than %d characters", RADIUS_MAX_PASSWORD_LENGTH)));
+ pfree(passwd);
return STATUS_ERROR;
}
@@ -2756,9 +2769,15 @@ CheckRADIUSAuth(Port *port)
*------
*/
if (ret == STATUS_OK)
+ {
+ pfree(passwd);
return STATUS_OK;
+ }
else if (ret == STATUS_EOF)
+ {
+ pfree(passwd);
return STATUS_ERROR;
+ }
/*
* secret, port and identifiers either have length 0 (use default),
@@ -2775,6 +2794,7 @@ CheckRADIUSAuth(Port *port)
}
/* No servers left to try, so give up */
+ pfree(passwd);
return STATUS_ERROR;
}
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 0013ee3878..1715c52462 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -71,14 +71,6 @@ get_role_password(const char *role, char **logdetail)
ReleaseSysCache(roleTup);
- if (*shadow_pass == '\0')
- {
- *logdetail = psprintf(_("User \"%s\" has an empty password."),
- role);
- pfree(shadow_pass);
- return NULL; /* empty password */
- }
-
/*
* Password OK, but check to be sure we are not past rolvaliduntil
*/
diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out
index bb25ad0c2c..393d836ead 100644
--- a/src/test/regress/expected/password.out
+++ b/src/test/regress/expected/password.out
@@ -75,11 +75,25 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
regress_passwd5 | md5e73a4b11df52a6068f8b39f90be36023
(5 rows)
+-- An empty password is not allowed, in any form
+CREATE ROLE regress_passwd_empty PASSWORD '';
+NOTICE: empty string is not a valid password, clearing password
+ALTER ROLE regress_passwd_empty PASSWORD 'md585939a5ce845f1a1b620742e3c659e0a';
+NOTICE: empty string is not a valid password, clearing password
+ALTER ROLE regress_passwd_empty PASSWORD 'SCRAM-SHA-256$4096:hpFyHTUsSWcR7O9P$LgZFIt6Oqdo27ZFKbZ2nV+vtnYM995pDh9ca6WSi120=:qVV5NeluNfUPkwm7Vqat25RjSPLkGeoZBQs6wVv+um4=';
+NOTICE: empty string is not a valid password, clearing password
+SELECT rolpassword FROM pg_authid WHERE rolname='regress_passwd_empty';
+ rolpassword
+-------------
+
+(1 row)
+
DROP ROLE regress_passwd1;
DROP ROLE regress_passwd2;
DROP ROLE regress_passwd3;
DROP ROLE regress_passwd4;
DROP ROLE regress_passwd5;
+DROP ROLE regress_passwd_empty;
-- all entries should have been removed
SELECT rolname, rolpassword
FROM pg_authid
diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql
index f168243725..8f8252d127 100644
--- a/src/test/regress/sql/password.sql
+++ b/src/test/regress/sql/password.sql
@@ -59,11 +59,18 @@ SELECT rolname, regexp_replace(rolpassword, '(SCRAM-SHA-256)\$(\d+):([a-zA-Z0-9+
WHERE rolname LIKE 'regress_passwd%'
ORDER BY rolname, rolpassword;
+-- An empty password is not allowed, in any form
+CREATE ROLE regress_passwd_empty PASSWORD '';
+ALTER ROLE regress_passwd_empty PASSWORD 'md585939a5ce845f1a1b620742e3c659e0a';
+ALTER ROLE regress_passwd_empty PASSWORD 'SCRAM-SHA-256$4096:hpFyHTUsSWcR7O9P$LgZFIt6Oqdo27ZFKbZ2nV+vtnYM995pDh9ca6WSi120=:qVV5NeluNfUPkwm7Vqat25RjSPLkGeoZBQs6wVv+um4=';
+SELECT rolpassword FROM pg_authid WHERE rolname='regress_passwd_empty';
+
DROP ROLE regress_passwd1;
DROP ROLE regress_passwd2;
DROP ROLE regress_passwd3;
DROP ROLE regress_passwd4;
DROP ROLE regress_passwd5;
+DROP ROLE regress_passwd_empty;
-- all entries should have been removed
SELECT rolname, rolpassword
--
cgit v1.2.3
From e568e1eee4650227170cf8c64eedb74bafd7d1f0 Mon Sep 17 00:00:00 2001
From: Noah Misch
Date: Mon, 7 Aug 2017 07:09:28 -0700
Subject: Again match pg_user_mappings to
information_schema.user_mapping_options.
Commit 3eefc51053f250837c3115c12f8119d16881a2d7 claimed to make
pg_user_mappings enforce the qualifications user_mapping_options had
been enforcing, but its removal of a longstanding restriction left them
distinct when the current user is the subject of a mapping yet has no
server privileges. user_mapping_options emits no rows for such a
mapping, but pg_user_mappings includes full umoptions. Change
pg_user_mappings to show null for umoptions. Back-patch to 9.2, like
the above commit.
Reviewed by Tom Lane. Reported by Jeff Janes.
Security: CVE-2017-7547
---
doc/src/sgml/catalogs.sgml | 32 +++++++++++++++++++-----
src/backend/catalog/system_views.sql | 4 ++-
src/test/regress/expected/foreign_data.out | 39 +++++++++++++++---------------
src/test/regress/expected/rules.out | 2 +-
src/test/regress/sql/foreign_data.sql | 19 +++++++++------
5 files changed, 61 insertions(+), 35 deletions(-)
(limited to 'src')
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index ea655a10a8..97e5ecf686 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -11099,17 +11099,37 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
text[]
- User mapping specific options, as keyword=value>
- strings. This column will show as null unless the current user
- is the user being mapped, or the mapping is for
- PUBLIC and the current user is the server
- owner, or the current user is a superuser. The intent is
- to protect password information stored as user mapping option.
+ User mapping specific options, as keyword=value> strings
+
+
+ To protect password information stored as a user mapping option,
+ the umoptions column will read as null
+ unless one of the following applies:
+
+
+
+ current user is the user being mapped, and owns the server or
+ holds USAGE> privilege on it
+
+
+
+
+ current user is the server owner and mapping is for PUBLIC>
+
+
+
+
+ current user is a superuser
+
+
+
+
+
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 0fdad0c119..dc40cde424 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -910,7 +910,9 @@ CREATE VIEW pg_user_mappings AS
ELSE
A.rolname
END AS usename,
- CASE WHEN (U.umuser <> 0 AND A.rolname = current_user)
+ CASE WHEN (U.umuser <> 0 AND A.rolname = current_user
+ AND (pg_has_role(S.srvowner, 'USAGE')
+ OR has_server_privilege(S.oid, 'USAGE')))
OR (U.umuser = 0 AND pg_has_role(S.srvowner, 'USAGE'))
OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user)
THEN U.umoptions
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 7f2f529393..927d0189a0 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -1185,10 +1185,11 @@ ERROR: permission denied for foreign-data wrapper foo
ALTER SERVER s9 VERSION '1.1';
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
CREATE USER MAPPING FOR current_user SERVER s9;
+-- We use terse mode to avoid ordering issues in cascade detail output.
+\set VERBOSITY terse
DROP SERVER s9 CASCADE;
NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to user mapping for public on server s9
-drop cascades to user mapping for regress_unprivileged_role on server s9
+\set VERBOSITY default
RESET ROLE;
CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
GRANT USAGE ON FOREIGN SERVER s9 TO regress_unprivileged_role;
@@ -1204,13 +1205,14 @@ ERROR: must be owner of foreign server s9
SET ROLE regress_test_role;
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
CREATE USER MAPPING FOR public SERVER s10 OPTIONS (user 'secret');
-GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
--- owner of server can see option fields
+CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');
+-- owner of server can see some option fields
\deu+
List of user mappings
Server | User name | FDW options
--------+---------------------------+-------------------
s10 | public | ("user" 'secret')
+ s10 | regress_unprivileged_role |
s4 | regress_foreign_data_user |
s5 | regress_test_role | (modified '1')
s6 | regress_test_role |
@@ -1218,15 +1220,16 @@ GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
s8 | regress_foreign_data_user |
s9 | regress_unprivileged_role |
t1 | public | (modified '1')
-(8 rows)
+(9 rows)
RESET ROLE;
--- superuser can see option fields
+-- superuser can see all option fields
\deu+
List of user mappings
Server | User name | FDW options
--------+---------------------------+---------------------
s10 | public | ("user" 'secret')
+ s10 | regress_unprivileged_role | ("user" 'secret')
s4 | regress_foreign_data_user |
s5 | regress_test_role | (modified '1')
s6 | regress_test_role |
@@ -1234,15 +1237,16 @@ RESET ROLE;
s8 | regress_foreign_data_user | (password 'public')
s9 | regress_unprivileged_role |
t1 | public | (modified '1')
-(8 rows)
+(9 rows)
--- unprivileged user cannot see option fields
+-- unprivileged user cannot see any option field
SET ROLE regress_unprivileged_role;
\deu+
List of user mappings
Server | User name | FDW options
--------+---------------------------+-------------
s10 | public |
+ s10 | regress_unprivileged_role |
s4 | regress_foreign_data_user |
s5 | regress_test_role |
s6 | regress_test_role |
@@ -1250,11 +1254,13 @@ SET ROLE regress_unprivileged_role;
s8 | regress_foreign_data_user |
s9 | regress_unprivileged_role |
t1 | public |
-(8 rows)
+(9 rows)
RESET ROLE;
+\set VERBOSITY terse
DROP SERVER s10 CASCADE;
-NOTICE: drop cascades to user mapping for public on server s10
+NOTICE: drop cascades to 2 other objects
+\set VERBOSITY default
-- Triggers
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
BEGIN
@@ -1596,15 +1602,12 @@ Inherits: pt1
Child tables: ct3,
ft3
+\set VERBOSITY terse
DROP FOREIGN TABLE ft2; -- ERROR
ERROR: cannot drop foreign table ft2 because other objects depend on it
-DETAIL: table ct3 depends on foreign table ft2
-foreign table ft3 depends on foreign table ft2
-HINT: Use DROP ... CASCADE to drop the dependent objects too.
DROP FOREIGN TABLE ft2 CASCADE;
NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to table ct3
-drop cascades to foreign table ft3
+\set VERBOSITY default
CREATE FOREIGN TABLE ft2 (
c1 integer NOT NULL,
c2 text,
@@ -2026,16 +2029,12 @@ owner of user mapping for regress_test_role on server s6
DROP SERVER t1 CASCADE;
NOTICE: drop cascades to user mapping for public on server t1
DROP USER MAPPING FOR regress_test_role SERVER s6;
--- This test causes some order dependent cascade detail output,
--- so switch to terse mode for it.
\set VERBOSITY terse
DROP FOREIGN DATA WRAPPER foo CASCADE;
NOTICE: drop cascades to 5 other objects
-\set VERBOSITY default
DROP SERVER s8 CASCADE;
NOTICE: drop cascades to 2 other objects
-DETAIL: drop cascades to user mapping for regress_foreign_data_user on server s8
-drop cascades to user mapping for public on server s8
+\set VERBOSITY default
DROP ROLE regress_test_indirect;
DROP ROLE regress_test_role;
DROP ROLE regress_unprivileged_role; -- ERROR
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 05adfa2376..d582bc9ee4 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -2228,7 +2228,7 @@ pg_user_mappings| SELECT u.oid AS umid,
ELSE a.rolname
END AS usename,
CASE
- WHEN (((u.umuser <> (0)::oid) AND (a.rolname = CURRENT_USER)) OR ((u.umuser = (0)::oid) AND pg_has_role(s.srvowner, 'USAGE'::text)) OR ( SELECT pg_authid.rolsuper
+ WHEN (((u.umuser <> (0)::oid) AND (a.rolname = CURRENT_USER) AND (pg_has_role(s.srvowner, 'USAGE'::text) OR has_server_privilege(s.oid, 'USAGE'::text))) OR ((u.umuser = (0)::oid) AND pg_has_role(s.srvowner, 'USAGE'::text)) OR ( SELECT pg_authid.rolsuper
FROM pg_authid
WHERE (pg_authid.rolname = CURRENT_USER))) THEN u.umoptions
ELSE NULL::text[]
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index 49255e309c..ebe8ffbffe 100644
--- a/src/test/regress/sql/foreign_data.sql
+++ b/src/test/regress/sql/foreign_data.sql
@@ -484,7 +484,10 @@ CREATE SERVER s10 FOREIGN DATA WRAPPER foo; -- ERROR
ALTER SERVER s9 VERSION '1.1';
GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
CREATE USER MAPPING FOR current_user SERVER s9;
+-- We use terse mode to avoid ordering issues in cascade detail output.
+\set VERBOSITY terse
DROP SERVER s9 CASCADE;
+\set VERBOSITY default
RESET ROLE;
CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
GRANT USAGE ON FOREIGN SERVER s9 TO regress_unprivileged_role;
@@ -498,17 +501,19 @@ DROP SERVER s9 CASCADE; -- ERROR
SET ROLE regress_test_role;
CREATE SERVER s10 FOREIGN DATA WRAPPER foo;
CREATE USER MAPPING FOR public SERVER s10 OPTIONS (user 'secret');
-GRANT USAGE ON FOREIGN SERVER s10 TO regress_unprivileged_role;
--- owner of server can see option fields
+CREATE USER MAPPING FOR regress_unprivileged_role SERVER s10 OPTIONS (user 'secret');
+-- owner of server can see some option fields
\deu+
RESET ROLE;
--- superuser can see option fields
+-- superuser can see all option fields
\deu+
--- unprivileged user cannot see option fields
+-- unprivileged user cannot see any option field
SET ROLE regress_unprivileged_role;
\deu+
RESET ROLE;
+\set VERBOSITY terse
DROP SERVER s10 CASCADE;
+\set VERBOSITY default
-- Triggers
CREATE FUNCTION dummy_trigger() RETURNS TRIGGER AS $$
@@ -638,8 +643,10 @@ SELECT relname, conname, contype, conislocal, coninhcount, connoinherit
-- child does not inherit NO INHERIT constraints
\d+ pt1
\d+ ft2
+\set VERBOSITY terse
DROP FOREIGN TABLE ft2; -- ERROR
DROP FOREIGN TABLE ft2 CASCADE;
+\set VERBOSITY default
CREATE FOREIGN TABLE ft2 (
c1 integer NOT NULL,
c2 text,
@@ -784,12 +791,10 @@ DROP SCHEMA foreign_schema CASCADE;
DROP ROLE regress_test_role; -- ERROR
DROP SERVER t1 CASCADE;
DROP USER MAPPING FOR regress_test_role SERVER s6;
--- This test causes some order dependent cascade detail output,
--- so switch to terse mode for it.
\set VERBOSITY terse
DROP FOREIGN DATA WRAPPER foo CASCADE;
-\set VERBOSITY default
DROP SERVER s8 CASCADE;
+\set VERBOSITY default
DROP ROLE regress_test_indirect;
DROP ROLE regress_test_role;
DROP ROLE regress_unprivileged_role; -- ERROR
--
cgit v1.2.3
From 8d9881911f0d30e0783a6bb1363b94a2c817433d Mon Sep 17 00:00:00 2001
From: Tom Lane
Date: Mon, 7 Aug 2017 10:19:01 -0400
Subject: Require update permission for the large object written by lo_put().
lo_put() surely should require UPDATE permission, the same as lowrite(),
but it failed to check for that, as reported by Chapman Flack. Oversight
in commit c50b7c09d; backpatch to 9.4 where that was introduced.
Tom Lane and Michael Paquier
Security: CVE-2017-7548
---
src/backend/libpq/be-fsstubs.c | 12 ++++++++++++
src/test/regress/expected/privileges.out | 10 ++++++++++
src/test/regress/sql/privileges.sql | 4 ++++
3 files changed, 26 insertions(+)
(limited to 'src')
diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c
index b31c90fa24..bf45461b2f 100644
--- a/src/backend/libpq/be-fsstubs.c
+++ b/src/backend/libpq/be-fsstubs.c
@@ -896,6 +896,18 @@ be_lo_put(PG_FUNCTION_ARGS)
CreateFSContext();
loDesc = inv_open(loOid, INV_WRITE, fscxt);
+
+ /* Permission check */
+ if (!lo_compat_privileges &&
+ pg_largeobject_aclcheck_snapshot(loDesc->id,
+ GetUserId(),
+ ACL_UPDATE,
+ loDesc->snapshot) != ACLCHECK_OK)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for large object %u",
+ loDesc->id)));
+
inv_seek(loDesc, offset, SEEK_SET);
written = inv_write(loDesc, VARDATA_ANY(str), VARSIZE_ANY_EXHDR(str));
Assert(written == VARSIZE_ANY_EXHDR(str));
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index da37c4faed..f37df6c709 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -1238,6 +1238,14 @@ SELECT lo_create(2002);
2002
(1 row)
+SELECT loread(lo_open(1001, x'20000'::int), 32); -- allowed, for now
+ loread
+--------
+ \x
+(1 row)
+
+SELECT lowrite(lo_open(1001, x'40000'::int), 'abcd'); -- fail, wrong mode
+ERROR: large object descriptor 0 was not opened for writing
SELECT loread(lo_open(1001, x'40000'::int), 32);
loread
--------
@@ -1333,6 +1341,8 @@ SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied
ERROR: permission denied for large object 1002
SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -- to be denied
ERROR: permission denied for large object 1002
+SELECT lo_put(1002, 1, 'abcd'); -- to be denied
+ERROR: permission denied for large object 1002
SELECT lo_unlink(1002); -- to be denied
ERROR: must be owner of large object 1002
SELECT lo_export(1001, '/dev/null'); -- to be denied
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 5bc47bcd13..e2c13e08a4 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -779,6 +779,9 @@ SET SESSION AUTHORIZATION regress_user2;
SELECT lo_create(2001);
SELECT lo_create(2002);
+SELECT loread(lo_open(1001, x'20000'::int), 32); -- allowed, for now
+SELECT lowrite(lo_open(1001, x'40000'::int), 'abcd'); -- fail, wrong mode
+
SELECT loread(lo_open(1001, x'40000'::int), 32);
SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied
SELECT loread(lo_open(1003, x'40000'::int), 32);
@@ -818,6 +821,7 @@ SET SESSION AUTHORIZATION regress_user4;
SELECT loread(lo_open(1002, x'40000'::int), 32); -- to be denied
SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied
SELECT lo_truncate(lo_open(1002, x'20000'::int), 10); -- to be denied
+SELECT lo_put(1002, 1, 'abcd'); -- to be denied
SELECT lo_unlink(1002); -- to be denied
SELECT lo_export(1001, '/dev/null'); -- to be denied
--
cgit v1.2.3
From 0e58455dd48ca9cbc9987c47b8297d10f1c307b0 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 7 Aug 2017 10:28:35 -0400
Subject: Fix handling of dropped columns in logical replication
The relation attribute map was not initialized for dropped columns,
leading to errors later on.
Author: Petr Jelinek
Reported-by: Scott Milliken
Bug: #14769
---
src/backend/replication/logical/relation.c | 3 +++
1 file changed, 3 insertions(+)
(limited to 'src')
diff --git a/src/backend/replication/logical/relation.c b/src/backend/replication/logical/relation.c
index 7779857456..a7ea16d714 100644
--- a/src/backend/replication/logical/relation.c
+++ b/src/backend/replication/logical/relation.c
@@ -280,7 +280,10 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
int attnum;
if (desc->attrs[i]->attisdropped)
+ {
+ entry->attrmap[i] = -1;
continue;
+ }
attnum = logicalrep_rel_att_by_name(remoterel,
NameStr(desc->attrs[i]->attname));
--
cgit v1.2.3
From fca17a933b4b3cedcd41f14b0fe4d3fb439ea4a4 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 7 Aug 2017 10:49:08 -0400
Subject: Fix local/remote attribute mix-up in logical replication
This would lead to failures if local and remote tables have a different
column order. The tests previously didn't catch that because they only
tested the initial data copy. So add another test that exercises the
apply worker.
Author: Petr Jelinek
---
src/backend/replication/logical/worker.c | 3 ++-
src/test/subscription/t/001_rep_changes.pl | 5 ++++-
2 files changed, 6 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 0d48dfa494..7c2df57645 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -402,7 +402,8 @@ slot_modify_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel,
errarg.attnum = remoteattnum;
getTypeInputInfo(att->atttypid, &typinput, &typioparam);
- slot->tts_values[i] = OidInputFunctionCall(typinput, values[i],
+ slot->tts_values[i] = OidInputFunctionCall(typinput,
+ values[remoteattnum],
typioparam,
att->atttypmod);
slot->tts_isnull[i] = false;
diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl
index a63c679848..268808da7d 100644
--- a/src/test/subscription/t/001_rep_changes.pl
+++ b/src/test/subscription/t/001_rep_changes.pl
@@ -89,6 +89,8 @@ $node_publisher->safe_psql('postgres',
$node_publisher->safe_psql('postgres', "DELETE FROM tab_rep WHERE a > 20");
$node_publisher->safe_psql('postgres', "UPDATE tab_rep SET a = -a");
+$node_publisher->safe_psql('postgres', "INSERT INTO tab_mixed VALUES (2, 'bar')");
+
$node_publisher->poll_query_until('postgres', $caughtup_query)
or die "Timed out while waiting for subscriber to catch up";
@@ -102,7 +104,8 @@ is($result, qq(20|-20|-1), 'check replicated changes on subscriber');
$result = $node_subscriber->safe_psql('postgres',
"SELECT c, b, a FROM tab_mixed");
-is($result, qq(|foo|1), 'check replicated changes with different column order');
+is($result, qq(|foo|1
+|bar|2), 'check replicated changes with different column order');
# insert some duplicate rows
$node_publisher->safe_psql('postgres',
--
cgit v1.2.3
From f7668b2b3532b627ec951e1f0a28944f30cc4a1b Mon Sep 17 00:00:00 2001
From: Peter Eisentraut
Date: Mon, 7 Aug 2017 13:55:34 -0400
Subject: Translation updates
Source-Git-URL: git://git.postgresql.org/git/pgtranslation/messages.git
Source-Git-Hash: 1a0b5e655d7871506c2b1c7ba562c2de6b6a55de
---
src/backend/po/es.po | 4 +-
src/backend/po/fr.po | 14696 +++++++++++++++++++--------------
src/bin/initdb/po/es.po | 4 +-
src/bin/initdb/po/sv.po | 790 +-
src/bin/pg_archivecleanup/nls.mk | 2 +-
src/bin/pg_archivecleanup/po/de.po | 173 +
src/bin/pg_archivecleanup/po/es.po | 2 +-
src/bin/pg_archivecleanup/po/sv.po | 176 +
src/bin/pg_basebackup/nls.mk | 2 +-
src/bin/pg_basebackup/po/de.po | 241 +-
src/bin/pg_basebackup/po/es.po | 4 +-
src/bin/pg_basebackup/po/fr.po | 312 +-
src/bin/pg_basebackup/po/he.po | 1405 ++++
src/bin/pg_config/nls.mk | 2 +-
src/bin/pg_config/po/es.po | 4 +-
src/bin/pg_config/po/he.po | 316 +
src/bin/pg_config/po/sv.po | 103 +-
src/bin/pg_controldata/po/de.po | 9 +-
src/bin/pg_controldata/po/es.po | 4 +-
src/bin/pg_controldata/po/sv.po | 256 +-
src/bin/pg_ctl/nls.mk | 2 +-
src/bin/pg_ctl/po/de.po | 412 +-
src/bin/pg_ctl/po/es.po | 342 +-
src/bin/pg_ctl/po/he.po | 884 ++
src/bin/pg_ctl/po/sv.po | 606 +-
src/bin/pg_dump/nls.mk | 2 +-
src/bin/pg_dump/po/de.po | 440 +-
src/bin/pg_dump/po/es.po | 227 +-
src/bin/pg_dump/po/fr.po | 460 +-
src/bin/pg_dump/po/sv.po | 2920 +++++++
src/bin/pg_resetwal/po/de.po | 267 +-
src/bin/pg_resetwal/po/es.po | 13 +-
src/bin/pg_resetwal/po/sv.po | 396 +-
src/bin/pg_rewind/nls.mk | 2 +-
src/bin/pg_rewind/po/es.po | 17 +-
src/bin/pg_rewind/po/fr.po | 62 +-
src/bin/pg_rewind/po/sv.po | 880 ++
src/bin/pg_test_fsync/nls.mk | 2 +-
src/bin/pg_test_fsync/po/es.po | 2 +-
src/bin/pg_test_fsync/po/sv.po | 176 +
src/bin/pg_test_timing/nls.mk | 2 +-
src/bin/pg_test_timing/po/es.po | 2 +-
src/bin/pg_test_timing/po/fr.po | 10 +-
src/bin/pg_test_timing/po/sv.po | 77 +
src/bin/pg_upgrade/nls.mk | 2 +-
src/bin/pg_upgrade/po/fr.po | 1631 ++++
src/bin/pg_waldump/nls.mk | 2 +-
src/bin/pg_waldump/po/es.po | 2 +-
src/bin/pg_waldump/po/sv.po | 246 +
src/bin/psql/nls.mk | 2 +-
src/bin/psql/po/es.po | 4 +-
src/bin/psql/po/fr.po | 957 ++-
src/bin/psql/po/sv.po | 7450 +++++++++++++++++
src/bin/scripts/po/es.po | 40 +-
src/bin/scripts/po/sv.po | 719 +-
src/interfaces/ecpg/ecpglib/po/es.po | 4 +-
src/interfaces/ecpg/preproc/po/es.po | 4 +-
src/interfaces/libpq/nls.mk | 2 +-
src/interfaces/libpq/po/de.po | 272 +-
src/interfaces/libpq/po/es.po | 185 +-
src/interfaces/libpq/po/fr.po | 236 +-
src/interfaces/libpq/po/he.po | 1087 +++
src/interfaces/libpq/po/sv.po | 1173 +++
src/pl/plperl/po/es.po | 4 +-
src/pl/plperl/po/sv.po | 160 +-
src/pl/plpgsql/src/nls.mk | 2 +-
src/pl/plpgsql/src/po/es.po | 4 +-
src/pl/plpgsql/src/po/sv.po | 820 ++
src/pl/plpython/nls.mk | 2 +-
src/pl/plpython/po/de.po | 117 +-
src/pl/plpython/po/es.po | 4 +-
src/pl/plpython/po/sv.po | 464 ++
src/pl/tcl/nls.mk | 2 +-
src/pl/tcl/po/es.po | 4 +-
src/pl/tcl/po/sv.po | 105 +
75 files changed, 32377 insertions(+), 10037 deletions(-)
create mode 100644 src/bin/pg_archivecleanup/po/de.po
create mode 100644 src/bin/pg_archivecleanup/po/sv.po
create mode 100644 src/bin/pg_basebackup/po/he.po
create mode 100644 src/bin/pg_config/po/he.po
create mode 100644 src/bin/pg_ctl/po/he.po
create mode 100644 src/bin/pg_dump/po/sv.po
create mode 100644 src/bin/pg_rewind/po/sv.po
create mode 100644 src/bin/pg_test_fsync/po/sv.po
create mode 100644 src/bin/pg_test_timing/po/sv.po
create mode 100644 src/bin/pg_upgrade/po/fr.po
create mode 100644 src/bin/pg_waldump/po/sv.po
create mode 100644 src/bin/psql/po/sv.po
create mode 100644 src/interfaces/libpq/po/he.po
create mode 100644 src/interfaces/libpq/po/sv.po
create mode 100644 src/pl/plpgsql/src/po/sv.po
create mode 100644 src/pl/plpython/po/sv.po
create mode 100644 src/pl/tcl/po/sv.po
(limited to 'src')
diff --git a/src/backend/po/es.po b/src/backend/po/es.po
index 1e98ded782..e1efe9ca38 100644
--- a/src/backend/po/es.po
+++ b/src/backend/po/es.po
@@ -56,10 +56,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: PostgreSQL server 9.6\n"
+"Project-Id-Version: PostgreSQL server 10\n"
"Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n"
"POT-Creation-Date: 2017-07-05 15:09+0000\n"
-"PO-Revision-Date: 2017-05-27 21:42-0400\n"
+"PO-Revision-Date: 2017-07-10 12:14-0400\n"
"Last-Translator: Álvaro Herrera \n"
"Language-Team: PgSQL Español \n"
"Language: es\n"
diff --git a/src/backend/po/fr.po b/src/backend/po/fr.po
index c70937040c..a375bc57cb 100644
--- a/src/backend/po/fr.po
+++ b/src/backend/po/fr.po
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PostgreSQL 9.6\n"
"Report-Msgid-Bugs-To: pgsql-bugs@postgresql.org\n"
-"POT-Creation-Date: 2017-02-06 16:08+0000\n"
-"PO-Revision-Date: 2017-02-06 19:01+0100\n"
+"POT-Creation-Date: 2017-08-04 02:39+0000\n"
+"PO-Revision-Date: 2017-08-04 20:59+0200\n"
"Last-Translator: Guillaume Lelarge \n"
"Language-Team: French \n"
"Language: fr\n"
@@ -17,57 +17,38 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 1.8.11\n"
+"X-Generator: Poedit 2.0.2\n"
-#: ../common/config_info.c:131 ../common/config_info.c:139 ../common/config_info.c:147 ../common/config_info.c:155 ../common/config_info.c:163 ../common/config_info.c:171 ../common/config_info.c:179 ../common/config_info.c:187 ../common/config_info.c:195
+#: ../common/config_info.c:130 ../common/config_info.c:138 ../common/config_info.c:146 ../common/config_info.c:154 ../common/config_info.c:162 ../common/config_info.c:170 ../common/config_info.c:178 ../common/config_info.c:186 ../common/config_info.c:194
msgid "not recorded"
msgstr "non enregistré"
-#: ../common/controldata_utils.c:52 commands/copy.c:2833 commands/extension.c:3141 utils/adt/genfile.c:134
+#: ../common/controldata_utils.c:57 commands/copy.c:3117 commands/extension.c:3330 utils/adt/genfile.c:135
#, c-format
msgid "could not open file \"%s\" for reading: %m"
msgstr "n'a pas pu ouvrir le fichier « %s » pour une lecture : %m"
-#: ../common/controldata_utils.c:56
+#: ../common/controldata_utils.c:61
#, c-format
msgid "%s: could not open file \"%s\" for reading: %s\n"
msgstr "%s : n'a pas pu ouvrir le fichier « %s » en lecture : %s\n"
-#: ../common/controldata_utils.c:66 access/transam/timeline.c:346 access/transam/xlog.c:3220 access/transam/xlog.c:10423 access/transam/xlog.c:10436 access/transam/xlog.c:10828 access/transam/xlog.c:10871 access/transam/xlog.c:10910 access/transam/xlog.c:10953 access/transam/xlogfuncs.c:665 access/transam/xlogfuncs.c:684 commands/extension.c:3151 replication/logical/origin.c:665 replication/logical/origin.c:695
-#: replication/logical/reorderbuffer.c:3099 replication/walsender.c:499 storage/file/copydir.c:176 utils/adt/genfile.c:151
+#: ../common/controldata_utils.c:71 access/transam/timeline.c:348 access/transam/xlog.c:3384 access/transam/xlog.c:10787 access/transam/xlog.c:10800 access/transam/xlog.c:11192 access/transam/xlog.c:11235 access/transam/xlog.c:11274 access/transam/xlog.c:11317 access/transam/xlogfuncs.c:668 access/transam/xlogfuncs.c:687 commands/extension.c:3340 libpq/hba.c:499 replication/logical/origin.c:661 replication/logical/origin.c:691
+#: replication/logical/reorderbuffer.c:3064 replication/walsender.c:506 storage/file/copydir.c:178 utils/adt/genfile.c:152 utils/adt/misc.c:924
#, c-format
msgid "could not read file \"%s\": %m"
msgstr "n'a pas pu lire le fichier « %s » : %m"
-#: ../common/controldata_utils.c:69
+#: ../common/controldata_utils.c:74
#, c-format
msgid "%s: could not read file \"%s\": %s\n"
msgstr "%s : n'a pas pu lire le fichier « %s » : %s\n"
-#: ../common/controldata_utils.c:86
-msgid "calculated CRC checksum does not match value stored in file"
-msgstr "la somme de contrôle CRC calculée ne correspond par à la valeur enregistrée dans le fichier"
-
-#: ../common/controldata_utils.c:88
-#, c-format
-msgid ""
-"WARNING: Calculated CRC checksum does not match value stored in file.\n"
-"Either the file is corrupt, or it has a different layout than this program\n"
-"is expecting. The results below are untrustworthy.\n"
-"\n"
-msgstr ""
-"ATTENTION : Les sommes de contrôle (CRC) calculées ne correspondent pas aux\n"
-"valeurs stockées dans le fichier.\n"
-"Soit le fichier est corrompu, soit son organisation diffère de celle\n"
-"attendue par le programme.\n"
-"Les résultats ci-dessous ne sont pas dignes de confiance.\n"
-"\n"
-
-#: ../common/controldata_utils.c:97
+#: ../common/controldata_utils.c:95
msgid "byte ordering mismatch"
msgstr "différence de l'ordre des octets"
-#: ../common/controldata_utils.c:99
+#: ../common/controldata_utils.c:97
#, c-format
msgid ""
"WARNING: possible byte ordering mismatch\n"
@@ -116,7 +97,7 @@ msgstr "n'a pas pu lire le lien symbolique « %s »"
msgid "pclose failed: %s"
msgstr "échec de pclose : %s"
-#: ../common/fe_memutils.c:35 ../common/fe_memutils.c:75 ../common/fe_memutils.c:98 ../common/psprintf.c:181 ../port/path.c:632 ../port/path.c:670 ../port/path.c:687
+#: ../common/fe_memutils.c:35 ../common/fe_memutils.c:75 ../common/fe_memutils.c:98 ../common/psprintf.c:181 ../port/path.c:632 ../port/path.c:670 ../port/path.c:687 utils/misc/ps_status.c:171 utils/misc/ps_status.c:179 utils/misc/ps_status.c:209 utils/misc/ps_status.c:217
#, c-format
msgid "out of memory\n"
msgstr "mémoire épuisée\n"
@@ -126,6 +107,36 @@ msgstr "mémoire épuisée\n"
msgid "cannot duplicate null pointer (internal error)\n"
msgstr "ne peut pas dupliquer un pointeur nul (erreur interne)\n"
+#: ../common/file_utils.c:82 ../common/file_utils.c:186
+#, c-format
+msgid "%s: could not stat file \"%s\": %s\n"
+msgstr "%s : n'a pas pu récupérer les informations sur le fichier « %s » : %s\n"
+
+#: ../common/file_utils.c:162
+#, c-format
+msgid "%s: could not open directory \"%s\": %s\n"
+msgstr "%s : n'a pas pu ouvrir le répertoire « %s » : %s\n"
+
+#: ../common/file_utils.c:198
+#, c-format
+msgid "%s: could not read directory \"%s\": %s\n"
+msgstr "%s : n'a pas pu lire le répertoire « %s » : %s\n"
+
+#: ../common/file_utils.c:231 ../common/file_utils.c:291 ../common/file_utils.c:367
+#, c-format
+msgid "%s: could not open file \"%s\": %s\n"
+msgstr "%s : n'a pas pu ouvrir le fichier « %s » : %s\n"
+
+#: ../common/file_utils.c:304 ../common/file_utils.c:376
+#, c-format
+msgid "%s: could not fsync file \"%s\": %s\n"
+msgstr "%s : n'a pas pu synchroniser sur disque le fichier « %s » : %s\n"
+
+#: ../common/file_utils.c:387
+#, c-format
+msgid "%s: could not rename file \"%s\" to \"%s\": %s\n"
+msgstr "%s : n'a pas pu renommer le fichier « %s » en « %s » : %s\n"
+
#: ../common/pgfnames.c:45
#, c-format
msgid "could not open directory \"%s\": %s\n"
@@ -141,10 +152,10 @@ msgstr "n'a pas pu lire le répertoire « %s » : %s\n"
msgid "could not close directory \"%s\": %s\n"
msgstr "n'a pas pu fermer le répertoire « %s » : %s\n"
-#: ../common/psprintf.c:179 ../port/path.c:630 ../port/path.c:668 ../port/path.c:685 access/transam/twophase.c:1262 access/transam/xlog.c:6108 lib/stringinfo.c:258 libpq/auth.c:850 libpq/auth.c:1213 libpq/auth.c:1281 libpq/auth.c:1797 postmaster/bgworker.c:289 postmaster/bgworker.c:796 postmaster/postmaster.c:2335 postmaster/postmaster.c:2366 postmaster/postmaster.c:3899 postmaster/postmaster.c:4589 postmaster/postmaster.c:4664
-#: postmaster/postmaster.c:5339 postmaster/postmaster.c:5603 replication/libpqwalreceiver/libpqwalreceiver.c:143 replication/logical/logical.c:168 storage/buffer/localbuf.c:436 storage/file/fd.c:729 storage/file/fd.c:1126 storage/file/fd.c:1244 storage/file/fd.c:1916 storage/ipc/procarray.c:1061 storage/ipc/procarray.c:1547 storage/ipc/procarray.c:1554 storage/ipc/procarray.c:1968 storage/ipc/procarray.c:2571 utils/adt/formatting.c:1522
-#: utils/adt/formatting.c:1642 utils/adt/formatting.c:1763 utils/adt/pg_locale.c:463 utils/adt/pg_locale.c:647 utils/adt/regexp.c:219 utils/adt/varlena.c:4440 utils/adt/varlena.c:4461 utils/fmgr/dfmgr.c:216 utils/hash/dynahash.c:429 utils/hash/dynahash.c:535 utils/hash/dynahash.c:1047 utils/mb/mbutils.c:376 utils/mb/mbutils.c:709 utils/misc/guc.c:3888 utils/misc/guc.c:3904 utils/misc/guc.c:3917 utils/misc/guc.c:6863 utils/misc/tzparser.c:468
-#: utils/mmgr/aset.c:509 utils/mmgr/mcxt.c:767 utils/mmgr/mcxt.c:802 utils/mmgr/mcxt.c:839 utils/mmgr/mcxt.c:876 utils/mmgr/mcxt.c:910 utils/mmgr/mcxt.c:939 utils/mmgr/mcxt.c:973 utils/mmgr/mcxt.c:1055 utils/mmgr/mcxt.c:1089 utils/mmgr/mcxt.c:1138
+#: ../common/psprintf.c:179 ../port/path.c:630 ../port/path.c:668 ../port/path.c:685 access/transam/twophase.c:1306 access/transam/xlog.c:6355 lib/stringinfo.c:258 libpq/auth.c:1108 libpq/auth.c:1474 libpq/auth.c:1542 libpq/auth.c:2058 postmaster/bgworker.c:337 postmaster/bgworker.c:908 postmaster/postmaster.c:2391 postmaster/postmaster.c:2413 postmaster/postmaster.c:3975 postmaster/postmaster.c:4683 postmaster/postmaster.c:4758
+#: postmaster/postmaster.c:5436 postmaster/postmaster.c:5773 replication/libpqwalreceiver/libpqwalreceiver.c:251 replication/logical/logical.c:170 storage/buffer/localbuf.c:436 storage/file/fd.c:773 storage/file/fd.c:1201 storage/file/fd.c:1319 storage/file/fd.c:2044 storage/ipc/procarray.c:1057 storage/ipc/procarray.c:1545 storage/ipc/procarray.c:1552 storage/ipc/procarray.c:1969 storage/ipc/procarray.c:2580 utils/adt/formatting.c:1579
+#: utils/adt/formatting.c:1703 utils/adt/formatting.c:1828 utils/adt/pg_locale.c:468 utils/adt/pg_locale.c:652 utils/adt/regexp.c:219 utils/adt/varlena.c:4585 utils/adt/varlena.c:4606 utils/fmgr/dfmgr.c:221 utils/hash/dynahash.c:444 utils/hash/dynahash.c:553 utils/hash/dynahash.c:1065 utils/mb/mbutils.c:376 utils/mb/mbutils.c:709 utils/misc/guc.c:3998 utils/misc/guc.c:4014 utils/misc/guc.c:4027 utils/misc/guc.c:6976 utils/misc/tzparser.c:468
+#: utils/mmgr/aset.c:404 utils/mmgr/dsa.c:713 utils/mmgr/dsa.c:795 utils/mmgr/mcxt.c:725 utils/mmgr/mcxt.c:760 utils/mmgr/mcxt.c:797 utils/mmgr/mcxt.c:834 utils/mmgr/mcxt.c:868 utils/mmgr/mcxt.c:897 utils/mmgr/mcxt.c:931 utils/mmgr/mcxt.c:982 utils/mmgr/mcxt.c:1016 utils/mmgr/mcxt.c:1050
#, c-format
msgid "out of memory"
msgstr "mémoire épuisée"
@@ -206,66 +217,66 @@ msgstr ""
msgid "could not remove file or directory \"%s\": %s\n"
msgstr "n'a pas pu supprimer le fichier ou répertoire « %s » : %s\n"
-#: ../common/username.c:45
+#: ../common/saslprep.c:1090
+#, c-format
+msgid "password too long"
+msgstr "mot de passe trop long"
+
+#: ../common/username.c:43
#, c-format
msgid "could not look up effective user ID %ld: %s"
msgstr "n'a pas pu trouver l'identifiant réel %ld de l'utilisateur : %s"
-#: ../common/username.c:47 libpq/auth.c:1744
+#: ../common/username.c:45 libpq/auth.c:2005
msgid "user does not exist"
msgstr "l'utilisateur n'existe pas"
-#: ../common/username.c:62
+#: ../common/username.c:60
#, c-format
msgid "user name lookup failure: error code %lu"
msgstr "échec de la recherche du nom d'utilisateur : code d'erreur %lu"
-#: ../common/wait_error.c:47
+#: ../common/wait_error.c:45
#, c-format
msgid "command not executable"
msgstr "commande non exécutable"
-#: ../common/wait_error.c:51
+#: ../common/wait_error.c:49
#, c-format
msgid "command not found"
msgstr "commande introuvable"
-#: ../common/wait_error.c:56
+#: ../common/wait_error.c:54
#, c-format
msgid "child process exited with exit code %d"
msgstr "le processus fils a quitté avec le code de sortie %d"
-#: ../common/wait_error.c:63
+#: ../common/wait_error.c:61
#, c-format
msgid "child process was terminated by exception 0x%X"
msgstr "le processus fils a été terminé par l'exception 0x%X"
-#: ../common/wait_error.c:73
+#: ../common/wait_error.c:71
#, c-format
msgid "child process was terminated by signal %s"
msgstr "le processus fils a été terminé par le signal %s"
-#: ../common/wait_error.c:77
+#: ../common/wait_error.c:75
#, c-format
msgid "child process was terminated by signal %d"
msgstr "le processus fils a été terminé par le signal %d"
-#: ../common/wait_error.c:82
+#: ../common/wait_error.c:80
#, c-format
msgid "child process exited with unrecognized status %d"
msgstr "le processus fils a quitté avec un statut %d non reconnu"
-#: ../port/chklocale.c:293
+#: ../port/chklocale.c:288
#, c-format
msgid "could not determine encoding for codeset \"%s\""
msgstr "n'a pas pu déterminer l'encodage pour le codeset « %s »"
-#: ../port/chklocale.c:294 ../port/chklocale.c:423 postmaster/postmaster.c:4868
-#, c-format
-msgid "Please report this to ."
-msgstr "Veuillez rapporter ceci à ."
-
-#: ../port/chklocale.c:415 ../port/chklocale.c:421
+#: ../port/chklocale.c:409 ../port/chklocale.c:415
#, c-format
msgid "could not determine encoding for locale \"%s\": codeset is \"%s\""
msgstr "n'a pas pu déterminer l'encodage pour la locale « %s » : le codeset vaut « %s »"
@@ -290,25 +301,25 @@ msgstr "n'a pas pu obtenir la jonction pour « %s » : %s"
msgid "could not get junction for \"%s\": %s\n"
msgstr "n'a pas pu obtenir la jonction pour « %s » : %s\n"
-#: ../port/open.c:112
+#: ../port/open.c:111
#, c-format
msgid "could not open file \"%s\": %s"
msgstr "n'a pas pu ouvrir le fichier « %s » : %s"
-#: ../port/open.c:113
+#: ../port/open.c:112
msgid "lock violation"
msgstr "violation du verrou"
-#: ../port/open.c:113
+#: ../port/open.c:112
msgid "sharing violation"
msgstr "violation du partage"
-#: ../port/open.c:114
+#: ../port/open.c:113
#, c-format
msgid "Continuing to retry for 30 seconds."
msgstr "Continue à tenter pendant 30 secondes."
-#: ../port/open.c:115
+#: ../port/open.c:114
#, c-format
msgid "You might have antivirus, backup, or similar software interfering with the database system."
msgstr ""
@@ -325,101 +336,116 @@ msgstr "n'a pas pu obtenir le répertoire de travail : %s\n"
msgid "unrecognized error %d"
msgstr "erreur %d non reconnue"
-#: ../port/win32security.c:68
-#, c-format
-msgid "could not open process token: error code %lu\n"
-msgstr "n'a pas pu ouvrir le jeton du processus : code d'erreur %lu\n"
-
-#: ../port/win32security.c:89
+#: ../port/win32security.c:62
#, c-format
msgid "could not get SID for Administrators group: error code %lu\n"
msgstr "n'a pas pu obtenir le SID du groupe d'administrateurs : code d'erreur %lu\n"
-#: ../port/win32security.c:99
+#: ../port/win32security.c:72
#, c-format
msgid "could not get SID for PowerUsers group: error code %lu\n"
msgstr ""
"n'a pas pu obtenir le SID du groupe des utilisateurs avec pouvoir :\n"
"code d'erreur %lu\n"
-#: access/brin/brin.c:810
+#: ../port/win32security.c:80
+#, c-format
+msgid "could not check access token membership: error code %lu\n"
+msgstr "n'a pas pu vérifier l'appartenance du jeton d'accès : code d'erreur %lu\n"
+
+#: access/brin/brin.c:867 access/brin/brin.c:938
+#, c-format
+msgid "block number out of range: %s"
+msgstr "numéro de bloc en dehors des limites : %s"
+
+#: access/brin/brin.c:890 access/brin/brin.c:961
#, c-format
msgid "\"%s\" is not a BRIN index"
msgstr "« %s » n'est pas un index BRIN"
-#: access/brin/brin.c:826
+#: access/brin/brin.c:906 access/brin/brin.c:977
#, c-format
msgid "could not open parent table of index %s"
msgstr "n'a pas pu ouvrir la table parent de l'index %s"
-#: access/brin/brin_pageops.c:76 access/brin/brin_pageops.c:362 access/brin/brin_pageops.c:828
+#: access/brin/brin_pageops.c:76 access/brin/brin_pageops.c:358 access/brin/brin_pageops.c:824 access/gin/ginentrypage.c:110 access/gist/gist.c:1363 access/nbtree/nbtinsert.c:577 access/nbtree/nbtsort.c:488 access/spgist/spgdoinsert.c:1933
+#, c-format
+msgid "index row size %zu exceeds maximum %zu for index \"%s\""
+msgstr "la taille de la ligne index, %zu, dépasse le maximum, %zu, pour l'index « %s »"
+
+#: access/brin/brin_revmap.c:382 access/brin/brin_revmap.c:388
+#, c-format
+msgid "corrupted BRIN index: inconsistent range map"
+msgstr "index BRIN corrompu : carte d'intervalle incohérente"
+
+#: access/brin/brin_revmap.c:404
#, c-format
-msgid "index row size %lu exceeds maximum %lu for index \"%s\""
-msgstr "la taille de la ligne index, %lu, dépasse le maximum, %lu, pour l'index « %s »"
+msgid "leftover placeholder tuple detected in BRIN index \"%s\", deleting"
+msgstr ""
-#: access/brin/brin_revmap.c:459
+#: access/brin/brin_revmap.c:601
#, c-format
msgid "unexpected page type 0x%04X in BRIN index \"%s\" block %u"
msgstr "type de page 0x%04X dans l'index BRIN « %s », bloc %u"
-#: access/brin/brin_validate.c:115
+#: access/brin/brin_validate.c:116 access/gin/ginvalidate.c:149 access/gist/gistvalidate.c:146 access/hash/hashvalidate.c:131 access/nbtree/nbtvalidate.c:101 access/spgist/spgvalidate.c:116
#, c-format
-msgid "brin operator family \"%s\" contains function %s with invalid support number %d"
+msgid "operator family \"%s\" of access method %s contains function %s with invalid support number %d"
msgstr ""
-"la famille d'opérateur brin « %s » contient la fonction %s\n"
-"avec le numéro de support %d invalide"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient la fonction %s avec\n"
+"le numéro de support invalide %d"
-#: access/brin/brin_validate.c:131
+#: access/brin/brin_validate.c:132 access/gin/ginvalidate.c:161 access/gist/gistvalidate.c:158 access/hash/hashvalidate.c:114 access/nbtree/nbtvalidate.c:113 access/spgist/spgvalidate.c:128
#, c-format
-msgid "brin operator family \"%s\" contains function %s with wrong signature for support number %d"
+msgid "operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d"
msgstr ""
-"la famille d'opérateur brin « %s » contient la fonction %s\n"
-"avec une mauvaise signature pour le numéro de support %d"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient la fonction %s avec une mauvaise\n"
+"signature pour le numéro de support %d"
-#: access/brin/brin_validate.c:153
+#: access/brin/brin_validate.c:154 access/gin/ginvalidate.c:180 access/gist/gistvalidate.c:178 access/hash/hashvalidate.c:152 access/nbtree/nbtvalidate.c:133 access/spgist/spgvalidate.c:147
#, c-format
-msgid "brin operator family \"%s\" contains operator %s with invalid strategy number %d"
+msgid "operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d"
msgstr ""
-"la famille d'opérateur brin « %s » contient l'opérateur %s\n"
-"avec le numéro de stratégie %d invalide"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient l'opérateur %s avec le numéro\n"
+"de stratégie invalide %d"
-#: access/brin/brin_validate.c:182
+#: access/brin/brin_validate.c:183 access/gin/ginvalidate.c:193 access/hash/hashvalidate.c:165 access/nbtree/nbtvalidate.c:146 access/spgist/spgvalidate.c:160
#, c-format
-msgid "brin operator family \"%s\" contains invalid ORDER BY specification for operator %s"
+msgid "operator family \"%s\" of access method %s contains invalid ORDER BY specification for operator %s"
msgstr ""
-"la famille d'opérateur brin « %s » contient une spécification\n"
-"ORDER BY invalide pour l'opérateur %s"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient la spécification ORDER BY\n"
+"invalide pour l'opérateur %s"
-#: access/brin/brin_validate.c:195
+#: access/brin/brin_validate.c:196 access/gin/ginvalidate.c:206 access/gist/gistvalidate.c:226 access/hash/hashvalidate.c:178 access/nbtree/nbtvalidate.c:159 access/spgist/spgvalidate.c:173
#, c-format
-msgid "brin operator family \"%s\" contains operator %s with wrong signature"
-msgstr "la famille d'opérateur brin « %s » contient l'opérateur %s avec une mauvaise signature"
+msgid "operator family \"%s\" of access method %s contains operator %s with wrong signature"
+msgstr "la famille d'opérateur « %s » de la méthode d'accès %s contient l'opérateur %s avec une mauvaise signature"
-#: access/brin/brin_validate.c:233
+#: access/brin/brin_validate.c:234 access/hash/hashvalidate.c:218 access/nbtree/nbtvalidate.c:201 access/spgist/spgvalidate.c:201
#, c-format
-msgid "brin operator family \"%s\" is missing operator(s) for types %s and %s"
+msgid "operator family \"%s\" of access method %s is missing operator(s) for types %s and %s"
msgstr ""
-"famille d'opérateur brin « %s » nécessite des opérateurs supplémentaires\n"
+"la famille d'opérateur « %s » de la méthode d'accès %s nécessite des opérateurs supplémentaires\n"
"pour les types %s et %s"
-#: access/brin/brin_validate.c:243
+#: access/brin/brin_validate.c:244
#, c-format
-msgid "brin operator family \"%s\" is missing support function(s) for types %s and %s"
+msgid "operator family \"%s\" of access method %s is missing support function(s) for types %s and %s"
msgstr ""
-"la famille d'opérateur brin « %s » nécessite des fonctions de support\n"
+"la famille d'opérateur « %s » de la méthode d'accès %s nécessite des fonctions de support\n"
"manquantes pour les types %s et %s"
-#: access/brin/brin_validate.c:256
+#: access/brin/brin_validate.c:257 access/hash/hashvalidate.c:232 access/nbtree/nbtvalidate.c:225 access/spgist/spgvalidate.c:234
#, c-format
-msgid "brin operator class \"%s\" is missing operator(s)"
-msgstr "il manque des opérateurs à la classe d'opérateur brin « %s »"
+msgid "operator class \"%s\" of access method %s is missing operator(s)"
+msgstr "il manque un ou des opérateurs à la classe d'opérateur « %s » de la méthode d'accès %s"
-#: access/brin/brin_validate.c:267
+#: access/brin/brin_validate.c:268 access/gin/ginvalidate.c:247 access/gist/gistvalidate.c:265
#, c-format
-msgid "brin operator class \"%s\" is missing support function %d"
-msgstr "la classe d'opérateur brin « %s » nécessite la fonction de support %d"
+msgid "operator class \"%s\" of access method %s is missing support function %d"
+msgstr "la classe d'opérateur « %s » de la méthode d'accès %s nécessite la fonction de support manquante %d"
-#: access/common/heaptuple.c:708 access/common/heaptuple.c:1339
+#: access/common/heaptuple.c:708 access/common/heaptuple.c:1405
#, c-format
msgid "number of columns (%d) exceeds limit (%d)"
msgstr "le nombre de colonnes (%d) dépasse la limite (%d)"
@@ -429,67 +455,67 @@ msgstr "le nombre de colonnes (%d) dépasse la limite (%d)"
msgid "number of index columns (%d) exceeds limit (%d)"
msgstr "le nombre de colonnes indexées (%d) dépasse la limite (%d)"
-#: access/common/indextuple.c:176 access/spgist/spgutils.c:642
+#: access/common/indextuple.c:176 access/spgist/spgutils.c:647
#, c-format
msgid "index row requires %zu bytes, maximum size is %zu"
msgstr "la ligne index requiert %zu octets, la taille maximum est %zu"
-#: access/common/printtup.c:292 tcop/fastpath.c:182 tcop/fastpath.c:544 tcop/postgres.c:1719
+#: access/common/printtup.c:290 tcop/fastpath.c:182 tcop/fastpath.c:532 tcop/postgres.c:1726
#, c-format
msgid "unsupported format code: %d"
msgstr "code de format non supporté : %d"
-#: access/common/reloptions.c:493
+#: access/common/reloptions.c:540
#, c-format
msgid "user-defined relation parameter types limit exceeded"
msgstr "limite dépassée des types de paramètres de la relation définie par l'utilisateur"
-#: access/common/reloptions.c:775
+#: access/common/reloptions.c:821
#, c-format
msgid "RESET must not include values for parameters"
msgstr "RESET ne doit pas inclure de valeurs pour les paramètres"
-#: access/common/reloptions.c:808
+#: access/common/reloptions.c:854
#, c-format
msgid "unrecognized parameter namespace \"%s\""
msgstr "espace de nom du paramètre « %s » non reconnu"
-#: access/common/reloptions.c:1050 parser/parse_clause.c:281
+#: access/common/reloptions.c:1094 parser/parse_clause.c:270
#, c-format
msgid "unrecognized parameter \"%s\""
msgstr "paramètre « %s » non reconnu"
-#: access/common/reloptions.c:1080
+#: access/common/reloptions.c:1124
#, c-format
msgid "parameter \"%s\" specified more than once"
msgstr "le paramètre « %s » est spécifié plus d'une fois"
-#: access/common/reloptions.c:1096
+#: access/common/reloptions.c:1140
#, c-format
msgid "invalid value for boolean option \"%s\": %s"
msgstr "valeur invalide pour l'option booléenne « %s » : %s"
-#: access/common/reloptions.c:1108
+#: access/common/reloptions.c:1152
#, c-format
msgid "invalid value for integer option \"%s\": %s"
msgstr "valeur invalide pour l'option de type integer « %s » : %s"
-#: access/common/reloptions.c:1114 access/common/reloptions.c:1134
+#: access/common/reloptions.c:1158 access/common/reloptions.c:1178
#, c-format
msgid "value %s out of bounds for option \"%s\""
msgstr "valeur %s en dehors des limites pour l'option « %s »"
-#: access/common/reloptions.c:1116
+#: access/common/reloptions.c:1160
#, c-format
msgid "Valid values are between \"%d\" and \"%d\"."
msgstr "Les valeurs valides sont entre « %d » et « %d »."
-#: access/common/reloptions.c:1128
+#: access/common/reloptions.c:1172
#, c-format
msgid "invalid value for floating point option \"%s\": %s"
msgstr "valeur invalide pour l'option de type float « %s » : %s"
-#: access/common/reloptions.c:1136
+#: access/common/reloptions.c:1180
#, c-format
msgid "Valid values are between \"%f\" and \"%f\"."
msgstr "Les valeurs valides sont entre « %f » et « %f »."
@@ -506,17 +532,17 @@ msgstr ""
"Le nombre de colonnes renvoyées (%d) ne correspond pas au nombre de colonnes\n"
"attendues (%d)."
-#: access/common/tupconvert.c:314
+#: access/common/tupconvert.c:318
#, c-format
msgid "Attribute \"%s\" of type %s does not match corresponding attribute of type %s."
msgstr "L'attribut « %s » du type %s ne correspond pas à l'attribut correspondant de type %s."
-#: access/common/tupconvert.c:326
+#: access/common/tupconvert.c:330
#, c-format
msgid "Attribute \"%s\" of type %s does not exist in type %s."
msgstr "L'attribut « %s » du type %s n'existe pas dans le type %s."
-#: access/common/tupdesc.c:635 parser/parse_relation.c:1518
+#: access/common/tupdesc.c:728 parser/parse_clause.c:841 parser/parse_relation.c:1544
#, c-format
msgid "column \"%s\" cannot be declared SETOF"
msgstr "la colonne « %s » ne peut pas être déclarée SETOF"
@@ -529,29 +555,24 @@ msgstr "la posting list est trop longue"
#: access/gin/ginbulk.c:45
#, c-format
msgid "Reduce maintenance_work_mem."
-msgstr "Réduisez le maintenance_work_mem"
-
-#: access/gin/ginentrypage.c:109 access/gist/gist.c:1337 access/nbtree/nbtinsert.c:576 access/nbtree/nbtsort.c:488 access/spgist/spgdoinsert.c:1907
-#, c-format
-msgid "index row size %zu exceeds maximum %zu for index \"%s\""
-msgstr "la taille de la ligne index, %zu, dépasse le maximum, %zu, pour l'index « %s »"
+msgstr "Réduisez le maintenance_work_mem."
-#: access/gin/ginfast.c:989 access/transam/xlog.c:9858 access/transam/xlog.c:10362 access/transam/xlogfuncs.c:293 access/transam/xlogfuncs.c:320 access/transam/xlogfuncs.c:359 access/transam/xlogfuncs.c:380 access/transam/xlogfuncs.c:401 access/transam/xlogfuncs.c:471 access/transam/xlogfuncs.c:527
+#: access/gin/ginfast.c:991 access/transam/xlog.c:10208 access/transam/xlog.c:10726 access/transam/xlogfuncs.c:296 access/transam/xlogfuncs.c:323 access/transam/xlogfuncs.c:362 access/transam/xlogfuncs.c:383 access/transam/xlogfuncs.c:404 access/transam/xlogfuncs.c:474 access/transam/xlogfuncs.c:530
#, c-format
msgid "recovery is in progress"
msgstr "restauration en cours"
-#: access/gin/ginfast.c:990
+#: access/gin/ginfast.c:992
#, c-format
msgid "GIN pending list cannot be cleaned up during recovery."
msgstr "la pending list GIN ne peut pas être nettoyée lors de la restauration"
-#: access/gin/ginfast.c:997
+#: access/gin/ginfast.c:999
#, c-format
msgid "\"%s\" is not a GIN index"
msgstr "« %s » n'est pas un index GIN"
-#: access/gin/ginfast.c:1008
+#: access/gin/ginfast.c:1010
#, c-format
msgid "cannot access temporary indexes of other sessions"
msgstr "ne peut pas accéder aux index temporaires d'autres sessions"
@@ -568,84 +589,51 @@ msgstr ""
msgid "To fix this, do REINDEX INDEX \"%s\"."
msgstr "Pour corriger ceci, faites un REINDEX INDEX « %s »."
-#: access/gin/ginvalidate.c:92
-#, c-format
-msgid "gin operator family \"%s\" contains support procedure %s with cross-type registration"
-msgstr ""
-"la famille d'opérateur gin « %s » contient la procédure de support\n"
-"%s avec un enregistrement inter-type"
-
-#: access/gin/ginvalidate.c:148
-#, c-format
-msgid "gin operator family \"%s\" contains function %s with invalid support number %d"
-msgstr ""
-"la famille d'opérateur gin « %s » contient la fonction %s avec\n"
-"le numéro de support invalide %d"
-
-#: access/gin/ginvalidate.c:160
-#, c-format
-msgid "gin operator family \"%s\" contains function %s with wrong signature for support number %d"
-msgstr ""
-"la famille d'opérateur gin « %s » contient la fonction %s avec une mauvaise\n"
-"signature pour le numéro de support %d"
-
-#: access/gin/ginvalidate.c:179
+#: access/gin/ginutil.c:134 executor/execExpr.c:1780 utils/adt/arrayfuncs.c:3803 utils/adt/arrayfuncs.c:6323 utils/adt/rowtypes.c:927
#, c-format
-msgid "gin operator family \"%s\" contains operator %s with invalid strategy number %d"
-msgstr ""
-"la famille d'opérateur gin « %s » contient l'opérateur %s avec le numéro\n"
-"de stratégie invalide %d"
+msgid "could not identify a comparison function for type %s"
+msgstr "n'a pas pu identifier une fonction de comparaison pour le type %s"
-#: access/gin/ginvalidate.c:192
+#: access/gin/ginvalidate.c:93 access/gist/gistvalidate.c:93 access/hash/hashvalidate.c:99 access/spgist/spgvalidate.c:93
#, c-format
-msgid "gin operator family \"%s\" contains invalid ORDER BY specification for operator %s"
+msgid "operator family \"%s\" of access method %s contains support procedure %s with different left and right input types"
msgstr ""
-"la famille d'opérateur gin « %s » contient la spécification ORDER BY\n"
-"invalide pour l'opérateur %s"
-
-#: access/gin/ginvalidate.c:205
-#, c-format
-msgid "gin operator family \"%s\" contains operator %s with wrong signature"
-msgstr "la famille d'opérateur gin « %s » contient l'opérateur %s avec une mauvaise signature"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient la procédure de support\n"
+"%s avec des types en entrée gauche et droite différents"
-#: access/gin/ginvalidate.c:246
+#: access/gin/ginvalidate.c:257
#, c-format
-msgid "gin operator class \"%s\" is missing support function %d"
-msgstr "la famille d'opérateur gin « %s » nécessite la fonction de support %d"
+msgid "operator class \"%s\" of access method %s is missing support function %d or %d"
+msgstr "la classe d'opérateur « %s » de la méthode d'accès %s nécessite la fonction de support manquante %d ou %d"
-#: access/gin/ginvalidate.c:256
-#, c-format
-msgid "gin operator class \"%s\" is missing support function %d or %d"
-msgstr "la famille d'opérateur gin « %s » nécessite la fonction de support %d ou %d"
-
-#: access/gist/gist.c:680 access/gist/gistvacuum.c:258
+#: access/gist/gist.c:706 access/gist/gistvacuum.c:258
#, c-format
msgid "index \"%s\" contains an inner tuple marked as invalid"
msgstr "l'index « %s » contient une ligne interne marquée comme invalide"
-#: access/gist/gist.c:682 access/gist/gistvacuum.c:260
+#: access/gist/gist.c:708 access/gist/gistvacuum.c:260
#, c-format
msgid "This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."
msgstr ""
"Ceci est dû à la division d'une page incomplète à la restauration suite à un\n"
"crash avant la mise à jour en 9.1."
-#: access/gist/gist.c:683 access/gist/gistutil.c:738 access/gist/gistutil.c:749 access/gist/gistvacuum.c:261 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:709 access/gist/gistutil.c:739 access/gist/gistutil.c:750 access/gist/gistvacuum.c:261 access/hash/hashutil.c:241 access/hash/hashutil.c:252 access/hash/hashutil.c:264 access/hash/hashutil.c:285 access/nbtree/nbtpage.c:519 access/nbtree/nbtpage.c:530
#, c-format
msgid "Please REINDEX it."
msgstr "Merci d'exécuter REINDEX sur cet objet."
-#: access/gist/gistbuild.c:249
+#: access/gist/gistbuild.c:250
#, c-format
msgid "invalid value for \"buffering\" option"
msgstr "valeur invalide pour l'option « buffering »"
-#: access/gist/gistbuild.c:250
+#: access/gist/gistbuild.c:251
#, c-format
msgid "Valid values are \"on\", \"off\", and \"auto\"."
msgstr "Les valeurs valides sont entre « on », « off » et « auto »."
-#: access/gist/gistbuildbuffers.c:778 utils/sort/logtape.c:209
+#: access/gist/gistbuildbuffers.c:778 utils/sort/logtape.c:231
#, c-format
msgid "could not write block %ld of temporary file: %m"
msgstr "n'a pas pu écrire le bloc %ld du fichier temporaire : %m"
@@ -663,286 +651,202 @@ msgstr ""
"ou essayez d'utiliser la colonne comme second dans la commande\n"
"CREATE INDEX."
-#: access/gist/gistutil.c:735 access/hash/hashutil.c:169 access/nbtree/nbtpage.c:515
+#: access/gist/gistutil.c:736 access/hash/hashutil.c:238 access/nbtree/nbtpage.c:516
#, c-format
msgid "index \"%s\" contains unexpected zero page at block %u"
msgstr "l'index « %s » contient une page zéro inattendue au bloc %u"
-#: access/gist/gistutil.c:746 access/hash/hashutil.c:180 access/hash/hashutil.c:192 access/nbtree/nbtpage.c:526
+#: access/gist/gistutil.c:747 access/hash/hashutil.c:249 access/hash/hashutil.c:261 access/nbtree/nbtpage.c:527
#, c-format
msgid "index \"%s\" contains corrupted page at block %u"
msgstr "l'index « %s » contient une page corrompue au bloc %u"
-#: access/gist/gistvalidate.c:92
+#: access/gist/gistvalidate.c:196
#, c-format
-msgid "gist operator family \"%s\" contains support procedure %s with cross-type registration"
+msgid "operator family \"%s\" of access method %s contains unsupported ORDER BY specification for operator %s"
msgstr ""
-"la famille d'opérateur gist « %s » contient la procédure de support\n"
-"%s avec un enregistrement inter-type"
-
-#: access/gist/gistvalidate.c:145
-#, c-format
-msgid "gist operator family \"%s\" contains function %s with invalid support number %d"
-msgstr ""
-"la famille d'opérateur gist « %s » contient la fonction %s avec\n"
-"le numéro de support invalide %d"
-
-#: access/gist/gistvalidate.c:157
-#, c-format
-msgid "gist operator family \"%s\" contains function %s with wrong signature for support number %d"
-msgstr ""
-"la famille d'opérateur gist « %s » contient la fonction %s avec une mauvaise\n"
-"signature pour le numéro de support %d"
-
-#: access/gist/gistvalidate.c:177
-#, c-format
-msgid "gist operator family \"%s\" contains operator %s with invalid strategy number %d"
-msgstr ""
-"la famille d'opérateur gist « %s » contient l'opérateur %s avec le numéro\n"
-"de stratégie invalide %d"
-
-#: access/gist/gistvalidate.c:195
-#, c-format
-msgid "gist operator family \"%s\" contains unsupported ORDER BY specification for operator %s"
-msgstr ""
-"la famille d'opérateur gist « %s » contient la spécification ORDER BY\n"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient une spécification ORDER BY\n"
"non supportée pour l'opérateur %s"
-#: access/gist/gistvalidate.c:206
+#: access/gist/gistvalidate.c:207
#, c-format
-msgid "gist operator family \"%s\" contains incorrect ORDER BY opfamily specification for operator %s"
+msgid "operator family \"%s\" of access method %s contains incorrect ORDER BY opfamily specification for operator %s"
msgstr ""
-"la famille d'opérateur gist « %s » contient la spécification opfamily ORDER BY\n"
+"la famille d'opérateur « %s » de la méthode d'accès %s contient la spécification opfamily ORDER BY\n"
"incorrecte pour l'opérateur %s"
-#: access/gist/gistvalidate.c:225
-#, c-format
-msgid "gist operator family \"%s\" contains operator %s with wrong signature"
-msgstr "la famille d'opérateur gist « %s » contient l'opérateur %s avec une mauvaise signature"
-
-#: access/gist/gistvalidate.c:264
-#, c-format
-msgid "gist operator class \"%s\" is missing support function %d"
-msgstr "la famille d'opérateur gist « %s » nécessite la fonction de support %d"
-
-#: access/hash/hashinsert.c:70
+#: access/hash/hashinsert.c:82
#, c-format
msgid "index row size %zu exceeds hash maximum %zu"
msgstr "la taille de la ligne index, %zu, dépasse le hachage maximum, %zu"
-#: access/hash/hashinsert.c:72 access/spgist/spgdoinsert.c:1911 access/spgist/spgutils.c:703
+#: access/hash/hashinsert.c:84 access/spgist/spgdoinsert.c:1937 access/spgist/spgutils.c:708
#, c-format
msgid "Values larger than a buffer page cannot be indexed."
msgstr "Les valeurs plus larges qu'une page de tampon ne peuvent pas être indexées."
-#: access/hash/hashovfl.c:546
+#: access/hash/hashovfl.c:87
+#, c-format
+msgid "invalid overflow block number %u"
+msgstr "numéro de bloc de surcharge invalide %u"
+
+#: access/hash/hashovfl.c:283 access/hash/hashpage.c:462
#, c-format
msgid "out of overflow pages in hash index \"%s\""
msgstr "en dehors des pages surchargées dans l'index haché « %s »"
-#: access/hash/hashsearch.c:153
+#: access/hash/hashsearch.c:250
#, c-format
msgid "hash indexes do not support whole-index scans"
msgstr "les index hâchés ne supportent pas les parcours complets d'index"
-#: access/hash/hashutil.c:208
+#: access/hash/hashutil.c:277
#, c-format
msgid "index \"%s\" is not a hash index"
msgstr "l'index « %s » n'est pas un index haché"
-#: access/hash/hashutil.c:214
+#: access/hash/hashutil.c:283
#, c-format
msgid "index \"%s\" has wrong hash version"
msgstr "l'index « %s » a la mauvaise version de hachage"
-#: access/hash/hashvalidate.c:98
-#, c-format
-msgid "hash operator family \"%s\" contains support procedure %s with cross-type registration"
-msgstr ""
-"la famille d'opérateur hash « %s » contient la procédure de support\n"
-"%s avec un enregistrement inter-type"
-
-#: access/hash/hashvalidate.c:113
-#, c-format
-msgid "hash operator family \"%s\" contains function %s with wrong signature for support number %d"
-msgstr ""
-"la famille d'opérateur hash « %s » contient la fonction %s avec une mauvaise\n"
-"signature pour le numéro de support %d"
-
-#: access/hash/hashvalidate.c:130
-#, c-format
-msgid "hash operator family \"%s\" contains function %s with invalid support number %d"
-msgstr ""
-"la famille d'opérateur hash « %s » contient la fonction %s avec\n"
-"le numéro de support invalide %d"
-
-#: access/hash/hashvalidate.c:151
+#: access/hash/hashvalidate.c:190
#, c-format
-msgid "hash operator family \"%s\" contains operator %s with invalid strategy number %d"
+msgid "operator family \"%s\" of access method %s lacks support function for operator %s"
msgstr ""
-"la famille d'opérateur hash « %s » contient l'opérateur %s avec le numéro\n"
-"de stratégie invalide %d"
-
-#: access/hash/hashvalidate.c:164
-#, c-format
-msgid "hash operator family \"%s\" contains invalid ORDER BY specification for operator %s"
-msgstr ""
-"la famille d'opérateur hash « %s » contient la spécification ORDER BY\n"
-"non supportée pour l'opérateur %s"
-
-#: access/hash/hashvalidate.c:177
-#, c-format
-msgid "hash operator family \"%s\" contains operator %s with wrong signature"
-msgstr "la famille d'opérateur hash « %s » contient l'opérateur %s avec une mauvaise signature"
-
-#: access/hash/hashvalidate.c:189
-#, c-format
-msgid "hash operator family \"%s\" lacks support function for operator %s"
-msgstr ""
-"la famille d'opérateur hash « %s » requiert la fonction de support\n"
+"la famille d'opérateur « %s » de la méthode d'accès %s requiert la fonction de support\n"
"pour l'opérateur %s"
-#: access/hash/hashvalidate.c:217
-#, c-format
-msgid "hash operator family \"%s\" is missing operator(s) for types %s and %s"
-msgstr ""
-"la famille d'opérateur hash « %s » nécessite des opérateurs supplémentaires\n"
-"pour les types %s et %s"
-
-#: access/hash/hashvalidate.c:231
-#, c-format
-msgid "hash operator class \"%s\" is missing operator(s)"
-msgstr "il manque des opérateurs pour la classe d'opérateur hash « %s »"
-
-#: access/hash/hashvalidate.c:247
+#: access/hash/hashvalidate.c:248 access/nbtree/nbtvalidate.c:242
#, c-format
-msgid "hash operator family \"%s\" is missing cross-type operator(s)"
-msgstr "il manque des opérateurs inter-type pour la famille d'opérateur hash « %s »"
+msgid "operator family \"%s\" of access method %s is missing cross-type operator(s)"
+msgstr "il manque un opérateur inter-type pour la famille d'opérateur « %s » de la méthode d'accès %s"
-#: access/heap/heapam.c:1295 access/heap/heapam.c:1323 access/heap/heapam.c:1355 catalog/aclchk.c:1756
+#: access/heap/heapam.c:1293 access/heap/heapam.c:1321 access/heap/heapam.c:1353 catalog/aclchk.c:1772
#, c-format
msgid "\"%s\" is an index"
msgstr "« %s » est un index"
-#: access/heap/heapam.c:1300 access/heap/heapam.c:1328 access/heap/heapam.c:1360 catalog/aclchk.c:1763 commands/tablecmds.c:9081 commands/tablecmds.c:12189
+#: access/heap/heapam.c:1298 access/heap/heapam.c:1326 access/heap/heapam.c:1358 catalog/aclchk.c:1779 commands/tablecmds.c:9885 commands/tablecmds.c:13115
#, c-format
msgid "\"%s\" is a composite type"
msgstr "« %s » est un type composite"
-#: access/heap/heapam.c:2567
+#: access/heap/heapam.c:2592
#, c-format
msgid "cannot insert tuples during a parallel operation"
msgstr "ne peut pas insérer les lignes lors d'une opération parallèle"
-#: access/heap/heapam.c:3017
+#: access/heap/heapam.c:3042
#, c-format
msgid "cannot delete tuples during a parallel operation"
msgstr "ne peut pas supprimer les lignes lors d'une opération parallèle"
-#: access/heap/heapam.c:3063
+#: access/heap/heapam.c:3088
#, c-format
msgid "attempted to delete invisible tuple"
msgstr "a tenté de supprimer la ligne invisible"
-#: access/heap/heapam.c:3489 access/heap/heapam.c:6240
+#: access/heap/heapam.c:3514 access/heap/heapam.c:6247
#, c-format
msgid "cannot update tuples during a parallel operation"
msgstr "ne peut pas mettre à jour les lignes lors d'une opération parallèle"
-#: access/heap/heapam.c:3611
+#: access/heap/heapam.c:3662
#, c-format
msgid "attempted to update invisible tuple"
msgstr "a tenté de mettre à jour la ligne invisible"
-#: access/heap/heapam.c:4963 access/heap/heapam.c:5001 access/heap/heapam.c:5253 executor/execMain.c:2314
+#: access/heap/heapam.c:4937 access/heap/heapam.c:4975 access/heap/heapam.c:5227 executor/execMain.c:2602
#, c-format
msgid "could not obtain lock on row in relation \"%s\""
msgstr "n'a pas pu obtenir un verrou sur la relation « %s »"
-#: access/heap/hio.c:322 access/heap/rewriteheap.c:664
+#: access/heap/hio.c:322 access/heap/rewriteheap.c:666
#, c-format
msgid "row is too big: size %zu, maximum size %zu"
msgstr "la ligne est trop grande : taille %zu, taille maximale %zu"
-#: access/heap/rewriteheap.c:923
+#: access/heap/rewriteheap.c:926
#, c-format
msgid "could not write to file \"%s\", wrote %d of %d: %m"
msgstr "n'a pas pu écrire le fichier « %s », a écrit %d de %d : %m"
-#: access/heap/rewriteheap.c:963 access/heap/rewriteheap.c:1175 access/heap/rewriteheap.c:1272 access/transam/timeline.c:407 access/transam/timeline.c:483 access/transam/xlog.c:3087 access/transam/xlog.c:3249 replication/logical/snapbuild.c:1605 replication/slot.c:1088 replication/slot.c:1173 storage/file/fd.c:624 storage/file/fd.c:3052 storage/smgr/md.c:1041 storage/smgr/md.c:1274 storage/smgr/md.c:1447 utils/misc/guc.c:6885
+#: access/heap/rewriteheap.c:966 access/heap/rewriteheap.c:1183 access/heap/rewriteheap.c:1282 access/transam/timeline.c:412 access/transam/timeline.c:492 access/transam/xlog.c:3249 access/transam/xlog.c:3417 replication/logical/snapbuild.c:1630 replication/slot.c:1290 replication/slot.c:1377 storage/file/fd.c:631 storage/file/fd.c:3180 storage/smgr/md.c:1044 storage/smgr/md.c:1277 storage/smgr/md.c:1450 utils/misc/guc.c:6998
#, c-format
msgid "could not fsync file \"%s\": %m"
msgstr "n'a pas pu synchroniser sur disque (fsync) le fichier « %s » : %m"
-#: access/heap/rewriteheap.c:1018 access/heap/rewriteheap.c:1138 access/transam/timeline.c:315 access/transam/timeline.c:461 access/transam/xlog.c:3043 access/transam/xlog.c:3192 access/transam/xlog.c:10192 access/transam/xlog.c:10230 access/transam/xlog.c:10603 postmaster/postmaster.c:4364 replication/logical/origin.c:542 replication/slot.c:1045 storage/file/copydir.c:162 storage/smgr/md.c:327 utils/time/snapmgr.c:1275
+#: access/heap/rewriteheap.c:1021 access/heap/rewriteheap.c:1141 access/transam/timeline.c:315 access/transam/timeline.c:467 access/transam/xlog.c:3202 access/transam/xlog.c:3355 access/transam/xlog.c:10543 access/transam/xlog.c:10581 access/transam/xlog.c:10966 postmaster/postmaster.c:4450 replication/logical/origin.c:535 replication/slot.c:1242 storage/file/copydir.c:162 storage/smgr/md.c:327 utils/time/snapmgr.c:1297
#, c-format
msgid "could not create file \"%s\": %m"
msgstr "n'a pas pu créer le fichier « %s » : %m"
-#: access/heap/rewriteheap.c:1147
+#: access/heap/rewriteheap.c:1151
#, c-format
msgid "could not truncate file \"%s\" to %u: %m"
msgstr "n'a pas pu tronquer le fichier « %s » en %u : %m"
-#: access/heap/rewriteheap.c:1154 replication/walsender.c:481 storage/smgr/md.c:1899
+#: access/heap/rewriteheap.c:1159 replication/walsender.c:486 storage/smgr/md.c:1949
#, c-format
msgid "could not seek to end of file \"%s\": %m"
msgstr "n'a pas pu trouver la fin du fichier « %s » : %m"
-#: access/heap/rewriteheap.c:1165 access/transam/timeline.c:367 access/transam/timeline.c:401 access/transam/timeline.c:477 access/transam/xlog.c:3078 access/transam/xlog.c:3242 postmaster/postmaster.c:4374 postmaster/postmaster.c:4384 replication/logical/origin.c:551 replication/logical/origin.c:587 replication/logical/origin.c:603 replication/logical/snapbuild.c:1589 replication/slot.c:1074 storage/file/copydir.c:187
-#: utils/init/miscinit.c:1228 utils/init/miscinit.c:1237 utils/init/miscinit.c:1244 utils/misc/guc.c:6846 utils/misc/guc.c:6877 utils/misc/guc.c:8727 utils/misc/guc.c:8741 utils/time/snapmgr.c:1280 utils/time/snapmgr.c:1287
+#: access/heap/rewriteheap.c:1171 access/transam/timeline.c:370 access/transam/timeline.c:405 access/transam/timeline.c:484 access/transam/xlog.c:3238 access/transam/xlog.c:3408 postmaster/postmaster.c:4460 postmaster/postmaster.c:4470 replication/logical/origin.c:544 replication/logical/origin.c:583 replication/logical/origin.c:599 replication/logical/snapbuild.c:1612 replication/slot.c:1273 storage/file/copydir.c:191
+#: utils/init/miscinit.c:1249 utils/init/miscinit.c:1260 utils/init/miscinit.c:1268 utils/misc/guc.c:6959 utils/misc/guc.c:6990 utils/misc/guc.c:8840 utils/misc/guc.c:8854 utils/time/snapmgr.c:1302 utils/time/snapmgr.c:1309
#, c-format
msgid "could not write to file \"%s\": %m"
msgstr "n'a pas pu écrire dans le fichier « %s » : %m"
-#: access/heap/rewriteheap.c:1248 access/transam/xlog.c:10441 access/transam/xlogarchive.c:114 access/transam/xlogarchive.c:468 replication/logical/origin.c:529 replication/logical/reorderbuffer.c:2632 replication/logical/reorderbuffer.c:2689 replication/logical/snapbuild.c:1533 replication/logical/snapbuild.c:1908 replication/slot.c:1147 storage/ipc/dsm.c:326 storage/smgr/md.c:427 storage/smgr/md.c:476 storage/smgr/md.c:1394
+#: access/heap/rewriteheap.c:1257 access/transam/xlogarchive.c:113 access/transam/xlogarchive.c:467 postmaster/postmaster.c:1257 postmaster/syslogger.c:1371 replication/logical/origin.c:522 replication/logical/reorderbuffer.c:2595 replication/logical/reorderbuffer.c:2652 replication/logical/snapbuild.c:1560 replication/logical/snapbuild.c:1936 replication/slot.c:1350 storage/file/fd.c:682 storage/ipc/dsm.c:327 storage/smgr/md.c:426
+#: storage/smgr/md.c:475 storage/smgr/md.c:1397
#, c-format
msgid "could not remove file \"%s\": %m"
msgstr "n'a pas pu supprimer le fichier « %s » : %m"
-#: access/heap/rewriteheap.c:1262 access/transam/timeline.c:111 access/transam/timeline.c:236 access/transam/timeline.c:334 access/transam/xlog.c:3019 access/transam/xlog.c:3136 access/transam/xlog.c:3177 access/transam/xlog.c:3450 access/transam/xlog.c:3528 access/transam/xlogutils.c:701 replication/basebackup.c:403 replication/basebackup.c:1150 replication/logical/origin.c:658 replication/logical/reorderbuffer.c:2156
-#: replication/logical/reorderbuffer.c:2402 replication/logical/reorderbuffer.c:3081 replication/logical/snapbuild.c:1582 replication/logical/snapbuild.c:1666 replication/slot.c:1162 replication/walsender.c:474 replication/walsender.c:2102 storage/file/copydir.c:155 storage/file/fd.c:607 storage/file/fd.c:2964 storage/file/fd.c:3031 storage/smgr/md.c:609 utils/error/elog.c:1879 utils/init/miscinit.c:1163 utils/init/miscinit.c:1284
-#: utils/init/miscinit.c:1362 utils/misc/guc.c:7105 utils/misc/guc.c:7138
+#: access/heap/rewriteheap.c:1271 access/transam/timeline.c:111 access/transam/timeline.c:236 access/transam/timeline.c:334 access/transam/xlog.c:3178 access/transam/xlog.c:3299 access/transam/xlog.c:3340 access/transam/xlog.c:3619 access/transam/xlog.c:3697 access/transam/xlogutils.c:706 postmaster/syslogger.c:1380 replication/basebackup.c:474 replication/basebackup.c:1218 replication/logical/origin.c:654
+#: replication/logical/reorderbuffer.c:2112 replication/logical/reorderbuffer.c:2361 replication/logical/reorderbuffer.c:3044 replication/logical/snapbuild.c:1604 replication/logical/snapbuild.c:1692 replication/slot.c:1365 replication/walsender.c:479 replication/walsender.c:2385 storage/file/copydir.c:155 storage/file/fd.c:614 storage/file/fd.c:3092 storage/file/fd.c:3159 storage/smgr/md.c:608 utils/error/elog.c:1879
+#: utils/init/miscinit.c:1173 utils/init/miscinit.c:1308 utils/init/miscinit.c:1385 utils/misc/guc.c:7218 utils/misc/guc.c:7251
#, c-format
msgid "could not open file \"%s\": %m"
msgstr "n'a pas pu ouvrir le fichier « %s » : %m"
-#: access/index/amapi.c:82 commands/amcmds.c:164
+#: access/index/amapi.c:83 commands/amcmds.c:163
#, c-format
msgid "access method \"%s\" is not of type %s"
msgstr "la méthode d'accès « %s » n'est pas de type %s"
-#: access/index/amapi.c:98
+#: access/index/amapi.c:99
#, c-format
msgid "index access method \"%s\" does not have a handler"
msgstr "la méthode d'accès « %s » n'a pas de handler"
-#: access/index/indexam.c:155 catalog/objectaddress.c:1196 commands/indexcmds.c:1799 commands/tablecmds.c:242 commands/tablecmds.c:12180
+#: access/index/indexam.c:160 catalog/objectaddress.c:1222 commands/indexcmds.c:1819 commands/tablecmds.c:247 commands/tablecmds.c:13106
#, c-format
msgid "\"%s\" is not an index"
msgstr "« %s » n'est pas un index"
-#: access/nbtree/nbtinsert.c:428
+#: access/nbtree/nbtinsert.c:429
#, c-format
msgid "duplicate key value violates unique constraint \"%s\""
msgstr "la valeur d'une clé dupliquée rompt la contrainte unique « %s »"
-#: access/nbtree/nbtinsert.c:430
+#: access/nbtree/nbtinsert.c:431
#, c-format
msgid "Key %s already exists."
msgstr "La clé « %s » existe déjà."
-#: access/nbtree/nbtinsert.c:497
+#: access/nbtree/nbtinsert.c:498
#, c-format
msgid "failed to re-find tuple within index \"%s\""
msgstr "échec pour retrouver la ligne dans l'index « %s »"
-#: access/nbtree/nbtinsert.c:499
+#: access/nbtree/nbtinsert.c:500
#, c-format
msgid "This may be because of a non-immutable index expression."
msgstr "Ceci peut être dû à une expression d'index immutable."
-#: access/nbtree/nbtinsert.c:579 access/nbtree/nbtsort.c:491
+#: access/nbtree/nbtinsert.c:580 access/nbtree/nbtsort.c:491
#, c-format
msgid ""
"Values larger than 1/3 of a buffer page cannot be indexed.\n"
@@ -953,168 +857,66 @@ msgstr ""
"Utilisez un index sur le hachage MD5 de la valeur ou passez à l'indexation\n"
"de la recherche plein texte."
-#: access/nbtree/nbtpage.c:168 access/nbtree/nbtpage.c:371 access/nbtree/nbtpage.c:458 parser/parse_utilcmd.c:1702
+#: access/nbtree/nbtpage.c:169 access/nbtree/nbtpage.c:372 access/nbtree/nbtpage.c:459 parser/parse_utilcmd.c:1900
#, c-format
msgid "index \"%s\" is not a btree"
msgstr "l'index « %s » n'est pas un btree"
-#: access/nbtree/nbtpage.c:174 access/nbtree/nbtpage.c:377 access/nbtree/nbtpage.c:464
+#: access/nbtree/nbtpage.c:175 access/nbtree/nbtpage.c:378 access/nbtree/nbtpage.c:465
#, c-format
msgid "version mismatch in index \"%s\": file version %d, code version %d"
msgstr "la version ne correspond pas dans l'index « %s » : version du fichier %d, version du code %d"
-#: access/nbtree/nbtpage.c:1152
+#: access/nbtree/nbtpage.c:1153
#, c-format
msgid "index \"%s\" contains a half-dead internal page"
msgstr "l'index « %s » contient une page interne à moitié morte"
-#: access/nbtree/nbtpage.c:1154
+#: access/nbtree/nbtpage.c:1155
#, c-format
msgid "This can be caused by an interrupted VACUUM in version 9.3 or older, before upgrade. Please REINDEX it."
msgstr "Ceci peut être dû à un VACUUM interrompu en version 9.3 ou antérieure, avant la mise à jour. Merci d'utiliser REINDEX."
-#: access/nbtree/nbtvalidate.c:100
+#: access/nbtree/nbtvalidate.c:211
#, c-format
-msgid "btree operator family \"%s\" contains function %s with invalid support number %d"
+msgid "operator family \"%s\" of access method %s is missing support function for types %s and %s"
msgstr ""
-"la famille d'opérateur btree « %s » contient la fonction %s\n"
-"avec le numéro de support invalide %d"
+"la famille d'opérateur « %s » de la méthode d'accès %s nécessite une fonction de support\n"
+"manquante pour les types %s et %s"
-#: access/nbtree/nbtvalidate.c:112
-#, c-format
-msgid "btree operator family \"%s\" contains function %s with wrong signature for support number %d"
-msgstr ""
-"la famille d'opérateur btree « %s » contient la fonction %s\n"
-"avec une mauvaise signature pour le numéro de support %d"
-
-#: access/nbtree/nbtvalidate.c:132
-#, c-format
-msgid "btree operator family \"%s\" contains operator %s with invalid strategy number %d"
-msgstr ""
-"la famille d'opérateur btree « %s » contient l'opérateur %s\n"
-"avec le numéro de stratégie invalide %d"
-
-#: access/nbtree/nbtvalidate.c:145
-#, c-format
-msgid "btree operator family \"%s\" contains invalid ORDER BY specification for operator %s"
-msgstr ""
-"la famille d'opérateur btree « %s » contient une spécification\n"
-"ORDER BY invalide pour l'opérateur %s"
-
-#: access/nbtree/nbtvalidate.c:158
-#, c-format
-msgid "btree operator family \"%s\" contains operator %s with wrong signature"
-msgstr "la famille d'opérateur btree « %s » contient l'opérateur %s avec une mauvaise signature"
-
-#: access/nbtree/nbtvalidate.c:200
-#, c-format
-msgid "btree operator family \"%s\" is missing operator(s) for types %s and %s"
-msgstr ""
-"la famille d'opérateur btree « %s » nécessite des opérateurs supplémentaires\n"
-"pour les types %s et %s"
-
-#: access/nbtree/nbtvalidate.c:210
-#, c-format
-msgid "btree operator family \"%s\" is missing support function for types %s and %s"
-msgstr ""
-"la famille d'opérateur btree « %s » nécessite une fonction de support\n"
-"pour les types %s et %s"
-
-#: access/nbtree/nbtvalidate.c:224
-#, c-format
-msgid "btree operator class \"%s\" is missing operator(s)"
-msgstr "il manque des opérateurs pour la classe d'opérateur btree « %s »"
-
-#: access/nbtree/nbtvalidate.c:241
-#, c-format
-msgid "btree operator family \"%s\" is missing cross-type operator(s)"
-msgstr "il manque des opérateurs inter-type pour la famille d'opérateur btree « %s »"
-
-#: access/spgist/spgutils.c:700
+#: access/spgist/spgutils.c:705
#, c-format
msgid "SP-GiST inner tuple size %zu exceeds maximum %zu"
msgstr "la taille de la ligne interne SP-GiST, %zu, dépasse le maximum, %zu"
-#: access/spgist/spgvalidate.c:92
-#, c-format
-msgid "spgist operator family \"%s\" contains support procedure %s with cross-type registration"
-msgstr ""
-"la famille d'opérateur spgist « %s » contient la procédure de support\n"
-"%s avec un enregistrement inter-type"
-
-#: access/spgist/spgvalidate.c:115
-#, c-format
-msgid "spgist operator family \"%s\" contains function %s with invalid support number %d"
-msgstr ""
-"la famille d'opérateur spgist « %s » contient la fonction %s\n"
-"avec le numéro de support %d invalide"
-
-#: access/spgist/spgvalidate.c:127
-#, c-format
-msgid "spgist operator family \"%s\" contains function %s with wrong signature for support number %d"
-msgstr ""
-"la famille d'opérateur spgist « %s » contient la fonction %s\n"
-"avec une mauvaise signature pour le numéro de support %d"
-
-#: access/spgist/spgvalidate.c:146
+#: access/spgist/spgvalidate.c:221
#, c-format
-msgid "spgist operator family \"%s\" contains operator %s with invalid strategy number %d"
+msgid "operator family \"%s\" of access method %s is missing support function %d for type %s"
msgstr ""
-"la famille d'opérateur spgist « %s » contient l'opérateur %s\n"
-"avec le numéro de stratégie invalide %d"
-
-#: access/spgist/spgvalidate.c:159
-#, c-format
-msgid "spgist operator family \"%s\" contains invalid ORDER BY specification for operator %s"
-msgstr ""
-"la famille d'opérateur spgist « %s » contient une spécification\n"
-"ORDER BY invalide pour l'opérateur %s"
-
-#: access/spgist/spgvalidate.c:172
-#, c-format
-msgid "spgist operator family \"%s\" contains operator %s with wrong signature"
-msgstr "la famille d'opérateur spgist « %s » contient l'opérateur %s avec une mauvaise signature"
-
-#: access/spgist/spgvalidate.c:200
-#, c-format
-msgid "spgist operator family \"%s\" is missing operator(s) for types %s and %s"
-msgstr ""
-"la famille d'opérateur spgist « %s » nécessite des opérateurs supplémentaires\n"
-"pour les types %s et %s"
-
-#: access/spgist/spgvalidate.c:220
-#, c-format
-msgid "spgist operator family \"%s\" is missing support function %d for type %s"
-msgstr ""
-"la famille d'opérateur spgist « %s » nécessite la fonction de support %d\n"
+"la famille d'opérateur « %s » de la méthode d'accès %s nécessite la fonction de support %d\n"
"pour le type %s"
-#: access/spgist/spgvalidate.c:233
-#, c-format
-msgid "spgist operator class \"%s\" is missing operator(s)"
-msgstr "il manque des opérateurs pour la classe d'opérateur spgist « %s »"
-
#: access/tablesample/bernoulli.c:152 access/tablesample/system.c:156
#, c-format
msgid "sample percentage must be between 0 and 100"
msgstr "le pourcentage de l'échantillonnage doit être compris entre 0 et 100"
-#: access/transam/commit_ts.c:294
+#: access/transam/commit_ts.c:295
#, c-format
msgid "cannot retrieve commit timestamp for transaction %u"
msgstr "ne peut pas récupérer l'horodatage de la validation pour la transaction %u"
-#: access/transam/commit_ts.c:392
+#: access/transam/commit_ts.c:393
#, c-format
msgid "could not get commit timestamp data"
msgstr "n'a pas pu récupérer les données d'horodatage de la validation"
-#: access/transam/commit_ts.c:394
+#: access/transam/commit_ts.c:395
#, c-format
msgid "Make sure the configuration parameter \"%s\" is set on the master server."
msgstr "Assurez-vous que le paramètre de configuration « %s » soit configuré sur le serveur primaire."
-#: access/transam/commit_ts.c:396 libpq/hba.c:1439
+#: access/transam/commit_ts.c:397
#, c-format
msgid "Make sure the configuration parameter \"%s\" is set."
msgstr "Assurez-vous que le paramètre de configuration « %s » soit configuré."
@@ -1140,14 +942,14 @@ msgstr ""
"la base de données n'accepte pas de commandes qui génèrent de nouveaux MultiXactId pour éviter des pertes de données à cause de la réinitialisation de l'identifiant de transaction dans\n"
"la base de données d'OID %u"
-#: access/transam/multixact.c:1028 access/transam/multixact.c:2314
+#: access/transam/multixact.c:1028 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] "un VACUUM doit être exécuté sur la base de données « %s » dans un maximum de %u MultiXactId"
msgstr[1] "un VACUUM doit être exécuté sur la base de données « %s » dans un maximum de %u MultiXactId"
-#: access/transam/multixact.c:1037 access/transam/multixact.c:2323
+#: access/transam/multixact.c:1037 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"
@@ -1193,12 +995,12 @@ msgstr "le MultiXactId %u n'existe plus - wraparound apparent"
msgid "MultiXactId %u has not been created yet -- apparent wraparound"
msgstr "le MultiXactId %u n'a pas encore été créer : wraparound apparent"
-#: access/transam/multixact.c:2264
+#: access/transam/multixact.c:2268
#, c-format
msgid "MultiXactId wrap limit is %u, limited by database with OID %u"
msgstr "La limite de réinitialisation MultiXactId est %u, limité par la base de données d'OID %u"
-#: access/transam/multixact.c:2319 access/transam/multixact.c:2328 access/transam/varsup.c:146 access/transam/varsup.c:153 access/transam/varsup.c:384 access/transam/varsup.c:391
+#: access/transam/multixact.c:2323 access/transam/multixact.c:2332 access/transam/varsup.c:146 access/transam/varsup.c:153 access/transam/varsup.c:405 access/transam/varsup.c:412
#, c-format
msgid ""
"To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
@@ -1208,111 +1010,111 @@ msgstr ""
"base. Vous pouvez avoir besoin d'enregistrer ou d'annuler les anciennes\n"
"transactions préparées."
-#: access/transam/multixact.c:2598
+#: access/transam/multixact.c:2602
#, c-format
msgid "oldest MultiXactId member is at offset %u"
msgstr "le membre le plus ancien du MultiXactId est au décalage %u"
-#: access/transam/multixact.c:2602
+#: 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 "Les protections sur la réutilisation d'un membre MultiXact sont désactivées car le plus ancien MultiXact géré par un checkpoint, %u, n'existe pas sur disque"
-#: access/transam/multixact.c:2624
+#: access/transam/multixact.c:2628
#, c-format
msgid "MultiXact member wraparound protections are now enabled"
msgstr "Les protections sur la réutilisation d'un membre MultiXact sont maintenant activées"
-#: access/transam/multixact.c:2626
+#: access/transam/multixact.c:2631
#, c-format
msgid "MultiXact member stop limit is now %u based on MultiXact %u"
msgstr "La limite d'arrêt d'un membre MultiXact est maintenant %x, base sur le MultiXact %u"
-#: access/transam/multixact.c:3006
+#: access/transam/multixact.c:3011
#, c-format
msgid "oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation"
msgstr "plus ancien MultiXact introuvable %u, plus récent MultiXact %u, ignore le troncage"
-#: access/transam/multixact.c:3024
+#: access/transam/multixact.c:3029
#, c-format
msgid "cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation"
msgstr "ne peut pas tronquer jusqu'au MutiXact %u car il n'existe pas sur disque, ignore le troncage"
-#: access/transam/multixact.c:3350
+#: access/transam/multixact.c:3355
#, c-format
msgid "invalid MultiXactId: %u"
msgstr "MultiXactId invalide : %u"
-#: access/transam/parallel.c:589
+#: access/transam/parallel.c:577
#, c-format
msgid "postmaster exited during a parallel transaction"
msgstr "postmaster a quitté pendant une transaction parallèle"
-#: access/transam/parallel.c:774
+#: access/transam/parallel.c:764
#, c-format
msgid "lost connection to parallel worker"
msgstr "perte de la connexion au processus parallèle"
-#: access/transam/parallel.c:833 access/transam/parallel.c:835
+#: access/transam/parallel.c:823 access/transam/parallel.c:825
msgid "parallel worker"
msgstr "processus parallèle"
-#: access/transam/parallel.c:974
+#: access/transam/parallel.c:968
#, c-format
msgid "could not map dynamic shared memory segment"
msgstr "n'a pas pu mapper le segment de mémoire partagée dynamique"
-#: access/transam/parallel.c:979
+#: access/transam/parallel.c:973
#, c-format
msgid "invalid magic number in dynamic shared memory segment"
msgstr "numéro magique invalide dans le segment de mémoire partagée dynamique"
-#: access/transam/slru.c:665
+#: access/transam/slru.c:668
#, c-format
msgid "file \"%s\" doesn't exist, reading as zeroes"
msgstr "le fichier « %s » n'existe pas, contenu lu comme des zéros"
-#: access/transam/slru.c:895 access/transam/slru.c:901 access/transam/slru.c:908 access/transam/slru.c:915 access/transam/slru.c:922 access/transam/slru.c:929
+#: access/transam/slru.c:907 access/transam/slru.c:913 access/transam/slru.c:920 access/transam/slru.c:927 access/transam/slru.c:934 access/transam/slru.c:941
#, c-format
msgid "could not access status of transaction %u"
msgstr "n'a pas pu accéder au statut de la transaction %u"
-#: access/transam/slru.c:896
+#: access/transam/slru.c:908
#, c-format
msgid "Could not open file \"%s\": %m."
-msgstr "N'a pas pu ouvrir le fichier « %s » : %m"
+msgstr "N'a pas pu ouvrir le fichier « %s » : %m."
-#: access/transam/slru.c:902
+#: access/transam/slru.c:914
#, c-format
msgid "Could not seek in file \"%s\" to offset %u: %m."
-msgstr "N'a pas pu se déplacer dans le fichier « %s » au décalage %u : %m"
+msgstr "N'a pas pu se déplacer dans le fichier « %s » au décalage %u : %m."
-#: access/transam/slru.c:909
+#: access/transam/slru.c:921
#, c-format
msgid "Could not read from file \"%s\" at offset %u: %m."
-msgstr "N'a pas pu lire le fichier « %s » au décalage %u : %m"
+msgstr "N'a pas pu lire le fichier « %s » au décalage %u : %m."
-#: access/transam/slru.c:916
+#: access/transam/slru.c:928
#, c-format
msgid "Could not write to file \"%s\" at offset %u: %m."
-msgstr "N'a pas pu écrire le fichier « %s » au décalage %u : %m"
+msgstr "N'a pas pu écrire le fichier « %s » au décalage %u : %m."
-#: access/transam/slru.c:923
+#: access/transam/slru.c:935
#, c-format
msgid "Could not fsync file \"%s\": %m."
-msgstr "N'a pas pu synchroniser sur disque (fsync) le fichier « %s » : %m"
+msgstr "N'a pas pu synchroniser sur disque (fsync) le fichier « %s » : %m."
-#: access/transam/slru.c:930
+#: access/transam/slru.c:942
#, c-format
msgid "Could not close file \"%s\": %m."
-msgstr "N'a pas pu fermer le fichier « %s » : %m"
+msgstr "N'a pas pu fermer le fichier « %s » : %m."
-#: access/transam/slru.c:1185
+#: access/transam/slru.c:1199
#, c-format
msgid "could not truncate directory \"%s\": apparent wraparound"
msgstr "n'a pas pu tronquer le répertoire « %s » : contournement apparent"
-#: access/transam/slru.c:1240 access/transam/slru.c:1296
+#: access/transam/slru.c:1254 access/transam/slru.c:1310
#, c-format
msgid "removing file \"%s\""
msgstr "suppression du fichier « %s »"
@@ -1325,17 +1127,17 @@ msgstr "erreur de syntaxe dans le fichier historique : %s"
#: access/transam/timeline.c:149
#, c-format
msgid "Expected a numeric timeline ID."
-msgstr "Identifiant timeline numérique attendue"
+msgstr "Attendait un identifiant timeline numérique."
#: access/transam/timeline.c:154
#, c-format
-msgid "Expected a transaction log switchpoint location."
-msgstr "Attendait un emplacement de bascule dans le journal de transactions."
+msgid "Expected a write-ahead log switchpoint location."
+msgstr "Attendait un emplacement de bascule de journal de transactions."
#: access/transam/timeline.c:158
#, c-format
msgid "invalid data in history file: %s"
-msgstr "données invalides dans le fichier historique : « %s »"
+msgstr "données invalides dans le fichier historique : %s"
#: access/transam/timeline.c:159
#, c-format
@@ -1354,182 +1156,197 @@ msgstr ""
"Les identifiants timeline doivent être plus petits que les enfants des\n"
"identifiants timeline."
-#: access/transam/timeline.c:412 access/transam/timeline.c:488 access/transam/xlog.c:3093 access/transam/xlog.c:3254 access/transam/xlogfuncs.c:690 commands/copy.c:1708 storage/file/copydir.c:201
+#: access/transam/timeline.c:418 access/transam/timeline.c:498 access/transam/xlog.c:3256 access/transam/xlog.c:3423 access/transam/xlogfuncs.c:693 commands/copy.c:1776 storage/file/copydir.c:206
#, c-format
msgid "could not close file \"%s\": %m"
msgstr "n'a pas pu fermer le fichier « %s » : %m"
-#: access/transam/timeline.c:570
+#: access/transam/timeline.c:580
#, c-format
msgid "requested timeline %u is not in this server's history"
msgstr "la timeline %u requise n'est pas dans l'historique de ce serveur"
-#: access/transam/twophase.c:363
+#: access/transam/twophase.c:383
#, c-format
msgid "transaction identifier \"%s\" is too long"
msgstr "l'identifiant de la transaction « %s » est trop long"
-#: access/transam/twophase.c:370
+#: access/transam/twophase.c:390
#, c-format
msgid "prepared transactions are disabled"
msgstr "les transactions préparées sont désactivées"
-#: access/transam/twophase.c:371
+#: access/transam/twophase.c:391
#, c-format
msgid "Set max_prepared_transactions to a nonzero value."
msgstr "Configure max_prepared_transactions à une valeur différente de zéro."
-#: access/transam/twophase.c:390
+#: access/transam/twophase.c:410
#, c-format
msgid "transaction identifier \"%s\" is already in use"
msgstr "l'identifiant de la transaction « %s » est déjà utilisé"
-#: access/transam/twophase.c:399
+#: access/transam/twophase.c:419 access/transam/twophase.c:2340
#, c-format
msgid "maximum number of prepared transactions reached"
msgstr "nombre maximum de transactions préparées obtenu"
-#: access/transam/twophase.c:400
+#: access/transam/twophase.c:420 access/transam/twophase.c:2341
#, c-format
msgid "Increase max_prepared_transactions (currently %d)."
msgstr "Augmentez max_prepared_transactions (actuellement %d)."
-#: access/transam/twophase.c:540
+#: access/transam/twophase.c:587
#, c-format
msgid "prepared transaction with identifier \"%s\" is busy"
msgstr "la transaction préparée d'identifiant « %s » est occupée"
-#: access/transam/twophase.c:546
+#: access/transam/twophase.c:593
#, c-format
msgid "permission denied to finish prepared transaction"
msgstr "droit refusé pour terminer la transaction préparée"
-#: access/transam/twophase.c:547
+#: access/transam/twophase.c:594
#, c-format
msgid "Must be superuser or the user that prepared the transaction."
msgstr "Doit être super-utilisateur ou l'utilisateur qui a préparé la transaction."
-#: access/transam/twophase.c:558
+#: access/transam/twophase.c:605
#, c-format
msgid "prepared transaction belongs to another database"
msgstr "la transaction préparée appartient à une autre base de données"
-#: access/transam/twophase.c:559
+#: access/transam/twophase.c:606
#, c-format
msgid "Connect to the database where the transaction was prepared to finish it."
msgstr ""
"Connectez-vous à la base de données où la transaction a été préparée pour\n"
"la terminer."
-#: access/transam/twophase.c:574
+#: access/transam/twophase.c:621
#, c-format
msgid "prepared transaction with identifier \"%s\" does not exist"
msgstr "la transaction préparée d'identifiant « %s » n'existe pas"
-#: access/transam/twophase.c:1043
+#: access/transam/twophase.c:1086
#, c-format
msgid "two-phase state file maximum length exceeded"
msgstr ""
"longueur maximale dépassée pour le fichier de statut de la validation en\n"
"deux phase"
-#: access/transam/twophase.c:1161
+#: access/transam/twophase.c:1204
#, c-format
msgid "could not open two-phase state file \"%s\": %m"
msgstr ""
"n'a pas pu ouvrir le fichier d'état de la validation en deux phases nommé\n"
"« %s » : %m"
-#: access/transam/twophase.c:1178
+#: access/transam/twophase.c:1221
#, c-format
msgid "could not stat two-phase state file \"%s\": %m"
msgstr ""
"n'a pas pu récupérer des informations sur le fichier d'état de la validation\n"
"en deux phases nommé « %s » : %m"
-#: access/transam/twophase.c:1210
+#: access/transam/twophase.c:1255
#, c-format
msgid "could not read two-phase state file \"%s\": %m"
msgstr ""
"n'a pas pu lire le fichier d'état de la validation en deux phases nommé\n"
"« %s » : %m"
-#: access/transam/twophase.c:1263 access/transam/xlog.c:6109
+#: access/transam/twophase.c:1307 access/transam/xlog.c:6356
#, c-format
-msgid "Failed while allocating an XLog reading processor."
-msgstr "Échec lors de l'allocation d'un processeur de lecture XLog"
+msgid "Failed while allocating a WAL reading processor."
+msgstr "Échec lors de l'allocation d'un processeur de lecture de journaux de transactions."
-#: access/transam/twophase.c:1269
+#: access/transam/twophase.c:1313
#, c-format
-msgid "could not read two-phase state from xlog at %X/%X"
-msgstr "n'a pas pu lire le fichier d'état de la validation en deux phases depuis les journaux de transaction à %X/%X"
+msgid "could not read two-phase state from WAL at %X/%X"
+msgstr "n'a pas pu lire le fichier d'état de la validation en deux phases depuis les journaux de transactions à %X/%X"
-#: access/transam/twophase.c:1277
+#: access/transam/twophase.c:1321
#, c-format
-msgid "expected two-phase state data is not present in xlog at %X/%X"
+msgid "expected two-phase state data is not present in WAL at %X/%X"
msgstr ""
"le fichier d'état de la validation en deux phases attendu n'est pas présent\n"
"dans les journaux de transaction à %X/%X"
-#: access/transam/twophase.c:1512
+#: access/transam/twophase.c:1558
#, c-format
msgid "could not remove two-phase state file \"%s\": %m"
msgstr ""
"n'a pas pu supprimer le fichier d'état de la validation en deux phases\n"
"« %s » : %m"
-#: access/transam/twophase.c:1542
+#: access/transam/twophase.c:1588
#, c-format
msgid "could not recreate two-phase state file \"%s\": %m"
msgstr ""
"n'a pas pu re-créer le fichier d'état de la validation en deux phases nommé\n"
"« %s » : %m"
-#: access/transam/twophase.c:1551 access/transam/twophase.c:1558
+#: access/transam/twophase.c:1599 access/transam/twophase.c:1607
#, c-format
msgid "could not write two-phase state file: %m"
msgstr "n'a pas pu écrire dans le fichier d'état de la validation en deux phases : %m"
-#: access/transam/twophase.c:1570
+#: access/transam/twophase.c:1621
#, c-format
msgid "could not fsync two-phase state file: %m"
msgstr ""
"n'a pas pu synchroniser sur disque (fsync) le fichier d'état de la\n"
"validation en deux phases : %m"
-#: access/transam/twophase.c:1576
+#: access/transam/twophase.c:1628
#, c-format
msgid "could not close two-phase state file: %m"
msgstr "n'a pas pu fermer le fichier d'état de la validation en deux phases : %m"
-#: access/transam/twophase.c:1649
+#: access/transam/twophase.c:1716
#, c-format
-msgid "%u two-phase state file was written for long-running prepared transactions"
+msgid "%u two-phase state file was written for a long-running prepared transaction"
msgid_plural "%u two-phase state files were written for long-running prepared transactions"
-msgstr[0] "le fichier d'état de la validation en deux phases %u a été écrit pour des transaction préparée de longue duré"
-msgstr[1] "les fichiers d'état de la validation en deux phases %u a été écrit pour des transaction préparée de longue duré"
+msgstr[0] "le fichier d'état de la validation en deux phases %u a été écrit pour une transaction préparée de longue durée"
+msgstr[1] "les fichiers d'état de la validation en deux phases %u a été écrit pour des transactions préparées de longue durée"
-#: access/transam/twophase.c:1713
+#: access/transam/twophase.c:1944
#, c-format
-msgid "removing future two-phase state file \"%s\""
-msgstr "suppression du futur fichier d'état de la validation en deux phases nommé « %s »"
+msgid "recovering prepared transaction %u from shared memory"
+msgstr "récupération de la transaction préparée %u à partir de la mémoire partagée"
-#: access/transam/twophase.c:1729 access/transam/twophase.c:1740 access/transam/twophase.c:1860 access/transam/twophase.c:1871 access/transam/twophase.c:1948
+#: access/transam/twophase.c:2034
#, c-format
-msgid "removing corrupt two-phase state file \"%s\""
-msgstr ""
-"suppression du fichier d'état corrompu de la validation en deux phases nommé\n"
-"« %s »"
+msgid "removing stale two-phase state file for \"%u\""
+msgstr "suppression du vieux fichier d'état de la validation en deux phases pour %u"
+
+#: access/transam/twophase.c:2041
+#, c-format
+msgid "removing stale two-phase state from shared memory for \"%u\""
+msgstr "suppression du vieux fichier d'état de la validation en deux phases nommé à partir de la mémoire partagée pour « %u »"
+
+#: access/transam/twophase.c:2054
+#, c-format
+msgid "removing future two-phase state file for \"%u\""
+msgstr "suppression du futur fichier d'état de la validation en deux phases pour « %u »"
-#: access/transam/twophase.c:1849 access/transam/twophase.c:1937
+#: access/transam/twophase.c:2061
#, c-format
-msgid "removing stale two-phase state file \"%s\""
-msgstr "suppression du vieux fichier d'état de la validation en deux phases nommé « %s »"
+msgid "removing future two-phase state from memory for \"%u\""
+msgstr "suppression du futur fichier d'état de la validation en deux phases en mémoire pour « %u »"
-#: access/transam/twophase.c:1955
+#: access/transam/twophase.c:2075 access/transam/twophase.c:2094
#, c-format
-msgid "recovering prepared transaction %u"
-msgstr "récupération de la transaction préparée %u"
+msgid "removing corrupt two-phase state file for \"%u\""
+msgstr "suppression du fichier d'état corrompu de la validation en deux phases pour « %u »"
+
+#: access/transam/twophase.c:2101
+#, c-format
+msgid "removing corrupt two-phase state from memory for \"%u\""
+msgstr ""
+"suppression du fichier d'état corrompu de la validation en deux phases en mémoire\n"
+"pour « %u »"
#: access/transam/varsup.c:124
#, c-format
@@ -1557,63 +1374,63 @@ msgstr ""
"données à cause de la réinitialisation de l'identifiant de transaction dans\n"
"la base de données %u"
-#: access/transam/varsup.c:143 access/transam/varsup.c:381
+#: access/transam/varsup.c:143 access/transam/varsup.c:402
#, c-format
msgid "database \"%s\" must be vacuumed within %u transactions"
msgstr ""
-"Un VACUUM doit être exécuté sur la base de données « %s » dans un maximum de\n"
+"un VACUUM doit être exécuté sur la base de données « %s » dans un maximum de\n"
"%u transactions"
-#: access/transam/varsup.c:150 access/transam/varsup.c:388
+#: access/transam/varsup.c:150 access/transam/varsup.c:409
#, c-format
msgid "database with OID %u must be vacuumed within %u transactions"
msgstr ""
"un VACUUM doit être exécuté sur la base de données d'OID %u dans un maximum de\n"
"%u transactions"
-#: access/transam/varsup.c:346
+#: access/transam/varsup.c:367
#, c-format
msgid "transaction ID wrap limit is %u, limited by database with OID %u"
msgstr ""
"la limite de réinitialisation de l'identifiant de transaction est %u,\n"
"limité par la base de données d'OID %u"
-#: access/transam/xact.c:943
+#: access/transam/xact.c:946
#, c-format
msgid "cannot have more than 2^32-2 commands in a transaction"
msgstr "ne peux pas avoir plus de 2^32-2 commandes dans une transaction"
-#: access/transam/xact.c:1467
+#: access/transam/xact.c:1471
#, c-format
msgid "maximum number of committed subtransactions (%d) exceeded"
msgstr "nombre maximum de sous-transactions validées (%d) dépassé"
-#: access/transam/xact.c:2263
+#: access/transam/xact.c:2268
#, c-format
msgid "cannot PREPARE a transaction that has operated on temporary tables"
msgstr ""
"ne peut pas préparer (PREPARE) une transaction qui a travaillé sur des\n"
"tables temporaires"
-#: access/transam/xact.c:2273
+#: access/transam/xact.c:2278
#, c-format
msgid "cannot PREPARE a transaction that has exported snapshots"
msgstr "ne peut pas préparer (PREPARE) une transaction qui a exporté des snapshots"
#. translator: %s represents an SQL statement name
-#: access/transam/xact.c:3155
+#: access/transam/xact.c:3164
#, c-format
msgid "%s cannot run inside a transaction block"
msgstr "%s ne peut pas être exécuté dans un bloc de transaction"
#. translator: %s represents an SQL statement name
-#: access/transam/xact.c:3165
+#: access/transam/xact.c:3174
#, c-format
msgid "%s cannot run inside a subtransaction"
msgstr "%s ne peut pas être exécuté dans un sous-bloc de transaction"
#. translator: %s represents an SQL statement name
-#: access/transam/xact.c:3175
+#: access/transam/xact.c:3184
#, c-format
msgid "%s cannot be executed from a function or multi-command string"
msgstr ""
@@ -1621,207 +1438,197 @@ msgstr ""
"contenant plusieurs commandes"
#. translator: %s represents an SQL statement name
-#: access/transam/xact.c:3246
+#: access/transam/xact.c:3255
#, c-format
msgid "%s can only be used in transaction blocks"
msgstr "%s peut seulement être utilisé dans des blocs de transaction"
-#: access/transam/xact.c:3430
+#: access/transam/xact.c:3439
#, c-format
msgid "there is already a transaction in progress"
msgstr "une transaction est déjà en cours"
-#: access/transam/xact.c:3598 access/transam/xact.c:3701
+#: access/transam/xact.c:3607 access/transam/xact.c:3710
#, c-format
msgid "there is no transaction in progress"
msgstr "aucune transaction en cours"
-#: access/transam/xact.c:3609
+#: access/transam/xact.c:3618
#, c-format
msgid "cannot commit during a parallel operation"
msgstr "ne peut pas valider pendant une opération parallèle"
-#: access/transam/xact.c:3712
+#: access/transam/xact.c:3721
#, c-format
msgid "cannot abort during a parallel operation"
msgstr "ne peut pas annuler pendant une opération en parallèle"
-#: access/transam/xact.c:3754
+#: access/transam/xact.c:3763
#, c-format
msgid "cannot define savepoints during a parallel operation"
msgstr "ne peut pas définir de points de sauvegarde lors d'une opération parallèle"
-#: access/transam/xact.c:3821
+#: access/transam/xact.c:3830
#, c-format
msgid "cannot release savepoints during a parallel operation"
msgstr "ne peut pas relâcher de points de sauvegarde pendant une opération parallèle"
-#: access/transam/xact.c:3832 access/transam/xact.c:3884 access/transam/xact.c:3890 access/transam/xact.c:3946 access/transam/xact.c:3996 access/transam/xact.c:4002
+#: access/transam/xact.c:3841 access/transam/xact.c:3893 access/transam/xact.c:3899 access/transam/xact.c:3955 access/transam/xact.c:4005 access/transam/xact.c:4011
#, c-format
msgid "no such savepoint"
msgstr "aucun point de sauvegarde"
-#: access/transam/xact.c:3934
+#: access/transam/xact.c:3943
#, c-format
msgid "cannot rollback to savepoints during a parallel operation"
msgstr "ne peut pas retourner à un point de sauvegarde pendant un opération parallèle"
-#: access/transam/xact.c:4062
+#: access/transam/xact.c:4071
#, c-format
msgid "cannot start subtransactions during a parallel operation"
msgstr "ne peut pas lancer de sous-transactions pendant une opération parallèle"
-#: access/transam/xact.c:4129
+#: access/transam/xact.c:4138
#, c-format
msgid "cannot commit subtransactions during a parallel operation"
msgstr "ne peut pas valider de sous-transactions pendant une opération parallèle"
-#: access/transam/xact.c:4737
+#: access/transam/xact.c:4746
#, c-format
msgid "cannot have more than 2^32-1 subtransactions in a transaction"
msgstr "ne peut pas avoir plus de 2^32-1 sous-transactions dans une transaction"
-#: access/transam/xlog.c:2299
+#: access/transam/xlog.c:2455
#, c-format
msgid "could not seek in log file %s to offset %u: %m"
msgstr "n'a pas pu se déplacer dans le fichier de transactions « %s » au décalage %u : %m"
-#: access/transam/xlog.c:2319
+#: access/transam/xlog.c:2477
#, c-format
msgid "could not write to log file %s at offset %u, length %zu: %m"
msgstr "n'a pas pu écrire le fichier de transactions %s au décalage %u, longueur %zu : %m"
-#: access/transam/xlog.c:2582
+#: access/transam/xlog.c:2741
#, c-format
msgid "updated min recovery point to %X/%X on timeline %u"
msgstr "mise à jour du point minimum de restauration sur %X/%X pour la timeline %u"
-#: access/transam/xlog.c:3224
+#: access/transam/xlog.c:3388
#, c-format
msgid "not enough data in file \"%s\""
msgstr "données insuffisantes dans le fichier « %s »"
-#: access/transam/xlog.c:3365
+#: access/transam/xlog.c:3534
#, c-format
-msgid "could not open transaction log file \"%s\": %m"
-msgstr "n'a pas pu ouvrir le journal des transactions « %s » : %m"
+msgid "could not open write-ahead log file \"%s\": %m"
+msgstr "n'a pas pu écrire dans le journal de transactions « %s » : %m"
-#: access/transam/xlog.c:3554 access/transam/xlog.c:5339
+#: access/transam/xlog.c:3723 access/transam/xlog.c:5541
#, c-format
msgid "could not close log file %s: %m"
msgstr "n'a pas pu fermer le fichier de transactions « %s » : %m"
-#: access/transam/xlog.c:3611 access/transam/xlogutils.c:696 replication/walsender.c:2097
+#: access/transam/xlog.c:3780 access/transam/xlogutils.c:701 replication/walsender.c:2380
#, c-format
msgid "requested WAL segment %s has already been removed"
msgstr "le segment demandé du journal de transaction, %s, a déjà été supprimé"
-#: access/transam/xlog.c:3671 access/transam/xlog.c:3746 access/transam/xlog.c:3944
+#: access/transam/xlog.c:3840 access/transam/xlog.c:3915 access/transam/xlog.c:4110
#, c-format
-msgid "could not open transaction log directory \"%s\": %m"
+msgid "could not open write-ahead log directory \"%s\": %m"
msgstr "n'a pas pu ouvrir le répertoire des journaux de transactions « %s » : %m"
-#: access/transam/xlog.c:3827
+#: access/transam/xlog.c:3996
#, c-format
-msgid "recycled transaction log file \"%s\""
+msgid "recycled write-ahead log file \"%s\""
msgstr "recyclage du journal de transactions « %s »"
-#: access/transam/xlog.c:3839
+#: access/transam/xlog.c:4008
#, c-format
-msgid "removing transaction log file \"%s\""
+msgid "removing write-ahead log file \"%s\""
msgstr "suppression du journal de transactions « %s »"
-#: access/transam/xlog.c:3859
+#: access/transam/xlog.c:4028
#, c-format
-msgid "could not rename old transaction log file \"%s\": %m"
+msgid "could not rename old write-ahead log file \"%s\": %m"
msgstr "n'a pas pu renommer l'ancien journal de transactions « %s » : %m"
-#: access/transam/xlog.c:3871
-#, c-format
-msgid "could not remove old transaction log file \"%s\": %m"
-msgstr "n'a pas pu supprimer l'ancien journal de transaction « %s » : %m"
-
-#: access/transam/xlog.c:3904 access/transam/xlog.c:3914
+#: access/transam/xlog.c:4070 access/transam/xlog.c:4080
#, c-format
msgid "required WAL directory \"%s\" does not exist"
msgstr "le répertoire « %s » requis pour les journaux de transactions n'existe pas"
-#: access/transam/xlog.c:3920
+#: access/transam/xlog.c:4086
#, c-format
msgid "creating missing WAL directory \"%s\""
msgstr "création du répertoire manquant « %s » pour les journaux de transactions"
-#: access/transam/xlog.c:3923
+#: access/transam/xlog.c:4089
#, c-format
msgid "could not create missing directory \"%s\": %m"
msgstr "n'a pas pu créer le répertoire « %s » manquant : %m"
-#: access/transam/xlog.c:3954
-#, c-format
-msgid "removing transaction log backup history file \"%s\""
-msgstr "suppression du fichier historique des journaux de transaction « %s »"
-
-#: access/transam/xlog.c:4035
+#: access/transam/xlog.c:4200
#, c-format
msgid "unexpected timeline ID %u in log segment %s, offset %u"
msgstr "identifiant timeline %u inattendu dans le journal de transactions %s, décalage %u"
-#: access/transam/xlog.c:4157
+#: access/transam/xlog.c:4322
#, c-format
msgid "new timeline %u is not a child of database system timeline %u"
msgstr ""
"le nouveau timeline %u n'est pas un fils du timeline %u du système de bases\n"
"de données"
-#: access/transam/xlog.c:4171
+#: access/transam/xlog.c:4336
#, c-format
msgid "new timeline %u forked off current database system timeline %u before current recovery point %X/%X"
msgstr ""
"la nouvelle timeline %u a été créée à partir de la timeline de la base de données système %u\n"
"avant le point de restauration courant %X/%X"
-#: access/transam/xlog.c:4190
+#: access/transam/xlog.c:4355
#, c-format
msgid "new target timeline is %u"
msgstr "la nouvelle timeline cible est %u"
-#: access/transam/xlog.c:4270
+#: access/transam/xlog.c:4436
#, c-format
msgid "could not create control file \"%s\": %m"
msgstr "n'a pas pu créer le fichier de contrôle « %s » : %m"
-#: access/transam/xlog.c:4281 access/transam/xlog.c:4517
+#: access/transam/xlog.c:4448 access/transam/xlog.c:4674
#, c-format
msgid "could not write to control file: %m"
msgstr "n'a pas pu écrire le fichier de contrôle : %m"
-#: access/transam/xlog.c:4287 access/transam/xlog.c:4523
+#: access/transam/xlog.c:4456 access/transam/xlog.c:4682
#, c-format
msgid "could not fsync control file: %m"
msgstr "n'a pas pu synchroniser sur disque (fsync) le fichier de contrôle : %m"
-#: access/transam/xlog.c:4292 access/transam/xlog.c:4528
+#: access/transam/xlog.c:4462 access/transam/xlog.c:4688
#, c-format
msgid "could not close control file: %m"
msgstr "n'a pas pu fermer le fichier de contrôle : %m"
-#: access/transam/xlog.c:4310 access/transam/xlog.c:4506
+#: access/transam/xlog.c:4480 access/transam/xlog.c:4662
#, c-format
msgid "could not open control file \"%s\": %m"
msgstr "n'a pas pu ouvrir le fichier de contrôle « %s » : %m"
-#: access/transam/xlog.c:4316
+#: access/transam/xlog.c:4487
#, c-format
msgid "could not read from control file: %m"
msgstr "n'a pas pu lire le fichier de contrôle : %m"
-#: access/transam/xlog.c:4329 access/transam/xlog.c:4338 access/transam/xlog.c:4362 access/transam/xlog.c:4369 access/transam/xlog.c:4376 access/transam/xlog.c:4381 access/transam/xlog.c:4388 access/transam/xlog.c:4395 access/transam/xlog.c:4402 access/transam/xlog.c:4409 access/transam/xlog.c:4416 access/transam/xlog.c:4423 access/transam/xlog.c:4430 access/transam/xlog.c:4439 access/transam/xlog.c:4446 access/transam/xlog.c:4455
-#: access/transam/xlog.c:4462 access/transam/xlog.c:4471 access/transam/xlog.c:4478 utils/init/miscinit.c:1380
+#: access/transam/xlog.c:4501 access/transam/xlog.c:4510 access/transam/xlog.c:4534 access/transam/xlog.c:4541 access/transam/xlog.c:4548 access/transam/xlog.c:4553 access/transam/xlog.c:4560 access/transam/xlog.c:4567 access/transam/xlog.c:4574 access/transam/xlog.c:4581 access/transam/xlog.c:4588 access/transam/xlog.c:4595 access/transam/xlog.c:4602 access/transam/xlog.c:4611 access/transam/xlog.c:4618 access/transam/xlog.c:4627
+#: access/transam/xlog.c:4634 utils/init/miscinit.c:1406
#, c-format
msgid "database files are incompatible with server"
msgstr "les fichiers de la base de données sont incompatibles avec le serveur"
-#: access/transam/xlog.c:4330
+#: access/transam/xlog.c:4502
#, c-format
msgid "The database cluster was initialized with PG_CONTROL_VERSION %d (0x%08x), but the server was compiled with PG_CONTROL_VERSION %d (0x%08x)."
msgstr ""
@@ -1829,300 +1636,303 @@ msgstr ""
"%d (0x%08x) alors que le serveur a été compilé avec un PG_CONTROL_VERSION à\n"
"%d (0x%08x)."
-#: access/transam/xlog.c:4334
+#: access/transam/xlog.c:4506
#, c-format
msgid "This could be a problem of mismatched byte ordering. It looks like you need to initdb."
msgstr ""
"Ceci peut être un problème d'incohérence dans l'ordre des octets.\n"
"Il se peut que vous ayez besoin d'initdb."
-#: access/transam/xlog.c:4339
+#: access/transam/xlog.c:4511
#, c-format
msgid "The database cluster was initialized with PG_CONTROL_VERSION %d, but the server was compiled with PG_CONTROL_VERSION %d."
msgstr ""
"Le cluster de base de données a été initialisé avec un PG_CONTROL_VERSION à\n"
"%d alors que le serveur a été compilé avec un PG_CONTROL_VERSION à %d."
-#: access/transam/xlog.c:4342 access/transam/xlog.c:4366 access/transam/xlog.c:4373 access/transam/xlog.c:4378
+#: access/transam/xlog.c:4514 access/transam/xlog.c:4538 access/transam/xlog.c:4545 access/transam/xlog.c:4550
#, c-format
msgid "It looks like you need to initdb."
msgstr "Il semble que vous avez besoin d'initdb."
-#: access/transam/xlog.c:4353
+#: access/transam/xlog.c:4525
#, c-format
msgid "incorrect checksum in control file"
msgstr "somme de contrôle incorrecte dans le fichier de contrôle"
-#: access/transam/xlog.c:4363
+#: access/transam/xlog.c:4535
#, c-format
msgid "The database cluster was initialized with CATALOG_VERSION_NO %d, but the server was compiled with CATALOG_VERSION_NO %d."
msgstr ""
"Le cluster de base de données a été initialisé avec un CATALOG_VERSION_NO à\n"
"%d alors que le serveur a été compilé avec un CATALOG_VERSION_NO à %d."
-#: access/transam/xlog.c:4370
+#: access/transam/xlog.c:4542
#, c-format
msgid "The database cluster was initialized with MAXALIGN %d, but the server was compiled with MAXALIGN %d."
msgstr ""
"Le cluster de bases de données a été initialisé avec un MAXALIGN à %d alors\n"
"que le serveur a été compilé avec un MAXALIGN à %d."
-#: access/transam/xlog.c:4377
+#: access/transam/xlog.c:4549
#, c-format
msgid "The database cluster appears to use a different floating-point number format than the server executable."
msgstr ""
"Le cluster de bases de données semble utiliser un format différent pour les\n"
"nombres à virgule flottante de celui de l'exécutable serveur."
-#: access/transam/xlog.c:4382
+#: access/transam/xlog.c:4554
#, c-format
msgid "The database cluster was initialized with BLCKSZ %d, but the server was compiled with BLCKSZ %d."
msgstr ""
"Le cluster de base de données a été initialisé avec un BLCKSZ à %d alors que\n"
"le serveur a été compilé avec un BLCKSZ à %d."
-#: access/transam/xlog.c:4385 access/transam/xlog.c:4392 access/transam/xlog.c:4399 access/transam/xlog.c:4406 access/transam/xlog.c:4413 access/transam/xlog.c:4420 access/transam/xlog.c:4427 access/transam/xlog.c:4434 access/transam/xlog.c:4442 access/transam/xlog.c:4449 access/transam/xlog.c:4458 access/transam/xlog.c:4465 access/transam/xlog.c:4474 access/transam/xlog.c:4481
+#: access/transam/xlog.c:4557 access/transam/xlog.c:4564 access/transam/xlog.c:4571 access/transam/xlog.c:4578 access/transam/xlog.c:4585 access/transam/xlog.c:4592 access/transam/xlog.c:4599 access/transam/xlog.c:4606 access/transam/xlog.c:4614 access/transam/xlog.c:4621 access/transam/xlog.c:4630 access/transam/xlog.c:4637
#, c-format
msgid "It looks like you need to recompile or initdb."
msgstr "Il semble que vous avez besoin de recompiler ou de relancer initdb."
-#: access/transam/xlog.c:4389
+#: access/transam/xlog.c:4561
#, c-format
msgid "The database cluster was initialized with RELSEG_SIZE %d, but the server was compiled with RELSEG_SIZE %d."
msgstr ""
"Le cluster de bases de données a été initialisé avec un RELSEG_SIZE à %d\n"
"alors que le serveur a été compilé avec un RELSEG_SIZE à %d."
-#: access/transam/xlog.c:4396
+#: access/transam/xlog.c:4568
#, c-format
msgid "The database cluster was initialized with XLOG_BLCKSZ %d, but the server was compiled with XLOG_BLCKSZ %d."
msgstr ""
"Le cluster de base de données a été initialisé avec un XLOG_BLCKSZ à %d\n"
"alors que le serveur a été compilé avec un XLOG_BLCKSZ à %d."
-#: access/transam/xlog.c:4403
+#: access/transam/xlog.c:4575
#, c-format
msgid "The database cluster was initialized with XLOG_SEG_SIZE %d, but the server was compiled with XLOG_SEG_SIZE %d."
msgstr ""
"Le cluster de bases de données a été initialisé avec un XLOG_SEG_SIZE à %d\n"
"alors que le serveur a été compilé avec un XLOG_SEG_SIZE à %d."
-#: access/transam/xlog.c:4410
+#: access/transam/xlog.c:4582
#, c-format
msgid "The database cluster was initialized with NAMEDATALEN %d, but the server was compiled with NAMEDATALEN %d."
msgstr ""
"Le cluster de bases de données a été initialisé avec un NAMEDATALEN à %d\n"
"alors que le serveur a été compilé avec un NAMEDATALEN à %d."
-#: access/transam/xlog.c:4417
+#: access/transam/xlog.c:4589
#, c-format
msgid "The database cluster was initialized with INDEX_MAX_KEYS %d, but the server was compiled with INDEX_MAX_KEYS %d."
msgstr ""
"Le groupe de bases de données a été initialisé avec un INDEX_MAX_KEYS à %d\n"
"alors que le serveur a été compilé avec un INDEX_MAX_KEYS à %d."
-#: access/transam/xlog.c:4424
+#: access/transam/xlog.c:4596
#, c-format
msgid "The database cluster was initialized with TOAST_MAX_CHUNK_SIZE %d, but the server was compiled with TOAST_MAX_CHUNK_SIZE %d."
msgstr ""
"Le cluster de bases de données a été initialisé avec un TOAST_MAX_CHUNK_SIZE\n"
"à %d alors que le serveur a été compilé avec un TOAST_MAX_CHUNK_SIZE à %d."
-#: access/transam/xlog.c:4431
+#: access/transam/xlog.c:4603
#, c-format
msgid "The database cluster was initialized with LOBLKSIZE %d, but the server was compiled with LOBLKSIZE %d."
msgstr ""
"Le cluster de base de données a été initialisé avec un LOBLKSIZE à %d alors que\n"
"le serveur a été compilé avec un LOBLKSIZE à %d."
-#: access/transam/xlog.c:4440
-#, c-format
-msgid "The database cluster was initialized without HAVE_INT64_TIMESTAMP but the server was compiled with HAVE_INT64_TIMESTAMP."
-msgstr "Le cluster de bases de données a été initialisé sans HAVE_INT64_TIMESTAMPalors que le serveur a été compilé avec."
-
-#: access/transam/xlog.c:4447
-#, c-format
-msgid "The database cluster was initialized with HAVE_INT64_TIMESTAMP but the server was compiled without HAVE_INT64_TIMESTAMP."
-msgstr ""
-"Le cluster de bases de données a été initialisé avec HAVE_INT64_TIMESTAMP\n"
-"alors que le serveur a été compilé sans."
-
-#: access/transam/xlog.c:4456
+#: access/transam/xlog.c:4612
#, c-format
msgid "The database cluster was initialized without USE_FLOAT4_BYVAL but the server was compiled with USE_FLOAT4_BYVAL."
msgstr ""
"Le cluster de base de données a été initialisé sans USE_FLOAT4_BYVAL\n"
"alors que le serveur a été compilé avec USE_FLOAT4_BYVAL."
-#: access/transam/xlog.c:4463
+#: access/transam/xlog.c:4619
#, c-format
msgid "The database cluster was initialized with USE_FLOAT4_BYVAL but the server was compiled without USE_FLOAT4_BYVAL."
msgstr ""
"Le cluster de base de données a été initialisé avec USE_FLOAT4_BYVAL\n"
"alors que le serveur a été compilé sans USE_FLOAT4_BYVAL."
-#: access/transam/xlog.c:4472
+#: access/transam/xlog.c:4628
#, c-format
msgid "The database cluster was initialized without USE_FLOAT8_BYVAL but the server was compiled with USE_FLOAT8_BYVAL."
msgstr ""
"Le cluster de base de données a été initialisé sans USE_FLOAT8_BYVAL\n"
"alors que le serveur a été compilé avec USE_FLOAT8_BYVAL."
-#: access/transam/xlog.c:4479
+#: access/transam/xlog.c:4635
#, c-format
msgid "The database cluster was initialized with USE_FLOAT8_BYVAL but the server was compiled without USE_FLOAT8_BYVAL."
msgstr ""
"Le cluster de base de données a été initialisé avec USE_FLOAT8_BYVAL\n"
"alors que le serveur a été compilé sans USE_FLOAT8_BYVAL."
-#: access/transam/xlog.c:4900
+#: access/transam/xlog.c:4991
#, c-format
-msgid "could not write bootstrap transaction log file: %m"
+msgid "could not generate secret authorization token"
+msgstr "n'a pas pu générer le jeton secret d'autorisation"
+
+#: access/transam/xlog.c:5081
+#, c-format
+msgid "could not write bootstrap write-ahead log file: %m"
msgstr "n'a pas pu écrire le « bootstrap » du journal des transactions : %m"
-#: access/transam/xlog.c:4906
+#: access/transam/xlog.c:5089
#, c-format
-msgid "could not fsync bootstrap transaction log file: %m"
+msgid "could not fsync bootstrap write-ahead log file: %m"
msgstr ""
"n'a pas pu synchroniser sur disque (fsync) le « bootstrap » du journal des\n"
"transactions : %m"
-#: access/transam/xlog.c:4911
+#: access/transam/xlog.c:5095
#, c-format
-msgid "could not close bootstrap transaction log file: %m"
+msgid "could not close bootstrap write-ahead log file: %m"
msgstr "n'a pas pu fermer le « bootstrap » du journal des transactions : %m"
-#: access/transam/xlog.c:4986
+#: access/transam/xlog.c:5171
#, c-format
msgid "could not open recovery command file \"%s\": %m"
msgstr "n'a pas pu ouvrir le fichier de restauration « %s » : %m"
-#: access/transam/xlog.c:5032 access/transam/xlog.c:5117
+#: access/transam/xlog.c:5217 access/transam/xlog.c:5319
#, c-format
msgid "invalid value for recovery parameter \"%s\": \"%s\""
msgstr "valeur invalide pour le paramètre de restauration « %s » : « %s »"
-#: access/transam/xlog.c:5035
+#: access/transam/xlog.c:5220
#, c-format
msgid "Valid values are \"pause\", \"promote\", and \"shutdown\"."
msgstr "Les valeurs valides sont « pause », « promote » et « shutdown »."
-#: access/transam/xlog.c:5055
+#: access/transam/xlog.c:5240
#, c-format
msgid "recovery_target_timeline is not a valid number: \"%s\""
msgstr "recovery_target_timeline n'est pas un nombre valide : « %s »"
-#: access/transam/xlog.c:5072
+#: access/transam/xlog.c:5257
#, c-format
msgid "recovery_target_xid is not a valid number: \"%s\""
msgstr "recovery_target_xid n'est pas un nombre valide : « %s »"
-#: access/transam/xlog.c:5103
+#: access/transam/xlog.c:5288
#, c-format
msgid "recovery_target_name is too long (maximum %d characters)"
msgstr "recovery_target_name est trop long (%d caractères maximum)"
-#: access/transam/xlog.c:5120
+#: access/transam/xlog.c:5322
#, c-format
msgid "The only allowed value is \"immediate\"."
msgstr "La seule valeur autorisée est « immediate »."
-#: access/transam/xlog.c:5133 access/transam/xlog.c:5144 commands/extension.c:534 commands/extension.c:542 utils/misc/guc.c:5640
+#: access/transam/xlog.c:5335 access/transam/xlog.c:5346 commands/extension.c:547 commands/extension.c:555 utils/misc/guc.c:5750
#, c-format
msgid "parameter \"%s\" requires a Boolean value"
msgstr "le paramètre « %s » requiert une valeur booléenne"
-#: access/transam/xlog.c:5179
+#: access/transam/xlog.c:5381
#, c-format
msgid "parameter \"%s\" requires a temporal value"
msgstr "le paramètre « %s » requiert une valeur temporelle"
-#: access/transam/xlog.c:5181 catalog/dependency.c:990 catalog/dependency.c:991 catalog/dependency.c:997 catalog/dependency.c:998 catalog/dependency.c:1009 catalog/dependency.c:1010 catalog/objectaddress.c:1100 commands/tablecmds.c:796 commands/tablecmds.c:9542 commands/user.c:1045 commands/view.c:499 libpq/auth.c:307 replication/syncrep.c:919 storage/lmgr/deadlock.c:1139 storage/lmgr/proc.c:1278 utils/adt/acl.c:5281 utils/misc/guc.c:5662
-#: utils/misc/guc.c:5755 utils/misc/guc.c:9708 utils/misc/guc.c:9742 utils/misc/guc.c:9776 utils/misc/guc.c:9810 utils/misc/guc.c:9845
+#: access/transam/xlog.c:5383 catalog/dependency.c:961 catalog/dependency.c:962 catalog/dependency.c:968 catalog/dependency.c:969 catalog/dependency.c:980 catalog/dependency.c:981 commands/tablecmds.c:946 commands/tablecmds.c:10345 commands/user.c:1029 commands/view.c:505 libpq/auth.c:328 replication/syncrep.c:1160 storage/lmgr/deadlock.c:1139 storage/lmgr/proc.c:1313 utils/adt/acl.c:5248 utils/misc/guc.c:5772 utils/misc/guc.c:5865
+#: utils/misc/guc.c:9821 utils/misc/guc.c:9855 utils/misc/guc.c:9889 utils/misc/guc.c:9923 utils/misc/guc.c:9958
#, c-format
msgid "%s"
msgstr "%s"
-#: access/transam/xlog.c:5188
+#: access/transam/xlog.c:5390
#, c-format
msgid "unrecognized recovery parameter \"%s\""
msgstr "paramètre de restauration « %s » non reconnu"
-#: access/transam/xlog.c:5199
+#: access/transam/xlog.c:5401
#, c-format
msgid "recovery command file \"%s\" specified neither primary_conninfo nor restore_command"
msgstr "le fichier de restauration « %s » n'a spécifié ni primary_conninfo ni restore_command"
-#: access/transam/xlog.c:5201
+#: access/transam/xlog.c:5403
#, c-format
-msgid "The database server will regularly poll the pg_xlog subdirectory to check for files placed there."
+msgid "The database server will regularly poll the pg_wal subdirectory to check for files placed there."
msgstr ""
"Le serveur de la base de données va régulièrement interroger le sous-répertoire\n"
-"pg_xlog pour vérifier les fichiers placés ici."
+"pg_wal pour vérifier les fichiers placés ici."
-#: access/transam/xlog.c:5208
+#: access/transam/xlog.c:5410
#, c-format
msgid "recovery command file \"%s\" must specify restore_command when standby mode is not enabled"
msgstr ""
"le fichier de restauration « %s » doit spécifier restore_command quand le mode\n"
"de restauration n'est pas activé"
-#: access/transam/xlog.c:5229
+#: access/transam/xlog.c:5431
#, c-format
msgid "standby mode is not supported by single-user servers"
msgstr "le mode de restauration n'est pas supporté pour les serveurs mono-utilisateur"
-#: access/transam/xlog.c:5248
+#: access/transam/xlog.c:5450
#, c-format
msgid "recovery target timeline %u does not exist"
msgstr "le timeline cible, %u, de la restauration n'existe pas"
-#: access/transam/xlog.c:5369
+#: access/transam/xlog.c:5571
#, c-format
msgid "archive recovery complete"
msgstr "restauration terminée de l'archive"
-#: access/transam/xlog.c:5428 access/transam/xlog.c:5656
+#: access/transam/xlog.c:5630 access/transam/xlog.c:5896
#, c-format
msgid "recovery stopping after reaching consistency"
msgstr "arrêt de la restauration après avoir atteint le point de cohérence"
-#: access/transam/xlog.c:5516
+#: access/transam/xlog.c:5651
+#, c-format
+msgid "recovery stopping before WAL location (LSN) \"%X/%X\""
+msgstr "arrêt de la restauration avant l'emplacement WAL (LSN) « %X/%X »"
+
+#: access/transam/xlog.c:5737
#, c-format
msgid "recovery stopping before commit of transaction %u, time %s"
msgstr "arrêt de la restauration avant validation de la transaction %u, %s"
-#: access/transam/xlog.c:5523
+#: access/transam/xlog.c:5744
#, c-format
msgid "recovery stopping before abort of transaction %u, time %s"
msgstr "arrêt de la restauration avant annulation de la transaction %u, %s"
-#: access/transam/xlog.c:5568
+#: access/transam/xlog.c:5790
#, c-format
msgid "recovery stopping at restore point \"%s\", time %s"
msgstr "restauration en arrêt au point de restauration « %s », heure %s"
-#: access/transam/xlog.c:5636
+#: access/transam/xlog.c:5808
+#, c-format
+msgid "recovery stopping after WAL location (LSN) \"%X/%X\""
+msgstr "arrêt de la restauration après l'emplacement WAL (LSN) « %X/%X »"
+
+#: access/transam/xlog.c:5876
#, c-format
msgid "recovery stopping after commit of transaction %u, time %s"
msgstr "arrêt de la restauration après validation de la transaction %u, %s"
-#: access/transam/xlog.c:5644
+#: access/transam/xlog.c:5884
#, c-format
msgid "recovery stopping after abort of transaction %u, time %s"
msgstr "arrêt de la restauration après annulation de la transaction %u, %s"
-#: access/transam/xlog.c:5683
+#: access/transam/xlog.c:5924
#, c-format
msgid "recovery has paused"
msgstr "restauration en pause"
-#: access/transam/xlog.c:5684
+#: access/transam/xlog.c:5925
#, c-format
-msgid "Execute pg_xlog_replay_resume() to continue."
-msgstr "Exécuter pg_xlog_replay_resume() pour continuer."
+msgid "Execute pg_wal_replay_resume() to continue."
+msgstr "Exécuter pg_wal_replay_resume() pour continuer."
-#: access/transam/xlog.c:5891
+#: access/transam/xlog.c:6133
#, c-format
msgid "hot standby is not possible because %s = %d is a lower setting than on the master server (its value was %d)"
msgstr ""
@@ -2130,266 +1940,271 @@ msgstr ""
"paramètrage plus bas que celui du serveur maître des journaux de transactions\n"
"(la valeur était %d)"
-#: access/transam/xlog.c:5917
+#: access/transam/xlog.c:6159
#, c-format
msgid "WAL was generated with wal_level=minimal, data may be missing"
msgstr ""
"le journal de transactions a été généré avec le paramètre wal_level configuré\n"
"à « minimal », des données pourraient manquer"
-#: access/transam/xlog.c:5918
+#: access/transam/xlog.c:6160
#, c-format
msgid "This happens if you temporarily set wal_level=minimal without taking a new base backup."
msgstr ""
"Ceci peut arriver si vous configurez temporairement wal_level à minimal sans avoir\n"
"pris une nouvelle sauvegarde de base."
-#: access/transam/xlog.c:5929
+#: access/transam/xlog.c:6171
#, c-format
msgid "hot standby is not possible because wal_level was not set to \"replica\" or higher on the master server"
msgstr ""
"les connexions en lecture seules ne sont pas possibles parce que le paramètre wal_level\n"
"n'a pas été positionné à « replica » ou plus sur le serveur maître"
-#: access/transam/xlog.c:5930
+#: access/transam/xlog.c:6172
#, c-format
msgid "Either set wal_level to \"replica\" on the master, or turn off hot_standby here."
msgstr ""
"Vous devez soit positionner le paramètre wal_level à « replica » sur le maître,\n"
"soit désactiver le hot_standby ici."
-#: access/transam/xlog.c:5987
+#: access/transam/xlog.c:6229
#, c-format
msgid "control file contains invalid data"
msgstr "le fichier de contrôle contient des données invalides"
-#: access/transam/xlog.c:5993
+#: access/transam/xlog.c:6235
#, c-format
msgid "database system was shut down at %s"
msgstr "le système de bases de données a été arrêté à %s"
-#: access/transam/xlog.c:5998
+#: access/transam/xlog.c:6240
#, c-format
msgid "database system was shut down in recovery at %s"
msgstr "le système de bases de données a été arrêté pendant la restauration à %s"
-#: access/transam/xlog.c:6002
+#: access/transam/xlog.c:6244
#, c-format
msgid "database system shutdown was interrupted; last known up at %s"
msgstr "le système de bases de données a été interrompu ; dernier lancement connu à %s"
-#: access/transam/xlog.c:6006
+#: access/transam/xlog.c:6248
#, c-format
msgid "database system was interrupted while in recovery at %s"
msgstr "le système de bases de données a été interrompu lors d'une restauration à %s"
-#: access/transam/xlog.c:6008
+#: access/transam/xlog.c:6250
#, c-format
msgid "This probably means that some data is corrupted and you will have to use the last backup for recovery."
msgstr ""
"Ceci signifie probablement que des données ont été corrompues et que vous\n"
"devrez utiliser la dernière sauvegarde pour la restauration."
-#: access/transam/xlog.c:6012
+#: access/transam/xlog.c:6254
#, c-format
msgid "database system was interrupted while in recovery at log time %s"
msgstr ""
"le système de bases de données a été interrompu lors d'une récupération à %s\n"
"(moment de la journalisation)"
-#: access/transam/xlog.c:6014
+#: access/transam/xlog.c:6256
#, c-format
msgid "If this has occurred more than once some data might be corrupted and you might need to choose an earlier recovery target."
msgstr ""
"Si c'est arrivé plus d'une fois, des données ont pu être corrompues et vous\n"
"pourriez avoir besoin de choisir une cible de récupération antérieure."
-#: access/transam/xlog.c:6018
+#: access/transam/xlog.c:6260
#, c-format
msgid "database system was interrupted; last known up at %s"
msgstr "le système de bases de données a été interrompu ; dernier lancement connu à %s"
-#: access/transam/xlog.c:6074
+#: access/transam/xlog.c:6316
#, c-format
msgid "entering standby mode"
msgstr "entre en mode standby"
-#: access/transam/xlog.c:6077
+#: access/transam/xlog.c:6319
#, c-format
msgid "starting point-in-time recovery to XID %u"
msgstr "début de la restauration de l'archive au XID %u"
-#: access/transam/xlog.c:6081
+#: access/transam/xlog.c:6323
#, c-format
msgid "starting point-in-time recovery to %s"
msgstr "début de la restauration de l'archive à %s"
-#: access/transam/xlog.c:6085
+#: access/transam/xlog.c:6327
#, c-format
msgid "starting point-in-time recovery to \"%s\""
msgstr "début de la restauration PITR à « %s »"
-#: access/transam/xlog.c:6089
+#: access/transam/xlog.c:6331
+#, c-format
+msgid "starting point-in-time recovery to WAL location (LSN) \"%X/%X\""
+msgstr "début de la restauration PITR à l'emplacement WAL (LSN) « %X/%X »"
+
+#: access/transam/xlog.c:6336
#, c-format
msgid "starting point-in-time recovery to earliest consistent point"
msgstr "début de la restauration de l'archive jusqu'au point de cohérence le plus proche"
-#: access/transam/xlog.c:6092
+#: access/transam/xlog.c:6339
#, c-format
msgid "starting archive recovery"
msgstr "début de la restauration de l'archive"
-#: access/transam/xlog.c:6136 access/transam/xlog.c:6264
+#: access/transam/xlog.c:6390 access/transam/xlog.c:6518
#, c-format
msgid "checkpoint record is at %X/%X"
msgstr "l'enregistrement du point de vérification est à %X/%X"
-#: access/transam/xlog.c:6150
+#: access/transam/xlog.c:6404
#, c-format
msgid "could not find redo location referenced by checkpoint record"
msgstr "n'a pas pu localiser l'enregistrement redo référencé par le point de vérification"
-#: access/transam/xlog.c:6151 access/transam/xlog.c:6158
+#: access/transam/xlog.c:6405 access/transam/xlog.c:6412
#, c-format
msgid "If you are not restoring from a backup, try removing the file \"%s/backup_label\"."
msgstr ""
"Si vous n'avez pas pu restaurer une sauvegarde, essayez de supprimer le\n"
"fichier « %s/backup_label »."
-#: access/transam/xlog.c:6157
+#: access/transam/xlog.c:6411
#, c-format
msgid "could not locate required checkpoint record"
msgstr "n'a pas pu localiser l'enregistrement d'un point de vérification requis"
-#: access/transam/xlog.c:6183 commands/tablespace.c:641
+#: access/transam/xlog.c:6437 commands/tablespace.c:639
#, c-format
msgid "could not create symbolic link \"%s\": %m"
msgstr "n'a pas pu créer le lien symbolique « %s » : %m"
-#: access/transam/xlog.c:6215 access/transam/xlog.c:6221
+#: access/transam/xlog.c:6469 access/transam/xlog.c:6475
#, c-format
msgid "ignoring file \"%s\" because no file \"%s\" exists"
msgstr "ignore le fichier « %s » car le fichier « %s » n'existe pas"
-#: access/transam/xlog.c:6217 access/transam/xlog.c:11032
+#: access/transam/xlog.c:6471 access/transam/xlog.c:11396
#, c-format
msgid "File \"%s\" was renamed to \"%s\"."
msgstr "Le fichier « %s » a été renommé en « %s »."
-#: access/transam/xlog.c:6223
+#: access/transam/xlog.c:6477
#, c-format
msgid "Could not rename file \"%s\" to \"%s\": %m."
msgstr "N'a pas pu renommer le fichier « %s » en « %s » : %m"
-#: access/transam/xlog.c:6274 access/transam/xlog.c:6289
+#: access/transam/xlog.c:6528 access/transam/xlog.c:6543
#, c-format
msgid "could not locate a valid checkpoint record"
msgstr "n'a pas pu localiser un enregistrement d'un point de vérification valide"
-#: access/transam/xlog.c:6283
+#: access/transam/xlog.c:6537
#, c-format
msgid "using previous checkpoint record at %X/%X"
msgstr "utilisation du précédent enregistrement d'un point de vérification à %X/%X"
-#: access/transam/xlog.c:6327
+#: access/transam/xlog.c:6581
#, c-format
msgid "requested timeline %u is not a child of this server's history"
msgstr "la timeline requise %u n'est pas un fils de l'historique de ce serveur"
-#: access/transam/xlog.c:6329
+#: access/transam/xlog.c:6583
#, c-format
msgid "Latest checkpoint is at %X/%X on timeline %u, but in the history of the requested timeline, the server forked off from that timeline at %X/%X."
msgstr "Le dernier checkpoint est à %X/%X sur la timeline %u, mais dans l'historique de la timeline demandée, le serveur est sorti de cette timeline à %X/%X."
-#: access/transam/xlog.c:6345
+#: access/transam/xlog.c:6599
#, c-format
msgid "requested timeline %u does not contain minimum recovery point %X/%X on timeline %u"
msgstr "la timeline requise, %u, ne contient pas le point de restauration minimum (%X/%X) sur la timeline %u"
-#: access/transam/xlog.c:6376
+#: access/transam/xlog.c:6630
#, c-format
msgid "invalid next transaction ID"
msgstr "prochain ID de transaction invalide"
-#: access/transam/xlog.c:6459
+#: access/transam/xlog.c:6724
#, c-format
msgid "invalid redo in checkpoint record"
msgstr "ré-exécution invalide dans l'enregistrement du point de vérification"
-#: access/transam/xlog.c:6470
+#: access/transam/xlog.c:6735
#, c-format
msgid "invalid redo record in shutdown checkpoint"
msgstr "enregistrement de ré-exécution invalide dans le point de vérification d'arrêt"
-#: access/transam/xlog.c:6498
+#: access/transam/xlog.c:6763
#, c-format
msgid "database system was not properly shut down; automatic recovery in progress"
msgstr ""
"le système de bases de données n'a pas été arrêté proprement ; restauration\n"
"automatique en cours"
-#: access/transam/xlog.c:6502
+#: access/transam/xlog.c:6767
#, c-format
msgid "crash recovery starts in timeline %u and has target timeline %u"
msgstr "la restauration après crash commence avec la timeline %u et a la timeline %u en cible"
-#: access/transam/xlog.c:6546
+#: access/transam/xlog.c:6811
#, c-format
msgid "backup_label contains data inconsistent with control file"
msgstr "backup_label contient des données incohérentes avec le fichier de contrôle"
-#: access/transam/xlog.c:6547
+#: access/transam/xlog.c:6812
#, c-format
msgid "This means that the backup is corrupted and you will have to use another backup for recovery."
msgstr ""
"Ceci signifie que la sauvegarde a été corrompue et que vous devrez utiliser\n"
"la dernière sauvegarde pour la restauration."
-#: access/transam/xlog.c:6621
+#: access/transam/xlog.c:6886
#, c-format
msgid "initializing for hot standby"
msgstr "initialisation pour « Hot Standby »"
-#: access/transam/xlog.c:6753
+#: access/transam/xlog.c:7018
#, c-format
msgid "redo starts at %X/%X"
msgstr "la ré-exécution commence à %X/%X"
-#: access/transam/xlog.c:6978
+#: access/transam/xlog.c:7252
#, c-format
msgid "requested recovery stop point is before consistent recovery point"
msgstr ""
"le point d'arrêt de la restauration demandée se trouve avant le point\n"
"cohérent de restauration"
-#: access/transam/xlog.c:7016
+#: access/transam/xlog.c:7290
#, c-format
msgid "redo done at %X/%X"
msgstr "ré-exécution faite à %X/%X"
-#: access/transam/xlog.c:7021 access/transam/xlog.c:8969
+#: access/transam/xlog.c:7295 access/transam/xlog.c:9309
#, c-format
msgid "last completed transaction was at log time %s"
msgstr "la dernière transaction a eu lieu à %s (moment de la journalisation)"
-#: access/transam/xlog.c:7030
+#: access/transam/xlog.c:7304
#, c-format
msgid "redo is not required"
msgstr "la ré-exécution n'est pas nécessaire"
-#: access/transam/xlog.c:7105 access/transam/xlog.c:7109
+#: access/transam/xlog.c:7379 access/transam/xlog.c:7383
#, c-format
msgid "WAL ends before end of online backup"
msgstr "le journal de transactions se termine avant la fin de la sauvegarde de base"
-#: access/transam/xlog.c:7106
+#: access/transam/xlog.c:7380
#, c-format
msgid "All WAL generated while online backup was taken must be available at recovery."
msgstr ""
"Tous les journaux de transactions générés pendant la sauvegarde en ligne\n"
"doivent être disponibles pour la restauration."
-#: access/transam/xlog.c:7110
+#: access/transam/xlog.c:7384
#, c-format
msgid "Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery."
msgstr ""
@@ -2397,219 +2212,225 @@ msgstr ""
"pg_stop_backup() et tous les journaux de transactions générés entre les deux\n"
"doivent être disponibles pour la restauration."
-#: access/transam/xlog.c:7113
+#: access/transam/xlog.c:7387
#, c-format
msgid "WAL ends before consistent recovery point"
msgstr "Le journal de transaction se termine avant un point de restauration cohérent"
-#: access/transam/xlog.c:7140
+#: access/transam/xlog.c:7414
#, c-format
msgid "selected new timeline ID: %u"
msgstr "identifiant d'un timeline nouvellement sélectionné : %u"
-#: access/transam/xlog.c:7551
+#: access/transam/xlog.c:7843
#, c-format
msgid "consistent recovery state reached at %X/%X"
msgstr "état de restauration cohérent atteint à %X/%X"
-#: access/transam/xlog.c:7742
+#: access/transam/xlog.c:8035
#, c-format
msgid "invalid primary checkpoint link in control file"
msgstr "lien du point de vérification primaire invalide dans le fichier de contrôle"
-#: access/transam/xlog.c:7746
+#: access/transam/xlog.c:8039
#, c-format
msgid "invalid secondary checkpoint link in control file"
msgstr "lien du point de vérification secondaire invalide dans le fichier de contrôle"
-#: access/transam/xlog.c:7750
+#: access/transam/xlog.c:8043
#, c-format
msgid "invalid checkpoint link in backup_label file"
msgstr "lien du point de vérification invalide dans le fichier backup_label"
-#: access/transam/xlog.c:7767
+#: access/transam/xlog.c:8060
#, c-format
msgid "invalid primary checkpoint record"
msgstr "enregistrement du point de vérification primaire invalide"
-#: access/transam/xlog.c:7771
+#: access/transam/xlog.c:8064
#, c-format
msgid "invalid secondary checkpoint record"
msgstr "enregistrement du point de vérification secondaire invalide"
-#: access/transam/xlog.c:7775
+#: access/transam/xlog.c:8068
#, c-format
msgid "invalid checkpoint record"
msgstr "enregistrement du point de vérification invalide"
-#: access/transam/xlog.c:7786
+#: access/transam/xlog.c:8079
#, c-format
msgid "invalid resource manager ID in primary checkpoint record"
msgstr "identifiant du gestionnaire de ressource invalide dans l'enregistrement primaire du point de vérification"
-#: access/transam/xlog.c:7790
+#: access/transam/xlog.c:8083
#, c-format
msgid "invalid resource manager ID in secondary checkpoint record"
msgstr "identifiant du gestionnaire de ressource invalide dans l'enregistrement secondaire du point de vérification"
-#: access/transam/xlog.c:7794
+#: access/transam/xlog.c:8087
#, c-format
msgid "invalid resource manager ID in checkpoint record"
msgstr "identifiant du gestionnaire de ressource invalide dans l'enregistrement du point de vérification"
-#: access/transam/xlog.c:7806
+#: access/transam/xlog.c:8100
#, c-format
msgid "invalid xl_info in primary checkpoint record"
msgstr "xl_info invalide dans l'enregistrement du point de vérification primaire"
-#: access/transam/xlog.c:7810
+#: access/transam/xlog.c:8104
#, c-format
msgid "invalid xl_info in secondary checkpoint record"
msgstr "xl_info invalide dans l'enregistrement du point de vérification secondaire"
-#: access/transam/xlog.c:7814
+#: access/transam/xlog.c:8108
#, c-format
msgid "invalid xl_info in checkpoint record"
msgstr "xl_info invalide dans l'enregistrement du point de vérification"
-#: access/transam/xlog.c:7825
+#: access/transam/xlog.c:8119
#, c-format
msgid "invalid length of primary checkpoint record"
msgstr "longueur invalide de l'enregistrement primaire du point de vérification"
-#: access/transam/xlog.c:7829
+#: access/transam/xlog.c:8123
#, c-format
msgid "invalid length of secondary checkpoint record"
msgstr "longueur invalide de l'enregistrement secondaire du point de vérification"
-#: access/transam/xlog.c:7833
+#: access/transam/xlog.c:8127
#, c-format
msgid "invalid length of checkpoint record"
msgstr "longueur invalide de l'enregistrement du point de vérification"
-#: access/transam/xlog.c:8001
+#: access/transam/xlog.c:8330
#, c-format
msgid "shutting down"
msgstr "arrêt en cours"
-#: access/transam/xlog.c:8514
+#: access/transam/xlog.c:8649
#, c-format
-msgid "concurrent transaction log activity while database system is shutting down"
+msgid "checkpoint skipped due to an idle system"
+msgstr "checkpoint ignoré, le système étant en attente"
+
+#: access/transam/xlog.c:8854
+#, fuzzy, c-format
+#| msgid "concurrent transaction log activity while database system is shutting down"
+msgid "concurrent write-ahead log activity while database system is shutting down"
msgstr ""
"activité en cours du journal de transactions alors que le système de bases\n"
"de données est en cours d'arrêt"
-#: access/transam/xlog.c:8768
+#: access/transam/xlog.c:9108
#, c-format
msgid "skipping restartpoint, recovery has already ended"
msgstr "restartpoint ignoré, la récupération est déjà terminée"
-#: access/transam/xlog.c:8791
+#: access/transam/xlog.c:9131
#, c-format
msgid "skipping restartpoint, already performed at %X/%X"
msgstr "ignore le point de redémarrage, déjà réalisé à %X/%X"
-#: access/transam/xlog.c:8967
+#: access/transam/xlog.c:9307
#, c-format
msgid "recovery restart point at %X/%X"
msgstr "la ré-exécution en restauration commence à %X/%X"
-#: access/transam/xlog.c:9100
+#: access/transam/xlog.c:9443
#, c-format
msgid "restore point \"%s\" created at %X/%X"
msgstr "point de restauration « %s » créé à %X/%X"
-#: access/transam/xlog.c:9230
+#: access/transam/xlog.c:9573
#, c-format
msgid "unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record"
msgstr "identifiant de timeline précédent %u inattendu (identifiant de la timeline courante %u) dans l'enregistrement du point de vérification"
-#: access/transam/xlog.c:9239
+#: access/transam/xlog.c:9582
#, c-format
msgid "unexpected timeline ID %u (after %u) in checkpoint record"
msgstr ""
"identifiant timeline %u inattendu (après %u) dans l'enregistrement du point\n"
"de vérification"
-#: access/transam/xlog.c:9255
+#: access/transam/xlog.c:9598
#, c-format
msgid "unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%X on timeline %u"
msgstr "identifiant timeline %u inattendu dans l'enregistrement du checkpoint, avant d'atteindre le point de restauration minimum %X/%X sur la timeline %u"
-#: access/transam/xlog.c:9326
+#: access/transam/xlog.c:9674
#, c-format
msgid "online backup was canceled, recovery cannot continue"
msgstr "la sauvegarde en ligne a été annulée, la restauration ne peut pas continuer"
-#: access/transam/xlog.c:9382 access/transam/xlog.c:9429 access/transam/xlog.c:9452
+#: access/transam/xlog.c:9730 access/transam/xlog.c:9777 access/transam/xlog.c:9800
#, c-format
msgid "unexpected timeline ID %u (should be %u) in checkpoint record"
msgstr ""
"identifiant timeline %u inattendu (devrait être %u) dans l'enregistrement du\n"
"point de vérification"
-#: access/transam/xlog.c:9727
+#: access/transam/xlog.c:10076
#, c-format
msgid "could not fsync log segment %s: %m"
msgstr "n'a pas pu synchroniser sur disque (fsync) le segment du journal des transactions %s : %m"
-#: access/transam/xlog.c:9751
+#: access/transam/xlog.c:10101
#, c-format
msgid "could not fsync log file %s: %m"
msgstr "n'a pas pu synchroniser sur disque (fsync) le fichier de transactions « %s » : %m"
-#: access/transam/xlog.c:9759
+#: access/transam/xlog.c:10109
#, c-format
msgid "could not fsync write-through log file %s: %m"
msgstr "n'a pas pu synchroniser sur disque (fsync) le journal des transactions %s : %m"
-#: access/transam/xlog.c:9768
+#: access/transam/xlog.c:10118
#, c-format
msgid "could not fdatasync log file %s: %m"
msgstr "n'a pas pu synchroniser sur disque (fdatasync) le journal de transactions %s : %m"
-#: access/transam/xlog.c:9859 access/transam/xlog.c:10363 access/transam/xlogfuncs.c:294 access/transam/xlogfuncs.c:321 access/transam/xlogfuncs.c:360 access/transam/xlogfuncs.c:381 access/transam/xlogfuncs.c:402
+#: access/transam/xlog.c:10209 access/transam/xlog.c:10727 access/transam/xlogfuncs.c:297 access/transam/xlogfuncs.c:324 access/transam/xlogfuncs.c:363 access/transam/xlogfuncs.c:384 access/transam/xlogfuncs.c:405
#, c-format
msgid "WAL control functions cannot be executed during recovery."
msgstr ""
"les fonctions de contrôle des journaux de transactions ne peuvent pas\n"
"être exécutées lors de la restauration."
-#: access/transam/xlog.c:9868 access/transam/xlog.c:10372
+#: access/transam/xlog.c:10218 access/transam/xlog.c:10736
#, c-format
msgid "WAL level not sufficient for making an online backup"
msgstr ""
"Le niveau de journalisation (configuré par wal_level) n'est pas suffisant pour\n"
"faire une sauvegarde en ligne."
-#: access/transam/xlog.c:9869 access/transam/xlog.c:10373 access/transam/xlogfuncs.c:327
+#: access/transam/xlog.c:10219 access/transam/xlog.c:10737 access/transam/xlogfuncs.c:330
#, c-format
msgid "wal_level must be set to \"replica\" or \"logical\" at server start."
msgstr ""
"wal_level doit être configuré à « replica » ou « logical »\n"
"au démarrage du serveur."
-#: access/transam/xlog.c:9874
+#: access/transam/xlog.c:10224
#, c-format
msgid "backup label too long (max %d bytes)"
msgstr "label de sauvegarde trop long (%d octets maximum)"
-#: access/transam/xlog.c:9911 access/transam/xlog.c:10183 access/transam/xlog.c:10221
+#: access/transam/xlog.c:10261 access/transam/xlog.c:10534 access/transam/xlog.c:10572
#, c-format
msgid "a backup is already in progress"
msgstr "une sauvegarde est déjà en cours"
-#: access/transam/xlog.c:9912
+#: access/transam/xlog.c:10262
#, c-format
msgid "Run pg_stop_backup() and try again."
msgstr "Exécutez pg_stop_backup() et tentez de nouveau."
-#: access/transam/xlog.c:10007
+#: access/transam/xlog.c:10357
#, c-format
msgid "WAL generated with full_page_writes=off was replayed since last restartpoint"
msgstr "Les journaux générés avec full_page_writes=off ont été rejoués depuis le dernier restartpoint."
-#: access/transam/xlog.c:10009 access/transam/xlog.c:10554
+#: access/transam/xlog.c:10359 access/transam/xlog.c:10917
#, c-format
msgid "This means that the backup being taken on the standby is corrupt and should not be used. Enable full_page_writes and run CHECKPOINT on the master, and then try an online backup again."
msgstr ""
@@ -2617,86 +2438,86 @@ msgstr ""
"corrompue et ne doit pas être utilisée. Activez full_page_writes et lancez\n"
"CHECKPOINT sur le maître, puis recommencez la sauvegarde."
-#: access/transam/xlog.c:10076 replication/basebackup.c:1026 utils/adt/misc.c:498
+#: access/transam/xlog.c:10426 replication/basebackup.c:1096 utils/adt/misc.c:497
#, c-format
msgid "could not read symbolic link \"%s\": %m"
msgstr "n'a pas pu lire le lien symbolique « %s » : %m"
-#: access/transam/xlog.c:10083 replication/basebackup.c:1031 utils/adt/misc.c:503
+#: access/transam/xlog.c:10433 replication/basebackup.c:1101 utils/adt/misc.c:502
#, c-format
msgid "symbolic link \"%s\" target is too long"
msgstr "la cible du lien symbolique « %s » est trop long"
-#: access/transam/xlog.c:10136 commands/tablespace.c:391 commands/tablespace.c:553 replication/basebackup.c:1047 utils/adt/misc.c:511
+#: access/transam/xlog.c:10486 commands/tablespace.c:389 commands/tablespace.c:551 replication/basebackup.c:1116 utils/adt/misc.c:510
#, c-format
msgid "tablespaces are not supported on this platform"
msgstr "les tablespaces ne sont pas supportés sur cette plateforme"
-#: access/transam/xlog.c:10177 access/transam/xlog.c:10215 access/transam/xlog.c:10411 access/transam/xlogarchive.c:106 access/transam/xlogarchive.c:265 commands/copy.c:1815 commands/copy.c:2839 commands/extension.c:3130 commands/tablespace.c:782 commands/tablespace.c:873 guc-file.l:1001 replication/basebackup.c:409 replication/basebackup.c:477 replication/logical/snapbuild.c:1491 storage/file/copydir.c:72 storage/file/copydir.c:115
-#: storage/file/fd.c:2826 storage/file/fd.c:2918 utils/adt/dbsize.c:70 utils/adt/dbsize.c:220 utils/adt/dbsize.c:300 utils/adt/genfile.c:114 utils/adt/genfile.c:333
+#: access/transam/xlog.c:10528 access/transam/xlog.c:10566 access/transam/xlog.c:10775 access/transam/xlogarchive.c:105 access/transam/xlogarchive.c:264 commands/copy.c:1897 commands/copy.c:3127 commands/extension.c:3319 commands/tablespace.c:780 commands/tablespace.c:871 guc-file.l:1001 replication/basebackup.c:480 replication/basebackup.c:548 replication/logical/snapbuild.c:1518 storage/file/copydir.c:72 storage/file/copydir.c:115
+#: storage/file/fd.c:2954 storage/file/fd.c:3046 utils/adt/dbsize.c:70 utils/adt/dbsize.c:227 utils/adt/dbsize.c:307 utils/adt/genfile.c:115 utils/adt/genfile.c:334
#, c-format
msgid "could not stat file \"%s\": %m"
msgstr "n'a pas pu tester le fichier « %s » : %m"
-#: access/transam/xlog.c:10184 access/transam/xlog.c:10222
+#: access/transam/xlog.c:10535 access/transam/xlog.c:10573
#, c-format
msgid "If you're sure there is no backup in progress, remove file \"%s\" and try again."
msgstr ""
"Si vous êtes certain qu'aucune sauvegarde n'est en cours, supprimez le\n"
"fichier « %s » et recommencez de nouveau."
-#: access/transam/xlog.c:10201 access/transam/xlog.c:10239 access/transam/xlog.c:10615
+#: access/transam/xlog.c:10552 access/transam/xlog.c:10590 access/transam/xlog.c:10978 postmaster/syslogger.c:1391 postmaster/syslogger.c:1404
#, c-format
msgid "could not write file \"%s\": %m"
msgstr "impossible d'écrire le fichier « %s » : %m"
-#: access/transam/xlog.c:10388
+#: access/transam/xlog.c:10752
#, c-format
msgid "exclusive backup not in progress"
msgstr "une sauvegarde exclusive n'est pas en cours"
-#: access/transam/xlog.c:10415
+#: access/transam/xlog.c:10779
#, c-format
msgid "a backup is not in progress"
msgstr "une sauvegarde n'est pas en cours"
-#: access/transam/xlog.c:10489 access/transam/xlog.c:10502 access/transam/xlog.c:10842 access/transam/xlog.c:10848 access/transam/xlog.c:10932 access/transam/xlogfuncs.c:695
+#: access/transam/xlog.c:10852 access/transam/xlog.c:10865 access/transam/xlog.c:11206 access/transam/xlog.c:11212 access/transam/xlog.c:11296 access/transam/xlogfuncs.c:698
#, c-format
msgid "invalid data in file \"%s\""
msgstr "données invalides dans le fichier « %s »"
-#: access/transam/xlog.c:10506 replication/basebackup.c:938
+#: access/transam/xlog.c:10869 replication/basebackup.c:994
#, c-format
msgid "the standby was promoted during online backup"
msgstr "le standby a été promu lors de la sauvegarde en ligne"
-#: access/transam/xlog.c:10507 replication/basebackup.c:939
+#: access/transam/xlog.c:10870 replication/basebackup.c:995
#, c-format
msgid "This means that the backup being taken is corrupt and should not be used. Try taking another online backup."
msgstr ""
"Cela signifie que la sauvegarde en cours de réalisation est corrompue et ne\n"
"doit pas être utilisée. Recommencez la sauvegarde."
-#: access/transam/xlog.c:10552
+#: access/transam/xlog.c:10915
#, c-format
msgid "WAL generated with full_page_writes=off was replayed during online backup"
msgstr ""
"le journal de transactions généré avec full_page_writes=off a été rejoué lors\n"
"de la sauvegarde en ligne"
-#: access/transam/xlog.c:10664
+#: access/transam/xlog.c:11028
#, c-format
msgid "pg_stop_backup cleanup done, waiting for required WAL segments to be archived"
msgstr "nettoyage de pg_stop_backup terminé, en attente des journaux de transactions requis à archiver"
-#: access/transam/xlog.c:10674
+#: access/transam/xlog.c:11038
#, c-format
msgid "pg_stop_backup still waiting for all required WAL segments to be archived (%d seconds elapsed)"
msgstr ""
"pg_stop_backup toujours en attente de la fin de l'archivage des segments de\n"
"journaux de transactions requis (%d secondes passées)"
-#: access/transam/xlog.c:10676
+#: access/transam/xlog.c:11040
#, c-format
msgid "Check that your archive_command is executing properly. pg_stop_backup can be canceled safely, but the database backup will not be usable without all the WAL segments."
msgstr ""
@@ -2704,12 +2525,12 @@ msgstr ""
"peut être annulé avec sûreté mais la sauvegarde de la base ne sera pas\n"
"utilisable sans tous les segments WAL."
-#: access/transam/xlog.c:10683
+#: access/transam/xlog.c:11047
#, c-format
msgid "pg_stop_backup complete, all required WAL segments have been archived"
msgstr "pg_stop_backup terminé, tous les journaux de transactions requis ont été archivés"
-#: access/transam/xlog.c:10687
+#: access/transam/xlog.c:11051
#, 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 ""
@@ -2717,73 +2538,73 @@ msgstr ""
"vous devez vous assurer que tous les fichiers requis des journaux de\n"
"transactions sont copiés par d'autre moyens pour terminer la sauvegarde."
-#. translator: %s is an XLog record description
-#: access/transam/xlog.c:10972
+#. translator: %s is a WAL record description
+#: access/transam/xlog.c:11336
#, c-format
-msgid "xlog redo at %X/%X for %s"
-msgstr "xlog redo à %X/%X pour %s"
+msgid "WAL redo at %X/%X for %s"
+msgstr "rejeu des WAL à %X/%X pour %s"
-#: access/transam/xlog.c:11021
+#: access/transam/xlog.c:11385
#, c-format
msgid "online backup mode was not canceled"
msgstr "le mode de sauvegarde en ligne n'a pas été annulé"
-#: access/transam/xlog.c:11022
+#: access/transam/xlog.c:11386
#, c-format
msgid "File \"%s\" could not be renamed to \"%s\": %m."
msgstr "Le fichier « %s » n'a pas pu être renommé en « %s » : %m"
-#: access/transam/xlog.c:11031 access/transam/xlog.c:11043 access/transam/xlog.c:11053
+#: access/transam/xlog.c:11395 access/transam/xlog.c:11407 access/transam/xlog.c:11417
#, c-format
msgid "online backup mode canceled"
msgstr "mode de sauvegarde en ligne annulé"
-#: access/transam/xlog.c:11044
+#: access/transam/xlog.c:11408
#, c-format
msgid "Files \"%s\" and \"%s\" were renamed to \"%s\" and \"%s\", respectively."
msgstr "Les fichiers « %s » et « %s » sont renommés respectivement « %s » et « %s »."
-#: access/transam/xlog.c:11054
+#: access/transam/xlog.c:11418
#, c-format
msgid "File \"%s\" was renamed to \"%s\", but file \"%s\" could not be renamed to \"%s\": %m."
msgstr "Le fichier « %s » a été renommé en « %s », mais le fichier « %s » n'a pas pu être renommé en « %s » : %m"
-#: access/transam/xlog.c:11176 access/transam/xlogutils.c:718 replication/walreceiver.c:994 replication/walsender.c:2114
+#: access/transam/xlog.c:11540 access/transam/xlogutils.c:724 replication/walreceiver.c:1005 replication/walsender.c:2397
#, c-format
msgid "could not seek in log segment %s to offset %u: %m"
msgstr "n'a pas pu se déplacer dans le journal de transactions %s au décalage %u : %m"
-#: access/transam/xlog.c:11188
+#: access/transam/xlog.c:11554
#, c-format
msgid "could not read from log segment %s, offset %u: %m"
msgstr "n'a pas pu lire le journal de transactions %s, décalage %u : %m"
-#: access/transam/xlog.c:11662
+#: access/transam/xlog.c:12043
#, c-format
msgid "received promote request"
msgstr "a reçu une demande de promotion"
-#: access/transam/xlog.c:11675
+#: access/transam/xlog.c:12056
#, c-format
msgid "trigger file found: %s"
msgstr "fichier trigger trouvé : %s"
-#: access/transam/xlog.c:11684
+#: access/transam/xlog.c:12065
#, c-format
msgid "could not stat trigger file \"%s\": %m"
msgstr "n'a pas pu tester le fichier trigger « %s » : %m"
-#: access/transam/xlogarchive.c:244
+#: access/transam/xlogarchive.c:243
#, c-format
msgid "archive file \"%s\" has wrong size: %lu instead of %lu"
msgstr "le fichier d'archive « %s » a la mauvaise taille : %lu au lieu de %lu"
-#: access/transam/xlogarchive.c:253
+#: access/transam/xlogarchive.c:252
#, c-format
msgid "restored log file \"%s\" from archive"
msgstr "restauration du journal de transactions « %s » à partir de l'archive"
-#: access/transam/xlogarchive.c:303
+#: access/transam/xlogarchive.c:302
#, c-format
msgid "could not restore file \"%s\" from archive: %s"
msgstr "n'a pas pu restaurer le fichier « %s » à partir de l'archive : %s"
@@ -2791,103 +2612,103 @@ msgstr "n'a pas pu restaurer le fichier « %s » à partir de l'archive : %s"
#. translator: First %s represents a recovery.conf parameter name like
#. "recovery_end_command", the 2nd is the value of that parameter, the
#. third an already translated error message.
-#: access/transam/xlogarchive.c:415
+#: access/transam/xlogarchive.c:414
#, c-format
msgid "%s \"%s\": %s"
msgstr "%s « %s »: %s"
-#: access/transam/xlogarchive.c:458 replication/logical/snapbuild.c:1619 replication/slot.c:480 replication/slot.c:992 replication/slot.c:1100 storage/file/fd.c:635 storage/file/fd.c:693 utils/time/snapmgr.c:1298
+#: access/transam/xlogarchive.c:457 postmaster/syslogger.c:1415 replication/logical/snapbuild.c:1645 replication/slot.c:589 replication/slot.c:1189 replication/slot.c:1303 storage/file/fd.c:642 storage/file/fd.c:737 utils/time/snapmgr.c:1318
#, c-format
msgid "could not rename file \"%s\" to \"%s\": %m"
msgstr "n'a pas pu renommer le fichier « %s » en « %s » : %m"
-#: access/transam/xlogarchive.c:525 access/transam/xlogarchive.c:589
+#: access/transam/xlogarchive.c:524 access/transam/xlogarchive.c:588
#, c-format
msgid "could not create archive status file \"%s\": %m"
msgstr "n'a pas pu créer le fichier de statut d'archivage « %s » : %m"
-#: access/transam/xlogarchive.c:533 access/transam/xlogarchive.c:597
+#: access/transam/xlogarchive.c:532 access/transam/xlogarchive.c:596
#, c-format
msgid "could not write archive status file \"%s\": %m"
msgstr "n'a pas pu écrire le fichier de statut d'archivage « %s » : %m"
-#: access/transam/xlogfuncs.c:58
+#: access/transam/xlogfuncs.c:55
#, c-format
msgid "aborting backup due to backend exiting before pg_stop_backup was called"
msgstr "annulation de la sauvegarde due à la déconnexion du processus serveur avant que pg_stop_backup ne soit appelé"
-#: access/transam/xlogfuncs.c:88
+#: access/transam/xlogfuncs.c:86
#, c-format
msgid "a backup is already in progress in this session"
msgstr "une sauvegarde est déjà en cours dans cette session"
-#: access/transam/xlogfuncs.c:94 commands/tablespace.c:705 commands/tablespace.c:715 postmaster/postmaster.c:1406 replication/basebackup.c:297 replication/basebackup.c:637 storage/file/copydir.c:53 storage/file/copydir.c:96 storage/file/fd.c:2292 storage/file/fd.c:2891 storage/ipc/dsm.c:300 utils/adt/genfile.c:439 utils/adt/misc.c:411 utils/misc/tzparser.c:339
+#: access/transam/xlogfuncs.c:92 commands/tablespace.c:703 commands/tablespace.c:713 postmaster/postmaster.c:1458 replication/basebackup.c:368 replication/basebackup.c:708 storage/file/copydir.c:53 storage/file/copydir.c:96 storage/file/fd.c:2420 storage/file/fd.c:3019 storage/ipc/dsm.c:301 utils/adt/genfile.c:440 utils/adt/misc.c:410 utils/misc/tzparser.c:339
#, c-format
msgid "could not open directory \"%s\": %m"
msgstr "n'a pas pu ouvrir le répertoire « %s » : %m"
-#: access/transam/xlogfuncs.c:155 access/transam/xlogfuncs.c:229
+#: access/transam/xlogfuncs.c:152 access/transam/xlogfuncs.c:234
#, c-format
msgid "non-exclusive backup in progress"
msgstr "une sauvegarde non exclusive est en cours"
-#: access/transam/xlogfuncs.c:156 access/transam/xlogfuncs.c:230
+#: access/transam/xlogfuncs.c:153 access/transam/xlogfuncs.c:235
#, c-format
msgid "Did you mean to use pg_stop_backup('f')?"
msgstr "Souhaitiez-vous utiliser pg_stop_backup('f') ?"
-#: access/transam/xlogfuncs.c:200 commands/event_trigger.c:1445 commands/event_trigger.c:1996 commands/extension.c:1729 commands/extension.c:1838 commands/extension.c:2031 commands/prepare.c:702 executor/execQual.c:1757 executor/execQual.c:1782 executor/execQual.c:2157 executor/execQual.c:5438 executor/functions.c:1031 foreign/foreign.c:492 replication/logical/logicalfuncs.c:175 replication/logical/origin.c:1391 replication/slotfuncs.c:189
-#: replication/walsender.c:2763 utils/adt/jsonfuncs.c:1483 utils/adt/jsonfuncs.c:1613 utils/adt/jsonfuncs.c:1801 utils/adt/jsonfuncs.c:1928 utils/adt/jsonfuncs.c:2694 utils/adt/pgstatfuncs.c:554 utils/adt/pgstatfuncs.c:655 utils/fmgr/funcapi.c:61 utils/misc/guc.c:8436 utils/mmgr/portalmem.c:1074
+#: access/transam/xlogfuncs.c:205 commands/event_trigger.c:1471 commands/event_trigger.c:2022 commands/extension.c:1895 commands/extension.c:2004 commands/extension.c:2228 commands/prepare.c:721 executor/execExpr.c:2121 executor/execSRF.c:688 executor/functions.c:1029 foreign/foreign.c:488 libpq/hba.c:2563 replication/logical/launcher.c:936 replication/logical/logicalfuncs.c:176 replication/logical/origin.c:1387 replication/slotfuncs.c:197
+#: replication/walsender.c:3166 utils/adt/jsonfuncs.c:1689 utils/adt/jsonfuncs.c:1819 utils/adt/jsonfuncs.c:2007 utils/adt/jsonfuncs.c:2134 utils/adt/jsonfuncs.c:3489 utils/adt/pgstatfuncs.c:456 utils/adt/pgstatfuncs.c:557 utils/fmgr/funcapi.c:62 utils/misc/guc.c:8549 utils/mmgr/portalmem.c:1053
#, c-format
msgid "set-valued function called in context that cannot accept a set"
msgstr ""
"la fonction avec set-value a été appelé dans un contexte qui n'accepte pas\n"
"un ensemble"
-#: access/transam/xlogfuncs.c:204 commands/event_trigger.c:1449 commands/event_trigger.c:2000 commands/extension.c:1733 commands/extension.c:1842 commands/extension.c:2035 commands/prepare.c:706 foreign/foreign.c:497 replication/logical/logicalfuncs.c:179 replication/logical/origin.c:1395 replication/slotfuncs.c:193 replication/walsender.c:2767 utils/adt/pgstatfuncs.c:558 utils/adt/pgstatfuncs.c:659 utils/misc/guc.c:8440
-#: utils/misc/pg_config.c:44 utils/mmgr/portalmem.c:1078
+#: access/transam/xlogfuncs.c:209 commands/event_trigger.c:1475 commands/event_trigger.c:2026 commands/extension.c:1899 commands/extension.c:2008 commands/extension.c:2232 commands/prepare.c:725 foreign/foreign.c:493 libpq/hba.c:2567 replication/logical/launcher.c:940 replication/logical/logicalfuncs.c:180 replication/logical/origin.c:1391 replication/slotfuncs.c:201 replication/walsender.c:3170 utils/adt/pgstatfuncs.c:460
+#: utils/adt/pgstatfuncs.c:561 utils/misc/guc.c:8553 utils/misc/pg_config.c:44 utils/mmgr/portalmem.c:1057
#, c-format
msgid "materialize mode required, but it is not allowed in this context"
msgstr "mode matérialisé requis mais interdit dans ce contexte"
-#: access/transam/xlogfuncs.c:247
+#: access/transam/xlogfuncs.c:251
#, c-format
msgid "non-exclusive backup is not in progress"
msgstr "une sauvegarde non exclusive n'est pas en cours"
-#: access/transam/xlogfuncs.c:248
+#: access/transam/xlogfuncs.c:252
#, c-format
msgid "Did you mean to use pg_stop_backup('t')?"
msgstr "Souhaitiez-vous utiliser pg_stop_backup('t') ?"
-#: access/transam/xlogfuncs.c:326
+#: access/transam/xlogfuncs.c:329
#, c-format
msgid "WAL level not sufficient for creating a restore point"
msgstr ""
"le niveau de journalisation (configuré par wal_level) n'est pas suffisant pour\n"
"créer un point de restauration"
-#: access/transam/xlogfuncs.c:334
+#: access/transam/xlogfuncs.c:337
#, c-format
msgid "value too long for restore point (maximum %d characters)"
msgstr "valeur trop longue pour le point de restauration (%d caractères maximum)"
-#: access/transam/xlogfuncs.c:472
+#: access/transam/xlogfuncs.c:475
#, c-format
-msgid "pg_xlogfile_name_offset() cannot be executed during recovery."
-msgstr "pg_xlogfile_name_offset() ne peut pas être exécuté lors de la restauration."
+msgid "pg_walfile_name_offset() cannot be executed during recovery."
+msgstr "pg_walfile_name_offset() ne peut pas être exécuté lors de la restauration."
-#: access/transam/xlogfuncs.c:528
+#: access/transam/xlogfuncs.c:531
#, c-format
-msgid "pg_xlogfile_name() cannot be executed during recovery."
-msgstr "pg_xlogfile_name() ne peut pas être exécuté lors de la restauration."
+msgid "pg_walfile_name() cannot be executed during recovery."
+msgstr "pg_walfile_name() ne peut pas être exécuté lors de la restauration."
-#: access/transam/xlogfuncs.c:548 access/transam/xlogfuncs.c:568 access/transam/xlogfuncs.c:585
+#: access/transam/xlogfuncs.c:551 access/transam/xlogfuncs.c:571 access/transam/xlogfuncs.c:588
#, c-format
msgid "recovery is not in progress"
msgstr "la restauration n'est pas en cours"
-#: access/transam/xlogfuncs.c:549 access/transam/xlogfuncs.c:569 access/transam/xlogfuncs.c:586
+#: access/transam/xlogfuncs.c:552 access/transam/xlogfuncs.c:572 access/transam/xlogfuncs.c:589
#, c-format
msgid "Recovery control functions can only be executed during recovery."
msgstr ""
@@ -2904,7 +2725,7 @@ msgstr "décalage invalide de l'enregistrement %X/%X"
msgid "contrecord is requested by %X/%X"
msgstr "« contrecord » est requis par %X/%X"
-#: access/transam/xlogreader.c:325 access/transam/xlogreader.c:624
+#: access/transam/xlogreader.c:325 access/transam/xlogreader.c:625
#, c-format
msgid "invalid record length at %X/%X: wanted %u, got %u"
msgstr "longueur invalide de l'enregistrement à %X/%X : voulait %u, a eu %u"
@@ -2924,664 +2745,715 @@ msgstr "il n'existe pas de drapeau contrecord à %X/%X"
msgid "invalid contrecord length %u at %X/%X"
msgstr "longueur %u invalide du contrecord à %X/%X"
-#: access/transam/xlogreader.c:632
+#: access/transam/xlogreader.c:633
#, c-format
msgid "invalid resource manager ID %u at %X/%X"
msgstr "identifiant du gestionnaire de ressources invalide %u à %X/%X"
-#: access/transam/xlogreader.c:646 access/transam/xlogreader.c:663
+#: access/transam/xlogreader.c:647 access/transam/xlogreader.c:664
#, c-format
msgid "record with incorrect prev-link %X/%X at %X/%X"
msgstr "enregistrement avec prev-link %X/%X incorrect à %X/%X"
-#: access/transam/xlogreader.c:700
+#: access/transam/xlogreader.c:701
#, c-format
msgid "incorrect resource manager data checksum in record at %X/%X"
msgstr ""
"somme de contrôle des données du gestionnaire de ressources incorrecte à\n"
"l'enregistrement %X/%X"
-#: access/transam/xlogreader.c:733
+#: access/transam/xlogreader.c:734
#, c-format
msgid "invalid magic number %04X in log segment %s, offset %u"
msgstr "numéro magique invalide %04X dans le segment %s, décalage %u"
-#: access/transam/xlogreader.c:747 access/transam/xlogreader.c:798
+#: access/transam/xlogreader.c:748 access/transam/xlogreader.c:799
#, c-format
msgid "invalid info bits %04X in log segment %s, offset %u"
msgstr "bits d'information %04X invalides dans le segment %s, décalage %u"
-#: access/transam/xlogreader.c:773
+#: access/transam/xlogreader.c:774
#, c-format
msgid "WAL file is from different database system: WAL file database system identifier is %s, pg_control database system identifier is %s"
msgstr "le fichier WAL provient d'un système différent : l'identifiant système de la base dans le fichier WAL est %s, alors que l'identifiant système de la base dans pg_control est %s"
-#: access/transam/xlogreader.c:780
+#: access/transam/xlogreader.c:781
#, c-format
msgid "WAL file is from different database system: incorrect XLOG_SEG_SIZE in page header"
msgstr "le fichier WAL provient d'un système différent : XLOG_SEG_SIZE invalide dans l'en-tête de page"
-#: access/transam/xlogreader.c:786
+#: access/transam/xlogreader.c:787
#, c-format
msgid "WAL file is from different database system: incorrect XLOG_BLCKSZ in page header"
msgstr "le fichier WAL provient d'un système différent : XLOG_BLCKSZ invalide dans l'en-tête de page"
-#: access/transam/xlogreader.c:812
+#: access/transam/xlogreader.c:813
#, c-format
msgid "unexpected pageaddr %X/%X in log segment %s, offset %u"
msgstr "pageaddr %X/%X inattendue dans le journal de transactions %s, segment %u"
-#: access/transam/xlogreader.c:837
+#: access/transam/xlogreader.c:838
#, c-format
msgid "out-of-sequence timeline ID %u (after %u) in log segment %s, offset %u"
msgstr "identifiant timeline %u hors de la séquence (après %u) dans le segment %s, décalage %u"
-#: access/transam/xlogreader.c:1081
+#: access/transam/xlogreader.c:1083
#, c-format
msgid "out-of-order block_id %u at %X/%X"
msgstr "block_id %u désordonné à %X/%X"
-#: access/transam/xlogreader.c:1103
+#: access/transam/xlogreader.c:1106
#, c-format
msgid "BKPBLOCK_HAS_DATA set, but no data included at %X/%X"
msgstr "BKPBLOCK_HAS_DATA configuré, mais aucune donnée inclus à %X/%X"
-#: access/transam/xlogreader.c:1110
+#: access/transam/xlogreader.c:1113
#, c-format
msgid "BKPBLOCK_HAS_DATA not set, but data length is %u at %X/%X"
msgstr "BKPBLOCK_HAS_DATA non configuré, mais la longueur des données est %u à %X/%X"
-#: access/transam/xlogreader.c:1143
+#: access/transam/xlogreader.c:1149
#, c-format
msgid "BKPIMAGE_HAS_HOLE set, but hole offset %u length %u block image length %u at %X/%X"
msgstr "BKPIMAGE_HAS_HOLE initialisé, mais décalage du trou %u longueur %u longueur de l'image du bloc %u à %X/%X"
-#: access/transam/xlogreader.c:1159
+#: access/transam/xlogreader.c:1165
#, c-format
msgid "BKPIMAGE_HAS_HOLE not set, but hole offset %u length %u at %X/%X"
msgstr "BKPIMAGE_HAS_HOLE non initialisé, mais décalage du trou %u longueur %u à %X/%X"
-#: access/transam/xlogreader.c:1174
+#: access/transam/xlogreader.c:1180
#, c-format
msgid "BKPIMAGE_IS_COMPRESSED set, but block image length %u at %X/%X"
msgstr "BKPIMAGE_IS_COMPRESSED configuré, mais la longueur de l'image du bloc est %u à %X/%X"
-#: access/transam/xlogreader.c:1189
+#: access/transam/xlogreader.c:1195
#, c-format
msgid "neither BKPIMAGE_HAS_HOLE nor BKPIMAGE_IS_COMPRESSED set, but block image length is %u at %X/%X"
msgstr "ni BKPIMAGE_HAS_HOLE ni BKPIMAGE_IS_COMPRESSED configuré, mais la longueur de l'image du bloc est %u à %X/%X"
-#: access/transam/xlogreader.c:1205
+#: access/transam/xlogreader.c:1211
#, c-format
msgid "BKPBLOCK_SAME_REL set but no previous rel at %X/%X"
msgstr "BKPBLOCK_SAME_REL configuré, mais pas de relation précédente à %X/%X"
-#: access/transam/xlogreader.c:1217
+#: access/transam/xlogreader.c:1223
#, c-format
msgid "invalid block_id %u at %X/%X"
msgstr "block_id %u invalide à %X/%X"
-#: access/transam/xlogreader.c:1282
+#: access/transam/xlogreader.c:1291
#, c-format
msgid "record with invalid length at %X/%X"
msgstr "enregistrement de longueur invalide à %X/%X"
-#: access/transam/xlogreader.c:1371
+#: access/transam/xlogreader.c:1380
#, c-format
msgid "invalid compressed image at %X/%X, block %d"
msgstr "image compressée invalide à %X/%X, bloc %d"
-#: access/transam/xlogutils.c:739 replication/walsender.c:2131
+#: access/transam/xlogutils.c:747 replication/walsender.c:2416
#, c-format
msgid "could not read from log segment %s, offset %u, length %lu: %m"
msgstr "n'a pas pu lire le journal de transactions %s, décalage %u, longueur %lu : %m"
-#: bootstrap/bootstrap.c:269 postmaster/postmaster.c:793 tcop/postgres.c:3501
+#: bootstrap/bootstrap.c:272 postmaster/postmaster.c:819 tcop/postgres.c:3510
#, c-format
msgid "--%s requires a value"
msgstr "--%s requiert une valeur"
-#: bootstrap/bootstrap.c:274 postmaster/postmaster.c:798 tcop/postgres.c:3506
+#: bootstrap/bootstrap.c:277 postmaster/postmaster.c:824 tcop/postgres.c:3515
#, c-format
msgid "-c %s requires a value"
msgstr "-c %s requiert une valeur"
-#: bootstrap/bootstrap.c:285 postmaster/postmaster.c:810 postmaster/postmaster.c:823
+#: bootstrap/bootstrap.c:288 postmaster/postmaster.c:836 postmaster/postmaster.c:849
#, c-format
msgid "Try \"%s --help\" for more information.\n"
msgstr "Essayez « %s --help » pour plus d'informations.\n"
-#: bootstrap/bootstrap.c:294
+#: bootstrap/bootstrap.c:297
#, c-format
msgid "%s: invalid command-line arguments\n"
msgstr "%s : arguments invalides en ligne de commande\n"
-#: catalog/aclchk.c:201
+#: catalog/aclchk.c:203
#, c-format
msgid "grant options can only be granted to roles"
msgstr "les options grant peuvent seulement être données aux rôles"
-#: catalog/aclchk.c:324
+#: catalog/aclchk.c:326
#, c-format
msgid "no privileges were granted for column \"%s\" of relation \"%s\""
msgstr "aucun droit n'a pu être accordé pour la colonne « %s » de la relation « %s »"
-#: catalog/aclchk.c:329
+#: catalog/aclchk.c:331
#, c-format
msgid "no privileges were granted for \"%s\""
msgstr "aucun droit n'a été accordé pour « %s »"
-#: catalog/aclchk.c:337
+#: catalog/aclchk.c:339
#, c-format
msgid "not all privileges were granted for column \"%s\" of relation \"%s\""
msgstr "certains droits n'ont pu être accordé pour la colonne « %s » de la relation « %s »"
-#: catalog/aclchk.c:342
+#: catalog/aclchk.c:344
#, c-format
msgid "not all privileges were granted for \"%s\""
msgstr "tous les droits n'ont pas été accordés pour « %s »"
-#: catalog/aclchk.c:353
+#: catalog/aclchk.c:355
#, c-format
msgid "no privileges could be revoked for column \"%s\" of relation \"%s\""
msgstr "aucun droit n'a pu être révoqué pour la colonne « %s » de la relation « %s »"
-#: catalog/aclchk.c:358
+#: catalog/aclchk.c:360
#, c-format
msgid "no privileges could be revoked for \"%s\""
msgstr "aucun droit n'a pu être révoqué pour « %s »"
-#: catalog/aclchk.c:366
+#: catalog/aclchk.c:368
#, c-format
msgid "not all privileges could be revoked for column \"%s\" of relation \"%s\""
msgstr "certains droits n'ont pu être révoqué pour la colonne « %s » de la relation « %s »"
-#: catalog/aclchk.c:371
+#: catalog/aclchk.c:373
#, c-format
msgid "not all privileges could be revoked for \"%s\""
msgstr "certains droits n'ont pu être révoqué pour « %s »"
-#: catalog/aclchk.c:453 catalog/aclchk.c:943
+#: catalog/aclchk.c:455 catalog/aclchk.c:948
#, c-format
msgid "invalid privilege type %s for relation"
msgstr "droit %s invalide pour la relation"
-#: catalog/aclchk.c:457 catalog/aclchk.c:947
+#: catalog/aclchk.c:459 catalog/aclchk.c:952
#, c-format
msgid "invalid privilege type %s for sequence"
msgstr "droit %s invalide pour la séquence"
-#: catalog/aclchk.c:461
+#: catalog/aclchk.c:463
#, c-format
msgid "invalid privilege type %s for database"
msgstr "droit %s invalide pour la base de données"
-#: catalog/aclchk.c:465
+#: catalog/aclchk.c:467
#, c-format
msgid "invalid privilege type %s for domain"
msgstr "type de droit %s invalide pour le domaine"
-#: catalog/aclchk.c:469 catalog/aclchk.c:951
+#: catalog/aclchk.c:471 catalog/aclchk.c:956
#, c-format
msgid "invalid privilege type %s for function"
msgstr "droit %s invalide pour la fonction"
-#: catalog/aclchk.c:473
+#: catalog/aclchk.c:475
#, c-format
msgid "invalid privilege type %s for language"
msgstr "droit %s invalide pour le langage"
-#: catalog/aclchk.c:477
+#: catalog/aclchk.c:479
#, c-format
msgid "invalid privilege type %s for large object"
msgstr "type de droit invalide, %s, pour le Large Object"
-#: catalog/aclchk.c:481
+#: catalog/aclchk.c:483 catalog/aclchk.c:964
#, c-format
msgid "invalid privilege type %s for schema"
msgstr "droit %s invalide pour le schéma"
-#: catalog/aclchk.c:485
+#: catalog/aclchk.c:487
#, c-format
msgid "invalid privilege type %s for tablespace"
msgstr "droit %s invalide pour le tablespace"
-#: catalog/aclchk.c:489 catalog/aclchk.c:955
+#: catalog/aclchk.c:491 catalog/aclchk.c:960
#, c-format
msgid "invalid privilege type %s for type"
msgstr "type de droit %s invalide pour le type"
-#: catalog/aclchk.c:493
+#: catalog/aclchk.c:495
#, c-format
msgid "invalid privilege type %s for foreign-data wrapper"
msgstr "type de droit %s invalide pour le wrapper de données distantes"
-#: catalog/aclchk.c:497
+#: catalog/aclchk.c:499
#, c-format
msgid "invalid privilege type %s for foreign server"
msgstr "type de droit %s invalide pour le serveur distant"
-#: catalog/aclchk.c:536
+#: catalog/aclchk.c:538
#, c-format
msgid "column privileges are only valid for relations"
msgstr "les droits sur la colonne sont seulement valides pour les relations"
-#: catalog/aclchk.c:695 catalog/aclchk.c:3923 catalog/aclchk.c:4705 catalog/objectaddress.c:873 catalog/pg_largeobject.c:113 storage/large_object/inv_api.c:291
+#: catalog/aclchk.c:696 catalog/aclchk.c:3926 catalog/aclchk.c:4708 catalog/objectaddress.c:928 catalog/pg_largeobject.c:111 storage/large_object/inv_api.c:291
#, c-format
msgid "large object %u does not exist"
msgstr "le « Large Object » %u n'existe pas"
-#: catalog/aclchk.c:882 catalog/aclchk.c:890 commands/collationcmds.c:92 commands/copy.c:1047 commands/copy.c:1065 commands/copy.c:1073 commands/copy.c:1081 commands/copy.c:1089 commands/copy.c:1097 commands/copy.c:1105 commands/copy.c:1113 commands/copy.c:1121 commands/copy.c:1137 commands/copy.c:1151 commands/copy.c:1170 commands/copy.c:1185 commands/dbcommands.c:155 commands/dbcommands.c:163 commands/dbcommands.c:171
-#: commands/dbcommands.c:179 commands/dbcommands.c:187 commands/dbcommands.c:195 commands/dbcommands.c:203 commands/dbcommands.c:211 commands/dbcommands.c:219 commands/dbcommands.c:1397 commands/dbcommands.c:1405 commands/dbcommands.c:1413 commands/dbcommands.c:1421 commands/extension.c:1219 commands/extension.c:1227 commands/extension.c:1235 commands/extension.c:1243 commands/extension.c:2761 commands/foreigncmds.c:539
-#: commands/foreigncmds.c:548 commands/functioncmds.c:533 commands/functioncmds.c:649 commands/functioncmds.c:657 commands/functioncmds.c:665 commands/functioncmds.c:673 commands/functioncmds.c:2085 commands/functioncmds.c:2093 commands/sequence.c:1189 commands/sequence.c:1197 commands/sequence.c:1205 commands/sequence.c:1213 commands/sequence.c:1221 commands/sequence.c:1229 commands/sequence.c:1237 commands/sequence.c:1245
-#: commands/typecmds.c:295 commands/typecmds.c:1382 commands/typecmds.c:1391 commands/typecmds.c:1399 commands/typecmds.c:1407 commands/typecmds.c:1415 commands/user.c:139 commands/user.c:156 commands/user.c:164 commands/user.c:172 commands/user.c:180 commands/user.c:188 commands/user.c:196 commands/user.c:204 commands/user.c:212 commands/user.c:220 commands/user.c:228 commands/user.c:236 commands/user.c:244 commands/user.c:537
-#: commands/user.c:549 commands/user.c:557 commands/user.c:565 commands/user.c:573 commands/user.c:581 commands/user.c:589 commands/user.c:597 commands/user.c:606 commands/user.c:614 commands/user.c:622
+#: catalog/aclchk.c:885 catalog/aclchk.c:894 commands/collationcmds.c:114 commands/copy.c:1042 commands/copy.c:1062 commands/copy.c:1071 commands/copy.c:1080 commands/copy.c:1089 commands/copy.c:1098 commands/copy.c:1107 commands/copy.c:1116 commands/copy.c:1125 commands/copy.c:1143 commands/copy.c:1159 commands/copy.c:1179 commands/copy.c:1196 commands/dbcommands.c:155 commands/dbcommands.c:164 commands/dbcommands.c:173
+#: commands/dbcommands.c:182 commands/dbcommands.c:191 commands/dbcommands.c:200 commands/dbcommands.c:209 commands/dbcommands.c:218 commands/dbcommands.c:227 commands/dbcommands.c:1427 commands/dbcommands.c:1436 commands/dbcommands.c:1445 commands/dbcommands.c:1454 commands/extension.c:1678 commands/extension.c:1688 commands/extension.c:1698 commands/extension.c:1708 commands/extension.c:2949 commands/foreigncmds.c:537
+#: commands/foreigncmds.c:546 commands/functioncmds.c:526 commands/functioncmds.c:643 commands/functioncmds.c:652 commands/functioncmds.c:661 commands/functioncmds.c:670 commands/functioncmds.c:2097 commands/functioncmds.c:2105 commands/publicationcmds.c:90 commands/sequence.c:1265 commands/sequence.c:1275 commands/sequence.c:1285 commands/sequence.c:1295 commands/sequence.c:1305 commands/sequence.c:1315 commands/sequence.c:1325
+#: commands/sequence.c:1335 commands/sequence.c:1345 commands/subscriptioncmds.c:110 commands/subscriptioncmds.c:120 commands/subscriptioncmds.c:130 commands/subscriptioncmds.c:140 commands/subscriptioncmds.c:154 commands/subscriptioncmds.c:165 commands/subscriptioncmds.c:179 commands/tablecmds.c:5960 commands/typecmds.c:298 commands/typecmds.c:1375 commands/typecmds.c:1384 commands/typecmds.c:1392 commands/typecmds.c:1400
+#: commands/typecmds.c:1408 commands/user.c:134 commands/user.c:148 commands/user.c:157 commands/user.c:166 commands/user.c:175 commands/user.c:184 commands/user.c:193 commands/user.c:202 commands/user.c:211 commands/user.c:220 commands/user.c:229 commands/user.c:238 commands/user.c:247 commands/user.c:532 commands/user.c:540 commands/user.c:548 commands/user.c:556 commands/user.c:564 commands/user.c:572 commands/user.c:580
+#: commands/user.c:588 commands/user.c:597 commands/user.c:605 commands/user.c:613 parser/parse_utilcmd.c:395 replication/pgoutput/pgoutput.c:107 replication/pgoutput/pgoutput.c:128 replication/walsender.c:800 replication/walsender.c:811 replication/walsender.c:821
#, c-format
msgid "conflicting or redundant options"
msgstr "options en conflit ou redondantes"
-#: catalog/aclchk.c:988
+#: catalog/aclchk.c:997
#, c-format
msgid "default privileges cannot be set for columns"
msgstr "les droits par défaut ne peuvent pas être configurés pour les colonnes"
-#: catalog/aclchk.c:1502 catalog/objectaddress.c:1390 commands/analyze.c:376 commands/copy.c:4458 commands/sequence.c:1491 commands/tablecmds.c:5198 commands/tablecmds.c:5304 commands/tablecmds.c:5364 commands/tablecmds.c:5477 commands/tablecmds.c:5534 commands/tablecmds.c:5628 commands/tablecmds.c:5724 commands/tablecmds.c:7915 commands/tablecmds.c:8177 commands/tablecmds.c:8597 commands/trigger.c:642 parser/analyze.c:2228
-#: parser/parse_relation.c:2628 parser/parse_relation.c:2690 parser/parse_target.c:951 parser/parse_type.c:127 utils/adt/acl.c:2840 utils/adt/ruleutils.c:1984
+#: catalog/aclchk.c:1157
+#, c-format
+msgid "cannot use IN SCHEMA clause when using GRANT/REVOKE ON SCHEMAS"
+msgstr "ne peut pas utiliser la clause IN SCHEMA lors de l'utilisation de GRANT/REVOKE ON SCHEMAS"
+
+#: catalog/aclchk.c:1521 catalog/objectaddress.c:1389 commands/analyze.c:390 commands/copy.c:4746 commands/sequence.c:1700 commands/tablecmds.c:5608 commands/tablecmds.c:5755 commands/tablecmds.c:5812 commands/tablecmds.c:5885 commands/tablecmds.c:5979 commands/tablecmds.c:6038 commands/tablecmds.c:6163 commands/tablecmds.c:6217 commands/tablecmds.c:6309 commands/tablecmds.c:6465 commands/tablecmds.c:8694 commands/tablecmds.c:8970
+#: commands/tablecmds.c:9405 commands/trigger.c:791 parser/analyze.c:2310 parser/parse_relation.c:2699 parser/parse_relation.c:2761 parser/parse_target.c:1002 parser/parse_type.c:127 utils/adt/acl.c:2823 utils/adt/ruleutils.c:2356
#, c-format
msgid "column \"%s\" of relation \"%s\" does not exist"
msgstr "la colonne « %s » de la relation « %s » n'existe pas"
-#: catalog/aclchk.c:1771 catalog/objectaddress.c:1203 commands/sequence.c:1078 commands/tablecmds.c:224 commands/tablecmds.c:12154 utils/adt/acl.c:2076 utils/adt/acl.c:2106 utils/adt/acl.c:2138 utils/adt/acl.c:2170 utils/adt/acl.c:2198 utils/adt/acl.c:2228
+#: catalog/aclchk.c:1787 catalog/objectaddress.c:1229 commands/sequence.c:1138 commands/tablecmds.c:229 commands/tablecmds.c:13080 utils/adt/acl.c:2059 utils/adt/acl.c:2089 utils/adt/acl.c:2121 utils/adt/acl.c:2153 utils/adt/acl.c:2181 utils/adt/acl.c:2211
#, c-format
msgid "\"%s\" is not a sequence"
msgstr "« %s » n'est pas une séquence"
-#: catalog/aclchk.c:1809
+#: catalog/aclchk.c:1825
#, c-format
msgid "sequence \"%s\" only supports USAGE, SELECT, and UPDATE privileges"
msgstr "la séquence « %s » accepte seulement les droits USAGE, SELECT et UPDATE"
-#: catalog/aclchk.c:1826
+#: catalog/aclchk.c:1842
#, c-format
-msgid "invalid privilege type USAGE for table"
-msgstr "droit USAGE invalide pour la table"
+msgid "invalid privilege type %s for table"
+msgstr "type de droit %s invalide pour la table"
-#: catalog/aclchk.c:1994
+#: catalog/aclchk.c:2008
#, c-format
msgid "invalid privilege type %s for column"
msgstr "type de droit %s invalide pour la colonne"
-#: catalog/aclchk.c:2007
+#: catalog/aclchk.c:2021
#, c-format
msgid "sequence \"%s\" only supports SELECT column privileges"
msgstr "la séquence « %s » accepte seulement le droit SELECT pour les colonnes"
-#: catalog/aclchk.c:2601
+#: catalog/aclchk.c:2603
#, c-format
msgid "language \"%s\" is not trusted"
msgstr "le langage « %s » n'est pas de confiance"
-#: catalog/aclchk.c:2603
+#: catalog/aclchk.c:2605
#, c-format
msgid "GRANT and REVOKE are not allowed on untrusted languages, because only superusers can use untrusted languages."
msgstr "GRANT et REVOKE ne sont pas autorisés sur des langages qui ne sont pas de confiance car seuls les super-utilisateurs peuvent utiliser ces langages"
-#: catalog/aclchk.c:3129
+#: catalog/aclchk.c:3119
#, c-format
msgid "cannot set privileges of array types"
msgstr "ne peut pas configurer les droits des types tableau"
-#: catalog/aclchk.c:3130
+#: catalog/aclchk.c:3120
#, c-format
msgid "Set the privileges of the element type instead."
msgstr "Configurez les droits du type élément à la place."
-#: catalog/aclchk.c:3137 catalog/objectaddress.c:1523 commands/typecmds.c:3146
+#: catalog/aclchk.c:3127 catalog/objectaddress.c:1519
#, c-format
msgid "\"%s\" is not a domain"
msgstr "« %s » n'est pas un domaine"
-#: catalog/aclchk.c:3260
+#: catalog/aclchk.c:3247
#, c-format
msgid "unrecognized privilege type \"%s\""
msgstr "droit « %s » non reconnu"
-#: catalog/aclchk.c:3309
+#: catalog/aclchk.c:3296
#, c-format
msgid "permission denied for column %s"
msgstr "droit refusé pour la colonne %s"
-#: catalog/aclchk.c:3311
+#: catalog/aclchk.c:3298
#, c-format
msgid "permission denied for relation %s"
msgstr "droit refusé pour la relation %s"
-#: catalog/aclchk.c:3313 commands/sequence.c:561 commands/sequence.c:786 commands/sequence.c:828 commands/sequence.c:865 commands/sequence.c:1543
+#: catalog/aclchk.c:3300 commands/sequence.c:600 commands/sequence.c:834 commands/sequence.c:876 commands/sequence.c:917 commands/sequence.c:1791 commands/sequence.c:1855
#, c-format
msgid "permission denied for sequence %s"
msgstr "droit refusé pour la séquence %s"
-#: catalog/aclchk.c:3315
+#: catalog/aclchk.c:3302
#, c-format
msgid "permission denied for database %s"
msgstr "droit refusé pour la base de données %s"
-#: catalog/aclchk.c:3317
+#: catalog/aclchk.c:3304
#, c-format
msgid "permission denied for function %s"
msgstr "droit refusé pour la fonction %s"
-#: catalog/aclchk.c:3319
+#: catalog/aclchk.c:3306
#, c-format
msgid "permission denied for operator %s"
msgstr "droit refusé pour l'opérateur %s"
-#: catalog/aclchk.c:3321
+#: catalog/aclchk.c:3308
#, c-format
msgid "permission denied for type %s"
msgstr "droit refusé pour le type %s"
-#: catalog/aclchk.c:3323
+#: catalog/aclchk.c:3310
#, c-format
msgid "permission denied for language %s"
msgstr "droit refusé pour le langage %s"
-#: catalog/aclchk.c:3325
+#: catalog/aclchk.c:3312
#, c-format
msgid "permission denied for large object %s"
msgstr "droit refusé pour le Large Object %s"
-#: catalog/aclchk.c:3327
+#: catalog/aclchk.c:3314
#, c-format
msgid "permission denied for schema %s"
msgstr "droit refusé pour le schéma %s"
-#: catalog/aclchk.c:3329
+#: catalog/aclchk.c:3316
#, c-format
msgid "permission denied for operator class %s"
msgstr "droit refusé pour la classe d'opérateur %s"
-#: catalog/aclchk.c:3331
+#: catalog/aclchk.c:3318
#, c-format
msgid "permission denied for operator family %s"
msgstr "droit refusé pour la famille d'opérateur %s"
-#: catalog/aclchk.c:3333
+#: catalog/aclchk.c:3320
#, c-format
msgid "permission denied for collation %s"
msgstr "droit refusé pour le collationnement %s"
-#: catalog/aclchk.c:3335
+#: catalog/aclchk.c:3322
#, c-format
msgid "permission denied for conversion %s"
msgstr "droit refusé pour la conversion %s"
-#: catalog/aclchk.c:3337
+#: catalog/aclchk.c:3324
+#, c-format
+msgid "permission denied for statistics object %s"
+msgstr "droit refusé pour l'objet statistique %s"
+
+#: catalog/aclchk.c:3326
#, c-format
msgid "permission denied for tablespace %s"
msgstr "droit refusé pour le tablespace %s"
-#: catalog/aclchk.c:3339
+#: catalog/aclchk.c:3328
#, c-format
msgid "permission denied for text search dictionary %s"
msgstr "droit refusé pour le dictionnaire de recherche plein texte %s"
-#: catalog/aclchk.c:3341
+#: catalog/aclchk.c:3330
#, c-format
msgid "permission denied for text search configuration %s"
msgstr "droit refusé pour la configuration de recherche plein texte %s"
-#: catalog/aclchk.c:3343
+#: catalog/aclchk.c:3332
#, c-format
msgid "permission denied for foreign-data wrapper %s"
msgstr "droit refusé pour le wrapper de données distantes %s"
-#: catalog/aclchk.c:3345
+#: catalog/aclchk.c:3334
#, c-format
msgid "permission denied for foreign server %s"
msgstr "droit refusé pour le serveur distant %s"
-#: catalog/aclchk.c:3347
+#: catalog/aclchk.c:3336
#, c-format
msgid "permission denied for event trigger %s"
msgstr "droit refusé pour le trigger sur événement %s"
-#: catalog/aclchk.c:3349
+#: catalog/aclchk.c:3338
#, c-format
msgid "permission denied for extension %s"
msgstr "droit refusé pour l'extension %s"
-#: catalog/aclchk.c:3355 catalog/aclchk.c:3357
+#: catalog/aclchk.c:3340
+#, c-format
+msgid "permission denied for publication %s"
+msgstr "droit refusé pour la publication %s"
+
+#: catalog/aclchk.c:3342
+#, c-format
+msgid "permission denied for subscription %s"
+msgstr "droit refusé pour la souscription %s"
+
+#: catalog/aclchk.c:3348 catalog/aclchk.c:3350
#, c-format
msgid "must be owner of relation %s"
msgstr "doit être le propriétaire de la relation %s"
-#: catalog/aclchk.c:3359
+#: catalog/aclchk.c:3352
#, c-format
msgid "must be owner of sequence %s"
msgstr "doit être le propriétaire de la séquence %s"
-#: catalog/aclchk.c:3361
+#: catalog/aclchk.c:3354
#, c-format
msgid "must be owner of database %s"
msgstr "doit être le propriétaire de la base de données %s"
-#: catalog/aclchk.c:3363
+#: catalog/aclchk.c:3356
#, c-format
msgid "must be owner of function %s"
msgstr "doit être le propriétaire de la fonction %s"
-#: catalog/aclchk.c:3365
+#: catalog/aclchk.c:3358
#, c-format
msgid "must be owner of operator %s"
msgstr "doit être le prorpriétaire de l'opérateur %s"
-#: catalog/aclchk.c:3367
+#: catalog/aclchk.c:3360
#, c-format
msgid "must be owner of type %s"
msgstr "doit être le propriétaire du type %s"
-#: catalog/aclchk.c:3369
+#: catalog/aclchk.c:3362
#, c-format
msgid "must be owner of language %s"
msgstr "doit être le propriétaire du langage %s"
-#: catalog/aclchk.c:3371
+#: catalog/aclchk.c:3364
#, c-format
msgid "must be owner of large object %s"
msgstr "doit être le propriétaire du Large Object %s"
-#: catalog/aclchk.c:3373
+#: catalog/aclchk.c:3366
#, c-format
msgid "must be owner of schema %s"
msgstr "doit être le propriétaire du schéma %s"
-#: catalog/aclchk.c:3375
+#: catalog/aclchk.c:3368
#, c-format
msgid "must be owner of operator class %s"
msgstr "doit être le propriétaire de la classe d'opérateur %s"
-#: catalog/aclchk.c:3377
+#: catalog/aclchk.c:3370
#, c-format
msgid "must be owner of operator family %s"
msgstr "doit être le prorpriétaire de la famille d'opérateur %s"
-#: catalog/aclchk.c:3379
+#: catalog/aclchk.c:3372
#, c-format
msgid "must be owner of collation %s"
msgstr "doit être le propriétaire du collationnement %s"
-#: catalog/aclchk.c:3381
+#: catalog/aclchk.c:3374
#, c-format
msgid "must be owner of conversion %s"
msgstr "doit être le propriétaire de la conversion %s"
-#: catalog/aclchk.c:3383
+#: catalog/aclchk.c:3376
+#, c-format
+msgid "must be owner of statistics object %s"
+msgstr "doit être le propriétaire de l'objet statistique %s"
+
+#: catalog/aclchk.c:3378
#, c-format
msgid "must be owner of tablespace %s"
msgstr "doit être le propriétaire du tablespace %s"
-#: catalog/aclchk.c:3385
+#: catalog/aclchk.c:3380
#, c-format
msgid "must be owner of text search dictionary %s"
msgstr "doit être le propriétaire du dictionnaire de recherche plein texte %s"
-#: catalog/aclchk.c:3387
+#: catalog/aclchk.c:3382
#, c-format
msgid "must be owner of text search configuration %s"
msgstr "doit être le propriétaire de la configuration de recherche plein texte %s"
-#: catalog/aclchk.c:3389
+#: catalog/aclchk.c:3384
#, c-format
msgid "must be owner of foreign-data wrapper %s"
msgstr "doit être le propriétaire du wrapper de données distantes %s"
-#: catalog/aclchk.c:3391
+#: catalog/aclchk.c:3386
#, c-format
msgid "must be owner of foreign server %s"
msgstr "doit être le propriétaire de serveur distant %s"
-#: catalog/aclchk.c:3393
+#: catalog/aclchk.c:3388
#, c-format
msgid "must be owner of event trigger %s"
msgstr "doit être le propriétaire du trigger sur événement %s"
-#: catalog/aclchk.c:3395
+#: catalog/aclchk.c:3390
#, c-format
msgid "must be owner of extension %s"
msgstr "doit être le propriétaire de l'extension %s"
-#: catalog/aclchk.c:3437
+#: catalog/aclchk.c:3392
+#, c-format
+msgid "must be owner of publication %s"
+msgstr "doit être le propriétaire de la publication %s"
+
+#: catalog/aclchk.c:3394
+#, c-format
+msgid "must be owner of subscription %s"
+msgstr "doit être le propriétaire de la souscription %s"
+
+#: catalog/aclchk.c:3436
#, c-format
msgid "permission denied for column \"%s\" of relation \"%s\""
msgstr "droit refusé pour la colonne « %s » de la relation « %s »"
-#: catalog/aclchk.c:3556 catalog/aclchk.c:3564
+#: catalog/aclchk.c:3559 catalog/aclchk.c:3567
#, c-format
msgid "attribute %d of relation with OID %u does not exist"
msgstr "l'attribut %d de la relation d'OID %u n'existe pas"
-#: catalog/aclchk.c:3637 catalog/aclchk.c:4556
+#: catalog/aclchk.c:3640 catalog/aclchk.c:4559
#, c-format
msgid "relation with OID %u does not exist"
msgstr "la relation d'OID %u n'existe pas"
-#: catalog/aclchk.c:3736 catalog/aclchk.c:4974
+#: catalog/aclchk.c:3739 catalog/aclchk.c:4977
#, c-format
msgid "database with OID %u does not exist"
msgstr "la base de données d'OID %u n'existe pas"
-#: catalog/aclchk.c:3790 catalog/aclchk.c:4634 tcop/fastpath.c:223
+#: catalog/aclchk.c:3793 catalog/aclchk.c:4637 tcop/fastpath.c:223 utils/fmgr/fmgr.c:2117
#, c-format
msgid "function with OID %u does not exist"
msgstr "la fonction d'OID %u n'existe pas"
-#: catalog/aclchk.c:3844 catalog/aclchk.c:4660
+#: catalog/aclchk.c:3847 catalog/aclchk.c:4663
#, c-format
msgid "language with OID %u does not exist"
msgstr "le langage d'OID %u n'existe pas"
-#: catalog/aclchk.c:4008 catalog/aclchk.c:4732
+#: catalog/aclchk.c:4011 catalog/aclchk.c:4735
#, c-format
msgid "schema with OID %u does not exist"
msgstr "le schéma d'OID %u n'existe pas"
-#: catalog/aclchk.c:4062 catalog/aclchk.c:4759
+#: catalog/aclchk.c:4065 catalog/aclchk.c:4762
#, c-format
msgid "tablespace with OID %u does not exist"
msgstr "le tablespace d'OID %u n'existe pas"
-#: catalog/aclchk.c:4121 catalog/aclchk.c:4893 commands/foreigncmds.c:325
+#: catalog/aclchk.c:4124 catalog/aclchk.c:4896 commands/foreigncmds.c:324
#, c-format
msgid "foreign-data wrapper with OID %u does not exist"
msgstr "le wrapper de données distantes d'OID %u n'existe pas"
-#: catalog/aclchk.c:4183 catalog/aclchk.c:4920 commands/foreigncmds.c:461
+#: catalog/aclchk.c:4186 catalog/aclchk.c:4923 commands/foreigncmds.c:459
#, c-format
msgid "foreign server with OID %u does not exist"
msgstr "le serveur distant d'OID %u n'existe pas"
-#: catalog/aclchk.c:4243 catalog/aclchk.c:4582
+#: catalog/aclchk.c:4246 catalog/aclchk.c:4585 utils/cache/typcache.c:238
#, c-format
msgid "type with OID %u does not exist"
msgstr "le type d'OID %u n'existe pas"
-#: catalog/aclchk.c:4608
+#: catalog/aclchk.c:4611
#, c-format
msgid "operator with OID %u does not exist"
msgstr "l'opérateur d'OID %u n'existe pas"
-#: catalog/aclchk.c:4785
+#: catalog/aclchk.c:4788
#, c-format
msgid "operator class with OID %u does not exist"
msgstr "la classe d'opérateur d'OID %u n'existe pas"
-#: catalog/aclchk.c:4812
+#: catalog/aclchk.c:4815
#, c-format
msgid "operator family with OID %u does not exist"
msgstr "la famille d'opérateur d'OID %u n'existe pas"
-#: catalog/aclchk.c:4839
+#: catalog/aclchk.c:4842
#, c-format
msgid "text search dictionary with OID %u does not exist"
msgstr "le dictionnaire de recherche plein texte d'OID %u n'existe pas"
-#: catalog/aclchk.c:4866
+#: catalog/aclchk.c:4869
#, c-format
msgid "text search configuration with OID %u does not exist"
msgstr "la configuration de recherche plein texte d'OID %u n'existe pas"
-#: catalog/aclchk.c:4947 commands/event_trigger.c:587
+#: catalog/aclchk.c:4950 commands/event_trigger.c:588
#, c-format
msgid "event trigger with OID %u does not exist"
msgstr "le trigger sur événement d'OID %u n'existe pas"
-#: catalog/aclchk.c:5000
+#: catalog/aclchk.c:5003 commands/collationcmds.c:348
#, c-format
msgid "collation with OID %u does not exist"
msgstr "le collationnement d'OID %u n'existe pas"
-#: catalog/aclchk.c:5026
+#: catalog/aclchk.c:5029
#, c-format
msgid "conversion with OID %u does not exist"
msgstr "la conversion d'OID %u n'existe pas"
-#: catalog/aclchk.c:5067
+#: catalog/aclchk.c:5070
#, c-format
msgid "extension with OID %u does not exist"
msgstr "l'extension d'OID %u n'existe pas"
-#: catalog/dependency.c:645
+#: catalog/aclchk.c:5097 commands/publicationcmds.c:733
+#, c-format
+msgid "publication with OID %u does not exist"
+msgstr "la publication d'OID %u n'existe pas"
+
+#: catalog/aclchk.c:5123 commands/subscriptioncmds.c:1075
+#, c-format
+msgid "subscription with OID %u does not exist"
+msgstr "la souscription d'OID %u n'existe pas"
+
+#: catalog/aclchk.c:5149
+#, c-format
+msgid "statistics object with OID %u does not exist"
+msgstr "l'objet statistique d'OID %u n'existe pas"
+
+#: catalog/dependency.c:613
#, c-format
msgid "cannot drop %s because %s requires it"
msgstr "n'a pas pu supprimer %s car il est requis par %s"
-#: catalog/dependency.c:648
+#: catalog/dependency.c:616
#, c-format
msgid "You can drop %s instead."
msgstr "Vous pouvez supprimer %s à la place."
-#: catalog/dependency.c:810 catalog/pg_shdepend.c:576
+#: catalog/dependency.c:779 catalog/pg_shdepend.c:574
#, c-format
msgid "cannot drop %s because it is required by the database system"
msgstr "n'a pas pu supprimer %s car il est requis par le système de bases de données"
-#: catalog/dependency.c:926
+#: catalog/dependency.c:897
#, c-format
msgid "drop auto-cascades to %s"
msgstr "DROP cascade automatiquement sur %s"
-#: catalog/dependency.c:938 catalog/dependency.c:947
+#: catalog/dependency.c:909 catalog/dependency.c:918
#, c-format
msgid "%s depends on %s"
msgstr "%s dépend de %s"
-#: catalog/dependency.c:959 catalog/dependency.c:968
+#: catalog/dependency.c:930 catalog/dependency.c:939
#, c-format
msgid "drop cascades to %s"
msgstr "DROP cascade sur %s"
-#: catalog/dependency.c:976 catalog/pg_shdepend.c:687
+#: catalog/dependency.c:947 catalog/pg_shdepend.c:685
#, c-format
msgid ""
"\n"
@@ -3596,95 +3468,85 @@ msgstr[1] ""
"\n"
"et %d autres objets (voir le journal applicatif du serveur pour une liste)"
-#: catalog/dependency.c:988
+#: catalog/dependency.c:959
#, c-format
msgid "cannot drop %s because other objects depend on it"
msgstr "n'a pas pu supprimer %s car d'autres objets en dépendent"
-#: catalog/dependency.c:992 catalog/dependency.c:999
+#: catalog/dependency.c:963 catalog/dependency.c:970
#, c-format
msgid "Use DROP ... CASCADE to drop the dependent objects too."
msgstr "Utilisez DROP ... CASCADE pour supprimer aussi les objets dépendants."
-#: catalog/dependency.c:996
+#: catalog/dependency.c:967
#, c-format
msgid "cannot drop desired object(s) because other objects depend on them"
msgstr "ne peut pas supprimer les objets désirés car d'autres objets en dépendent"
#. translator: %d always has a value larger than 1
-#: catalog/dependency.c:1005
+#: catalog/dependency.c:976
#, c-format
msgid "drop cascades to %d other object"
msgid_plural "drop cascades to %d other objects"
msgstr[0] "DROP cascade sur %d autre objet"
msgstr[1] "DROP cascade sur %d autres objets"
-#: catalog/dependency.c:1633
+#: catalog/dependency.c:1635
#, c-format
-msgid "constant of the type \"regrole\" cannot be used here"
-msgstr "une constante de type « regrole » ne peut pas être utilisée ici"
+msgid "constant of the type %s cannot be used here"
+msgstr "la constante de type %s ne peut pas être utilisée ici"
-#: catalog/heap.c:278
+#: catalog/heap.c:283
#, c-format
msgid "permission denied to create \"%s.%s\""
msgstr "droit refusé pour créer « %s.%s »"
-#: catalog/heap.c:280
+#: catalog/heap.c:285
#, c-format
msgid "System catalog modifications are currently disallowed."
msgstr "Les modifications du catalogue système sont actuellement interdites."
-#: catalog/heap.c:415 commands/tablecmds.c:1439 commands/tablecmds.c:1896 commands/tablecmds.c:4820
+#: catalog/heap.c:421 commands/tablecmds.c:1649 commands/tablecmds.c:2159 commands/tablecmds.c:5212
#, c-format
msgid "tables can have at most %d columns"
msgstr "les tables peuvent avoir au plus %d colonnes"
-#: catalog/heap.c:432 commands/tablecmds.c:5081
+#: catalog/heap.c:438 commands/tablecmds.c:5471
#, c-format
msgid "column name \"%s\" conflicts with a system column name"
msgstr "le nom de la colonne « %s » entre en conflit avec le nom d'une colonne système"
-#: catalog/heap.c:448
+#: catalog/heap.c:454
#, c-format
msgid "column name \"%s\" specified more than once"
msgstr "colonne « %s » spécifiée plus d'une fois"
-#: catalog/heap.c:498
-#, c-format
-msgid "column \"%s\" has type \"unknown\""
-msgstr "la colonne « %s » est de type « unknown »"
-
-#: catalog/heap.c:499
-#, c-format
-msgid "Proceeding with relation creation anyway."
-msgstr "Poursuit malgré tout la création de la relation."
-
-#: catalog/heap.c:512
+#: catalog/heap.c:507
#, c-format
msgid "column \"%s\" has pseudo-type %s"
msgstr "la colonne « %s » a le pseudo type %s"
-#: catalog/heap.c:542
+#: catalog/heap.c:537
#, c-format
msgid "composite type %s cannot be made a member of itself"
msgstr "le type composite %s ne peut pas être membre de lui-même"
-#: catalog/heap.c:584 commands/createas.c:201 commands/createas.c:498
+#: catalog/heap.c:579 commands/createas.c:201 commands/createas.c:498
#, c-format
msgid "no collation was derived for column \"%s\" with collatable type %s"
msgstr "aucun collationnement n'a été dérivé pour la colonne « %s » de type collationnable %s"
-#: catalog/heap.c:586 commands/createas.c:204 commands/createas.c:501 commands/indexcmds.c:1132 commands/view.c:103 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:5334 utils/adt/varlena.c:1421 utils/adt/varlena.c:1826
+#: catalog/heap.c:581 commands/createas.c:204 commands/createas.c:501 commands/indexcmds.c:1149 commands/tablecmds.c:13376 commands/view.c:103 regex/regc_pg_locale.c:263 utils/adt/formatting.c:1547 utils/adt/formatting.c:1671 utils/adt/formatting.c:1796 utils/adt/like.c:184 utils/adt/selfuncs.c:5563 utils/adt/varlena.c:1417 utils/adt/varlena.c:1866
#, c-format
msgid "Use the COLLATE clause to set the collation explicitly."
msgstr "Utilisez la clause COLLARE pour configurer explicitement le collationnement."
-#: catalog/heap.c:1067 catalog/index.c:792 commands/tablecmds.c:2623
+#: catalog/heap.c:1067 catalog/index.c:807 commands/tablecmds.c:2943
#, c-format
msgid "relation \"%s\" already exists"
msgstr "la relation « %s » existe déjà"
-#: catalog/heap.c:1083 catalog/pg_type.c:412 catalog/pg_type.c:722 commands/typecmds.c:237 commands/typecmds.c:784 commands/typecmds.c:1135 commands/typecmds.c:1357 commands/typecmds.c:2113
+#: catalog/heap.c:1083 catalog/pg_type.c:410 catalog/pg_type.c:732 commands/typecmds.c:239 commands/typecmds.c:788 commands/typecmds.c:1139 commands/typecmds.c:1350 commands/typecmds.c:2106
#, c-format
msgid "type \"%s\" already exists"
msgstr "le type « %s » existe déjà"
@@ -3696,94 +3558,94 @@ msgstr ""
"Une relation a un type associé du même nom, donc vous devez utiliser un nom\n"
"qui n'entre pas en conflit avec un type existant."
-#: catalog/heap.c:1112
+#: catalog/heap.c:1113
#, c-format
msgid "pg_class heap OID value not set when in binary upgrade mode"
msgstr "OID du heap de pg_class non configuré en mode de mise à jour binaire"
-#: catalog/heap.c:2291
+#: catalog/heap.c:2078
+#, c-format
+msgid "cannot add NO INHERIT constraint to partitioned table \"%s\""
+msgstr "ne peut pas ajouter une contrainte NO INHERIT pour la table partitionnée « %s »"
+
+#: catalog/heap.c:2336
#, c-format
msgid "check constraint \"%s\" already exists"
msgstr "la contrainte de vérification « %s » existe déjà"
-#: catalog/heap.c:2456 catalog/pg_constraint.c:654 commands/tablecmds.c:6069
+#: catalog/heap.c:2504 catalog/pg_constraint.c:649 commands/tablecmds.c:6825
#, c-format
msgid "constraint \"%s\" for relation \"%s\" already exists"
msgstr "la contrainte « %s » de la relation « %s » existe déjà"
-#: catalog/heap.c:2463
+#: catalog/heap.c:2511
#, c-format
msgid "constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\""
msgstr "la contrainte « %s » entre en conflit avec la constrainte non héritée sur la relation « %s »"
-#: catalog/heap.c:2474
+#: catalog/heap.c:2522
#, c-format
msgid "constraint \"%s\" conflicts with inherited constraint on relation \"%s\""
msgstr "la contrainte « %s » entre en conflit avec une contrainte héritée sur la relation « %s »"
-#: catalog/heap.c:2484
+#: catalog/heap.c:2532
#, c-format
msgid "constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\""
msgstr "la contrainte « %s » entre en conflit avec une contrainte NOT VALID sur la relation « %s »"
-#: catalog/heap.c:2489
+#: catalog/heap.c:2537
#, c-format
msgid "merging constraint \"%s\" with inherited definition"
msgstr "assemblage de la contrainte « %s » avec une définition héritée"
-#: catalog/heap.c:2595
+#: catalog/heap.c:2653
#, c-format
msgid "cannot use column references in default expression"
msgstr "ne peut pas utiliser les références de colonnes dans l'expression par défaut"
-#: catalog/heap.c:2606
-#, c-format
-msgid "default expression must not return a set"
-msgstr "l'expression par défaut ne doit pas renvoyer un ensemble"
-
-#: catalog/heap.c:2625 rewrite/rewriteHandler.c:1084
+#: catalog/heap.c:2678 rewrite/rewriteHandler.c:1171
#, c-format
msgid "column \"%s\" is of type %s but default expression is of type %s"
msgstr "la colonne « %s » est de type %s alors que l'expression par défaut est de type %s"
-#: catalog/heap.c:2630 commands/prepare.c:374 parser/parse_node.c:428 parser/parse_target.c:539 parser/parse_target.c:789 parser/parse_target.c:799 rewrite/rewriteHandler.c:1089
+#: catalog/heap.c:2683 commands/prepare.c:384 parser/parse_node.c:430 parser/parse_target.c:590 parser/parse_target.c:840 parser/parse_target.c:850 rewrite/rewriteHandler.c:1176
#, c-format
msgid "You will need to rewrite or cast the expression."
msgstr "Vous devez réécrire l'expression ou lui appliquer une transformation de type."
-#: catalog/heap.c:2677
+#: catalog/heap.c:2730
#, c-format
msgid "only table \"%s\" can be referenced in check constraint"
msgstr "seule la table « %s » peut être référencée dans la contrainte de vérification"
-#: catalog/heap.c:2917
+#: catalog/heap.c:2970
#, c-format
msgid "unsupported ON COMMIT and foreign key combination"
msgstr "combinaison ON COMMIT et clé étrangère non supportée"
-#: catalog/heap.c:2918
+#: catalog/heap.c:2971
#, c-format
msgid "Table \"%s\" references \"%s\", but they do not have the same ON COMMIT setting."
msgstr ""
"La table « %s » référence « %s » mais elles n'ont pas la même valeur pour le\n"
"paramètre ON COMMIT."
-#: catalog/heap.c:2923
+#: catalog/heap.c:2976
#, c-format
msgid "cannot truncate a table referenced in a foreign key constraint"
msgstr "ne peut pas tronquer une table référencée dans une contrainte de clé étrangère"
-#: catalog/heap.c:2924
+#: catalog/heap.c:2977
#, c-format
msgid "Table \"%s\" references \"%s\"."
msgstr "La table « %s » référence « %s »."
-#: catalog/heap.c:2926
+#: catalog/heap.c:2979
#, c-format
msgid "Truncate table \"%s\" at the same time, or use TRUNCATE ... CASCADE."
msgstr "Tronquez la table « %s » en même temps, ou utilisez TRUNCATE ... CASCADE."
-#: catalog/index.c:210 parser/parse_utilcmd.c:1473 parser/parse_utilcmd.c:1559
+#: catalog/index.c:210 parser/parse_utilcmd.c:1671 parser/parse_utilcmd.c:1757
#, c-format
msgid "multiple primary keys for table \"%s\" are not allowed"
msgstr "les clés primaires multiples ne sont pas autorisées pour la table « %s »"
@@ -3793,270 +3655,234 @@ msgstr "les clés primaires multiples ne sont pas autorisées pour la table « %
msgid "primary keys cannot be expressions"
msgstr "les clés primaires ne peuvent pas être des expressions"
-#: catalog/index.c:742 catalog/index.c:1160
+#: catalog/index.c:757 catalog/index.c:1175
#, c-format
msgid "user-defined indexes on system catalog tables are not supported"
msgstr "les index définis par l'utilisateur sur les tables du catalogue système ne sont pas supportés"
-#: catalog/index.c:752
+#: catalog/index.c:767
#, c-format
msgid "concurrent index creation on system catalog tables is not supported"
msgstr ""
"la création en parallèle d'un index sur les tables du catalogue système\n"
"n'est pas supportée"
-#: catalog/index.c:770
+#: catalog/index.c:785
#, c-format
msgid "shared indexes cannot be created after initdb"
msgstr "les index partagés ne peuvent pas être créés après initdb"
-#: catalog/index.c:784 commands/createas.c:249 commands/sequence.c:141 parser/parse_utilcmd.c:191
+#: catalog/index.c:799 commands/createas.c:250 commands/sequence.c:152 parser/parse_utilcmd.c:201
#, c-format
msgid "relation \"%s\" already exists, skipping"
msgstr "la relation « %s » existe déjà, poursuite du traitement"
-#: catalog/index.c:820
+#: catalog/index.c:835
#, c-format
msgid "pg_class index OID value not set when in binary upgrade mode"
msgstr "OID de l'index de pg_class non configuré en mode de mise à jour binaire"
-#: catalog/index.c:1422
+#: catalog/index.c:1436
#, c-format
msgid "DROP INDEX CONCURRENTLY must be first action in transaction"
msgstr "DROP INDEX CONCURRENTLY doit être la première action dans une transaction"
-#: catalog/index.c:2004
+#: catalog/index.c:2024
#, c-format
msgid "building index \"%s\" on table \"%s\""
msgstr "construction de l'index « %s » sur la table « %s »"
-#: catalog/index.c:3322
+#: catalog/index.c:3336
#, c-format
msgid "cannot reindex temporary tables of other sessions"
msgstr "ne peut pas ré-indexer les tables temporaires des autres sessions"
-#: catalog/index.c:3454
+#: catalog/index.c:3467
#, c-format
msgid "index \"%s\" was reindexed"
msgstr "l'index « %s » a été réindexée"
-#: catalog/index.c:3456 commands/vacuumlazy.c:1338 commands/vacuumlazy.c:1414 commands/vacuumlazy.c:1603 commands/vacuumlazy.c:1813
-#, c-format
-msgid "%s."
-msgstr "%s."
-
-#: catalog/namespace.c:249 catalog/namespace.c:447 catalog/namespace.c:541 commands/trigger.c:4523
+#: catalog/namespace.c:235 catalog/namespace.c:433 catalog/namespace.c:527 commands/trigger.c:4931
#, c-format
msgid "cross-database references are not implemented: \"%s.%s.%s\""
msgstr "les références entre bases de données ne sont pas implémentées : « %s.%s.%s »"
-#: catalog/namespace.c:306
+#: catalog/namespace.c:292
#, c-format
msgid "temporary tables cannot specify a schema name"
msgstr "les tables temporaires ne peuvent pas spécifier un nom de schéma"
-#: catalog/namespace.c:385
+#: catalog/namespace.c:371
#, c-format
msgid "could not obtain lock on relation \"%s.%s\""
msgstr "n'a pas pu obtenir un verrou sur la relation « %s.%s »"
-#: catalog/namespace.c:390 commands/lockcmds.c:146
+#: catalog/namespace.c:376 commands/lockcmds.c:145
#, c-format
msgid "could not obtain lock on relation \"%s\""
msgstr "n'a pas pu obtenir un verrou sur la relation « %s »"
-#: catalog/namespace.c:414 parser/parse_relation.c:1138
+#: catalog/namespace.c:400 parser/parse_relation.c:1158
#, c-format
msgid "relation \"%s.%s\" does not exist"
msgstr "la relation « %s.%s » n'existe pas"
-#: catalog/namespace.c:419 parser/parse_relation.c:1151 parser/parse_relation.c:1159 utils/adt/regproc.c:1034
+#: catalog/namespace.c:405 parser/parse_relation.c:1177 parser/parse_relation.c:1185
#, c-format
msgid "relation \"%s\" does not exist"
msgstr "la relation « %s » n'existe pas"
-#: catalog/namespace.c:487 catalog/namespace.c:2841 commands/extension.c:1383 commands/extension.c:1389
+#: catalog/namespace.c:473 catalog/namespace.c:2992 commands/extension.c:1466 commands/extension.c:1472
#, c-format
msgid "no schema has been selected to create in"
msgstr "aucun schéma n'a été sélectionné pour cette création"
-#: catalog/namespace.c:639 catalog/namespace.c:652
+#: catalog/namespace.c:625 catalog/namespace.c:638
#, c-format
msgid "cannot create relations in temporary schemas of other sessions"
msgstr "ne peut pas créer les relations dans les schémas temporaires d'autres sessions"
-#: catalog/namespace.c:643
+#: catalog/namespace.c:629
#, c-format
msgid "cannot create temporary relation in non-temporary schema"
msgstr "ne peut pas créer une relation temporaire dans un schéma non temporaire"
-#: catalog/namespace.c:658
+#: catalog/namespace.c:644
#, c-format
msgid "only temporary relations may be created in temporary schemas"
msgstr "seules les relations temporaires peuvent être créées dans des schémas temporaires"
-#: catalog/namespace.c:2154
+#: catalog/namespace.c:2182
+#, c-format
+msgid "statistics object \"%s\" does not exist"
+msgstr "l'objet statistique « %s » n'existe pas"
+
+#: catalog/namespace.c:2305
#, c-format
msgid "text search parser \"%s\" does not exist"
msgstr "l'analyseur de recherche plein texte « %s » n'existe pas"
-#: catalog/namespace.c:2280
+#: catalog/namespace.c:2431
#, c-format
msgid "text search dictionary \"%s\" does not exist"
msgstr "le dictionnaire de recherche plein texte « %s » n'existe pas"
-#: catalog/namespace.c:2407
+#: catalog/namespace.c:2558
#, c-format
msgid "text search template \"%s\" does not exist"
msgstr "le modèle de recherche plein texte « %s » n'existe pas"
-#: catalog/namespace.c:2533 commands/tsearchcmds.c:1197 utils/cache/ts_cache.c:611
+#: catalog/namespace.c:2684 commands/tsearchcmds.c:1185 utils/cache/ts_cache.c:612
#, c-format
msgid "text search configuration \"%s\" does not exist"
msgstr "la configuration de recherche plein texte « %s » n'existe pas"
-#: catalog/namespace.c:2646 parser/parse_expr.c:792 parser/parse_target.c:1141
+#: catalog/namespace.c:2797 parser/parse_expr.c:789 parser/parse_target.c:1192
#, c-format
msgid "cross-database references are not implemented: %s"
msgstr "les références entre bases de données ne sont pas implémentées : %s"
-#: catalog/namespace.c:2652 gram.y:13450 gram.y:14819 parser/parse_expr.c:799 parser/parse_target.c:1148
+#: catalog/namespace.c:2803 gram.y:14300 gram.y:15721 parser/parse_expr.c:796 parser/parse_target.c:1199
#, c-format
msgid "improper qualified name (too many dotted names): %s"
msgstr "mauvaise qualification du nom (trop de points entre les noms) : %s"
-#: catalog/namespace.c:2783
+#: catalog/namespace.c:2934
#, c-format
msgid "cannot move objects into or out of temporary schemas"
msgstr "ne peut pas déplacer les objets dans ou à partir des schémas temporaires"
-#: catalog/namespace.c:2789
+#: catalog/namespace.c:2940
#, c-format
msgid "cannot move objects into or out of TOAST schema"
msgstr "ne peut pas déplacer les objets dans ou à partir des schémas TOAST"
-#: catalog/namespace.c:2862 commands/schemacmds.c:238 commands/schemacmds.c:317 commands/tablecmds.c:741
+#: catalog/namespace.c:3013 commands/schemacmds.c:256 commands/schemacmds.c:334 commands/tablecmds.c:891
#, c-format
msgid "schema \"%s\" does not exist"
msgstr "le schéma « %s » n'existe pas"
-#: catalog/namespace.c:2893
+#: catalog/namespace.c:3044
#, c-format
msgid "improper relation name (too many dotted names): %s"
msgstr "nom de relation incorrecte (trop de points entre les noms) : %s"
-#: catalog/namespace.c:3403
+#: catalog/namespace.c:3538
#, c-format
msgid "collation \"%s\" for encoding \"%s\" does not exist"
msgstr "le collationnement « %s » pour l'encodage « %s » n'existe pas"
-#: catalog/namespace.c:3458
+#: catalog/namespace.c:3593
#, c-format
msgid "conversion \"%s\" does not exist"
msgstr "la conversion « %s » n'existe pas"
-#: catalog/namespace.c:3666
+#: catalog/namespace.c:3801
#, c-format
msgid "permission denied to create temporary tables in database \"%s\""
msgstr "droit refusé pour la création de tables temporaires dans la base de données « %s »"
-#: catalog/namespace.c:3682
+#: catalog/namespace.c:3817
#, c-format
msgid "cannot create temporary tables during recovery"
msgstr "ne peut pas créer des tables temporaires lors de la restauration"
-#: catalog/namespace.c:3688
+#: catalog/namespace.c:3823
#, c-format
-msgid "cannot create temporary tables in parallel mode"
-msgstr "ne peut pas créer des tables temporaires dans le mode de parallélisation"
+msgid "cannot create temporary tables during a parallel operation"
+msgstr "ne peut pas créer de tables temporaires pendant une opération parallèle"
-#: catalog/namespace.c:3932 commands/tablespace.c:1173 commands/variable.c:63 utils/misc/guc.c:9875
+#: catalog/namespace.c:4072 commands/tablespace.c:1169 commands/variable.c:64 utils/misc/guc.c:9990 utils/misc/guc.c:10068
#, c-format
msgid "List syntax is invalid."
msgstr "La syntaxe de la liste est invalide."
-#: catalog/objectaddress.c:1065
-msgid "access method name cannot be qualified"
-msgstr "le nom de la méthode d'accès ne peut pas être qualifiée"
-
-#: catalog/objectaddress.c:1068
-msgid "database name cannot be qualified"
-msgstr "le nom de la base de donnée ne peut être qualifié"
-
-#: catalog/objectaddress.c:1071 commands/extension.c:2507
-#, c-format
-msgid "extension name cannot be qualified"
-msgstr "le nom de l'extension ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1074
-msgid "tablespace name cannot be qualified"
-msgstr "le nom du tablespace ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1077
-msgid "role name cannot be qualified"
-msgstr "le nom du rôle ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1080
-msgid "schema name cannot be qualified"
-msgstr "le nom du schéma ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1083
-msgid "language name cannot be qualified"
-msgstr "le nom du langage ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1086
-msgid "foreign-data wrapper name cannot be qualified"
-msgstr "le nom du wrapper de données distantes ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1089
-msgid "server name cannot be qualified"
-msgstr "le nom du serveur ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1092
-msgid "event trigger name cannot be qualified"
-msgstr "le nom du trigger sur événement ne peut pas être qualifié"
-
-#: catalog/objectaddress.c:1210 commands/lockcmds.c:94 commands/policy.c:94 commands/policy.c:382 commands/policy.c:471 commands/tablecmds.c:218 commands/tablecmds.c:1300 commands/tablecmds.c:4347 commands/tablecmds.c:8017
+#: catalog/objectaddress.c:1237 catalog/pg_publication.c:66 commands/lockcmds.c:93 commands/policy.c:94 commands/policy.c:391 commands/policy.c:481 commands/tablecmds.c:223 commands/tablecmds.c:265 commands/tablecmds.c:1507 commands/tablecmds.c:4722 commands/tablecmds.c:8810
#, c-format
msgid "\"%s\" is not a table"
msgstr "« %s » n'est pas une table"
-#: catalog/objectaddress.c:1217 commands/tablecmds.c:230 commands/tablecmds.c:4377 commands/tablecmds.c:12159 commands/view.c:141
+#: catalog/objectaddress.c:1244 commands/tablecmds.c:235 commands/tablecmds.c:4752 commands/tablecmds.c:13085 commands/view.c:141
#, c-format
msgid "\"%s\" is not a view"
msgstr "« %s » n'est pas une vue"
-#: catalog/objectaddress.c:1224 commands/matview.c:174 commands/tablecmds.c:236 commands/tablecmds.c:12164
+#: catalog/objectaddress.c:1251 commands/matview.c:174 commands/tablecmds.c:241 commands/tablecmds.c:13090
#, c-format
msgid "\"%s\" is not a materialized view"
msgstr "« %s » n'est pas une vue matérialisée"
-#: catalog/objectaddress.c:1231 commands/tablecmds.c:254 commands/tablecmds.c:4380 commands/tablecmds.c:12169
+#: catalog/objectaddress.c:1258 commands/tablecmds.c:259 commands/tablecmds.c:4755 commands/tablecmds.c:13095
#, c-format
msgid "\"%s\" is not a foreign table"
msgstr "« %s » n'est pas une table distante"
-#: catalog/objectaddress.c:1376 catalog/objectaddress.c:1429
+#: catalog/objectaddress.c:1299
+#, c-format
+msgid "must specify relation and object name"
+msgstr "doit indiquer les noms de relation et d'objet"
+
+#: catalog/objectaddress.c:1375 catalog/objectaddress.c:1428
#, c-format
msgid "column name must be qualified"
msgstr "le nom de la colonne doit être qualifié"
-#: catalog/objectaddress.c:1472
+#: catalog/objectaddress.c:1471
#, c-format
msgid "default value for column \"%s\" of relation \"%s\" does not exist"
msgstr "la valeur par défaut de la colonne « %s » de la relation « %s » n'existe pas"
-#: catalog/objectaddress.c:1512 commands/functioncmds.c:128 commands/tablecmds.c:246 commands/typecmds.c:3214 parser/parse_type.c:226 parser/parse_type.c:255 parser/parse_type.c:795 utils/adt/acl.c:4374 utils/adt/regproc.c:1225
+#: catalog/objectaddress.c:1508 commands/functioncmds.c:128 commands/tablecmds.c:251 commands/typecmds.c:3233 parser/parse_type.c:226 parser/parse_type.c:255 parser/parse_type.c:794 utils/adt/acl.c:4357
#, c-format
msgid "type \"%s\" does not exist"
msgstr "le type « %s » n'existe pas"
-#: catalog/objectaddress.c:1629
+#: catalog/objectaddress.c:1625
#, c-format
msgid "operator %d (%s, %s) of %s does not exist"
msgstr "l'opérateur %d (%s, %s) de %s n'existe pas"
-#: catalog/objectaddress.c:1658
+#: catalog/objectaddress.c:1656
#, c-format
msgid "function %d (%s, %s) of %s does not exist"
msgstr "la fonction %d (%s, %s) de %s n'existe pas"
@@ -4066,156 +3892,166 @@ msgstr "la fonction %d (%s, %s) de %s n'existe pas"
msgid "user mapping for user \"%s\" on server \"%s\" does not exist"
msgstr "la correspondance pour l'utilisateur « %s » sur le serveur « %s » n'existe pas"
-#: catalog/objectaddress.c:1722 commands/foreigncmds.c:430 commands/foreigncmds.c:997 commands/foreigncmds.c:1359 foreign/foreign.c:692
+#: catalog/objectaddress.c:1722 commands/foreigncmds.c:428 commands/foreigncmds.c:1004 commands/foreigncmds.c:1377 foreign/foreign.c:688
#, c-format
msgid "server \"%s\" does not exist"
msgstr "le serveur « %s » n'existe pas"
-#: catalog/objectaddress.c:1794
+#: catalog/objectaddress.c:1789
+#, c-format
+msgid "publication relation \"%s\" in publication \"%s\" does not exist"
+msgstr "la relation de publication « %s » dans la publication « %s » n'existe pas"
+
+#: catalog/objectaddress.c:1851
#, c-format
-msgid "unrecognized default ACL object type %c"
-msgstr "type d'objet de droits par défaut non reconnu %c"
+msgid "unrecognized default ACL object type \"%c\""
+msgstr "type d'objet de droits par défaut non reconnu « %c »"
-#: catalog/objectaddress.c:1795
+#: catalog/objectaddress.c:1852
#, c-format
-msgid "Valid object types are \"r\", \"S\", \"f\", and \"T\"."
-msgstr "Les types d'objet valides sont « r », « S », « f » et « T »."
+msgid "Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\"."
+msgstr "Les types d'objet valides sont « %c », « %c », « %c », « %c », « %c »."
-#: catalog/objectaddress.c:1841
+#: catalog/objectaddress.c:1903
#, c-format
msgid "default ACL for user \"%s\" in schema \"%s\" on %s does not exist"
msgstr "le droit par défaut pour l'utilisateur « % s» dans le schéma « %s » de %s n'existe pas"
-#: catalog/objectaddress.c:1846
+#: catalog/objectaddress.c:1908
#, c-format
msgid "default ACL for user \"%s\" on %s does not exist"
msgstr "le droit par défaut pour l'utilisateur « %s » sur %s n'existe pas"
-#: catalog/objectaddress.c:1873 catalog/objectaddress.c:1929 catalog/objectaddress.c:1984
+#: catalog/objectaddress.c:1935 catalog/objectaddress.c:1993 catalog/objectaddress.c:2048
#, c-format
msgid "name or argument lists may not contain nulls"
msgstr "le nom ou les listes d'arguments ne peuvent pas contenir de valeurs NULL"
-#: catalog/objectaddress.c:1905
+#: catalog/objectaddress.c:1969
#, c-format
msgid "unsupported object type \"%s\""
msgstr "type d'objet « %s » non supporté"
-#: catalog/objectaddress.c:1925 catalog/objectaddress.c:1943
+#: catalog/objectaddress.c:1989 catalog/objectaddress.c:2007 catalog/objectaddress.c:2145
#, c-format
msgid "name list length must be exactly %d"
msgstr "la liste de nom doit être exactement de longueur %d"
-#: catalog/objectaddress.c:1947
+#: catalog/objectaddress.c:2011
#, c-format
msgid "large object OID may not be null"
msgstr "l'OID du Large Object peut ne pas être NULL"
-#: catalog/objectaddress.c:1956 catalog/objectaddress.c:2016 catalog/objectaddress.c:2023
+#: catalog/objectaddress.c:2020 catalog/objectaddress.c:2081 catalog/objectaddress.c:2088
#, c-format
msgid "name list length must be at least %d"
msgstr "la longueur de la liste de nom doit au moins être %d"
-#: catalog/objectaddress.c:2009 catalog/objectaddress.c:2029
+#: catalog/objectaddress.c:2074 catalog/objectaddress.c:2094
#, c-format
msgid "argument list length must be exactly %d"
msgstr "la longueur de la liste d'arguments doit être %d exactement"
-#: catalog/objectaddress.c:2165 libpq/be-fsstubs.c:350
+#: catalog/objectaddress.c:2320 libpq/be-fsstubs.c:350
#, c-format
msgid "must be owner of large object %u"
msgstr "doit être le propriétaire du Large Object %u"
-#: catalog/objectaddress.c:2180 commands/functioncmds.c:1426
+#: catalog/objectaddress.c:2335 commands/functioncmds.c:1440
#, c-format
msgid "must be owner of type %s or type %s"
msgstr "doit être le propriétaire du type %s ou du type %s"
-#: catalog/objectaddress.c:2220 catalog/objectaddress.c:2237
+#: catalog/objectaddress.c:2385 catalog/objectaddress.c:2402
#, c-format
msgid "must be superuser"
msgstr "doit être super-utilisateur"
-#: catalog/objectaddress.c:2227
+#: catalog/objectaddress.c:2392
#, c-format
msgid "must have CREATEROLE privilege"
msgstr "doit avoir l'attribut CREATEROLE"
-#: catalog/objectaddress.c:2302
+#: catalog/objectaddress.c:2471
#, c-format
msgid "unrecognized object type \"%s\""
msgstr "type d'objet non reconnu « %s »"
-#: catalog/objectaddress.c:2497
+#: catalog/objectaddress.c:2666
#, c-format
msgid " column %s"
msgstr " colonne %s"
-#: catalog/objectaddress.c:2503
+#: catalog/objectaddress.c:2672
#, c-format
msgid "function %s"
msgstr "fonction %s"
-#: catalog/objectaddress.c:2508
+#: catalog/objectaddress.c:2677
#, c-format
msgid "type %s"
msgstr "type %s"
-#: catalog/objectaddress.c:2538
+#: catalog/objectaddress.c:2707
#, c-format
msgid "cast from %s to %s"
msgstr "conversion de %s en %s"
-#: catalog/objectaddress.c:2558
+#: catalog/objectaddress.c:2727
#, c-format
msgid "collation %s"
msgstr "collationnement %s"
-#: catalog/objectaddress.c:2582
+#: catalog/objectaddress.c:2751
#, c-format
msgid "constraint %s on %s"
msgstr "contrainte %s sur %s"
-#: catalog/objectaddress.c:2588
+#: catalog/objectaddress.c:2757
#, c-format
msgid "constraint %s"
msgstr "contrainte %s"
-#: catalog/objectaddress.c:2605
+#: catalog/objectaddress.c:2774
#, c-format
msgid "conversion %s"
msgstr "conversion %s"
-#: catalog/objectaddress.c:2642
+#: catalog/objectaddress.c:2811
#, c-format
msgid "default for %s"
msgstr "valeur par défaut pour %s"
-#: catalog/objectaddress.c:2651
+#: catalog/objectaddress.c:2820
#, c-format
msgid "language %s"
msgstr "langage %s"
-#: catalog/objectaddress.c:2656
+#: catalog/objectaddress.c:2825
#, c-format
msgid "large object %u"
msgstr "« Large Object » %u"
-#: catalog/objectaddress.c:2661
+#: catalog/objectaddress.c:2830
#, c-format
msgid "operator %s"
msgstr "opérateur %s"
-#: catalog/objectaddress.c:2693
+#: catalog/objectaddress.c:2862
#, c-format
msgid "operator class %s for access method %s"
msgstr "classe d'opérateur %s pour la méthode d'accès %s"
+#: catalog/objectaddress.c:2885
+#, c-format
+msgid "access method %s"
+msgstr "méthode d'accès %s"
+
#. translator: %d is the operator strategy (a number), the
#. first two %s's are data type names, the third %s is the
#. description of the operator family, and the last %s is the
#. textual form of the operator with arguments.
-#: catalog/objectaddress.c:2743
+#: catalog/objectaddress.c:2927
#, c-format
msgid "operator %d (%s, %s) of %s: %s"
msgstr "opérateur %d (%s, %s) de %s : %s"
@@ -4224,181 +4060,220 @@ msgstr "opérateur %d (%s, %s) de %s : %s"
#. are data type names, the third %s is the description of the
#. operator family, and the last %s is the textual form of the
#. function with arguments.
-#: catalog/objectaddress.c:2793
+#: catalog/objectaddress.c:2977
#, c-format
msgid "function %d (%s, %s) of %s: %s"
msgstr "fonction %d (%s, %s) de %s : %s"
-#: catalog/objectaddress.c:2833
+#: catalog/objectaddress.c:3017
#, c-format
msgid "rule %s on "
msgstr "règle %s active "
-#: catalog/objectaddress.c:2855
-#, c-format
-msgid "transform for %s language %s"
-msgstr "transformation pour %s langage %s"
-
-#: catalog/objectaddress.c:2889
+#: catalog/objectaddress.c:3052
#, c-format
msgid "trigger %s on "
msgstr "trigger %s actif "
-#: catalog/objectaddress.c:2906
+#: catalog/objectaddress.c:3069
#, c-format
msgid "schema %s"
msgstr "schéma %s"
-#: catalog/objectaddress.c:2919
+#: catalog/objectaddress.c:3086
+#, c-format
+msgid "statistics object %s"
+msgstr "objet statistique %s"
+
+#: catalog/objectaddress.c:3102
#, c-format
msgid "text search parser %s"
msgstr "analyseur %s de la recherche plein texte"
-#: catalog/objectaddress.c:2934
+#: catalog/objectaddress.c:3117
#, c-format
msgid "text search dictionary %s"
msgstr "dictionnaire %s de la recherche plein texte"
-#: catalog/objectaddress.c:2949
+#: catalog/objectaddress.c:3132
#, c-format
msgid "text search template %s"
msgstr "modèle %s de la recherche plein texte"
-#: catalog/objectaddress.c:2964
+#: catalog/objectaddress.c:3147
#, c-format
msgid "text search configuration %s"
msgstr "configuration %s de recherche plein texte"
-#: catalog/objectaddress.c:2972
+#: catalog/objectaddress.c:3155
#, c-format
msgid "role %s"
msgstr "rôle %s"
-#: catalog/objectaddress.c:2985
+#: catalog/objectaddress.c:3168
#, c-format
msgid "database %s"
msgstr "base de données %s"
-#: catalog/objectaddress.c:2997
+#: catalog/objectaddress.c:3180
#, c-format
msgid "tablespace %s"
msgstr "tablespace %s"
-#: catalog/objectaddress.c:3006
+#: catalog/objectaddress.c:3189
#, c-format
msgid "foreign-data wrapper %s"
msgstr "wrapper de données distantes %s"
-#: catalog/objectaddress.c:3015
+#: catalog/objectaddress.c:3198
#, c-format
msgid "server %s"
msgstr "serveur %s"
-#: catalog/objectaddress.c:3043
+#: catalog/objectaddress.c:3226
#, c-format
msgid "user mapping for %s on server %s"
msgstr "correspondance utilisateur pour %s sur le serveur %s"
-#: catalog/objectaddress.c:3078
+#: catalog/objectaddress.c:3261
#, c-format
msgid "default privileges on new relations belonging to role %s"
msgstr "droits par défaut pour les nouvelles relations appartenant au rôle %s"
-#: catalog/objectaddress.c:3083
+#: catalog/objectaddress.c:3266
#, c-format
msgid "default privileges on new sequences belonging to role %s"
msgstr "droits par défaut pour les nouvelles séquences appartenant au rôle %s"
-#: catalog/objectaddress.c:3088
+#: catalog/objectaddress.c:3271
#, c-format
msgid "default privileges on new functions belonging to role %s"
msgstr "droits par défaut pour les nouvelles fonctions appartenant au rôle %s"
-#: catalog/objectaddress.c:3093
+#: catalog/objectaddress.c:3276
#, c-format
msgid "default privileges on new types belonging to role %s"
msgstr "droits par défaut pour les nouveaux types appartenant au rôle %s"
-#: catalog/objectaddress.c:3099
+#: catalog/objectaddress.c:3281
+#, c-format
+msgid "default privileges on new schemas belonging to role %s"
+msgstr "droits par défaut pour les nouveaux schémas appartenant au rôle %s"
+
+#: catalog/objectaddress.c:3287
#, c-format
msgid "default privileges belonging to role %s"
msgstr "droits par défaut appartenant au rôle %s"
-#: catalog/objectaddress.c:3107
+#: catalog/objectaddress.c:3295
#, c-format
msgid " in schema %s"
msgstr " dans le schéma %s"
-#: catalog/objectaddress.c:3124
+#: catalog/objectaddress.c:3312
#, c-format
msgid "extension %s"
msgstr "extension %s"
-#: catalog/objectaddress.c:3137
+#: catalog/objectaddress.c:3325
#, c-format
msgid "event trigger %s"
msgstr "trigger sur événement %s"
-#: catalog/objectaddress.c:3169
+#: catalog/objectaddress.c:3357
#, c-format
msgid "policy %s on "
msgstr "politique %s sur "
-#: catalog/objectaddress.c:3187
+#: catalog/objectaddress.c:3368
#, c-format
-msgid "access method %s"
-msgstr "méthode d'accès %s"
+msgid "publication %s"
+msgstr "publication %s"
+
+#: catalog/objectaddress.c:3388
+#, c-format
+msgid "publication table %s in publication %s"
+msgstr "table de publication %s dans la publication %s"
+
+#: catalog/objectaddress.c:3396
+#, c-format
+msgid "subscription %s"
+msgstr "souscription %s"
+
+#: catalog/objectaddress.c:3414
+#, c-format
+msgid "transform for %s language %s"
+msgstr "transformation pour %s langage %s"
-#: catalog/objectaddress.c:3247
+#: catalog/objectaddress.c:3475
#, c-format
msgid "table %s"
msgstr "table %s"
-#: catalog/objectaddress.c:3251
+#: catalog/objectaddress.c:3479
#, c-format
msgid "index %s"
msgstr "index %s"
-#: catalog/objectaddress.c:3255
+#: catalog/objectaddress.c:3483
#, c-format
msgid "sequence %s"
msgstr "séquence %s"
-#: catalog/objectaddress.c:3259
+#: catalog/objectaddress.c:3487
#, c-format
msgid "toast table %s"
msgstr "table TOAST %s"
-#: catalog/objectaddress.c:3263
+#: catalog/objectaddress.c:3491
#, c-format
msgid "view %s"
msgstr "vue %s"
-#: catalog/objectaddress.c:3267
+#: catalog/objectaddress.c:3495
#, c-format
msgid "materialized view %s"
msgstr "vue matérialisée %s"
-#: catalog/objectaddress.c:3271
+#: catalog/objectaddress.c:3499
#, c-format
msgid "composite type %s"
msgstr "type composite %s"
-#: catalog/objectaddress.c:3275
+#: catalog/objectaddress.c:3503
#, c-format
msgid "foreign table %s"
msgstr "table distante %s"
-#: catalog/objectaddress.c:3280
+#: catalog/objectaddress.c:3508
#, c-format
msgid "relation %s"
msgstr "relation %s"
-#: catalog/objectaddress.c:3317
+#: catalog/objectaddress.c:3545
#, c-format
msgid "operator family %s for access method %s"
msgstr "famille d'opérateur %s pour la méthode d'accès %s"
+#: catalog/objectaddress.c:4914
+#, c-format
+msgid "%s in publication %s"
+msgstr "%s dans la publication %s"
+
+#: catalog/partition.c:727
+#, c-format
+msgid "cannot create range partition with empty range"
+msgstr "ne peut pas créer une partition par intervalle avec un intervalle vide"
+
+#: catalog/partition.c:808
+#, c-format
+msgid "partition \"%s\" would overlap partition \"%s\""
+msgstr "la partition « %s » surchargerait la partition « %s »"
+
+#: catalog/partition.c:921 catalog/partition.c:1099 commands/analyze.c:1446 commands/copy.c:1467 commands/tablecmds.c:8872 executor/execExprInterp.c:2853 executor/execMain.c:1878 executor/execMain.c:1956 executor/execMain.c:2004 executor/execMain.c:2114 executor/execMain.c:3294 executor/nodeModifyTable.c:1518
+msgid "could not convert row type"
+msgstr "n'a pas pu convertir le type de ligne"
+
#: catalog/pg_aggregate.c:125
#, c-format
msgid "aggregates cannot have more than %d argument"
@@ -4446,7 +4321,7 @@ msgstr ""
msgid "return type of inverse transition function %s is not %s"
msgstr "le type de retour de la fonction de transition inverse %s n'est pas %s"
-#: catalog/pg_aggregate.c:351 executor/nodeWindowAgg.c:2334
+#: catalog/pg_aggregate.c:351 executor/nodeWindowAgg.c:2298
#, c-format
msgid "strictness of aggregate's forward and inverse transition functions must match"
msgstr "la fonction de transition d'agrégat en déplacement ne doit pas renvoyer null"
@@ -4462,8 +4337,9 @@ msgid "return type of combine function %s is not %s"
msgstr "le type de retour de la fonction de d'unification %s n'est pas %s"
#: catalog/pg_aggregate.c:436
-#, c-format
-msgid "combine function with \"%s\" transition type must not be declared STRICT"
+#, fuzzy, c-format
+#| msgid "combine function with \"%s\" transition type must not be declared STRICT"
+msgid "combine function with transition type %s must not be declared STRICT"
msgstr "la fonction d'unification avec le type de transaction «%s » ne doit pas être déclaré STRICT"
#: catalog/pg_aggregate.c:455
@@ -4476,7 +4352,7 @@ msgstr "le type de retour de la fonction de sérialisation %s n'est pas %s"
msgid "return type of deserialization function %s is not %s"
msgstr "le type de retour de la fonction de désérialisation %s n'est pas %s"
-#: catalog/pg_aggregate.c:491 catalog/pg_proc.c:246 catalog/pg_proc.c:253
+#: catalog/pg_aggregate.c:491 catalog/pg_proc.c:243 catalog/pg_proc.c:250
#, c-format
msgid "cannot determine result data type"
msgstr "n'a pas pu déterminer le type de données en résultat"
@@ -4488,12 +4364,12 @@ msgstr ""
"Un agrégat renvoyant un type polymorphique doit avoir au moins un argument\n"
"de type polymorphique."
-#: catalog/pg_aggregate.c:504 catalog/pg_proc.c:259
+#: catalog/pg_aggregate.c:504 catalog/pg_proc.c:256
#, c-format
msgid "unsafe use of pseudo-type \"internal\""
msgstr "utilisation non sûre des pseudo-types « INTERNAL »"
-#: catalog/pg_aggregate.c:505 catalog/pg_proc.c:260
+#: catalog/pg_aggregate.c:505 catalog/pg_proc.c:257
#, c-format
msgid "A function returning \"internal\" must have at least one \"internal\" argument."
msgstr ""
@@ -4510,60 +4386,70 @@ msgstr "l'impémentation d'aggrégat glissant retourne le type %s, mais l'implé
msgid "sort operator can only be specified for single-argument aggregates"
msgstr "l'opérateur de tri peut seulement être indiqué pour des agrégats à un seul argument"
-#: catalog/pg_aggregate.c:812 commands/typecmds.c:1705 commands/typecmds.c:1756 commands/typecmds.c:1787 commands/typecmds.c:1810 commands/typecmds.c:1831 commands/typecmds.c:1858 commands/typecmds.c:1885 commands/typecmds.c:1962 commands/typecmds.c:2004 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:1923
+#: catalog/pg_aggregate.c:810 commands/typecmds.c:1698 commands/typecmds.c:1749 commands/typecmds.c:1780 commands/typecmds.c:1803 commands/typecmds.c:1824 commands/typecmds.c:1851 commands/typecmds.c:1878 commands/typecmds.c:1955 commands/typecmds.c:1997 parser/parse_func.c:369 parser/parse_func.c:398 parser/parse_func.c:423 parser/parse_func.c:437 parser/parse_func.c:512 parser/parse_func.c:523 parser/parse_func.c:1977
#, c-format
msgid "function %s does not exist"
msgstr "la fonction %s n'existe pas"
-#: catalog/pg_aggregate.c:818
+#: catalog/pg_aggregate.c:816
#, c-format
msgid "function %s returns a set"
msgstr "la fonction %s renvoie un ensemble"
-#: catalog/pg_aggregate.c:833
+#: catalog/pg_aggregate.c:831
#, c-format
msgid "function %s must accept VARIADIC ANY to be used in this aggregate"
msgstr "la fonction %s doit accepter VARIADIC ANY pour être utilisé dans cet agrégat"
-#: catalog/pg_aggregate.c:857
+#: catalog/pg_aggregate.c:855
#, c-format
msgid "function %s requires run-time type coercion"
msgstr "la fonction %s requiert une coercion sur le type à l'exécution"
-#: catalog/pg_collation.c:77
+#: catalog/pg_collation.c:93 catalog/pg_collation.c:140
#, c-format
-msgid "collation \"%s\" for encoding \"%s\" already exists"
-msgstr "le collationnement « %s » pour l'encodage « %s » existe déjà"
+msgid "collation \"%s\" already exists, skipping"
+msgstr "le collationnement « %s » existe déjà, poursuite du traitement"
-#: catalog/pg_collation.c:91
+#: catalog/pg_collation.c:95
+#, c-format
+msgid "collation \"%s\" for encoding \"%s\" already exists, skipping"
+msgstr "le collationnement « %s » pour l'encodage « %s » existe déjà, poursuite du traitement"
+
+#: catalog/pg_collation.c:103 catalog/pg_collation.c:147
#, c-format
msgid "collation \"%s\" already exists"
msgstr "le collationnement « %s » existe déjà"
-#: catalog/pg_constraint.c:663
+#: catalog/pg_collation.c:105
+#, c-format
+msgid "collation \"%s\" for encoding \"%s\" already exists"
+msgstr "le collationnement « %s » pour l'encodage « %s » existe déjà"
+
+#: catalog/pg_constraint.c:658
#, c-format
msgid "constraint \"%s\" for domain %s already exists"
msgstr "la contrainte « %s » du domaine %s existe déjà"
-#: catalog/pg_constraint.c:797
+#: catalog/pg_constraint.c:788
#, c-format
msgid "table \"%s\" has multiple constraints named \"%s\""
msgstr "la table « %s » a de nombreuses contraintes nommées « %s »"
-#: catalog/pg_constraint.c:809
+#: catalog/pg_constraint.c:800
#, c-format
msgid "constraint \"%s\" for table \"%s\" does not exist"
msgstr "la contrainte « %s » de la table « %s » n'existe pas"
-#: catalog/pg_constraint.c:855
+#: catalog/pg_constraint.c:846
#, c-format
-msgid "domain \"%s\" has multiple constraints named \"%s\""
-msgstr "le domaine « %s » a plusieurs contraintes nommées « %s »"
+msgid "domain %s has multiple constraints named \"%s\""
+msgstr "le domaine %s a plusieurs contraintes nommées « %s »"
-#: catalog/pg_constraint.c:867
+#: catalog/pg_constraint.c:858
#, c-format
-msgid "constraint \"%s\" for domain \"%s\" does not exist"
-msgstr "la contrainte « %s » du domaine « %s » n'existe pas"
+msgid "constraint \"%s\" for domain %s does not exist"
+msgstr "la contrainte « %s » du domaine %s n'existe pas"
#: catalog/pg_conversion.c:66
#, c-format
@@ -4575,220 +4461,270 @@ msgstr "la conversion « %s » existe déjà"
msgid "default conversion for %s to %s already exists"
msgstr "la conversion par défaut de %s vers %s existe déjà"
-#: catalog/pg_depend.c:165 commands/extension.c:3029
+#: catalog/pg_depend.c:163 commands/extension.c:3218
#, c-format
msgid "%s is already a member of extension \"%s\""
msgstr "%s est déjà un membre de l'extension « %s »"
-#: catalog/pg_depend.c:324
+#: catalog/pg_depend.c:322
#, c-format
msgid "cannot remove dependency on %s because it is a system object"
msgstr "ne peut pas supprimer la dépendance sur %s car il s'agit d'un objet système"
-#: catalog/pg_enum.c:115 catalog/pg_enum.c:202
+#: catalog/pg_enum.c:115 catalog/pg_enum.c:201 catalog/pg_enum.c:488
#, c-format
msgid "invalid enum label \"%s\""
msgstr "nom du label enum « %s » invalide"
-#: catalog/pg_enum.c:116 catalog/pg_enum.c:203
+#: catalog/pg_enum.c:116 catalog/pg_enum.c:202 catalog/pg_enum.c:489
#, c-format
msgid "Labels must be %d characters or less."
msgstr "Les labels doivent avoir au plus %d caractères"
-#: catalog/pg_enum.c:231
+#: catalog/pg_enum.c:230
#, c-format
msgid "enum label \"%s\" already exists, skipping"
msgstr "le label « %s » existe déjà, poursuite du traitement"
-#: catalog/pg_enum.c:238
+#: catalog/pg_enum.c:237 catalog/pg_enum.c:532
#, c-format
msgid "enum label \"%s\" already exists"
msgstr "le label « %s » existe déjà"
-#: catalog/pg_enum.c:293
+#: catalog/pg_enum.c:292 catalog/pg_enum.c:527
#, c-format
msgid "\"%s\" is not an existing enum label"
msgstr "« %s » n'est pas un label enum existant"
-#: catalog/pg_enum.c:349
+#: catalog/pg_enum.c:350
#, c-format
msgid "pg_enum OID value not set when in binary upgrade mode"
msgstr "OID de pg_enum non configuré en mode de mise à jour binaire"
-#: catalog/pg_enum.c:359
+#: catalog/pg_enum.c:360
#, c-format
msgid "ALTER TYPE ADD BEFORE/AFTER is incompatible with binary upgrade"
msgstr "ALTER TYPE ADD BEFORE/AFTER est incompatible avec la mise à jour binaire"
-#: catalog/pg_namespace.c:61 commands/schemacmds.c:246
+#: catalog/pg_namespace.c:63 commands/schemacmds.c:264
#, c-format
msgid "schema \"%s\" already exists"
msgstr "le schéma « %s » existe déjà"
-#: catalog/pg_operator.c:219 catalog/pg_operator.c:360
+#: catalog/pg_operator.c:219 catalog/pg_operator.c:358
#, c-format
msgid "\"%s\" is not a valid operator name"
msgstr "« %s » n'est pas un nom d'opérateur valide"
-#: catalog/pg_operator.c:369
+#: catalog/pg_operator.c:367
#, c-format
msgid "only binary operators can have commutators"
msgstr "seuls les opérateurs binaires peuvent avoir des commutateurs"
-#: catalog/pg_operator.c:373 commands/operatorcmds.c:485
+#: catalog/pg_operator.c:371 commands/operatorcmds.c:482
#, c-format
msgid "only binary operators can have join selectivity"
msgstr "seuls les opérateurs binaires peuvent avoir une sélectivité des jointures"
-#: catalog/pg_operator.c:377
+#: catalog/pg_operator.c:375
#, c-format
msgid "only binary operators can merge join"
msgstr "seuls les opérateurs binaires peuvent exécuter des jointures MERGE"
-#: catalog/pg_operator.c:381
+#: catalog/pg_operator.c:379
#, c-format
msgid "only binary operators can hash"
msgstr "seuls les opérateurs binaires ont du hachage"
-#: catalog/pg_operator.c:392
+#: catalog/pg_operator.c:390
#, c-format
msgid "only boolean operators can have negators"
msgstr "seuls les opérateurs booléens peuvent avoir des négations"
-#: catalog/pg_operator.c:396 commands/operatorcmds.c:493
+#: catalog/pg_operator.c:394 commands/operatorcmds.c:490
#, c-format
msgid "only boolean operators can have restriction selectivity"
msgstr "seuls les opérateurs booléens peuvent avoir une sélectivité des restrictions"
-#: catalog/pg_operator.c:400 commands/operatorcmds.c:497
+#: catalog/pg_operator.c:398 commands/operatorcmds.c:494
#, c-format
msgid "only boolean operators can have join selectivity"
msgstr "seuls les opérateurs booléens peuvent avoir une sélectivité des jointures"
-#: catalog/pg_operator.c:404
+#: catalog/pg_operator.c:402
#, c-format
msgid "only boolean operators can merge join"
msgstr "seuls les opérateurs booléens peuvent exécuter des jointures MERGE"
-#: catalog/pg_operator.c:408
+#: catalog/pg_operator.c:406
#, c-format
msgid "only boolean operators can hash"
msgstr "seuls les opérateurs booléens peuvent hacher"
-#: catalog/pg_operator.c:420
+#: catalog/pg_operator.c:418
#, c-format
msgid "operator %s already exists"
msgstr "l'opérateur %s existe déjà"
-#: catalog/pg_operator.c:617
+#: catalog/pg_operator.c:612
#, c-format
msgid "operator cannot be its own negator or sort operator"
msgstr "l'opérateur ne peut pas être son propre opérateur de négation ou de tri"
-#: catalog/pg_proc.c:134 parser/parse_func.c:1947 parser/parse_func.c:1987
+#: catalog/pg_proc.c:131 parser/parse_func.c:2001 parser/parse_func.c:2041
#, c-format
msgid "functions cannot have more than %d argument"
msgid_plural "functions cannot have more than %d arguments"
msgstr[0] "les fonctions ne peuvent avoir plus de %d argument"
msgstr[1] "les fonctions ne peuvent avoir plus de %d arguments"
-#: catalog/pg_proc.c:247
+#: catalog/pg_proc.c:244
#, c-format
msgid "A function returning a polymorphic type must have at least one polymorphic argument."
msgstr ""
"Une fonction renvoyant un type polymorphique doit avoir au moins un argument\n"
"de type polymorphique."
-#: catalog/pg_proc.c:254
+#: catalog/pg_proc.c:251
#, c-format
msgid "A function returning \"anyrange\" must have at least one \"anyrange\" argument."
msgstr "Une fonction renvoyant « anyrange » doit avoir au moins un argument du type « anyrange »."
-#: catalog/pg_proc.c:272
+#: catalog/pg_proc.c:269
#, c-format
msgid "\"%s\" is already an attribute of type %s"
msgstr "« %s » est déjà un attribut du type %s"
-#: catalog/pg_proc.c:403
+#: catalog/pg_proc.c:400
#, c-format
msgid "function \"%s\" already exists with same argument types"
msgstr "la fonction « %s » existe déjà avec des types d'arguments identiques"
-#: catalog/pg_proc.c:417 catalog/pg_proc.c:440
+#: catalog/pg_proc.c:414 catalog/pg_proc.c:437
#, c-format
msgid "cannot change return type of existing function"
msgstr "ne peut pas modifier le type de retour d'une fonction existante"
-#: catalog/pg_proc.c:418 catalog/pg_proc.c:442 catalog/pg_proc.c:485 catalog/pg_proc.c:509 catalog/pg_proc.c:536
+#: catalog/pg_proc.c:415 catalog/pg_proc.c:439 catalog/pg_proc.c:482 catalog/pg_proc.c:506 catalog/pg_proc.c:532
#, c-format
msgid "Use DROP FUNCTION %s first."
msgstr "Utilisez tout d'abord DROP FUNCTION %s."
-#: catalog/pg_proc.c:441
+#: catalog/pg_proc.c:438
#, c-format
msgid "Row type defined by OUT parameters is different."
msgstr "Le type de ligne défini par les paramètres OUT est différent."
-#: catalog/pg_proc.c:483
+#: catalog/pg_proc.c:480
#, c-format
msgid "cannot change name of input parameter \"%s\""
msgstr "ne peut pas modifier le nom du paramètre en entrée « %s »"
-#: catalog/pg_proc.c:508
+#: catalog/pg_proc.c:505
#, c-format
msgid "cannot remove parameter defaults from existing function"
msgstr ""
"ne peut pas supprimer les valeurs par défaut des paramètres de la\n"
"fonction existante"
-#: catalog/pg_proc.c:535
+#: catalog/pg_proc.c:531
#, c-format
msgid "cannot change data type of existing parameter default value"
msgstr ""
"ne peut pas modifier le type de données d'un paramètre avec une valeur\n"
"par défaut"
-#: catalog/pg_proc.c:548
+#: catalog/pg_proc.c:544
#, c-format
msgid "function \"%s\" is an aggregate function"
msgstr "la fonction « %s » est une fonction d'agrégat"
-#: catalog/pg_proc.c:553
+#: catalog/pg_proc.c:549
#, c-format
msgid "function \"%s\" is not an aggregate function"
msgstr "la fonction « %s » n'est pas une fonction d'agrégat"
-#: catalog/pg_proc.c:561
+#: catalog/pg_proc.c:557
#, c-format
msgid "function \"%s\" is a window function"
msgstr "la fonction « %s » est une fonction window"
-#: catalog/pg_proc.c:566
+#: catalog/pg_proc.c:562
#, c-format
msgid "function \"%s\" is not a window function"
msgstr "la fonction « %s » n'est pas une fonction window"
-#: catalog/pg_proc.c:774
+#: catalog/pg_proc.c:768
#, c-format
msgid "there is no built-in function named \"%s\""
msgstr "il n'existe pas de fonction intégrée nommée « %s »"
-#: catalog/pg_proc.c:872
+#: catalog/pg_proc.c:866
#, c-format
msgid "SQL functions cannot return type %s"
msgstr "les fonctions SQL ne peuvent pas renvoyer un type %s"
-#: catalog/pg_proc.c:887
+#: catalog/pg_proc.c:881
#, c-format
msgid "SQL functions cannot have arguments of type %s"
msgstr "les fonctions SQL ne peuvent avoir d'arguments du type %s"
-#: catalog/pg_proc.c:973 executor/functions.c:1431
+#: catalog/pg_proc.c:968 executor/functions.c:1429
#, c-format
msgid "SQL function \"%s\""
msgstr "Fonction SQL « %s »"
-#: catalog/pg_shdepend.c:694
+#: catalog/pg_publication.c:57 commands/trigger.c:196
+#, c-format
+msgid "\"%s\" is a partitioned table"
+msgstr "« %s » est une table partitionnée"
+
+#: catalog/pg_publication.c:59
+#, c-format
+msgid "Adding partitioned tables to publications is not supported."
+msgstr "Ajouter des tables partitionnées à des publications n'est pas supporté."
+
+#: catalog/pg_publication.c:60
+#, c-format
+msgid "You can add the table partitions individually."
+msgstr "Vous pouvez ajouter les partitions de table individuellement."
+
+#: catalog/pg_publication.c:68
+#, c-format
+msgid "Only tables can be added to publications."
+msgstr "Seules des tables peuvent être ajoutées aux publications."
+
+#: catalog/pg_publication.c:74
+#, c-format
+msgid "\"%s\" is a system table"
+msgstr "« %s » est une table système"
+
+#: catalog/pg_publication.c:76
+#, c-format
+msgid "System tables cannot be added to publications."
+msgstr "Les tables systèmes ne peuvent pas être ajoutées à une publication."
+
+#: catalog/pg_publication.c:82
+#, c-format
+msgid "table \"%s\" cannot be replicated"
+msgstr "la table « %s » ne peut pas être répliquée"
+
+#: catalog/pg_publication.c:84
+#, c-format
+msgid "Temporary and unlogged relations cannot be replicated."
+msgstr "Les tables tremporaires et les tables non journalisées ne peuvent pas être répliquées."
+
+#: catalog/pg_publication.c:166
+#, c-format
+msgid "relation \"%s\" is already member of publication \"%s\""
+msgstr "la relation « %s » est déjà un membre de la publication « %s »"
+
+#: catalog/pg_publication.c:393 catalog/pg_publication.c:414 commands/publicationcmds.c:401 commands/publicationcmds.c:702
+#, c-format
+msgid "publication \"%s\" does not exist"
+msgstr "la publication « %s » n'existe pas"
+
+#: catalog/pg_shdepend.c:692
#, c-format
msgid ""
"\n"
@@ -4805,94 +4741,99 @@ msgstr[1] ""
"et des objets dans %d autres bases de données (voir le journal applicatif du\n"
"serveur pour une liste)"
-#: catalog/pg_shdepend.c:1006
+#: catalog/pg_shdepend.c:998
#, c-format
msgid "role %u was concurrently dropped"
msgstr "le rôle %u a été supprimé simultanément"
-#: catalog/pg_shdepend.c:1025
+#: catalog/pg_shdepend.c:1017
#, c-format
msgid "tablespace %u was concurrently dropped"
msgstr "le tablespace %u a été supprimé simultanément"
-#: catalog/pg_shdepend.c:1040
+#: catalog/pg_shdepend.c:1032
#, c-format
msgid "database %u was concurrently dropped"
msgstr "la base de données %u a été supprimé simultanément"
-#: catalog/pg_shdepend.c:1085
+#: catalog/pg_shdepend.c:1077
#, c-format
msgid "owner of %s"
msgstr "propriétaire de %s"
-#: catalog/pg_shdepend.c:1087
+#: catalog/pg_shdepend.c:1079
#, c-format
msgid "privileges for %s"
msgstr "droits pour « %s »"
-#: catalog/pg_shdepend.c:1089
+#: catalog/pg_shdepend.c:1081
#, c-format
msgid "target of %s"
msgstr "cible de %s"
#. translator: %s will always be "database %s"
-#: catalog/pg_shdepend.c:1097
+#: catalog/pg_shdepend.c:1089
#, c-format
msgid "%d object in %s"
msgid_plural "%d objects in %s"
msgstr[0] "%d objet dans %s"
msgstr[1] "%d objets dans %s"
-#: catalog/pg_shdepend.c:1208
+#: catalog/pg_shdepend.c:1200
#, c-format
msgid "cannot drop objects owned by %s because they are required by the database system"
msgstr ""
"n'a pas pu supprimer les objets appartenant à %s car ils sont nécessaires au\n"
"système de bases de données"
-#: catalog/pg_shdepend.c:1323
+#: catalog/pg_shdepend.c:1315
#, c-format
msgid "cannot reassign ownership of objects owned by %s because they are required by the database system"
msgstr ""
"ne peut pas réaffecter les objets appartenant à %s car ils sont nécessaires au\n"
"système de bases de données"
-#: catalog/pg_type.c:136 catalog/pg_type.c:454
+#: catalog/pg_subscription.c:176 commands/subscriptioncmds.c:636 commands/subscriptioncmds.c:844 commands/subscriptioncmds.c:1044
+#, c-format
+msgid "subscription \"%s\" does not exist"
+msgstr "la souscription « %s » n'existe pas"
+
+#: catalog/pg_type.c:136 catalog/pg_type.c:452
#, c-format
msgid "pg_type OID value not set when in binary upgrade mode"
msgstr "OID de pg_type non configuré en mode de mise à jour binaire"
-#: catalog/pg_type.c:253
+#: catalog/pg_type.c:251
#, c-format
msgid "invalid type internal size %d"
msgstr "taille interne de type invalide %d"
-#: catalog/pg_type.c:269 catalog/pg_type.c:277 catalog/pg_type.c:285 catalog/pg_type.c:294
+#: catalog/pg_type.c:267 catalog/pg_type.c:275 catalog/pg_type.c:283 catalog/pg_type.c:292
#, c-format
msgid "alignment \"%c\" is invalid for passed-by-value type of size %d"
msgstr "l'alignement « %c » est invalide pour le type passé par valeur de taille %d"
-#: catalog/pg_type.c:301
+#: catalog/pg_type.c:299
#, c-format
msgid "internal size %d is invalid for passed-by-value type"
msgstr "la taille interne %d est invalide pour le type passé par valeur"
-#: catalog/pg_type.c:310 catalog/pg_type.c:316
+#: catalog/pg_type.c:308 catalog/pg_type.c:314
#, c-format
msgid "alignment \"%c\" is invalid for variable-length type"
msgstr "l'alignement « %c » est invalide pour le type de longueur variable"
-#: catalog/pg_type.c:324
+#: catalog/pg_type.c:322
#, c-format
msgid "fixed-size types must have storage PLAIN"
msgstr "les types de taille fixe doivent avoir un stockage de base"
-#: catalog/pg_type.c:789
+#: catalog/pg_type.c:801
#, c-format
msgid "could not form array type name for type \"%s\""
msgstr "n'a pas pu former le nom du type array pour le type de données %s"
-#: catalog/toasting.c:105 commands/indexcmds.c:389 commands/tablecmds.c:4359 commands/tablecmds.c:12047
+#: catalog/toasting.c:105 commands/indexcmds.c:399 commands/tablecmds.c:4734 commands/tablecmds.c:12973
#, c-format
msgid "\"%s\" is not a table or materialized view"
msgstr "« %s » n'est pas une table ou une vue matérialisée"
@@ -4904,142 +4845,157 @@ msgstr ""
"les tables partagées ne peuvent pas avoir une table TOAST après la commande\n"
"initdb"
-#: commands/aggregatecmds.c:159
+#: commands/aggregatecmds.c:157
#, c-format
msgid "only ordered-set aggregates can be hypothetical"
msgstr "seuls les agrégats à ensemble ordonné peuvent être hypothétiques"
-#: commands/aggregatecmds.c:184
+#: commands/aggregatecmds.c:182
#, c-format
msgid "aggregate attribute \"%s\" not recognized"
msgstr "l'attribut de l'agrégat « %s » n'est pas reconnu"
-#: commands/aggregatecmds.c:194
+#: commands/aggregatecmds.c:192
#, c-format
msgid "aggregate stype must be specified"
msgstr "le type source de l'agrégat doit être spécifié"
-#: commands/aggregatecmds.c:198
+#: commands/aggregatecmds.c:196
#, c-format
msgid "aggregate sfunc must be specified"
msgstr "la fonction source de l'agrégat doit être spécifiée"
-#: commands/aggregatecmds.c:210
+#: commands/aggregatecmds.c:208
#, c-format
msgid "aggregate msfunc must be specified when mstype is specified"
msgstr "la fonction msfunc de l'agrégat doit être spécifiée quand mstype est spécifié"
-#: commands/aggregatecmds.c:214
+#: commands/aggregatecmds.c:212
#, c-format
msgid "aggregate minvfunc must be specified when mstype is specified"
msgstr "la fonction minvfunc de l'agrégat doit être spécifiée quand mstype est spécifié"
-#: commands/aggregatecmds.c:221
+#: commands/aggregatecmds.c:219
#, c-format
msgid "aggregate msfunc must not be specified without mstype"
msgstr "la fonction msfunc de l'agrégat ne doit pas être spécifiée sans mstype"
-#: commands/aggregatecmds.c:225
+#: commands/aggregatecmds.c:223
#, c-format
msgid "aggregate minvfunc must not be specified without mstype"
msgstr "la fonction minvfunc de l'agrégat ne doit pas être spécifiée sans mstype"
-#: commands/aggregatecmds.c:229
+#: commands/aggregatecmds.c:227
#, c-format
msgid "aggregate mfinalfunc must not be specified without mstype"
msgstr "la fonction mfinalfunc de l'agrégat ne doit pas être spécifiée sans mstype"
-#: commands/aggregatecmds.c:233
+#: commands/aggregatecmds.c:231
#, c-format
msgid "aggregate msspace must not be specified without mstype"
msgstr "la fonction msspace de l'agrégat ne doit pas être spécifiée sans mstype"
-#: commands/aggregatecmds.c:237
+#: commands/aggregatecmds.c:235
#, c-format
msgid "aggregate minitcond must not be specified without mstype"
msgstr "la fonction minitcond de l'agrégat ne doit pas être spécifiée sans mstype"
-#: commands/aggregatecmds.c:257
+#: commands/aggregatecmds.c:255
#, c-format
msgid "aggregate input type must be specified"
msgstr "le type de saisie de l'agrégat doit être précisé"
-#: commands/aggregatecmds.c:287
+#: commands/aggregatecmds.c:285
#, c-format
msgid "basetype is redundant with aggregate input type specification"
msgstr "le type de base est redondant avec la spécification du type en entrée de l'agrégat"
-#: commands/aggregatecmds.c:328 commands/aggregatecmds.c:369
+#: commands/aggregatecmds.c:326 commands/aggregatecmds.c:367
#, c-format
msgid "aggregate transition data type cannot be %s"
msgstr "Le type de données de transition de l'agrégat ne peut pas être %s"
-#: commands/aggregatecmds.c:340
+#: commands/aggregatecmds.c:338
#, c-format
msgid "serialization functions may be specified only when the aggregate transition data type is %s"
msgstr "les fonctions de sérialisation ne peuvent être spécifiées que quand le type de données des transitions d'aggrégat est %s"
-#: commands/aggregatecmds.c:350
+#: commands/aggregatecmds.c:348
#, c-format
msgid "must specify both or neither of serialization and deserialization functions"
msgstr "doit spécifier soit toutes soit aucunes des fonctions de sérialisation et désérialisation"
-#: commands/aggregatecmds.c:415 commands/functioncmds.c:570
+#: commands/aggregatecmds.c:413 commands/functioncmds.c:564
#, c-format
msgid "parameter \"parallel\" must be SAFE, RESTRICTED, or UNSAFE"
msgstr "le paramètre « parallel » doit être SAFE, RESTRICTED ou UNSAFE"
-#: commands/alter.c:80 commands/event_trigger.c:231
+#: commands/alter.c:84 commands/event_trigger.c:234
#, c-format
msgid "event trigger \"%s\" already exists"
msgstr "le trigger sur événement « %s » existe déjà"
-#: commands/alter.c:83 commands/foreigncmds.c:597
+#: commands/alter.c:87 commands/foreigncmds.c:595
#, c-format
msgid "foreign-data wrapper \"%s\" already exists"
msgstr "le wrapper de données distantes « %s » existe déjà"
-#: commands/alter.c:86 commands/foreigncmds.c:890
+#: commands/alter.c:90 commands/foreigncmds.c:898
#, c-format
msgid "server \"%s\" already exists"
msgstr "le serveur « %s » existe déjà"
-#: commands/alter.c:89 commands/proclang.c:366
+#: commands/alter.c:93 commands/proclang.c:367
#, c-format
msgid "language \"%s\" already exists"
msgstr "le langage « %s » existe déjà"
-#: commands/alter.c:112
+#: commands/alter.c:96 commands/publicationcmds.c:170
+#, c-format
+msgid "publication \"%s\" already exists"
+msgstr "la publication « %s » existe déjà"
+
+#: commands/alter.c:99 commands/subscriptioncmds.c:358
+#, c-format
+msgid "subscription \"%s\" already exists"
+msgstr "la souscription « %s » existe déjà"
+
+#: commands/alter.c:122
#, c-format
msgid "conversion \"%s\" already exists in schema \"%s\""
msgstr "la conversion « %s » existe déjà dans le schéma « %s »"
-#: commands/alter.c:116
+#: commands/alter.c:126
+#, c-format
+msgid "statistics object \"%s\" already exists in schema \"%s\""
+msgstr "l'objet statistique « %s » existe déjà dans le schéma « %s »"
+
+#: commands/alter.c:130
#, c-format
msgid "text search parser \"%s\" already exists in schema \"%s\""
msgstr "l'analyseur de recherche plein texte « %s » existe déjà dans le schéma « %s »"
-#: commands/alter.c:120
+#: commands/alter.c:134
#, c-format
msgid "text search dictionary \"%s\" already exists in schema \"%s\""
msgstr "le dictionnaire de recherche plein texte « %s » existe déjà dans le schéma « %s »"
-#: commands/alter.c:124
+#: commands/alter.c:138
#, c-format
msgid "text search template \"%s\" already exists in schema \"%s\""
msgstr "le modèle de recherche plein texte « %s » existe déjà dans le schéma « %s »"
-#: commands/alter.c:128
+#: commands/alter.c:142
#, c-format
msgid "text search configuration \"%s\" already exists in schema \"%s\""
msgstr "la configuration de recherche plein texte « %s » existe déjà dans le schéma « %s »"
-#: commands/alter.c:202
+#: commands/alter.c:216
#, c-format
msgid "must be superuser to rename %s"
msgstr "doit être super-utilisateur pour renommer « %s »"
-#: commands/alter.c:655
+#: commands/alter.c:709
#, c-format
msgid "must be superuser to set schema of %s"
msgstr "doit être super-utilisateur pour configurer le schéma de %s"
@@ -5059,76 +5015,76 @@ msgstr "Doit être super-utilisateur pour créer une méthode d'accès."
msgid "access method \"%s\" already exists"
msgstr "la méthode d'accès « %s » existe déjà"
-#: commands/amcmds.c:124
+#: commands/amcmds.c:123
#, c-format
msgid "must be superuser to drop access methods"
msgstr "doit être super-utilisateur pour supprimer des méthodes d'accès"
-#: commands/amcmds.c:175 commands/indexcmds.c:164 commands/indexcmds.c:495 commands/opclasscmds.c:365 commands/opclasscmds.c:790
+#: commands/amcmds.c:174 commands/indexcmds.c:163 commands/indexcmds.c:515 commands/opclasscmds.c:363 commands/opclasscmds.c:777
#, c-format
msgid "access method \"%s\" does not exist"
msgstr "la méthode d'accès « %s » n'existe pas"
-#: commands/amcmds.c:251
+#: commands/amcmds.c:250
#, c-format
msgid "handler function is not specified"
msgstr "la fonction handler n'est pas spécifiée"
-#: commands/amcmds.c:263 commands/event_trigger.c:240 commands/foreigncmds.c:489 commands/proclang.c:117 commands/proclang.c:288 commands/trigger.c:441 parser/parse_clause.c:761
+#: commands/amcmds.c:262 commands/event_trigger.c:243 commands/foreigncmds.c:487 commands/proclang.c:117 commands/proclang.c:289 commands/trigger.c:590 parser/parse_clause.c:1011
#, c-format
msgid "function %s must return type %s"
msgstr "la fonction %s doit renvoyer le type %s"
-#: commands/analyze.c:145
+#: commands/analyze.c:151
#, c-format
msgid "skipping analyze of \"%s\" --- lock not available"
msgstr "ignore l'analyse de « %s » --- verrou non disponible"
-#: commands/analyze.c:162
+#: commands/analyze.c:168
#, c-format
msgid "skipping \"%s\" --- only superuser can analyze it"
msgstr "ignore « %s » --- seul le super-utilisateur peut l'analyser"
-#: commands/analyze.c:166
+#: commands/analyze.c:172
#, c-format
msgid "skipping \"%s\" --- only superuser or database owner can analyze it"
msgstr ""
"ignore « %s » --- seul le super-utilisateur ou le propriétaire de la base de\n"
"données peut l'analyser"
-#: commands/analyze.c:170
+#: commands/analyze.c:176
#, c-format
msgid "skipping \"%s\" --- only table or database owner can analyze it"
msgstr ""
"ignore « %s » --- seul le propriétaire de la table ou de la base de données\n"
"peut l'analyser"
-#: commands/analyze.c:230
+#: commands/analyze.c:236
#, c-format
msgid "skipping \"%s\" --- cannot analyze this foreign table"
msgstr "ignore « %s » --- ne peut pas analyser cette table distante"
-#: commands/analyze.c:241
+#: commands/analyze.c:253
#, c-format
msgid "skipping \"%s\" --- cannot analyze non-tables or special system tables"
msgstr "ignore « %s » --- ne peut pas analyser les objets autres que les tables et les tables système"
-#: commands/analyze.c:320
+#: commands/analyze.c:334
#, c-format
msgid "analyzing \"%s.%s\" inheritance tree"
msgstr "analyse l'arbre d'héritage « %s.%s »"
-#: commands/analyze.c:325
+#: commands/analyze.c:339
#, c-format
msgid "analyzing \"%s.%s\""
msgstr "analyse « %s.%s »"
-#: commands/analyze.c:650
+#: commands/analyze.c:668
#, c-format
msgid "automatic analyze of table \"%s.%s.%s\" system usage: %s"
msgstr "ANALYZE automatique de la table « %s.%s.%s » ; utilisation système : %s"
-#: commands/analyze.c:1204
+#: commands/analyze.c:1220
#, 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 ""
@@ -5137,20 +5093,16 @@ msgstr ""
" %d lignes dans l'échantillon,\n"
" %.0f lignes totales estimées"
-#: commands/analyze.c:1283
+#: commands/analyze.c:1300
#, c-format
msgid "skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no child tables"
msgstr "ignore l'analyse de l'arbre d'héritage « %s.%s » --- cet arbre d'héritage ne contient pas de tables enfants"
-#: commands/analyze.c:1372
+#: commands/analyze.c:1398
#, c-format
msgid "skipping analyze of \"%s.%s\" inheritance tree --- this inheritance tree contains no analyzable child tables"
msgstr "ignore l'analyse de l'arbre d'héritage « %s.%s » --- cet arbre d'héritage ne contient pas de tables enfants analysables"
-#: commands/analyze.c:1420 commands/tablecmds.c:8079 executor/execQual.c:2927
-msgid "could not convert row type"
-msgstr "n'a pas pu convertir le type de ligne"
-
#: commands/async.c:555
#, c-format
msgid "channel name cannot be empty"
@@ -5205,7 +5157,7 @@ msgstr "ne peut pas exécuter CLUSTER sur les tables temporaires des autres sess
msgid "there is no previously clustered index for table \"%s\""
msgstr "Il n'existe pas d'index CLUSTER pour la table « %s »"
-#: commands/cluster.c:173 commands/tablecmds.c:9383 commands/tablecmds.c:11143
+#: commands/cluster.c:173 commands/tablecmds.c:10185 commands/tablecmds.c:12066
#, c-format
msgid "index \"%s\" for table \"%s\" does not exist"
msgstr "l'index « %s » pour la table « %s » n'existe pas"
@@ -5220,7 +5172,7 @@ msgstr "ne peut pas exécuter CLUSTER sur un catalogue partagé"
msgid "cannot vacuum temporary tables of other sessions"
msgstr "ne peut pas exécuter VACUUM sur les tables temporaires des autres sessions"
-#: commands/cluster.c:431 commands/tablecmds.c:11153
+#: commands/cluster.c:431 commands/tablecmds.c:12076
#, c-format
msgid "\"%s\" is not an index for table \"%s\""
msgstr "« %s » n'est pas un index de la table « %s »"
@@ -5252,19 +5204,19 @@ msgstr "cluster sur « %s.%s » en utilisant un parcours d'index sur « %s »"
msgid "clustering \"%s.%s\" using sequential scan and sort"
msgstr "cluster sur « %s.%s » en utilisant un parcours séquentiel puis un tri"
-#: commands/cluster.c:929 commands/vacuumlazy.c:479
+#: commands/cluster.c:929 commands/vacuumlazy.c:490
#, c-format
msgid "vacuuming \"%s.%s\""
msgstr "exécution du VACUUM sur « %s.%s »"
-#: commands/cluster.c:1088
+#: commands/cluster.c:1084
#, c-format
msgid "\"%s\": found %.0f removable, %.0f nonremovable row versions in %u pages"
msgstr ""
"« %s » : %.0f versions de ligne supprimables, %.0f non supprimables\n"
"parmi %u pages"
-#: commands/cluster.c:1092
+#: commands/cluster.c:1088
#, c-format
msgid ""
"%.0f dead row versions cannot be removed yet.\n"
@@ -5273,47 +5225,92 @@ msgstr ""
"%.0f versions de lignes ne peuvent pas encore être supprimées.\n"
"%s."
-#: commands/collationcmds.c:80
+#: commands/collationcmds.c:101
#, c-format
msgid "collation attribute \"%s\" not recognized"
msgstr "attribut de collationnement « %s » non reconnu"
-#: commands/collationcmds.c:125
+#: commands/collationcmds.c:143
+#, c-format
+msgid "collation \"default\" cannot be copied"
+msgstr "le collationnement « default » ne peut pas être copié"
+
+#: commands/collationcmds.c:173
+#, c-format
+msgid "unrecognized collation provider: %s"
+msgstr "fournisseur de collationnement non reconnu : %s"
+
+#: commands/collationcmds.c:182
#, c-format
msgid "parameter \"lc_collate\" must be specified"
msgstr "le paramètre « lc_collate » doit être spécifié"
-#: commands/collationcmds.c:130
+#: commands/collationcmds.c:187
#, c-format
msgid "parameter \"lc_ctype\" must be specified"
msgstr "le paramètre « lc_ctype » doit être spécifié"
-#: commands/collationcmds.c:166
+#: commands/collationcmds.c:246
#, c-format
msgid "collation \"%s\" for encoding \"%s\" already exists in schema \"%s\""
msgstr "le collationnament « %s » pour l'encodage « %s » existe déjà dans le schéma « %s »"
-#: commands/collationcmds.c:177
+#: commands/collationcmds.c:257
#, c-format
msgid "collation \"%s\" already exists in schema \"%s\""
msgstr "le collationnement « %s » existe déjà dans le schéma « %s »"
-#: commands/comment.c:62 commands/dbcommands.c:797 commands/dbcommands.c:962 commands/dbcommands.c:1067 commands/dbcommands.c:1257 commands/dbcommands.c:1477 commands/dbcommands.c:1594 commands/dbcommands.c:2011 utils/init/postinit.c:841 utils/init/postinit.c:943 utils/init/postinit.c:960
+#: commands/collationcmds.c:305
+#, c-format
+msgid "changing version from %s to %s"
+msgstr "changement de version de %s à %s"
+
+#: commands/collationcmds.c:320
+#, c-format
+msgid "version has not changed"
+msgstr "la version n'a pas changé"
+
+#: commands/collationcmds.c:451
+#, c-format
+msgid "could not convert locale name \"%s\" to language tag: %s"
+msgstr "n'a pas pu convertir le nom de locale « %s » en balise de langage : %s"
+
+#: commands/collationcmds.c:512
+#, c-format
+msgid "must be superuser to import system collations"
+msgstr "doit être super-utilisateur pour importer les collationnements systèmes"
+
+#: commands/collationcmds.c:535 commands/copy.c:1860 commands/copy.c:3102
+#, c-format
+msgid "could not execute command \"%s\": %m"
+msgstr "n'a pas pu exécuter la commande « %s » : %m"
+
+#: commands/collationcmds.c:666
+#, c-format
+msgid "no usable system locales were found"
+msgstr "aucune locale système utilisable n'a été trouvée"
+
+#: commands/collationcmds.c:730 commands/collationcmds.c:769
+#, c-format
+msgid "could not get keyword values for locale \"%s\": %s"
+msgstr "n'a pas pu obtenir les valeurs des mots clés pour la locale « %s » : %s"
+
+#: commands/comment.c:61 commands/dbcommands.c:808 commands/dbcommands.c:996 commands/dbcommands.c:1100 commands/dbcommands.c:1290 commands/dbcommands.c:1513 commands/dbcommands.c:1627 commands/dbcommands.c:2043 utils/init/postinit.c:846 utils/init/postinit.c:951 utils/init/postinit.c:968
#, c-format
msgid "database \"%s\" does not exist"
msgstr "la base de données « %s » n'existe pas"
-#: commands/comment.c:101 commands/seclabel.c:116 parser/parse_utilcmd.c:753
+#: commands/comment.c:101 commands/seclabel.c:117 parser/parse_utilcmd.c:931
#, c-format
msgid "\"%s\" is not a table, view, materialized view, composite type, or foreign table"
msgstr "« %s » n'est ni une table, ni une vue, ni une vue matérialisée, ni un type composite, ni une table distante"
-#: commands/constraint.c:60 utils/adt/ri_triggers.c:2715
+#: commands/constraint.c:60 utils/adt/ri_triggers.c:2712
#, c-format
msgid "function \"%s\" was not called by trigger manager"
msgstr "la fonction « %s » n'a pas été appelée par le gestionnaire de triggers"
-#: commands/constraint.c:67 utils/adt/ri_triggers.c:2724
+#: commands/constraint.c:67 utils/adt/ri_triggers.c:2721
#, c-format
msgid "function \"%s\" must be fired AFTER ROW"
msgstr "la fonction « %s » doit être exécutée pour l'instruction AFTER ROW"
@@ -5323,528 +5320,548 @@ msgstr "la fonction « %s » doit être exécutée pour l'instruction AFTER ROW"
msgid "function \"%s\" must be fired for INSERT or UPDATE"
msgstr "la fonction « %s » doit être exécutée pour les instructions INSERT ou UPDATE"
-#: commands/conversioncmds.c:67
+#: commands/conversioncmds.c:66
#, c-format
msgid "source encoding \"%s\" does not exist"
msgstr "le codage source « %s » n'existe pas"
-#: commands/conversioncmds.c:74
+#: commands/conversioncmds.c:73
#, c-format
msgid "destination encoding \"%s\" does not exist"
msgstr "l'encodage de destination « %s » n'existe pas"
-#: commands/conversioncmds.c:88
+#: commands/conversioncmds.c:87
#, c-format
msgid "encoding conversion function %s must return type %s"
msgstr "la fonction de conversion d'encodage %s doit renvoyer le type %s"
-#: commands/copy.c:362 commands/copy.c:374 commands/copy.c:408 commands/copy.c:420
+#: commands/copy.c:373 commands/copy.c:407
#, c-format
msgid "COPY BINARY is not supported to stdout or from stdin"
msgstr "COPY BINARY n'est pas supporté vers stdout ou à partir de stdin"
-#: commands/copy.c:520
+#: commands/copy.c:507
#, c-format
msgid "could not write to COPY program: %m"
msgstr "n'a pas pu écrire vers le programme COPY : %m"
-#: commands/copy.c:525
+#: commands/copy.c:512
#, c-format
msgid "could not write to COPY file: %m"
msgstr "n'a pas pu écrire dans le fichier COPY : %m"
-#: commands/copy.c:538
+#: commands/copy.c:525
#, c-format
msgid "connection lost during COPY to stdout"
msgstr "connexion perdue lors de l'opération COPY vers stdout"
-#: commands/copy.c:579
+#: commands/copy.c:569
#, c-format
msgid "could not read from COPY file: %m"
msgstr "n'a pas pu lire le fichier COPY : %m"
-#: commands/copy.c:595 commands/copy.c:616 commands/copy.c:620 tcop/postgres.c:341 tcop/postgres.c:377 tcop/postgres.c:404
+#: commands/copy.c:585 commands/copy.c:606 commands/copy.c:610 tcop/postgres.c:335 tcop/postgres.c:371 tcop/postgres.c:398
#, c-format
msgid "unexpected EOF on client connection with an open transaction"
msgstr ""
"fin de fichier (EOF) inattendue de la connexion du client avec une\n"
"transaction ouverte"
-#: commands/copy.c:633
+#: commands/copy.c:623
#, c-format
msgid "COPY from stdin failed: %s"
msgstr "échec de la commande COPY à partir de stdin : %s"
-#: commands/copy.c:649
+#: commands/copy.c:639
#, c-format
msgid "unexpected message type 0x%02X during COPY from stdin"
msgstr "type 0x%02X du message, inattendu, lors d'une opération COPY à partir de stdin"
-#: commands/copy.c:806
+#: commands/copy.c:800
#, c-format
msgid "must be superuser to COPY to or from an external program"
msgstr "doit être super-utilisateur pour utiliser COPY avec un programme externe"
-#: commands/copy.c:807 commands/copy.c:813
+#: commands/copy.c:801 commands/copy.c:807
#, c-format
msgid "Anyone can COPY to stdout or from stdin. psql's \\copy command also works for anyone."
msgstr ""
"Tout le monde peut utiliser COPY vers stdout ou à partir de stdin.\n"
"La commande \\copy de psql fonctionne aussi pour tout le monde."
-#: commands/copy.c:812
+#: commands/copy.c:806
#, c-format
msgid "must be superuser to COPY to or from a file"
msgstr "doit être super-utilisateur pour utiliser COPY à partir ou vers un fichier"
-#: commands/copy.c:879
+#: commands/copy.c:868
#, c-format
msgid "COPY FROM not supported with row-level security"
msgstr "COPY FROM non supporté avec la sécurité niveau ligne"
-#: commands/copy.c:880
+#: commands/copy.c:869
#, c-format
msgid "Use INSERT statements instead."
msgstr "Utilisez des instructions INSERT à la place."
-#: commands/copy.c:1058
+#: commands/copy.c:1054
#, c-format
msgid "COPY format \"%s\" not recognized"
msgstr "format COPY « %s » non reconnu"
-#: commands/copy.c:1129 commands/copy.c:1143 commands/copy.c:1157 commands/copy.c:1177
+#: commands/copy.c:1134 commands/copy.c:1150 commands/copy.c:1165 commands/copy.c:1187
#, c-format
msgid "argument to option \"%s\" must be a list of column names"
msgstr "l'argument de l'option « %s » doit être une liste de noms de colonnes"
-#: commands/copy.c:1190
+#: commands/copy.c:1202
#, c-format
msgid "argument to option \"%s\" must be a valid encoding name"
msgstr "l'argument de l'option « %s » doit être un nom d'encodage valide"
-#: commands/copy.c:1196 commands/dbcommands.c:232 commands/dbcommands.c:1427
+#: commands/copy.c:1209 commands/dbcommands.c:242 commands/dbcommands.c:1461
#, c-format
msgid "option \"%s\" not recognized"
msgstr "option « %s » non reconnu"
-#: commands/copy.c:1207
+#: commands/copy.c:1221
#, c-format
msgid "cannot specify DELIMITER in BINARY mode"
msgstr "ne peut pas spécifier le délimiteur (DELIMITER) en mode binaire (BINARY)"
-#: commands/copy.c:1212
+#: commands/copy.c:1226
#, c-format
msgid "cannot specify NULL in BINARY mode"
msgstr "ne peut pas spécifier NULL en mode binaire (BINARY)"
-#: commands/copy.c:1234
+#: commands/copy.c:1248
#, c-format
msgid "COPY delimiter must be a single one-byte character"
msgstr "le délimiteur COPY doit être sur un seul caractère sur un octet"
-#: commands/copy.c:1241
+#: commands/copy.c:1255
#, c-format
msgid "COPY delimiter cannot be newline or carriage return"
msgstr "le délimiteur de COPY ne peut pas être un retour à la ligne ou un retour chariot"
-#: commands/copy.c:1247
+#: commands/copy.c:1261
#, c-format
msgid "COPY null representation cannot use newline or carriage return"
msgstr ""
"la représentation du NULL dans COPY ne peut pas utiliser le caractère du\n"
"retour à la ligne ou du retour chariot"
-#: commands/copy.c:1264
+#: commands/copy.c:1278
#, c-format
msgid "COPY delimiter cannot be \"%s\""
msgstr "le délimiteur de COPY ne peut pas être « %s »"
-#: commands/copy.c:1270
+#: commands/copy.c:1284
#, c-format
msgid "COPY HEADER available only in CSV mode"
msgstr "COPY HEADER disponible uniquement en mode CSV"
-#: commands/copy.c:1276
+#: commands/copy.c:1290
#, c-format
msgid "COPY quote available only in CSV mode"
msgstr "le guillemet COPY n'est disponible que dans le mode CSV"
-#: commands/copy.c:1281
+#: commands/copy.c:1295
#, c-format
msgid "COPY quote must be a single one-byte character"
msgstr "le guillemet COPY doit être sur un seul caractère sur un octet"
-#: commands/copy.c:1286
+#: commands/copy.c:1300
#, c-format
msgid "COPY delimiter and quote must be different"
msgstr "le délimiteur de COPY ne doit pas être un guillemet"
-#: commands/copy.c:1292
+#: commands/copy.c:1306
#, c-format
msgid "COPY escape available only in CSV mode"
msgstr "le caractère d'échappement COPY n'est disponible que dans le mode CSV"
-#: commands/copy.c:1297
+#: commands/copy.c:1311
#, c-format
msgid "COPY escape must be a single one-byte character"
msgstr "le caractère d'échappement COPY doit être sur un seul caractère sur un octet"
-#: commands/copy.c:1303
+#: commands/copy.c:1317
#, c-format
msgid "COPY force quote available only in CSV mode"
msgstr "le guillemet forcé COPY n'est disponible que dans le mode CSV"
-#: commands/copy.c:1307
+#: commands/copy.c:1321
#, c-format
msgid "COPY force quote only available using COPY TO"
msgstr "le guillemet forcé COPY n'est disponible qu'en utilisant COPY TO"
-#: commands/copy.c:1313
+#: commands/copy.c:1327
#, c-format
msgid "COPY force not null available only in CSV mode"
msgstr "« COPY force not null » n'est disponible que dans la version CSV"
-#: commands/copy.c:1317
+#: commands/copy.c:1331
#, c-format
msgid "COPY force not null only available using COPY FROM"
msgstr "« COPY force not null » n'est disponible qu'en utilisant COPY FROM"
-#: commands/copy.c:1323
+#: commands/copy.c:1337
#, c-format
msgid "COPY force null available only in CSV mode"
msgstr "« COPY force null » n'est disponible que dans le mode CSV"
-#: commands/copy.c:1328
+#: commands/copy.c:1342
#, c-format
msgid "COPY force null only available using COPY FROM"
msgstr "« COPY force null » n'est disponible qu'en utilisant COPY FROM"
-#: commands/copy.c:1334
+#: commands/copy.c:1348
#, c-format
msgid "COPY delimiter must not appear in the NULL specification"
msgstr "le délimiteur COPY ne doit pas apparaître dans la spécification de NULL"
-#: commands/copy.c:1341
+#: commands/copy.c:1355
#, c-format
msgid "CSV quote character must not appear in the NULL specification"
msgstr "le caractère guillemet de CSV ne doit pas apparaître dans la spécification de NULL"
-#: commands/copy.c:1402
+#: commands/copy.c:1416
#, c-format
msgid "table \"%s\" does not have OIDs"
msgstr "la table « %s » n'a pas d'OID"
-#: commands/copy.c:1419
+#: commands/copy.c:1486
#, c-format
msgid "COPY (query) WITH OIDS is not supported"
msgstr "COPY (requête) WITH OIDS n'est pas supporté"
-#: commands/copy.c:1439
+#: commands/copy.c:1507
#, c-format
msgid "DO INSTEAD NOTHING rules are not supported for COPY"
msgstr "les règles DO INSTEAD NOTHING ne sont pas supportées par l'instruction COPY"
-#: commands/copy.c:1453
+#: commands/copy.c:1521
#, c-format
msgid "conditional DO INSTEAD rules are not supported for COPY"
msgstr "les règles DO INSTEAD conditionnelles ne sont pas supportées par l'instruction COPY"
-#: commands/copy.c:1457
+#: commands/copy.c:1525
#, c-format
msgid "DO ALSO rules are not supported for the COPY"
msgstr "les règles DO ALSO ne sont pas supportées par l'instruction COPY"
-#: commands/copy.c:1462
+#: commands/copy.c:1530
#, c-format
msgid "multi-statement DO INSTEAD rules are not supported for COPY"
msgstr "les règles DO INSTEAD multi-instructions ne sont pas supportées par l'instruction COPY"
-#: commands/copy.c:1472
+#: commands/copy.c:1540
#, c-format
msgid "COPY (SELECT INTO) is not supported"
msgstr "COPY (SELECT INTO) n'est pas supporté"
-#: commands/copy.c:1489
+#: commands/copy.c:1557
#, c-format
msgid "COPY query must have a RETURNING clause"
msgstr "La requête COPY doit avoir une clause RETURNING"
-#: commands/copy.c:1517
+#: commands/copy.c:1585
#, c-format
msgid "relation referenced by COPY statement has changed"
msgstr "la relation référencée par l'instruction COPY a changé"
-#: commands/copy.c:1575
+#: commands/copy.c:1643
#, c-format
msgid "FORCE_QUOTE column \"%s\" not referenced by COPY"
msgstr "la colonne « %s » FORCE_QUOTE n'est pas référencée par COPY"
-#: commands/copy.c:1597
+#: commands/copy.c:1665
#, c-format
msgid "FORCE_NOT_NULL column \"%s\" not referenced by COPY"
msgstr "la colonne « %s » FORCE_NOT_NULL n'est pas référencée par COPY"
-#: commands/copy.c:1619
+#: commands/copy.c:1687
#, c-format
msgid "FORCE_NULL column \"%s\" not referenced by COPY"
msgstr "colonne « %s » FORCE_NULL non référencée par COPY"
-#: commands/copy.c:1684
+#: commands/copy.c:1752
#, c-format
msgid "could not close pipe to external command: %m"
msgstr "n'a pas pu fermer le fichier pipe vers la commande externe : %m"
-#: commands/copy.c:1688
+#: commands/copy.c:1756
#, c-format
msgid "program \"%s\" failed"
msgstr "le programme « %s » a échoué"
-#: commands/copy.c:1738
+#: commands/copy.c:1806
#, c-format
msgid "cannot copy from view \"%s\""
msgstr "ne peut pas copier à partir de la vue « %s »"
-#: commands/copy.c:1740 commands/copy.c:1746 commands/copy.c:1752
+#: commands/copy.c:1808 commands/copy.c:1814 commands/copy.c:1820 commands/copy.c:1831
#, c-format
msgid "Try the COPY (SELECT ...) TO variant."
msgstr "Tentez la variante COPY (SELECT ...) TO."
-#: commands/copy.c:1744
+#: commands/copy.c:1812
#, c-format
msgid "cannot copy from materialized view \"%s\""
msgstr "ne peut pas copier à partir de la vue matérialisée « %s »"
-#: commands/copy.c:1750
+#: commands/copy.c:1818
#, c-format
msgid "cannot copy from foreign table \"%s\""
msgstr "ne peut pas copier à partir de la table distante « %s »"
-#: commands/copy.c:1756
+#: commands/copy.c:1824
#, c-format
msgid "cannot copy from sequence \"%s\""
msgstr "ne peut pas copier à partir de la séquence « %s »"
-#: commands/copy.c:1761
+#: commands/copy.c:1829
#, c-format
-msgid "cannot copy from non-table relation \"%s\""
-msgstr "ne peut pas copier à partir de la relation « %s », qui n'est pas une table"
+msgid "cannot copy from partitioned table \"%s\""
+msgstr "ne peut pas copier à partir de la table partitionnée « %s »"
-#: commands/copy.c:1786 commands/copy.c:2822
+#: commands/copy.c:1835
#, c-format
-msgid "could not execute command \"%s\": %m"
-msgstr "n'a pas pu exécuter la commande « %s » : %m"
+msgid "cannot copy from non-table relation \"%s\""
+msgstr "ne peut pas copier à partir de la relation « %s », qui n'est pas une table"
-#: commands/copy.c:1801
+#: commands/copy.c:1875
#, c-format
msgid "relative path not allowed for COPY to file"
msgstr "un chemin relatif n'est pas autorisé à utiliser COPY vers un fichier"
-#: commands/copy.c:1809
+#: commands/copy.c:1887
#, c-format
msgid "could not open file \"%s\" for writing: %m"
msgstr "n'a pas pu ouvrir le fichier « %s » en écriture : %m"
-#: commands/copy.c:1821 commands/copy.c:2845
+#: commands/copy.c:1890
+#, c-format
+msgid "COPY TO instructs the PostgreSQL server process to write a file. You may want a client-side facility such as psql's \\copy."
+msgstr "COPY TO indique au serveur PostgreSQL d'écrire un fichier. Vous pourriez vouloir utiliser la fonctionnalité \\copy de psql pour écrire en local."
+
+#: commands/copy.c:1903 commands/copy.c:3133
#, c-format
msgid "\"%s\" is a directory"
msgstr "« %s » est un répertoire"
-#: commands/copy.c:2144
+#: commands/copy.c:2226
#, c-format
msgid "COPY %s, line %d, column %s"
msgstr "COPY %s, ligne %d, colonne %s"
-#: commands/copy.c:2148 commands/copy.c:2195
+#: commands/copy.c:2230 commands/copy.c:2277
#, c-format
msgid "COPY %s, line %d"
msgstr "COPY %s, ligne %d"
-#: commands/copy.c:2159
+#: commands/copy.c:2241
#, c-format
msgid "COPY %s, line %d, column %s: \"%s\""
msgstr "COPY %s, ligne %d, colonne %s : « %s »"
-#: commands/copy.c:2167
+#: commands/copy.c:2249
#, c-format
msgid "COPY %s, line %d, column %s: null input"
msgstr "COPY %s, ligne %d, colonne %s : NULL en entrée"
-#: commands/copy.c:2189
+#: commands/copy.c:2271
#, c-format
msgid "COPY %s, line %d: \"%s\""
msgstr "COPY %s, ligne %d : « %s »"
-#: commands/copy.c:2273
+#: commands/copy.c:2365
#, c-format
msgid "cannot copy to view \"%s\""
msgstr "ne peut pas copier vers la vue « %s »"
-#: commands/copy.c:2278
+#: commands/copy.c:2367
+#, c-format
+msgid "To enable copying to a view, provide an INSTEAD OF INSERT trigger."
+msgstr "Pour activer la copie d'une vue, fournissez un trigger INSTEAD OF INSERT."
+
+#: commands/copy.c:2371
#, c-format
msgid "cannot copy to materialized view \"%s\""
msgstr "ne peut pas copier vers la vue matérialisée « %s »"
-#: commands/copy.c:2283
+#: commands/copy.c:2376
#, c-format
msgid "cannot copy to foreign table \"%s\""
msgstr "ne peut pas copier vers la table distante « %s »"
-#: commands/copy.c:2288
+#: commands/copy.c:2381
#, c-format
msgid "cannot copy to sequence \"%s\""
msgstr "ne peut pas copier vers la séquence « %s »"
-#: commands/copy.c:2293
+#: commands/copy.c:2386
#, c-format
msgid "cannot copy to non-table relation \"%s\""
msgstr "ne peut pas copier vers une relation « %s » qui n'est pas une table"
-#: commands/copy.c:2356
+#: commands/copy.c:2449
#, c-format
msgid "cannot perform FREEZE because of prior transaction activity"
msgstr "n'a pas pu exécuter un FREEZE à cause d'une activité transactionnelle précédente"
-#: commands/copy.c:2362
+#: commands/copy.c:2455
#, c-format
msgid "cannot perform FREEZE because the table was not created or truncated in the current subtransaction"
msgstr "n'a pas pu exécuter un FREEZE parce que la table n'était pas créée ou tronquée dans la transaction en cours"
-#: commands/copy.c:2865
+#: commands/copy.c:2618 executor/nodeModifyTable.c:311
+#, c-format
+msgid "cannot route inserted tuples to a foreign table"
+msgstr "ne peut pas envoyer les lignes insérées dans une table distante"
+
+#: commands/copy.c:3120
+#, c-format
+msgid "COPY FROM instructs the PostgreSQL server process to read a file. You may want a client-side facility such as psql's \\copy."
+msgstr "COPY TO indique au serveur PostgreSQL de lire un fichier. Vous pourriez vouloir utiliser la fonctionnalité \\copy de psql pour lire en local."
+
+#: commands/copy.c:3153
#, c-format
msgid "COPY file signature not recognized"
msgstr "la signature du fichier COPY n'est pas reconnue"
-#: commands/copy.c:2870
+#: commands/copy.c:3158
#, c-format
msgid "invalid COPY file header (missing flags)"
msgstr "en-tête du fichier COPY invalide (options manquantes)"
-#: commands/copy.c:2876
+#: commands/copy.c:3164
#, c-format
msgid "unrecognized critical flags in COPY file header"
msgstr "options critiques non reconnues dans l'en-tête du fichier COPY"
-#: commands/copy.c:2882
+#: commands/copy.c:3170
#, c-format
msgid "invalid COPY file header (missing length)"
msgstr "en-tête du fichier COPY invalide (longueur manquante)"
-#: commands/copy.c:2889
+#: commands/copy.c:3177
#, c-format
msgid "invalid COPY file header (wrong length)"
msgstr "en-tête du fichier COPY invalide (mauvaise longueur)"
-#: commands/copy.c:3022 commands/copy.c:3729 commands/copy.c:3959
+#: commands/copy.c:3310 commands/copy.c:4017 commands/copy.c:4247
#, c-format
msgid "extra data after last expected column"
msgstr "données supplémentaires après la dernière colonne attendue"
-#: commands/copy.c:3032
+#: commands/copy.c:3320
#, c-format
msgid "missing data for OID column"
msgstr "données manquantes pour la colonne OID"
-#: commands/copy.c:3038
+#: commands/copy.c:3326
#, c-format
msgid "null OID in COPY data"
msgstr "OID NULL dans les données du COPY"
-#: commands/copy.c:3048 commands/copy.c:3171
+#: commands/copy.c:3336 commands/copy.c:3459
#, c-format
msgid "invalid OID in COPY data"
msgstr "OID invalide dans les données du COPY"
-#: commands/copy.c:3063
+#: commands/copy.c:3351
#, c-format
msgid "missing data for column \"%s\""
msgstr "données manquantes pour la colonne « %s »"
-#: commands/copy.c:3146
+#: commands/copy.c:3434
#, c-format
msgid "received copy data after EOF marker"
msgstr "a reçu des données de COPY après le marqueur de fin"
-#: commands/copy.c:3153
+#: commands/copy.c:3441
#, c-format
msgid "row field count is %d, expected %d"
msgstr "le nombre de champs de la ligne est %d, %d attendus"
-#: commands/copy.c:3493 commands/copy.c:3510
+#: commands/copy.c:3781 commands/copy.c:3798
#, c-format
msgid "literal carriage return found in data"
msgstr "retour chariot trouvé dans les données"
-#: commands/copy.c:3494 commands/copy.c:3511
+#: commands/copy.c:3782 commands/copy.c:3799
#, c-format
msgid "unquoted carriage return found in data"
msgstr "retour chariot sans guillemet trouvé dans les données"
-#: commands/copy.c:3496 commands/copy.c:3513
+#: commands/copy.c:3784 commands/copy.c:3801
#, c-format
msgid "Use \"\\r\" to represent carriage return."
msgstr "Utilisez « \\r » pour représenter un retour chariot."
-#: commands/copy.c:3497 commands/copy.c:3514
+#: commands/copy.c:3785 commands/copy.c:3802
#, c-format
msgid "Use quoted CSV field to represent carriage return."
msgstr "Utiliser le champ CSV entre guillemets pour représenter un retour chariot."
-#: commands/copy.c:3526
+#: commands/copy.c:3814
#, c-format
msgid "literal newline found in data"
msgstr "retour à la ligne trouvé dans les données"
-#: commands/copy.c:3527
+#: commands/copy.c:3815
#, c-format
msgid "unquoted newline found in data"
msgstr "retour à la ligne trouvé dans les données"
-#: commands/copy.c:3529
+#: commands/copy.c:3817
#, c-format
msgid "Use \"\\n\" to represent newline."
msgstr "Utilisez « \\n » pour représenter un retour à la ligne."
-#: commands/copy.c:3530
+#: commands/copy.c:3818
#, c-format
msgid "Use quoted CSV field to represent newline."
msgstr "Utiliser un champ CSV entre guillemets pour représenter un retour à la ligne."
-#: commands/copy.c:3576 commands/copy.c:3612
+#: commands/copy.c:3864 commands/copy.c:3900
#, c-format
msgid "end-of-copy marker does not match previous newline style"
msgstr "le marqueur fin-de-copie ne correspond pas à un précédent style de fin de ligne"
-#: commands/copy.c:3585 commands/copy.c:3601
+#: commands/copy.c:3873 commands/copy.c:3889
#, c-format
msgid "end-of-copy marker corrupt"
msgstr "marqueur fin-de-copie corrompu"
-#: commands/copy.c:4043
+#: commands/copy.c:4331
#, c-format
msgid "unterminated CSV quoted field"
msgstr "champ CSV entre guillemets non terminé"
-#: commands/copy.c:4120 commands/copy.c:4139
+#: commands/copy.c:4408 commands/copy.c:4427
#, c-format
msgid "unexpected EOF in COPY data"
msgstr "fin de fichier (EOF) inattendu dans les données du COPY"
-#: commands/copy.c:4129
+#: commands/copy.c:4417
#, c-format
msgid "invalid field size"
msgstr "taille du champ invalide"
-#: commands/copy.c:4152
+#: commands/copy.c:4440
#, c-format
msgid "incorrect binary data format"
msgstr "format de données binaires incorrect"
-#: commands/copy.c:4463 commands/indexcmds.c:1053 commands/tablecmds.c:1464 commands/tablecmds.c:2291 parser/parse_relation.c:3177 parser/parse_relation.c:3197 utils/adt/tsvector_op.c:2559
+#: commands/copy.c:4751 commands/indexcmds.c:1070 commands/tablecmds.c:1685 commands/tablecmds.c:2187 commands/tablecmds.c:2613 parser/parse_relation.c:3249 parser/parse_relation.c:3269 utils/adt/tsvector_op.c:2561
#, c-format
msgid "column \"%s\" does not exist"
msgstr "la colonne « %s » n'existe pas"
-#: commands/copy.c:4470 commands/tablecmds.c:1490 commands/trigger.c:651 parser/parse_target.c:967 parser/parse_target.c:978
+#: commands/copy.c:4758 commands/tablecmds.c:1711 commands/tablecmds.c:2213 commands/trigger.c:800 parser/parse_target.c:1018 parser/parse_target.c:1029
#, c-format
msgid "column \"%s\" specified more than once"
msgstr "la colonne « %s » est spécifiée plus d'une fois"
@@ -5859,243 +5876,255 @@ msgstr "trop de noms de colonnes ont été spécifiés"
msgid "policies not yet implemented for this command"
msgstr "politiques non encore implémentées pour cette commande"
-#: commands/dbcommands.c:226
+#: commands/dbcommands.c:235
#, c-format
msgid "LOCATION is not supported anymore"
msgstr "LOCATION n'est plus supporté"
-#: commands/dbcommands.c:227
+#: commands/dbcommands.c:236
#, c-format
msgid "Consider using tablespaces instead."
msgstr "Considérer l'utilisation de tablespaces."
-#: commands/dbcommands.c:251 utils/adt/ascii.c:144
+#: commands/dbcommands.c:262 utils/adt/ascii.c:145
#, c-format
msgid "%d is not a valid encoding code"
msgstr "%d n'est pas un code d'encodage valide"
-#: commands/dbcommands.c:261 utils/adt/ascii.c:126
+#: commands/dbcommands.c:273 utils/adt/ascii.c:127
#, c-format
msgid "%s is not a valid encoding name"
msgstr "%s n'est pas un nom d'encodage valide"
-#: commands/dbcommands.c:279 commands/dbcommands.c:1458 commands/user.c:272 commands/user.c:650
+#: commands/dbcommands.c:292 commands/dbcommands.c:1494 commands/user.c:276 commands/user.c:641
#, c-format
msgid "invalid connection limit: %d"
msgstr "limite de connexion invalide : %d"
-#: commands/dbcommands.c:298
+#: commands/dbcommands.c:311
#, c-format
msgid "permission denied to create database"
msgstr "droit refusé pour créer une base de données"
-#: commands/dbcommands.c:321
+#: commands/dbcommands.c:334
#, c-format
msgid "template database \"%s\" does not exist"
msgstr "la base de données modèle « %s » n'existe pas"
-#: commands/dbcommands.c:333
+#: commands/dbcommands.c:346
#, c-format
msgid "permission denied to copy database \"%s\""
msgstr "droit refusé pour copier la base de données « %s »"
-#: commands/dbcommands.c:349
+#: commands/dbcommands.c:362
#, c-format
msgid "invalid server encoding %d"
msgstr "encodage serveur %d invalide"
-#: commands/dbcommands.c:355 commands/dbcommands.c:360
+#: commands/dbcommands.c:368 commands/dbcommands.c:373
#, c-format
msgid "invalid locale name: \"%s\""
msgstr "nom de locale invalide : « %s »"
-#: commands/dbcommands.c:380
+#: commands/dbcommands.c:393
#, c-format
msgid "new encoding (%s) is incompatible with the encoding of the template database (%s)"
msgstr ""
"le nouvel encodage (%sà est incompatible avec l'encodage de la base de\n"
"données modèle (%s)"
-#: commands/dbcommands.c:383
+#: commands/dbcommands.c:396
#, c-format
msgid "Use the same encoding as in the template database, or use template0 as template."
msgstr ""
"Utilisez le même encodage que celui de la base de données modèle,\n"
"ou utilisez template0 comme modèle."
-#: commands/dbcommands.c:388
+#: commands/dbcommands.c:401
#, c-format
msgid "new collation (%s) is incompatible with the collation of the template database (%s)"
msgstr ""
"le nouveau tri (%s) est incompatible avec le tri de la base de\n"
"données modèle (%s)"
-#: commands/dbcommands.c:390
+#: commands/dbcommands.c:403
#, c-format
msgid "Use the same collation as in the template database, or use template0 as template."
msgstr ""
"Utilisez le même tri que celui de la base de données modèle,\n"
"ou utilisez template0 comme modèle."
-#: commands/dbcommands.c:395
+#: commands/dbcommands.c:408
#, c-format
msgid "new LC_CTYPE (%s) is incompatible with the LC_CTYPE of the template database (%s)"
msgstr ""
"le nouveau LC_CTYPE (%s) est incompatible avec le LC_CTYPE de la base de\n"
"données modèle (%s)"
-#: commands/dbcommands.c:397
+#: commands/dbcommands.c:410
#, c-format
msgid "Use the same LC_CTYPE as in the template database, or use template0 as template."
msgstr ""
"Utilisez le même LC_CTYPE que celui de la base de données modèle,\n"
"ou utilisez template0 comme modèle."
-#: commands/dbcommands.c:419 commands/dbcommands.c:1113
+#: commands/dbcommands.c:432 commands/dbcommands.c:1146
#, c-format
msgid "pg_global cannot be used as default tablespace"
msgstr "pg_global ne peut pas être utilisé comme tablespace par défaut"
-#: commands/dbcommands.c:445
+#: commands/dbcommands.c:458
#, c-format
msgid "cannot assign new default tablespace \"%s\""
msgstr "ne peut pas affecter un nouveau tablespace par défaut « %s »"
-#: commands/dbcommands.c:447
+#: commands/dbcommands.c:460
#, c-format
msgid "There is a conflict because database \"%s\" already has some tables in this tablespace."
msgstr ""
"Il existe un conflit car la base de données « %s » a déjà quelques tables\n"
"dans son tablespace."
-#: commands/dbcommands.c:467 commands/dbcommands.c:982
+#: commands/dbcommands.c:480 commands/dbcommands.c:1016
#, c-format
msgid "database \"%s\" already exists"
msgstr "la base de données « %s » existe déjà"
-#: commands/dbcommands.c:481
+#: commands/dbcommands.c:494
#, c-format
msgid "source database \"%s\" is being accessed by other users"
msgstr "la base de données source « %s » est accédée par d'autres utilisateurs"
-#: commands/dbcommands.c:726 commands/dbcommands.c:741
+#: commands/dbcommands.c:736 commands/dbcommands.c:751
#, c-format
msgid "encoding \"%s\" does not match locale \"%s\""
msgstr "l'encodage « %s » ne correspond pas à la locale « %s »"
-#: commands/dbcommands.c:729
+#: commands/dbcommands.c:739
#, c-format
msgid "The chosen LC_CTYPE setting requires encoding \"%s\"."
msgstr "Le paramètre LC_CTYPE choisi nécessite l'encodage « %s »."
-#: commands/dbcommands.c:744
+#: commands/dbcommands.c:754
#, c-format
msgid "The chosen LC_COLLATE setting requires encoding \"%s\"."
msgstr "Le paramètre LC_COLLATE choisi nécessite l'encodage « %s »."
-#: commands/dbcommands.c:804
+#: commands/dbcommands.c:815
#, c-format
msgid "database \"%s\" does not exist, skipping"
msgstr "la base de données « %s » n'existe pas, poursuite du traitement"
-#: commands/dbcommands.c:828
+#: commands/dbcommands.c:839
#, c-format
msgid "cannot drop a template database"
msgstr "ne peut pas supprimer une base de données modèle"
-#: commands/dbcommands.c:834
+#: commands/dbcommands.c:845
#, c-format
msgid "cannot drop the currently open database"
msgstr "ne peut pas supprimer la base de données actuellement ouverte"
-#: commands/dbcommands.c:844
+#: commands/dbcommands.c:858
#, c-format
-msgid "database \"%s\" is used by a logical replication slot"
-msgstr "la base de données « %s » est utilisée par un slot de réplication logique"
+msgid "database \"%s\" is used by an active logical replication slot"
+msgstr "la base de données « %s » est utilisée par un slot de réplication logique actif"
-#: commands/dbcommands.c:846
+#: commands/dbcommands.c:860
#, c-format
-msgid "There is %d slot, %d of them active."
-msgid_plural "There are %d slots, %d of them active."
-msgstr[0] "Il existe %d slot, et %d actifs."
-msgstr[1] "Il existe %d slots, et %d actifs."
+msgid "There is %d active slot"
+msgid_plural "There are %d active slots"
+msgstr[0] "Il existe %d slot actif"
+msgstr[1] "Il existe %d slots actifs"
-#: commands/dbcommands.c:860 commands/dbcommands.c:1004 commands/dbcommands.c:1135
+#: commands/dbcommands.c:874 commands/dbcommands.c:1038 commands/dbcommands.c:1168
#, c-format
msgid "database \"%s\" is being accessed by other users"
msgstr "la base de données « %s » est en cours d'utilisation par d'autres utilisateurs"
-#: commands/dbcommands.c:973
+#: commands/dbcommands.c:887
+#, c-format
+msgid "database \"%s\" is being used by logical replication subscription"
+msgstr "la base de données « %s » est utilisée par une souscription de réplication logique"
+
+#: commands/dbcommands.c:889
+#, c-format
+msgid "There is %d subscription."
+msgid_plural "There are %d subscriptions."
+msgstr[0] "Il existe %d souscription."
+msgstr[1] "Il existe %d souscriptions."
+
+#: commands/dbcommands.c:1007
#, c-format
msgid "permission denied to rename database"
msgstr "droit refusé pour le renommage de la base de données"
-#: commands/dbcommands.c:993
+#: commands/dbcommands.c:1027
#, c-format
msgid "current database cannot be renamed"
msgstr "la base de données actuelle ne peut pas être renommée"
-#: commands/dbcommands.c:1091
+#: commands/dbcommands.c:1124
#, c-format
msgid "cannot change the tablespace of the currently open database"
msgstr "ne peut pas modifier le tablespace de la base de données actuellement ouverte"
-#: commands/dbcommands.c:1194
+#: commands/dbcommands.c:1227
#, c-format
msgid "some relations of database \"%s\" are already in tablespace \"%s\""
msgstr ""
"certaines relations de la base de données « %s » sont déjà dans le\n"
"tablespace « %s »"
-#: commands/dbcommands.c:1196
+#: commands/dbcommands.c:1229
#, c-format
msgid "You must move them back to the database's default tablespace before using this command."
msgstr ""
"Vous devez d'abord les déplacer dans le tablespace par défaut de la base\n"
"de données avant d'utiliser cette commande."
-#: commands/dbcommands.c:1325 commands/dbcommands.c:1868 commands/dbcommands.c:2072 commands/dbcommands.c:2120 commands/tablespace.c:606
+#: commands/dbcommands.c:1355 commands/dbcommands.c:1900 commands/dbcommands.c:2104 commands/dbcommands.c:2159 commands/tablespace.c:604
#, c-format
msgid "some useless files may be left behind in old database directory \"%s\""
msgstr ""
"certains fichiers inutiles pourraient se trouver dans l'ancien répertoire\n"
"de la base de données « %s »"
-#: commands/dbcommands.c:1440
+#: commands/dbcommands.c:1475
#, c-format
msgid "option \"%s\" cannot be specified with other options"
msgstr "l'option « %s » ne peut pas être spécifié avec d'autres options"
-#: commands/dbcommands.c:1494
+#: commands/dbcommands.c:1530
#, c-format
msgid "cannot disallow connections for current database"
msgstr "ne peut pas désactiver les connexions pour la base de données courante"
-#: commands/dbcommands.c:1634
+#: commands/dbcommands.c:1667
#, c-format
msgid "permission denied to change owner of database"
msgstr "droit refusé pour modifier le propriétaire de la base de données"
-#: commands/dbcommands.c:1955
+#: commands/dbcommands.c:1987
#, c-format
msgid "There are %d other session(s) and %d prepared transaction(s) using the database."
msgstr "%d autres sessions et %d transactions préparées utilisent la base de données."
-#: commands/dbcommands.c:1958
+#: commands/dbcommands.c:1990
#, c-format
msgid "There is %d other session using the database."
msgid_plural "There are %d other sessions using the database."
msgstr[0] "%d autre session utilise la base de données."
msgstr[1] "%d autres sessions utilisent la base de données."
-#: commands/dbcommands.c:1963
+#: commands/dbcommands.c:1995
#, c-format
msgid "There is %d prepared transaction using the database."
msgid_plural "There are %d prepared transactions using the database."
msgstr[0] "%d transaction préparée utilise la base de données"
msgstr[1] "%d transactions préparées utilisent la base de données"
-#: commands/define.c:54 commands/define.c:228 commands/define.c:260 commands/define.c:288
+#: commands/define.c:54 commands/define.c:228 commands/define.c:260 commands/define.c:288 commands/define.c:334
#, c-format
msgid "%s requires a parameter"
msgstr "%s requiert un paramètre"
@@ -6130,73 +6159,78 @@ msgstr "l'argument de %s doit être un nom de type"
msgid "invalid argument for %s: \"%s\""
msgstr "argument invalide pour %s : « %s »"
-#: commands/dropcmds.c:112 commands/functioncmds.c:1203 utils/adt/ruleutils.c:2080
+#: commands/dropcmds.c:104 commands/functioncmds.c:1201 utils/adt/ruleutils.c:2452
#, c-format
msgid "\"%s\" is an aggregate function"
msgstr "« %s » est une fonction d'agrégat"
-#: commands/dropcmds.c:114
+#: commands/dropcmds.c:106
#, c-format
msgid "Use DROP AGGREGATE to drop aggregate functions."
msgstr "Utiliser DROP AGGREGATE pour supprimer les fonctions d'agrégat."
-#: commands/dropcmds.c:165 commands/sequence.c:424 commands/tablecmds.c:2378 commands/tablecmds.c:2529 commands/tablecmds.c:2571 commands/tablecmds.c:11524 tcop/utility.c:1119
+#: commands/dropcmds.c:157 commands/sequence.c:442 commands/tablecmds.c:2697 commands/tablecmds.c:2848 commands/tablecmds.c:2891 commands/tablecmds.c:12449 tcop/utility.c:1168
#, c-format
msgid "relation \"%s\" does not exist, skipping"
msgstr "la relation « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:195 commands/dropcmds.c:296 commands/tablecmds.c:746
+#: commands/dropcmds.c:187 commands/dropcmds.c:286 commands/tablecmds.c:896
#, c-format
msgid "schema \"%s\" does not exist, skipping"
msgstr "le schéma « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:237 commands/dropcmds.c:276 commands/tablecmds.c:247
+#: commands/dropcmds.c:227 commands/dropcmds.c:266 commands/tablecmds.c:252
#, c-format
msgid "type \"%s\" does not exist, skipping"
msgstr "le type « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:266
+#: commands/dropcmds.c:256
#, c-format
msgid "access method \"%s\" does not exist, skipping"
msgstr "la méthode d'accès « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:284
+#: commands/dropcmds.c:274
#, c-format
msgid "collation \"%s\" does not exist, skipping"
msgstr "le collationnement « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:291
+#: commands/dropcmds.c:281
#, c-format
msgid "conversion \"%s\" does not exist, skipping"
msgstr "la conversion « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:302
+#: commands/dropcmds.c:292
+#, c-format
+msgid "statistics object \"%s\" does not exist, skipping"
+msgstr "l'objet statistique « %s » n'existe pas, poursuite du traitement"
+
+#: commands/dropcmds.c:299
#, c-format
msgid "text search parser \"%s\" does not exist, skipping"
msgstr ""
"l'analyseur de recherche plein texte « %s » n'existe pas, poursuite du\n"
"traitement"
-#: commands/dropcmds.c:309
+#: commands/dropcmds.c:306
#, c-format
msgid "text search dictionary \"%s\" does not exist, skipping"
msgstr ""
"le dictionnaire de recherche plein texte « %s » n'existe pas, poursuite du\n"
"traitement"
-#: commands/dropcmds.c:316
+#: commands/dropcmds.c:313
#, c-format
msgid "text search template \"%s\" does not exist, skipping"
msgstr "le modèle de recherche plein texte « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:323
+#: commands/dropcmds.c:320
#, c-format
msgid "text search configuration \"%s\" does not exist, skipping"
msgstr ""
"la configuration de recherche plein texte « %s » n'existe pas, poursuite du\n"
"traitement"
-#: commands/dropcmds.c:328
+#: commands/dropcmds.c:325
#, c-format
msgid "extension \"%s\" does not exist, skipping"
msgstr "l'extension « %s » n'existe pas, poursuite du traitement"
@@ -6206,390 +6240,400 @@ msgstr "l'extension « %s » n'existe pas, poursuite du traitement"
msgid "function %s(%s) does not exist, skipping"
msgstr "la fonction %s(%s) n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:344
+#: commands/dropcmds.c:348
#, c-format
msgid "aggregate %s(%s) does not exist, skipping"
msgstr "L'agrégat %s(%s) n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:353
+#: commands/dropcmds.c:361
#, c-format
msgid "operator %s does not exist, skipping"
msgstr "l'opérateur %s n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:358
+#: commands/dropcmds.c:367
#, c-format
msgid "language \"%s\" does not exist, skipping"
msgstr "le langage « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:367
+#: commands/dropcmds.c:376
#, c-format
msgid "cast from type %s to type %s does not exist, skipping"
msgstr "la conversion du type %s vers le type %s n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:376
+#: commands/dropcmds.c:385
#, c-format
msgid "transform for type %s language \"%s\" does not exist, skipping"
msgstr "la transformation pour le type %s et le langage « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:384
+#: commands/dropcmds.c:393
#, c-format
msgid "trigger \"%s\" for relation \"%s\" does not exist, skipping"
msgstr "le trigger « %s » de la relation « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:393
+#: commands/dropcmds.c:402
#, c-format
msgid "policy \"%s\" for relation \"%s\" does not exist, skipping"
msgstr "la politique « %s » de la relation « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:400
+#: commands/dropcmds.c:409
#, c-format
msgid "event trigger \"%s\" does not exist, skipping"
msgstr "le trigger sur événement « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:406
+#: commands/dropcmds.c:415
#, c-format
msgid "rule \"%s\" for relation \"%s\" does not exist, skipping"
msgstr "la règle « %s » de la relation « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:413
+#: commands/dropcmds.c:422
#, c-format
msgid "foreign-data wrapper \"%s\" does not exist, skipping"
msgstr "le wrapper de données distantes « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:417
+#: commands/dropcmds.c:426
#, c-format
msgid "server \"%s\" does not exist, skipping"
msgstr "le serveur « %s » n'existe pas, poursuite du traitement"
-#: commands/dropcmds.c:426
+#: commands/dropcmds.c:435
#, c-format
msgid "operator class \"%s\" does not exist for access method \"%s\", skipping"
msgstr "la classe d'opérateur « %s » n'existe pas pour la méthode d'accès « %s », ignoré"
-#: commands/dropcmds.c:438
+#: commands/dropcmds.c:447
#, c-format
msgid "operator family \"%s\" does not exist for access method \"%s\", skipping"
msgstr "la famille d'opérateur « %s » n'existe pas pour la méthode d'accès « %s », ignoré"
-#: commands/event_trigger.c:182
+#: commands/dropcmds.c:454
+#, c-format
+msgid "publication \"%s\" does not exist, skipping"
+msgstr "la publication « %s » n'existe pas, poursuite du traitement"
+
+#: commands/event_trigger.c:185
#, c-format
msgid "permission denied to create event trigger \"%s\""
msgstr "droit refusé pour créer le trigger sur événement « %s »"
-#: commands/event_trigger.c:184
+#: commands/event_trigger.c:187
#, c-format
msgid "Must be superuser to create an event trigger."
msgstr "Doit être super-utilisateur pour créer un trigger sur événement."
-#: commands/event_trigger.c:193
+#: commands/event_trigger.c:196
#, c-format
msgid "unrecognized event name \"%s\""
msgstr "nom d'événement non reconnu : « %s »"
-#: commands/event_trigger.c:210
+#: commands/event_trigger.c:213
#, c-format
msgid "unrecognized filter variable \"%s\""
msgstr "variable « %s » du filtre non reconnu"
-#: commands/event_trigger.c:265
+#: commands/event_trigger.c:268
#, c-format
msgid "filter value \"%s\" not recognized for filter variable \"%s\""
msgstr "valeur de filtre « %s » non reconnu pour la variable de filtre « %s »"
#. translator: %s represents an SQL statement name
-#: commands/event_trigger.c:271 commands/event_trigger.c:341
+#: commands/event_trigger.c:274 commands/event_trigger.c:344
#, c-format
msgid "event triggers are not supported for %s"
msgstr "les triggers sur événemenr ne sont pas supportés pour %s"
-#: commands/event_trigger.c:364
+#: commands/event_trigger.c:367
#, c-format
msgid "filter variable \"%s\" specified more than once"
msgstr "variable « %s » du filtre spécifiée plus d'une fois"
-#: commands/event_trigger.c:512 commands/event_trigger.c:556 commands/event_trigger.c:649
+#: commands/event_trigger.c:514 commands/event_trigger.c:557 commands/event_trigger.c:649
#, c-format
msgid "event trigger \"%s\" does not exist"
msgstr "le trigger sur événement « %s » n'existe pas"
-#: commands/event_trigger.c:617
+#: commands/event_trigger.c:618
#, c-format
msgid "permission denied to change owner of event trigger \"%s\""
msgstr "droit refusé pour modifier le propriétaire du trigger sur événement « %s »"
-#: commands/event_trigger.c:619
+#: commands/event_trigger.c:620
#, c-format
msgid "The owner of an event trigger must be a superuser."
msgstr "Le propriétaire du trigger sur événement doit être un super-utilisateur."
-#: commands/event_trigger.c:1438
+#: commands/event_trigger.c:1464
#, c-format
msgid "%s can only be called in a sql_drop event trigger function"
msgstr "%s peut seulement être appelé dans une fonction de trigger sur événement sql_drop"
-#: commands/event_trigger.c:1558 commands/event_trigger.c:1579
+#: commands/event_trigger.c:1584 commands/event_trigger.c:1605
#, c-format
msgid "%s can only be called in a table_rewrite event trigger function"
msgstr "%s peut seulement être appelé dans une fonction de trigger sur événement table_rewrite"
-#: commands/event_trigger.c:1989
+#: commands/event_trigger.c:2015
#, c-format
msgid "%s can only be called in an event trigger function"
msgstr "%s peut seulement être appelé dans une fonction de trigger sur événement"
-#: commands/explain.c:185
+#: commands/explain.c:194
#, c-format
msgid "unrecognized value for EXPLAIN option \"%s\": \"%s\""
msgstr "valeur non reconnue pour l'option EXPLAIN « %s » : %s"
-#: commands/explain.c:191
+#: commands/explain.c:201
#, c-format
msgid "unrecognized EXPLAIN option \"%s\""
msgstr "option EXPLAIN « %s » non reconnu"
-#: commands/explain.c:198
+#: commands/explain.c:209
#, c-format
msgid "EXPLAIN option BUFFERS requires ANALYZE"
msgstr "l'option BUFFERS d'EXPLAIN nécessite ANALYZE"
-#: commands/explain.c:207
+#: commands/explain.c:218
#, c-format
msgid "EXPLAIN option TIMING requires ANALYZE"
msgstr "l'option TIMING d'EXPLAIN nécessite ANALYZE"
-#: commands/extension.c:155 commands/extension.c:2719
+#: commands/extension.c:168 commands/extension.c:2907
#, c-format
msgid "extension \"%s\" does not exist"
msgstr "l'extension « %s » n'existe pas"
-#: commands/extension.c:254 commands/extension.c:263 commands/extension.c:275 commands/extension.c:285
+#: commands/extension.c:267 commands/extension.c:276 commands/extension.c:288 commands/extension.c:298
#, c-format
msgid "invalid extension name: \"%s\""
msgstr "nom d'extension invalide : « %s »"
-#: commands/extension.c:255
+#: commands/extension.c:268
#, c-format
msgid "Extension names must not be empty."
msgstr "Les noms d'extension ne doivent pas être vides."
-#: commands/extension.c:264
+#: commands/extension.c:277
#, c-format
msgid "Extension names must not contain \"--\"."
msgstr "Les noms d'extension ne doivent pas contenir « -- »."
-#: commands/extension.c:276
+#: commands/extension.c:289
#, c-format
msgid "Extension names must not begin or end with \"-\"."
msgstr "Les noms des extensions ne doivent pas commencer ou finir avec un tiret (« - »)."
-#: commands/extension.c:286
+#: commands/extension.c:299
#, c-format
msgid "Extension names must not contain directory separator characters."
msgstr "Les noms des extensions ne doivent pas contenir des caractères séparateurs de répertoire."
-#: commands/extension.c:301 commands/extension.c:310 commands/extension.c:319 commands/extension.c:329
+#: commands/extension.c:314 commands/extension.c:323 commands/extension.c:332 commands/extension.c:342
#, c-format
msgid "invalid extension version name: \"%s\""
msgstr "nom de version de l'extension invalide : « %s »"
-#: commands/extension.c:302
+#: commands/extension.c:315
#, c-format
msgid "Version names must not be empty."
msgstr "Les noms de version ne doivent pas être vides."
-#: commands/extension.c:311
+#: commands/extension.c:324
#, c-format
msgid "Version names must not contain \"--\"."
msgstr "Les noms de version ne doivent pas contenir « -- »."
-#: commands/extension.c:320
+#: commands/extension.c:333
#, c-format
msgid "Version names must not begin or end with \"-\"."
msgstr "Les noms de version ne doivent ni commencer ni se terminer avec un tiret."
-#: commands/extension.c:330
+#: commands/extension.c:343
#, c-format
msgid "Version names must not contain directory separator characters."
msgstr ""
"Les noms de version ne doivent pas contenir de caractères séparateurs de\n"
"répertoire."
-#: commands/extension.c:480
+#: commands/extension.c:493
#, c-format
msgid "could not open extension control file \"%s\": %m"
msgstr "n'a pas pu ouvrir le fichier de contrôle d'extension « %s » : %m"
-#: commands/extension.c:502 commands/extension.c:512
+#: commands/extension.c:515 commands/extension.c:525
#, c-format
msgid "parameter \"%s\" cannot be set in a secondary extension control file"
msgstr ""
"le paramètre « %s » ne peut pas être configuré dans un fichier de contrôle\n"
"secondaire de l'extension"
-#: commands/extension.c:551
+#: commands/extension.c:564
#, c-format
msgid "\"%s\" is not a valid encoding name"
msgstr "« %s » n'est pas un nom d'encodage valide"
-#: commands/extension.c:565
+#: commands/extension.c:578
#, c-format
msgid "parameter \"%s\" must be a list of extension names"
msgstr "l'argument « %s » doit être une liste de noms d'extension"
-#: commands/extension.c:572
+#: commands/extension.c:585
#, c-format
msgid "unrecognized parameter \"%s\" in file \"%s\""
msgstr "paramètre « %s » non reconnu dans le fichier « %s »"
-#: commands/extension.c:581
+#: commands/extension.c:594
#, c-format
msgid "parameter \"schema\" cannot be specified when \"relocatable\" is true"
msgstr "le paramètre « schema » ne peut pas être indiqué quand « relocatable » est vrai"
-#: commands/extension.c:722
+#: commands/extension.c:761
#, c-format
msgid "transaction control statements are not allowed within an extension script"
msgstr ""
"les instructions de contrôle des transactions ne sont pas autorisées dans un\n"
"script d'extension"
-#: commands/extension.c:790
+#: commands/extension.c:807
#, c-format
msgid "permission denied to create extension \"%s\""
msgstr "droit refusé pour créer l'extension « %s »"
-#: commands/extension.c:792
+#: commands/extension.c:809
#, c-format
msgid "Must be superuser to create this extension."
msgstr "Doit être super-utilisateur pour créer cette extension."
-#: commands/extension.c:796
+#: commands/extension.c:813
#, c-format
msgid "permission denied to update extension \"%s\""
msgstr "droit refusé pour mettre à jour l'extension « %s »"
-#: commands/extension.c:798
+#: commands/extension.c:815
#, c-format
msgid "Must be superuser to update this extension."
msgstr "Doit être super-utilisateur pour mettre à jour cette extension."
-#: commands/extension.c:1080
+#: commands/extension.c:1097
#, c-format
msgid "extension \"%s\" has no update path from version \"%s\" to version \"%s\""
msgstr "l'extension « %s » n'a pas de chemin de mise à jour pour aller de la version « %s » à la version « %s »"
-#: commands/extension.c:1262 commands/extension.c:2779
+#: commands/extension.c:1304 commands/extension.c:2968
#, c-format
msgid "version to install must be specified"
msgstr "la version à installer doit être précisée"
-#: commands/extension.c:1279
+#: commands/extension.c:1326
#, c-format
msgid "FROM version must be different from installation target version \"%s\""
msgstr "la version FROM doit être différente de la version cible d'installation « %s »"
-#: commands/extension.c:1344
+#: commands/extension.c:1391
+#, c-format
+msgid "extension \"%s\" has no installation script nor update path for version \"%s\""
+msgstr "l'extension « %s » n'a pas de script d'installation ou de chemin de de mise à jour pour la version « %s »"
+
+#: commands/extension.c:1426
#, c-format
msgid "extension \"%s\" must be installed in schema \"%s\""
msgstr "l'extension « %s » doit être installée dans le schéma « %s »"
-#: commands/extension.c:1436
+#: commands/extension.c:1579
#, c-format
msgid "cyclic dependency detected between extensions \"%s\" and \"%s\""
msgstr "dépendance cyclique détectée entre les extensions « %s » et « %s »"
-#: commands/extension.c:1441
+#: commands/extension.c:1584
#, c-format
msgid "installing required extension \"%s\""
msgstr "installation de l'extension requise « %s »"
-#: commands/extension.c:1469 commands/extension.c:2924
+#: commands/extension.c:1608
#, c-format
msgid "required extension \"%s\" is not installed"
msgstr "l'extension « %s » requise n'est pas installée"
-#: commands/extension.c:1471
+#: commands/extension.c:1611
#, c-format
msgid "Use CREATE EXTENSION ... CASCADE to install required extensions too."
msgstr "Utilisez CREATE EXTENSION ... CASCADE pour installer également les extensions requises."
-#: commands/extension.c:1535
+#: commands/extension.c:1648
#, c-format
msgid "extension \"%s\" already exists, skipping"
msgstr "l'extension « %s » existe déjà, poursuite du traitement"
-#: commands/extension.c:1542
+#: commands/extension.c:1655
#, c-format
msgid "extension \"%s\" already exists"
msgstr "l'extension « %s » existe déjà"
-#: commands/extension.c:1553
+#: commands/extension.c:1666
#, c-format
msgid "nested CREATE EXTENSION is not supported"
msgstr "CREATE EXTENSION imbriqué n'est pas supporté"
-#: commands/extension.c:1681
+#: commands/extension.c:1847
#, c-format
msgid "cannot drop extension \"%s\" because it is being modified"
msgstr "ne peut pas supprimer l'extension « %s » car il est en cours de modification"
-#: commands/extension.c:2152
+#: commands/extension.c:2349
#, c-format
msgid "pg_extension_config_dump() can only be called from an SQL script executed by CREATE EXTENSION"
msgstr ""
"pg_extension_config_dump() peut seulement être appelé à partir d'un script SQL\n"
"exécuté par CREATE EXTENSION"
-#: commands/extension.c:2164
+#: commands/extension.c:2361
#, c-format
msgid "OID %u does not refer to a table"
msgstr "l'OID %u ne fait pas référence à une table"
-#: commands/extension.c:2169
+#: commands/extension.c:2366
#, c-format
msgid "table \"%s\" is not a member of the extension being created"
msgstr "la table « %s » n'est pas un membre de l'extension en cours de création"
-#: commands/extension.c:2534
+#: commands/extension.c:2722
#, c-format
msgid "cannot move extension \"%s\" into schema \"%s\" because the extension contains the schema"
msgstr ""
"ne peut pas déplacer l'extension « %s » dans le schéma « %s » car l'extension\n"
"contient le schéma"
-#: commands/extension.c:2574 commands/extension.c:2637
+#: commands/extension.c:2763 commands/extension.c:2826
#, c-format
msgid "extension \"%s\" does not support SET SCHEMA"
msgstr "l'extension « %s » ne supporte pas SET SCHEMA"
-#: commands/extension.c:2639
+#: commands/extension.c:2828
#, c-format
msgid "%s is not in the extension's schema \"%s\""
msgstr "%s n'est pas dans le schéma « %s » de l'extension"
-#: commands/extension.c:2699
+#: commands/extension.c:2887
#, c-format
msgid "nested ALTER EXTENSION is not supported"
msgstr "un ALTER EXTENSION imbriqué n'est pas supporté"
-#: commands/extension.c:2790
+#: commands/extension.c:2979
#, c-format
msgid "version \"%s\" of extension \"%s\" is already installed"
msgstr "la version « %s » de l'extension « %s » est déjà installée"
-#: commands/extension.c:3041
+#: commands/extension.c:3230
#, c-format
msgid "cannot add schema \"%s\" to extension \"%s\" because the schema contains the extension"
msgstr ""
"ne peut pas ajouter le schéma « %s » à l'extension « %s » car le schéma\n"
"contient l'extension"
-#: commands/extension.c:3069
+#: commands/extension.c:3258
#, c-format
msgid "%s is not a member of extension \"%s\""
msgstr "%s n'est pas un membre de l'extension « %s »"
-#: commands/extension.c:3135
+#: commands/extension.c:3324
#, c-format
msgid "file \"%s\" is too large"
msgstr "le fichier « %s » est trop gros"
@@ -6621,78 +6665,88 @@ msgstr ""
msgid "The owner of a foreign-data wrapper must be a superuser."
msgstr "Le propriétaire du wrapper de données distantes doit être un super-utilisateur."
-#: commands/foreigncmds.c:292 commands/foreigncmds.c:709 foreign/foreign.c:671
+#: commands/foreigncmds.c:291 commands/foreigncmds.c:706 foreign/foreign.c:667
#, c-format
msgid "foreign-data wrapper \"%s\" does not exist"
msgstr "le wrapper de données distantes « %s » n'existe pas"
-#: commands/foreigncmds.c:584
+#: commands/foreigncmds.c:582
#, c-format
msgid "permission denied to create foreign-data wrapper \"%s\""
msgstr "droit refusé pour la création du wrapper de données distantes « %s »"
-#: commands/foreigncmds.c:586
+#: commands/foreigncmds.c:584
#, c-format
msgid "Must be superuser to create a foreign-data wrapper."
msgstr "Doit être super-utilisateur pour créer un wrapper de données distantes."
-#: commands/foreigncmds.c:699
+#: commands/foreigncmds.c:696
#, c-format
msgid "permission denied to alter foreign-data wrapper \"%s\""
msgstr "droit refusé pour modifier le wrapper de données distantes « %s »"
-#: commands/foreigncmds.c:701
+#: commands/foreigncmds.c:698
#, c-format
msgid "Must be superuser to alter a foreign-data wrapper."
msgstr "Doit être super-utilisateur pour modifier un wrapper de données distantes"
-#: commands/foreigncmds.c:732
+#: commands/foreigncmds.c:729
#, c-format
msgid "changing the foreign-data wrapper handler can change behavior of existing foreign tables"
msgstr ""
"la modification du validateur de wrapper de données distantes peut modifier\n"
"le comportement des tables distantes existantes"
-#: commands/foreigncmds.c:747
+#: commands/foreigncmds.c:744
#, c-format
msgid "changing the foreign-data wrapper validator can cause the options for dependent objects to become invalid"
msgstr ""
"la modification du validateur du wrapper de données distantes peut faire en\n"
"sorte que les options des objets dépendants deviennent invalides"
-#: commands/foreigncmds.c:1165
+#: commands/foreigncmds.c:890
+#, c-format
+msgid "server \"%s\" already exists, skipping"
+msgstr "le serveur « %s » existe déjà, poursuite du traitement"
+
+#: commands/foreigncmds.c:1175
#, c-format
-msgid "user mapping \"%s\" already exists for server %s"
-msgstr "la correspondance utilisateur « %s » existe déjà dans le serveur « %s »"
+msgid "user mapping for \"%s\" already exists for server %s, skipping"
+msgstr "la correspondance utilisateur « %s » existe déjà pour le serveur « %s », ignoré"
-#: commands/foreigncmds.c:1259 commands/foreigncmds.c:1375
+#: commands/foreigncmds.c:1185
#, c-format
-msgid "user mapping \"%s\" does not exist for the server"
+msgid "user mapping for \"%s\" already exists for server %s"
+msgstr "la correspondance utilisateur « %s » existe déjà pour le serveur « %s »"
+
+#: commands/foreigncmds.c:1278 commands/foreigncmds.c:1393
+#, c-format
+msgid "user mapping for \"%s\" does not exist for the server"
msgstr "la correspondance utilisateur « %s » n'existe pas pour le serveur"
-#: commands/foreigncmds.c:1362
+#: commands/foreigncmds.c:1380
#, c-format
msgid "server does not exist, skipping"
msgstr "le serveur n'existe pas, poursuite du traitement"
-#: commands/foreigncmds.c:1380
+#: commands/foreigncmds.c:1398
#, c-format
-msgid "user mapping \"%s\" does not exist for the server, skipping"
+msgid "user mapping for \"%s\" does not exist for the server, skipping"
msgstr ""
"la correspondance utilisateur « %s » n'existe pas pour le serveur, poursuite\n"
"du traitement"
-#: commands/foreigncmds.c:1532 foreign/foreign.c:361
+#: commands/foreigncmds.c:1549 foreign/foreign.c:357
#, c-format
msgid "foreign-data wrapper \"%s\" has no handler"
msgstr "le wrapper de données distantes « %s » n'a pas de gestionnaire"
-#: commands/foreigncmds.c:1538
+#: commands/foreigncmds.c:1555
#, c-format
msgid "foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA"
msgstr "le wrapper de données distantes « %s » ne supporte pas IMPORT FOREIGN SCHEMA"
-#: commands/foreigncmds.c:1631
+#: commands/foreigncmds.c:1658
#, c-format
msgid "importing foreign table \"%s\""
msgstr "import de la table distante « %s »"
@@ -6722,89 +6776,89 @@ msgstr "le type « %s » n'est pas encore défini"
msgid "Creating a shell type definition."
msgstr "Création d'une définition d'un type shell."
-#: commands/functioncmds.c:239
+#: commands/functioncmds.c:233
#, c-format
msgid "SQL function cannot accept shell type %s"
msgstr "la fonction SQL ne peut pas accepter le type shell %s"
-#: commands/functioncmds.c:245
+#: commands/functioncmds.c:239
#, c-format
msgid "aggregate cannot accept shell type %s"
msgstr "l'agrégat ne peut pas accepter le type shell %s"
-#: commands/functioncmds.c:250
+#: commands/functioncmds.c:244
#, c-format
msgid "argument type %s is only a shell"
msgstr "le type d'argument %s est seulement un shell"
-#: commands/functioncmds.c:260
+#: commands/functioncmds.c:254
#, c-format
msgid "type %s does not exist"
msgstr "le type %s n'existe pas"
-#: commands/functioncmds.c:274
+#: commands/functioncmds.c:268
#, c-format
msgid "aggregates cannot accept set arguments"
msgstr "les agrégats ne peuvent pas utiliser des arguments d'ensemble"
-#: commands/functioncmds.c:278
+#: commands/functioncmds.c:272
#, c-format
msgid "functions cannot accept set arguments"
msgstr "les fonctions ne peuvent pas accepter des arguments d'ensemble"
-#: commands/functioncmds.c:288
+#: commands/functioncmds.c:282
#, c-format
msgid "VARIADIC parameter must be the last input parameter"
msgstr "le paramètre VARIADIC doit être le dernier paramètre en entrée"
-#: commands/functioncmds.c:316
+#: commands/functioncmds.c:310
#, c-format
msgid "VARIADIC parameter must be an array"
msgstr "le paramètre VARIADIC doit être un tableau"
-#: commands/functioncmds.c:356
+#: commands/functioncmds.c:350
#, c-format
msgid "parameter name \"%s\" used more than once"
msgstr "le nom du paramètre « %s » est utilisé plus d'une fois"
-#: commands/functioncmds.c:371
+#: commands/functioncmds.c:365
#, c-format
msgid "only input parameters can have default values"
msgstr "seuls les paramètres en entrée peuvent avoir des valeurs par défaut"
-#: commands/functioncmds.c:386
+#: commands/functioncmds.c:380
#, c-format
msgid "cannot use table references in parameter default value"
msgstr ""
"ne peut pas utiliser les références de tables dans la valeur par défaut des\n"
"paramètres"
-#: commands/functioncmds.c:410
+#: commands/functioncmds.c:404
#, c-format
msgid "input parameters after one with a default value must also have defaults"
msgstr "les paramètres en entrée suivant un paramètre avec valeur par défaut doivent aussi avoir des valeurs par défaut"
-#: commands/functioncmds.c:701
+#: commands/functioncmds.c:700
#, c-format
msgid "no function body specified"
msgstr "aucun corps de fonction spécifié"
-#: commands/functioncmds.c:711
+#: commands/functioncmds.c:710
#, c-format
msgid "no language specified"
msgstr "aucun langage spécifié"
-#: commands/functioncmds.c:736 commands/functioncmds.c:1243
+#: commands/functioncmds.c:735 commands/functioncmds.c:1242
#, c-format
msgid "COST must be positive"
msgstr "COST doit être positif"
-#: commands/functioncmds.c:744 commands/functioncmds.c:1251
+#: commands/functioncmds.c:743 commands/functioncmds.c:1250
#, c-format
msgid "ROWS must be positive"
msgstr "ROWS doit être positif"
-#: commands/functioncmds.c:785
+#: commands/functioncmds.c:784
#, c-format
msgid "unrecognized function attribute \"%s\" ignored"
msgstr "l'attribut « %s » non reconnu de la fonction a été ignoré"
@@ -6814,17 +6868,17 @@ msgstr "l'attribut « %s » non reconnu de la fonction a été ignoré"
msgid "only one AS item needed for language \"%s\""
msgstr "seul un élément AS est nécessaire pour le langage « %s »"
-#: commands/functioncmds.c:929 commands/functioncmds.c:2119 commands/proclang.c:563
+#: commands/functioncmds.c:930 commands/functioncmds.c:2131 commands/proclang.c:561
#, c-format
msgid "language \"%s\" does not exist"
msgstr "le langage « %s » n'existe pas"
-#: commands/functioncmds.c:931 commands/functioncmds.c:2121
+#: commands/functioncmds.c:932 commands/functioncmds.c:2133
#, c-format
msgid "Use CREATE LANGUAGE to load the language into the database."
msgstr "Utiliser CREATE LANGUAGE pour charger le langage dans la base de données."
-#: commands/functioncmds.c:966 commands/functioncmds.c:1235
+#: commands/functioncmds.c:967 commands/functioncmds.c:1234
#, c-format
msgid "only superuser can define a leakproof function"
msgstr "seul un superutilisateur peut définir une fonction leakproof"
@@ -6839,361 +6893,361 @@ msgstr "le type de résultat de la fonction doit être %s à cause des paramètr
msgid "function result type must be specified"
msgstr "le type de résultat de la fonction doit être spécifié"
-#: commands/functioncmds.c:1077 commands/functioncmds.c:1255
+#: commands/functioncmds.c:1077 commands/functioncmds.c:1254
#, c-format
msgid "ROWS is not applicable when function does not return a set"
msgstr "ROWS n'est pas applicable quand la fonction ne renvoie pas un ensemble"
-#: commands/functioncmds.c:1412
+#: commands/functioncmds.c:1426
#, c-format
msgid "source data type %s is a pseudo-type"
msgstr "le type de données source %s est un pseudo-type"
-#: commands/functioncmds.c:1418
+#: commands/functioncmds.c:1432
#, c-format
msgid "target data type %s is a pseudo-type"
msgstr "le type de données cible %s est un pseudo-type"
-#: commands/functioncmds.c:1442
+#: commands/functioncmds.c:1456
#, c-format
msgid "cast will be ignored because the source data type is a domain"
msgstr "la conversion sera ignorée car le type de données source est un domaine"
-#: commands/functioncmds