Skip to content

Commit 10cdc2c

Browse files
authored
Merge branch 'postgres:master' into master
2 parents 0ddd069 + aadf7db commit 10cdc2c

33 files changed

+883
-118
lines changed

contrib/postgres_fdw/deparse.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ static void deparseDistinctExpr(DistinctExpr *node, deparse_expr_cxt *context);
161161
static void deparseScalarArrayOpExpr(ScalarArrayOpExpr *node,
162162
deparse_expr_cxt *context);
163163
static void deparseRelabelType(RelabelType *node, deparse_expr_cxt *context);
164+
static void deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context);
164165
static void deparseBoolExpr(BoolExpr *node, deparse_expr_cxt *context);
165166
static void deparseNullTest(NullTest *node, deparse_expr_cxt *context);
166167
static void deparseCaseExpr(CaseExpr *node, deparse_expr_cxt *context);
@@ -702,6 +703,34 @@ foreign_expr_walker(Node *node,
702703
state = FDW_COLLATE_UNSAFE;
703704
}
704705
break;
706+
case T_ArrayCoerceExpr:
707+
{
708+
ArrayCoerceExpr *e = (ArrayCoerceExpr *) node;
709+
710+
/*
711+
* Recurse to input subexpression.
712+
*/
713+
if (!foreign_expr_walker((Node *) e->arg,
714+
glob_cxt, &inner_cxt, case_arg_cxt))
715+
return false;
716+
717+
/*
718+
* T_ArrayCoerceExpr must not introduce a collation not
719+
* derived from an input foreign Var (same logic as for a
720+
* function).
721+
*/
722+
collation = e->resultcollid;
723+
if (collation == InvalidOid)
724+
state = FDW_COLLATE_NONE;
725+
else if (inner_cxt.state == FDW_COLLATE_SAFE &&
726+
collation == inner_cxt.collation)
727+
state = FDW_COLLATE_SAFE;
728+
else if (collation == DEFAULT_COLLATION_OID)
729+
state = FDW_COLLATE_NONE;
730+
else
731+
state = FDW_COLLATE_UNSAFE;
732+
}
733+
break;
705734
case T_BoolExpr:
706735
{
707736
BoolExpr *b = (BoolExpr *) node;
@@ -2919,6 +2948,9 @@ deparseExpr(Expr *node, deparse_expr_cxt *context)
29192948
case T_RelabelType:
29202949
deparseRelabelType((RelabelType *) node, context);
29212950
break;
2951+
case T_ArrayCoerceExpr:
2952+
deparseArrayCoerceExpr((ArrayCoerceExpr *) node, context);
2953+
break;
29222954
case T_BoolExpr:
29232955
deparseBoolExpr((BoolExpr *) node, context);
29242956
break;
@@ -3507,6 +3539,24 @@ deparseRelabelType(RelabelType *node, deparse_expr_cxt *context)
35073539
node->resulttypmod));
35083540
}
35093541

3542+
/*
3543+
* Deparse an ArrayCoerceExpr (array-type conversion) node.
3544+
*/
3545+
static void
3546+
deparseArrayCoerceExpr(ArrayCoerceExpr *node, deparse_expr_cxt *context)
3547+
{
3548+
deparseExpr(node->arg, context);
3549+
3550+
/*
3551+
* No difference how to deparse explicit cast, but if we omit implicit
3552+
* cast in the query, it'll be more user-friendly
3553+
*/
3554+
if (node->coerceformat != COERCE_IMPLICIT_CAST)
3555+
appendStringInfo(context->buf, "::%s",
3556+
deparse_type_name(node->resulttype,
3557+
node->resulttypmod));
3558+
}
3559+
35103560
/*
35113561
* Deparse a BoolExpr node.
35123562
*/

contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,27 @@ SELECT * FROM ft1 WHERE CASE c3 COLLATE "C" WHEN c6 THEN true ELSE c3 < 'bar' EN
11801180
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
11811181
(4 rows)
11821182

