41
41
#include "parser/parse_oper.h"
42
42
#include "parser/parsetree.h"
43
43
#include "utils/lsyscache.h"
44
+ #include "utils/memutils.h"
44
45
#include "utils/syscache.h"
45
46
46
47
@@ -741,19 +742,52 @@ inheritance_planner(PlannerInfo *root)
741
742
List * rowMarks ;
742
743
List * tlist ;
743
744
PlannerInfo subroot ;
745
+ MemoryContext childcxt ;
744
746
ListCell * l ;
745
747
748
+ /*
749
+ * Memory management here is a bit messy, because the planning process can
750
+ * scribble on both the query parsetree and the rangetable. We need to
751
+ * ensure that each call of grouping_planner gets an un-scribbled-on copy
752
+ * to start with, so we start by copying the given query tree each time
753
+ * (as a byproduct of adjust_appendrel_attrs). However, we also want to
754
+ * make sure that the modified rangetable ultimately gets propagated back
755
+ * to the master copy, to pick up any changes of the Query structures
756
+ * inside subquery RTEs. We do that by copying back the rangetable from
757
+ * the first successful child planning step. (We are effectively assuming
758
+ * that sub-Queries will get planned identically each time, or at least
759
+ * that the impacts on their rangetables will be the same each time.)
760
+ *
761
+ * Another consideration is that when there are a lot of child tables, we
762
+ * can eat a lot of memory this way. To fix that, we create a child
763
+ * memory context that can be reset between steps to recover memory, at
764
+ * the cost of having to copy the completed plan trees out to the parent
765
+ * context.
766
+ */
767
+ childcxt = AllocSetContextCreate (CurrentMemoryContext ,
768
+ "Inheritance child planning context" ,
769
+ ALLOCSET_DEFAULT_MINSIZE ,
770
+ ALLOCSET_DEFAULT_INITSIZE ,
771
+ ALLOCSET_DEFAULT_MAXSIZE );
772
+
746
773
foreach (l , root -> append_rel_list )
747
774
{
748
775
AppendRelInfo * appinfo = (AppendRelInfo * ) lfirst (l );
749
776
Plan * subplan ;
777
+ MemoryContext oldcxt ;
750
778
751
779
/* append_rel_list contains all append rels; ignore others */
752
780
if (appinfo -> parent_relid != parentRTindex )
753
781
continue ;
754
782
755
783
/*
756
- * Generate modified query with this rel as target.
784
+ * Discard any cruft generated in previous loop iterations.
785
+ */
786
+ MemoryContextReset (childcxt );
787
+ oldcxt = MemoryContextSwitchTo (childcxt );
788
+
789
+ /*
790
+ * Generate modified query (in childcxt) with this rel as target.
757
791
*/
758
792
memcpy (& subroot , root , sizeof (PlannerInfo ));
759
793
subroot .parse = (Query * )
@@ -767,24 +801,32 @@ inheritance_planner(PlannerInfo *root)
767
801
/* and we haven't created PlaceHolderInfos, either */
768
802
Assert (subroot .placeholder_list == NIL );
769
803
770
- /* Generate plan */
804
+ /* Generate plan (also in childcxt) */
771
805
subplan = grouping_planner (& subroot , 0.0 /* retrieve all tuples */ );
772
806
807
+ MemoryContextSwitchTo (oldcxt );
808
+
773
809
/*
774
810
* If this child rel was excluded by constraint exclusion, exclude it
775
811
* from the plan.
776
812
*/
777
813
if (is_dummy_plan (subplan ))
778
814
continue ;
779
815
780
- /* Save rtable from first rel for use below */
816
+ /*
817
+ * Be sure to copy what we need out of the child context.
818
+ */
819
+ subplan = copyObject (subplan );
820
+
821
+ /* Save rtable from first child to install in parent after the loop */
781
822
if (subplans == NIL )
782
- rtable = subroot .parse -> rtable ;
823
+ rtable = copyObject ( subroot .parse -> rtable ) ;
783
824
784
825
subplans = lappend (subplans , subplan );
785
826
786
827
/* Make sure any initplans from this rel get into the outer list */
787
- root -> init_plans = list_concat (root -> init_plans , subroot .init_plans );
828
+ root -> init_plans = list_concat (root -> init_plans ,
829
+ copyObject (subroot .init_plans ));
788
830
789
831
/* Build target-relations list for the executor */
790
832
resultRelations = lappend_int (resultRelations , appinfo -> child_relid );
@@ -794,14 +836,18 @@ inheritance_planner(PlannerInfo *root)
794
836
{
795
837
List * rlist ;
796
838
839
+ rlist = copyObject (subroot .parse -> returningList );
797
840
rlist = set_returning_clause_references (root -> glob ,
798
- subroot . parse -> returningList ,
841
+ rlist ,
799
842
subplan ,
800
843
appinfo -> child_relid );
801
844
returningLists = lappend (returningLists , rlist );
802
845
}
803
846
}
804
847
848
+ /* Done with child context */
849
+ MemoryContextDelete (childcxt );
850
+
805
851
root -> resultRelations = resultRelations ;
806
852
807
853
/* Mark result as unordered (probably unnecessary) */
@@ -824,15 +870,7 @@ inheritance_planner(PlannerInfo *root)
824
870
}
825
871
826
872
/*
827
- * Planning might have modified the rangetable, due to changes of the
828
- * Query structures inside subquery RTEs. We have to ensure that this
829
- * gets propagated back to the master copy. But can't do this until we
830
- * are done planning, because all the calls to grouping_planner need
831
- * virgin sub-Queries to work from. (We are effectively assuming that
832
- * sub-Queries will get planned identically each time, or at least that
833
- * the impacts on their rangetables will be the same each time.)
834
- *
835
- * XXX should clean this up someday
873
+ * Install modified rangetable from first child into parent parsetree.
836
874
*/
837
875
parse -> rtable = rtable ;
838
876
0 commit comments