Skip to content

Commit 6afa610

Browse files
committed
attempt to fix performance issues described in issue #164
1 parent 79e11d9 commit 6afa610

File tree

4 files changed

+153
-81
lines changed

4 files changed

+153
-81
lines changed

expected/pathman_rebuild_updates.out

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,10 @@ UPDATE test_updates.test SET b = 0 WHERE val = 1 RETURNING *, tableoid::REGCLASS
4343
EXPLAIN (COSTS OFF) UPDATE test_updates.test SET b = 0 WHERE val = 101;
4444
QUERY PLAN
4545
-----------------------------
46-
Update on test
47-
Update on test
48-
Update on test_11
49-
-> Seq Scan on test
50-
Filter: (val = 101)
46+
Update on test_11
5147
-> Seq Scan on test_11
5248
Filter: (val = 101)
53-
(7 rows)
49+
(3 rows)
5450

5551
UPDATE test_updates.test SET b = 0 WHERE val = 101 RETURNING *, tableoid::REGCLASS;
5652
val | b | tableoid

src/include/compat/pg_compat.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "nodes/pg_list.h"
3030
#include "optimizer/cost.h"
3131
#include "optimizer/paths.h"
32+
#include "optimizer/prep.h"
3233
#include "utils/memutils.h"
3334

3435
/*

src/pg_pathman.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include "miscadmin.h"
2727
#include "optimizer/clauses.h"
2828
#include "optimizer/plancat.h"
29-
#include "optimizer/prep.h"
3029
#include "optimizer/restrictinfo.h"
3130
#include "optimizer/cost.h"
3231
#include "utils/datum.h"

src/planner_tree_modification.c

Lines changed: 150 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ typedef struct
9494
} transform_query_cxt;
9595

9696

97+
typedef struct
98+
{
99+
Index child_varno;
100+
List *translated_vars;
101+
} adjust_appendrel_varnos_cxt;
102+
103+
97104

98105
static bool pathman_transform_query_walker(Node *node, void *context);
99106

@@ -103,6 +110,7 @@ static void handle_modification_query(Query *parse, transform_query_cxt *context
103110
static void partition_filter_visitor(Plan *plan, void *context);
104111

105112
static Node *eval_extern_params_mutator(Node *node, ParamListInfo params);
113+
static bool adjust_appendrel_varnos(Node *node, adjust_appendrel_varnos_cxt *context);
106114

107115

108116
/*
@@ -366,20 +374,20 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
366374
WrapperNode *wrap;
367375
Expr *expr;
368376
WalkerContext wcxt;
369-
Index result_rel;
377+
Index result_rti;
370378
int num_selected;
371379
ParamListInfo params;
372380

373381
/* Fetch index of result relation */
374-
result_rel = parse->resultRelation;
382+
result_rti = parse->resultRelation;
375383