1183+
-- Test array type conversion pushdown
1184+
SET plan_cache_mode = force_generic_plan;
1185+
PREPARE s(varchar[]) AS SELECT count(*) FROM ft2 WHERE c6 = ANY ($1);
1186+
EXPLAIN (VERBOSE, COSTS OFF)
1187+
EXECUTE s(ARRAY['1','2']);
1188+
QUERY PLAN
1189+
---------------------------------------------------------------------------------------------
1190+
Foreign Scan
1191+
Output: (count(*))
1192+
Relations: Aggregate on (public.ft2)
1193+
Remote SQL: SELECT count(*) FROM "S 1"."T 1" WHERE ((c6 = ANY ($1::character varying[])))
1194+
(4 rows)
1195+
1196+
EXECUTE s(ARRAY['1','2']);
1197+
count
1198+
-------
1199+
200
1200+
(1 row)
1201+
1202+
DEALLOCATE s;
1203+
RESET plan_cache_mode;
11831204
-- a regconfig constant referring to this text search configuration
11841205
-- is initially unshippable
11851206
CREATE TEXT SEARCH CONFIGURATION public.custom_search

contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,15 @@ SELECT * FROM ft1 WHERE CASE c3 WHEN c6 THEN true ELSE c3 < 'bar' END;
458458
EXPLAIN (VERBOSE, COSTS OFF)
459459
SELECT * FROM ft1 WHERE CASE c3 COLLATE "C" WHEN c6 THEN true ELSE c3 < 'bar' END;
460460

461+
-- Test array type conversion pushdown
462+
SET plan_cache_mode = force_generic_plan;
463+
PREPARE s(varchar[]) AS SELECT count(*) FROM ft2 WHERE c6 = ANY ($1);
464+
EXPLAIN (VERBOSE, COSTS OFF)
465+
EXECUTE s(ARRAY['1','2']);
466+
EXECUTE s(ARRAY['1','2']);
467+
DEALLOCATE s;
468+
RESET plan_cache_mode;
469+
461470
-- a regconfig constant referring to this text search configuration
462471
-- is initially unshippable
463472
CREATE TEXT SEARCH CONFIGURATION public.custom_search

src/backend/access/transam/xlogreader.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -723,11 +723,12 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
723723
/* Calculate pointer to beginning of next page */
724724
targetPagePtr += XLOG_BLCKSZ;
725725

726-
/* Wait for the next page to become available */
727-
readOff = ReadPageInternal(state, targetPagePtr,
728-
Min(total_len - gotlen + SizeOfXLogShortPHD,
729-
XLOG_BLCKSZ));
730-
726+
/*
727+
* Read the page header before processing the record data, so we
728+
* can handle the case where the previous record ended as being a
729+
* partial one.
730+
*/
731+
readOff = ReadPageInternal(state, targetPagePtr, SizeOfXLogShortPHD);
731732
if (readOff == XLREAD_WOULDBLOCK)
732733
return XLREAD_WOULDBLOCK;
733734
else if (readOff < 0)
@@ -776,6 +777,15 @@ XLogDecodeNextRecord(XLogReaderState *state, bool nonblocking)
776777
goto err;
777778
}
778779

780+
/* Wait for the next page to become available */
781+
readOff = ReadPageInternal(state, targetPagePtr,
782+
Min(total_len - gotlen + SizeOfXLogShortPHD,
783+
XLOG_BLCKSZ));
784+
if (readOff == XLREAD_WOULDBLOCK)
785+
return XLREAD_WOULDBLOCK;
786+
else if (readOff < 0)
787+
goto err;
788+
779789
/* Append the continuation from this page to the buffer */
780790
pageHeaderSize = XLogPageHeaderSize(pageHeader);
781791

