/** * Handle MySQL's plugin functions * This is mostly for handling the null related functions that MySQL adds to the execution plan */ void InSub::handleFunc(gp_walk_info* gwip, Item_func* func) { if (func->functype() == Item_func::TRIG_COND_FUNC || func->functype() == Item_func::COND_OR_FUNC) { // purpose: remove the isnull() function from the parsetree in ptWorkStack. // IDB handles the null semantics in the join operation // trigcond(or_cond) is the only form we recognize for now if (func->argument_count() > 2) { fGwip.fatalParseError = true; fGwip.parseErrorText = "Unsupported item in IN subquery"; return; } Item_cond* cond; if (func->functype() == Item_func::TRIG_COND_FUNC) { Item* item; if (func->arguments()[0]->type() == Item::REF_ITEM) item = (Item_ref*)(func->arguments()[0])->real_item(); else item = func->arguments()[0]; cond = (Item_cond*)(item); } else { cond = (Item_cond*)(func); } if (cond->functype() == Item_func::COND_OR_FUNC) { // (cache=item) case. do nothing. ignore trigcond()? if (cond->argument_list()->elements == 1) return; // (cache=item or isnull(item)) case. remove "or isnull()" if (cond->argument_list()->elements == 2) { // don't know how to deal with this. don't think it's a fatal error either. if (gwip->ptWorkStack.empty()) return; ParseTree* pt = gwip->ptWorkStack.top(); if (!pt->left() || !pt->right()) return; SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->left()->data()); //assert (sf && sf->op()->op() == execplan::OP_ISNULL); if (!sf || sf->op()->op() != execplan::OP_ISNULL) return; delete sf; sf = dynamic_cast<SimpleFilter*>(pt->right()->data()); //idbassert(sf && sf->op()->op() == execplan::OP_EQ); if (!sf || sf->op()->op() != execplan::OP_EQ) return; // set NULLMATCH for both operand. It's really a setting for the join. // should only set NULLMATCH when the subtype is NOT_IN. for some IN subquery // with aggregation column, MySQL inefficiently convert to: // (cache=item or item is null) and item is not null, which is equivalent to // cache = item. Do not set NULLMATCH for this case. // Because we don't know IN or NOTIN yet, set candidate bit and switch to NULLMATCH // later in handleNot function. if (sf->lhs()->joinInfo() & JOIN_CORRELATED) sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); if (sf->rhs()->joinInfo() & JOIN_CORRELATED) sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); pt = pt->right(); gwip->ptWorkStack.pop(); gwip->ptWorkStack.push(pt); } } else if (cond->functype() == Item_func::EQ_FUNC) { // not in (select const ...) if (gwip->ptWorkStack.empty()) return; ParseTree* pt = gwip->ptWorkStack.top(); SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->data()); if (!sf || sf->op()->op() != execplan::OP_EQ) return; if (sf->lhs()->joinInfo() & JOIN_CORRELATED) sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); if (sf->rhs()->joinInfo() & JOIN_CORRELATED) sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE); } } }
void PrintItemTree(Item* item, int indent) { #ifdef PURE_LIBRARY BHERROR("NOT IMPLEMENTED! Depends on MySQL code."); #else static const char* name_of[] = { "FIELD_ITEM", "FUNC_ITEM", "SUM_FUNC_ITEM", "STRING_ITEM", "INT_ITEM", "REAL_ITEM", "NULL_ITEM", "VARBIN_ITEM", "COPY_STR_ITEM", "FIELD_AVG_ITEM", "DEFAULT_VALUE_ITEM", "PROC_ITEM", "COND_ITEM", "REF_ITEM", "FIELD_STD_ITEM", "FIELD_VARIANCE_ITEM", "INSERT_VALUE_ITEM", "SUBSELECT_ITEM", "ROW_ITEM", "CACHE_ITEM", "TYPE_HOLDER", "PARAM_ITEM", "TRIGGER_FIELD_ITEM", "DECIMAL_ITEM", "XPATH_NODESET", "XPATH_NODESET_CMP", "VIEW_FIXER_ITEM" }; static const char* sum_name_of[] = { "COUNT_FUNC", "COUNT_DISTINCT_FUNC", "SUM_FUNC", "SUM_DISTINCT_FUNC", "AVG_FUNC", "AVG_DISTINCT_FUNC", "MIN_FUNC", "MAX_FUNC", "STD_FUNC", "VARIANCE_FUNC", "SUM_BIT_FUNC", "UDF_SUM_FUNC", "GROUP_CONCAT_FUNC" }; for(int i = 0; i <= indent; i++) fprintf(stderr, "*"); fprintf(stderr, " "); indent += 1; if(!item) { fprintf(stderr, "NULL item\n"); return; } const char* name; Item::Type type = item->type(); if((int)type < sizeof(name_of)/sizeof(*name_of)) name = name_of[type]; else name = "BHFIELD_ITEM"; const char* result = "<unknown result type>"; switch (item->result_type()) { case STRING_RESULT: result = "STRING_RESULT"; break; case INT_RESULT: result = "INT_RESULT"; break; case REAL_RESULT: result = "REAL_RESULT"; break; case DECIMAL_RESULT: result = "DECIMAL_RESULT"; break; } fprintf(stderr, "%s %s @%p %s %s max_length=%d", name, item->full_name(), (void*)item, FieldType(item->field_type()), result, item->max_length); if(item->result_type() == DECIMAL_RESULT) fprintf(stderr, " [prec=%d,dec=%d,int=%d]", item->decimal_precision(), (int)item->decimals, item->decimal_int_part()); switch(type) { case Item::FUNC_ITEM: { Item_func* func = static_cast <Item_func*> (item); fprintf(stderr, " func_name=%s\n", func->func_name()); String str; // GA, print function takes extra argument but do not use it in the base class. func->print(&str,QT_ORDINARY); fprintf(stderr, " f contents: %s\n", str.c_ptr_safe()); Item** args = func->arguments(); for(uint i = 0; i < func->argument_count(); i++) PrintItemTree(args[i], indent); return; } case Item::COND_ITEM: { Item_cond* cond = static_cast <Item_cond*> (item); fprintf(stderr, " func_name=%s\n", cond->func_name()); List_iterator<Item> li(*cond->argument_list()); Item* arg; while ((arg = li++)) PrintItemTree(arg, indent); return; } case Item::SUM_FUNC_ITEM: { Item_sum* sum_func = static_cast <Item_sum*> (item); uint index = sum_func->sum_func(); const char* sumname; if (index >= sizeof(sum_name_of)/sizeof(*sum_name_of)) sumname = "<UNKNOWN>"; else sumname = sum_name_of[index]; fprintf(stderr, " %s\n", sumname); Item** args = sum_func->args; uint args_count = sum_func->arg_count; for(uint i=0; i < args_count; i++) PrintItemTree(args[i], indent); return; } case Item::REF_ITEM: { Item_ref* ref = static_cast<Item_ref*> (item); Item* real = ref->real_item(); fprintf(stderr, "\n"); if(ref != real) PrintItemTree(real, indent); return; } case Item::INT_ITEM: { Item_int_with_ref* int_ref = dynamic_cast<Item_int_with_ref*>(item); if(!int_ref) break; // else item is an instance of Item_int_with_ref, not Item_int fprintf(stderr, " [Item_int_with_ref]\n"); PrintItemTree(int_ref->real_item(), indent); return; } case Item::SUBSELECT_ITEM: Item_subselect* ss = dynamic_cast<Item_subselect*>(item); fprintf(stderr, " subselect type %d\n", ss->substype()); String str; // GA, print function takes extra argument but do not use it. ss->get_unit()->print(&str, QT_ORDINARY); fprintf(stderr, "%s\n", str.c_ptr_safe()); } fprintf(stderr, "\n"); #endif }