List:Commits« Previous MessageNext Message »
From:Ole John Aske Date:October 26 2010 9:21am
Subject:bzr commit into mysql-5.1-telco-7.0-spj-scan-vs-scan branch
(ole.john.aske:3323)
View as plain text  
#At file:///net/fimafeng09/export/home/tmp/oleja/mysql/mysql-5.1-telco-7.0-spj-scan-scan/ based on revid:ole.john.aske@stripped

 3323 Ole John Aske	2010-10-26
      spj-svs: Added EXPLAIN EXTENDED functionality which add info as warnings about why (parts of) a query is not pushed:
      
      Usage:
       set ndb_join_pushdown = true
      
       EXPLAIN EXTENDED <query>;
       SHOW WARNINGS;

    modified:
      sql/ha_ndbcluster.cc
      sql/ha_ndbcluster.h
      sql/share/errmsg.txt
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc	2010-10-21 08:31:51 +0000
+++ b/sql/ha_ndbcluster.cc	2010-10-26 09:21:10 +0000
@@ -306,6 +306,14 @@ static int ndb_to_mysql_error(const NdbE
   code= ndb_to_mysql_error(&tmp);        \
 }
 
+#define EXPLAIN_NO_PUSH(msgfmt, ...)                              \
+{                                                                 \
+  if (unlikely((current_thd->lex->describe & DESCRIBE_EXTENDED))) \
+  {                                                               \
+    explain_no_push ((msgfmt), __VA_ARGS__);                      \
+  }                                                               \
+}
+
 static int ndbcluster_inited= 0;
 int ndbcluster_terminating= 0;
 
@@ -455,11 +463,21 @@ public:
 class ndb_pushed_builder_ctx
 {
 public:
-  ndb_pushed_builder_ctx(AQP::Join_plan& plan, const AQP::Table_access* const join_root)
-   : m_plan(plan), m_join_root(join_root), m_join_scope(join_root), m_const_scope()
+
+  ndb_pushed_builder_ctx(AQP::Join_plan& plan)
+   : m_plan(plan), m_join_root(), m_join_scope(), m_const_scope()
+  { init_pushability();
+  }
+
+  void set_root(const AQP::Table_access* const join_root)
   {
+    m_join_root= join_root;
+    m_join_scope.clear_all();
+    m_const_scope.clear_all();
+
+    m_join_scope.add(join_root);
     for (uint i= 0; i<join_root->get_access_no(); i++)
-      m_const_scope.add(plan.get_table_access(i));
+      m_const_scope.add(m_plan.get_table_access(i));
   }
 
   const AQP::Join_plan& plan() const
@@ -488,7 +506,10 @@ public:
                   const ndb_table_access_map& old_parents,
                   ndb_table_access_map& parents) const;
 
-  bool field_ref_is_join_pushable(
+  bool is_pushable_as_parent(
+                  const AQP::Table_access* table);
+
+  bool is_pushable_as_child(
                   const AQP::Table_access* table,
                   const Item* join_items[],
                   const AQP::Table_access*& parent);
@@ -506,9 +527,18 @@ public:
     return parents.is_overlapping(m_tables[table->get_access_no()].m_ancestors);
   }
 
+  enum pushability
+  {
+    PUSHABLE_AS_PARENT= 0x01,
+    PUSHABLE_AS_CHILD= 0x02
+  } enum_pushability;
+
+private:
+  void init_pushability();
+
 private:
   const AQP::Join_plan& m_plan;
-  const AQP::Table_access* const m_join_root;
+  const AQP::Table_access* m_join_root;
 
   // Scope of tables covered by this pushed join
   ndb_table_access_map m_join_scope;
@@ -520,12 +550,14 @@ private:
   struct pushed_tables
   {
     pushed_tables() : 
+      m_maybe_pushable(PUSHABLE_AS_CHILD | PUSHABLE_AS_PARENT),
       m_parent(MAX_TABLES), 
       m_ancestors(), 
       m_last_scan_descendant(MAX_TABLES), 
       op(NULL) 
     {}
 
+    int  m_maybe_pushable;
     uint m_parent;
     ndb_table_access_map m_ancestors;
     uint m_last_scan_descendant;
@@ -672,6 +704,17 @@ static bool is_lookup_operation(AQP::enu
           accessType == AQP::AT_UNIQUE_KEY);
 }
 
