diff -Narup ./021_mariadb-10.4.3-merge_table/sql/ha_partition.cc ./039_mariadb-10.4.3-child_partition_pruning/sql/ha_partition.cc
--- ./021_mariadb-10.4.3-merge_table/sql/ha_partition.cc	2019-03-17 17:33:32.000000000 +0900
+++ ./039_mariadb-10.4.3-child_partition_pruning/sql/ha_partition.cc	2019-03-26 19:33:55.151890300 +0900
@@ -11657,6 +11657,39 @@ int ha_partition::info_push(uint info_ty
 }
 
 
+int ha_partition::set_top_table_and_fields(
+  TABLE *top_table,
+  Field **top_table_field,
+  uint top_table_fields
+) {
+  int error;
+  handler **file, **file_err;
+  DBUG_ENTER("ha_partition::set_top_table_and_fields");
+  if (!set_top_table_fields)
+  {
+    for (file= m_file; *file; file++)
+    {
+      if ((error= (*file)->set_top_table_and_fields(top_table,
+                                                    top_table_field,
+                                                    top_table_fields)))
+      {
+        goto err;
+      }
+    }
+    this->top_table= top_table;
+    this->top_table_field= top_table_field;
+    this->top_table_fields= top_table_fields;
+    set_top_table_fields= TRUE;
+  }
+  DBUG_RETURN(0);
+
+err:
+  for (file_err= m_file; file_err < file; file_err++)
+    (*file_err)->clear_top_table_fields();
+  DBUG_RETURN(error);
+}
+
+
 void ha_partition::clear_top_table_fields()
 {
   handler **file;
@@ -11675,6 +11708,20 @@ void ha_partition::clear_top_table_field
 }
 
 
+bool ha_partition::prune_partitions_for_child(THD *thd, Item *pprune_cond)
+{
+  bool res= FALSE;
+  handler **file;
+  DBUG_ENTER("ha_partition::prune_partitions_for_child");
+
+  for (file= m_file; *file; file++)
+    if (bitmap_is_set(&(m_part_info->read_partitions), (file - m_file)))
+      if ((*file)->prune_partitions_for_child(thd, pprune_cond))
+        res= TRUE;
+  DBUG_RETURN(res);
+}
+
+
 struct st_mysql_storage_engine partition_storage_engine=
 { MYSQL_HANDLERTON_INTERFACE_VERSION };
 
diff -Narup ./021_mariadb-10.4.3-merge_table/sql/ha_partition.h ./039_mariadb-10.4.3-child_partition_pruning/sql/ha_partition.h
--- ./021_mariadb-10.4.3-merge_table/sql/ha_partition.h	2019-03-17 17:34:44.000000000 +0900
+++ ./039_mariadb-10.4.3-child_partition_pruning/sql/ha_partition.h	2019-03-26 19:31:13.988846300 +0900
@@ -1415,7 +1415,11 @@ public:
   */
     virtual const COND *cond_push(const COND *cond);
     virtual void cond_pop();
+    virtual int set_top_table_and_fields(TABLE *top_table,
+                                         Field **top_table_field,
+                                         uint top_table_fields);
     virtual void clear_top_table_fields();
+    virtual bool prune_partitions_for_child(THD *thd, Item *pprune_cond);
     virtual int info_push(uint info_type, void *info);
 
     private:
diff -Narup ./021_mariadb-10.4.3-merge_table/sql/handler.cc ./039_mariadb-10.4.3-child_partition_pruning/sql/handler.cc
--- ./021_mariadb-10.4.3-merge_table/sql/handler.cc	2019-02-25 00:01:04.000000000 +0900
+++ ./039_mariadb-10.4.3-child_partition_pruning/sql/handler.cc	2019-03-26 19:20:00.686857100 +0900
@@ -6925,6 +6925,93 @@ void handler::unlock_shared_ha_data()
     mysql_mutex_unlock(&table_share->LOCK_ha_data);
 }
 
