From 9e04ebfa99c12ffef5f03846c3696ba650986f4b Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 9 May 2005 18:56:29 +0200 Subject: Fix for Bug #9246 Condition pushdown and left join, wrong result --- sql/sql_select.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 47c7de6eba7..72fc407692b 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5401,10 +5401,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if (!(tmp= add_found_match_trig_cond(first_inner_tab, tmp, 0))) DBUG_RETURN(1); tab->select_cond=sel->cond=tmp; + /* Push condition to storage engine if this is enabled + and the condition is not guarded */ if (thd->variables.engine_condition_pushdown) { COND *push_cond= - make_cond_for_table(cond,current_map,current_map); + make_cond_for_table(tmp,current_map,current_map); tab->table->file->pushed_cond= NULL; if (push_cond) { -- cgit v1.2.1 From 267c5d7986dcb0415d02ddb6317b8976e362b55d Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 18 May 2005 14:32:05 +0200 Subject: Added support for BETWEEN and IN in condition pushdown to ndbcluster by rewriting them as AND and OR expressions --- sql/ha_ndbcluster.cc | 1226 +++++++++++++++++++++++++++++--------------------- sql/ha_ndbcluster.h | 36 +- 2 files changed, 755 insertions(+), 507 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 372a178b59a..74aff359483 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6184,572 +6184,784 @@ void ndb_serialize_cond(const Item *item, void *arg) context->supported= FALSE; break; } - + DBUG_VOID_RETURN; } if (context->supported) { - Ndb_cond_stack *ndb_stack= context->stack_ptr; - Ndb_cond *prev_cond= context->cond_ptr; - Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond(); - if (!ndb_stack->ndb_cond) - ndb_stack->ndb_cond= curr_cond; - curr_cond->prev= prev_cond; - if (prev_cond) prev_cond->next= curr_cond; - - // Check for end of AND/OR expression - if (!item) + Ndb_rewrite_context *rewrite_context= context->rewrite_stack; + const Item_func *func_item; + // Check if we are rewriting some unsupported function call + if (rewrite_context && + (func_item= rewrite_context->func_item) && + rewrite_context->count++ == 0) { - // End marker for condition group - DBUG_PRINT("info", ("End of condition group")); - curr_cond->ndb_item= new Ndb_item(NDB_END_COND); - } - else - switch(item->type()) { - case(Item::FIELD_ITEM): { - Item_field *field_item= (Item_field *) item; - Field *field= field_item->field; - enum_field_types type= field->type(); + switch(func_item->functype()) { + case(Item_func::BETWEEN): /* - Check that the field is part of the table of the handler - instance and that we expect a field with of this result type. + Rewrite + | BETWEEN | AND | + to | > | AND + | < | + or actually in prefix format + BEGIN(AND) GT(|, |), + LT(|, |), END() */ - if (context->table == field->table) - { - const NDBTAB *tab= (const NDBTAB *) context->ndb_table; - DBUG_PRINT("info", ("FIELD_ITEM")); - DBUG_PRINT("info", ("table %s", tab->getName())); - DBUG_PRINT("info", ("column %s", field->field_name)); - DBUG_PRINT("info", ("result type %d", field->result_type())); - - // Check that we are expecting a field and with the correct - // result type - if(context->expecting(Item::FIELD_ITEM) && - (context->expecting_field_result(field->result_type()) || - // Date and year can be written as strings - (type == MYSQL_TYPE_TIME || - type == MYSQL_TYPE_DATE || - type == MYSQL_TYPE_YEAR || - type == MYSQL_TYPE_DATETIME) - ? context->expecting_field_result(STRING_RESULT) : true) - // Bit fields no yet supported in scan filter - && type != MYSQL_TYPE_BIT) + case(Item_func::IN_FUNC): { + /* + Rewrite | IN(|, |,..) + to | = | OR + = | ... + or actually in prefix format + BEGIN(OR) EQ(|, ), + EQ(|, |), ... END() + Each part of the disjunction is added for each call + to ndb_serialize_cond and end of rewrite statement + is wrapped in end of ndb_serialize_cond + */ + if (context->expecting(item->type())) + { + // This is the | item, save it in the rewrite context + rewrite_context->left_hand_item= item; + if (item->type() == Item::FUNC_ITEM) { - const NDBCOL *col= tab->getColumn(field->field_name); - DBUG_ASSERT(col); - curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo()); - context->dont_expect(Item::FIELD_ITEM); - context->expect_no_field_result(); - if (context->expect_mask) + Item_func *func_item= (Item_func *) item; + if (func_item->functype() == Item_func::UNKNOWN_FUNC && + func_item->const_item()) { - // We have not seen second argument yet - if (type == MYSQL_TYPE_TIME || - type == MYSQL_TYPE_DATE || - type == MYSQL_TYPE_YEAR || - type == MYSQL_TYPE_DATETIME) - { - context->expect_only(Item::STRING_ITEM); - context->expect(Item::INT_ITEM); - } - else - switch(field->result_type()) { - case(STRING_RESULT): - // Expect char string or binary string - context->expect_only(Item::STRING_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect_collation(field_item->collation.collation); - break; - case(REAL_RESULT): - context->expect_only(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - break; - case(INT_RESULT): - context->expect_only(Item::INT_ITEM); - context->expect(Item::VARBIN_ITEM); - break; - case(DECIMAL_RESULT): - context->expect_only(Item::DECIMAL_ITEM); - context->expect(Item::REAL_ITEM); - break; - default: - break; - } + // Skip any arguments since we will evaluate function instead + DBUG_PRINT("info", ("Skip until end of arguments marker")); + context->skip= func_item->argument_count(); } else { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); - // Check that field and string constant collations are the same - if ((field->result_type() == STRING_RESULT) && - !context->expecting_collation(item->collation.collation)) - { - DBUG_PRINT("info", ("Found non-matching collation %s", - item->collation.collation->name)); - context->supported= FALSE; - } + DBUG_PRINT("info", ("Found unsupported functional expression in BETWEEN|IN")); + context->supported= FALSE; + DBUG_VOID_RETURN; + } - break; } } - DBUG_PRINT("info", ("Was not expecting field of type %u", - field->result_type())); - context->supported= FALSE; - break; - } - case(Item::FUNC_ITEM): { - Item_func *func_item= (Item_func *) item; - // Check that we expect a function or functional expression here - if (context->expecting(Item::FUNC_ITEM) || - func_item->functype() == Item_func::UNKNOWN_FUNC) - context->expect_nothing(); else { - // Did not expect function here + // Non-supported BETWEEN|IN expression + DBUG_PRINT("info", ("Found unexpected item of type %u in BETWEEN|IN", + item->type())); context->supported= FALSE; - break; + DBUG_VOID_RETURN; } - + break; + } + default: + context->supported= FALSE; + break; + } + DBUG_VOID_RETURN; + } + else + { + Ndb_cond_stack *ndb_stack= context->stack_ptr; + Ndb_cond *prev_cond= context->cond_ptr; + Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond(); + if (!ndb_stack->ndb_cond) + ndb_stack->ndb_cond= curr_cond; + curr_cond->prev= prev_cond; + if (prev_cond) prev_cond->next= curr_cond; + // Check if we are rewriting some unsupported function call + if (context->rewrite_stack) + { + Ndb_rewrite_context *rewrite_context= context->rewrite_stack; + const Item_func *func_item= rewrite_context->func_item; switch(func_item->functype()) { - case(Item_func::EQ_FUNC): { - DBUG_PRINT("info", ("EQ_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::INT_ITEM); - context->expect(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); - break; - } - case(Item_func::NE_FUNC): { - DBUG_PRINT("info", ("NE_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::INT_ITEM); - context->expect(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); - break; - } - case(Item_func::LT_FUNC): { - DBUG_PRINT("info", ("LT_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::INT_ITEM); - context->expect(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); - break; - } - case(Item_func::LE_FUNC): { - DBUG_PRINT("info", ("LE_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::INT_ITEM); - context->expect(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); - break; - } - case(Item_func::GE_FUNC): { - DBUG_PRINT("info", ("GE_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::INT_ITEM); - context->expect(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); - break; - } - case(Item_func::GT_FUNC): { - DBUG_PRINT("info", ("GT_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::REAL_ITEM); - context->expect(Item::DECIMAL_ITEM); - context->expect(Item::INT_ITEM); - context->expect(Item::VARBIN_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); - break; - } - case(Item_func::LIKE_FUNC): { - DBUG_PRINT("info", ("LIKE_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - break; - } - case(Item_func::NOTLIKE_FUNC): { - DBUG_PRINT("info", ("NOTLIKE_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::STRING_ITEM); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - break; - } - case(Item_func::ISNULL_FUNC): { - DBUG_PRINT("info", ("ISNULL_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); + case(Item_func::BETWEEN): { + /* + Rewrite + | BETWEEN | AND | + to | > | AND + | < | + or actually in prefix format + BEGIN(AND) GT(|, |), + LT(|, |), END() + */ + if (rewrite_context->count == 2) + { + // Lower limit of BETWEEN + DBUG_PRINT("info", ("GE_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::GE_FUNC, 2); + } + else if (rewrite_context->count == 3) + { + // Upper limit of BETWEEN + DBUG_PRINT("info", ("LE_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::LE_FUNC, 2); + } + else + { + // Illegal BETWEEN expression + DBUG_PRINT("info", ("Illegal BETWEEN expression")); + context->supported= FALSE; + DBUG_VOID_RETURN; + } break; } - case(Item_func::ISNOTNULL_FUNC): { - DBUG_PRINT("info", ("ISNOTNULL_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::FIELD_ITEM); - context->expect_field_result(STRING_RESULT); - context->expect_field_result(REAL_RESULT); - context->expect_field_result(INT_RESULT); - context->expect_field_result(DECIMAL_RESULT); + case(Item_func::IN_FUNC): { + /* + Rewrite | IN(|, |,..) + to | = | OR + = | ... + or actually in prefix format + BEGIN(OR) EQ(|, ), + EQ(|, |), ... END() + Each part of the disjunction is added for each call + to ndb_serialize_cond and end of rewrite statement + is wrapped in end of ndb_serialize_cond + */ + DBUG_PRINT("info", ("EQ_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::EQ_FUNC, 2); break; } - case(Item_func::NOT_FUNC): { - DBUG_PRINT("info", ("NOT_FUNC")); - curr_cond->ndb_item= new Ndb_item(func_item->functype(), - func_item); - context->expect(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); - break; + default: + context->supported= FALSE; } - case(Item_func::UNKNOWN_FUNC): { - DBUG_PRINT("info", ("UNKNOWN_FUNC %s", - func_item->const_item()?"const":"")); - DBUG_PRINT("info", ("result type %d", func_item->result_type())); - if (func_item->const_item()) - switch(func_item->result_type()) { - case(STRING_RESULT): { - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::STRING_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) + // Handle left hand | + context->rewrite_stack= NULL; // Disable rewrite mode + context->expect_only(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::INT_ITEM); + context->expect(Item::STRING_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FUNC_ITEM); + ndb_serialize_cond(rewrite_context->left_hand_item, arg); + context->skip= 0; // Any FUNC_ITEM expression has already been parsed + context->rewrite_stack= rewrite_context; // Enable rewrite mode + if (!context->supported) + DBUG_VOID_RETURN; + + prev_cond= context->cond_ptr; + curr_cond= context->cond_ptr= new Ndb_cond(); + prev_cond->next= curr_cond; + } + + // Check for end of AND/OR expression + if (!item) + { + // End marker for condition group + DBUG_PRINT("info", ("End of condition group")); + curr_cond->ndb_item= new Ndb_item(NDB_END_COND); + } + else + switch(item->type()) { + case(Item::FIELD_ITEM): { + Item_field *field_item= (Item_field *) item; + Field *field= field_item->field; + enum_field_types type= field->type(); + /* + Check that the field is part of the table of the handler + instance and that we expect a field with of this result type. + */ + if (context->table == field->table) + { + const NDBTAB *tab= (const NDBTAB *) context->ndb_table; + DBUG_PRINT("info", ("FIELD_ITEM")); + DBUG_PRINT("info", ("table %s", tab->getName())); + DBUG_PRINT("info", ("column %s", field->field_name)); + DBUG_PRINT("info", ("result type %d", field->result_type())); + + // Check that we are expecting a field and with the correct + // result type + if (context->expecting(Item::FIELD_ITEM) && + (context->expecting_field_result(field->result_type()) || + // Date and year can be written as strings + ((type == MYSQL_TYPE_TIME || + type == MYSQL_TYPE_DATE || + type == MYSQL_TYPE_YEAR || + type == MYSQL_TYPE_DATETIME) + ? context->expecting_field_result(STRING_RESULT) : true)) && + // Bit fields no yet supported in scan filter + type != MYSQL_TYPE_BIT) + { + const NDBCOL *col= tab->getColumn(field->field_name); + DBUG_ASSERT(col); + curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo()); + context->dont_expect(Item::FIELD_ITEM); + context->expect_no_field_result(); + if (context->expect_mask) { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(STRING_RESULT); - context->expect_collation(func_item->collation.collation); + // We have not seen second argument yet + if (type == MYSQL_TYPE_TIME || + type == MYSQL_TYPE_DATE || + type == MYSQL_TYPE_YEAR || + type == MYSQL_TYPE_DATETIME) + { + context->expect_only(Item::STRING_ITEM); + context->expect(Item::INT_ITEM); + } + else + switch(field->result_type()) { + case(STRING_RESULT): + // Expect char string or binary string + context->expect_only(Item::STRING_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect_collation(field_item->collation.collation); + break; + case(REAL_RESULT): + context->expect_only(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + break; + case(INT_RESULT): + context->expect_only(Item::INT_ITEM); + context->expect(Item::VARBIN_ITEM); + break; + case(DECIMAL_RESULT): + context->expect_only(Item::DECIMAL_ITEM); + context->expect(Item::REAL_ITEM); + break; + default: + break; + } } else { // Expect another logical expression context->expect_only(Item::FUNC_ITEM); context->expect(Item::COND_ITEM); - // Check that string result have correct collation - if (!context->expecting_collation(item->collation.collation)) + // Check that field and string constant collations are the same + if ((field->result_type() == STRING_RESULT) && + !context->expecting_collation(item->collation.collation) + && type != MYSQL_TYPE_TIME + && type != MYSQL_TYPE_DATE + && type != MYSQL_TYPE_YEAR + && type != MYSQL_TYPE_DATETIME) { DBUG_PRINT("info", ("Found non-matching collation %s", - item->collation.collation->name)); - context->supported= FALSE; + item->collation.collation->name)); + context->supported= FALSE; } } - // Skip any arguments since we will evaluate function instead - DBUG_PRINT("info", ("Skip until end of arguments marker")); - context->skip= func_item->argument_count(); break; } - case(REAL_RESULT): { - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::REAL_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) - { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(REAL_RESULT); - } - else - { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); - } - - // Skip any arguments since we will evaluate function instead - DBUG_PRINT("info", ("Skip until end of arguments marker")); - context->skip= func_item->argument_count(); - break; - } - case(INT_RESULT): { - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::INT_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) - { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(INT_RESULT); - } - else - { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); - } - - // Skip any arguments since we will evaluate function instead - DBUG_PRINT("info", ("Skip until end of arguments marker")); - context->skip= func_item->argument_count(); - break; - } - case(DECIMAL_RESULT): { - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::DECIMAL_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) - { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(DECIMAL_RESULT); - } - else - { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); - } - // Skip any arguments since we will evaluate function instead - DBUG_PRINT("info", ("Skip until end of arguments marker")); - context->skip= func_item->argument_count(); - break; - } - default: - break; + else + { + DBUG_PRINT("info", ("Was not expecting field of type %u", + field->result_type())); + context->supported= FALSE; } + } else - // Function does not return constant expression + { + DBUG_PRINT("info", ("Was not expecting field from table %s(%s)", + context->table->s->table_name, + field->table->s->table_name)); context->supported= FALSE; + } break; } - default: { - DBUG_PRINT("info", ("Found func_item of type %d", - func_item->functype())); - context->supported= FALSE; - } - } - break; - } - case(Item::STRING_ITEM): - DBUG_PRINT("info", ("STRING_ITEM")); - if (context->expecting(Item::STRING_ITEM)) - { -#ifndef DBUG_OFF - char buff[256]; - String str(buff,(uint32) sizeof(buff), system_charset_info); - str.length(0); - Item_string *string_item= (Item_string *) item; - DBUG_PRINT("info", ("value \"%s\"", - string_item->val_str(&str)->ptr())); -#endif - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::STRING_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) + case(Item::FUNC_ITEM): { + Item_func *func_item= (Item_func *) item; + // Check that we expect a function or functional expression here + if (context->expecting(Item::FUNC_ITEM) || + func_item->functype() == Item_func::UNKNOWN_FUNC) + context->expect_nothing(); + else { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(STRING_RESULT); - context->expect_collation(item->collation.collation); + // Did not expect function here + context->supported= FALSE; + break; } - else - { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); - // Check that we are comparing with a field with same collation - if (!context->expecting_collation(item->collation.collation)) - { - DBUG_PRINT("info", ("Found non-matching collation %s", - item->collation.collation->name)); - context->supported= FALSE; - } + + switch(func_item->functype()) { + case(Item_func::EQ_FUNC): { + DBUG_PRINT("info", ("EQ_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::FUNC_ITEM); + break; } - } - else - context->supported= FALSE; - break; - case(Item::INT_ITEM): - DBUG_PRINT("info", ("INT_ITEM")); - if (context->expecting(Item::INT_ITEM)) - { - Item_int *int_item= (Item_int *) item; - DBUG_PRINT("info", ("value %d", int_item->value)); - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::INT_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) - { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(INT_RESULT); + case(Item_func::NE_FUNC): { + DBUG_PRINT("info", ("NE_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::FUNC_ITEM); + break; } - else - { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); + case(Item_func::LT_FUNC): { + DBUG_PRINT("info", ("LT_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::LE_FUNC): { + DBUG_PRINT("info", ("LE_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::GE_FUNC): { + DBUG_PRINT("info", ("GE_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::GT_FUNC): { + DBUG_PRINT("info", ("GT_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::REAL_ITEM); + context->expect(Item::DECIMAL_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::LIKE_FUNC): { + DBUG_PRINT("info", ("LIKE_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::NOTLIKE_FUNC): { + DBUG_PRINT("info", ("NOTLIKE_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::STRING_ITEM); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::ISNULL_FUNC): { + DBUG_PRINT("info", ("ISNULL_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + break; + } + case(Item_func::ISNOTNULL_FUNC): { + DBUG_PRINT("info", ("ISNOTNULL_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::FIELD_ITEM); + context->expect_field_result(STRING_RESULT); + context->expect_field_result(REAL_RESULT); + context->expect_field_result(INT_RESULT); + context->expect_field_result(DECIMAL_RESULT); + break; + } + case(Item_func::NOT_FUNC): { + DBUG_PRINT("info", ("NOT_FUNC")); + curr_cond->ndb_item= new Ndb_item(func_item->functype(), + func_item); + context->expect(Item::FUNC_ITEM); context->expect(Item::COND_ITEM); + break; } - } - else - context->supported= FALSE; - break; - case(Item::REAL_ITEM): - DBUG_PRINT("info", ("REAL_ITEM %s")); - if (context->expecting(Item::REAL_ITEM)) - { - Item_float *float_item= (Item_float *) item; - DBUG_PRINT("info", ("value %f", float_item->value)); - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::REAL_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) - { - // We have not seen the field argument yet + case(Item_func::BETWEEN) : { + DBUG_PRINT("info", ("BETWEEN, rewriting using AND")); + Ndb_rewrite_context *rewrite_context= + new Ndb_rewrite_context(func_item); + rewrite_context->next= context->rewrite_stack; + context->rewrite_stack= rewrite_context; + DBUG_PRINT("info", ("COND_AND_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::COND_AND_FUNC, + func_item->argument_count() - 1); context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(REAL_RESULT); + context->expect(Item::INT_ITEM); + context->expect(Item::STRING_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FUNC_ITEM); + break; } - else - { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); + case(Item_func::IN_FUNC) : { + DBUG_PRINT("info", ("IN_FUNC, rewriting using OR")); + Ndb_rewrite_context *rewrite_context= + new Ndb_rewrite_context(func_item); + rewrite_context->next= context->rewrite_stack; + context->rewrite_stack= rewrite_context; + DBUG_PRINT("info", ("COND_OR_FUNC")); + curr_cond->ndb_item= new Ndb_item(Item_func::COND_OR_FUNC, + func_item->argument_count() - 1); + context->expect_only(Item::FIELD_ITEM); + context->expect(Item::INT_ITEM); + context->expect(Item::STRING_ITEM); + context->expect(Item::VARBIN_ITEM); + context->expect(Item::FUNC_ITEM); + break; + } + case(Item_func::UNKNOWN_FUNC): { + DBUG_PRINT("info", ("UNKNOWN_FUNC %s", + func_item->const_item()?"const":"")); + DBUG_PRINT("info", ("result type %d", func_item->result_type())); + if (func_item->const_item()) + switch(func_item->result_type()) { + case(STRING_RESULT): { + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::STRING_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(STRING_RESULT); + context->expect_collation(func_item->collation.collation); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + // Check that string result have correct collation + if (!context->expecting_collation(item->collation.collation)) + { + DBUG_PRINT("info", ("Found non-matching collation %s", + item->collation.collation->name)); + context->supported= FALSE; + } + } + // Skip any arguments since we will evaluate function instead + DBUG_PRINT("info", ("Skip until end of arguments marker")); + context->skip= func_item->argument_count(); + break; + } + case(REAL_RESULT): { + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::REAL_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(REAL_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } + + // Skip any arguments since we will evaluate function instead + DBUG_PRINT("info", ("Skip until end of arguments marker")); + context->skip= func_item->argument_count(); + break; + } + case(INT_RESULT): { + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::INT_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(INT_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } + + // Skip any arguments since we will evaluate function instead + DBUG_PRINT("info", ("Skip until end of arguments marker")); + context->skip= func_item->argument_count(); + break; + } + case(DECIMAL_RESULT): { + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::DECIMAL_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(DECIMAL_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } + // Skip any arguments since we will evaluate function instead + DBUG_PRINT("info", ("Skip until end of arguments marker")); + context->skip= func_item->argument_count(); + break; + } + default: + break; + } + else + // Function does not return constant expression + context->supported= FALSE; + break; + } + default: { + DBUG_PRINT("info", ("Found func_item of type %d", + func_item->functype())); + context->supported= FALSE; } + } + break; } - else - context->supported= FALSE; - break; - case(Item::VARBIN_ITEM): - DBUG_PRINT("info", ("VARBIN_ITEM")); - if (context->expecting(Item::VARBIN_ITEM)) - { + case(Item::STRING_ITEM): + DBUG_PRINT("info", ("STRING_ITEM")); + if (context->expecting(Item::STRING_ITEM)) + { #ifndef DBUG_OFF - char buff[256]; - String str(buff,(uint32) sizeof(buff), system_charset_info); - str.length(0); - Item_hex_string *varbin_item= (Item_hex_string *) item; - DBUG_PRINT("info", ("value \"%s\"", - varbin_item->val_str(&str)->ptr())); + char buff[256]; + String str(buff,(uint32) sizeof(buff), system_charset_info); + str.length(0); + Item_string *string_item= (Item_string *) item; + DBUG_PRINT("info", ("value \"%s\"", + string_item->val_str(&str)->ptr())); #endif - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::VARBIN_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::STRING_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(STRING_RESULT); + context->expect_collation(item->collation.collation); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + // Check that we are comparing with a field with same collation + if (!context->expecting_collation(item->collation.collation)) + { + DBUG_PRINT("info", ("Found non-matching collation %s", + item->collation.collation->name)); + context->supported= FALSE; + } + } + } + else + context->supported= FALSE; + break; + case(Item::INT_ITEM): + DBUG_PRINT("info", ("INT_ITEM")); + if (context->expecting(Item::INT_ITEM)) { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(STRING_RESULT); + Item_int *int_item= (Item_int *) item; + DBUG_PRINT("info", ("value %d", int_item->value)); + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::INT_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(INT_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } } else + context->supported= FALSE; + break; + case(Item::REAL_ITEM): + DBUG_PRINT("info", ("REAL_ITEM %s")); + if (context->expecting(Item::REAL_ITEM)) { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); + Item_float *float_item= (Item_float *) item; + DBUG_PRINT("info", ("value %f", float_item->value)); + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::REAL_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(REAL_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } } - } - else - context->supported= FALSE; - break; - case(Item::DECIMAL_ITEM): - DBUG_PRINT("info", ("DECIMAL_ITEM %s")); - if (context->expecting(Item::DECIMAL_ITEM)) - { - Item_decimal *decimal_item= (Item_decimal *) item; - DBUG_PRINT("info", ("value %f", decimal_item->val_real())); - NDB_ITEM_QUALIFICATION q; - q.value_type= Item::DECIMAL_ITEM; - curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); - if (context->expect_field_result_mask) + else + context->supported= FALSE; + break; + case(Item::VARBIN_ITEM): + DBUG_PRINT("info", ("VARBIN_ITEM")); + if (context->expecting(Item::VARBIN_ITEM)) { - // We have not seen the field argument yet - context->expect_only(Item::FIELD_ITEM); - context->expect_only_field_result(REAL_RESULT); - context->expect_field_result(DECIMAL_RESULT); + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::VARBIN_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(STRING_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } } else + context->supported= FALSE; + break; + case(Item::DECIMAL_ITEM): + DBUG_PRINT("info", ("DECIMAL_ITEM %s")); + if (context->expecting(Item::DECIMAL_ITEM)) { - // Expect another logical expression - context->expect_only(Item::FUNC_ITEM); - context->expect(Item::COND_ITEM); + Item_decimal *decimal_item= (Item_decimal *) item; + DBUG_PRINT("info", ("value %f", decimal_item->val_real())); + NDB_ITEM_QUALIFICATION q; + q.value_type= Item::DECIMAL_ITEM; + curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item); + if (context->expect_field_result_mask) + { + // We have not seen the field argument yet + context->expect_only(Item::FIELD_ITEM); + context->expect_only_field_result(REAL_RESULT); + context->expect_field_result(DECIMAL_RESULT); + } + else + { + // Expect another logical expression + context->expect_only(Item::FUNC_ITEM); + context->expect(Item::COND_ITEM); + } } + else + context->supported= FALSE; + break; + case(Item::COND_ITEM): { + Item_cond *cond_item= (Item_cond *) item; + + if (context->expecting(Item::COND_ITEM)) + switch(cond_item->functype()) { + case(Item_func::COND_AND_FUNC): + DBUG_PRINT("info", ("COND_AND_FUNC")); + curr_cond->ndb_item= new Ndb_item(cond_item->functype(), + cond_item); + break; + case(Item_func::COND_OR_FUNC): + DBUG_PRINT("info", ("COND_OR_FUNC")); + curr_cond->ndb_item= new Ndb_item(cond_item->functype(), + cond_item); + break; + default: + DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype())); + context->supported= FALSE; + break; + } + else + // Did not expect condition + context->supported= FALSE; + break; } - else + default: { + DBUG_PRINT("info", ("Found item of type %d", item->type())); context->supported= FALSE; - break; - case(Item::COND_ITEM): { - Item_cond *cond_item= (Item_cond *) item; - - if (context->expecting(Item::COND_ITEM)) - switch(cond_item->functype()) { - case(Item_func::COND_AND_FUNC): - DBUG_PRINT("info", ("COND_AND_FUNC")); - curr_cond->ndb_item= new Ndb_item(cond_item->functype(), - cond_item); - break; - case(Item_func::COND_OR_FUNC): - DBUG_PRINT("info", ("COND_OR_FUNC")); - curr_cond->ndb_item= new Ndb_item(cond_item->functype(), - cond_item); - break; - default: - DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype())); - context->supported= FALSE; - break; - } - else - // Did not expect condition - context->supported= FALSE; - break; - } - default: { - DBUG_PRINT("info", ("Found item of type %d", item->type())); - context->supported= FALSE; - } + } + } + + if (context->supported && context->rewrite_stack) + { + Ndb_rewrite_context *rewrite_context= context->rewrite_stack; + if (rewrite_context->count == + rewrite_context->func_item->argument_count()) + { + // Rewrite is done, wrap an END() at the en + DBUG_PRINT("info", ("End of condition group")); + prev_cond= curr_cond; + curr_cond= context->cond_ptr= new Ndb_cond(); + prev_cond->next= curr_cond; + curr_cond->ndb_item= new Ndb_item(NDB_END_COND); + // Pop rewrite stack + context->rewrite_stack= context->rewrite_stack->next; + } } + } } - + DBUG_VOID_RETURN; } @@ -7065,14 +7277,20 @@ ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter) bool simple_cond= TRUE; DBUG_ENTER("build_scan_filter"); - switch(cond->ndb_item->type) { - case(Item_func::COND_AND_FUNC): - case(Item_func::COND_OR_FUNC): - simple_cond= FALSE; - break; - default: - break; - } + switch(cond->ndb_item->type) { + case(NDB_FUNCTION): + switch(cond->ndb_item->qualification.function_type) { + case(Item_func::COND_AND_FUNC): + case(Item_func::COND_OR_FUNC): + simple_cond= FALSE; + break; + default: + break; + } + break; + default: + break; + } if (simple_cond && filter->begin() == -1) DBUG_RETURN(1); if (build_scan_filter_group(cond, filter)) diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 81b2873d9dd..47ac7986e59 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -86,6 +86,7 @@ typedef struct ndb_item_field_value { typedef union ndb_item_value { const Item *item; NDB_ITEM_FIELD_VALUE *field_value; + uint arg_count; } NDB_ITEM_VALUE; struct negated_function_mapping @@ -144,6 +145,7 @@ class Ndb_item { } case(NDB_FUNCTION): value.item= item_value; + value.arg_count= ((Item_func *) item_value)->argument_count(); break; case(NDB_END_COND): break; @@ -162,6 +164,13 @@ class Ndb_item { { qualification.function_type= func_type; value.item= item_value; + value.arg_count= ((Item_func *) item_value)->argument_count(); + }; + Ndb_item(Item_func::Functype func_type, uint no_args) + : type(NDB_FUNCTION) + { + qualification.function_type= func_type; + value.arg_count= no_args; }; ~Ndb_item() { @@ -194,7 +203,7 @@ class Ndb_item { int argument_count() { - return ((Item_func *) value.item)->argument_count(); + return value.arg_count; }; const char* get_val() @@ -273,12 +282,28 @@ class Ndb_cond_stack { if (ndb_cond) delete ndb_cond; ndb_cond= NULL; + if (next) delete next; next= NULL; }; Ndb_cond *ndb_cond; Ndb_cond_stack *next; }; +class Ndb_rewrite_context +{ +public: + Ndb_rewrite_context(Item_func *func) + : func_item(func), left_hand_item(NULL), count(0) {}; + ~Ndb_rewrite_context() + { + if (next) delete next; + } + const Item_func *func_item; + const Item *left_hand_item; + uint count; + Ndb_rewrite_context *next; +}; + /* This class is used for storing the context when traversing the Item tree. It stores a reference to the table the condition @@ -292,11 +317,16 @@ class Ndb_cond_traverse_context Ndb_cond_traverse_context(TABLE *tab, void* ndb_tab, Ndb_cond_stack* stack) : table(tab), ndb_table(ndb_tab), supported(TRUE), stack_ptr(stack), cond_ptr(NULL), - expect_mask(0), expect_field_result_mask(0), skip(0), collation(NULL) + expect_mask(0), expect_field_result_mask(0), skip(0), collation(NULL), + rewrite_stack(NULL) { if (stack) cond_ptr= stack->ndb_cond; }; + ~Ndb_cond_traverse_context() + { + if (rewrite_stack) delete rewrite_stack; + } void expect(Item::Type type) { expect_mask|= (1 << type); @@ -357,7 +387,7 @@ class Ndb_cond_traverse_context uint expect_field_result_mask; uint skip; CHARSET_INFO* collation; - + Ndb_rewrite_context *rewrite_stack; }; /* -- cgit v1.2.1 From af8cbbaec5cab3b3bbce3a0af423d9725c33f3f0 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2005 16:41:53 -0700 Subject: Fix '%h', '%I', and '%l' format specifiers in TIME_FORMAT() to handle large time values as documented. (Bug #10590) mysql-test/r/func_time.result: Add new results mysql-test/t/func_time.test: Add new regression test sql/item_timefunc.cc: Fix handling of '%h', '%I', and '%l' format specifiers for TIME_FORMAT() to handle large time values correctly. --- sql/item_timefunc.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sql') diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 7a9c7898856..a99297180e5 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -497,7 +497,6 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, timestamp_type type, String *str) { char intbuff[15]; - uint days_i; uint hours_i; uint weekday; ulong length; @@ -600,8 +599,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, break; case 'h': case 'I': - days_i= l_time->hour/24; - hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i; + hours_i= (l_time->hour%24 + 11)%12+1; length= int10_to_str(hours_i, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 2, '0'); break; @@ -622,8 +620,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time, str->append_with_prefill(intbuff, length, 1, '0'); break; case 'l': - days_i= l_time->hour/24; - hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i; + hours_i= (l_time->hour%24 + 11)%12+1; length= int10_to_str(hours_i, intbuff, 10) - intbuff; str->append_with_prefill(intbuff, length, 1, '0'); break; -- cgit v1.2.1 From 9f50c2ffacfdeba18bfc85c8c2410d59c8528c39 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Jun 2005 11:56:47 +0200 Subject: Fixed handling of condition pushdown to storage engine of NO BETWEEN and NOT IN --- sql/ha_ndbcluster.cc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 8b9706bb81f..0b6a8e34e93 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -7232,8 +7232,10 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) break; } case(Item_func::NOT_FUNC): { + DBUG_PRINT("info", ("Generating negated query")); cond= cond->next; negated= TRUE; + break; } default: @@ -7249,12 +7251,14 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter) if (cond) cond= cond->next; if (filter->end() == -1) DBUG_RETURN(1); - break; + if (!negated) + break; + // else fall through (NOT END is an illegal condition) default: { DBUG_PRINT("info", ("Illegal scan filter")); } } - } while (level > 0); + } while (level > 0 || negated); DBUG_RETURN(0); } @@ -7296,6 +7300,7 @@ ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack, DBUG_ENTER("generate_scan_filter"); if (ndb_cond_stack) { + DBUG_PRINT("info", ("Generating scan filter")); NdbScanFilter filter(op); bool multiple_cond= FALSE; // Wrap an AND group around multiple conditions -- cgit v1.2.1 From 04ed9f0204c1d21d4ebac0ad612f9b5aaf27effa Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 1 Jun 2005 18:33:16 +0200 Subject: more than 64 indexes per table. bugfixes. bug#10995 --- sql/sql_bitmap.h | 23 +++++++++++------------ sql/sql_select.cc | 1 + 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'sql') diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index 2fd603d9381..958268fc314 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -28,7 +28,7 @@ template class Bitmap uchar buffer[(default_width+7)/8]; public: Bitmap() { init(); } - Bitmap(Bitmap& from) { *this=from; } + Bitmap(const Bitmap& from) { *this=from; } explicit Bitmap(uint prefix_to_set) { init(prefix_to_set); } void init() { bitmap_init(&map, buffer, default_width, 0); } void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); } @@ -61,18 +61,17 @@ public: my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); } char *print(char *buf) const { - char *s=buf; int i; - for (i=sizeof(buffer)-1; i>=0 ; i--) + char *s=buf; + const uchar *e=buffer, *b=e+sizeof(buffer)-1; + while (!*b && b>e) + b--; + if ((*s=_dig_vec_upper[*b >> 4]) != '0') + s++; + *s++=_dig_vec_upper[*b & 15]; + while (--b>=e) { - if ((*s=_dig_vec_upper[buffer[i] >> 4]) != '0') - break; - if ((*s=_dig_vec_upper[buffer[i] & 15]) != '0') - break; - } - for (s++, i-- ; i>=0 ; i--) - { - *s++=_dig_vec_upper[buffer[i] >> 4]; - *s++=_dig_vec_upper[buffer[i] & 15]; + *s++=_dig_vec_upper[*b >> 4]; + *s++=_dig_vec_upper[*b & 15]; } *s=0; return buf; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e23d32cca84..4d8145d8df2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5792,6 +5792,7 @@ make_join_readinfo(JOIN *join, uint options) if (!table->no_keyread) { if (tab->select && tab->select->quick && + tab->select->quick->index != MAX_KEY && //not index_merge table->used_keys.is_set(tab->select->quick->index)) { table->key_read=1; -- cgit v1.2.1 From 17678a7b885beb59fa808b7ace5cee4a0e21667d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 16:17:44 +0500 Subject: item_func.cc: set_var.cc: variables.result variables.test Bug #10904 Illegal mix of collations between a system variable and a constant Changing coercibility of system variables to SYSCONST, to be the same with USER(), DATABASE(), etc. sql/item_func.cc: Bug #10904 Illegal mix of collations between a system variable and a constant Changing coercibility of system variables to SYSCONST To be the same with USER(), DATABASE(), etc. --- sql/item_func.cc | 2 +- sql/set_var.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 598439c60c1..ad8479c7b0b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3369,7 +3369,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name, !my_strcasecmp(system_charset_info, name.str, "VERSION")) return new Item_string("@@VERSION", server_version, (uint) strlen(server_version), - system_charset_info); + system_charset_info, DERIVATION_SYSCONST); Item *item; sys_var *var; diff --git a/sql/set_var.cc b/sql/set_var.cc index b006dde2b4b..5564ba096ac 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1606,7 +1606,8 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base) Item_string *tmp; pthread_mutex_lock(&LOCK_global_system_variables); char *str= (char*) value_ptr(thd, var_type, base); - tmp= new Item_string(str, strlen(str), system_charset_info); + tmp= new Item_string(str, strlen(str), + system_charset_info, DERIVATION_SYSCONST); pthread_mutex_unlock(&LOCK_global_system_variables); return tmp; } -- cgit v1.2.1 From b8c37b95025acf0d028dff6a1d22dc9b2d7530cc Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 14:46:58 +0200 Subject: Removed bug introduced when implementing support for IN and BETWEEN --- sql/ha_ndbcluster.cc | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sql') diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 0b6a8e34e93..65e16dcb539 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6476,7 +6476,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(REAL_RESULT); context->expect_field_result(INT_RESULT); context->expect_field_result(DECIMAL_RESULT); - context->expect(Item::FUNC_ITEM); break; } case(Item_func::NE_FUNC): { @@ -6493,7 +6492,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(REAL_RESULT); context->expect_field_result(INT_RESULT); context->expect_field_result(DECIMAL_RESULT); - context->expect(Item::FUNC_ITEM); break; } case(Item_func::LT_FUNC): { @@ -6510,7 +6508,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(REAL_RESULT); context->expect_field_result(INT_RESULT); context->expect_field_result(DECIMAL_RESULT); - context->expect(Item::FUNC_ITEM); break; } case(Item_func::LE_FUNC): { @@ -6527,7 +6524,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(REAL_RESULT); context->expect_field_result(INT_RESULT); context->expect_field_result(DECIMAL_RESULT); - context->expect(Item::FUNC_ITEM); break; } case(Item_func::GE_FUNC): { @@ -6544,7 +6540,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(REAL_RESULT); context->expect_field_result(INT_RESULT); context->expect_field_result(DECIMAL_RESULT); - context->expect(Item::FUNC_ITEM); break; } case(Item_func::GT_FUNC): { @@ -6561,7 +6556,6 @@ void ndb_serialize_cond(const Item *item, void *arg) context->expect_field_result(REAL_RESULT); context->expect_field_result(INT_RESULT); context->expect_field_result(DECIMAL_RESULT); - context->expect(Item::FUNC_ITEM); break; } case(Item_func::LIKE_FUNC): { -- cgit v1.2.1 From 2d008198d29509c69677c44985af8b086ac063fe Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 14:48:19 +0200 Subject: Modified handling of guarded predicates at condition pushdown to storage engine, to make valgrind happy --- sql/sql_select.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7bd2d6f4fd2..d0038561d5e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5454,6 +5454,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) */ if (cond) { + COND *unguarded= tmp; /* Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without a cond, so neutralize the hack above. @@ -5463,11 +5464,12 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) tab->select_cond=sel->cond=tmp; /* Push condition to storage engine if this is enabled and the condition is not guarded */ - if (thd->variables.engine_condition_pushdown) + tab->table->file->pushed_cond= NULL; + if (thd->variables.engine_condition_pushdown && + unguarded == tmp) { COND *push_cond= - make_cond_for_table(tmp,current_map,current_map); - tab->table->file->pushed_cond= NULL; + make_cond_for_table(cond, current_map, current_map); if (push_cond) { /* Push condition to handler */ -- cgit v1.2.1 From c8e797b5b6d921803746d82b81c5e9e35d7c03a6 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 17:00:07 +0400 Subject: Fix bug #9669 Ordering on IF function with FROM_UNIXTIME function fails Integer overflow results in wrong field sortlength. sql/item_cmpfunc.cc: Fix bug #9669 Ordering on IF function with FROM_UNIXTIME function fails. mysql-test/t/func_if.test: Test for bug #9669 Ordering on IF function with FROM_UNIXTIME function fails. mysql-test/r/func_if.result: Test for bug #9669 Ordering on IF function with FROM_UNIXTIME function fails. --- sql/item_cmpfunc.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index a7abb5f9be8..eb0dddd3e28 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1227,9 +1227,16 @@ Item_func_if::fix_length_and_dec() { maybe_null=args[1]->maybe_null || args[2]->maybe_null; decimals= max(args[1]->decimals, args[2]->decimals); - max_length= (max(args[1]->max_length - args[1]->decimals, + if (decimals == NOT_FIXED_DEC) + { + max_length= max(args[1]->max_length, args[2]->max_length); + } + else + { + max_length= (max(args[1]->max_length - args[1]->decimals, args[2]->max_length - args[2]->decimals) + decimals); + } enum Item_result arg1_type=args[1]->result_type(); enum Item_result arg2_type=args[2]->result_type(); bool null1=args[1]->const_item() && args[1]->null_value; -- cgit v1.2.1 From 1dd50e466d7ad4c2cb39be6393840abf5cbb9fbf Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 15:32:02 +0200 Subject: misc. fixes for windoze builds VC++Files/client/mysql.dsp: added missing mysys.lib VC++Files/client/mysqladmin.dsp: added missing mysys.lib VC++Files/client/mysqlimport.dsp: added missing mysys.lib VC++Files/client/mysqlshow.dsp: added missing mysys.lib VC++Files/libmysql/libmysql.dsp: added missing mysys.lib VC++Files/mysql.dsw: added dependencies on mysys include/config-win.h: added missing constant sql/sql_base.cc: pulled declaration of table_list out of for-scope --- sql/sql_base.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sql') diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5719f77e3ef..036a838b6fc 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3222,7 +3222,8 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, if (!(*leaves)) make_leaves_list(leaves, tables); - for (TABLE_LIST *table_list= *leaves; + TABLE_LIST *table_list; + for (table_list= *leaves; table_list; table_list= table_list->next_leaf, tablenr++) { @@ -3261,7 +3262,7 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES); DBUG_RETURN(1); } - for (TABLE_LIST *table_list= tables; + for (table_list= tables; table_list; table_list= table_list->next_local) { -- cgit v1.2.1 From 1ea49fecddde8e2d81438ee8d0eefff1a5fd8527 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 15:45:20 +0200 Subject: cleanup extra/yassl/src/ssl.cpp: unresolved __cxa_pure_virtual sql/item_func.cc: don't call arg[0]->val_xxx() twice --- sql/item_func.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 3767844e200..6e630fd389b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2325,9 +2325,6 @@ longlong Item_func_field::val_int() { DBUG_ASSERT(fixed == 1); - if (args[0]->is_null()) - return 0; - if (cmp_type == STRING_RESULT) { String *field; @@ -2343,6 +2340,8 @@ longlong Item_func_field::val_int() else if (cmp_type == INT_RESULT) { longlong val= args[0]->val_int(); + if (args[0]->null_value) + return 0; for (uint i=1; i < arg_count ; i++) { if (!args[i]->is_null() && val == args[i]->val_int()) @@ -2353,6 +2352,8 @@ longlong Item_func_field::val_int() { my_decimal dec_arg_buf, *dec_arg, dec_buf, *dec= args[0]->val_decimal(&dec_buf); + if (args[0]->null_value) + return 0; for (uint i=1; i < arg_count; i++) { dec_arg= args[i]->val_decimal(&dec_arg_buf); @@ -2363,6 +2364,8 @@ longlong Item_func_field::val_int() else { double val= args[0]->val_real(); + if (args[0]->null_value) + return 0; for (uint i=1; i < arg_count ; i++) { if (!args[i]->is_null() && val == args[i]->val_real()) -- cgit v1.2.1 From 21989e7d4e281b67f060d61fdd0dd4fa2b4eba54 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 07:27:02 -0700 Subject: item_func.h: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. The str_op virtual method was added into Item_func_numhybrid. item_func.cc: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. The str_op virtual method was added into Item_func_numhybrid. item_cmpfunc.h, item_cmpfunc.cc: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. Item_func_coalesce and Item_func_ifnull now inherit from a modified Item_func_numhybrid. case.test, case.result: Added test cases for bug #9939. mysql-test/r/case.result: Added test cases for bug #9939. mysql-test/t/case.test: Added test cases for bug #9939. sql/item_cmpfunc.cc: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. Item_func_coalesce and Item_func_ifnull now inherit from a modified Item_func_numhybrid. sql/item_cmpfunc.h: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. Item_func_coalesce and Item_func_ifnull now inherit from a modified Item_func_numhybrid. sql/item_func.cc: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. The str_op virtual method was added into Item_func_numhybrid. sql/item_func.h: Fixed bug #9939: a wrong conversion of arguments for functions COALESCE and IFNULL. he str_op virtual method was added into Item_func_numhybrid. BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- sql/item_cmpfunc.cc | 24 ++++++++++++------------ sql/item_cmpfunc.h | 30 +++++++++++++----------------- sql/item_func.cc | 25 +++++++++++++++++++++++++ sql/item_func.h | 6 ++++++ 4 files changed, 56 insertions(+), 29 deletions(-) (limited to 'sql') diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 66f0bf9c395..d64f1df78ab 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1114,8 +1114,8 @@ Item_func_ifnull::fix_length_and_dec() max_length= (max(args[0]->max_length - args[0]->decimals, args[1]->max_length - args[1]->decimals) + decimals); - agg_result_type(&cached_result_type, args, 2); - switch (cached_result_type) { + agg_result_type(&hybrid_type, args, 2); + switch (hybrid_type) { case STRING_RESULT: agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV); break; @@ -1153,7 +1153,7 @@ Field *Item_func_ifnull::tmp_table_field(TABLE *table) } double -Item_func_ifnull::val_real() +Item_func_ifnull::real_op() { DBUG_ASSERT(fixed == 1); double value= args[0]->val_real(); @@ -1169,7 +1169,7 @@ Item_func_ifnull::val_real() } longlong -Item_func_ifnull::val_int() +Item_func_ifnull::int_op() { DBUG_ASSERT(fixed == 1); longlong value=args[0]->val_int(); @@ -1185,7 +1185,7 @@ Item_func_ifnull::val_int() } -my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value) +my_decimal *Item_func_ifnull::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); my_decimal *value= args[0]->val_decimal(decimal_value); @@ -1202,7 +1202,7 @@ my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value) String * -Item_func_ifnull::val_str(String *str) +Item_func_ifnull::str_op(String *str) { DBUG_ASSERT(fixed == 1); String *res =args[0]->val_str(str); @@ -1676,7 +1676,7 @@ void Item_func_case::print(String *str) Coalesce - return first not NULL argument. */ -String *Item_func_coalesce::val_str(String *str) +String *Item_func_coalesce::str_op(String *str) { DBUG_ASSERT(fixed == 1); null_value=0; @@ -1690,7 +1690,7 @@ String *Item_func_coalesce::val_str(String *str) return 0; } -longlong Item_func_coalesce::val_int() +longlong Item_func_coalesce::int_op() { DBUG_ASSERT(fixed == 1); null_value=0; @@ -1704,7 +1704,7 @@ longlong Item_func_coalesce::val_int() return 0; } -double Item_func_coalesce::val_real() +double Item_func_coalesce::real_op() { DBUG_ASSERT(fixed == 1); null_value=0; @@ -1719,7 +1719,7 @@ double Item_func_coalesce::val_real() } -my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value) +my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value) { DBUG_ASSERT(fixed == 1); null_value= 0; @@ -1736,8 +1736,8 @@ my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value) void Item_func_coalesce::fix_length_and_dec() { - agg_result_type(&cached_result_type, args, arg_count); - switch (cached_result_type) { + agg_result_type(&hybrid_type, args, arg_count); + switch (hybrid_type) { case STRING_RESULT: count_only_length(); decimals= NOT_FIXED_DEC; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index a929d509723..7a22e76b217 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -453,23 +453,19 @@ public: }; -class Item_func_coalesce :public Item_func +class Item_func_coalesce :public Item_func_numhybrid { protected: - enum Item_result cached_result_type; - Item_func_coalesce(Item *a, Item *b) - :Item_func(a, b), cached_result_type(INT_RESULT) - {} + Item_func_coalesce(Item *a, Item *b) :Item_func_numhybrid(a, b) {} public: - Item_func_coalesce(List &list) - :Item_func(list),cached_result_type(INT_RESULT) - {} - double val_real(); - longlong val_int(); - String *val_str(String *); - my_decimal *val_decimal(my_decimal *); + Item_func_coalesce(List &list) :Item_func_numhybrid(list) {} + double real_op(); + longlong int_op(); + String *str_op(String *); + my_decimal *decimal_op(my_decimal *); void fix_length_and_dec(); - enum Item_result result_type () const { return cached_result_type; } + void find_num_type() {} + enum Item_result result_type () const { return hybrid_type; } const char *func_name() const { return "coalesce"; } table_map not_null_tables() const { return 0; } }; @@ -482,10 +478,10 @@ protected: bool field_type_defined; public: Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {} - double val_real(); - longlong val_int(); - String *val_str(String *str); - my_decimal *val_decimal(my_decimal *); + double real_op(); + longlong int_op(); + String *str_op(String *str); + my_decimal *decimal_op(my_decimal *); enum_field_types field_type() const; void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 47dffa679e9..21837dfbadb 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -815,6 +815,8 @@ String *Item_func_numhybrid::val_str(String *str) str->set(nr,decimals,&my_charset_bin); break; } + case STRING_RESULT: + return str_op(&str_value); default: DBUG_ASSERT(0); } @@ -839,6 +841,14 @@ double Item_func_numhybrid::val_real() return (double)int_op(); case REAL_RESULT: return real_op(); + case STRING_RESULT: + { + char *end_not_used; + int err_not_used; + String *res= str_op(&str_value); + return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(), + &end_not_used, &err_not_used) : 0.0); + } default: DBUG_ASSERT(0); } @@ -863,6 +873,15 @@ longlong Item_func_numhybrid::val_int() return int_op(); case REAL_RESULT: return (longlong)real_op(); + case STRING_RESULT: + { + char *end_not_used; + int err_not_used; + String *res= str_op(&str_value); + CHARSET_INFO *cs= str_value.charset(); + return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end_not_used, + &err_not_used) : 0); + } default: DBUG_ASSERT(0); } @@ -891,6 +910,12 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value) break; } case STRING_RESULT: + { + String *res= str_op(&str_value); + str2my_decimal(E_DEC_FATAL_ERROR, (char*) res->ptr(), + res->length(), res->charset(), decimal_value); + break; + } case ROW_RESULT: default: DBUG_ASSERT(0); diff --git a/sql/item_func.h b/sql/item_func.h index b53f2a0b9c6..797aec952f9 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -194,6 +194,9 @@ public: Item_func_numhybrid(Item *a,Item *b) :Item_func(a,b),hybrid_type(REAL_RESULT) {} + Item_func_numhybrid(List &list) + :Item_func(list),hybrid_type(REAL_RESULT) + {} enum Item_result result_type () const { return hybrid_type; } void fix_length_and_dec(); @@ -208,6 +211,7 @@ public: virtual longlong int_op()= 0; virtual double real_op()= 0; virtual my_decimal *decimal_op(my_decimal *)= 0; + virtual String *str_op(String *)= 0; bool is_null() { (void) val_real(); return null_value; } }; @@ -220,6 +224,7 @@ public: void fix_num_length_and_dec(); void find_num_type(); + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } }; @@ -231,6 +236,7 @@ class Item_num_op :public Item_func_numhybrid virtual void result_precision()= 0; void print(String *str) { print_op(str); } void find_num_type(); + String *str_op(String *str) { DBUG_ASSERT(0); return 0; } }; -- cgit v1.2.1 From 78a9e47e467313231e59c1cc3f8c6f3aca371659 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 16:56:08 +0200 Subject: Added update_used_tables to add_found_match_trig_cond, to make valgrind happy --- sql/sql_select.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d0038561d5e..811fdc69ba7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5233,7 +5233,10 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab) tmp= new Item_func_trig_cond(tmp, &tab->found); } if (tmp) + { tmp->quick_fix_field(); + tmp->update_used_tables(); + } return tmp; } @@ -5454,7 +5457,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) */ if (cond) { - COND *unguarded= tmp; /* Because of QUICK_GROUP_MIN_MAX_SELECT there may be a select without a cond, so neutralize the hack above. @@ -5465,11 +5467,10 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) /* Push condition to storage engine if this is enabled and the condition is not guarded */ tab->table->file->pushed_cond= NULL; - if (thd->variables.engine_condition_pushdown && - unguarded == tmp) + if (thd->variables.engine_condition_pushdown) { COND *push_cond= - make_cond_for_table(cond, current_map, current_map); + make_cond_for_table(tmp, current_map, current_map); if (push_cond) { /* Push condition to handler */ -- cgit v1.2.1 From e9799ba6fa687fd879e8d2fe84986103c6279b8a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 18:10:32 +0300 Subject: ha_innodb.cc: Weaken InnoDB table locking at the start of a stored procedure call: this will make multi-transaction stored procedures less deterministic for binlogging, but since they are non-deterministic anyway, it is not that bad; this fix will remove the huge amount of InnoDB tranasctional deadlocks caused by table locking at the start of a stored procedure sql/ha_innodb.cc: Weaken InnoDB table locking at the start of a stored procedure call: this will make multi-transaction stored procedures less deterministic for binlogging, but since they are non-deterministic anyway, it is not that bad; this fix will remove the huge amount of InnoDB tranasctional deadlocks caused by table locking at the start of a stored procedure --- sql/ha_innodb.cc | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 1703a405035..d956e692152 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -5963,11 +5963,14 @@ ha_innobase::external_lock( TABLES if AUTOCOMMIT=1. It does not make much sense to acquire an InnoDB table lock if it is released immediately at the end of LOCK TABLES, and InnoDB's table locks in that case cause - VERY easily deadlocks. */ + VERY easily deadlocks. We do not set InnoDB table locks when + MySQL sets them at the start of a stored procedure call + (MySQL does have thd->in_lock_tables TRUE there). */ if (prebuilt->select_lock_type != LOCK_NONE) { if (thd->in_lock_tables && + thd->lex->sql_command != SQLCOM_CALL && thd->variables.innodb_table_locks && (thd->options & OPTION_NOT_AUTOCOMMIT)) { @@ -6478,11 +6481,21 @@ ha_innobase::store_lock( if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) { + /* Starting from 5.0.7, we weaken also the table locks + set at the start of a MySQL stored procedure call, just like + we weaken the locks set at the start of an SQL statement. + MySQL does set thd->in_lock_tables TRUE there, but in reality + we do not need table locks to make the execution of a + single transaction stored procedure call deterministic + (if it does not use a consistent read). */ + /* If we are not doing a LOCK TABLE or DISCARD/IMPORT TABLESPACE or TRUNCATE TABLE, then allow multiple writers */ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) && !thd->in_lock_tables + lock_type <= TL_WRITE) + && (!thd->in_lock_tables + || thd->lex->sql_command == SQLCOM_CALL) && !thd->tablespace_op && thd->lex->sql_command != SQLCOM_TRUNCATE && thd->lex->sql_command != SQLCOM_CREATE_TABLE) { @@ -6496,7 +6509,10 @@ ha_innobase::store_lock( to t2. Convert the lock to a normal read lock to allow concurrent inserts to t2. */ - if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) { + if (lock_type == TL_READ_NO_INSERT + && (!thd->in_lock_tables + || thd->lex->sql_command == SQLCOM_CALL)) { + lock_type = TL_READ; } -- cgit v1.2.1 From 33b114aac25c787ca6a49a099c14af765c19a71b Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 2 Jun 2005 10:00:32 -0700 Subject: item_func.h: Identation correction for the fix of bug #9939. sql/item_func.h: Identation correction for the fix of bug #9939. --- sql/item_func.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sql') diff --git a/sql/item_func.h b/sql/item_func.h index 797aec952f9..f0c7e25ad53 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -189,13 +189,13 @@ class Item_func_numhybrid: public Item_func protected: Item_result hybrid_type; public: - Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT) + Item_func_numhybrid(Item *a) :Item_func(a), hybrid_type(REAL_RESULT) {} Item_func_numhybrid(Item *a,Item *b) - :Item_func(a,b),hybrid_type(REAL_RESULT) + :Item_func(a,b), hybrid_type(REAL_RESULT) {} Item_func_numhybrid(List &list) - :Item_func(list),hybrid_type(REAL_RESULT) + :Item_func(list), hybrid_type(REAL_RESULT) {} enum Item_result result_type () const { return hybrid_type; } -- cgit v1.2.1 From 892032a2c2db6ecbe983578132f34ce8dc596048 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Jun 2005 00:02:47 +0400 Subject: Give Item_arena::is_stmt_prepare a more descriptive name (it marks the code that is active for SP as well in 5.0) sql/item.cc: Rename of an Item_arena method. sql/item_subselect.cc: Rename of an Item_arena method. sql/sql_class.h: Rename of an Item_arena method. sql/sql_parse.cc: Rename of an Item_arena method. sql/sql_union.cc: Rename of an Item_arena method. --- sql/item.cc | 2 +- sql/item_subselect.cc | 2 +- sql/sql_class.h | 3 ++- sql/sql_parse.cc | 4 ++-- sql/sql_union.cc | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/item.cc b/sql/item.cc index 0db9a56055f..a9c1ef7198e 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1027,7 +1027,7 @@ Item_field::Item_field(THD *thd, Field *f) structure can go away and pop up again between subsequent executions of a prepared statement). */ - if (thd->current_arena->is_stmt_prepare()) + if (thd->current_arena->is_stmt_prepare_or_first_sp_execute()) { if (db_name) orig_db_name= thd->strdup(db_name); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b7aefdd6f2e..4f1e5b9a290 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -362,7 +362,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join) because we do not rollback this changes TODO: make rollback for it, or special name resolving mode in 5.0. */ - !arena->is_stmt_prepare() + !arena->is_stmt_prepare_or_first_sp_execute() ) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 47987f3a0c6..7c8ead7558e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -695,7 +695,8 @@ public: virtual Type type() const; virtual ~Item_arena() {}; - inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; } + inline bool is_stmt_prepare_or_first_sp_execute() const + { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } inline bool is_stmt_execute() const { return state == PREPARED || state == EXECUTED; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 2af9191110c..a9e68de3705 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5894,7 +5894,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->db= empty_c_string; ptr->db_length= 0; } - if (thd->current_arena->is_stmt_prepare()) + if (thd->current_arena->is_stmt_prepare_or_first_sp_execute()) ptr->db= thd->strdup(ptr->db); ptr->alias= alias_str; @@ -6972,7 +6972,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables, against the opened tables to ensure we don't use a table that is part of the view (which can only be done after the table has been opened). */ - if (thd->current_arena->is_stmt_prepare()) + if (thd->current_arena->is_stmt_prepare_or_first_sp_execute()) { /* For temporary tables we don't have to check if the created table exists diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 8d36889df76..56401ced67c 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -323,7 +323,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } if (tmp_arena) thd->restore_backup_item_arena(tmp_arena, &backup); - if (arena->is_stmt_prepare()) + if (arena->is_stmt_prepare_or_first_sp_execute()) { /* prepare fake select to initialize it correctly */ init_prepare_fake_select_lex(thd); -- cgit v1.2.1 From 52b70ceff707657a91787a6b67ce79ca015dcabf Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Jun 2005 09:37:53 +0500 Subject: ctype_utf8.result, ctype_utf8.test: adding test field.cc: bug#10714 Inserting double value into utf8 column crashes server: sprintf was executed with too big length, which caused crash on some Windows platforms. sql/field.cc: bug#10714 Inserting double value into utf8 column crashes server sprintf was executed with too long length, which cau crashe on Windows. mysql-test/t/ctype_utf8.test: adding test mysql-test/r/ctype_utf8.result: adding test --- sql/field.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'sql') diff --git a/sql/field.cc b/sql/field.cc index 60287d4003b..21c3fe12bb2 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4981,31 +4981,32 @@ int Field_str::store(double nr) char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; uint length; bool use_scientific_notation= TRUE; + uint char_length= field_length / charset()->mbmaxlen; /* Check fabs(nr) against longest value that can be stored in field, which depends on whether the value is < 1 or not, and negative or not */ double anr= fabs(nr); int neg= (nr < 0.0) ? 1 : 0; - if (field_length > 4 && field_length < 32 && - (anr < 1.0 ? anr > 1/(log_10[max(0,field_length-neg-2)]) /* -2 for "0." */ - : anr < log_10[field_length-neg]-1)) + if (char_length > 4 && char_length < 32 && + (anr < 1.0 ? anr > 1/(log_10[max(0,char_length-neg-2)]) /* -2 for "0." */ + : anr < log_10[char_length-neg]-1)) use_scientific_notation= FALSE; length= (uint) my_sprintf(buff, (buff, "%-.*g", (use_scientific_notation ? - max(0, (int)field_length-neg-5) : - field_length), + max(0, (int)char_length-neg-5) : + char_length), nr)); /* +1 below is because "precision" in %g above means the max. number of significant digits, not the output width. Thus the width can be larger than number of significant digits by 1 (for decimal point) - the test for field_length < 5 is for extreme cases, + the test for char_length < 5 is for extreme cases, like inserting 500.0 in char(1) */ - DBUG_ASSERT(field_length < 5 || length <= field_length+1); + DBUG_ASSERT(char_length < 5 || length <= char_length+1); return store((const char *) buff, length, charset()); } -- cgit v1.2.1 From 6de5ae6816ceb682f2856d7d45704d80d75adef8 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Jun 2005 12:56:51 +0200 Subject: Post review fix of BUG#10969. sql/item.h: Return name as LEX_STRING instead of its components. sql/sql_yacc.yy: Name returned as LEX_STRING instead of its components. --- sql/item.h | 8 +++++--- sql/sql_yacc.yy | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'sql') diff --git a/sql/item.h b/sql/item.h index f2e8e582780..4f5ed9934c5 100644 --- a/sql/item.h +++ b/sql/item.h @@ -585,10 +585,12 @@ public: } /* For error printing */ - inline void my_name(char **strp, uint *lengthp) + inline LEX_STRING *my_name(LEX_STRING *get_name) { - *strp= m_name.str; - *lengthp= m_name.length; + if (!get_name) + return &m_name; + (*get_name)= m_name; + return get_name; } bool is_splocal() { return 1; } /* Needed for error checking */ diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c0f5d6e296c..2f584bc6b4e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4346,11 +4346,11 @@ simple_expr: { if ($3->is_splocal()) { - LEX_STRING name; + LEX_STRING *name; Item_splocal *il= static_cast($3); - il->my_name(&name.str, &name.length); - my_error(ER_WRONG_COLUMN_NAME, MYF(0), name.str); + name= il->my_name(NULL); + my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str); YYABORT; } $$= new Item_default_value($3); -- cgit v1.2.1 From 2906e27a7c3a287be6af12fa2969c034f37f5b40 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Jun 2005 13:43:17 +0200 Subject: yassl template instantiation - don't do too much mysys/my_access.c: remove incorrect fix comments extra/yassl/taocrypt/src/integer.cpp: yassl template instantiation - don't do too much extra/yassl/taocrypt/src/template_instnt.cpp: yassl template instantiation - don't do too much mysys/my_access.c: remove incorrect fix sql/item_func.cc: a couple of comment. assert added. --- sql/item_func.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'sql') diff --git a/sql/item_func.cc b/sql/item_func.cc index 18c2efb0ace..5af99cb8132 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -695,8 +695,8 @@ String *Item_int_func::val_str(String *str) /* - Check arguments here to determine result's type for function with two - arguments. + Check arguments here to determine result's type for a numeric + function of two arguments. SYNOPSIS Item_num_op::find_num_type() @@ -722,8 +722,9 @@ void Item_num_op::find_num_type(void) hybrid_type= DECIMAL_RESULT; result_precision(); } - else if (r0 == INT_RESULT && r1 == INT_RESULT) + else { + DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT); decimals= 0; hybrid_type=INT_RESULT; result_precision(); @@ -738,7 +739,9 @@ void Item_num_op::find_num_type(void) /* - Set result type of function if it (type) is depends only on first argument + Set result type for a numeric function of one argument + (can be also used by a numeric function of many arguments, if the result + type depends only on the first argument) SYNOPSIS Item_func_num1::find_num_type() -- cgit v1.2.1