Skip to content

Commit cf8a4d2

Browse files
committed
Merge branch 'REL9_6_STABLE' into PGPRO9_6
2 parents 2149537 + ff2d537 commit cf8a4d2

File tree

14 files changed

+321
-39
lines changed

14 files changed

+321
-39
lines changed

doc/src/sgml/sourcerepo.sgml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
Note that building <productname>&productname;</productname> from the source
2121
repository requires reasonably up-to-date versions of <application>bison</>,
2222
<application>flex</>, and <application>Perl</>. These tools are not needed
23-
to build from a distribution tarball since the files they are used to build
24-
are included in the tarball. Other tool requirements are the same as shown
25-
in <xref linkend="installation">.
23+
to build from a distribution tarball, because the files that these tools
24+
are used to build are included in the tarball. Other tool requirements
25+
are the same as shown in <xref linkend="install-requirements">.
2626
</para>
2727

2828
<sect1 id="git">

doc/src/sgml/storage.sgml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ can be used to examine the information stored in free space maps.
624624
Each heap relation has a Visibility Map
625625
(VM) to keep track of which pages contain only tuples that are known to be
626626
visible to all active transactions; it also keeps track of which pages contain
627-
only unfrozen tuples. It's stored
627+
only frozen tuples. It's stored
628628
alongside the main relation data in a separate relation fork, named after the
629629
filenode number of the relation, plus a <literal>_vm</> suffix. For example,
630630
if the filenode of a relation is 12345, the VM is stored in a file called

src/backend/commands/vacuumlazy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
524524
* safely set for relfrozenxid or relminmxid.
525525
*
526526
* Before entering the main loop, establish the invariant that
527-
* next_unskippable_block is the next block number >= blkno that's not we
527+
* next_unskippable_block is the next block number >= blkno that we
528528
* can't skip based on the visibility map, either all-visible for a
529529
* regular scan or all-frozen for an aggressive scan. We set it to
530530
* nblocks if there's no such block. We also set up the skipping_blocks

src/backend/postmaster/postmaster.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4447,6 +4447,7 @@ internal_forkexec(int argc, char *argv[], Port *port)
44474447
static pid_t
44484448
internal_forkexec(int argc, char *argv[], Port *port)
44494449
{
4450+
int retry_count = 0;
44504451
STARTUPINFO si;
44514452
PROCESS_INFORMATION pi;
44524453
int i;
@@ -4464,6 +4465,9 @@ internal_forkexec(int argc, char *argv[], Port *port)
44644465
Assert(strncmp(argv[1], "--fork", 6) == 0);
44654466
Assert(argv[2] == NULL);
44664467

4468+
/* Resume here if we need to retry */
4469+
retry:
4470+
44674471
/* Set up shared memory for parameter passing */
44684472
ZeroMemory(&sa, sizeof(sa));
44694473
sa.nLength = sizeof(sa);
@@ -4555,22 +4559,26 @@ internal_forkexec(int argc, char *argv[], Port *port)
45554559

45564560
/*
45574561
* Reserve the memory region used by our main shared memory segment before
4558-
* we resume the child process.
4562+
* we resume the child process. Normally this should succeed, but if ASLR
4563+
* is active then it might sometimes fail due to the stack or heap having
4564+
* gotten mapped into that range. In that case, just terminate the
4565+
* process and retry.
45594566
*/
45604567
if (!pgwin32_ReserveSharedMemoryRegion(pi.hProcess))
45614568
{
4562-
/*
4563-
* Failed to reserve the memory, so terminate the newly created
4564-
* process and give up.
4565-
*/
4569+
/* pgwin32_ReserveSharedMemoryRegion already made a log entry */
45664570
if (!TerminateProcess(pi.hProcess, 255))
45674571
ereport(LOG,
45684572
(errmsg_internal("could not terminate process that failed to reserve memory: error code %lu",
45694573
GetLastError())));
45704574
CloseHandle(pi.hProcess);
45714575
CloseHandle(pi.hThread);
4572-
return -1; /* logging done made by
4573-
* pgwin32_ReserveSharedMemoryRegion() */
4576+
if (++retry_count < 100)
4577+
goto retry;
4578+
ereport(LOG,
4579+
(errmsg("giving up after too many tries to reserve shared memory"),
4580+
errhint("This might be caused by ASLR or antivirus software.")));
4581+
return -1;
45744582
}
45754583

45764584
/*

src/backend/replication/syncrep.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,11 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
265265
* WalSender has checked our LSN and has removed us from queue. Clean up
266266
* state and leave. It's OK to reset these shared memory fields without
267267
* holding SyncRepLock, because any walsenders will ignore us anyway when
268-
* we're not on the queue.
268+
* we're not on the queue. We need a read barrier to make sure we see
269+
* the changes to the queue link (this might be unnecessary without
270+
* assertions, but better safe than sorry).
269271
*/
272+
pg_read_barrier();
270273
Assert(SHMQueueIsDetached(&(MyProc->syncRepLinks)));
271274
MyProc->syncRepState = SYNC_REP_NOT_WAITING;
272275
MyProc->waitLSN = 0;
@@ -791,15 +794,22 @@ SyncRepWakeQueue(bool all, int mode)
791794
offsetof(PGPROC, syncRepLinks));
792795