+static void
+explain_no_push(const char* msgfmt, ...)
+{
+  va_list args;
+  char wbuff[1024];
+  va_start(args,msgfmt);
+  (void) my_vsnprintf (wbuff, sizeof(wbuff), msgfmt, args);
+  va_end(args);
+  push_warning(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, WARN_QUERY_NOT_PUSHED, wbuff);
+} // explain_no_push();
+
 void
 ndb_pushed_builder_ctx::add_pushed(
                   const AQP::Table_access* table,
@@ -682,6 +725,7 @@ ndb_pushed_builder_ctx::add_pushed(
   DBUG_ASSERT(table_no < MAX_TABLES);
   m_join_scope.add(table);
   m_tables[table_no].op= query_op;
+  m_tables[table_no].m_maybe_pushable= 0; // Exclude from further pushing
   if (likely(parent))
   {
     uint parent_no= parent->get_access_no();
@@ -775,9 +819,69 @@ ndb_pushed_builder_ctx::add_parent_candi
   }
 } // ndb_pushed_builder_ctx::add_parent_candidate
 
+/**
+ * Set up the 'm_maybe_pushable' property of each table from the 'Abstract Query Plan' associated
+ * with this ndb_pushed_builder_ctx. A table may be possibly pushable as both:
+ * PUSHABLE_AS_CHILD and/or PUSHABLE_AS_PARENT.
+ * When a table is annotated as not PUSHABLE_AS_... it will be excluded from further
+ * pushability investigation for this specific table.
+ */
+void
+ndb_pushed_builder_ctx::init_pushability()
+{
+  for (uint i= 0; i< m_plan.get_access_count(); i++)
+  {
+    m_tables[i].m_maybe_pushable= 0;
+
+    const TABLE* const table= m_plan.get_table_access(i)->get_table();
+    if (table->file->ht != ndbcluster_hton)
+    {
+      m_tables[i].m_maybe_pushable= 0;
+      EXPLAIN_NO_PUSH("Table %s not in Cluster engine, not pushable", table->alias);
+      continue;
+    }
+    m_tables[i].m_maybe_pushable= static_cast<ha_ndbcluster*>(table->file)->get_pushability();
+  }
+
+  m_tables[0].m_maybe_pushable &= ~PUSHABLE_AS_CHILD;
+  m_tables[m_plan.get_access_count()-1].m_maybe_pushable &= ~PUSHABLE_AS_PARENT;
+} // ndb_pushed_builder_ctx::init_pushability()
+
+
+bool
+ndb_pushed_builder_ctx::is_pushable_as_parent(const AQP::Table_access* table)
+{
+  DBUG_ENTER("::is_pushable_as_parent");
+  uint table_no = table->get_access_no();
+  if ((m_tables[table_no].m_maybe_pushable & PUSHABLE_AS_PARENT) != PUSHABLE_AS_PARENT)
+  {
+    DBUG_PRINT("info", ("Table %d already reported 'not pushable_as_parent'", table_no));
+    DBUG_RETURN(false);
+  }
+
+  const AQP::enum_access_type access_type= table->get_access_type();
+  DBUG_ASSERT(access_type != AQP::AT_VOID);
+
+  if (access_type == AQP::AT_OTHER)
+  {
+    EXPLAIN_NO_PUSH("Table %s is not pushable, unknown access 'type'", table->get_table()->alias);
+    m_tables[table_no].m_maybe_pushable &= ~PUSHABLE_AS_PARENT;
+    DBUG_RETURN(false);
+  }
+  if (access_type == AQP::AT_MULTI_UNIQUE_KEY)
+  {
+    EXPLAIN_NO_PUSH("Table %s is not pushable, access type 'MULTI_UNIQUE_KEY' not implemented",
+                     table->get_table()->alias);
+    m_tables[table_no].m_maybe_pushable &= ~PUSHABLE_AS_PARENT;
+    DBUG_RETURN(false);
+  }
+
+  DBUG_RETURN(true);
+} // ndb_pushed_builder_ctx::is_pushable_as_parent()
+
 
 /***************************************************************
- *  field_ref_is_join_pushable()
+ *  is_pushable_as_child()
  *
  * Determines if the specified child ('table') can be appended to 
  * an existing chain of previously pushed join operations.
@@ -796,21 +900,48 @@ ndb_pushed_builder_ctx::add_parent_candi
  * join_items[] .
  ****************************************************************/
 bool
-ndb_pushed_builder_ctx::field_ref_is_join_pushable(
+ndb_pushed_builder_ctx::is_pushable_as_child(
                            const AQP::Table_access* table,
                            const Item* join_items[ndb_pushed_join::MAX_LINKED_KEYS+1],
                            const AQP::Table_access*& parent)
 {
-  DBUG_ENTER("field_ref_is_join_pushable");
+  DBUG_ENTER("is_pushable_as_child");
   uint tab_no = table->get_access_no();
   parent= NULL;
 
   DBUG_ASSERT (join_root() < table);
 
+  if ((m_tables[tab_no].m_maybe_pushable & PUSHABLE_AS_CHILD) != PUSHABLE_AS_CHILD)
+  {
+    DBUG_PRINT("info", ("Table %s already known 'not is_pushable_as_child'", table->get_table()->alias));
+    DBUG_RETURN(false);
+  }
+
+  AQP::enum_access_type access_type= table->get_access_type();
+  AQP::enum_access_type root_type= join_root()->get_access_type();
+
+  if (!(is_lookup_operation(access_type) || access_type==AQP::AT_ORDERED_INDEX_SCAN))
+  {
+    EXPLAIN_NO_PUSH("Can't push table %s as child, 'type' must be a REF access",
+                     table->get_table()->alias);
+    m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD;
+    DBUG_RETURN(false);
+  }
+     
+  // Currently there is a limitation in not allowing LOOKUP - (index)SCAN operations
+  if (is_lookup_operation(root_type) && access_type==AQP::AT_ORDERED_INDEX_SCAN)
+  {
+    EXPLAIN_NO_PUSH("Push of table %s as scan-child with lookup-root %s not implemented",
+                     table->get_table()->alias, join_root()->get_table()->alias);
+    // 'table' may still be PUSHABLE_AS_CHILD with another parent
+    DBUG_RETURN(false);
+  }
+
   if (table->get_no_of_key_fields() > ndb_pushed_join::MAX_LINKED_KEYS)
   {
-    DBUG_PRINT("info", ("  'key_parts >= ndb_pushed_join::MAX_LINKED_KEYS', "
-                        "can't append table:%d", tab_no+1));
+    EXPLAIN_NO_PUSH("Can't push table %s as child; to many #REF'ed parent fields",
+                     table->get_table()->alias);
+    m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD; // Permanently dissable
     DBUG_RETURN(false);
   }
 
@@ -841,7 +972,7 @@ ndb_pushed_builder_ctx::field_ref_is_joi
     {
       DBUG_PRINT("info", ("  Item type:%d not join_pushable -> can't append table:%d",
                   key_item->type(), tab_no+1));
-      DBUG_RETURN(false);
+      DBUG_RETURN(false);  // TODO, handle gracefull -> continue?
     }
 
     const Item_field* const key_item_field 
@@ -855,7 +986,7 @@ ndb_pushed_builder_ctx::field_ref_is_joi
         ->eq_def(table->get_key_part_info(key_part_no)->field))
     {
       DBUG_PRINT("info", ("Item_field does not have same definition as REF'ed key"));
-      DBUG_RETURN(false);
+      DBUG_RETURN(false);  // TODO, handle gracefull -> continue?
     }
 
     /**
@@ -956,26 +1087,37 @@ ndb_pushed_builder_ctx::field_ref_is_joi
     }
     else
     {
-      DBUG_PRINT("info", ("Item_field %s.%s is outside scope of pushable join",
-                  get_referred_table_access_name(key_item_field),
-                  get_referred_field_name(key_item_field)));
+      EXPLAIN_NO_PUSH("Can't push table %s as child of %s, "
+                      "Item_field '%s.%s' is outside scope of pushable join",
+                       table->get_table()->alias, join_root()->get_table()->alias,
+                       get_referred_table_access_name(key_item_field),
+                       get_referred_field_name(key_item_field));
       DBUG_RETURN(false);
     }
   } // for (uint key_part_no= 0 ...
 
   join_items[table->get_no_of_key_fields()]= NULL;
 
-  if (m_const_scope.contain(current_parents))
+  if (current_parents.is_clear_all())
+  {
+    EXPLAIN_NO_PUSH("Can't push table %s as child; no usable REF'ed parent FIELD_ITEMs",
+                     table->get_table()->alias);
+    m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD;  // Permanently disable as child
+    DBUG_RETURN(false);
+  }
+  else if (m_const_scope.contain(current_parents))
    {
      // NOTE: This is a constant table wrt. this instance of the pushed join.
      //       It should be relatively simple to extend the SPJ block to 
      //       allow such tables to be included in the pushed join.
-    DBUG_PRINT("info", ("  Contain only const/param REFs, -> can't append(yet) as 'const' wrt. pushed join:%d\n",tab_no+1));
+    EXPLAIN_NO_PUSH("Can't push table %s as child of %s, their dependency is 'const'",
+                     table->get_table()->alias, join_root()->get_table()->alias);
     DBUG_RETURN(false);
   }
   else if (parents.is_clear_all())
   {
-    DBUG_PRINT("info", ("  No common parents, -> can't append table to pushed joins:%d\n",tab_no+1));
+    EXPLAIN_NO_PUSH("Can't push table %s as child of %s, no parents found within scope",
+                     table->get_table()->alias, join_root()->get_table()->alias);
     DBUG_RETURN(false);
   }
 
@@ -1022,17 +1164,20 @@ ndb_pushed_builder_ctx::field_ref_is_joi
       if (scan_descendant->get_join_type(parent) == AQP::JT_OUTER_JOIN)
       {
         DBUG_PRINT("info", ("  There are outer joins between parent and artificial parent -> can't append"));
+        EXPLAIN_NO_PUSH("Can't push table %s as child of %s, implementation limitations for outer joins",
+                     table->get_table()->alias, join_root()->get_table()->alias);
         DBUG_RETURN(false);
       }
       parent_no= descendant_no;
 //    parent= scan_descendant;
-      DBUG_PRINT("info", ("  Force artificial grandparent dependency through scan-child %s", scan_descendant->get_table()->alias));
+      DBUG_PRINT("info", ("  Force artificial grandparent dependency through scan-child %s",
+                         scan_descendant->get_table()->alias));
 
       if (scan_descendant && 
          table->get_join_type(scan_descendant) == AQP::JT_OUTER_JOIN)
       {
-        DBUG_PRINT("info", ("  Table scan %d is outer joined with scan-descendant %d, not pushable (yet)",
-                    tab_no, descendant_no));
+        EXPLAIN_NO_PUSH("Can't push table %s as child of %s, outer join with scan-descendant %s not implemented",
+                     table->get_table()->alias, join_root()->get_table()->alias, scan_descendant->get_table()->alias);
         DBUG_RETURN(false);
       }
     }
@@ -1047,13 +1192,17 @@ ndb_pushed_builder_ctx::field_ref_is_joi
       uint ancestor_no= parent_no;
       while (ancestor_no != MAX_TABLES)
       {
+        scan_ancestor= m_plan.get_table_access(ancestor_no);
         if (m_tables[ancestor_no].m_last_scan_descendant < MAX_TABLES)
         {
-          DBUG_PRINT("info", ("  Ancestor tab %d has scan descendants -> can't append", ancestor_no));
+          EXPLAIN_NO_PUSH("Can't push table %s as child of %s, "
+                          "implementation limitations due to bushy scan with %s indirect through %s",
+                           table->get_table()->alias, join_root()->get_table()->alias,
+                           m_plan.get_table_access(m_tables[ancestor_no].m_last_scan_descendant)->get_table()->alias,
+                           scan_ancestor->get_table()->alias);
           DBUG_RETURN(false);
         }
 
-        scan_ancestor= m_plan.get_table_access(ancestor_no);
         if (!is_lookup_operation(scan_ancestor->get_access_type()))
         {
           break; // As adding this scanop was prev. allowed, above ancestor can't be scan bushy
@@ -1067,8 +1216,8 @@ ndb_pushed_builder_ctx::field_ref_is_joi
       if (scan_ancestor && 
          table->get_join_type(scan_ancestor) == AQP::JT_OUTER_JOIN)
       {
-        DBUG_PRINT("info", ("  Table scan %d is outer joined with scan-ancestor %d, not pushable (yet)",
-                    tab_no, ancestor_no));
+        EXPLAIN_NO_PUSH("Can't push table %s as child of %s, outer join with scan-ancestor %s not implemented",
+                     table->get_table()->alias, join_root()->get_table()->alias, scan_ancestor->get_table()->alias);
         DBUG_RETURN(false);
       }
     }
@@ -1152,7 +1301,7 @@ ndb_pushed_builder_ctx::field_ref_is_joi
   } // substitute
 
   DBUG_RETURN(true);
-} // ndb_pushed_builder_ctx::field_ref_is_join_pushable
+} // ndb_pushed_builder_ctx::is_pushable_as_child
 
 
 /**
@@ -1210,44 +1359,20 @@ build_key_map(const NDBTAB* table, const
 } // build_key_map
 
 int
-ha_ndbcluster::make_pushed_join(AQP::Join_plan& plan,
+ha_ndbcluster::make_pushed_join(ndb_pushed_builder_ctx& context,
                                 const AQP::Table_access* const join_root)
 {
   DBUG_ENTER("make_pushed_join");
 
-  if (m_pushed_join_member)  // Already member of another pushed join.
-    DBUG_RETURN(0);
-
-  const AQP::enum_access_type access_type= join_root->get_access_type();
-  DBUG_ASSERT(access_type != AQP::AT_VOID);
+  DBUG_ASSERT (context.is_pushable_as_parent(join_root));
+  context.set_root(join_root);
+  const AQP::Join_plan& plan= context.plan();
 
-  DBUG_PRINT("enter", ("Investigating from table %d as root", join_root->get_access_no()));
-  if (access_type == AQP::AT_OTHER)
-  {
-    DBUG_PRINT("info", ("join_root->get_access_type() == AQP::AT_OTHER"
-                        " -> not pushable"));
-    DBUG_RETURN(0);
-  }
-  if (access_type == AQP::AT_MULTI_UNIQUE_KEY)
-  {
-    DBUG_PRINT("info", ("join_root->get_access_type() == AQP::AT_MULTI_KEY"
-                        " -> not (yet) pushable"));
-    DBUG_RETURN(0);
-  }
-  if (uses_blob_value(table->read_set))
-  {
-    DBUG_PRINT("info", ("'read_set' contain BLOB columns -> not pushable"));
-    DBUG_RETURN(0);
-  }
-  if (m_user_defined_partitioning)
-  {
-    DBUG_PRINT("info", ("Tables has user defined partioning -> not pushable"));
-    DBUG_RETURN(0);
-  }
-
-  DBUG_PRINT("info", ("join_root is pushable:"));
+  DBUG_PRINT("enter", ("Table %d as root is pushable", join_root->get_access_no()));
   DBUG_EXECUTE("info", join_root->dbug_print(););
 
+  const AQP::enum_access_type access_type= join_root->get_access_type();
+
   /**
    * Past this point we know at least join_root to be join pushable 
    * as parent operation. Search for tables to be appendable as child 
@@ -1256,7 +1381,6 @@ ha_ndbcluster::make_pushed_join(AQP::Joi
    * appendable child.
    */
   NdbQueryBuilder builder(*m_thd_ndb->ndb);
-  ndb_pushed_builder_ctx context(plan, join_root);
 
   uint push_cnt= 0;
   uint fld_refs= 0;
@@ -1270,39 +1394,7 @@ ha_ndbcluster::make_pushed_join(AQP::Joi
     const AQP::Table_access* const join_tab= plan.get_table_access(join_cnt);
     const NdbQueryOperationDef* query_op= NULL;
 
-    if (join_tab->get_table()->file->ht != ht)
-    {
-      DBUG_PRINT("info", ("Table %d not same SE, not pushable", join_cnt));
-      continue;
-    }
-
-    const ha_ndbcluster* const handler=
-      static_cast<ha_ndbcluster*>(join_tab->get_table()->file);
-
-    if (handler->m_pushed_join_member)
-    {
-      DBUG_PRINT("info", ("Table %d already contained in another pushed join", join_cnt));
-      continue;
-    }
-    if (handler->uses_blob_value(join_tab->get_table()->read_set))
-    {
-      DBUG_PRINT("info", ("Table %d, 'read_set' contains BLOBs, not pushable", join_cnt));
-      continue;
-    }
-    if (handler->m_user_defined_partitioning)
-    {
-      DBUG_PRINT("info", ("Table %d has user defined partioning, not pushable", join_cnt));
-      continue;
-    }
-    AQP::enum_access_type child_type= join_tab->get_access_type();
-    if (!(is_lookup_operation(child_type)  ||
-          // Currently there is a limitation in not allowing LOOKUP - (index)SCAN operations
-          (child_type==AQP::AT_ORDERED_INDEX_SCAN && !is_lookup_operation(access_type))))
-    {
-      DBUG_PRINT("info", ("Table %d not a pushable access type", join_cnt));
-      continue;
-    }
-    if (!context.field_ref_is_join_pushable(join_tab, join_items, join_parent))
+    if (!context.is_pushable_as_child(join_tab, join_items, join_parent))
     {
       DBUG_PRINT("info", ("Table %d not REF-joined, not pushable", join_cnt));
       continue;
@@ -1386,6 +1478,10 @@ ha_ndbcluster::make_pushed_join(AQP::Joi
     DBUG_PRINT("info", ("Appending child, join_cnt:%d, key_parts:%d", push_cnt, 
                         join_tab->get_no_of_key_fields()));
 
+    DBUG_ASSERT(join_tab->get_table()->file->ht == ht);
+    const ha_ndbcluster* const handler=
+      static_cast<ha_ndbcluster*>(join_tab->get_table()->file);
+
     KEY *key= &handler->table->key_info[join_tab->get_index_no()];
 
     const NdbQueryOperand* linked_key[ndb_pushed_join::MAX_LINKED_KEYS]= {NULL};
@@ -1428,7 +1524,7 @@ ha_ndbcluster::make_pushed_join(AQP::Joi
         if (field->is_real_null())
         {
           DBUG_PRINT("info", ("NULL constValues in key -> not pushable"));
-          DBUG_RETURN(0);
+          DBUG_RETURN(0);  // TODO, handle gracefull -> continue?
         }
         const uchar* const ptr= (field->real_type() == MYSQL_TYPE_VARCHAR)
                 ? field->ptr + ((Field_varstring*)field)->length_bytes
@@ -1472,7 +1568,7 @@ ha_ndbcluster::make_pushed_join(AQP::Joi
           if (unlikely(fld_refs >= ndb_pushed_join::MAX_REFERRED_FIELDS))
           {
             DBUG_PRINT("info", ("Too many Field refs ( >= MAX_REFERRED_FIELDS) encountered"));
-            DBUG_RETURN(0);
+            DBUG_RETURN(0);  // TODO, handle gracefull -> continue?
           }
           referred_fields[fld_refs++]= field_item->field;
           linked_key[map[i]]= builder.paramValue();
@@ -1556,6 +1652,25 @@ ha_ndbcluster::make_pushed_join(AQP::Joi
 } // ha_ndbcluster::make_pushed_join()
 
 
+//ndb_pushed_builder_ctx::enum_pushability
+int
+ha_ndbcluster::get_pushability() const
+{
+  if (uses_blob_value(table->read_set))
+  {
+    EXPLAIN_NO_PUSH("Table %s not pushable, 'read_set' contain BLOB columns", table->alias);
+    return 0;
+  }
+  if (m_user_defined_partitioning)
+  {
+    EXPLAIN_NO_PUSH("Table %s not pushable, has user defined partioning", table->alias);
+    return 0;
+  }
+  return (ndb_pushed_builder_ctx::PUSHABLE_AS_CHILD | 
+          ndb_pushed_builder_ctx::PUSHABLE_AS_PARENT);
+} // ha_ndbcluster::get_pushability()
+
+
 static
 int ndbcluster_make_pushed_join(handlerton *hton, THD* thd,
                                 AQP::Join_plan* plan)
@@ -1565,15 +1680,16 @@ int ndbcluster_make_pushed_join(handlert
   if (!THDVAR(thd, join_pushdown))
     DBUG_RETURN(0);
 
+  ndb_pushed_builder_ctx context(*plan);
   for (uint i= 0; i < plan->get_access_count()-1; i++)
   {
     const AQP::Table_access* const join_root=  plan->get_table_access(i);
-    if (join_root->get_table()->file->ht == ndbcluster_hton)
+    if (context.is_pushable_as_parent(join_root))
     {
       ha_ndbcluster* const handler=
         static_cast<ha_ndbcluster*>(join_root->get_table()->file);
 
-      int error= handler->make_pushed_join(*plan,join_root);
+      int error= handler->make_pushed_join(context,join_root);
       if (unlikely(error))
       {
         handler->print_error(error, MYF(0));

=== modified file 'sql/ha_ndbcluster.h'
--- a/sql/ha_ndbcluster.h	2010-10-15 21:04:14 +0000
+++ b/sql/ha_ndbcluster.h	2010-10-26 09:21:10 +0000
@@ -417,6 +417,8 @@ class ha_ndbcluster: public handler
   ha_ndbcluster(handlerton *hton, TABLE_SHARE *table);
   ~ha_ndbcluster();
 
+  int get_pushability() const;
+
   int ha_initialise();
   void column_bitmaps_signal(uint sig_type);
   int open(const char *name, int mode, uint test_if_locked);
@@ -588,7 +590,7 @@ static void set_tabname(const char *path
  */
   void cond_pop();
 
-  int make_pushed_join(AQP::Join_plan& plan,
+  int make_pushed_join(class ndb_pushed_builder_ctx& context,
                        const AQP::Table_access* const join_root);
 
   bool test_push_flag(enum ha_push_flag flag) const;

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2010-06-16 12:04:53 +0000
+++ b/sql/share/errmsg.txt	2010-10-26 09:21:10 +0000
@@ -6221,3 +6221,5 @@ ER_SLAVE_CONVERSION_FAILED
   eng "Column %d of table '%-.192s.%-.192s' cannot be converted from type '%-.32s' to type '%-.32s'"
 ER_SLAVE_CANT_CREATE_CONVERSION
   eng "Can't create conversion table for table '%-.192s.%-.192s'"
+WARN_QUERY_NOT_PUSHED
+  eng "Table can't be part of pushed join" 


Attachment: [text/bzr-bundle] bzr/ole.john.aske@oracle.com-20101026092110-o4zkofqugr7etdbr.bundle
Thread
bzr commit into mysql-5.1-telco-7.0-spj-scan-vs-scan branch(ole.john.aske:3323) Ole John Aske26 Oct
  • Re: bzr commit into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (ole.john.aske:3323)Magnus Blåudd26 Oct
Re: bzr commit into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (ole.john.aske:3323)Magnus Blåudd27 Oct