26 #include "ha_ndbcluster_glue.h" 
   28 #ifdef WITH_NDBCLUSTER_STORAGE_ENGINE 
   30 #include "ha_ndbcluster.h" 
   31 #include "ha_ndbcluster_push.h" 
   32 #include "ha_ndbcluster_binlog.h" 
   33 #include "ha_ndbcluster_cond.h" 
   34 #include "abstract_query_plan.h" 
   36 #include <ndbapi/NdbApi.hpp> 
   37 #include <ndbapi/NdbInterpretedCode.hpp> 
   38 #include "../storage/ndb/src/ndbapi/NdbQueryBuilder.hpp" 
   39 #include "../storage/ndb/src/ndbapi/NdbQueryOperation.hpp" 
   41 #include <ndb_version.h> 
   43 #define EXPLAIN_NO_PUSH(msgfmt, ...)                              \ 
   46   if (unlikely(current_thd->lex->describe & DESCRIBE_EXTENDED))   \ 
   48     ndbcluster_explain_no_push ((msgfmt), __VA_ARGS__);           \ 
   54 static inline const char* get_referred_field_name(
const Item_field* field_item)
 
   56   DBUG_ASSERT(field_item->type() == Item::FIELD_ITEM);
 
   57   return field_item->field->field_name;
 
   60 static const char* get_referred_table_access_name(
const Item_field* field_item)
 
   62   DBUG_ASSERT(field_item->type() == Item::FIELD_ITEM);
 
   63   return field_item->field->table->alias;
 
   77 static void ndbcluster_explain_no_push(
const char* msgfmt, ...)
 
   81   va_start(args,msgfmt);
 
   82   (void) my_vsnprintf (wbuff, 
sizeof(wbuff), msgfmt, args);
 
   91   push_warning(current_thd, Sql_condition::WARN_LEVEL_NOTE, warn_code,
 
   97 ndb_table_access_map::first_table(uint start)
 const 
   99   for (uint table_no= start; table_no<length(); table_no++)
 
  101     if (contain(table_no))
 
  108 ndb_table_access_map::last_table(uint start)
 const 
  110   uint table_no= start;
 
  113     if (contain(table_no))
 
  115     else if (table_no == 0)
 
  121 ndb_pushed_join::ndb_pushed_join(
 
  125   m_query_def(query_def),
 
  126   m_operation_count(0),
 
  127   m_field_count(builder.m_fld_refs)
 
  129   DBUG_ASSERT(query_def != NULL);
 
  130   DBUG_ASSERT(builder.m_fld_refs <= MAX_REFERRED_FIELDS);
 
  132   for (uint tab_no= 0; !(searched==builder.m_join_scope); tab_no++)
 
  135     if (builder.m_join_scope.contain(tab_no))
 
  137       DBUG_ASSERT(m_operation_count < MAX_PUSHED_OPERATIONS);
 
  138       m_tables[m_operation_count++] = join_tab->
get_table();
 
  139       searched.add(tab_no);
 
  142   for (uint 
i= 0; 
i < builder.m_fld_refs; 
i++)
 
  144     m_referred_fields[
i] = builder.m_referred_fields[
i];
 
  148 ndb_pushed_join::~ndb_pushed_join()
 
  151     m_query_def->destroy();
 
  157                       bool needSorted)
 const 
  160     m_query_def->getQueryOperation((uint)0);
 
  162     root_operation->getType();
 
  164   if (def_type != type)
 
  167                (
"Cannot execute push join. Root operation prepared as %s " 
  168                 "not executable as %s",
 
  169                 NdbQueryOperationDef::getTypeName(def_type),
 
  179     DBUG_ASSERT(idx!=NULL);
 
  180     DBUG_ASSERT(idx->unique_index == expected_index);
 
  184     DBUG_ASSERT(idx!=NULL);
 
  186     if (idx->unique_index != expected_index)
 
  188       DBUG_PRINT(
"info", (
"Actual index %s differs from expected index %s." 
  189                           "Therefore, join cannot be pushed.", 
 
  197     DBUG_ASSERT (idx==NULL && expected_index==NULL);
 
  201                  (
"TableScan access can not be provied as sorted result. "  
  202                   "Therefore, join cannot be pushed."));
 
  208     DBUG_ASSERT(idx!=NULL);
 
  210     if (idx->index != expected_index)
 
  212       DBUG_PRINT(
"info", (
"Actual index %s differs from expected index %s. " 
  213                           "Therefore, join cannot be pushed.", 
 
  221                  (
"OrderedIndexScan with scan siblings "  
  222                   "can not execute as pushed join."));
 
  239     Field* field= m_referred_fields[
i];
 
  240     if (field->is_real_null())
 
  243                  (
"paramValue is NULL, can not execute as pushed join"));
 
  256   DBUG_ENTER(
"make_query_instance");
 
  258              (
"executing chain of %d pushed joins." 
  259               " First table is %s, accessed as %s.", 
 
  262               NdbQueryOperationDef::getTypeName(
 
  263                 m_query_def->getQueryOperation((uint)0)->getType())
 
  275   if (unlikely(outer_fields > 0))
 
  280     for (uint 
i= 0; 
i < paramCnt; 
i++)
 
  287     for (uint 
i= 0; 
i < outer_fields; 
i++)
 
  289       Field* field= m_referred_fields[
i];
 
  290       DBUG_ASSERT(!field->is_real_null());  
 
  293     paramValues= extendedParams;
 
  297   if (unlikely(extendedParams != NULL))
 
  299     for (uint 
i = 0; 
i < paramCnt + outer_fields; 
i++)
 
  301       extendedParams[
i].~NdbQueryParamValue();
 
  303     my_afree(extendedParams);
 
  319   const uint count= m_plan.get_access_count();
 
  325     for (uint 
i= 0; 
i < count; 
i++)
 
  327       m_tables[
i].m_maybe_pushable= 0;
 
  330       if (table->
get_table()->file->ht != ndbcluster_hton)
 
  332         EXPLAIN_NO_PUSH(
"Table '%s' not in ndb engine, not pushable", 
 
  344         EXPLAIN_NO_PUSH(
"Table '%s' was optimized away, or const'ified by optimizer",
 
  349         EXPLAIN_NO_PUSH(
"Table '%s' is not pushable: %s",
 
  355         EXPLAIN_NO_PUSH(
"Table '%s' is not pushable: " 
  356                         "Access type was not chosen at 'prepare' time",
 
  361         const char* reason= NULL;
 
  365         if (handler->maybe_pushable_join(reason))
 
  367           m_tables[
i].m_maybe_pushable= PUSHABLE_AS_CHILD | PUSHABLE_AS_PARENT;
 
  371           EXPLAIN_NO_PUSH(
"Table '%s' is not pushable: %s",
 
  378     m_tables[0].m_maybe_pushable &= ~PUSHABLE_AS_CHILD;
 
  379     m_tables[count-1].m_maybe_pushable &= ~PUSHABLE_AS_PARENT;
 
  382     for (uint 
i= 0; 
i < count; 
i++)
 
  385       uint external= table->
get_table()->tablenr;
 
  388       m_remap[
i].to_external= external;
 
  389       m_remap[external].to_internal= 
i;
 
  394 ndb_pushed_builder_ctx::~ndb_pushed_builder_ctx()
 
  402 const NdbError& ndb_pushed_builder_ctx::getNdbError()
 const 
  404   DBUG_ASSERT(m_builder);
 
  412 ndb_pushed_builder_ctx::get_table_no(
const Item* key_item)
 const 
  414   DBUG_ASSERT(key_item->type() == Item::FIELD_ITEM);
 
  415   table_map bitmap= key_item->used_tables();
 
  417   for (uint 
i= 0; i<MAX_TABLES && bitmap!=0; i++, bitmap>>=1)
 
  421       DBUG_ASSERT(bitmap == 0x01);  
 
  422       return m_remap[
i].to_internal;
 
  455   DBUG_ENTER(
"make_pushed_join");
 
  458   if (is_pushable_with_root(join_root))
 
  461     error= optimize_query_plan();
 
  465     error= build_query();
 
  469     const NdbQueryDef* 
const query_def= m_builder->prepare();
 
  470     if (unlikely(query_def == NULL))
 
  474     if (unlikely (pushed_join == NULL))
 
  475       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
  477     DBUG_PRINT(
"info", (
"Created pushed join with %d child operations", 
 
  492   DBUG_ENTER(
"is_pushable_with_root");
 
  495   if ((m_tables[root_no].m_maybe_pushable & PUSHABLE_AS_PARENT) != PUSHABLE_AS_PARENT)
 
  497     DBUG_PRINT(
"info", (
"Table %d already reported 'not pushable_as_parent'", root_no));
 
  506     EXPLAIN_NO_PUSH(
"Table '%s' is not pushable, " 
  507                     "access type 'MULTI_UNIQUE_KEY' not implemented",
 
  509     m_tables[root_no].m_maybe_pushable &= ~PUSHABLE_AS_PARENT;
 
  517   DBUG_PRINT(
"info", (
"Table %d is pushable as root", root->
get_access_no()));
 
  521   m_const_scope.set_prefix(root_no);
 
  528     if (is_pushable_as_child(table))
 
  533   DBUG_RETURN(push_cnt>0);
 
  557 ndb_pushed_builder_ctx::is_pushable_as_child(
 
  560   DBUG_ENTER(
"is_pushable_as_child");
 
  564   DBUG_ASSERT(tab_no > root_no);
 
  566   if ((m_tables[tab_no].m_maybe_pushable & PUSHABLE_AS_CHILD) != PUSHABLE_AS_CHILD)
 
  568     DBUG_PRINT(
"info", (
"Table %s already known 'not is_pushable_as_child'", table->
get_table()->alias));
 
  575   if (!(ndbcluster_is_lookup_operation(access_type) || 
 
  578     EXPLAIN_NO_PUSH(
"Can't push table '%s' as child, 'type' must be a 'ref' access",
 
  580     m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD;
 
  586       ndbcluster_is_lookup_operation(root_type))
 
  588     EXPLAIN_NO_PUSH(
"Push of table '%s' as scan-child " 
  589                     "with lookup-root '%s' not implemented",
 
  599     EXPLAIN_NO_PUSH(
"Push of table '%s' as scan-child " 
  600                     "with ordered indexscan-root '%s' not implemented",
 
  608     EXPLAIN_NO_PUSH(
"Can't push table '%s' as child, " 
  609                     "to many ref'ed parent fields",
 
  611     m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD; 
 
  615   for (uint 
i = tab_no - 1; 
i >= root_no && 
i < ~uint(0); 
 
  620       EXPLAIN_NO_PUSH(
"Cannot push table '%s' as child of table '%s'. Doing so " 
  621                       "would prevent using join buffer for table '%s'.",
 
  629   DBUG_PRINT(
"info", (
"Table:%d, Checking %d REF keys", tab_no, 
 
  655   for (uint key_part_no= 0; 
 
  662     if (key_item->const_item()) 
 
  664       DBUG_PRINT(
"info", (
" Item type:%d is 'const_item'", key_item->type()));
 
  665       if (!is_const_item_pushable(key_item, key_part))
 
  670     else if (key_item->type() == Item::FIELD_ITEM)
 
  677       if (!is_field_item_pushable(table, key_item, key_part, field_parents))
 
  682       if (key_item->type() == Item::FIELD_ITEM)
 
  684         uint referred_table_no= get_table_no(key_item);
 
  685         current_parents.add(referred_table_no);
 
  692       common_parents.intersect(field_parents);
 
  702       extend_parents.add(field_parents);
 
  704       const uint first= field_parents.first_table(root_no);
 
  705       depend_parents.add(first);
 
  709       EXPLAIN_NO_PUSH(
"Can't push table '%s' as child, " 
  710                       "column '%s' does neither 'ref' a column nor a constant",
 
  712                       key_part->field->field_name);
 
  713       m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD; 
 
  718   if (m_const_scope.contain(current_parents))
 
  723     EXPLAIN_NO_PUSH(
"Can't push table '%s' as child of '%s', " 
  724                     "their dependency is 'const'",
 
  729   else if (extend_parents.is_clear_all())
 
  731     EXPLAIN_NO_PUSH(
"Can't push table '%s' as child of '%s', " 
  732                     "no parents found within scope",
 
  769       EXPLAIN_NO_PUSH(
"Can't push table '%s' as child of '%s', " 
  770                       "outer join of scan-child not implemented",
 
  782   grandparents.clear_bit(root_no);
 
  783   uint ancestor_no= root_no+1;
 
  784   while (!grandparents.is_clear_all())
 
  786     if (grandparents.contain(ancestor_no))
 
  788       grandparents.clear_bit(ancestor_no);
 
  789       if (grandparents.is_clear_all())
 
  795       if (ancestor->
get_join_type(m_join_root) == AQP::JT_OUTER_JOIN)
 
  797         EXPLAIN_NO_PUSH(
"Can't push table '%s' as child of '%s', " 
  798                         "dependencies on outer joined grandparents not implemented", 
 
  807   DBUG_ASSERT(m_join_scope.contain(common_parents));
 
  808   DBUG_ASSERT(m_join_scope.contain(extend_parents));
 
  809   DBUG_ASSERT(extend_parents.is_clear_all() ||
 
  810               extend_parents.contain(common_parents));
 
  814   m_tables[tab_no].m_common_parents= common_parents;
 
  815   m_tables[tab_no].m_extend_parents= extend_parents;
 
  816   m_tables[tab_no].m_depend_parents= depend_parents;
 
  819   m_tables[tab_no].m_maybe_pushable= 0; 
 
  820   m_join_scope.add(tab_no);
 
  840 bool ndb_pushed_builder_ctx::is_field_item_pushable(
 
  842                      const Item* key_item, 
 
  846   DBUG_ENTER(
"is_field_item_pushable()");
 
  848   DBUG_ASSERT(key_item->type() == Item::FIELD_ITEM);
 
  853   DBUG_PRINT(
"info", (
"keyPart:%d, field:%s.%s",
 
  855               key_item_field->field->table->alias, 
 
  856               key_item_field->field->field_name));
 
  858   if (!key_item_field->field->eq_def(key_part->field))
 
  860     EXPLAIN_NO_PUSH(
"Can't push table '%s' as child, " 
  861                     "column '%s' does not have same datatype as ref'ed " 
  864                     key_part->field->field_name,
 
  865                     key_item_field->field->table->alias, 
 
  866                     key_item_field->field->field_name);
 
  867     m_tables[tab_no].m_maybe_pushable &= ~PUSHABLE_AS_CHILD; 
 
  886   field_parents.clear_all();
 
  891   uint referred_table_no= get_table_no(key_item_field);
 
  892   if (m_join_scope.contain(referred_table_no))
 
  894     field_parents.add(referred_table_no);
 
  906     while ((substitute_field= equal_iter.
next()) != NULL)
 
  908       if (substitute_field != key_item_field)
 
  910         const uint substitute_table_no= get_table_no(substitute_field);
 
  911         if (m_join_scope.contain(substitute_table_no))
 
  914                      (
" join_items[%d] %s.%s can be replaced with %s.%s",
 
  916                       get_referred_table_access_name(key_item_field),
 
  917                       get_referred_field_name(key_item_field),
 
  918                       get_referred_table_access_name(substitute_field),
 
  919                       get_referred_field_name(substitute_field)));
 
  921           field_parents.add(substitute_table_no);
 
  926   if (!field_parents.is_clear_all())
 
  931   if (m_const_scope.contain(referred_table_no))
 
  935     DBUG_ASSERT(field_parents.is_clear_all());
 
  942       const TABLE* 
const referred_tab = key_item_field->field->table;
 
  943       uint access_no = tab_no;
 
  946         DBUG_ASSERT(access_no > 0);
 
  950           EXPLAIN_NO_PUSH(
"Cannot push table '%s' as child of '%s', since " 
  951                           "it referes to column '%s.%s' which will be stored " 
  955                           get_referred_table_access_name(key_item_field),
 
  956                           get_referred_field_name(key_item_field));
 
  968     EXPLAIN_NO_PUSH(
"Can't push table '%s' as child of '%s', " 
  969                     "column '%s.%s' is outside scope of pushable join",
 
  971                      get_referred_table_access_name(key_item_field),
 
  972                      get_referred_field_name(key_item_field));
 
  978 bool ndb_pushed_builder_ctx::is_const_item_pushable(
 
  979                      const Item* key_item, 
 
  982   DBUG_ENTER(
"is_const_item_pushable()");
 
  983   DBUG_ASSERT(key_item->const_item());
 
  989   Field* 
const field= key_part->field;
 
  991     const_cast<Item*
>(key_item)->save_in_field_no_warnings(field, 
true);
 
  994     DBUG_PRINT(
"info", (
"Failed to store constant Item into Field -> not" 
  998   if (field->is_real_null())
 
 1000     DBUG_PRINT(
"info", (
"NULL constValues in key -> not pushable"));
 
 1008 ndb_pushed_builder_ctx::optimize_query_plan()
 
 1010   DBUG_ENTER(
"optimize_query_plan");
 
 1018     struct pushed_tables &table= m_tables[tab_no];
 
 1019     if (!m_join_scope.contain(tab_no))
 
 1028     if (!table.m_depend_parents.is_clear_all())
 
 1031       DBUG_ASSERT(!dependency.contain(tab_no)); 
 
 1033       uint depends_on_parent= dependency.last_table(tab_no-1);
 
 1035       dependency_mask.set_prefix(depends_on_parent);
 
 1037       if (table.m_extend_parents.is_overlapping(dependency_mask))
 
 1039         table.m_extend_parents.subtract(dependency_mask);
 
 1040         DBUG_ASSERT(table.m_extend_parents.contain(depends_on_parent) ||
 
 1042         table.m_extend_parents.add(depends_on_parent);
 
 1044       if (table.m_common_parents.is_overlapping(dependency_mask))
 
 1046         table.m_common_parents.clear_all();
 
 1056        table.m_common_parents.is_clear_all()
 
 1057        ? table.m_extend_parents
 
 1058        : table.m_common_parents;
 
 1060     DBUG_ASSERT(!parents.is_clear_all());
 
 1061     DBUG_ASSERT(!parents.contain(tab_no)); 
 
 1068     parent_no= parents.first_table(root_no);
 
 1069     DBUG_ASSERT(parent_no < tab_no);
 
 1070     table.m_parent= parent_no;
 
 1073     dependency.clear_bit(parent_no);
 
 1074     m_tables[parent_no].m_depend_parents.add(dependency);
 
 1078   for (uint tab_no= root_no+1;
 
 1082     if (m_join_scope.contain(tab_no))
 
 1084       struct pushed_tables &table= m_tables[tab_no];
 
 1085       const uint parent_no= table.m_parent;
 
 1086       table.m_ancestors= m_tables[parent_no].m_ancestors;
 
 1087       table.m_ancestors.add(parent_no);
 
 1088       DBUG_ASSERT(table.m_ancestors.contain(table.m_depend_parents));
 
 1096 ndb_pushed_builder_ctx::collect_key_refs(
 
 1098                                   const Item* key_refs[])
 const 
 1100   DBUG_ENTER(
"collect_key_refs");
 
 1103   const uint parent_no= m_tables[tab_no].m_parent;
 
 1106   DBUG_ASSERT(m_join_scope.contain(ancestors));
 
 1107   DBUG_ASSERT(ancestors.contain(parent_no));
 
 1114   for (uint key_part_no= 0; 
 
 1119     key_refs[key_part_no]= key_item;
 
 1121     DBUG_ASSERT(key_item->const_item() || key_item->type()==Item::FIELD_ITEM);
 
 1123     if (key_item->type() == Item::FIELD_ITEM)
 
 1126       uint referred_table_no= get_table_no(join_item);
 
 1129       if (referred_table_no != parent_no && 
 
 1134         while ((substitute_field= iter.
next()) != NULL)
 
 1139           const uint substitute_table_no= get_table_no(substitute_field);
 
 1140           if (substitute_table_no == parent_no)
 
 1143                        (
" Replacing key_refs[%d] %s.%s with %s.%s (parent)",
 
 1145                         get_referred_table_access_name(join_item),
 
 1146                         get_referred_field_name(join_item),
 
 1147                         get_referred_table_access_name(substitute_field),
 
 1148                         get_referred_field_name(substitute_field)));
 
 1150             referred_table_no= substitute_table_no;
 
 1151             key_refs[key_part_no]= join_item= substitute_field;
 
 1154           else if (ancestors.contain(substitute_table_no))
 
 1156             DBUG_ASSERT(substitute_table_no <= parent_no);
 
 1165             if (!ancestors.contain(referred_table_no) ||   
 
 1166                 referred_table_no < substitute_table_no)   
 
 1169                          (
" Replacing key_refs[%d] %s.%s with %s.%s (grandparent)",
 
 1171                           get_referred_table_access_name(join_item),
 
 1172                           get_referred_field_name(join_item),
 
 1173                           get_referred_table_access_name(substitute_field),
 
 1174                           get_referred_field_name(substitute_field)));
 
 1176               referred_table_no= substitute_table_no;
 
 1177               key_refs[key_part_no]= join_item= substitute_field;
 
 1182         DBUG_ASSERT (referred_table_no == parent_no ||
 
 1183                      !m_join_scope.contain(referred_table_no)  || 
 
 1184                      !m_tables[tab_no].m_common_parents.contain(parent_no));
 
 1198   DBUG_ENTER(
"build_key");
 
 1204   if (table == m_join_root)
 
 1210         op_key[
i]= m_builder->paramValue();
 
 1211         if (unlikely(op_key[
i] == NULL))
 
 1222     DBUG_ASSERT(key_fields > 0 && key_fields <= key->user_defined_key_parts);
 
 1229       ndbcluster_build_key_map(handler->m_table, 
 
 1235       for (uint ix = 0; ix < key_fields; ix++)
 
 1242     collect_key_refs(table,join_items);
 
 1245     for (uint 
i= 0; 
i < key_fields; 
i++, key_part++)
 
 1247       const Item* 
const item= join_items[
i];
 
 1248       op_key[map[
i]]= NULL;
 
 1250       DBUG_ASSERT(item->const_item() == item->const_during_execution());
 
 1251       if (item->const_item())
 
 1257         Field* 
const field= key_part->field;
 
 1258         DBUG_ASSERT(!field->is_real_null());
 
 1259         const uchar* 
const ptr= (field->real_type() == MYSQL_TYPE_VARCHAR)
 
 1263         op_key[map[
i]]= m_builder->constValue(ptr, field->data_length());
 
 1267         DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
 
 1269         const uint referred_table_no= get_table_no(field_item);
 
 1271         if (m_join_scope.contain(referred_table_no))
 
 1276           DBUG_ASSERT(parent_op != NULL);
 
 1279           op_key[map[
i]]= m_builder->linkedValue(parent_op, 
 
 1280                                                field_item->field_name);
 
 1284           DBUG_ASSERT(m_const_scope.contain(referred_table_no));
 
 1289             DBUG_PRINT(
"info", (
"Too many Field refs ( >= MAX_REFERRED_FIELDS) " 
 1293           m_referred_fields[m_fld_refs++]= field_item->field;
 
 1294           op_key[map[
i]]= m_builder->paramValue();
 
 1298       if (unlikely(op_key[map[
i]] == NULL))
 
 1303     op_key[key_fields]= NULL;
 
 1310 ndb_pushed_builder_ctx::build_query()
 
 1312   DBUG_ENTER(
"build_query");
 
 1314   DBUG_PRINT(
"enter", (
"Table %d as root is pushable", m_join_root->
get_access_no()));
 
 1315   DBUG_EXECUTE(
"info", m_join_root->
dbug_print(););
 
 1318   DBUG_ASSERT(m_join_scope.contain(root_no));
 
 1320   if (m_builder == NULL)
 
 1323     if (unlikely (m_builder==NULL))
 
 1325       DBUG_RETURN(HA_ERR_OUT_OF_MEM);
 
 1331     if (!m_join_scope.contain(tab_no))
 
 1342       const int error= build_key(table, op_key);
 
 1343       if (unlikely(error))
 
 1348     if (handler->m_cond)
 
 1351       if (handler->m_cond->generate_scan_filter(&
code, NULL) != 0)
 
 1357     if (table != m_join_root)
 
 1359       DBUG_ASSERT(m_tables[tab_no].m_parent!=
MAX_TABLES);
 
 1360       const uint parent_no= m_tables[tab_no].m_parent;
 
 1363       if (!m_tables[tab_no].m_common_parents.contain(parent_no))
 
 1365         DBUG_ASSERT(m_tables[parent_no].m_op != NULL);
 
 1366         options.
setParent(m_tables[parent_no].m_op);
 
 1375     if (ndbcluster_is_lookup_operation(access_type))
 
 1381         DBUG_PRINT(
"info", (
"Operation is 'primary-key-lookup'"));
 
 1382         query_op= m_builder->readTuple(handler->m_table, op_key, &options);
 
 1387         DBUG_PRINT(
"info", (
"Operation is 'unique-index-lookup'"));
 
 1389           = handler->m_index[table->
get_index_no()].unique_index;
 
 1391         query_op= m_builder->readTuple(index, handler->m_table, op_key, &options);
 
 1405       DBUG_ASSERT(handler->m_index[table->
get_index_no()].index != NULL);
 
 1407       DBUG_PRINT(
"info", (
"Operation is 'equal-range-lookup'"));
 
 1408       DBUG_PRINT(
"info", (
"Creating scanIndex on index id:%d, name:%s",
 
 1414       query_op= m_builder->scanIndex(handler->m_index[table->
get_index_no()].index,
 
 1415                                    handler->m_table, &bounds, &options);
 
 1419       DBUG_PRINT(
"info", (
"Operation is 'table scan'"));
 
 1420       query_op= m_builder->scanTable(handler->m_table, &options);
 
 1427     if (unlikely(!query_op))
 
 1430     m_tables[tab_no].m_op= query_op;
 
 1448   if (index.unique_index_attrid_map) 
 
 1452       ix_map[ix]= index.unique_index_attrid_map[ix];
 
 1460     assert (index.type == PRIMARY_KEY_ORDERED_INDEX || index.type == PRIMARY_KEY_INDEX);
 
 1462     for (ix = 0, key_part= key_def->key_part; ix < key_def->user_defined_key_parts; ix++, key_part++)
 
 1468       if (key_part->fieldnr < columnnr)
 
 1476       while (columnnr < key_part->fieldnr-1)
 
 1483       ix_map[ix]= key_pos;
 
 1491 #endif // WITH_NDBCLUSTER_STORAGE_ENGINE