src/backend/commands/trigger.c

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static bool GetTupleForTrigger(EState *estate,
8080
ItemPointer tid,
8181
LockTupleMode lockmode,
8282
TupleTableSlot *oldslot,
83+
bool do_epq_recheck,
8384
TupleTableSlot **epqslot,
8485
TM_Result *tmresultp,
8586
TM_FailureData *tmfdp);
@@ -2693,7 +2694,8 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
26932694
HeapTuple fdw_trigtuple,
26942695
TupleTableSlot **epqslot,
26952696
TM_Result *tmresult,
2696-
TM_FailureData *tmfd)
2697+
TM_FailureData *tmfd,
2698+
bool is_merge_delete)
26972699
{
26982700
TupleTableSlot *slot = ExecGetTriggerOldSlot(estate, relinfo);
26992701
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
@@ -2708,9 +2710,17 @@ ExecBRDeleteTriggers(EState *estate, EPQState *epqstate,
27082710
{
27092711
TupleTableSlot *epqslot_candidate = NULL;
27102712

2713+
/*
2714+
* Get a copy of the on-disk tuple we are planning to delete. In
2715+
* general, if the tuple has been concurrently updated, we should
2716+
* recheck it using EPQ. However, if this is a MERGE DELETE action,
2717+
* we skip this EPQ recheck and leave it to the caller (it must do
2718+
* additional rechecking, and might end up executing a different
2719+
* action entirely).
2720+
*/
27112721
if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2712-
LockTupleExclusive, slot, &epqslot_candidate,
2713-
tmresult, tmfd))
2722+
LockTupleExclusive, slot, !is_merge_delete,
2723+
&epqslot_candidate, tmresult, tmfd))
27142724
return false;
27152725

27162726
/*
@@ -2800,6 +2810,7 @@ ExecARDeleteTriggers(EState *estate,
28002810
tupleid,
28012811
LockTupleExclusive,
28022812
slot,
2813+
false,
28032814
NULL,
28042815
NULL,
28052816
NULL);
@@ -2944,7 +2955,8 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
29442955
HeapTuple fdw_trigtuple,
29452956
TupleTableSlot *newslot,
29462957
TM_Result *tmresult,
2947-
TM_FailureData *tmfd)
2958+
TM_FailureData *tmfd,
2959+
bool is_merge_update)
29482960
{
29492961
TriggerDesc *trigdesc = relinfo->ri_TrigDesc;
29502962
TupleTableSlot *oldslot = ExecGetTriggerOldSlot(estate, relinfo);
@@ -2965,10 +2977,17 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
29652977
{
29662978
TupleTableSlot *epqslot_candidate = NULL;
29672979

2968-
/* get a copy of the on-disk tuple we are planning to update */
2980+
/*
2981+
* Get a copy of the on-disk tuple we are planning to update. In
2982+
* general, if the tuple has been concurrently updated, we should
2983+
* recheck it using EPQ. However, if this is a MERGE UPDATE action,
2984+
* we skip this EPQ recheck and leave it to the caller (it must do
2985+
* additional rechecking, and might end up executing a different
2986+
* action entirely).
2987+
*/
29692988
if (!GetTupleForTrigger(estate, epqstate, relinfo, tupleid,
2970-
lockmode, oldslot, &epqslot_candidate,
2971-
tmresult, tmfd))
2989+
lockmode, oldslot, !is_merge_update,
2990+
&epqslot_candidate, tmresult, tmfd))
29722991
return false; /* cancel the update action */
29732992