376384
/* Exit if it's not a DELETE or UPDATE query */
377-
if (result_rel == 0 ||
385+
if (result_rti == 0 ||
378386
(parse->commandType != CMD_UPDATE &&
379387
parse->commandType != CMD_DELETE))
380388
return;
381389

382-
rte = rt_fetch(result_rel, parse->rtable);
390+
rte = rt_fetch(result_rti, parse->rtable);
383391

384392
/* Exit if it's DELETE FROM ONLY table */
385393
if (!rte->inh) return;
@@ -406,7 +414,7 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
406414
expr = (Expr *) eval_extern_params_mutator((Node *) expr, params);
407415

408416
/* Prepare partitioning expression */
409-
prel_expr = PrelExpressionForRelid(prel, result_rel);
417+
prel_expr = PrelExpressionForRelid(prel, result_rti);
410418

411419
/* Parse syntax tree and extract partition ranges */
412420
InitWalkerContext(&wcxt, prel_expr, prel, NULL);
@@ -430,13 +438,14 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
430438
Relation child_rel,
431439
parent_rel;
432440

433-
void *tuple_map; /* we don't need the map itself */
434-
435441
LOCKMODE lockmode = RowExclusiveLock; /* UPDATE | DELETE */
436442

437443
HeapTuple syscache_htup;
438444
char child_relkind;
439445

446+
List *translated_vars;
447+
adjust_appendrel_varnos_cxt aav_cxt;
448+
440449
/* Lock 'child' table */
441450
LockRelationOid(child, lockmode);
442451

@@ -460,19 +469,23 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
460469
child_rel = heap_open(child, NoLock);
461470
parent_rel = heap_open(parent, NoLock);
462471

463-
/* Build a conversion map (may be trivial, i.e. NULL) */
464-
tuple_map = build_part_tuple_map(parent_rel, child_rel);
465-
if (tuple_map)
466-
free_conversion_map((TupleConversionMap *) tuple_map);
472+
make_inh_translation_list(parent_rel, child_rel, 0, &translated_vars);
473+
474+
/* Translate varnos for this child */
475+
aav_cxt.child_varno = result_rti;
476+
aav_cxt.translated_vars = translated_vars;
477+
if (adjust_appendrel_varnos((Node *) parse, &aav_cxt))
478+
return; /* failed to perform rewrites */
479+
480+
/* Translate column privileges for this child */
481+
rte->selectedCols = translate_col_privs(rte->selectedCols, translated_vars);
482+
rte->insertedCols = translate_col_privs(rte->insertedCols, translated_vars);
483+
rte->updatedCols = translate_col_privs(rte->updatedCols, translated_vars);
467484

468485
/* Close relations (should remain locked, though) */
469486
heap_close(child_rel, NoLock);
470487
heap_close(parent_rel, NoLock);
471488

472-
/* Exit if tuple map was NOT trivial */
473-
if (tuple_map) /* just checking the pointer! */
474-
return;
475-
476489
/* Update RTE's relid and relkind (for FDW) */
477490
rte->relid = child;
478491
rte->relkind = child_relkind;
@@ -490,6 +503,128 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
490503
}
491504
}
492505

506+
/* Replace extern param nodes with consts */
507+
static Node *
508+
eval_extern_params_mutator(Node *node, ParamListInfo params)
509+
{
510+
if (node == NULL)
511+
return NULL;
512+
513+
if (IsA(node, Param))
514+
{
515+
Param *param = (Param *) node;
516+
517+
Assert(params);
518+
519+
/* Look to see if we've been given a value for this Param */
520+
if (param->paramkind == PARAM_EXTERN &&
521+
param->paramid > 0 &&
522+
param->paramid <= params->numParams)
523+
{
524+
ParamExternData *prm = &params->params[param->paramid - 1];
525+
526+
if (OidIsValid(prm->ptype))
527+
{
528+
/* OK to substitute parameter value? */
529+
if (prm->pflags & PARAM_FLAG_CONST)
530+
{
531+
/*
532+
* Return a Const representing the param value.
533+
* Must copy pass-by-ref datatypes, since the
534+
* Param might be in a memory context
535+
* shorter-lived than our output plan should be.
536+
*/
537+
int16 typLen;
538+
bool typByVal;
539+
Datum pval;
540+
541+
Assert(prm->ptype == param->paramtype);
542+
get_typlenbyval(param->paramtype,
543+
&typLen, &typByVal);
544+
if (prm->isnull || typByVal)
545+
pval = prm->value;
546+
else
547+
pval = datumCopy(prm->value, typByVal, typLen);
548+
return (Node *) makeConst(param->paramtype,
549+
param->paramtypmod,
550+
param->paramcollid,
551+
(int) typLen,
552+
pval,
553+
prm->isnull,
554+
typByVal);
555+
}
556+
}
557+
}
558+
}
559+
560+
return expression_tree_mutator(node, eval_extern_params_mutator,
561+
(void *) params);
562+
}
563+
564+
static bool
565+
adjust_appendrel_varnos(Node *node, adjust_appendrel_varnos_cxt *context)
566+
{
567+
if (node == NULL)
568+
return false;
569+
570+
if (IsA(node, Query))
571+
{
572+
Query *query = (Query *) node;
573+
ListCell *lc;
574+
575+
foreach (lc, query->targetList)
576+
{
577+
TargetEntry *te = (TargetEntry *) lfirst(lc);
578+
Var *child_var;
579+
580+
if (te->resjunk)
581+
continue;
582+
583+
if (te->resno > list_length(context->translated_vars))
584+
return true;
585+
586+
child_var = list_nth(context->translated_vars, te->resno - 1);
587+
if (!child_var)
588+
return true;
589+
590+
/* Transform attribute number */
591+
te->resno = child_var->varattno;
592+
}
593+
594+
return query_tree_walker((Query *) node,
595+
adjust_appendrel_varnos,
596+
context,
597+
QTW_IGNORE_RC_SUBQUERIES);
598+
}
599+
600+
if (IsA(node, Var))
601+
{
602+
Var *var = (Var *) node;
603+
604+
/* Don't tranform system columns & other relations' Vars */
605+
if (var->varoattno > 0 && var->varno == context->child_varno)
606+
{
607+
Var *child_var;
608+
609+
if (var->varattno > list_length(context->translated_vars))
610+
return true;
611+
612+
child_var = list_nth(context->translated_vars, var->varattno - 1);
613+
if (!child_var)
614+
return true;
615+
616+
/* Transform attribute number */
617+
var->varattno = child_var->varattno;
618+
}
619+
620+
return false;
621+
}
622+
623+
return expression_tree_walker(node,
624+
adjust_appendrel_varnos,
625+
context);
626+
}
627+
493628

