summaryrefslogtreecommitdiff
path: root/sql/ha_ndbcluster.cc
diff options
context:
space:
mode:
authorunknown <tomas@whalegate.ndb.mysql.com>2007-04-24 19:24:07 +0200
committerunknown <tomas@whalegate.ndb.mysql.com>2007-04-24 19:24:07 +0200
commitea7130843562de508bf78047c08693ec759307d0 (patch)
tree9d8e7a0380074a0407683ecdae0f7e4805378992 /sql/ha_ndbcluster.cc
parentf692f710b759cc697176405aedd39bf094240269 (diff)
parent38672eb79896c6557559eef3fef9ac5a1ef15962 (diff)
downloadmariadb-git-ea7130843562de508bf78047c08693ec759307d0.tar.gz
Merge tulin@bk-internal.mysql.com:/home/bk/mysql-5.0-ndb
into whalegate.ndb.mysql.com:/home/tomas/mysql-5.0-ndb sql/ha_ndbcluster.cc: Auto merged
Diffstat (limited to 'sql/ha_ndbcluster.cc')
-rw-r--r--sql/ha_ndbcluster.cc1488
1 files changed, 71 insertions, 1417 deletions
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 8bca5ea7c5c..ad1c311a655 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -29,7 +29,7 @@
#include <my_dir.h>
#include "ha_ndbcluster.h"
#include <ndbapi/NdbApi.hpp>
-#include <ndbapi/NdbScanFilter.hpp>
+#include "ha_ndbcluster_cond.h"
// options from from mysqld.cc
extern my_bool opt_ndb_optimized_node_selection;
@@ -2114,7 +2114,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key,
DBUG_RETURN(res);
}
- if (!restart && generate_scan_filter(m_cond_stack, op))
+ if (!restart && m_cond && m_cond->generate_scan_filter(op))
DBUG_RETURN(ndb_err(trans));
if (!restart && (res= define_read_attrs(buf, op)))
@@ -2153,7 +2153,14 @@ int ha_ndbcluster::unique_index_scan(const KEY* key_info,
parallelism))
ERR_RETURN(trans->getNdbError());
m_active_cursor= op;
- 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);
@@ -2186,7 +2193,7 @@ int ha_ndbcluster::full_table_scan(byte *buf)
parallelism))
ERR_RETURN(trans->getNdbError());
m_active_cursor= op;
- 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);
@@ -2720,7 +2727,7 @@ void ha_ndbcluster::unpack_record(byte* buf)
hidden_col->getName(),
llstr(rec->u_64_value(), buff)));
}
- print_results();
+ //print_results();
#endif
DBUG_VOID_RETURN;
}
@@ -3449,7 +3456,10 @@ 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();
+ }
/* reset flags set by extra calls */
m_retrieve_all_fields= FALSE;
@@ -4872,7 +4882,7 @@ ha_ndbcluster::ha_ndbcluster(TABLE *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;
@@ -4919,9 +4929,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;
}
@@ -6511,7 +6525,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;
@@ -6970,1412 +6984,6 @@ next:
DBUG_RETURN(NULL);
}
-/*
- Condition pushdown
-*/
-/*
- Push a condition to ndbcluster storage engine for evaluation
- during table and index scans. The conditions will be stored on a stack
- for possibly storing several conditions. The stack can be popped
- by calling cond_pop, handler::extra(HA_EXTRA_RESET) (handler::reset())
- will clear the stack.
- The current implementation supports arbitrary AND/OR nested conditions
- with comparisons between columns and constants (including constant
- expressions and function calls) and the following comparison operators:
- =, !=, >, >=, <, <=, "is null", and "is not null".
-
- RETURN
- NULL The condition was supported and will be evaluated for each
- row found during the scan
- cond The condition was not supported and all rows will be returned from
- the scan for evaluation (and thus not saved on stack)
-*/
-const
-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)
- {
- 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);
-}
-
-/*
- Pop the top condition from the condition stack of the handler instance.
-*/
-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,
- 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;
-}
-
-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;
- 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::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);
-}
-
int
ndbcluster_show_status(THD* thd)
{
@@ -8423,4 +7031,50 @@ ndbcluster_show_status(THD* thd)
DBUG_RETURN(FALSE);
}
+/*
+ Condition pushdown
+*/
+/*
+ Push a condition to ndbcluster storage engine for evaluation
+ during table and index scans. The conditions will be stored on a stack
+ for possibly storing several conditions. The stack can be popped
+ by calling cond_pop, handler::extra(HA_EXTRA_RESET) (handler::reset())
+ will clear the stack.
+ The current implementation supports arbitrary AND/OR nested conditions
+ with comparisons between columns and constants (including constant
+ expressions and function calls) and the following comparison operators:
+ =, !=, >, >=, <, <=, "is null", and "is not null".
+
+ RETURN
+ NULL The condition was supported and will be evaluated for each
+ row found during the scan
+ cond The condition was not supported and all rows will be returned from
+ the scan for evaluation (and thus not saved on stack)
+*/
+const
+COND*
+ha_ndbcluster::cond_push(const COND *cond)
+{
+ DBUG_ENTER("cond_push");
+ 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););
+ DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table));
+}
+
+/*
+ Pop the top condition from the condition stack of the handler instance.
+*/
+void
+ha_ndbcluster::cond_pop()
+{
+ if (m_cond)
+ m_cond->cond_pop();
+}
+
#endif /* HAVE_NDBCLUSTER_DB */