Skip to content

Commit 88fcacb

Browse files
committed
restore compatibility with PostgreSQL 10, refactoring of prepare_expr_state()
1 parent 4ef0128 commit 88fcacb

File tree

6 files changed

+176
-91
lines changed

6 files changed

+176
-91
lines changed

Diff for: pg_compat_available.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/bash
2+
3+
dir=$(dirname $0)
4+
func="$1"
5+
6+
grep -n -r --include=pg_compat.c --include=pg_compat.h $func $dir | head -n1

Diff for: src/include/compat/pg_compat.h

+39-5
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,18 @@
158158
#endif
159159

160160

161+
/*
162+
* CheckValidResultRel()
163+
*/
164+
#if PG_VERSION_NUM >= 100000
165+
#define CheckValidResultRelCompat(rri, cmd) \
166+
CheckValidResultRel((rri), (cmd))
167+
#elif PG_VERSION_NUM >= 90500
168+
#define CheckValidResultRelCompat(rri, cmd) \
169+
CheckValidResultRel((rri)->ri_RelationDesc, (cmd))
170+
#endif
171+
172+
161173
/*
162174
* create_append_path()
163175
*/
@@ -266,7 +278,7 @@ extern void create_plain_partial_paths(PlannerInfo *root,
266278

267279

268280
/*
269-
* ExecBuildProjectionInfo
281+
* ExecBuildProjectionInfo()
270282
*/
271283
#if PG_VERSION_NUM >= 100000
272284
#define ExecBuildProjectionInfoCompat(targetList, econtext, resultSlot, \
@@ -366,7 +378,7 @@ char get_rel_persistence(Oid relid);
366378

367379

368380
/*
369-
* initial_cost_nestloop
381+
* initial_cost_nestloop()
370382
*/
371383
#if PG_VERSION_NUM >= 100000 || (defined(PGPRO_VERSION) && PG_VERSION_NUM >= 90603)
372384
#define initial_cost_nestloop_compat(root, workspace, jointype, outer_path, \
@@ -382,7 +394,7 @@ char get_rel_persistence(Oid relid);
382394

383395

384396
/*
385-
* InitResultRelInfo
397+
* InitResultRelInfo()
386398
*
387399
* for v10 set NULL into 'partition_root' argument to specify that result
388400
* relation is not vanilla partition
@@ -461,7 +473,7 @@ extern int oid_cmp(const void *p1, const void *p2);
461473

462474

463475
/*
464-
* pg_analyze_and_rewrite
476+
* pg_analyze_and_rewrite()
465477
*
466478
* for v10 cast first arg to RawStmt type
467479
*/
@@ -479,7 +491,7 @@ extern int oid_cmp(const void *p1, const void *p2);
479491

480492

481493
/*
482-
* ProcessUtility
494+
* ProcessUtility()
483495
*
484496
* for v10 set NULL into 'queryEnv' argument
485497
*/
@@ -577,6 +589,7 @@ extern AttrNumber *convert_tuples_by_name_map(TupleDesc indesc,
577589
ExecARInsertTriggers((estate), (relinfo), (trigtuple), (recheck_indexes))
578590
#endif
579591

592+
580593
/*
581594
* ExecARDeleteTriggers()
582595
*/
@@ -591,6 +604,7 @@ extern AttrNumber *convert_tuples_by_name_map(TupleDesc indesc,
591604
ExecARDeleteTriggers((estate), (relinfo), (tupleid), (fdw_trigtuple))
592605
#endif
593606

607+
594608
/*
595609
* ExecASInsertTriggers()
596610
*/
@@ -603,6 +617,26 @@ extern AttrNumber *convert_tuples_by_name_map(TupleDesc indesc,
603617
#endif
604618

605619

620+
/*
621+
* map_variable_attnos()
622+
*/
623+
#if PG_VERSION_NUM >= 100000
624+
#define map_variable_attnos_compat(node, varno, \
625+
sublevels_up, map, map_len, \
626+
to_rowtype, found_wholerow) \
627+
map_variable_attnos((node), (varno), \
628+
(sublevels_up), (map), (map_len), \
629+
(to_rowtype), (found_wholerow))
630+
#elif PG_VERSION_NUM >= 90500
631+
#define map_variable_attnos_compat(node, varno, \
632+
sublevels_up, map, map_len, \
633+
to_rowtype, found_wholerow) \
634+
map_variable_attnos((node), (varno), \
635+
(sublevels_up), (map), (map_len), \
636+
(found_wholerow))
637+
#endif
638+
639+
606640

607641
/*
608642
* -------------

Diff for: src/include/relation_info.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ PrelExpressionForRelid(const PartRelationInfo *prel, Index rel_index)
271271
return expr;
272272
}
273273

274+
AttrNumber *PrelExpressionAttributesMap(const PartRelationInfo *prel,
275+
TupleDesc source_tupdesc,
276+
int *map_length);
277+
274278

275279
const PartRelationInfo *refresh_pathman_relation_info(Oid relid,
276280
Datum *values,
@@ -393,8 +397,5 @@ extern bool pg_pathman_enable_bounds_cache;
393397

394398
void init_relation_info_static_data(void);
395399

396-
AttrNumber *build_attributes_map(const PartRelationInfo *prel,
397-
TupleDesc child_tupdesc);
398-
399400

400401
#endif /* RELATION_INFO_H */

Diff for: src/partition_filter.c

+82-60
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ CustomScanMethods partition_filter_plan_methods;
6969
CustomExecMethods partition_filter_exec_methods;
7070

7171
static ExprState *prepare_expr_state(const PartRelationInfo *prel,
72-
EState *estate);
72+
Relation source_rel,
73+
EState *estate,
74+
bool try_map);
7375
static void prepare_rri_for_insert(EState *estate,
7476
ResultRelInfoHolder *rri_holder,
7577
const ResultPartsStorage *rps_storage,
@@ -261,7 +263,6 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage)
261263

262264
/* Open child relation and check if it is a valid target */
263265
child_rel = heap_open(partid, NoLock);
264-
CheckValidResultRel(child_rel, parts_storage->command_type);
265266

266267
/* Build Var translation list for 'inserted_cols' */
267268
make_inh_translation_list(base_rel, child_rel, 0, &translated_vars);
@@ -311,6 +312,10 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage)
311312
/* ri_ConstraintExprs will be initialized by ExecRelCheck() */
312313
child_result_rel_info->ri_ConstraintExprs = NULL;
313314

