3183 Ole John Aske 2010-06-22
Prevent prepared pushed joins to be instantiated & executed if any of
the parameter values are the NULL value.
modified:
mysql-test/suite/ndb/r/ndb_join_pushdown.result
mysql-test/suite/ndb/t/ndb_join_pushdown.test
sql/ha_ndbcluster.cc
3182 Ole John Aske 2010-06-22
Moved ha_ndbcluster::check_if_pushable() and ha_ndbcluster::check_is_pushed()
together with rest of methods in ha_ndbcluster.cc used to determine
pushability of a set of JOIN_TAB's - NO CODE CHANGE!
modified:
sql/ha_ndbcluster.cc
3181 Ole John Aske 2010-06-22
Key items refering parents in the 'const_scope' incorrectly caused
the 'parent' map to be cleared. This later caused this operation to
be considdered to be non pushable.
modified:
mysql-test/suite/ndb/r/ndb_join_pushdown.result
mysql-test/suite/ndb/t/ndb_join_pushdown.test
sql/ha_ndbcluster.cc
3180 Ole John Aske 2010-06-22
Recommited:
Fixed bug related to (non-)pushability of joins with NULL values
as part of the EQ_REF lookup key.
We have to catch the case where a constant value 'is NULL', and prevent
that operation from being join pushed.
modified:
mysql-test/suite/ndb/r/ndb_join_pushdown.result
mysql-test/suite/ndb/t/ndb_join_pushdown.test
sql/ha_ndbcluster.cc
=== modified file 'mysql-test/suite/ndb/r/ndb_join_pushdown.result'
--- a/mysql-test/suite/ndb/r/ndb_join_pushdown.result 2010-06-22 09:29:41 +0000
+++ b/mysql-test/suite/ndb/r/ndb_join_pushdown.result 2010-06-22 12:23:04 +0000
@@ -1871,6 +1871,23 @@ select straight_join *
from t3 as X JOIN t3 as Y on X.c3 = Y.c3
where Y.b3 is NULL;
a3 b3 c3 d3 a3 b3 c3 d3
+explain
+select straight_join * from
+t3 as X1
+JOIN t3 as Y1 on X1.b3 = Y1.b3 and X1.d3 = Y1.d3
+JOIN t3 as X2 on X2.b3 = Y1.b3
+JOIN t3 as Y2 on Y2.b3 = X2.c3 and Y2.d3 = X1.c3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE X1 ALL b3,c3,c3_2 NULL NULL NULL 7 Parent of 2 pushed join@1
+1 SIMPLE Y1 ref b3 b3 9 test.X1.b3,test.X1.d3 1 Child of pushed join@1; Using where
+1 SIMPLE X2 ref b3,c3,c3_2 b3 4 test.X1.b3 1 Parent of 2 pushed join@2
+1 SIMPLE Y2 ref b3 b3 9 test.X2.c3,test.X1.c3 1 Child of pushed join@2; Using where
+select straight_join * from
+t3 as X1
+JOIN t3 as Y1 on X1.b3 = Y1.b3 and X1.d3 = Y1.d3
+JOIN t3 as X2 on X2.b3 = Y1.b3
+JOIN t3 as Y2 on Y2.b3 = X2.c3 and Y2.d3 = X1.c3;
+a3 b3 c3 d3 a3 b3 c3 d3 a3 b3 c3 d3 a3 b3 c3 d3
drop table t3;
create table t1 (a int primary key, b int, c int, index(b,c)) engine = ndb;
insert into t1 values (1,null, 2);
=== modified file 'mysql-test/suite/ndb/t/ndb_join_pushdown.test'
--- a/mysql-test/suite/ndb/t/ndb_join_pushdown.test 2010-06-22 09:29:41 +0000
+++ b/mysql-test/suite/ndb/t/ndb_join_pushdown.test 2010-06-22 12:23:04 +0000
@@ -1208,6 +1208,23 @@ select straight_join *
from t3 as X JOIN t3 as Y on X.c3 = Y.c3
where Y.b3 is NULL;
+## Will break up query in 2 pushed joins.
+## Last join (JOIN t3 as Y2) refer X1.c3 which will
+## be handled as a constant paramValue wrt. scope of the
+## second pushed join.
+explain
+select straight_join * from
+ t3 as X1
+ JOIN t3 as Y1 on X1.b3 = Y1.b3 and X1.d3 = Y1.d3
+ JOIN t3 as X2 on X2.b3 = Y1.b3
+ JOIN t3 as Y2 on Y2.b3 = X2.c3 and Y2.d3 = X1.c3;
+--sorted_result
+select straight_join * from
+ t3 as X1
+ JOIN t3 as Y1 on X1.b3 = Y1.b3 and X1.d3 = Y1.d3
+ JOIN t3 as X2 on X2.b3 = Y1.b3
+ JOIN t3 as Y2 on Y2.b3 = X2.c3 and Y2.d3 = X1.c3;
+
drop table t3;
####################
=== modified file 'sql/ha_ndbcluster.cc'
--- a/sql/ha_ndbcluster.cc 2010-06-22 09:29:41 +0000
+++ b/sql/ha_ndbcluster.cc 2010-06-22 12:23:04 +0000
@@ -902,7 +902,14 @@ ndb_pushed_builder_ctx::field_ref_is_joi
if (parents.is_clear_all())
break;
}
- else if (!m_const_scope.contain(parent_map))
+ else if (m_const_scope.contain(parent_map))
+ {
+ // This key item is const. and did not cause the set of possible parents
+ // to be recalculated. Reuse what we had before this key item.
+ DBUG_ASSERT(parents.is_clear_all());
+ parents= old_parents;
+ }
+ else
{
DBUG_PRINT("info", ("Item_field %s.%s is outside scope of pushable join",
get_referred_table_access_name(key_item_field),
@@ -1402,6 +1409,117 @@ int ndbcluster_make_pushed_join(handlert
} // ndbcluster_make_pushed_join
+/**
+ * C++98 does not allow forward declarations of enum types. By using this
+ * class instead of using NdbQueryOperationDef::Type directly,
+ * ha_ndbcluster.h avoids including NdbQueryBuilder.h.
+ */
+class NdbQueryOperationTypeWrapper
+{
+public:
+ /** Implcit conversion from NdbQueryOperationDef::Type.*/
+ NdbQueryOperationTypeWrapper(NdbQueryOperationDef::Type type)
+ :m_type(type)
+ {}
+
+ /** Implcit conversion to NdbQueryOperationDef::Type.*/
+ operator NdbQueryOperationDef::Type() const
+ { return m_type; }
+
+private:
+ const NdbQueryOperationDef::Type m_type;
+};
+
+
+/**
+ * Check if this table access operation (and a number of succeding operation)
+ * can be pushed to the cluster and executed there. This requires that there
+ * is an NdbQueryDefiniton and that it still matches the corresponds to the
+ * type of operation that we intend to execute. (The MySQL server will
+ * sometimes change its mind and replace a scan with a lookup or vice versa
+ * as it works its way into the nested loop join.)
+ *
+ * @param type This is the operation type that the server want to execute.
+ * @param idx Index used whenever relevant for operation type
+ * @return True if the operation may be pushed.
+ */
+bool
+ha_ndbcluster::check_if_pushable(const NdbQueryOperationTypeWrapper& type, uint idx) const
+{
+ bool pushable= FALSE;
+
+ if (m_pushed_join != NULL)
+ {
+ const NdbQueryOperationDef* const root_operation=
+ m_pushed_join->get_query_def().getQueryOperation(0U);
+
+ const NdbQueryOperationTypeWrapper& query_def_type= root_operation->getType();
+
+ if (query_def_type == type)
+ {
+ if (m_disable_pushed_join)
+ {
+ DBUG_PRINT("info", ("Push disabled (HA_EXTRA_KEYREAD)"));
+ }
+ else
+ {
+ const NdbDictionary::Index* const expected_index= root_operation->getIndex();
+ pushable= TRUE;
+
+ switch (type)
+ {
+ case NdbQueryOperationDef::PrimaryKeyAccess:
+ DBUG_ASSERT(idx==table->s->primary_key);
+ break;
+ case NdbQueryOperationDef::UniqueIndexAccess:
+ DBUG_ASSERT(idx<MAX_KEY);
+// DBUG_ASSERT(m_index[idx].unique_index == expected_index);
+ pushable= (m_index[idx].unique_index == expected_index);
+ break;
+ case NdbQueryOperationDef::TableScan:
+ DBUG_ASSERT (idx==MAX_KEY);
+ break;
+ case NdbQueryOperationDef::OrderedIndexScan:
+ DBUG_ASSERT(idx<MAX_KEY);
+// DBUG_ASSERT(m_index[idx].index == expected_index);
+ pushable= (m_index[idx].index == expected_index);
+ break;
+ default:
+ DBUG_ASSERT(false);
+ break;
+ }
+
+ if (likely(pushable))
+ {
+ // There may be referrences to Field values from tables outside the scope of
+ // our pushed join which are supplied as paramValues().
+ // If any of these are NULL values, join can't be pushed
+ for (uint i= 0; i < m_pushed_join->get_field_referrences_count(); i++)
+ {
+ Field* field= m_pushed_join->get_field_ref(i);
+ if (field->is_real_null())
+ {
+ DBUG_PRINT("info", ("paramValue is NULL, can not execute as pushed join"));
+ pushable= false;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info",
+ ("Cannot execute push join. Root operation prepared as %s "
+ "not executable as %s w/ index %d",
+ NdbQueryOperationDef::getTypeName(query_def_type),
+ NdbQueryOperationDef::getTypeName(type), idx));
+ }
+ }
+ return pushable;
+}
+
+
static
bool
is_shrinked_varchar(const Field *field)
@@ -1435,7 +1553,7 @@ ha_ndbcluster::create_pushed_join(NdbQue
{
Field* field= m_pushed_join->get_field_ref(i);
bool shrinkVarChar= is_shrinked_varchar(field);
- DBUG_ASSERT(!field->is_real_null());
+ DBUG_ASSERT(!field->is_real_null()); // Checked by ::check_if_pushable()
paramValues[paramOffs+i]= NdbQueryParamValue(field->ptr, shrinkVarChar);
}
@@ -1487,6 +1605,17 @@ ha_ndbcluster::create_pushed_join(NdbQue
} // ha_ndbcluster::create_pushed_join
+/**
+ * Check if this table access operation is part if a pushed join operation
+ * which is actively executing.
+ */
+bool
+ha_ndbcluster::check_is_pushed() const
+{
+ return (m_pushed_join_member && m_pushed_join_member->m_active_query);
+}
+
+
uint
ha_ndbcluster::is_parent_of_pushed_join() const
{
@@ -3801,111 +3930,6 @@ bool ha_ndbcluster::check_index_fields_i
}
/**
- * C++98 does not allow forward declarations of enum types. By using this
- * class instead of using NdbQueryOperationDef::Type directly,
- * ha_ndbcluster.h avoids including NdbQueryBuilder.h.
- */
-class NdbQueryOperationTypeWrapper
-{
-public:
- /** Implcit conversion from NdbQueryOperationDef::Type.*/
- NdbQueryOperationTypeWrapper(NdbQueryOperationDef::Type type)
- :m_type(type)
- {}
-
- /** Implcit conversion to NdbQueryOperationDef::Type.*/
- operator NdbQueryOperationDef::Type() const
- { return m_type; }
-
-private:
- const NdbQueryOperationDef::Type m_type;
-};
-
-
-/**
- * Check if this table access operation (and a number of succeding operation)
- * can be pushed to the cluster and executed there. This requires that there
- * is an NdbQueryDefiniton and that it still matches the corresponds to the
- * type of operation that we intend to execute. (The MySQL server will
- * sometimes change its mind and replace a scan with a lookup or vice versa
- * as it works its way into the nested loop join.)
- *
- * @param type This is the operation type that the server want to execute.
- * @param idx Index used whenever relevant for operation type
- * @return True if the operation may be pushed.
- */
-bool
-ha_ndbcluster::check_if_pushable(const NdbQueryOperationTypeWrapper& type, uint idx) const
-{
- bool pushable= FALSE;
-
- if (m_pushed_join != NULL)
- {
- const NdbQueryOperationDef* const root_operation=
- m_pushed_join->get_query_def().getQueryOperation(0U);
-
- const NdbQueryOperationTypeWrapper& query_def_type= root_operation->getType();
-
- if (query_def_type == type)
- {
- if (m_disable_pushed_join)
- {
- DBUG_PRINT("info", ("Push disabled (HA_EXTRA_KEYREAD)"));
- }
- else
- {
- const NdbDictionary::Index* const expected_index= root_operation->getIndex();
- pushable= TRUE;
-
- switch (type)
- {
- case NdbQueryOperationDef::PrimaryKeyAccess:
- DBUG_ASSERT(idx==table->s->primary_key);
- break;
- case NdbQueryOperationDef::UniqueIndexAccess:
- DBUG_ASSERT(idx<MAX_KEY);
-// DBUG_ASSERT(m_index[idx].unique_index == expected_index);
- pushable= (m_index[idx].unique_index == expected_index);
- break;
- case NdbQueryOperationDef::TableScan:
- DBUG_ASSERT (idx==MAX_KEY);
- break;
- case NdbQueryOperationDef::OrderedIndexScan:
- DBUG_ASSERT(idx<MAX_KEY);
-// DBUG_ASSERT(m_index[idx].index == expected_index);
- pushable= (m_index[idx].index == expected_index);
- break;
- default:
- DBUG_ASSERT(false);
- break;
- }
- }
- }
- else
- {
- DBUG_PRINT("info",
- ("Cannot execute push join. Root operation prepared as %s "
- "not executable as %s w/ index %d",
- NdbQueryOperationDef::getTypeName(query_def_type),
- NdbQueryOperationDef::getTypeName(type), idx));
- }
- }
- return pushable;
-}
-
-
-/**
- * Check if this table access operation is part if a pushed join operation
- * which is actively executing.
- */
-bool
-ha_ndbcluster::check_is_pushed() const
-{
- return (m_pushed_join_member && m_pushed_join_member->m_active_query);
-}
-
-
-/**
Read one record from NDB using primary key.
*/
Attachment: [text/bzr-bundle] bzr/ole.john.aske@sun.com-20100622122304-krsqzp9dq7aosrs0.bundle
| Thread |
|---|
| • bzr push into mysql-5.1-telco-7.0-spj branch (ole.john.aske:3180 to 3183) | Ole John Aske | 22 Jun |