+
+/**
+  Set pointers of the oldest parent table and fields to current handler.
+*/
+
+int handler::set_top_table_and_fields(TABLE *top_table,
+                                      Field **top_table_field,
+                                      uint top_table_fields)
+{
+  DBUG_ENTER("handler::set_top_table_and_fields");
+  DBUG_PRINT("info",("set_top_table_fields: %s",
+    set_top_table_fields ? "TRUE" : "FALSE"));
+  if (!set_top_table_fields)
+  {
+    set_top_table_fields= TRUE;
+    this->top_table= top_table;
+    this->top_table_field= top_table_field;
+    this->top_table_fields= top_table_fields;
+  }
+  DBUG_RETURN(0);
+}
+
+
+/**
+  Clear pointers of the oldest parent table and fields from current handler.
+*/
+
+void handler::clear_top_table_fields()
+{
+  DBUG_ENTER("handler::clear_top_table_fields");
+  DBUG_PRINT("info",("set_top_table_fields: %s",
+    set_top_table_fields ? "TRUE" : "FALSE"));
+  if (set_top_table_fields)
+  {
+    set_top_table_fields= FALSE;
+    top_table= NULL;
+    top_table_field= NULL;
+    top_table_fields= 0;
+  }
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Get a pointer of the oldest parent field from field index of current handler.
+*/
+
+Field *handler::get_top_table_field(uint16 field_index)
+{
+  DBUG_ENTER("handler::get_top_table_field");
+  Field *field;
+  DBUG_PRINT("info",("set_top_table_fields: %s",
+    set_top_table_fields ? "TRUE" : "FALSE"));
+  if (set_top_table_fields)
+  {
+    field = top_table->field[field_index];
+  } else {
+    field = table->field[field_index];
+  }
+  DBUG_RETURN(field);
+}
+
+
+/**
+  Get a pointer of a field of current handler from a field pointer of the
+  oldest handler.
+*/
+
+Field *handler::field_exchange(Field *field)
+{
+  DBUG_ENTER("handler::field_exchange");
+  DBUG_PRINT("info",("set_top_table_fields: %s",
+    set_top_table_fields ? "TRUE" : "FALSE"));
+  if (set_top_table_fields)
+  {
+    if (field->table != top_table)
+      DBUG_RETURN(NULL);
+    if (!(field = top_table_field[field->field_index]))
+      DBUG_RETURN(NULL);
+  } else {
+    if (field->table != table)
+      DBUG_RETURN(NULL);
+  }
+  DBUG_RETURN(field);
+}
+
+
 /** @brief
   Dummy function which accept information about log files which is not need
   by handlers
diff -Narup ./021_mariadb-10.4.3-merge_table/sql/handler.h ./039_mariadb-10.4.3-child_partition_pruning/sql/handler.h
--- ./021_mariadb-10.4.3-merge_table/sql/handler.h	2019-03-18 16:55:58.000000000 +0900
+++ ./039_mariadb-10.4.3-child_partition_pruning/sql/handler.h	2019-03-26 19:02:57.422325000 +0900
@@ -4119,27 +4119,12 @@ public:
  */
  virtual int set_top_table_and_fields(TABLE *top_table,
                                       Field **top_table_field,
-                                      uint top_table_fields)
- {
-   if (!set_top_table_fields)
-   {
-     set_top_table_fields= TRUE;
-     this->top_table= top_table;
-     this->top_table_field= top_table_field;
-     this->top_table_fields= top_table_fields;
-   }
-   return 0;
- }
- virtual void clear_top_table_fields()
- {
-   if (set_top_table_fields)
-   {
-     set_top_table_fields= FALSE;
-     top_table= NULL;
-     top_table_field= NULL;
-     top_table_fields= 0;
-   }
- }
+                                      uint top_table_fields);
+ virtual void clear_top_table_fields();
+ virtual Field *get_top_table_field(uint16 field_index);
+ virtual Field *field_exchange(Field *field);
+ virtual bool prune_partitions_for_child(THD *thd, Item *pprune_cond)
+ { return FALSE; }
 
  /**
    Push down an index condition to the handler.
diff -Narup ./021_mariadb-10.4.3-merge_table/sql/opt_range.cc ./039_mariadb-10.4.3-child_partition_pruning/sql/opt_range.cc
--- ./021_mariadb-10.4.3-merge_table/sql/opt_range.cc	2019-02-25 00:01:06.000000000 +0900
+++ ./039_mariadb-10.4.3-child_partition_pruning/sql/opt_range.cc	2019-03-26 19:14:06.325115400 +0900
@@ -3799,15 +3799,31 @@ bool prune_partitions(THD *thd, TABLE *t
 {
   bool retval= FALSE;
   partition_info *part_info = table->part_info;
+  TABLE *base_table= table;
   DBUG_ENTER("prune_partitions");
+  DBUG_PRINT("info",("partition table: %p", table));
+  DBUG_PRINT("info",("partition table->file: %p", table->file));
 
   if (!part_info)
-    DBUG_RETURN(FALSE); /* not a partitioned table */
+  {
+    /* not a partitioned table */
+    retval= base_table->file->prune_partitions_for_child(thd, pprune_cond);
+    DBUG_RETURN(retval);
+  }
   
   if (!pprune_cond)
   {
     mark_all_partitions_as_used(part_info);
-    DBUG_RETURN(FALSE);
+    retval= base_table->file->prune_partitions_for_child(thd, pprune_cond);
+    DBUG_RETURN(retval);
+  }
+
+  /* get the oldest parent table */
+  while (table->pos_in_table_list->parent_l)
+  {
+    table= table->pos_in_table_list->parent_l->table;
+    DBUG_PRINT("info",("partition table: %p", table));
+    DBUG_PRINT("info",("partition table->file: %p", table->file));
   }
   
   PART_PRUNE_PARAM prune_param;