315+
/* Check that this partition is a valid result relation */
316+
CheckValidResultRelCompat(child_result_rel_info,
317+
parts_storage->command_type);
318+
314319
/* Fill the ResultRelInfo holder */
315320
rri_holder->partid = partid;
316321
rri_holder->result_rel_info = child_result_rel_info;
@@ -446,11 +451,11 @@ select_partition_for_insert(ExprState *expr_state,
446451
elog(ERROR, ERR_PART_ATTR_MULTIPLE);
447452
else if (nparts == 0)
448453
{
449-
partition_relid = create_partitions_for_value(parent_relid,
450-
value, prel->ev_type);
454+
partition_relid = create_partitions_for_value(parent_relid,
455+
value, prel->ev_type);
451456

452-
/* get_pathman_relation_info() will refresh this entry */
453-
invalidate_pathman_relation_info(parent_relid, NULL);
457+
/* get_pathman_relation_info() will refresh this entry */
458+
invalidate_pathman_relation_info(parent_relid, NULL);
454459
}
455460
else partition_relid = parts[0];
456461

@@ -475,23 +480,32 @@ select_partition_for_insert(ExprState *expr_state,
475480
/* This partition might have sub-partitions */
476481
else if (rri_holder->has_children)
477482
{
478-
const PartRelationInfo *sub_prel;
483+
const PartRelationInfo *child_prel;
479484

480485
/* Fetch PartRelationInfo for this partitioned relation */
481-
sub_prel = get_pathman_relation_info(rri_holder->partid);
486+
child_prel = get_pathman_relation_info(rri_holder->partid);
482487

483488
/* Might be a false alarm */
484-
if (!sub_prel)
489+
if (!child_prel)
485490
return rri_holder;
486491

487-
/* Build an expression state if not yet */
492+
/* Build an expression state if it's not ready yet */
488493
if (!rri_holder->expr_state)
489-
rri_holder->expr_state = prepare_expr_state(sub_prel, estate);
494+
{
495+
/* Fetch original topmost parent */
496+
Relation source_rel = parts_storage->base_rri->ri_RelationDesc;
497+
498+
/* Build a partitioning expression state */
499+
rri_holder->expr_state = prepare_expr_state(child_prel,
500+
source_rel,
501+
estate,
502+
true);
503+
}
490504

491505
/* Recursively search for subpartitions */
492506
rri_holder = select_partition_for_insert(rri_holder->expr_state,
493507
econtext, estate,
494-
sub_prel, parts_storage);
508+
child_prel, parts_storage);
495509
}
496510
}
497511
/* Loop until we get some result */
@@ -501,15 +515,45 @@ select_partition_for_insert(ExprState *expr_state,
501515
}
502516