494629
/*
495630
* -------------------------------
@@ -592,65 +727,6 @@ get_rel_parenthood_status(RangeTblEntry *rte)
592727
}
593728

594729

595-
/* Replace extern param nodes with consts */
596-
static Node *
597-
eval_extern_params_mutator(Node *node, ParamListInfo params)
598-
{
599-
if (node == NULL)
600-
return NULL;
601-
602-
if (IsA(node, Param))
603-
{
604-
Param *param = (Param *) node;
605-
606-
Assert(params);
607-
608-
/* Look to see if we've been given a value for this Param */
609-
if (param->paramkind == PARAM_EXTERN &&
610-
param->paramid > 0 &&
611-
param->paramid <= params->numParams)
612-
{
613-
ParamExternData *prm = &params->params[param->paramid - 1];
614-
615-
if (OidIsValid(prm->ptype))
616-
{
617-
/* OK to substitute parameter value? */
618-
if (prm->pflags & PARAM_FLAG_CONST)
619-
{
620-
/*
621-
* Return a Const representing the param value.
622-
* Must copy pass-by-ref datatypes, since the
623-
* Param might be in a memory context
624-
* shorter-lived than our output plan should be.
625-
*/
626-
int16 typLen;
627-
bool typByVal;
628-
Datum pval;
629-
630-
Assert(prm->ptype == param->paramtype);
631-
get_typlenbyval(param->paramtype,
632-
&typLen, &typByVal);
633-
if (prm->isnull || typByVal)
634-
pval = prm->value;
635-
else
636-
pval = datumCopy(prm->value, typByVal, typLen);
637-
return (Node *) makeConst(param->paramtype,
638-
param->paramtypmod,
639-
param->paramcollid,
640-
(int) typLen,
641-
pval,
642-
prm->isnull,
643-
typByVal);
644-
}
645-
}
646-
}
647-
}
648-
649-
return expression_tree_mutator(node, eval_extern_params_mutator,
650-
(void *) params);
651-
}
652-
653-
654730
/*
655731
* -----------------------------------------------
656732
* Count number of times we've visited planner()

0 commit comments

Comments
 (0)