@@ -3826,7 +3842,8 @@ bool prune_partitions(THD *thd, TABLE *t
   {
     mark_all_partitions_as_used(part_info);
     free_root(&alloc,MYF(0));		// Return memory & allocator
-    DBUG_RETURN(FALSE);
+    retval= base_table->file->prune_partitions_for_child(thd, pprune_cond);
+    DBUG_RETURN(retval);
   }
 
   dbug_tmp_use_all_columns(table, old_sets, 
@@ -3856,19 +3873,28 @@ bool prune_partitions(THD *thd, TABLE *t
 
   tree= pprune_cond->get_mm_tree(range_par, &pprune_cond);
   if (!tree)
+  {
+    DBUG_PRINT("info",("partition !tree"));
     goto all_used;
+  }
 
   if (tree->type == SEL_TREE::IMPOSSIBLE)
   {
+    DBUG_PRINT("info",("partition tree->type == SEL_TREE::IMPOSSIBLE"));
     retval= TRUE;
     goto end;
   }
 
   if (tree->type != SEL_TREE::KEY && tree->type != SEL_TREE::KEY_SMALLER)
+  {
+    DBUG_PRINT("info",("partition tree->type != SEL_TREE::KEY && tree->type !="
+                       " SEL_TREE::KEY_SMALLER"));
     goto all_used;
+  }
 
   if (tree->merges.is_empty())
   {
+    DBUG_PRINT("info",("partition tree->merges is empty"));
     /* Range analysis has produced a single list of intervals. */
     prune_param.arg_stack_end= prune_param.arg_stack;
     prune_param.cur_part_fields= 0;
@@ -3885,6 +3911,8 @@ bool prune_partitions(THD *thd, TABLE *t
   }
   else
   {
+    DBUG_PRINT("info",("partition tree->merges.elements: %u",
+      tree->merges.elements));
     if (tree->merges.elements == 1)
     {
       /* 
@@ -3958,6 +3986,8 @@ end:
     table->all_partitions_pruned_away= true;
     retval= TRUE;
   }
+  if (!retval)
+    retval= base_table->file->prune_partitions_for_child(thd, pprune_cond);
   DBUG_RETURN(retval);
 }
 
@@ -4656,6 +4686,7 @@ static bool fields_ok_for_partition_inde
 
 static bool create_partition_index_description(PART_PRUNE_PARAM *ppar)
 {
+  DBUG_ENTER("create_partition_index_description");
   RANGE_OPT_PARAM *range_par= &(ppar->range_param);
   partition_info *part_info= ppar->part_info;
   uint used_part_fields, used_subpart_fields;
@@ -4698,14 +4729,14 @@ static bool create_partition_index_descr
                                                            total_parts)) ||
       !(ppar->is_subpart_keypart= (my_bool*)alloc_root(alloc, sizeof(my_bool)*
                                                            total_parts)))
-    return TRUE;
+    DBUG_RETURN(TRUE);
  
   if (ppar->subpart_fields)
   {
     my_bitmap_map *buf;
     uint32 bufsize= bitmap_buffer_size(ppar->part_info->num_subparts);
     if (!(buf= (my_bitmap_map*) alloc_root(alloc, bufsize)))
-      return TRUE;
+      DBUG_RETURN(TRUE);
     my_bitmap_init(&ppar->subparts_bitmap, buf, ppar->part_info->num_subparts,
                 FALSE);
   }
@@ -4726,6 +4757,8 @@ static bool create_partition_index_descr
                          key_part->length, key_part->store_length));
 
     key_part->field=        (*field);
+    DBUG_PRINT("info", ("key_part->field->field_name: %s",
+                         key_part->field->field_name));
     key_part->image_type =  Field::itRAW;
     /* 
       We set keypart flag to 0 here as the only HA_PART_KEY_SEG is checked
@@ -4754,12 +4787,12 @@ static bool create_partition_index_descr
   if (!(range_par->min_key= (uchar*)alloc_root(alloc,total_key_len)) ||
       !(range_par->max_key= (uchar*)alloc_root(alloc,total_key_len)))
   {
-    return true;
+    DBUG_RETURN(TRUE);
   }
 
   DBUG_EXECUTE("info", print_partitioning_index(range_par->key_parts,
                                                 range_par->key_parts_end););
-  return FALSE;
+  DBUG_RETURN(FALSE);
 }
 
 
@@ -8447,47 +8480,65 @@ Item_bool_func::get_mm_parts(RANGE_OPT_P
       (value_used_tables= value->used_tables()) &
       ~(param->prev_tables | param->read_tables))
     DBUG_RETURN(0);
-  for (; key_part != end ; key_part++)
-  {
-    if (field->eq(key_part->field))
-    {
-      SEL_ARG *sel_arg=0;
-      if (!tree && !(tree=new (param->thd->mem_root) SEL_TREE(param->mem_root,
-                                                              param->keys)))
-	DBUG_RETURN(0);				// OOM
-      if (!value || !(value_used_tables & ~param->read_tables))
-      {
-        /*
-          We need to restore the runtime mem_root of the thread in this
-          function because it evaluates the value of its argument, while
-          the argument can be any, e.g. a subselect. The subselect
-          items, in turn, assume that all the memory allocated during
-          the evaluation has the same life span as the item itself.
-          TODO: opt_range.cc should not reset thd->mem_root at all.
-        */
-        MEM_ROOT *tmp_root= param->mem_root;
-        param->thd->mem_root= param->old_root;
-        sel_arg= get_mm_leaf(param, key_part->field, key_part, type, value);
-        param->thd->mem_root= tmp_root;
-
-	if (!sel_arg)
-	  continue;
-	if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
-	{
-	  tree->type=SEL_TREE::IMPOSSIBLE;
-	  DBUG_RETURN(tree);
-	}
+  handler *file= key_part->field->table->file;
+  DBUG_PRINT("info",("key_part->field->table->s->db: %s",
+    key_part->field->table->s->db.str));
+  DBUG_PRINT("info",("key_part->field->table->s->table_name: %s",
+    key_part->field->table->s->table_name.str));
+  DBUG_PRINT("info",("field->field_name: %s", field->field_name));
+  Field *child_field = file->field_exchange(field);
+  if (child_field)
+  {
+    DBUG_PRINT("info",("child_field->field_name: %s",
+      child_field->field_name));
+    for (; key_part != end ; key_part++)
+    {
+      DBUG_PRINT("info",("key_part->field->field_name: %s",
+        key_part->field->field_name));
+      DBUG_PRINT("info",("key_part->field->field_index: %u",
+        key_part->field->field_index));
+      if (child_field->eq(key_part->field))
+      {
+        DBUG_PRINT("info",("match field"));
+        SEL_ARG *sel_arg=0;
+        if (!tree &&
+            !(tree=new (param->thd->mem_root) SEL_TREE(param->mem_root,
+                                                       param->keys)))
+          DBUG_RETURN(0);				// OOM
+        if (!value || !(value_used_tables & ~param->read_tables))
+        {
+          /*
+            We need to restore the runtime mem_root of the thread in this
+            function because it evaluates the value of its argument, while
+            the argument can be any, e.g. a subselect. The subselect
+            items, in turn, assume that all the memory allocated during
+            the evaluation has the same life span as the item itself.
+            TODO: opt_range.cc should not reset thd->mem_root at all.
+          */
+          MEM_ROOT *tmp_root= param->mem_root;
+          param->thd->mem_root= param->old_root;
+          sel_arg= get_mm_leaf(param, key_part->field, key_part, type, value);
+          param->thd->mem_root= tmp_root;
+
+          if (!sel_arg)
+            continue;
+          if (sel_arg->type == SEL_ARG::IMPOSSIBLE)
+          {
+            tree->type=SEL_TREE::IMPOSSIBLE;
+            DBUG_RETURN(tree);
+          }
+        }
+        else
+        {
+          // This key may be used later
+          if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY)))
+            DBUG_RETURN(0);			// OOM
+        }
+        sel_arg->part=(uchar) key_part->part;
+        sel_arg->max_part_no= sel_arg->part+1;
+        tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
+        tree->keys_map.set_bit(key_part->key);
       }
-      else
-      {
-	// This key may be used later
-	if (!(sel_arg= new SEL_ARG(SEL_ARG::MAYBE_KEY)))
-	  DBUG_RETURN(0);			// OOM
-      }
-      sel_arg->part=(uchar) key_part->part;
-      sel_arg->max_part_no= sel_arg->part+1;
-      tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
-      tree->keys_map.set_bit(key_part->key);
     }
   }
 
@@ -8560,6 +8611,7 @@ Item_func_like::get_mm_leaf(RANGE_OPT_PA
       field->type_handler() == &type_handler_set)
     DBUG_RETURN(0);
 
+  DBUG_PRINT("info",("value: %p", value));
   /*
     TODO:
     Check if this was a function. This should have be optimized away