503517
static ExprState *
504-
prepare_expr_state(const PartRelationInfo *prel, EState *estate)
518+
prepare_expr_state(const PartRelationInfo *prel,
519+
Relation source_rel,
520+
EState *estate,
521+
bool try_map)
505522
{
506523
ExprState *expr_state;
507524
MemoryContext old_mcxt;
508525
Node *expr;
509526

510-
/* Change varno in Vars according to range table */
527+
/* Fetch partitioning expression (we don't care about varno) */
511528
expr = PrelExpressionForRelid(prel, PART_EXPR_VARNO);
512529

530+
/* Should we try using map? */
531+
if (try_map)
532+
{
533+
534+
AttrNumber *map;
535+
int map_length;
536+
TupleDesc source_tupdesc = RelationGetDescr(source_rel);
537+
538+
/* Remap expression attributes for source relation */
539+
map = PrelExpressionAttributesMap(prel, source_tupdesc, &map_length);
540+
541+
if (map)
542+
{
543+
bool found_whole_row;
544+
545+
expr = map_variable_attnos_compat(expr, PART_EXPR_VARNO, 0, map,
546+
map_length, InvalidOid,
547+
&found_whole_row);
548+
549+
if (found_whole_row)
550+
elog(ERROR, "unexpected whole-row reference"
551+
" found in partition key");
552+
553+
pfree(map);
554+
}
555+
}
556+
513557
/* Prepare state for expression execution */
514558
old_mcxt = MemoryContextSwitchTo(estate->es_query_cxt);
515559
expr_state = ExecInitExpr((Expr *) expr, NULL);
@@ -595,8 +639,6 @@ partition_filter_create_scan_state(CustomScan *node)
595639
Assert(state->on_conflict_action >= ONCONFLICT_NONE ||
596640
state->on_conflict_action <= ONCONFLICT_UPDATE);
597641

598-
state->expr_state = NULL;
599-
600642
/* There should be exactly one subplan */
601643
Assert(list_length(node->custom_plans) == 1);
602644

@@ -607,55 +649,35 @@ void
607649
partition_filter_begin(CustomScanState *node, EState *estate, int eflags)
608650
{
609651
PartitionFilterState *state = (PartitionFilterState *) node;
610-
const PartRelationInfo *prel;
611652
PlanState *child_state;
653+
ResultRelInfo *current_rri;
654+
Relation current_rel;
655+
const PartRelationInfo *prel;
656+
bool try_map;
612657

613658
/* It's convenient to store PlanState in 'custom_ps' */
614659
child_state = ExecInitNode(state->subplan, estate, eflags);
615660
node->custom_ps = list_make1(child_state);
616661

617-
if (state->expr_state == NULL)
618-
{
619-
/* Fetch PartRelationInfo for this partitioned relation */
620-
prel = get_pathman_relation_info(state->partitioned_table);
662+
/* Fetch current result relation (rri + rel) */
663+
current_rri = estate->es_result_relation_info;
664+
current_rel = current_rri->ri_RelationDesc;
621665

622-
/* Prepare state for expression execution */
623-
if (state->command_type == CMD_UPDATE)
624-
{
625-
/*
626-
* In UPDATE queries we would work with child relation, but
627-
* expression contains varattnos of base relation, so we map
628-
* parent varattnos to child varattnos.
629-
*/
630-
bool found_whole_row;
631-
632-
AttrNumber *map;
633-
Node *expr;
634-
ResultRelInfo *child_rri = estate->es_result_relation_info;
635-
Relation child_rel = child_rri->ri_RelationDesc;
636-
637-
MemoryContext old_mcxt;
638-
639-
map = build_attributes_map(prel, RelationGetDescr(child_rel));
640-
expr = map_variable_attnos(PrelExpressionForRelid(prel, PART_EXPR_VARNO),
641-
PART_EXPR_VARNO, 0, map,
642-
RelationGetDescr(child_rel)->natts,
643-
&found_whole_row);
666+
/* Fetch PartRelationInfo for this partitioned relation */
667+
prel = get_pathman_relation_info(state->partitioned_table);
644668

645-
if (found_whole_row)
646-
elog(ERROR, "unexpected whole-row reference found in partition key");
669+
/*
670+
* In UPDATE queries we have to work with child relation tlist,
671+
* but expression contains varattnos of base relation, so we
672+
* map parent varattnos to child varattnos.
673+
*
674+
* We don't need map if current relation == base relation.
675+
*/
676+
try_map = state->command_type == CMD_UPDATE &&
677+
RelationGetRelid(current_rel) != state->partitioned_table;
647678

648-
/* Prepare state for expression execution */
649-
old_mcxt = MemoryContextSwitchTo(estate->es_query_cxt);
650-
state->expr_state = ExecInitExpr((Expr *) expr, NULL);
651-
MemoryContextSwitchTo(old_mcxt);
652-
}
653-
else
654-
{
655-
/* Simple INSERT, expression based on parent attribute numbers */
656-
state->expr_state = prepare_expr_state(prel, estate);
657-
}
658-
}
679+
/* Build a partitioning expression state */
680+
state->expr_state = prepare_expr_state(prel, current_rel, estate, try_map);
659681

660682
/* Init ResultRelInfo cache */
661683
init_result_parts_storage(&state->result_parts, estate,
@@ -665,6 +687,10 @@ partition_filter_begin(CustomScanState *node, EState *estate, int eflags)
665687
(void *) state,
666688
state->command_type);
667689

690+
/* Don't forget to initialize 'base_rri'! */
691+
state->result_parts.base_rri = current_rri;
692+
693+
/* No warnings yet */
668694
state->warning_triggered = false;
669695
}
670696

@@ -681,10 +707,6 @@ partition_filter_exec(CustomScanState *node)
681707
slot = ExecProcNode(child_ps);
682708
state->subplan_slot = slot;
683709

684-
/* Don't forget to initialize 'base_rri'! */
685-
if (!state->result_parts.base_rri)
686-
state->result_parts.base_rri = estate->es_result_relation_info;
687-
688710
if (state->tup_convert_slot)
689711
ExecClearTuple(state->tup_convert_slot);
690712

0 commit comments

Comments
 (0)