29742993
/*
@@ -3142,6 +3161,7 @@ ExecARUpdateTriggers(EState *estate, ResultRelInfo *relinfo,
31423161
tupleid,
31433162
LockTupleExclusive,
31443163
oldslot,
3164+
false,
31453165
NULL,
31463166
NULL,
31473167
NULL);
@@ -3298,6 +3318,7 @@ GetTupleForTrigger(EState *estate,
32983318
ItemPointer tid,
32993319
LockTupleMode lockmode,
33003320
TupleTableSlot *oldslot,
3321+
bool do_epq_recheck,
33013322
TupleTableSlot **epqslot,
33023323
TM_Result *tmresultp,
33033324
TM_FailureData *tmfdp)
@@ -3357,29 +3378,30 @@ GetTupleForTrigger(EState *estate,
33573378
if (tmfd.traversed)
33583379
{
33593380
/*
3360-
* Recheck the tuple using EPQ. For MERGE, we leave this
3361-
* to the caller (it must do additional rechecking, and
3362-
* might end up executing a different action entirely).
3381+
* Recheck the tuple using EPQ, if requested. Otherwise,
3382+
* just return that it was concurrently updated.
33633383
*/
3364-
if (estate->es_plannedstmt->commandType == CMD_MERGE)
3384+
if (do_epq_recheck)
33653385
{
3366-
if (tmresultp)
3367-
*tmresultp = TM_Updated;
3368-
return false;
3386+
*epqslot = EvalPlanQual(epqstate,
3387+
relation,
3388+
relinfo->ri_RangeTableIndex,
3389+
oldslot);
3390+
3391+
/*
3392+
* If PlanQual failed for updated tuple - we must not
3393+
* process this tuple!
3394+
*/
3395+
if (TupIsNull(*epqslot))
3396+
{
3397+
*epqslot = NULL;
3398+
return false;
3399+
}
33693400
}
3370-
3371-
*epqslot = EvalPlanQual(epqstate,
3372-
relation,
3373-
relinfo->ri_RangeTableIndex,
3374-
oldslot);
3375-
3376-
/*
3377-
* If PlanQual failed for updated tuple - we must not
3378-
* process this tuple!
3379-
*/
3380-
if (TupIsNull(*epqslot))
3401+
else
33813402
{
3382-
*epqslot = NULL;
3403+
if (tmresultp)
3404+
*tmresultp = TM_Updated;
33833405
return false;
33843406
}
33853407
}

src/backend/executor/execReplication.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo,
670670
resultRelInfo->ri_TrigDesc->trig_update_before_row)
671671
{
672672
if (!ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
673-
tid, NULL, slot, NULL, NULL))
673+
tid, NULL, slot, NULL, NULL, false))
674674
skip_tuple = true; /* "do nothing" */
675675
}
676676

@@ -746,7 +746,7 @@ ExecSimpleRelationDelete(ResultRelInfo *resultRelInfo,
746746
resultRelInfo->ri_TrigDesc->trig_delete_before_row)
747747
{
748748
skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
749-
tid, NULL, NULL, NULL, NULL);
749+
tid, NULL, NULL, NULL, NULL, false);
750750
}
751751

752752
if (!skip_tuple)

src/backend/executor/nodeModifyTable.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1474,7 +1474,8 @@ ExecDeletePrologue(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
14741474

14751475
return ExecBRDeleteTriggers(context->estate, context->epqstate,
14761476
resultRelInfo, tupleid, oldtuple,
1477-
epqreturnslot, result, &context->tmfd);
1477+
epqreturnslot, result, &context->tmfd,
1478+
context->mtstate->operation == CMD_MERGE);
14781479
}
14791480

14801481
return true;
@@ -2117,7 +2118,8 @@ ExecUpdatePrologue(ModifyTableContext *context, ResultRelInfo *resultRelInfo,
21172118

21182119
return ExecBRUpdateTriggers(context->estate, context->epqstate,
21192120
resultRelInfo, tupleid, oldtuple, slot,
2120-
result, &context->tmfd);
2121+
result, &context->tmfd,
2122+
context->mtstate->operation == CMD_MERGE);
21212123
}
21222124

21232125
return true;

src/backend/storage/lmgr/generate-lwlocknames.pl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
my $output_path = '.';
1111

1212
my $lastlockidx = -1;
13-
my $continue = "\n";
1413

1514
GetOptions('outdir:s' => \$output_path);
1615

@@ -102,10 +101,8 @@
102101
while ($lastlockidx < $lockidx - 1)
103102
{
104103
++$lastlockidx;
105-
$continue = ",\n";
106104
}
107105
$lastlockidx = $lockidx;
108-
$continue = ",\n";
109106

110107
# Add a "Lock" suffix to each lock name, as the C code depends on that
111108
printf $h "#define %-32s (&MainLWLockArray[$lockidx].lock)\n",

0 commit comments

Comments
 (0)