List:Commits« Previous MessageNext Message »
From:Ole John Aske Date:June 22 2010 12:24pm
Subject:bzr push into mysql-5.1-telco-7.0-spj branch (ole.john.aske:3180 to 3183)
View as plain text  
 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 Aske22 Jun