summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormskold/marty@linux.site <>2007-04-24 15:11:22 +0200
committermskold/marty@linux.site <>2007-04-24 15:11:22 +0200
commitcabef956c24d2d1ff91f9b7f794e73652cfef780 (patch)
tree1b0aeb3810da954769837643337d6d533291a411
parentcf8ef29ca047f433fe6a3a90562a5d2c3a6f240f (diff)
parentfb6b0708b1230d2c6ea6adbb13170ff9e430c2d4 (diff)
downloadmariadb-git-cabef956c24d2d1ff91f9b7f794e73652cfef780.tar.gz
Merge mskold@bk-internal.mysql.com:/home/bk/mysql-5.1-ndb
into mysql.com:/windows/Linux_space/MySQL/mysql-5.1-new-ndb
-rw-r--r--libmysqld/Makefile.am5
-rw-r--r--sql/Makefile.am15
-rw-r--r--sql/ha_ndbcluster.cc1409
-rw-r--r--sql/ha_ndbcluster.h443
-rw-r--r--sql/ha_ndbcluster_cond.cc1426
-rw-r--r--sql/ha_ndbcluster_cond.h475
6 files changed, 1947 insertions, 1826 deletions
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index cef91899e62..a9e951cb9af 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -45,7 +45,7 @@ libmysqlsources = errmsg.c get_password.c libmysql.c client.c pack.c \
noinst_HEADERS = embedded_priv.h emb_qcache.h
sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
- ha_ndbcluster.cc \
+ ha_ndbcluster.cc ha_ndbcluster_cond.cc \
ha_ndbcluster_binlog.cc ha_partition.cc \
handler.cc sql_handler.cc \
hostname.cc init.cc password.c \
@@ -107,6 +107,9 @@ endif
ha_ndbcluster.o:ha_ndbcluster.cc
$(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
+ha_ndbcluster_cond.o:ha_ndbcluster_cond.cc
+ $(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
+
ha_ndbcluster_binlog.o: ha_ndbcluster_binlog.cc
$(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
diff --git a/sql/Makefile.am b/sql/Makefile.am
index a04386611f8..08f5d7c7e78 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -48,9 +48,9 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_map.h sql_string.h unireg.h \
sql_error.h field.h handler.h mysqld_suffix.h \
- ha_partition.h \
- ha_ndbcluster.h ha_ndbcluster_binlog.h \
- ha_ndbcluster_tables.h rpl_constants.h \
+ ha_ndbcluster.h ha_ndbcluster_cond.h \
+ ha_ndbcluster_binlog.h ha_ndbcluster_tables.h
+ ha_partition.h rpl_constants.h \
opt_range.h protocol.h rpl_tblmap.h rpl_utility.h \
log.h sql_show.h rpl_rli.h rpl_mi.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h \
@@ -92,8 +92,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
log_event_old.cc rpl_record_old.cc \
discover.cc time.cc opt_range.cc opt_sum.cc \
records.cc filesort.cc handler.cc \
- ha_partition.cc \
- ha_ndbcluster.cc ha_ndbcluster_binlog.cc \
+ ha_ndbcluster.cc ha_ndbcluster_cond.cc \
+ ha_ndbcluster_binlog.cc ha_partition.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
@@ -156,10 +156,13 @@ lex_hash.h: gen_lex_hash.cc lex.h
./gen_lex_hash$(EXEEXT) > $@-t
$(MV) $@-t $@
-# the following three should eventually be moved out of this directory
+# the following four should eventually be moved out of this directory
ha_ndbcluster.o:ha_ndbcluster.cc ha_ndbcluster.h
$(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
+ha_ndbcluster_cond.o:ha_ndbcluster_cond.cc ha_ndbcluster_cond.h
+ $(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
+
ha_ndbcluster_binlog.o:ha_ndbcluster_binlog.cc ha_ndbcluster_binlog.h
$(CXXCOMPILE) @ndbcluster_includes@ $(LM_CFLAGS) -c $<
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 7f5c1cfd494..07e4f580ca1 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -30,7 +30,7 @@
#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
#include "ha_ndbcluster.h"
#include <ndbapi/NdbApi.hpp>
-#include <ndbapi/NdbScanFilter.hpp>
+#include "ha_ndbcluster_cond.h"
#include <../util/Bitmask.hpp>
#include <ndbapi/NdbIndexStat.hpp>
@@ -2403,7 +2403,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
if (!restart)
{
- if (generate_scan_filter(m_cond_stack, op))
+ if (m_cond && m_cond->generate_scan_filter(op))
DBUG_RETURN(ndb_err(trans));
if ((res= define_read_attrs(buf, op)))
@@ -2509,8 +2509,14 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info,
(get_ndb_partition_id(op)))
ERR_RETURN(trans->getNdbError());
}
-
- if (generate_scan_filter_from_key(op, key_info, key, key_len, buf))
+ if (!m_cond)
+ m_cond= new ha_ndbcluster_cond;
+ if (!m_cond)
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(my_errno);
+ }
+ if (m_cond->generate_scan_filter_from_key(op, key_info, key, key_len, buf))
DBUG_RETURN(ndb_err(trans));
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
@@ -2579,7 +2585,7 @@ int ha_ndbcluster::full_table_scan(byte *buf)
ERR_RETURN(trans->getNdbError());
}
- if (generate_scan_filter(m_cond_stack, op))
+ if (m_cond && m_cond->generate_scan_filter(op))
DBUG_RETURN(ndb_err(trans));
if ((res= define_read_attrs(buf, op)))
DBUG_RETURN(res);
@@ -3969,7 +3975,11 @@ int ha_ndbcluster::extra(enum ha_extra_function operation)
int ha_ndbcluster::reset()
{
DBUG_ENTER("ha_ndbcluster::reset");
- cond_clear();
+ if (m_cond)
+ {
+ m_cond->cond_clear();
+ }
+
/*
Regular partition pruning will set the bitmap appropriately.
Some queries like ALTER TABLE doesn't use partition pruning and
@@ -6036,7 +6046,7 @@ ha_ndbcluster::ha_ndbcluster(handlerton *hton, TABLE_SHARE *table_arg):
m_force_send(TRUE),
m_autoincrement_prefetch((ha_rows) 32),
m_transaction_on(TRUE),
- m_cond_stack(NULL),
+ m_cond(NULL),
m_multi_cursor(NULL)
{
int i;
@@ -6095,9 +6105,13 @@ ha_ndbcluster::~ha_ndbcluster()
}
DBUG_ASSERT(m_active_trans == NULL);
- // Discard the condition stack
- DBUG_PRINT("info", ("Clearing condition stack"));
- cond_clear();
+ // Discard any generated condition
+ DBUG_PRINT("info", ("Deleting generated condition"));
+ if (m_cond)
+ {
+ delete m_cond;
+ m_cond= NULL;
+ }
DBUG_VOID_RETURN;
}
@@ -8469,7 +8483,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
else if ((scanOp= m_active_trans->getNdbIndexScanOperation(idx, tab))
&&!scanOp->readTuples(lm, 0, parallelism, sorted,
FALSE, TRUE, need_pk, TRUE)
- &&!generate_scan_filter(m_cond_stack, scanOp)
+ &&!(m_cond && m_cond->generate_scan_filter(scanOp))
&&!define_read_attrs(end_of_buffer-reclength, scanOp))
{
m_multi_cursor= scanOp;
@@ -9055,28 +9069,15 @@ COND*
ha_ndbcluster::cond_push(const COND *cond)
{
DBUG_ENTER("cond_push");
- Ndb_cond_stack *ndb_cond = new Ndb_cond_stack();
- if (ndb_cond == NULL)
+ if (!m_cond)
+ m_cond= new ha_ndbcluster_cond;
+ if (!m_cond)
{
my_errno= HA_ERR_OUT_OF_MEM;
DBUG_RETURN(NULL);
}
DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname););
- if (m_cond_stack)
- ndb_cond->next= m_cond_stack;
- else
- ndb_cond->next= NULL;
- m_cond_stack= ndb_cond;
-
- if (serialize_cond(cond, ndb_cond))
- {
- DBUG_RETURN(NULL);
- }
- else
- {
- cond_pop();
- }
- DBUG_RETURN(cond);
+ DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table));
}
/*
@@ -9085,1356 +9086,8 @@ ha_ndbcluster::cond_push(const COND *cond)
void
ha_ndbcluster::cond_pop()
{
- Ndb_cond_stack *ndb_cond_stack= m_cond_stack;
- if (ndb_cond_stack)
- {
- m_cond_stack= ndb_cond_stack->next;
- delete ndb_cond_stack;
- }
-}
-
-/*
- Clear the condition stack
-*/
-void
-ha_ndbcluster::cond_clear()
-{
- DBUG_ENTER("cond_clear");
- while (m_cond_stack)
- cond_pop();
-
- DBUG_VOID_RETURN;
-}
-
-/*
- Serialize the item tree into a linked list represented by Ndb_cond
- for fast generation of NbdScanFilter. Adds information such as
- position of fields that is not directly available in the Item tree.
- Also checks if condition is supported.
-*/
-void ndb_serialize_cond(const Item *item, void *arg)
-{
- Ndb_cond_traverse_context *context= (Ndb_cond_traverse_context *) arg;
- DBUG_ENTER("ndb_serialize_cond");
-
- // Check if we are skipping arguments to a function to be evaluated
- if (context->skip)
- {
- DBUG_PRINT("info", ("Skiping argument %d", context->skip));
- context->skip--;
- switch (item->type()) {
- case Item::FUNC_ITEM:
- {
- Item_func *func_item= (Item_func *) item;
- context->skip+= func_item->argument_count();
- break;
- }
- case Item::INT_ITEM:
- case Item::REAL_ITEM:
- case Item::STRING_ITEM:
- case Item::VARBIN_ITEM:
- case Item::DECIMAL_ITEM:
- break;
- default:
- context->supported= FALSE;
- break;
- }
-
- DBUG_VOID_RETURN;
- }
-
- if (context->supported)
- {
- Ndb_rewrite_context *rewrite_context2= context->rewrite_stack;
- const Item_func *rewrite_func_item;
- // Check if we are rewriting some unsupported function call
- if (rewrite_context2 &&
- (rewrite_func_item= rewrite_context2->func_item) &&
- rewrite_context2->count++ == 0)
- {
- switch (rewrite_func_item->functype()) {
- case Item_func::BETWEEN:
- /*
- Rewrite
- <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
- to <field>|<const> > <const1>|<field1> AND
- <field>|<const> < <const2>|<field2>
- or actually in prefix format
- BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
- LT(<field>|<const>, <const2>|<field2>), END()
- */
- case Item_func::IN_FUNC:
- {
- /*
- Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
- to <field>|<const> = <const1>|<field1> OR
- <field> = <const2>|<field2> ...
- or actually in prefix format
- BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
- EQ(<field>|<const>, <const2>|<field2>), ... 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 <field>|<const> item, save it in the rewrite context
- rewrite_context2->left_hand_item= item;
- if (item->type() == Item::FUNC_ITEM)
- {
- Item_func *func_item= (Item_func *) item;
- if (func_item->functype() == Item_func::UNKNOWN_FUNC &&
- func_item->const_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();
- }
- else
- {
- DBUG_PRINT("info", ("Found unsupported functional expression in BETWEEN|IN"));
- context->supported= FALSE;
- DBUG_VOID_RETURN;
-
- }
- }
- }
- else
- {
- // Non-supported BETWEEN|IN expression
- DBUG_PRINT("info", ("Found unexpected item of type %u in BETWEEN|IN",
- item->type()));
- context->supported= FALSE;
- 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::BETWEEN:
- {
- /*
- Rewrite
- <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
- to <field>|<const> > <const1>|<field1> AND
- <field>|<const> < <const2>|<field2>
- or actually in prefix format
- BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
- LT(<field>|<const>, <const2>|<field2>), 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::IN_FUNC:
- {
- /*
- Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
- to <field>|<const> = <const1>|<field1> OR
- <field> = <const2>|<field2> ...
- or actually in prefix format
- BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
- EQ(<field>|<const>, <const2>|<field2>), ... 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;
- }
- default:
- context->supported= FALSE;
- }
- // Handle left hand <field>|<const>
- 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->s == field->table->s)
- {
- 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", ("type %d", field->type()));
- 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_type(field->type()) &&
- (context->expecting_field_result(field->result_type()) ||
- // Date and year can be written as string or int
- ((type == MYSQL_TYPE_TIME ||
- type == MYSQL_TYPE_DATE ||
- type == MYSQL_TYPE_YEAR ||
- type == MYSQL_TYPE_DATETIME)
- ? (context->expecting_field_result(STRING_RESULT) ||
- context->expecting_field_result(INT_RESULT))
- : TRUE)) &&
- // Bit fields no yet supported in scan filter
- type != MYSQL_TYPE_BIT &&
- // No BLOB support in scan filter
- type != MYSQL_TYPE_TINY_BLOB &&
- type != MYSQL_TYPE_MEDIUM_BLOB &&
- type != MYSQL_TYPE_LONG_BLOB &&
- type != MYSQL_TYPE_BLOB)
- {
- 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->expecting_nothing())
- {
- // 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);
- context->expect(Item::INT_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);
- context->expect(Item::INT_ITEM);
- break;
- default:
- break;
- }
- }
- 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)
- && 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;
- }
- }
- break;
- }
- else
- {
- DBUG_PRINT("info", ("Was not expecting field of type %u(%u)",
- field->result_type(), type));
- context->supported= FALSE;
- }
- }
- else
- {
- DBUG_PRINT("info", ("Was not expecting field from table %s (%s)",
- context->table->s->table_name.str,
- field->table->s->table_name.str));
- 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
- context->supported= FALSE;
- break;
- }
-
- 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_only_field_type(MYSQL_TYPE_STRING);
- context->expect_field_type(MYSQL_TYPE_VAR_STRING);
- context->expect_field_type(MYSQL_TYPE_VARCHAR);
- 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;
- }
- case Item_func::BETWEEN:
- {
- DBUG_PRINT("info", ("BETWEEN, rewriting using AND"));
- Item_func_between *between_func= (Item_func_between *) func_item;
- Ndb_rewrite_context *rewrite_context=
- new Ndb_rewrite_context(func_item);
- rewrite_context->next= context->rewrite_stack;
- context->rewrite_stack= rewrite_context;
- if (between_func->negated)
- {
- DBUG_PRINT("info", ("NOT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
- prev_cond= curr_cond;
- curr_cond= context->cond_ptr= new Ndb_cond();
- curr_cond->prev= prev_cond;
- prev_cond->next= curr_cond;
- }
- 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(Item::INT_ITEM);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FUNC_ITEM);
- break;
- }
- case Item_func::IN_FUNC:
- {
- DBUG_PRINT("info", ("IN_FUNC, rewriting using OR"));
- Item_func_in *in_func= (Item_func_in *) func_item;
- Ndb_rewrite_context *rewrite_context=
- new Ndb_rewrite_context(func_item);
- rewrite_context->next= context->rewrite_stack;
- context->rewrite_stack= rewrite_context;
- if (in_func->negated)
- {
- DBUG_PRINT("info", ("NOT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
- prev_cond= curr_cond;
- curr_cond= context->cond_ptr= new Ndb_cond();
- curr_cond->prev= prev_cond;
- prev_cond->next= curr_cond;
- }
- 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->expecting_no_field_result())
- {
- // 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->expecting_no_field_result())
- {
- // 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->expecting_no_field_result())
- {
- // 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->expecting_no_field_result())
- {
- // 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;
- }
- 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->expecting_no_field_result())
- {
- // 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))
- {
- DBUG_PRINT("info", ("value %ld",
- (long) ((Item_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->expecting_no_field_result())
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(INT_RESULT);
- context->expect_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::REAL_ITEM:
- DBUG_PRINT("info", ("REAL_ITEM"));
- if (context->expecting(Item::REAL_ITEM))
- {
- DBUG_PRINT("info", ("value %f", ((Item_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->expecting_no_field_result())
- {
- // 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::VARBIN_ITEM:
- DBUG_PRINT("info", ("VARBIN_ITEM"));
- if (context->expecting(Item::VARBIN_ITEM))
- {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::VARBIN_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (! context->expecting_no_field_result())
- {
- // 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"));
- if (context->expecting(Item::DECIMAL_ITEM))
- {
- DBUG_PRINT("info", ("value %f",
- ((Item_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->expecting_no_field_result())
- {
- // 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;
- }
- 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();
- curr_cond->prev= prev_cond;
- prev_cond->next= curr_cond;
- curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
- // Pop rewrite stack
- context->rewrite_stack= rewrite_context->next;
- rewrite_context->next= NULL;
- delete(rewrite_context);
- }
- }
- }
- }
-
- DBUG_VOID_RETURN;
-}
-
-bool
-ha_ndbcluster::serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond)
-{
- DBUG_ENTER("serialize_cond");
- Item *item= (Item *) cond;
- Ndb_cond_traverse_context context(table, (void *)m_table, ndb_cond);
- // Expect a logical expression
- context.expect(Item::FUNC_ITEM);
- context.expect(Item::COND_ITEM);
- item->traverse_cond(&ndb_serialize_cond, (void *) &context, Item::PREFIX);
- DBUG_PRINT("info", ("The pushed condition is %ssupported", (context.supported)?"":"not "));
-
- DBUG_RETURN(context.supported);
-}
-
-int
-ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond,
- NdbScanFilter *filter,
- bool negated)
-{
- DBUG_ENTER("build_scan_filter_predicate");
- switch (cond->ndb_item->type) {
- case NDB_FUNCTION:
- {
- if (!cond->next)
- break;
- Ndb_item *a= cond->next->ndb_item;
- Ndb_item *b, *field, *value= NULL;
-
- switch (cond->ndb_item->argument_count()) {
- case 1:
- field= (a->type == NDB_FIELD)? a : NULL;
- break;
- case 2:
- if (!cond->next->next)
- {
- field= NULL;
- break;
- }
- b= cond->next->next->ndb_item;
- value= ((a->type == NDB_VALUE) ? a :
- (b->type == NDB_VALUE) ? b :
- NULL);
- field= ((a->type == NDB_FIELD) ? a :
- (b->type == NDB_FIELD) ? b :
- NULL);
- break;
- default:
- field= NULL; //Keep compiler happy
- DBUG_ASSERT(0);
- break;
- }
- switch ((negated) ?
- Ndb_item::negate(cond->ndb_item->qualification.function_type)
- : cond->ndb_item->qualification.function_type) {
- case NDB_EQ_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating EQ filter"));
- if (filter->cmp(NdbScanFilter::COND_EQ,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_NE_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating NE filter"));
- if (filter->cmp(NdbScanFilter::COND_NE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_LT_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating LT filter"));
- if (filter->cmp(NdbScanFilter::COND_LT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating GT filter"));
- if (filter->cmp(NdbScanFilter::COND_GT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_LE_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating LE filter"));
- if (filter->cmp(NdbScanFilter::COND_LE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating GE filter"));
- if (filter->cmp(NdbScanFilter::COND_GE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_GE_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating GE filter"));
- if (filter->cmp(NdbScanFilter::COND_GE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating LE filter"));
- if (filter->cmp(NdbScanFilter::COND_LE,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_GT_FUNC:
- {
- if (!value || !field) break;
- // Save value in right format for the field type
- value->save_in_field(field);
- if (a == field)
- {
- DBUG_PRINT("info", ("Generating GT filter"));
- if (filter->cmp(NdbScanFilter::COND_GT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating LT filter"));
- if (filter->cmp(NdbScanFilter::COND_LT,
- field->get_field_no(),
- field->get_val(),
- field->pack_length()) == -1)
- DBUG_RETURN(1);
- }
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_LIKE_FUNC:
- {
- if (!value || !field) break;
- if ((value->qualification.value_type != Item::STRING_ITEM) &&
- (value->qualification.value_type != Item::VARBIN_ITEM))
- break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating LIKE filter: like(%d,%s,%d)",
- field->get_field_no(), value->get_val(),
- value->pack_length()));
- if (filter->cmp(NdbScanFilter::COND_LIKE,
- field->get_field_no(),
- value->get_val(),
- value->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_NOTLIKE_FUNC:
- {
- if (!value || !field) break;
- if ((value->qualification.value_type != Item::STRING_ITEM) &&
- (value->qualification.value_type != Item::VARBIN_ITEM))
- break;
- // Save value in right format for the field type
- value->save_in_field(field);
- DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)",
- field->get_field_no(), value->get_val(),
- value->pack_length()));
- if (filter->cmp(NdbScanFilter::COND_NOT_LIKE,
- field->get_field_no(),
- value->get_val(),
- value->pack_length()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next->next;
- DBUG_RETURN(0);
- }
- case NDB_ISNULL_FUNC:
- if (!field)
- break;
- DBUG_PRINT("info", ("Generating ISNULL filter"));
- if (filter->isnull(field->get_field_no()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next;
- DBUG_RETURN(0);
- case NDB_ISNOTNULL_FUNC:
- {
- if (!field)
- break;
- DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
- if (filter->isnotnull(field->get_field_no()) == -1)
- DBUG_RETURN(1);
- cond= cond->next->next;
- DBUG_RETURN(0);
- }
- default:
- break;
- }
- break;
- }
- default:
- break;
- }
- DBUG_PRINT("info", ("Found illegal condition"));
- DBUG_RETURN(1);
-}
-
-
-int
-ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
-{
- uint level=0;
- bool negated= FALSE;
- DBUG_ENTER("build_scan_filter_group");
-
- do
- {
- if (!cond)
- DBUG_RETURN(1);
- switch (cond->ndb_item->type) {
- case NDB_FUNCTION:
- {
- switch (cond->ndb_item->qualification.function_type) {
- case NDB_COND_AND_FUNC:
- {
- level++;
- DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
- level));
- if ((negated) ? filter->begin(NdbScanFilter::NAND)
- : filter->begin(NdbScanFilter::AND) == -1)
- DBUG_RETURN(1);
- negated= FALSE;
- cond= cond->next;
- break;
- }
- case NDB_COND_OR_FUNC:
- {
- level++;
- DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
- level));
- if ((negated) ? filter->begin(NdbScanFilter::NOR)
- : filter->begin(NdbScanFilter::OR) == -1)
- DBUG_RETURN(1);
- negated= FALSE;
- cond= cond->next;
- break;
- }
- case NDB_NOT_FUNC:
- {
- DBUG_PRINT("info", ("Generating negated query"));
- cond= cond->next;
- negated= TRUE;
- break;
- }
- default:
- if (build_scan_filter_predicate(cond, filter, negated))
- DBUG_RETURN(1);
- negated= FALSE;
- break;
- }
- break;
- }
- case NDB_END_COND:
- DBUG_PRINT("info", ("End of group %u", level));
- level--;
- if (cond) cond= cond->next;
- if (filter->end() == -1)
- DBUG_RETURN(1);
- if (!negated)
- break;
- // else fall through (NOT END is an illegal condition)
- default:
- {
- DBUG_PRINT("info", ("Illegal scan filter"));
- }
- }
- } while (level > 0 || negated);
-
- DBUG_RETURN(0);
-}
-
-
-int
-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 NDB_FUNCTION:
- switch (cond->ndb_item->qualification.function_type) {
- case NDB_COND_AND_FUNC:
- case NDB_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))
- DBUG_RETURN(1);
- if (simple_cond && filter->end() == -1)
- DBUG_RETURN(1);
-
- DBUG_RETURN(0);
-}
-
-int
-ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack,
- NdbScanOperation *op)
-{
- DBUG_ENTER("generate_scan_filter");
-
- if (ndb_cond_stack)
- {
- NdbScanFilter filter(op);
-
- DBUG_RETURN(generate_scan_filter_from_cond(ndb_cond_stack, filter));
- }
- else
- {
- DBUG_PRINT("info", ("Empty stack"));
- }
-
- DBUG_RETURN(0);
-}
-
-
-int
-ha_ndbcluster::generate_scan_filter_from_cond(Ndb_cond_stack *ndb_cond_stack,
- NdbScanFilter& filter)
-{
- bool multiple_cond= FALSE;
- DBUG_ENTER("generate_scan_filter_from_cond");
-
- // Wrap an AND group around multiple conditions
- if (ndb_cond_stack->next)
- {
- multiple_cond= TRUE;
- if (filter.begin() == -1)
- DBUG_RETURN(1);
- }
- for (Ndb_cond_stack *stack= ndb_cond_stack;
- (stack);
- stack= stack->next)
- {
- Ndb_cond *cond= stack->ndb_cond;
-
- if (build_scan_filter(cond, &filter))
- {
- DBUG_PRINT("info", ("build_scan_filter failed"));
- DBUG_RETURN(1);
- }
- }
- if (multiple_cond && filter.end() == -1)
- DBUG_RETURN(1);
-
- DBUG_RETURN(0);
-}
-
-
-int ha_ndbcluster::generate_scan_filter_from_key(NdbScanOperation *op,
- const KEY* key_info,
- const byte *key,
- uint key_len,
- byte *buf)
-{
- KEY_PART_INFO* key_part= key_info->key_part;
- KEY_PART_INFO* end= key_part+key_info->key_parts;
- NdbScanFilter filter(op);
- int res;
- DBUG_ENTER("generate_scan_filter_from_key");
-
- filter.begin(NdbScanFilter::AND);
- for (; key_part != end; key_part++)
- {
- Field* field= key_part->field;
- uint32 pack_len= field->pack_length();
- const byte* ptr= key;
- DBUG_PRINT("info", ("Filtering value for %s", field->field_name));
- DBUG_DUMP("key", (char*)ptr, pack_len);
- if (key_part->null_bit)
- {
- DBUG_PRINT("info", ("Generating ISNULL filter"));
- if (filter.isnull(key_part->fieldnr-1) == -1)
- DBUG_RETURN(1);
- }
- else
- {
- DBUG_PRINT("info", ("Generating EQ filter"));
- if (filter.cmp(NdbScanFilter::COND_EQ,
- key_part->fieldnr-1,
- ptr,
- pack_len) == -1)
- DBUG_RETURN(1);
- }
- key += key_part->store_length;
- }
- // Add any pushed condition
- if (m_cond_stack &&
- (res= generate_scan_filter_from_cond(m_cond_stack, filter)))
- DBUG_RETURN(res);
-
- if (filter.end() == -1)
- DBUG_RETURN(1);
-
- DBUG_RETURN(0);
+ if (m_cond)
+ m_cond->cond_pop();
}
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index afc781e762c..df621ff1938 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -37,11 +37,11 @@ class NdbOperation; // Forward declaration
class NdbTransaction; // Forward declaration
class NdbRecAttr; // Forward declaration
class NdbScanOperation;
-class NdbScanFilter;
class NdbIndexScanOperation;
class NdbBlob;
class NdbIndexStat;
class NdbEventOperation;
+class ha_ndbcluster_cond;
// connectstring to cluster if given by mysqld
extern const char *ndbcluster_connectstring;
@@ -161,424 +161,6 @@ struct Ndb_tuple_id_range_guard {
#define NSF_NO_BINLOG 4 /* table should not be binlogged */
#endif
-typedef enum ndb_item_type {
- NDB_VALUE = 0, // Qualified more with Item::Type
- NDB_FIELD = 1, // Qualified from table definition
- NDB_FUNCTION = 2,// Qualified from Item_func::Functype
- NDB_END_COND = 3 // End marker for condition group
-} NDB_ITEM_TYPE;
-
-typedef enum ndb_func_type {
- NDB_EQ_FUNC = 0,
- NDB_NE_FUNC = 1,
- NDB_LT_FUNC = 2,
- NDB_LE_FUNC = 3,
- NDB_GT_FUNC = 4,
- NDB_GE_FUNC = 5,
- NDB_ISNULL_FUNC = 6,
- NDB_ISNOTNULL_FUNC = 7,
- NDB_LIKE_FUNC = 8,
- NDB_NOTLIKE_FUNC = 9,
- NDB_NOT_FUNC = 10,
- NDB_UNKNOWN_FUNC = 11,
- NDB_COND_AND_FUNC = 12,
- NDB_COND_OR_FUNC = 13,
- NDB_UNSUPPORTED_FUNC = 14
-} NDB_FUNC_TYPE;
-
-typedef union ndb_item_qualification {
- Item::Type value_type;
- enum_field_types field_type; // Instead of Item::FIELD_ITEM
- NDB_FUNC_TYPE function_type; // Instead of Item::FUNC_ITEM
-} NDB_ITEM_QUALIFICATION;
-
-typedef struct ndb_item_field_value {
- Field* field;
- int column_no;
-} 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
-{
- NDB_FUNC_TYPE pos_fun;
- NDB_FUNC_TYPE neg_fun;
-};
-
-
-/*
- Define what functions can be negated in condition pushdown.
- Note, these HAVE to be in the same order as in definition enum
-*/
-static const negated_function_mapping neg_map[]=
-{
- {NDB_EQ_FUNC, NDB_NE_FUNC},
- {NDB_NE_FUNC, NDB_EQ_FUNC},
- {NDB_LT_FUNC, NDB_GE_FUNC},
- {NDB_LE_FUNC, NDB_GT_FUNC},
- {NDB_GT_FUNC, NDB_LE_FUNC},
- {NDB_GE_FUNC, NDB_LT_FUNC},
- {NDB_ISNULL_FUNC, NDB_ISNOTNULL_FUNC},
- {NDB_ISNOTNULL_FUNC, NDB_ISNULL_FUNC},
- {NDB_LIKE_FUNC, NDB_NOTLIKE_FUNC},
- {NDB_NOTLIKE_FUNC, NDB_LIKE_FUNC},
- {NDB_NOT_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_UNKNOWN_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_COND_AND_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_COND_OR_FUNC, NDB_UNSUPPORTED_FUNC},
- {NDB_UNSUPPORTED_FUNC, NDB_UNSUPPORTED_FUNC}
-};
-
-/*
- This class is the construction element for serialization of Item tree
- in condition pushdown.
- An instance of Ndb_Item represents a constant, table field reference,
- unary or binary comparison predicate, and start/end of AND/OR.
- Instances of Ndb_Item are stored in a linked list implemented by Ndb_cond
- class.
- The order of elements produced by Ndb_cond::next corresponds to
- breadth-first traversal of the Item (i.e. expression) tree in prefix order.
- AND and OR have arbitrary arity, so the end of AND/OR group is marked with
- Ndb_item with type == NDB_END_COND.
- NOT items represent negated conditions and generate NAND/NOR groups.
-*/
-class Ndb_item {
- public:
- Ndb_item(NDB_ITEM_TYPE item_type) : type(item_type) {};
- Ndb_item(NDB_ITEM_TYPE item_type,
- NDB_ITEM_QUALIFICATION item_qualification,
- const Item *item_value)
- : type(item_type), qualification(item_qualification)
- {
- switch(item_type) {
- case(NDB_VALUE):
- value.item= item_value;
- break;
- case(NDB_FIELD): {
- NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
- Item_field *field_item= (Item_field *) item_value;
- field_value->field= field_item->field;
- field_value->column_no= -1; // Will be fetched at scan filter generation
- value.field_value= field_value;
- break;
- }
- case(NDB_FUNCTION):
- value.item= item_value;
- value.arg_count= ((Item_func *) item_value)->argument_count();
- break;
- case(NDB_END_COND):
- break;
- }
- };
- Ndb_item(Field *field, int column_no) : type(NDB_FIELD)
- {
- NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
- qualification.field_type= field->type();
- field_value->field= field;
- field_value->column_no= column_no;
- value.field_value= field_value;
- };
- Ndb_item(Item_func::Functype func_type, const Item *item_value)
- : type(NDB_FUNCTION)
- {
- qualification.function_type= item_func_to_ndb_func(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= item_func_to_ndb_func(func_type);
- value.arg_count= no_args;
- };
- ~Ndb_item()
- {
- if (type == NDB_FIELD)
- {
- delete value.field_value;
- value.field_value= NULL;
- }
- };
-
- uint32 pack_length()
- {
- switch(type) {
- case(NDB_VALUE):
- if(qualification.value_type == Item::STRING_ITEM)
- return value.item->str_value.length();
- break;
- case(NDB_FIELD):
- return value.field_value->field->pack_length();
- default:
- break;
- }
-
- return 0;
- };
-
- Field * get_field() { return value.field_value->field; };
-
- int get_field_no() { return value.field_value->column_no; };
-
- int argument_count()
- {
- return value.arg_count;
- };
-
- const char* get_val()
- {
- switch(type) {
- case(NDB_VALUE):
- if(qualification.value_type == Item::STRING_ITEM)
- return value.item->str_value.ptr();
- break;
- case(NDB_FIELD):
- return value.field_value->field->ptr;
- default:
- break;
- }
-
- return NULL;
- };
-
- void save_in_field(Ndb_item *field_item)
- {
- Field *field = field_item->value.field_value->field;
- const Item *item= value.item;
-
- if (item && field)
- {
- my_bitmap_map *old_map=
- dbug_tmp_use_all_columns(field->table, field->table->write_set);
- ((Item *)item)->save_in_field(field, FALSE);
- dbug_tmp_restore_column_map(field->table->write_set, old_map);
- }
- };
-
- static NDB_FUNC_TYPE item_func_to_ndb_func(Item_func::Functype fun)
- {
- switch (fun) {
- case (Item_func::EQ_FUNC): { return NDB_EQ_FUNC; }
- case (Item_func::NE_FUNC): { return NDB_NE_FUNC; }
- case (Item_func::LT_FUNC): { return NDB_LT_FUNC; }
- case (Item_func::LE_FUNC): { return NDB_LE_FUNC; }
- case (Item_func::GT_FUNC): { return NDB_GT_FUNC; }
- case (Item_func::GE_FUNC): { return NDB_GE_FUNC; }
- case (Item_func::ISNULL_FUNC): { return NDB_ISNULL_FUNC; }
- case (Item_func::ISNOTNULL_FUNC): { return NDB_ISNOTNULL_FUNC; }
- case (Item_func::LIKE_FUNC): { return NDB_LIKE_FUNC; }
- case (Item_func::NOT_FUNC): { return NDB_NOT_FUNC; }
- case (Item_func::UNKNOWN_FUNC): { return NDB_UNKNOWN_FUNC; }
- case (Item_func::COND_AND_FUNC): { return NDB_COND_AND_FUNC; }
- case (Item_func::COND_OR_FUNC): { return NDB_COND_OR_FUNC; }
- default: { return NDB_UNSUPPORTED_FUNC; }
- }
- };
-
- static NDB_FUNC_TYPE negate(NDB_FUNC_TYPE fun)
- {
- uint i= (uint) fun;
- DBUG_ASSERT(fun == neg_map[i].pos_fun);
- return neg_map[i].neg_fun;
- };
-
- NDB_ITEM_TYPE type;
- NDB_ITEM_QUALIFICATION qualification;
- private:
- NDB_ITEM_VALUE value;
-};
-
-/*
- This class implements a linked list used for storing a
- serialization of the Item tree for condition pushdown.
- */
-class Ndb_cond
-{
- public:
- Ndb_cond() : ndb_item(NULL), next(NULL), prev(NULL) {};
- ~Ndb_cond()
- {
- if (ndb_item) delete ndb_item;
- ndb_item= NULL;
- if (next) delete next;
- next= prev= NULL;
- };
- Ndb_item *ndb_item;
- Ndb_cond *next;
- Ndb_cond *prev;
-};
-
-/*
- This class implements a stack for storing several conditions
- for pushdown (represented as serialized Item trees using Ndb_cond).
- The current implementation only pushes one condition, but is
- prepared for handling several (C1 AND C2 ...) if the logic for
- pushing conditions is extended in sql_select.
-*/
-class Ndb_cond_stack
-{
- public:
- Ndb_cond_stack() : ndb_cond(NULL), next(NULL) {};
- ~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
- is defined on, the serialized representation being generated,
- if the condition found is supported, and information what is
- expected next in the tree inorder for the condition to be supported.
-*/
-class Ndb_cond_traverse_context
-{
- public:
- 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),
- skip(0), collation(NULL), rewrite_stack(NULL)
- {
- // Allocate type checking bitmaps
- bitmap_init(&expect_mask, 0, 512, FALSE);
- bitmap_init(&expect_field_type_mask, 0, 512, FALSE);
- bitmap_init(&expect_field_result_mask, 0, 512, FALSE);
-
- if (stack)
- cond_ptr= stack->ndb_cond;
- };
- ~Ndb_cond_traverse_context()
- {
- bitmap_free(&expect_mask);
- bitmap_free(&expect_field_type_mask);
- bitmap_free(&expect_field_result_mask);
- if (rewrite_stack) delete rewrite_stack;
- }
- void expect(Item::Type type)
- {
- bitmap_set_bit(&expect_mask, (uint) type);
- if (type == Item::FIELD_ITEM) expect_all_field_types();
- };
- void dont_expect(Item::Type type)
- {
- bitmap_clear_bit(&expect_mask, (uint) type);
- };
- bool expecting(Item::Type type)
- {
- return bitmap_is_set(&expect_mask, (uint) type);
- };
- void expect_nothing()
- {
- bitmap_clear_all(&expect_mask);
- };
- bool expecting_nothing()
- {
- return bitmap_is_clear_all(&expect_mask);
- }
- void expect_only(Item::Type type)
- {
- expect_nothing();
- expect(type);
- };
-
- void expect_field_type(enum_field_types type)
- {
- bitmap_set_bit(&expect_field_type_mask, (uint) type);
- };
- void expect_all_field_types()
- {
- bitmap_set_all(&expect_field_type_mask);
- };
- bool expecting_field_type(enum_field_types type)
- {
- return bitmap_is_set(&expect_field_type_mask, (uint) type);
- };
- void expect_no_field_type()
- {
- bitmap_clear_all(&expect_field_type_mask);
- };
- bool expecting_no_field_type()
- {
- return bitmap_is_clear_all(&expect_field_type_mask);
- }
- void expect_only_field_type(enum_field_types result)
- {
- expect_no_field_type();
- expect_field_type(result);
- };
-
- void expect_field_result(Item_result result)
- {
- bitmap_set_bit(&expect_field_result_mask, (uint) result);
- };
- bool expecting_field_result(Item_result result)
- {
- return bitmap_is_set(&expect_field_result_mask, (uint) result);
- };
- void expect_no_field_result()
- {
- bitmap_clear_all(&expect_field_result_mask);
- };
- bool expecting_no_field_result()
- {
- return bitmap_is_clear_all(&expect_field_result_mask);
- }
- void expect_only_field_result(Item_result result)
- {
- expect_no_field_result();
- expect_field_result(result);
- };
- void expect_collation(CHARSET_INFO* col)
- {
- collation= col;
- };
- bool expecting_collation(CHARSET_INFO* col)
- {
- bool matching= (!collation) ? true : (collation == col);
- collation= NULL;
-
- return matching;
- };
-
- TABLE* table;
- void* ndb_table;
- bool supported;
- Ndb_cond_stack* stack_ptr;
- Ndb_cond* cond_ptr;
- MY_BITMAP expect_mask;
- MY_BITMAP expect_field_type_mask;
- MY_BITMAP expect_field_result_mask;
- uint skip;
- CHARSET_INFO* collation;
- Ndb_rewrite_context *rewrite_stack;
-};
-
-
typedef enum ndb_query_state_bits {
NDB_QUERY_NORMAL = 0,
NDB_QUERY_MULTI_READ_RANGE = 1
@@ -906,27 +488,6 @@ private:
void release_completed_operations(NdbTransaction*, bool);
- /*
- Condition pushdown
- */
- void cond_clear();
- bool serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond);
- int build_scan_filter_predicate(Ndb_cond* &cond,
- NdbScanFilter* filter,
- bool negated= false);
- int build_scan_filter_group(Ndb_cond* &cond,
- NdbScanFilter* filter);
- int build_scan_filter(Ndb_cond* &cond, NdbScanFilter* filter);
- int generate_scan_filter(Ndb_cond_stack* cond_stack,
- NdbScanOperation* op);
- int generate_scan_filter_from_cond(Ndb_cond_stack* cond_stack,
- NdbScanFilter& filter);
- int generate_scan_filter_from_key(NdbScanOperation* op,
- const KEY* key_info,
- const byte *key,
- uint key_len,
- byte *buf);
-
friend int execute_commit(ha_ndbcluster*, NdbTransaction*);
friend int execute_no_commit_ignore_no_key(ha_ndbcluster*, NdbTransaction*);
friend int execute_no_commit(ha_ndbcluster*, NdbTransaction*, bool);
@@ -982,7 +543,7 @@ private:
ha_rows m_autoincrement_prefetch;
bool m_transaction_on;
- Ndb_cond_stack *m_cond_stack;
+ ha_ndbcluster_cond *m_cond;
bool m_disable_multi_read;
byte *m_multi_range_result_ptr;
KEY_MULTI_RANGE *m_multi_ranges;
diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc
new file mode 100644
index 00000000000..267be17c330
--- /dev/null
+++ b/sql/ha_ndbcluster_cond.cc
@@ -0,0 +1,1426 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/*
+ This file defines the NDB Cluster handler engine_condition_pushdown
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+
+#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE
+#include <ndbapi/NdbApi.hpp>
+#include "ha_ndbcluster_cond.h"
+
+// Typedefs for long names
+typedef NdbDictionary::Column NDBCOL;
+typedef NdbDictionary::Table NDBTAB;
+
+/*
+ Serialize the item tree into a linked list represented by Ndb_cond
+ for fast generation of NbdScanFilter. Adds information such as
+ position of fields that is not directly available in the Item tree.
+ Also checks if condition is supported.
+*/
+void ndb_serialize_cond(const Item *item, void *arg)
+{
+ Ndb_cond_traverse_context *context= (Ndb_cond_traverse_context *) arg;
+ DBUG_ENTER("ndb_serialize_cond");
+
+ // Check if we are skipping arguments to a function to be evaluated
+ if (context->skip)
+ {
+ DBUG_PRINT("info", ("Skiping argument %d", context->skip));
+ context->skip--;
+ switch (item->type()) {
+ case Item::FUNC_ITEM:
+ {
+ Item_func *func_item= (Item_func *) item;
+ context->skip+= func_item->argument_count();
+ break;
+ }
+ case Item::INT_ITEM:
+ case Item::REAL_ITEM:
+ case Item::STRING_ITEM:
+ case Item::VARBIN_ITEM:
+ case Item::DECIMAL_ITEM:
+ break;
+ default:
+ context->supported= FALSE;
+ break;
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ if (context->supported)
+ {
+ Ndb_rewrite_context *rewrite_context2= context->rewrite_stack;
+ const Item_func *rewrite_func_item;
+ // Check if we are rewriting some unsupported function call
+ if (rewrite_context2 &&
+ (rewrite_func_item= rewrite_context2->func_item) &&
+ rewrite_context2->count++ == 0)
+ {
+ switch (rewrite_func_item->functype()) {
+ case Item_func::BETWEEN:
+ /*
+ Rewrite
+ <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
+ to <field>|<const> > <const1>|<field1> AND
+ <field>|<const> < <const2>|<field2>
+ or actually in prefix format
+ BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
+ LT(<field>|<const>, <const2>|<field2>), END()
+ */
+ case Item_func::IN_FUNC:
+ {
+ /*
+ Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
+ to <field>|<const> = <const1>|<field1> OR
+ <field> = <const2>|<field2> ...
+ or actually in prefix format
+ BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
+ EQ(<field>|<const>, <const2>|<field2>), ... 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 <field>|<const> item, save it in the rewrite context
+ rewrite_context2->left_hand_item= item;
+ if (item->type() == Item::FUNC_ITEM)
+ {
+ Item_func *func_item= (Item_func *) item;
+ if (func_item->functype() == Item_func::UNKNOWN_FUNC &&
+ func_item->const_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();
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Found unsupported functional expression in BETWEEN|IN"));
+ context->supported= FALSE;
+ DBUG_VOID_RETURN;
+
+ }
+ }
+ }
+ else
+ {
+ // Non-supported BETWEEN|IN expression
+ DBUG_PRINT("info", ("Found unexpected item of type %u in BETWEEN|IN",
+ item->type()));
+ context->supported= FALSE;
+ 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::BETWEEN:
+ {
+ /*
+ Rewrite
+ <field>|<const> BETWEEN <const1>|<field1> AND <const2>|<field2>
+ to <field>|<const> > <const1>|<field1> AND
+ <field>|<const> < <const2>|<field2>
+ or actually in prefix format
+ BEGIN(AND) GT(<field>|<const>, <const1>|<field1>),
+ LT(<field>|<const>, <const2>|<field2>), 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::IN_FUNC:
+ {
+ /*
+ Rewrite <field>|<const> IN(<const1>|<field1>, <const2>|<field2>,..)
+ to <field>|<const> = <const1>|<field1> OR
+ <field> = <const2>|<field2> ...
+ or actually in prefix format
+ BEGIN(OR) EQ(<field>|<const>, <const1><field1>),
+ EQ(<field>|<const>, <const2>|<field2>), ... 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;
+ }
+ default:
+ context->supported= FALSE;
+ }
+ // Handle left hand <field>|<const>
+ 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->s == field->table->s)
+ {
+ const NDBTAB *tab= 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", ("type %d", field->type()));
+ 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_type(field->type()) &&
+ (context->expecting_field_result(field->result_type()) ||
+ // Date and year can be written as string or int
+ ((type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ ? (context->expecting_field_result(STRING_RESULT) ||
+ context->expecting_field_result(INT_RESULT))
+ : TRUE)) &&
+ // Bit fields no yet supported in scan filter
+ type != MYSQL_TYPE_BIT &&
+ // No BLOB support in scan filter
+ type != MYSQL_TYPE_TINY_BLOB &&
+ type != MYSQL_TYPE_MEDIUM_BLOB &&
+ type != MYSQL_TYPE_LONG_BLOB &&
+ type != MYSQL_TYPE_BLOB)
+ {
+ 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->expecting_nothing())
+ {
+ // 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);
+ context->expect(Item::INT_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);
+ context->expect(Item::INT_ITEM);
+ break;
+ default:
+ break;
+ }
+ }
+ 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)
+ && 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;
+ }
+ }
+ break;
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Was not expecting field of type %u(%u)",
+ field->result_type(), type));
+ context->supported= FALSE;
+ }
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Was not expecting field from table %s (%s)",
+ context->table->s->table_name.str,
+ field->table->s->table_name.str));
+ 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
+ context->supported= FALSE;
+ break;
+ }
+
+ 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_only_field_type(MYSQL_TYPE_STRING);
+ context->expect_field_type(MYSQL_TYPE_VAR_STRING);
+ context->expect_field_type(MYSQL_TYPE_VARCHAR);
+ 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;
+ }
+ case Item_func::BETWEEN:
+ {
+ DBUG_PRINT("info", ("BETWEEN, rewriting using AND"));
+ Item_func_between *between_func= (Item_func_between *) func_item;
+ Ndb_rewrite_context *rewrite_context=
+ new Ndb_rewrite_context(func_item);
+ rewrite_context->next= context->rewrite_stack;
+ context->rewrite_stack= rewrite_context;
+ if (between_func->negated)
+ {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
+ prev_cond= curr_cond;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ curr_cond->prev= prev_cond;
+ prev_cond->next= curr_cond;
+ }
+ 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(Item::INT_ITEM);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FUNC_ITEM);
+ break;
+ }
+ case Item_func::IN_FUNC:
+ {
+ DBUG_PRINT("info", ("IN_FUNC, rewriting using OR"));
+ Item_func_in *in_func= (Item_func_in *) func_item;
+ Ndb_rewrite_context *rewrite_context=
+ new Ndb_rewrite_context(func_item);
+ rewrite_context->next= context->rewrite_stack;
+ context->rewrite_stack= rewrite_context;
+ if (in_func->negated)
+ {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::NOT_FUNC, 1);
+ prev_cond= curr_cond;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ curr_cond->prev= prev_cond;
+ prev_cond->next= curr_cond;
+ }
+ 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->expecting_no_field_result())
+ {
+ // 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->expecting_no_field_result())
+ {
+ // 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->expecting_no_field_result())
+ {
+ // 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->expecting_no_field_result())
+ {
+ // 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;
+ }
+ 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->expecting_no_field_result())
+ {
+ // 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))
+ {
+ DBUG_PRINT("info", ("value %ld",
+ (long) ((Item_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->expecting_no_field_result())
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ context->expect_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::REAL_ITEM:
+ DBUG_PRINT("info", ("REAL_ITEM"));
+ if (context->expecting(Item::REAL_ITEM))
+ {
+ DBUG_PRINT("info", ("value %f", ((Item_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->expecting_no_field_result())
+ {
+ // 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::VARBIN_ITEM:
+ DBUG_PRINT("info", ("VARBIN_ITEM"));
+ if (context->expecting(Item::VARBIN_ITEM))
+ {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::VARBIN_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (! context->expecting_no_field_result())
+ {
+ // 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"));
+ if (context->expecting(Item::DECIMAL_ITEM))
+ {
+ DBUG_PRINT("info", ("value %f",
+ ((Item_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->expecting_no_field_result())
+ {
+ // 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;
+ }
+ 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();
+ curr_cond->prev= prev_cond;
+ prev_cond->next= curr_cond;
+ curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
+ // Pop rewrite stack
+ context->rewrite_stack= rewrite_context->next;
+ rewrite_context->next= NULL;
+ delete(rewrite_context);
+ }
+ }
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Push a condition
+ */
+const
+COND*
+ha_ndbcluster_cond::cond_push(const COND *cond,
+ TABLE *table, const NDBTAB *ndb_table)
+{
+ DBUG_ENTER("cond_push");
+ Ndb_cond_stack *ndb_cond = new Ndb_cond_stack();
+ if (ndb_cond == NULL)
+ {
+ my_errno= HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(NULL);
+ }
+ if (m_cond_stack)
+ ndb_cond->next= m_cond_stack;
+ else
+ ndb_cond->next= NULL;
+ m_cond_stack= ndb_cond;
+
+ if (serialize_cond(cond, ndb_cond, table, ndb_table))
+ {
+ DBUG_RETURN(NULL);
+ }
+ else
+ {
+ cond_pop();
+ }
+ DBUG_RETURN(cond);
+}
+
+/*
+ Pop the top condition from the condition stack
+*/
+void
+ha_ndbcluster_cond::cond_pop()
+{
+ Ndb_cond_stack *ndb_cond_stack= m_cond_stack;
+ if (ndb_cond_stack)
+ {
+ m_cond_stack= ndb_cond_stack->next;
+ ndb_cond_stack->next= NULL;
+ delete ndb_cond_stack;
+ }
+}
+
+/*
+ Clear the condition stack
+*/
+void
+ha_ndbcluster_cond::cond_clear()
+{
+ DBUG_ENTER("cond_clear");
+ while (m_cond_stack)
+ cond_pop();
+
+ DBUG_VOID_RETURN;
+}
+
+bool
+ha_ndbcluster_cond::serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond,
+ TABLE *table, const NDBTAB *ndb_table)
+{
+ DBUG_ENTER("serialize_cond");
+ Item *item= (Item *) cond;
+ Ndb_cond_traverse_context context(table, ndb_table, ndb_cond);
+ // Expect a logical expression
+ context.expect(Item::FUNC_ITEM);
+ context.expect(Item::COND_ITEM);
+ item->traverse_cond(&ndb_serialize_cond, (void *) &context, Item::PREFIX);
+ DBUG_PRINT("info", ("The pushed condition is %ssupported", (context.supported)?"":"not "));
+
+ DBUG_RETURN(context.supported);
+}
+
+int
+ha_ndbcluster_cond::build_scan_filter_predicate(Ndb_cond * &cond,
+ NdbScanFilter *filter,
+ bool negated)
+{
+ DBUG_ENTER("build_scan_filter_predicate");
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ {
+ if (!cond->next)
+ break;
+ Ndb_item *a= cond->next->ndb_item;
+ Ndb_item *b, *field, *value= NULL;
+
+ switch (cond->ndb_item->argument_count()) {
+ case 1:
+ field= (a->type == NDB_FIELD)? a : NULL;
+ break;
+ case 2:
+ if (!cond->next->next)
+ {
+ field= NULL;
+ break;
+ }
+ b= cond->next->next->ndb_item;
+ value= ((a->type == NDB_VALUE) ? a :
+ (b->type == NDB_VALUE) ? b :
+ NULL);
+ field= ((a->type == NDB_FIELD) ? a :
+ (b->type == NDB_FIELD) ? b :
+ NULL);
+ break;
+ default:
+ field= NULL; //Keep compiler happy
+ DBUG_ASSERT(0);
+ break;
+ }
+ switch ((negated) ?
+ Ndb_item::negate(cond->ndb_item->qualification.function_type)
+ : cond->ndb_item->qualification.function_type) {
+ case NDB_EQ_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating EQ filter"));
+ if (filter->cmp(NdbScanFilter::COND_EQ,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_NE_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating NE filter"));
+ if (filter->cmp(NdbScanFilter::COND_NE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_LT_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating LT filter"));
+ if (filter->cmp(NdbScanFilter::COND_LT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating GT filter"));
+ if (filter->cmp(NdbScanFilter::COND_GT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_LE_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating LE filter"));
+ if (filter->cmp(NdbScanFilter::COND_LE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating GE filter"));
+ if (filter->cmp(NdbScanFilter::COND_GE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_GE_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating GE filter"));
+ if (filter->cmp(NdbScanFilter::COND_GE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating LE filter"));
+ if (filter->cmp(NdbScanFilter::COND_LE,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_GT_FUNC:
+ {
+ if (!value || !field) break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ if (a == field)
+ {
+ DBUG_PRINT("info", ("Generating GT filter"));
+ if (filter->cmp(NdbScanFilter::COND_GT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating LT filter"));
+ if (filter->cmp(NdbScanFilter::COND_LT,
+ field->get_field_no(),
+ field->get_val(),
+ field->pack_length()) == -1)
+ DBUG_RETURN(1);
+ }
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_LIKE_FUNC:
+ {
+ if (!value || !field) break;
+ if ((value->qualification.value_type != Item::STRING_ITEM) &&
+ (value->qualification.value_type != Item::VARBIN_ITEM))
+ break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating LIKE filter: like(%d,%s,%d)",
+ field->get_field_no(), value->get_val(),
+ value->pack_length()));
+ if (filter->cmp(NdbScanFilter::COND_LIKE,
+ field->get_field_no(),
+ value->get_val(),
+ value->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_NOTLIKE_FUNC:
+ {
+ if (!value || !field) break;
+ if ((value->qualification.value_type != Item::STRING_ITEM) &&
+ (value->qualification.value_type != Item::VARBIN_ITEM))
+ break;
+ // Save value in right format for the field type
+ value->save_in_field(field);
+ DBUG_PRINT("info", ("Generating NOTLIKE filter: notlike(%d,%s,%d)",
+ field->get_field_no(), value->get_val(),
+ value->pack_length()));
+ if (filter->cmp(NdbScanFilter::COND_NOT_LIKE,
+ field->get_field_no(),
+ value->get_val(),
+ value->pack_length()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next->next;
+ DBUG_RETURN(0);
+ }
+ case NDB_ISNULL_FUNC:
+ if (!field)
+ break;
+ DBUG_PRINT("info", ("Generating ISNULL filter"));
+ if (filter->isnull(field->get_field_no()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next;
+ DBUG_RETURN(0);
+ case NDB_ISNOTNULL_FUNC:
+ {
+ if (!field)
+ break;
+ DBUG_PRINT("info", ("Generating ISNOTNULL filter"));
+ if (filter->isnotnull(field->get_field_no()) == -1)
+ DBUG_RETURN(1);
+ cond= cond->next->next;
+ DBUG_RETURN(0);
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ DBUG_PRINT("info", ("Found illegal condition"));
+ DBUG_RETURN(1);
+}
+
+
+int
+ha_ndbcluster_cond::build_scan_filter_group(Ndb_cond* &cond,
+ NdbScanFilter *filter)
+{
+ uint level=0;
+ bool negated= FALSE;
+ DBUG_ENTER("build_scan_filter_group");
+
+ do
+ {
+ if (!cond)
+ DBUG_RETURN(1);
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ {
+ switch (cond->ndb_item->qualification.function_type) {
+ case NDB_COND_AND_FUNC:
+ {
+ level++;
+ DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NAND":"AND",
+ level));
+ if ((negated) ? filter->begin(NdbScanFilter::NAND)
+ : filter->begin(NdbScanFilter::AND) == -1)
+ DBUG_RETURN(1);
+ negated= FALSE;
+ cond= cond->next;
+ break;
+ }
+ case NDB_COND_OR_FUNC:
+ {
+ level++;
+ DBUG_PRINT("info", ("Generating %s group %u", (negated)?"NOR":"OR",
+ level));
+ if ((negated) ? filter->begin(NdbScanFilter::NOR)
+ : filter->begin(NdbScanFilter::OR) == -1)
+ DBUG_RETURN(1);
+ negated= FALSE;
+ cond= cond->next;
+ break;
+ }
+ case NDB_NOT_FUNC:
+ {
+ DBUG_PRINT("info", ("Generating negated query"));
+ cond= cond->next;
+ negated= TRUE;
+ break;
+ }
+ default:
+ if (build_scan_filter_predicate(cond, filter, negated))
+ DBUG_RETURN(1);
+ negated= FALSE;
+ break;
+ }
+ break;
+ }
+ case NDB_END_COND:
+ DBUG_PRINT("info", ("End of group %u", level));
+ level--;
+ if (cond) cond= cond->next;
+ if (filter->end() == -1)
+ DBUG_RETURN(1);
+ if (!negated)
+ break;
+ // else fall through (NOT END is an illegal condition)
+ default:
+ {
+ DBUG_PRINT("info", ("Illegal scan filter"));
+ }
+ }
+ } while (level > 0 || negated);
+
+ DBUG_RETURN(0);
+}
+
+
+int
+ha_ndbcluster_cond::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
+{
+ bool simple_cond= TRUE;
+ DBUG_ENTER("build_scan_filter");
+
+ switch (cond->ndb_item->type) {
+ case NDB_FUNCTION:
+ switch (cond->ndb_item->qualification.function_type) {
+ case NDB_COND_AND_FUNC:
+ case NDB_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))
+ DBUG_RETURN(1);
+ if (simple_cond && filter->end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+int
+ha_ndbcluster_cond::generate_scan_filter(NdbScanOperation *op)
+{
+ DBUG_ENTER("generate_scan_filter");
+
+ if (m_cond_stack)
+ {
+ NdbScanFilter filter(op);
+
+ DBUG_RETURN(generate_scan_filter_from_cond(filter));
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Empty stack"));
+ }
+
+ DBUG_RETURN(0);
+}
+
+
+int
+ha_ndbcluster_cond::generate_scan_filter_from_cond(NdbScanFilter& filter)
+{
+ bool multiple_cond= FALSE;
+ DBUG_ENTER("generate_scan_filter_from_cond");
+
+ // Wrap an AND group around multiple conditions
+ if (m_cond_stack->next)
+ {
+ multiple_cond= TRUE;
+ if (filter.begin() == -1)
+ DBUG_RETURN(1);
+ }
+ for (Ndb_cond_stack *stack= m_cond_stack;
+ (stack);
+ stack= stack->next)
+ {
+ Ndb_cond *cond= stack->ndb_cond;
+
+ if (build_scan_filter(cond, &filter))
+ {
+ DBUG_PRINT("info", ("build_scan_filter failed"));
+ DBUG_RETURN(1);
+ }
+ }
+ if (multiple_cond && filter.end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+
+int ha_ndbcluster_cond::generate_scan_filter_from_key(NdbScanOperation *op,
+ const KEY* key_info,
+ const byte *key,
+ uint key_len,
+ byte *buf)
+{
+ KEY_PART_INFO* key_part= key_info->key_part;
+ KEY_PART_INFO* end= key_part+key_info->key_parts;
+ NdbScanFilter filter(op);
+ int res;
+ DBUG_ENTER("generate_scan_filter_from_key");
+
+ filter.begin(NdbScanFilter::AND);
+ for (; key_part != end; key_part++)
+ {
+ Field* field= key_part->field;
+ uint32 pack_len= field->pack_length();
+ const byte* ptr= key;
+ DBUG_PRINT("info", ("Filtering value for %s", field->field_name));
+ DBUG_DUMP("key", (char*)ptr, pack_len);
+ if (key_part->null_bit)
+ {
+ DBUG_PRINT("info", ("Generating ISNULL filter"));
+ if (filter.isnull(key_part->fieldnr-1) == -1)
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Generating EQ filter"));
+ if (filter.cmp(NdbScanFilter::COND_EQ,
+ key_part->fieldnr-1,
+ ptr,
+ pack_len) == -1)
+ DBUG_RETURN(1);
+ }
+ key += key_part->store_length;
+ }
+ // Add any pushed condition
+ if (m_cond_stack &&
+ (res= generate_scan_filter_from_cond(filter)))
+ DBUG_RETURN(res);
+
+ if (filter.end() == -1)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
+}
+
+#endif /* HAVE_NDBCLUSTER_DB */
diff --git a/sql/ha_ndbcluster_cond.h b/sql/ha_ndbcluster_cond.h
new file mode 100644
index 00000000000..617302107d8
--- /dev/null
+++ b/sql/ha_ndbcluster_cond.h
@@ -0,0 +1,475 @@
+/* Copyright (C) 2000-2007 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ This file defines the data structures used by engine condition pushdown in
+ the NDB Cluster handler
+*/
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+typedef enum ndb_item_type {
+ NDB_VALUE = 0, // Qualified more with Item::Type
+ NDB_FIELD = 1, // Qualified from table definition
+ NDB_FUNCTION = 2,// Qualified from Item_func::Functype
+ NDB_END_COND = 3 // End marker for condition group
+} NDB_ITEM_TYPE;
+
+typedef enum ndb_func_type {
+ NDB_EQ_FUNC = 0,
+ NDB_NE_FUNC = 1,
+ NDB_LT_FUNC = 2,
+ NDB_LE_FUNC = 3,
+ NDB_GT_FUNC = 4,
+ NDB_GE_FUNC = 5,
+ NDB_ISNULL_FUNC = 6,
+ NDB_ISNOTNULL_FUNC = 7,
+ NDB_LIKE_FUNC = 8,
+ NDB_NOTLIKE_FUNC = 9,
+ NDB_NOT_FUNC = 10,
+ NDB_UNKNOWN_FUNC = 11,
+ NDB_COND_AND_FUNC = 12,
+ NDB_COND_OR_FUNC = 13,
+ NDB_UNSUPPORTED_FUNC = 14
+} NDB_FUNC_TYPE;
+
+typedef union ndb_item_qualification {
+ Item::Type value_type;
+ enum_field_types field_type; // Instead of Item::FIELD_ITEM
+ NDB_FUNC_TYPE function_type; // Instead of Item::FUNC_ITEM
+} NDB_ITEM_QUALIFICATION;
+
+typedef struct ndb_item_field_value {
+ Field* field;
+ int column_no;
+} 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
+{
+ NDB_FUNC_TYPE pos_fun;
+ NDB_FUNC_TYPE neg_fun;
+};
+
+/*
+ Define what functions can be negated in condition pushdown.
+ Note, these HAVE to be in the same order as in definition enum
+*/
+static const negated_function_mapping neg_map[]=
+{
+ {NDB_EQ_FUNC, NDB_NE_FUNC},
+ {NDB_NE_FUNC, NDB_EQ_FUNC},
+ {NDB_LT_FUNC, NDB_GE_FUNC},
+ {NDB_LE_FUNC, NDB_GT_FUNC},
+ {NDB_GT_FUNC, NDB_LE_FUNC},
+ {NDB_GE_FUNC, NDB_LT_FUNC},
+ {NDB_ISNULL_FUNC, NDB_ISNOTNULL_FUNC},
+ {NDB_ISNOTNULL_FUNC, NDB_ISNULL_FUNC},
+ {NDB_LIKE_FUNC, NDB_NOTLIKE_FUNC},
+ {NDB_NOTLIKE_FUNC, NDB_LIKE_FUNC},
+ {NDB_NOT_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_UNKNOWN_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_COND_AND_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_COND_OR_FUNC, NDB_UNSUPPORTED_FUNC},
+ {NDB_UNSUPPORTED_FUNC, NDB_UNSUPPORTED_FUNC}
+};
+
+/*
+ This class is the construction element for serialization of Item tree
+ in condition pushdown.
+ An instance of Ndb_Item represents a constant, table field reference,
+ unary or binary comparison predicate, and start/end of AND/OR.
+ Instances of Ndb_Item are stored in a linked list implemented by Ndb_cond
+ class.
+ The order of elements produced by Ndb_cond::next corresponds to
+ breadth-first traversal of the Item (i.e. expression) tree in prefix order.
+ AND and OR have arbitrary arity, so the end of AND/OR group is marked with
+ Ndb_item with type == NDB_END_COND.
+ NOT items represent negated conditions and generate NAND/NOR groups.
+*/
+class Ndb_item : public Sql_alloc
+{
+public:
+ Ndb_item(NDB_ITEM_TYPE item_type) : type(item_type) {};
+ Ndb_item(NDB_ITEM_TYPE item_type,
+ NDB_ITEM_QUALIFICATION item_qualification,
+ const Item *item_value)
+ : type(item_type), qualification(item_qualification)
+ {
+ switch(item_type) {
+ case(NDB_VALUE):
+ value.item= item_value;
+ break;
+ case(NDB_FIELD): {
+ NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
+ Item_field *field_item= (Item_field *) item_value;
+ field_value->field= field_item->field;
+ field_value->column_no= -1; // Will be fetched at scan filter generation
+ value.field_value= field_value;
+ break;
+ }
+ case(NDB_FUNCTION):
+ value.item= item_value;
+ value.arg_count= ((Item_func *) item_value)->argument_count();
+ break;
+ case(NDB_END_COND):
+ break;
+ }
+ };
+ Ndb_item(Field *field, int column_no) : type(NDB_FIELD)
+ {
+ NDB_ITEM_FIELD_VALUE *field_value= new NDB_ITEM_FIELD_VALUE();
+ qualification.field_type= field->type();
+ field_value->field= field;
+ field_value->column_no= column_no;
+ value.field_value= field_value;
+ };
+ Ndb_item(Item_func::Functype func_type, const Item *item_value)
+ : type(NDB_FUNCTION)
+ {
+ qualification.function_type= item_func_to_ndb_func(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= item_func_to_ndb_func(func_type);
+ value.arg_count= no_args;
+ };
+ ~Ndb_item()
+ {
+ if (type == NDB_FIELD)
+ {
+ delete value.field_value;
+ value.field_value= NULL;
+ }
+ };
+
+ uint32 pack_length()
+ {
+ switch(type) {
+ case(NDB_VALUE):
+ if(qualification.value_type == Item::STRING_ITEM)
+ return value.item->str_value.length();
+ break;
+ case(NDB_FIELD):
+ return value.field_value->field->pack_length();
+ default:
+ break;
+ }
+
+ return 0;
+ };
+
+ Field * get_field() { return value.field_value->field; };
+
+ int get_field_no() { return value.field_value->column_no; };
+
+ int argument_count()
+ {
+ return value.arg_count;
+ };
+
+ const char* get_val()
+ {
+ switch(type) {
+ case(NDB_VALUE):
+ if(qualification.value_type == Item::STRING_ITEM)
+ return value.item->str_value.ptr();
+ break;
+ case(NDB_FIELD):
+ return value.field_value->field->ptr;
+ default:
+ break;
+ }
+
+ return NULL;
+ };
+
+ void save_in_field(Ndb_item *field_item)
+ {
+ Field *field = field_item->value.field_value->field;
+ const Item *item= value.item;
+
+ if (item && field)
+ {
+ my_bitmap_map *old_map=
+ dbug_tmp_use_all_columns(field->table, field->table->write_set);
+ ((Item *)item)->save_in_field(field, FALSE);
+ dbug_tmp_restore_column_map(field->table->write_set, old_map);
+ }
+ };
+
+ static NDB_FUNC_TYPE item_func_to_ndb_func(Item_func::Functype fun)
+ {
+ switch (fun) {
+ case (Item_func::EQ_FUNC): { return NDB_EQ_FUNC; }
+ case (Item_func::NE_FUNC): { return NDB_NE_FUNC; }
+ case (Item_func::LT_FUNC): { return NDB_LT_FUNC; }
+ case (Item_func::LE_FUNC): { return NDB_LE_FUNC; }
+ case (Item_func::GT_FUNC): { return NDB_GT_FUNC; }
+ case (Item_func::GE_FUNC): { return NDB_GE_FUNC; }
+ case (Item_func::ISNULL_FUNC): { return NDB_ISNULL_FUNC; }
+ case (Item_func::ISNOTNULL_FUNC): { return NDB_ISNOTNULL_FUNC; }
+ case (Item_func::LIKE_FUNC): { return NDB_LIKE_FUNC; }
+ case (Item_func::NOT_FUNC): { return NDB_NOT_FUNC; }
+ case (Item_func::UNKNOWN_FUNC): { return NDB_UNKNOWN_FUNC; }
+ case (Item_func::COND_AND_FUNC): { return NDB_COND_AND_FUNC; }
+ case (Item_func::COND_OR_FUNC): { return NDB_COND_OR_FUNC; }
+ default: { return NDB_UNSUPPORTED_FUNC; }
+ }
+ };
+
+ static NDB_FUNC_TYPE negate(NDB_FUNC_TYPE fun)
+ {
+ uint i= (uint) fun;
+ DBUG_ASSERT(fun == neg_map[i].pos_fun);
+ return neg_map[i].neg_fun;
+ };
+
+ NDB_ITEM_TYPE type;
+ NDB_ITEM_QUALIFICATION qualification;
+ private:
+ NDB_ITEM_VALUE value;
+};
+
+/*
+ This class implements a linked list used for storing a
+ serialization of the Item tree for condition pushdown.
+ */
+class Ndb_cond : public Sql_alloc
+{
+ public:
+ Ndb_cond() : ndb_item(NULL), next(NULL), prev(NULL) {};
+ ~Ndb_cond()
+ {
+ if (ndb_item) delete ndb_item;
+ ndb_item= NULL;
+ if (next) delete next;
+ next= prev= NULL;
+ };
+ Ndb_item *ndb_item;
+ Ndb_cond *next;
+ Ndb_cond *prev;
+};
+
+/*
+ This class implements a stack for storing several conditions
+ for pushdown (represented as serialized Item trees using Ndb_cond).
+ The current implementation only pushes one condition, but is
+ prepared for handling several (C1 AND C2 ...) if the logic for
+ pushing conditions is extended in sql_select.
+*/
+class Ndb_cond_stack : public Sql_alloc
+{
+ public:
+ Ndb_cond_stack() : ndb_cond(NULL), next(NULL) {};
+ ~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 Sql_alloc
+{
+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
+ is defined on, the serialized representation being generated,
+ if the condition found is supported, and information what is
+ expected next in the tree inorder for the condition to be supported.
+*/
+class Ndb_cond_traverse_context : public Sql_alloc
+{
+ public:
+ Ndb_cond_traverse_context(TABLE *tab, const NdbDictionary::Table *ndb_tab,
+ Ndb_cond_stack* stack)
+ : table(tab), ndb_table(ndb_tab),
+ supported(TRUE), stack_ptr(stack), cond_ptr(NULL),
+ skip(0), collation(NULL), rewrite_stack(NULL)
+ {
+ // Allocate type checking bitmaps
+ bitmap_init(&expect_mask, 0, 512, FALSE);
+ bitmap_init(&expect_field_type_mask, 0, 512, FALSE);
+ bitmap_init(&expect_field_result_mask, 0, 512, FALSE);
+
+ if (stack)
+ cond_ptr= stack->ndb_cond;
+ };
+ ~Ndb_cond_traverse_context()
+ {
+ bitmap_free(&expect_mask);
+ bitmap_free(&expect_field_type_mask);
+ bitmap_free(&expect_field_result_mask);
+ if (rewrite_stack) delete rewrite_stack;
+ }
+ void expect(Item::Type type)
+ {
+ bitmap_set_bit(&expect_mask, (uint) type);
+ if (type == Item::FIELD_ITEM) expect_all_field_types();
+ };
+ void dont_expect(Item::Type type)
+ {
+ bitmap_clear_bit(&expect_mask, (uint) type);
+ };
+ bool expecting(Item::Type type)
+ {
+ return bitmap_is_set(&expect_mask, (uint) type);
+ };
+ void expect_nothing()
+ {
+ bitmap_clear_all(&expect_mask);
+ };
+ bool expecting_nothing()
+ {
+ return bitmap_is_clear_all(&expect_mask);
+ }
+ void expect_only(Item::Type type)
+ {
+ expect_nothing();
+ expect(type);
+ };
+
+ void expect_field_type(enum_field_types type)
+ {
+ bitmap_set_bit(&expect_field_type_mask, (uint) type);
+ };
+ void expect_all_field_types()
+ {
+ bitmap_set_all(&expect_field_type_mask);
+ };
+ bool expecting_field_type(enum_field_types type)
+ {
+ return bitmap_is_set(&expect_field_type_mask, (uint) type);
+ };
+ void expect_no_field_type()
+ {
+ bitmap_clear_all(&expect_field_type_mask);
+ };
+ bool expecting_no_field_type()
+ {
+ return bitmap_is_clear_all(&expect_field_type_mask);
+ }
+ void expect_only_field_type(enum_field_types result)
+ {
+ expect_no_field_type();
+ expect_field_type(result);
+ };
+
+ void expect_field_result(Item_result result)
+ {
+ bitmap_set_bit(&expect_field_result_mask, (uint) result);
+ };
+ bool expecting_field_result(Item_result result)
+ {
+ return bitmap_is_set(&expect_field_result_mask, (uint) result);
+ };
+ void expect_no_field_result()
+ {
+ bitmap_clear_all(&expect_field_result_mask);
+ };
+ bool expecting_no_field_result()
+ {
+ return bitmap_is_clear_all(&expect_field_result_mask);
+ }
+ void expect_only_field_result(Item_result result)
+ {
+ expect_no_field_result();
+ expect_field_result(result);
+ };
+ void expect_collation(CHARSET_INFO* col)
+ {
+ collation= col;
+ };
+ bool expecting_collation(CHARSET_INFO* col)
+ {
+ bool matching= (!collation) ? true : (collation == col);
+ collation= NULL;
+
+ return matching;
+ };
+
+ TABLE* table;
+ const NdbDictionary::Table *ndb_table;
+ bool supported;
+ Ndb_cond_stack* stack_ptr;
+ Ndb_cond* cond_ptr;
+ MY_BITMAP expect_mask;
+ MY_BITMAP expect_field_type_mask;
+ MY_BITMAP expect_field_result_mask;
+ uint skip;
+ CHARSET_INFO* collation;
+ Ndb_rewrite_context *rewrite_stack;
+};
+
+class ha_ndbcluster;
+
+class ha_ndbcluster_cond
+{
+public:
+ ha_ndbcluster_cond()
+ : m_cond_stack(NULL)
+ {}
+ ~ha_ndbcluster_cond()
+ { if (m_cond_stack) delete m_cond_stack; }
+ const COND *cond_push(const COND *cond,
+ TABLE *table, const NdbDictionary::Table *ndb_table);
+ void cond_pop();
+ void cond_clear();
+ int generate_scan_filter(NdbScanOperation* op);
+ int generate_scan_filter_from_cond(NdbScanFilter& filter);
+ int generate_scan_filter_from_key(NdbScanOperation* op,
+ const KEY* key_info,
+ const byte *key,
+ uint key_len,
+ byte *buf);
+private:
+ bool serialize_cond(const COND *cond, Ndb_cond_stack *ndb_cond,
+ TABLE *table, const NdbDictionary::Table *ndb_table);
+ int build_scan_filter_predicate(Ndb_cond* &cond,
+ NdbScanFilter* filter,
+ bool negated= false);
+ int build_scan_filter_group(Ndb_cond* &cond,
+ NdbScanFilter* filter);
+ int build_scan_filter(Ndb_cond* &cond, NdbScanFilter* filter);
+
+ Ndb_cond_stack *m_cond_stack;
+};