@@ -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
98105static 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
103110static void partition_filter_visitor (Plan * plan , void * context );
104111
105112static 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