summaryrefslogtreecommitdiff
path: root/sql/ha_ndbcluster_cond.cc
diff options
context:
space:
mode:
authorunknown <mskold/marty@mysql.com/linux.site>2007-04-23 11:25:33 +0200
committerunknown <mskold/marty@mysql.com/linux.site>2007-04-23 11:25:33 +0200
commitc40726c3ce40ce408a2f2282aec8300ecee91549 (patch)
tree79c4e200e03cfcc5324bdba09a5cb78482b663a5 /sql/ha_ndbcluster_cond.cc
parentce2bc993e98ce1a2ee00742725cf1a99d078a5ce (diff)
downloadmariadb-git-c40726c3ce40ce408a2f2282aec8300ecee91549.tar.gz
Moved all code related to engine_condition_pushdown to a new class,
ha_ndbcluster_cond. Added new files: sql/ha_ndbcluster_cond.h sql/ha_ndbcluster_cond.cc sql/ha_ndbcluster_cond.cc: BitKeeper file /windows/Linux_space/MySQL/mysql-5.0-ndb/sql/ha_ndbcluster_cond.cc sql/ha_ndbcluster_cond.h: BitKeeper file /windows/Linux_space/MySQL/mysql-5.0-ndb/sql/ha_ndbcluster_cond.h sql/Makefile.am: Added compilation of new separate files for engine_condition_pushdown sql/ha_ndbcluster.cc: Moved all code related to engine_condition_pushdown to ha_ndbcluster_cond sql/ha_ndbcluster.h: Moved all code related to engine_condition_pushdown to ha_ndbcluster_cond
Diffstat (limited to 'sql/ha_ndbcluster_cond.cc')
-rw-r--r--sql/ha_ndbcluster_cond.cc1427
1 files changed, 1427 insertions, 0 deletions
diff --git a/sql/ha_ndbcluster_cond.cc b/sql/ha_ndbcluster_cond.cc
new file mode 100644
index 00000000000..a284bc13308
--- /dev/null
+++ b/sql/ha_ndbcluster_cond.cc
@@ -0,0 +1,1427 @@
+/* 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: the interface between MySQL and
+ NDB Cluster
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+
+#ifdef HAVE_NDBCLUSTER_DB
+#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= (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,
+ field->table->s->table_name));
+ 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, 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, NDBTAB *ndb_table)
+{
+ DBUG_ENTER("serialize_cond");
+ Item *item= (Item *) cond;
+ Ndb_cond_traverse_context context(table, (void *)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;
+ LINT_INIT(field);
+
+ switch (cond->ndb_item->argument_count()) {
+ case 1:
+ field=
+ (a->type == NDB_FIELD)? a : NULL;
+ break;
+ case 2:
+ if (!cond->next->next)
+ 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:
+ 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 */