@@ -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)
366374WrapperNode * wrap ;
367375Expr * expr ;
368376WalkerContext wcxt ;
369- Index result_rel ;
377+ Index result_rti ;
370378int num_selected ;
371379ParamListInfo 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 &&
379387parse -> commandType != CMD_DELETE ))
380388return ;
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 */
385393if (!rte -> inh )return ;
@@ -406,7 +414,7 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
406414expr = (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 */
412420InitWalkerContext (& wcxt ,prel_expr ,prel ,NULL );
@@ -430,13 +438,14 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
430438Relation child_rel ,
431439parent_rel ;
432440
433- void * tuple_map ;/* we don't need the map itself */
434-
435441LOCKMODE lockmode = RowExclusiveLock ;/* UPDATE | DELETE */
436442
437443HeapTuple syscache_htup ;
438444char child_relkind ;
439445
446+ List * translated_vars ;
447+ adjust_appendrel_varnos_cxt aav_cxt ;
448+
440449/* Lock 'child' table */
441450LockRelationOid (child ,lockmode );
442451
@@ -460,19 +469,23 @@ handle_modification_query(Query *parse, transform_query_cxt *context)
460469child_rel = heap_open (child ,NoLock );
461470parent_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) */
469486heap_close (child_rel ,NoLock );
470487heap_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) */
477490rte -> relid = child ;
478491rte -> 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()