793796
/*
794-
* Set state to complete; see SyncRepWaitForLSN() for discussion of
795-
* the various states.
797+
* Remove thisproc from queue.
796798
*/
797-
thisproc->syncRepState = SYNC_REP_WAIT_COMPLETE;
799+
SHMQueueDelete(&(thisproc->syncRepLinks));
798800

799801
/*
800-
* Remove thisproc from queue.
802+
* SyncRepWaitForLSN() reads syncRepState without holding the lock, so
803+
* make sure that it sees the queue link being removed before the
804+
* syncRepState change.
801805
*/
802-
SHMQueueDelete(&(thisproc->syncRepLinks));
806+
pg_write_barrier();
807+
808+
/*
809+
* Set state to complete; see SyncRepWaitForLSN() for discussion of
810+
* the various states.
811+
*/
812+
thisproc->syncRepState = SYNC_REP_WAIT_COMPLETE;
803813

804814
/*
805815
* Wake only when we have set state and removed from queue.

src/backend/rewrite/rewriteHandler.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ process_matched_tle(TargetEntry *src_tle,
878878
const char *attrName)
879879
{
880880
TargetEntry *result;
881+
CoerceToDomain *coerce_expr = NULL;
881882
Node *src_expr;
882883
Node *prior_expr;
883884
Node *src_input;
@@ -914,10 +915,30 @@ process_matched_tle(TargetEntry *src_tle,
914915
* For FieldStore, instead of nesting we can generate a single
915916
* FieldStore with multiple target fields. We must nest when
916917
* ArrayRefs are involved though.
918+
*
919+
* As a further complication, the destination column might be a domain,
920+
* resulting in each assignment containing a CoerceToDomain node over a
921+
* FieldStore or ArrayRef. These should have matching target domains,
922+
* so we strip them and reconstitute a single CoerceToDomain over the
923+
* combined FieldStore/ArrayRef nodes. (Notice that this has the result
924+
* that the domain's checks are applied only after we do all the field or
925+
* element updates, not after each one. This is arguably desirable.)
917926
*----------
918927
*/
919928
src_expr = (Node *) src_tle->expr;
920929
prior_expr = (Node *) prior_tle->expr;
930+
931+
if (src_expr && IsA(src_expr, CoerceToDomain) &&
932+
prior_expr && IsA(prior_expr, CoerceToDomain) &&
933+
((CoerceToDomain *) src_expr)->resulttype ==
934+
((CoerceToDomain *) prior_expr)->resulttype)
935+
{
936+
/* we assume without checking that resulttypmod/resultcollid match */
937+
coerce_expr = (CoerceToDomain *) src_expr;
938+
src_expr = (Node *) ((CoerceToDomain *) src_expr)->arg;
939+
prior_expr = (Node *) ((CoerceToDomain *) prior_expr)->arg;
940+
}
941+
921942
src_input = get_assignment_input(src_expr);
922943
prior_input = get_assignment_input(prior_expr);
923944
if (src_input == NULL ||
@@ -986,6 +1007,16 @@ process_matched_tle(TargetEntry *src_tle,
9861007
newexpr = NULL;
9871008
}
9881009

1010+
if (coerce_expr)
1011+
{
1012+
/* put back the CoerceToDomain */
1013+
CoerceToDomain *newcoerce = makeNode(CoerceToDomain);
1014+
1015+
memcpy(newcoerce, coerce_expr, sizeof(CoerceToDomain));
1016+
newcoerce->arg = (Expr *) newexpr;
1017+
newexpr = (Node *) newcoerce;
1018+
}
1019+
9891020
result = flatCopyTargetEntry(src_tle);
9901021
result->expr = (Expr *) newexpr;
9911022
return result;

src/backend/storage/ipc/standby.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,14 +586,14 @@ StandbyLockTimeoutHandler(void)
586586
* one transaction on one relation.
587587
*
588588
* We keep a single dynamically expandible list of locks in local memory,
589-
* RelationLockList, so we can keep track of the various entries made by
589+
* RecoveryLockList, so we can keep track of the various entries made by
590590
* the Startup process's virtual xid in the shared lock table.
591591
*
592592
* We record the lock against the top-level xid, rather than individual
593593
* subtransaction xids. This means AccessExclusiveLocks held by aborted
594594
* subtransactions are not released as early as possible on standbys.
595595
*
596-
* List elements use type xl_rel_lock, since the WAL record type exactly
596+
* List elements use type xl_standby_lock, since the WAL record type exactly
597597
* matches the information that we need to keep track of.
598598
*
599599
* We use session locks rather than normal locks so we don't need

src/backend/tsearch/ts_typanalyze.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,17 +232,20 @@ compute_tsvector_stats(VacAttrStats *stats,
232232

233233
/*
234234
* We loop through the lexemes in the tsvector and add them to our
235-
* tracking hashtable. Note: the hashtable entries will point into
236-
* the (detoasted) tsvector value, therefore we cannot free that
237-
* storage until we're done.
235+
* tracking hashtable.
238236
*/
239237
lexemesptr = STRPTR(vector);
240238
curentryptr = ARRPTR(vector);
241239
for (j = 0; j < vector->size; j++)
242240
{
243241
bool found;
244242

245-
/* Construct a hash key */
243+
/*
244+
* Construct a hash key. The key points into the (detoasted)
245+
* tsvector value at this point, but if a new entry is created, we
246+
* make a copy of it. This way we can free the tsvector value
247+
* once we've processed all its lexemes.
248+
*/
246249
hash_key.lexeme = lexemesptr + curentryptr->pos;
247250
hash_key.length = curentryptr->len;
248251

@@ -261,6 +264,9 @@ compute_tsvector_stats(VacAttrStats *stats,
261264
/* Initialize new tracking list element */
262265
item->frequency = 1;
263266
item->delta = b_current - 1;
267+
268+
item->key.lexeme = palloc(hash_key.length);
269+
memcpy(item->key.lexeme, hash_key.lexeme, hash_key.length);
264270
}
265271

266272
/* lexeme_no is the number of elements processed (ie N) */
@@ -276,6 +282,10 @@ compute_tsvector_stats(VacAttrStats *stats,
276282
/* Advance to the next WordEntry in the tsvector */
277283
curentryptr++;
278284
}
285+
286+
/* If the vector was toasted, free the detoasted copy. */
287+
if (TSVectorGetDatum(vector) != value)
288+
pfree(vector);
279289
}
280290

281291
/* We can only compute real stats if we found some non-null values. */
@@ -447,9 +457,12 @@ prune_lexemes_hashtable(HTAB *lexemes_tab, int b_current)
447457
{
448458
if (item->frequency + item->delta <= b_current)
449459
{
460+
char *lexeme = item->key.lexeme;
461+
450462
if (hash_search(lexemes_tab, (const void *) &item->key,
451463
HASH_REMOVE, NULL) == NULL)
452464
elog(ERROR, "hash table corrupted");
465+
pfree(lexeme);
453466
}
454467
}
455468
}

src/backend/utils/adt/ruleutils.c

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5863,8 +5863,11 @@ get_update_query_targetlist_def(Query *query, List *targetList,
58635863
/*
58645864
* We must dig down into the expr to see if it's a PARAM_MULTIEXPR
58655865
* Param. That could be buried under FieldStores and ArrayRefs
5866-
* (cf processIndirection()), and underneath those there could be
5867-
* an implicit type coercion.
5866+
* and CoerceToDomains (cf processIndirection()), and underneath
5867+
* those there could be an implicit type coercion. Because we
5868+
* would ignore implicit type coercions anyway, we don't need to
5869+
* be as careful as processIndirection() is about descending past
5870+
* implicit CoerceToDomains.
58685871
*/
58695872
expr = (Node *) tle->expr;
58705873
while (expr)
@@ -5883,6 +5886,14 @@ get_update_query_targetlist_def(Query *query, List *targetList,
58835886
break;
58845887
expr = (Node *) aref->refassgnexpr;
58855888
}
5889+
else if (IsA(expr, CoerceToDomain))
5890+
{
5891+
CoerceToDomain *cdomain = (CoerceToDomain *) expr;
5892+
5893+
if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
5894+
break;
5895+
expr = (Node *) cdomain->arg;
5896+
}
58865897
else
58875898
break;
58885899
}
@@ -9584,13 +9595,17 @@ get_opclass_name(Oid opclass, Oid actual_datatype,
95849595
*
95859596
* We strip any top-level FieldStore or assignment ArrayRef nodes that
95869597
* appear in the input, printing them as decoration for the base column
9587-
* name (which we assume the caller just printed). Return the subexpression
9588-
* that's to be assigned.
9598+
* name (which we assume the caller just printed). We might also need to
9599+
* strip CoerceToDomain nodes, but only ones that appear above assignment
9600+
* nodes.
9601+
*
9602+
* Returns the subexpression that's to be assigned.
95899603
*/
95909604
static Node *
95919605
processIndirection(Node *node, deparse_context *context)
95929606
{
95939607
StringInfo buf = context->buf;
9608+
CoerceToDomain *cdomain = NULL;
95949609

95959610
for (;;)
95969611
{
@@ -9638,10 +9653,28 @@ processIndirection(Node *node, deparse_context *context)
96389653
*/
96399654
node = (Node *) aref->refassgnexpr;
96409655
}
9656+
else if (IsA(node, CoerceToDomain))
9657+
{
9658+
cdomain = (CoerceToDomain *) node;
9659+
/* If it's an explicit domain coercion, we're done */
9660+
if (cdomain->coercionformat != COERCE_IMPLICIT_CAST)
9661+
break;
9662+
/* Tentatively descend past the CoerceToDomain */
9663+
node = (Node *) cdomain->arg;
9664+
}
96419665
else
96429666
break;
96439667
}
96449668

9669+
/*
9670+
* If we descended past a CoerceToDomain whose argument turned out not to
9671+
* be a FieldStore or array assignment, back up to the CoerceToDomain.
9672+
* (This is not enough to be fully correct if there are nested implicit
9673+
* CoerceToDomains, but such cases shouldn't ever occur.)
9674+
*/
9675+
if (cdomain && node == (Node *) cdomain->arg)
9676+
node = (Node *) cdomain;
9677+
96459678
return node;
96469679
}
96479680

src/backend/utils/sort/tuplesort.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3799,7 +3799,7 @@ tuplesort_heap_siftup(Tuplesortstate *state, bool checkIndex)
37993799
{
38003800
SortTuple *memtuples = state->memtuples;
38013801
SortTuple *tuple;
3802-
int i,
3802+
unsigned int i,
38033803
n;
38043804

38053805
Assert(!checkIndex || state->currentRun == RUN_FIRST);
@@ -3808,12 +3808,17 @@ tuplesort_heap_siftup(Tuplesortstate *state, bool checkIndex)
38083808

38093809
CHECK_FOR_INTERRUPTS();
38103810

3811+
/*
3812+
* state->memtupcount is "int", but we use "unsigned int" for i, j, n.
3813+
* This prevents overflow in the "2 * i + 1" calculation, since at the top
3814+
* of the loop we must have i < n <= INT_MAX <= UINT_MAX/2.
3815+
*/
38113816
n = state->memtupcount;
38123817
tuple = &memtuples[n]; /* tuple that must be reinserted */
38133818
i = 0; /* i is where the "hole" is */
38143819
for (;;)
38153820
{
3816-
int j = 2 * i + 1;
3821+
unsigned int j = 2 * i + 1;
38173822

38183823
if (j >= n)
38193824
break;

src/bin/psql/tab-complete.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3087,13 +3087,9 @@ psql_completion(const char *text, int start, int end)
30873087
COMPLETE_WITH_LIST_CS2("single", "double");
30883088
}
30893089
else if (TailMatchesCS1("\\unset"))
3090-
{
30913090
matches = complete_from_variables(text, "", "", true);
3092-
}
30933091
else if (TailMatchesCS1("\\set"))
3094-
{
30953092
matches = complete_from_variables(text, "", "", false);
3096-
}
30973093
else if (TailMatchesCS2("\\set", MatchAny))
30983094
{
30993095
if (TailMatchesCS1("AUTOCOMMIT|ON_ERROR_STOP|QUIET|"

src/test/modules/commit_ts/t/001_base.pl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Test::More tests => 2;
88
use PostgresNode;
99

10-
my $node = get_new_node();
10+
my $node = get_new_node('foxtrot');
1111
$node->init;
1212
$node->append_conf('postgresql.conf', 'track_commit_timestamp = on');
1313
$node->start;

0 commit comments

Comments
 (0)