Hi,
good looks greate, just one question inline.
/ Magnus
On 10/26/2010 11:21 AM, Ole John Aske wrote:
> #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__); \
> + } \
> +}
magnus: reacted on this since using defines are not really recommended.
I suspect that you don't want to call a function just to check the if
and return?
But, why not declare 'explain_no_push' as "static inline" the function
would be inlined, right?
Plus, if trying to avoid "expensive calls", why use 'current_thd' macro
(yes it is) and not pass THD* as first argument to the function?
> +
> 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"
>
>
>
>
>