From: Ole John Aske Date: July 1 2011 10:54am Subject: bzr push into mysql-5.1-telco-7.0-spj-scan-vs-scan branch (ole.john.aske:3525 to 3526) List-Archive: http://lists.mysql.com/commits/140072 Message-Id: <20110701105435.82E4C225@fimafeng09.norway.sun.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 3526 Ole John Aske 2011-07-01 Refactoring intended to move more of the 'PUSHED_JOIN' specific code from ha_ndbcluster.* into ha_ndbcluster_push.* Two new methods has been created as member of ndb_pushed_join: - ::match_definition() check that the NdbQueryDef encapsulated as part of this ndb_pushed_join object match the execution request as specified by the arguments. (Access type, index usage, ordered) - ::make_query_instance() instantiate another executable NdbQuery from the definition contained in this ndb_psuhed_join object. These new methods now contain a lot of the code previously found in ha_ndbcluster::check_if_pushable() and ::create_pushed_join(). modified: sql/ha_ndbcluster.cc sql/ha_ndbcluster.h sql/ha_ndbcluster_push.cc sql/ha_ndbcluster_push.h 3525 jonas oreland 2011-07-01 ndb - remove pointless includes (causing build-failure on windows in 55-cluster) modified: sql/abstract_query_plan.cc === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc 2011-06-30 09:00:45 +0000 +++ b/sql/ha_ndbcluster.cc 2011-07-01 10:54:02 +0000 @@ -886,30 +886,7 @@ SHOW_VAR ndb_status_index_stat_variables }; #ifndef NO_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; -}; - static int ndbcluster_make_pushed_join(handlerton *, THD*,AQP::Join_plan*); - #endif /* @@ -4005,7 +3982,8 @@ ha_ndbcluster::pk_unique_index_read_key_ uint i; Uint32 offset= 0; - NdbQueryParamValue paramValues[ndb_pushed_join::MAX_KEY_PART + ndb_pushed_join::MAX_REFERRED_FIELDS]; + NdbQueryParamValue paramValues[ndb_pushed_join::MAX_KEY_PART]; + DBUG_ASSERT(key_def->key_parts <= ndb_pushed_join::MAX_KEY_PART); uint map[ndb_pushed_join::MAX_KEY_PART]; ndbcluster_build_key_map(m_table, m_index[idx], &table->key_info[idx], map); @@ -4029,11 +4007,8 @@ ha_ndbcluster::pk_unique_index_read_key_ offset+= key_part->store_length; } - const int error= create_pushed_join(paramValues, key_def->key_parts); - if (unlikely(error)) - DBUG_RETURN(error); - - DBUG_RETURN(0); + const int ret= create_pushed_join(paramValues, key_def->key_parts); + DBUG_RETURN(ret); } // ha_ndbcluster::pk_unique_index_read_key_pushed @@ -4168,8 +4143,7 @@ int ha_ndbcluster::ordered_index_scan(co if (check_if_pushable(NdbQueryOperationDef::OrderedIndexScan, active_index, sorted)) { - NdbQueryParamValue paramValues[ndb_pushed_join::MAX_REFERRED_FIELDS]; - const int error= create_pushed_join(paramValues); + const int error= create_pushed_join(); if (unlikely(error)) DBUG_RETURN(error); @@ -4361,8 +4335,7 @@ int ha_ndbcluster::full_table_scan(const if (check_if_pushable(NdbQueryOperationDef::TableScan)) { - NdbQueryParamValue paramValues[ndb_pushed_join::MAX_REFERRED_FIELDS]; - const int error= create_pushed_join(paramValues); + const int error= create_pushed_join(); if (unlikely(error)) DBUG_RETURN(error); @@ -13738,8 +13711,7 @@ ha_ndbcluster::read_multi_range_first(KE { if (!m_active_query) { - NdbQueryParamValue paramValues[ndb_pushed_join::MAX_REFERRED_FIELDS]; - const int error= create_pushed_join(paramValues); + const int error= create_pushed_join(); if (unlikely(error)) DBUG_RETURN(error); @@ -14384,141 +14356,37 @@ ha_ndbcluster::maybe_pushable_join(const * * @param type This is the operation type that the server want to execute. * @param idx Index used whenever relevant for operation type - * @param rootSorted True if the root operation is an ordered index scan + * @param needSorted True if the root operation is an ordered index scan * with sorted results. * @return True if the operation may be pushed. */ bool -ha_ndbcluster::check_if_pushable(const NdbQueryOperationTypeWrapper& type, - uint idx, bool needSorted) const +ha_ndbcluster::check_if_pushable(int type, //NdbQueryOperationDef::Type, + uint idx, + bool needSorted) const { - if (m_pushed_join_operation != PUSHED_ROOT) - { - return FALSE; - } - - const NdbQueryDef& queryDef= m_pushed_join_member->get_query_def(); - const NdbQueryOperationDef* const root_operation= - queryDef.getQueryOperation((uint)PUSHED_ROOT); - - const NdbQueryOperationTypeWrapper& query_def_type= - root_operation->getType(); - if (m_disable_pushed_join) { DBUG_PRINT("info", ("Push disabled (HA_EXTRA_KEYREAD)")); - return FALSE; - } - - if (query_def_type != type) - { - 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 FALSE; - } - - const NdbDictionary::Index* const expected_index= root_operation->getIndex(); - - // Check that we still use the same index as when the query was prepared. - switch (type) - { - case NdbQueryOperationDef::PrimaryKeyAccess: - DBUG_ASSERT(idx==table->s->primary_key); - break; - - case NdbQueryOperationDef::UniqueIndexAccess: - DBUG_ASSERT(idxgetName(), - expected_index->getName())); - return FALSE; - } - break; - - case NdbQueryOperationDef::TableScan: - DBUG_ASSERT (idx==0); - if (needSorted) - { - DBUG_PRINT("info", - ("TableScan access not not be provied as sorted result. " - "Therefore, join cannot be pushed.")); - return FALSE; - } - break; - - case NdbQueryOperationDef::OrderedIndexScan: - DBUG_ASSERT(idxgetName(), - expected_index->getName())); - return FALSE; - } - if (needSorted && queryDef.getQueryType() == NdbQueryDef::MultiScanQuery) - { - DBUG_PRINT("info", - ("OrderedIndexScan with scan siblings " - "can not execute as pushed join.")); - return FALSE; - } - break; - - default: - DBUG_ASSERT(false); - break; - } - - // 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_member->get_field_referrences_count(); i++) - { - Field* field= m_pushed_join_member->get_field_ref(i); - if (field->is_real_null()) - { - DBUG_PRINT("info", - ("paramValue is NULL, can not execute as pushed join")); - return FALSE; - } + return false; } - - return TRUE; + return m_pushed_join_operation == PUSHED_ROOT + && m_pushed_join_member != NULL + && m_pushed_join_member->match_definition( + type, + (idxget_operation_count(), - m_pushed_join_member->get_table(0)->alias, - NdbQueryOperationDef::getTypeName( - m_pushed_join_member->get_query_def().getQueryOperation((uint)PUSHED_ROOT)->getType())) - ); - - // There may be referrences to Field values from tables outside the scope of - // our pushed join: These are expected to be supplied as paramValues() - for (uint i= 0; i < m_pushed_join_member->get_field_referrences_count(); i++) - { - Field* field= m_pushed_join_member->get_field_ref(i); - DBUG_ASSERT(!field->is_real_null()); // Checked by ::check_if_pushable() - paramValues[paramOffs+i]= NdbQueryParamValue(field->ptr, false); - } + DBUG_ASSERT(m_pushed_join_member && m_pushed_join_operation == PUSHED_ROOT); + + NdbQuery* const query= + m_pushed_join_member->make_query_instance(m_thd_ndb->trans, keyFieldParams, paramCnt); - NdbQuery* const query= m_thd_ndb->trans->createQuery(&m_pushed_join_member->get_query_def(), paramValues); if (unlikely(query==NULL)) ERR_RETURN(m_thd_ndb->trans->getNdbError()); @@ -14650,7 +14518,7 @@ ha_ndbcluster::test_push_flag(enum ha_pu DBUG_RETURN(true); } const NdbQueryDef& query_def = m_pushed_join_member->get_query_def(); - const NdbQueryOperationTypeWrapper& root_type= + const NdbQueryOperationDef::Type root_type= query_def.getQueryOperation((uint)PUSHED_ROOT)->getType(); /** @@ -14670,7 +14538,7 @@ ha_ndbcluster::test_push_flag(enum ha_pu { for (uint i= 1; i < query_def.getNoOfOperations(); i++) { - const NdbQueryOperationTypeWrapper& child_type= + const NdbQueryOperationDef::Type child_type= query_def.getQueryOperation(i)->getType(); if (child_type == NdbQueryOperationDef::TableScan || child_type == NdbQueryOperationDef::OrderedIndexScan) === modified file 'sql/ha_ndbcluster.h' --- a/sql/ha_ndbcluster.h 2011-06-30 08:49:22 +0000 +++ b/sql/ha_ndbcluster.h 2011-07-01 10:54:02 +0000 @@ -799,11 +799,12 @@ private: bool has_null_in_unique_index(uint idx_no) const; bool check_index_fields_not_null(KEY *key_info); - bool check_if_pushable(const NdbQueryOperationTypeWrapper& type, - uint idx= 0, - bool rootSorted= false) const; + bool check_if_pushable(int type, //NdbQueryOperationDef::Type, + uint idx= MAX_KEY, + bool rootSorted= false) const; bool check_is_pushed() const; - int create_pushed_join(NdbQueryParamValue* paramValues, uint paramOffs= 0); + int create_pushed_join(const NdbQueryParamValue* keyFieldParams=NULL, + uint paramCnt= 0); int set_up_partition_info(partition_info *part_info, NdbDictionary::Table&) const; === modified file 'sql/ha_ndbcluster_push.cc' --- a/sql/ha_ndbcluster_push.cc 2011-06-30 09:17:30 +0000 +++ b/sql/ha_ndbcluster_push.cc 2011-07-01 10:54:02 +0000 @@ -41,6 +41,7 @@ #include #include #include "../storage/ndb/src/ndbapi/NdbQueryBuilder.hpp" +#include "../storage/ndb/src/ndbapi/NdbQueryOperation.hpp" #include @@ -161,6 +162,153 @@ ndb_pushed_join::~ndb_pushed_join() m_query_def->destroy(); } +bool ndb_pushed_join::match_definition( + int type, //NdbQueryOperationDef::Type, + const NDB_INDEX_DATA* idx, + bool needSorted) const +{ + const NdbQueryOperationDef* const root_operation= + m_query_def->getQueryOperation((uint)0); + const NdbQueryOperationDef::Type def_type= + root_operation->getType(); + + if (def_type != type) + { + DBUG_PRINT("info", + ("Cannot execute push join. Root operation prepared as %s " + "not executable as %s", + NdbQueryOperationDef::getTypeName(def_type), + NdbQueryOperationDef::getTypeName((NdbQueryOperationDef::Type)type))); + return FALSE; + } + const NdbDictionary::Index* const expected_index= root_operation->getIndex(); + + // Check that we still use the same index as when the query was prepared. + switch (def_type) + { + case NdbQueryOperationDef::PrimaryKeyAccess: + DBUG_ASSERT(idx!=NULL); + DBUG_ASSERT(idx->unique_index == expected_index); + break; + + case NdbQueryOperationDef::UniqueIndexAccess: + DBUG_ASSERT(idx!=NULL); + // DBUG_ASSERT(idx->unique_index == expected_index); + if (idx->unique_index != expected_index) + { + DBUG_PRINT("info", ("Actual index %s differs from expected index %s." + "Therefore, join cannot be pushed.", + idx->unique_index->getName(), + expected_index->getName())); + return FALSE; + } + break; + + case NdbQueryOperationDef::TableScan: + DBUG_ASSERT (idx==NULL && expected_index==NULL); + if (needSorted) + { + DBUG_PRINT("info", + ("TableScan access can not be provied as sorted result. " + "Therefore, join cannot be pushed.")); + return FALSE; + } + break; + + case NdbQueryOperationDef::OrderedIndexScan: + DBUG_ASSERT(idx!=NULL); + // DBUG_ASSERT(idx->index == expected_index); + if (idx->index != expected_index) + { + DBUG_PRINT("info", ("Actual index %s differs from expected index %s. " + "Therefore, join cannot be pushed.", + idx->index->getName(), + expected_index->getName())); + return FALSE; + } + if (needSorted && m_query_def->getQueryType() == NdbQueryDef::MultiScanQuery) + { + DBUG_PRINT("info", + ("OrderedIndexScan with scan siblings " + "can not execute as pushed join.")); + return FALSE; + } + break; + + default: + DBUG_ASSERT(false); + break; + } + + /** + * 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 < get_field_referrences_count(); i++) + { + Field* field= m_referred_fields[i]; + if (field->is_real_null()) + { + DBUG_PRINT("info", + ("paramValue is NULL, can not execute as pushed join")); + return FALSE; + } + } + + return TRUE; +} + +NdbQuery* ndb_pushed_join::make_query_instance( + NdbTransaction* trans, + const NdbQueryParamValue* keyFieldParams, + uint paramCnt) const +{ + DBUG_ENTER("make_query_instance"); + DBUG_PRINT("info", + ("executing chain of %d pushed joins." + " First table is %s, accessed as %s.", + get_operation_count(), + get_table(0)->alias, + NdbQueryOperationDef::getTypeName( + m_query_def->getQueryOperation((uint)0)->getType()) + )); + + const NdbQueryParamValue* paramValues = keyFieldParams; + + /** + * There may be referrences to Field values from tables outside the scope of + * our pushed join: These are expected to be supplied as paramValues() + * after the keyFieldParams[]. + */ + uint outer_fields= get_field_referrences_count(); + if (unlikely(outer_fields > 0)) + { + uint size= sizeof(NdbQueryParamValue) * (paramCnt+outer_fields); + NdbQueryParamValue* extendedParams = reinterpret_cast(alloca(size)); + // Copy specified keyFieldParams[] first + for (uint i= 0; i < paramCnt; i++) + { + extendedParams[i]= keyFieldParams[i]; + } + + // There may be referrences to Field values from tables outside the scope of + // our pushed join: These are expected to be supplied as paramValues() + for (uint i= 0; i < outer_fields; i++) + { + Field* field= m_referred_fields[i]; + DBUG_ASSERT(!field->is_real_null()); // Checked by ::check_if_pushable() + extendedParams[paramCnt+i]= NdbQueryParamValue(field->ptr, false); + } + paramValues= extendedParams; + } + + NdbQuery* query= trans->createQuery(&get_query_def(), paramValues); + DBUG_RETURN(query); +} + +///////////////////////////////////////// + ndb_pushed_builder_ctx::ndb_pushed_builder_ctx(const AQP::Join_plan& plan) : m_plan(plan), === modified file 'sql/ha_ndbcluster_push.h' --- a/sql/ha_ndbcluster_push.h 2011-06-20 14:40:46 +0000 +++ b/sql/ha_ndbcluster_push.h 2011-07-01 10:54:02 +0000 @@ -21,6 +21,7 @@ #include "sql_bitmap.h" +class NdbTransaction; class NdbQueryBuilder; class NdbQueryOperand; class NdbQueryOperationDef; @@ -96,6 +97,20 @@ public: ~ndb_pushed_join(); + /** + * Check that this prepared pushed query matches the type + * of operation specified by the arguments. + */ + bool match_definition(int type, //NdbQueryOperationDef::Type, + const NDB_INDEX_DATA* idx, + bool needSorted) const; + + /** Create an executable instance of this defined query. */ + NdbQuery* make_query_instance( + NdbTransaction* trans, + const NdbQueryParamValue* keyFieldParams, + uint paramCnt) const; + /** Get the number of pushed table access operations.*/ uint get_operation_count() const { return m_operation_count; } @@ -108,14 +123,6 @@ public: uint get_field_referrences_count() const { return m_field_count; } - /** Get the no'th referred field of table access operations that executes - * prior to the pushed join.*/ - Field* get_field_ref(uint no) const - { - DBUG_ASSERT(no < m_field_count); - return m_referred_fields[no]; - } - const NdbQueryDef& get_query_def() const { return *m_query_def; } No bundle (reason: useless for push emails).