summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/examples/ha_archive.cc10
-rw-r--r--sql/examples/ha_example.cc8
-rw-r--r--sql/examples/ha_tina.cc41
-rw-r--r--sql/field.cc17
-rw-r--r--sql/ha_berkeley.cc2
-rw-r--r--sql/ha_blackhole.cc2
-rw-r--r--sql/ha_federated.cc5
-rw-r--r--sql/ha_federated.h2
-rw-r--r--sql/ha_heap.cc2
-rw-r--r--sql/ha_innodb.cc24
-rw-r--r--sql/ha_myisam.cc2
-rw-r--r--sql/ha_myisammrg.cc2
-rw-r--r--sql/ha_ndbcluster.cc1231
-rw-r--r--sql/ha_ndbcluster.h36
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/hash_filo.cc2
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item.h9
-rw-r--r--sql/item_cmpfunc.cc35
-rw-r--r--sql/item_cmpfunc.h30
-rw-r--r--sql/item_func.cc59
-rw-r--r--sql/item_func.h10
-rw-r--r--sql/item_geofunc.cc2
-rw-r--r--sql/item_strfunc.cc2
-rw-r--r--sql/item_subselect.cc7
-rw-r--r--sql/item_sum.cc2
-rw-r--r--sql/item_timefunc.cc9
-rw-r--r--sql/item_uniq.cc3
-rw-r--r--sql/lock.cc70
-rw-r--r--sql/log_event.cc3
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/mysqld.cc3
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/opt_range.h2
-rw-r--r--sql/procedure.cc2
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/protocol.h4
-rw-r--r--sql/protocol_cursor.cc2
-rw-r--r--sql/repl_failsafe.cc2
-rw-r--r--sql/set_var.cc5
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sp_cache.cc3
-rw-r--r--sql/sp_head.cc17
-rw-r--r--sql/sp_pcontext.cc2
-rw-r--r--sql/sp_rcontext.cc2
-rw-r--r--sql/sql_acl.cc10
-rw-r--r--sql/sql_analyse.cc2
-rw-r--r--sql/sql_base.cc11
-rw-r--r--sql/sql_bitmap.h23
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h3
-rw-r--r--sql/sql_crypt.cc2
-rw-r--r--sql/sql_handler.cc2
-rw-r--r--sql/sql_insert.cc26
-rw-r--r--sql/sql_list.cc2
-rw-r--r--sql/sql_map.cc2
-rw-r--r--sql/sql_olap.cc2
-rw-r--r--sql/sql_parse.cc42
-rw-r--r--sql/sql_select.cc16
-rw-r--r--sql/sql_string.cc3
-rw-r--r--sql/sql_table.cc148
-rw-r--r--sql/sql_udf.cc2
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_yacc.yy40
-rw-r--r--sql/tztime.cc12
65 files changed, 1262 insertions, 780 deletions
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index f28ba79a00e..4f0cfb91d20 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -14,7 +14,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#ifdef __GNUC__
+#include <my_global.h>
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -600,7 +602,7 @@ int ha_archive::write_row(byte * buf)
if (!delayed_insert || !bulk_insert)
share->dirty= TRUE;
- if (written != table->s->reclength)
+ if (written != (z_off_t)table->s->reclength)
goto error;
/*
We should probably mark the table as damagaged if the record is written
@@ -617,7 +619,7 @@ int ha_archive::write_row(byte * buf)
{
((Field_blob*) table->field[*ptr])->get_ptr(&data_ptr);
written= gzwrite(share->archive_write, data_ptr, (unsigned)size);
- if (written != size)
+ if (written != (z_off_t)size)
goto error;
}
}
@@ -788,7 +790,7 @@ int ha_archive::rnd_pos(byte * buf, byte *pos)
statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
&LOCK_status);
current_position= my_get_ptr(pos, ref_length);
- z_off_t seek= gzseek(archive, current_position, SEEK_SET);
+ (void)gzseek(archive, current_position, SEEK_SET);
DBUG_RETURN(get_row(archive, buf));
}
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index 562b51878bf..66d1a801333 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -63,7 +63,9 @@
-Brian
*/
-#ifdef __GNUC__
+#include <my_global.h>
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -150,10 +152,8 @@ static EXAMPLE_SHARE *get_share(const char *table_name, TABLE *table)
return share;
-error2:
- thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
error:
+ pthread_mutex_destroy(&share->mutex);
pthread_mutex_unlock(&example_mutex);
my_free((gptr) share, MYF(0));
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
index 9ac446587ec..6ca7f67ef66 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -20,10 +20,10 @@
First off, this is a play thing for me, there are a number of things wrong with it:
*) It was designed for csv and therefor its performance is highly questionable.
*) Indexes have not been implemented. This is because the files can be traded in
- and out of the table directory without having to worry about rebuilding anything.
+ and out of the table directory without having to worry about rebuilding anything.
*) NULLs and "" are treated equally (like a spreadsheet).
*) There was in the beginning no point to anyone seeing this other then me, so there
- is a good chance that I haven't quite documented it well.
+ is a good chance that I haven't quite documented it well.
*) Less design, more "make it work"
Now there are a few cool things with it:
@@ -38,7 +38,9 @@ TODO:
-Brian
*/
-#ifdef __GNUC__
+#include <my_global.h>
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -89,12 +91,12 @@ int get_mmap(TINA_SHARE *share, int write)
{
if (write)
share->mapped_file= (byte *)mmap(NULL, share->file_stat.st_size,
- PROT_READ|PROT_WRITE, MAP_SHARED,
- share->data_file, 0);
+ PROT_READ|PROT_WRITE, MAP_SHARED,
+ share->data_file, 0);
else
share->mapped_file= (byte *)mmap(NULL, share->file_stat.st_size,
- PROT_READ, MAP_PRIVATE,
- share->data_file, 0);
+ PROT_READ, MAP_PRIVATE,
+ share->data_file, 0);
if ((share->mapped_file ==(caddr_t)-1))
{
/*
@@ -144,9 +146,9 @@ static TINA_SHARE *get_share(const char *table_name, TABLE *table)
{
char data_file_name[FN_REFLEN];
if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
- &share, sizeof(*share),
- &tmp_name, length+1,
- NullS))
+ &share, sizeof(*share),
+ &tmp_name, length+1,
+ NullS))
{
pthread_mutex_unlock(&tina_mutex);
return NULL;
@@ -341,7 +343,6 @@ int ha_tina::find_current_row(byte *buf)
for (Field **field=table->field ; *field ; field++)
{
- int x;
buffer.length(0);
mapped_ptr++; // Increment past the first quote
for(;mapped_ptr != end_ptr; mapped_ptr++)
@@ -746,28 +747,16 @@ int ha_tina::rnd_end()
*/
qsort(chain, (size_t)(chain_ptr - chain), sizeof(tina_set), (qsort_cmp)sort_set);
for (ptr= chain; ptr < chain_ptr; ptr++)
- printf("Chain %d, %d\n", (int)ptr->begin, (int)ptr->end);
- for (ptr= chain; ptr < chain_ptr; ptr++)
{
- //memmove(share->mapped_file + ptr->begin, share->mapped_file
- //+ ptr->end, length - (size_t)ptr->end);
/* We peek a head to see if this is the last chain */
- printf("Delete %d, %d, %d\n", (int)ptr->begin, (int)ptr->end, (int)length);
if (ptr+1 == chain_ptr)
- {
- printf("Shiftina(end) %d(%d) to %d\n", (int)ptr->end, (int)(length - (size_t)ptr->end), (int)ptr->begin);
memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
length - (size_t)ptr->end);
- }
else
- {
- printf("Shifting %d(%d) to %d\n", (int)ptr->end, (int)((ptr++)->begin - (size_t)ptr->end), (int)ptr->begin);
- memmove(share->mapped_file + ptr->begin, share->mapped_file + ptr->end,
- (size_t)(ptr++)->begin - (size_t)ptr->end);
- }
+ memmove((caddr_t)share->mapped_file + ptr->begin, (caddr_t)share->mapped_file + ptr->end,
+ (size_t)((ptr++)->begin - ptr->end));
length= length - (size_t)(ptr->end - ptr->begin);
}
- printf("Buffer %s\n",share->mapped_file);
/* Truncate the file to the new size */
if (my_chsize(share->data_file, length, 0, MYF(MY_WME)))
@@ -850,7 +839,7 @@ int ha_tina::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_i
DBUG_ENTER("ha_tina::create");
if ((create_file= my_create(fn_format(name_buff,name,"",".CSV",MY_REPLACE_EXT|MY_UNPACK_FILENAME),0,
- O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
+ O_RDWR | O_TRUNC,MYF(MY_WME))) < 0)
DBUG_RETURN(-1);
my_close(create_file,MYF(0));
diff --git a/sql/field.cc b/sql/field.cc
index 0c7fed99493..7e2e32083e1 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -19,6 +19,8 @@
** This file implements classes defined in field.h
*****************************************************************************/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -5856,31 +5858,32 @@ int Field_str::store(double nr)
char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE];
uint length;
bool use_scientific_notation= TRUE;
+ uint char_length= field_length / charset()->mbmaxlen;
/*
Check fabs(nr) against longest value that can be stored in field,
which depends on whether the value is < 1 or not, and negative or not
*/
double anr= fabs(nr);
int neg= (nr < 0.0) ? 1 : 0;
- if (field_length > 4 && field_length < 32 &&
- (anr < 1.0 ? anr > 1/(log_10[max(0,(int) field_length-neg-2)]) /* -2 for "0." */
- : anr < log_10[field_length-neg]-1))
+ if (char_length > 4 && char_length < 32 &&
+ (anr < 1.0 ? anr > 1/(log_10[max(0,(int) char_length-neg-2)]) /* -2 for "0." */
+ : anr < log_10[char_length-neg]-1))
use_scientific_notation= FALSE;
length= (uint) my_sprintf(buff, (buff, "%-.*g",
(use_scientific_notation ?
- max(0, (int)field_length-neg-5) :
- field_length),
+ max(0, (int)char_length-neg-5) :
+ char_length),
nr));
/*
+1 below is because "precision" in %g above means the
max. number of significant digits, not the output width.
Thus the width can be larger than number of significant digits by 1
(for decimal point)
- the test for field_length < 5 is for extreme cases,
+ the test for char_length < 5 is for extreme cases,
like inserting 500.0 in char(1)
*/
- DBUG_ASSERT(field_length < 5 || length <= field_length+1);
+ DBUG_ASSERT(char_length < 5 || length <= char_length+1);
return store((const char *) buff, length, charset());
}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 5942973c732..46f510bb905 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -47,6 +47,8 @@
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc
index 6a841801487..00128d3d3b6 100644
--- a/sql/ha_blackhole.cc
+++ b/sql/ha_blackhole.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index c76034c7986..89210a2f3cd 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -345,12 +345,11 @@
*/
-#ifdef __GNUC__
+#include "mysql_priv.h"
+#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
-#include "mysql_priv.h"
-
#ifdef HAVE_FEDERATED_DB
#include "ha_federated.h"
#define MAX_REMOTE_SIZE IO_SIZE
diff --git a/sql/ha_federated.h b/sql/ha_federated.h
index 22fc03e9eec..f084976718c 100644
--- a/sql/ha_federated.h
+++ b/sql/ha_federated.h
@@ -21,7 +21,7 @@
that you can implement.
*/
-#ifdef __GNUC__
+#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index cd655eeb0a9..3581b26a585 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 7f454f43ae5..d956e692152 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -27,6 +27,8 @@ have disables the InnoDB inlining in this file. */
in Windows?
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -5961,11 +5963,14 @@ ha_innobase::external_lock(
TABLES if AUTOCOMMIT=1. It does not make much sense to acquire
an InnoDB table lock if it is released immediately at the end
of LOCK TABLES, and InnoDB's table locks in that case cause
- VERY easily deadlocks. */
+ VERY easily deadlocks. We do not set InnoDB table locks when
+ MySQL sets them at the start of a stored procedure call
+ (MySQL does have thd->in_lock_tables TRUE there). */
if (prebuilt->select_lock_type != LOCK_NONE) {
if (thd->in_lock_tables &&
+ thd->lex->sql_command != SQLCOM_CALL &&
thd->variables.innodb_table_locks &&
(thd->options & OPTION_NOT_AUTOCOMMIT)) {
@@ -6476,11 +6481,21 @@ ha_innobase::store_lock(
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
+ /* Starting from 5.0.7, we weaken also the table locks
+ set at the start of a MySQL stored procedure call, just like
+ we weaken the locks set at the start of an SQL statement.
+ MySQL does set thd->in_lock_tables TRUE there, but in reality
+ we do not need table locks to make the execution of a
+ single transaction stored procedure call deterministic
+ (if it does not use a consistent read). */
+
/* If we are not doing a LOCK TABLE or DISCARD/IMPORT
TABLESPACE or TRUNCATE TABLE, then allow multiple writers */
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
- lock_type <= TL_WRITE) && !thd->in_lock_tables
+ lock_type <= TL_WRITE)
+ && (!thd->in_lock_tables
+ || thd->lex->sql_command == SQLCOM_CALL)
&& !thd->tablespace_op
&& thd->lex->sql_command != SQLCOM_TRUNCATE
&& thd->lex->sql_command != SQLCOM_CREATE_TABLE) {
@@ -6494,7 +6509,10 @@ ha_innobase::store_lock(
to t2. Convert the lock to a normal read lock to allow
concurrent inserts to t2. */
- if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) {
+ if (lock_type == TL_READ_NO_INSERT
+ && (!thd->in_lock_tables
+ || thd->lex->sql_command == SQLCOM_CALL)) {
+
lock_type = TL_READ;
}
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 1352fd84d9d..3b17512c6c2 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 0796ded3ac0..d4dc365a163 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 208c97ccd7f..4785bf7bd49 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -20,6 +20,8 @@
NDB Cluster
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -6172,572 +6174,778 @@ void ndb_serialize_cond(const Item *item, void *arg)
context->supported= FALSE;
break;
}
-
+
DBUG_VOID_RETURN;
}
if (context->supported)
{
- Ndb_cond_stack *ndb_stack= context->stack_ptr;
- Ndb_cond *prev_cond= context->cond_ptr;
- Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond();
- if (!ndb_stack->ndb_cond)
- ndb_stack->ndb_cond= curr_cond;
- curr_cond->prev= prev_cond;
- if (prev_cond) prev_cond->next= curr_cond;
-
- // Check for end of AND/OR expression
- if (!item)
+ Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
+ const Item_func *func_item;
+ // Check if we are rewriting some unsupported function call
+ if (rewrite_context &&
+ (func_item= rewrite_context->func_item) &&
+ rewrite_context->count++ == 0)
{
- // End marker for condition group
- DBUG_PRINT("info", ("End of condition group"));
- curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
- }
- else
- switch(item->type()) {
- case(Item::FIELD_ITEM): {
- Item_field *field_item= (Item_field *) item;
- Field *field= field_item->field;
- enum_field_types type= field->type();
+ switch(func_item->functype()) {
+ case(Item_func::BETWEEN):
/*
- Check that the field is part of the table of the handler
- instance and that we expect a field with of this result type.
+ Rewrite
+ <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 (context->table == field->table)
- {
- const NDBTAB *tab= (const NDBTAB *) context->ndb_table;
- DBUG_PRINT("info", ("FIELD_ITEM"));
- DBUG_PRINT("info", ("table %s", tab->getName()));
- DBUG_PRINT("info", ("column %s", field->field_name));
- DBUG_PRINT("info", ("result type %d", field->result_type()));
-
- // Check that we are expecting a field and with the correct
- // result type
- if(context->expecting(Item::FIELD_ITEM) &&
- (context->expecting_field_result(field->result_type()) ||
- // Date and year can be written as strings
- (type == MYSQL_TYPE_TIME ||
- type == MYSQL_TYPE_DATE ||
- type == MYSQL_TYPE_YEAR ||
- type == MYSQL_TYPE_DATETIME)
- ? context->expecting_field_result(STRING_RESULT) : true)
- // Bit fields no yet supported in scan filter
- && type != MYSQL_TYPE_BIT)
+ case(Item_func::IN_FUNC): {
+ /*
+ Rewrite <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_context->left_hand_item= item;
+ if (item->type() == Item::FUNC_ITEM)
{
- const NDBCOL *col= tab->getColumn(field->field_name);
- DBUG_ASSERT(col);
- curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo());
- context->dont_expect(Item::FIELD_ITEM);
- context->expect_no_field_result();
- if (context->expect_mask)
+ Item_func *func_item= (Item_func *) item;
+ if (func_item->functype() == Item_func::UNKNOWN_FUNC &&
+ func_item->const_item())
{
- // We have not seen second argument yet
- if (type == MYSQL_TYPE_TIME ||
- type == MYSQL_TYPE_DATE ||
- type == MYSQL_TYPE_YEAR ||
- type == MYSQL_TYPE_DATETIME)
- {
- context->expect_only(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- }
- else
- switch(field->result_type()) {
- case(STRING_RESULT):
- // Expect char string or binary string
- context->expect_only(Item::STRING_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect_collation(field_item->collation.collation);
- break;
- case(REAL_RESULT):
- context->expect_only(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- break;
- case(INT_RESULT):
- context->expect_only(Item::INT_ITEM);
- context->expect(Item::VARBIN_ITEM);
- break;
- case(DECIMAL_RESULT):
- context->expect_only(Item::DECIMAL_ITEM);
- context->expect(Item::REAL_ITEM);
- break;
- default:
- break;
- }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
}
else
{
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- // Check that field and string constant collations are the same
- if ((field->result_type() == STRING_RESULT) &&
- !context->expecting_collation(item->collation.collation))
- {
- DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
- }
+ DBUG_PRINT("info", ("Found unsupported functional expression in BETWEEN|IN"));
+ context->supported= FALSE;
+ DBUG_VOID_RETURN;
+
}
- break;
}
}
- DBUG_PRINT("info", ("Was not expecting field of type %u",
- field->result_type()));
- context->supported= FALSE;
- break;
- }
- case(Item::FUNC_ITEM): {
- Item_func *func_item= (Item_func *) item;
- // Check that we expect a function or functional expression here
- if (context->expecting(Item::FUNC_ITEM) ||
- func_item->functype() == Item_func::UNKNOWN_FUNC)
- context->expect_nothing();
else
{
- // Did not expect function here
+ // Non-supported BETWEEN|IN expression
+ DBUG_PRINT("info", ("Found unexpected item of type %u in BETWEEN|IN",
+ item->type()));
context->supported= FALSE;
- break;
+ DBUG_VOID_RETURN;
}
-
+ break;
+ }
+ default:
+ context->supported= FALSE;
+ break;
+ }
+ DBUG_VOID_RETURN;
+ }
+ else
+ {
+ Ndb_cond_stack *ndb_stack= context->stack_ptr;
+ Ndb_cond *prev_cond= context->cond_ptr;
+ Ndb_cond *curr_cond= context->cond_ptr= new Ndb_cond();
+ if (!ndb_stack->ndb_cond)
+ ndb_stack->ndb_cond= curr_cond;
+ curr_cond->prev= prev_cond;
+ if (prev_cond) prev_cond->next= curr_cond;
+ // Check if we are rewriting some unsupported function call
+ if (context->rewrite_stack)
+ {
+ Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
+ const Item_func *func_item= rewrite_context->func_item;
switch(func_item->functype()) {
- case(Item_func::EQ_FUNC): {
- DBUG_PRINT("info", ("EQ_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case(Item_func::NE_FUNC): {
- DBUG_PRINT("info", ("NE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case(Item_func::LT_FUNC): {
- DBUG_PRINT("info", ("LT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case(Item_func::LE_FUNC): {
- DBUG_PRINT("info", ("LE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case(Item_func::GE_FUNC): {
- DBUG_PRINT("info", ("GE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case(Item_func::GT_FUNC): {
- DBUG_PRINT("info", ("GT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::REAL_ITEM);
- context->expect(Item::DECIMAL_ITEM);
- context->expect(Item::INT_ITEM);
- context->expect(Item::VARBIN_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
- break;
- }
- case(Item_func::LIKE_FUNC): {
- DBUG_PRINT("info", ("LIKE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- break;
- }
- case(Item_func::NOTLIKE_FUNC): {
- DBUG_PRINT("info", ("NOTLIKE_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::STRING_ITEM);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- break;
- }
- case(Item_func::ISNULL_FUNC): {
- DBUG_PRINT("info", ("ISNULL_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
+ case(Item_func::BETWEEN): {
+ /*
+ Rewrite
+ <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::ISNOTNULL_FUNC): {
- DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::FIELD_ITEM);
- context->expect_field_result(STRING_RESULT);
- context->expect_field_result(REAL_RESULT);
- context->expect_field_result(INT_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
+ case(Item_func::IN_FUNC): {
+ /*
+ Rewrite <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;
}
- case(Item_func::NOT_FUNC): {
- DBUG_PRINT("info", ("NOT_FUNC"));
- curr_cond->ndb_item= new Ndb_item(func_item->functype(),
- func_item);
- context->expect(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- break;
+ default:
+ context->supported= FALSE;
}
- case(Item_func::UNKNOWN_FUNC): {
- DBUG_PRINT("info", ("UNKNOWN_FUNC %s",
- func_item->const_item()?"const":""));
- DBUG_PRINT("info", ("result type %d", func_item->result_type()));
- if (func_item->const_item())
- switch(func_item->result_type()) {
- case(STRING_RESULT): {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::STRING_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
+ // Handle left hand <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 == field->table)
+ {
+ const NDBTAB *tab= (const NDBTAB *) context->ndb_table;
+ DBUG_PRINT("info", ("FIELD_ITEM"));
+ DBUG_PRINT("info", ("table %s", tab->getName()));
+ DBUG_PRINT("info", ("column %s", field->field_name));
+ DBUG_PRINT("info", ("result type %d", field->result_type()));
+
+ // Check that we are expecting a field and with the correct
+ // result type
+ if (context->expecting(Item::FIELD_ITEM) &&
+ (context->expecting_field_result(field->result_type()) ||
+ // Date and year can be written as strings
+ ((type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ ? context->expecting_field_result(STRING_RESULT) : true)) &&
+ // Bit fields no yet supported in scan filter
+ type != MYSQL_TYPE_BIT)
+ {
+ const NDBCOL *col= tab->getColumn(field->field_name);
+ DBUG_ASSERT(col);
+ curr_cond->ndb_item= new Ndb_item(field, col->getColumnNo());
+ context->dont_expect(Item::FIELD_ITEM);
+ context->expect_no_field_result();
+ if (context->expect_mask)
{
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
- context->expect_collation(func_item->collation.collation);
+ // We have not seen second argument yet
+ if (type == MYSQL_TYPE_TIME ||
+ type == MYSQL_TYPE_DATE ||
+ type == MYSQL_TYPE_YEAR ||
+ type == MYSQL_TYPE_DATETIME)
+ {
+ context->expect_only(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ }
+ else
+ switch(field->result_type()) {
+ case(STRING_RESULT):
+ // Expect char string or binary string
+ context->expect_only(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect_collation(field_item->collation.collation);
+ break;
+ case(REAL_RESULT):
+ context->expect_only(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ break;
+ case(INT_RESULT):
+ context->expect_only(Item::INT_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ break;
+ case(DECIMAL_RESULT):
+ context->expect_only(Item::DECIMAL_ITEM);
+ context->expect(Item::REAL_ITEM);
+ break;
+ default:
+ break;
+ }
}
else
{
// Expect another logical expression
context->expect_only(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
- // Check that string result have correct collation
- if (!context->expecting_collation(item->collation.collation))
+ // Check that field and string constant collations are the same
+ if ((field->result_type() == STRING_RESULT) &&
+ !context->expecting_collation(item->collation.collation)
+ && type != MYSQL_TYPE_TIME
+ && type != MYSQL_TYPE_DATE
+ && type != MYSQL_TYPE_YEAR
+ && type != MYSQL_TYPE_DATETIME)
{
DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
+ item->collation.collation->name));
+ context->supported= FALSE;
}
}
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
break;
}
- case(REAL_RESULT): {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::REAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
-
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case(INT_RESULT): {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::INT_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(INT_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
-
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- case(DECIMAL_RESULT): {
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::DECIMAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(DECIMAL_RESULT);
- }
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- }
- // Skip any arguments since we will evaluate function instead
- DBUG_PRINT("info", ("Skip until end of arguments marker"));
- context->skip= func_item->argument_count();
- break;
- }
- default:
- break;
+ else
+ {
+ DBUG_PRINT("info", ("Was not expecting field of type %u",
+ field->result_type()));
+ context->supported= FALSE;
}
+ }
else
- // Function does not return constant expression
+ {
+ DBUG_PRINT("info", ("Was not expecting field from table %s(%s)",
+ context->table->s->table_name,
+ field->table->s->table_name));
context->supported= FALSE;
+ }
break;
}
- default: {
- DBUG_PRINT("info", ("Found func_item of type %d",
- func_item->functype()));
- context->supported= FALSE;
- }
- }
- break;
- }
- case(Item::STRING_ITEM):
- DBUG_PRINT("info", ("STRING_ITEM"));
- if (context->expecting(Item::STRING_ITEM))
- {
-#ifndef DBUG_OFF
- char buff[256];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
- Item_string *string_item= (Item_string *) item;
- DBUG_PRINT("info", ("value \"%s\"",
- string_item->val_str(&str)->ptr()));
-#endif
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::STRING_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
+ case(Item::FUNC_ITEM): {
+ Item_func *func_item= (Item_func *) item;
+ // Check that we expect a function or functional expression here
+ if (context->expecting(Item::FUNC_ITEM) ||
+ func_item->functype() == Item_func::UNKNOWN_FUNC)
+ context->expect_nothing();
+ else
{
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
- context->expect_collation(item->collation.collation);
+ // Did not expect function here
+ context->supported= FALSE;
+ break;
}
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
- // Check that we are comparing with a field with same collation
- if (!context->expecting_collation(item->collation.collation))
- {
- DBUG_PRINT("info", ("Found non-matching collation %s",
- item->collation.collation->name));
- context->supported= FALSE;
- }
+
+ switch(func_item->functype()) {
+ case(Item_func::EQ_FUNC): {
+ DBUG_PRINT("info", ("EQ_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
}
- }
- else
- context->supported= FALSE;
- break;
- case(Item::INT_ITEM):
- DBUG_PRINT("info", ("INT_ITEM"));
- if (context->expecting(Item::INT_ITEM))
- {
- Item_int *int_item= (Item_int *) item;
- DBUG_PRINT("info", ("value %d", int_item->value));
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::INT_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
- {
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(INT_RESULT);
+ case(Item_func::NE_FUNC): {
+ DBUG_PRINT("info", ("NE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
}
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
+ case(Item_func::LT_FUNC): {
+ DBUG_PRINT("info", ("LT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::LE_FUNC): {
+ DBUG_PRINT("info", ("LE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::GE_FUNC): {
+ DBUG_PRINT("info", ("GE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::GT_FUNC): {
+ DBUG_PRINT("info", ("GT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::REAL_ITEM);
+ context->expect(Item::DECIMAL_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::LIKE_FUNC): {
+ DBUG_PRINT("info", ("LIKE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect(Item::FUNC_ITEM);
+ break;
+ }
+ case(Item_func::NOTLIKE_FUNC): {
+ DBUG_PRINT("info", ("NOTLIKE_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect(Item::FUNC_ITEM);
+ break;
+ }
+ case(Item_func::ISNULL_FUNC): {
+ DBUG_PRINT("info", ("ISNULL_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::ISNOTNULL_FUNC): {
+ DBUG_PRINT("info", ("ISNOTNULL_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FIELD_ITEM);
+ context->expect_field_result(STRING_RESULT);
+ context->expect_field_result(REAL_RESULT);
+ context->expect_field_result(INT_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ break;
+ }
+ case(Item_func::NOT_FUNC): {
+ DBUG_PRINT("info", ("NOT_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(func_item->functype(),
+ func_item);
+ context->expect(Item::FUNC_ITEM);
context->expect(Item::COND_ITEM);
+ break;
}
- }
- else
- context->supported= FALSE;
- break;
- case(Item::REAL_ITEM):
- DBUG_PRINT("info", ("REAL_ITEM %s"));
- if (context->expecting(Item::REAL_ITEM))
- {
- Item_float *float_item= (Item_float *) item;
- DBUG_PRINT("info", ("value %f", float_item->value));
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::REAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
- {
- // We have not seen the field argument yet
+ case(Item_func::BETWEEN) : {
+ DBUG_PRINT("info", ("BETWEEN, rewriting using AND"));
+ Ndb_rewrite_context *rewrite_context=
+ new Ndb_rewrite_context(func_item);
+ rewrite_context->next= context->rewrite_stack;
+ context->rewrite_stack= rewrite_context;
+ DBUG_PRINT("info", ("COND_AND_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::COND_AND_FUNC,
+ func_item->argument_count() - 1);
context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FUNC_ITEM);
+ break;
}
- else
- {
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
+ case(Item_func::IN_FUNC) : {
+ DBUG_PRINT("info", ("IN_FUNC, rewriting using OR"));
+ Ndb_rewrite_context *rewrite_context=
+ new Ndb_rewrite_context(func_item);
+ rewrite_context->next= context->rewrite_stack;
+ context->rewrite_stack= rewrite_context;
+ DBUG_PRINT("info", ("COND_OR_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(Item_func::COND_OR_FUNC,
+ func_item->argument_count() - 1);
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect(Item::INT_ITEM);
+ context->expect(Item::STRING_ITEM);
+ context->expect(Item::VARBIN_ITEM);
+ context->expect(Item::FUNC_ITEM);
+ break;
}
+ case(Item_func::UNKNOWN_FUNC): {
+ DBUG_PRINT("info", ("UNKNOWN_FUNC %s",
+ func_item->const_item()?"const":""));
+ DBUG_PRINT("info", ("result type %d", func_item->result_type()));
+ if (func_item->const_item())
+ switch(func_item->result_type()) {
+ case(STRING_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(func_item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that string result have correct collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case(REAL_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case(INT_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ case(DECIMAL_RESULT): {
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
+ // Skip any arguments since we will evaluate function instead
+ DBUG_PRINT("info", ("Skip until end of arguments marker"));
+ context->skip= func_item->argument_count();
+ break;
+ }
+ default:
+ break;
+ }
+ else
+ // Function does not return constant expression
+ context->supported= FALSE;
+ break;
+ }
+ default: {
+ DBUG_PRINT("info", ("Found func_item of type %d",
+ func_item->functype()));
+ context->supported= FALSE;
+ }
+ }
+ break;
}
- else
- context->supported= FALSE;
- break;
- case(Item::VARBIN_ITEM):
- DBUG_PRINT("info", ("VARBIN_ITEM"));
- if (context->expecting(Item::VARBIN_ITEM))
- {
+ case(Item::STRING_ITEM):
+ DBUG_PRINT("info", ("STRING_ITEM"));
+ if (context->expecting(Item::STRING_ITEM))
+ {
#ifndef DBUG_OFF
- char buff[256];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- str.length(0);
- Item_hex_string *varbin_item= (Item_hex_string *) item;
- DBUG_PRINT("info", ("value \"%s\"",
- varbin_item->val_str(&str)->ptr()));
+ char buff[256];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ str.length(0);
+ Item_string *string_item= (Item_string *) item;
+ DBUG_PRINT("info", ("value \"%s\"",
+ string_item->val_str(&str)->ptr()));
#endif
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::VARBIN_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::STRING_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ context->expect_collation(item->collation.collation);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ // Check that we are comparing with a field with same collation
+ if (!context->expecting_collation(item->collation.collation))
+ {
+ DBUG_PRINT("info", ("Found non-matching collation %s",
+ item->collation.collation->name));
+ context->supported= FALSE;
+ }
+ }
+ }
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::INT_ITEM):
+ DBUG_PRINT("info", ("INT_ITEM"));
+ if (context->expecting(Item::INT_ITEM))
{
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(STRING_RESULT);
+ Item_int *int_item= (Item_int *) item;
+ DBUG_PRINT("info", ("value %d", int_item->value));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::INT_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(INT_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
}
else
+ context->supported= FALSE;
+ break;
+ case(Item::REAL_ITEM):
+ DBUG_PRINT("info", ("REAL_ITEM %s"));
+ if (context->expecting(Item::REAL_ITEM))
{
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
+ Item_float *float_item= (Item_float *) item;
+ DBUG_PRINT("info", ("value %f", float_item->value));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::REAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
}
- }
- else
- context->supported= FALSE;
- break;
- case(Item::DECIMAL_ITEM):
- DBUG_PRINT("info", ("DECIMAL_ITEM %s"));
- if (context->expecting(Item::DECIMAL_ITEM))
- {
- Item_decimal *decimal_item= (Item_decimal *) item;
- DBUG_PRINT("info", ("value %f", decimal_item->val_real()));
- NDB_ITEM_QUALIFICATION q;
- q.value_type= Item::DECIMAL_ITEM;
- curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
- if (context->expect_field_result_mask)
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::VARBIN_ITEM):
+ DBUG_PRINT("info", ("VARBIN_ITEM"));
+ if (context->expecting(Item::VARBIN_ITEM))
{
- // We have not seen the field argument yet
- context->expect_only(Item::FIELD_ITEM);
- context->expect_only_field_result(REAL_RESULT);
- context->expect_field_result(DECIMAL_RESULT);
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::VARBIN_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(STRING_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
}
else
+ context->supported= FALSE;
+ break;
+ case(Item::DECIMAL_ITEM):
+ DBUG_PRINT("info", ("DECIMAL_ITEM %s"));
+ if (context->expecting(Item::DECIMAL_ITEM))
{
- // Expect another logical expression
- context->expect_only(Item::FUNC_ITEM);
- context->expect(Item::COND_ITEM);
+ Item_decimal *decimal_item= (Item_decimal *) item;
+ DBUG_PRINT("info", ("value %f", decimal_item->val_real()));
+ NDB_ITEM_QUALIFICATION q;
+ q.value_type= Item::DECIMAL_ITEM;
+ curr_cond->ndb_item= new Ndb_item(NDB_VALUE, q, item);
+ if (context->expect_field_result_mask)
+ {
+ // We have not seen the field argument yet
+ context->expect_only(Item::FIELD_ITEM);
+ context->expect_only_field_result(REAL_RESULT);
+ context->expect_field_result(DECIMAL_RESULT);
+ }
+ else
+ {
+ // Expect another logical expression
+ context->expect_only(Item::FUNC_ITEM);
+ context->expect(Item::COND_ITEM);
+ }
}
+ else
+ context->supported= FALSE;
+ break;
+ case(Item::COND_ITEM): {
+ Item_cond *cond_item= (Item_cond *) item;
+
+ if (context->expecting(Item::COND_ITEM))
+ switch(cond_item->functype()) {
+ case(Item_func::COND_AND_FUNC):
+ DBUG_PRINT("info", ("COND_AND_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
+ cond_item);
+ break;
+ case(Item_func::COND_OR_FUNC):
+ DBUG_PRINT("info", ("COND_OR_FUNC"));
+ curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
+ cond_item);
+ break;
+ default:
+ DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
+ context->supported= FALSE;
+ break;
+ }
+ else
+ // Did not expect condition
+ context->supported= FALSE;
+ break;
}
- else
+ default: {
+ DBUG_PRINT("info", ("Found item of type %d", item->type()));
context->supported= FALSE;
- break;
- case(Item::COND_ITEM): {
- Item_cond *cond_item= (Item_cond *) item;
-
- if (context->expecting(Item::COND_ITEM))
- switch(cond_item->functype()) {
- case(Item_func::COND_AND_FUNC):
- DBUG_PRINT("info", ("COND_AND_FUNC"));
- curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
- cond_item);
- break;
- case(Item_func::COND_OR_FUNC):
- DBUG_PRINT("info", ("COND_OR_FUNC"));
- curr_cond->ndb_item= new Ndb_item(cond_item->functype(),
- cond_item);
- break;
- default:
- DBUG_PRINT("info", ("COND_ITEM %d", cond_item->functype()));
- context->supported= FALSE;
- break;
- }
- else
- // Did not expect condition
- context->supported= FALSE;
- break;
- }
- default: {
- DBUG_PRINT("info", ("Found item of type %d", item->type()));
- context->supported= FALSE;
- }
+ }
+ }
+
+ if (context->supported && context->rewrite_stack)
+ {
+ Ndb_rewrite_context *rewrite_context= context->rewrite_stack;
+ if (rewrite_context->count ==
+ rewrite_context->func_item->argument_count())
+ {
+ // Rewrite is done, wrap an END() at the en
+ DBUG_PRINT("info", ("End of condition group"));
+ prev_cond= curr_cond;
+ curr_cond= context->cond_ptr= new Ndb_cond();
+ prev_cond->next= curr_cond;
+ curr_cond->ndb_item= new Ndb_item(NDB_END_COND);
+ // Pop rewrite stack
+ context->rewrite_stack= context->rewrite_stack->next;
+ }
}
+ }
}
-
+
DBUG_VOID_RETURN;
}
@@ -7020,8 +7228,10 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
break;
}
case(Item_func::NOT_FUNC): {
+ DBUG_PRINT("info", ("Generating negated query"));
cond= cond->next;
negated= TRUE;
+
break;
}
default:
@@ -7037,12 +7247,14 @@ ha_ndbcluster::build_scan_filter_group(Ndb_cond* &cond, NdbScanFilter *filter)
if (cond) cond= cond->next;
if (filter->end() == -1)
DBUG_RETURN(1);
- break;
+ if (!negated)
+ break;
+ // else fall through (NOT END is an illegal condition)
default: {
DBUG_PRINT("info", ("Illegal scan filter"));
}
}
- } while (level > 0);
+ } while (level > 0 || negated);
DBUG_RETURN(0);
}
@@ -7053,14 +7265,20 @@ ha_ndbcluster::build_scan_filter(Ndb_cond * &cond, NdbScanFilter *filter)
bool simple_cond= TRUE;
DBUG_ENTER("build_scan_filter");
- switch(cond->ndb_item->type) {
- case(Item_func::COND_AND_FUNC):
- case(Item_func::COND_OR_FUNC):
- simple_cond= FALSE;
- break;
- default:
- break;
- }
+ switch(cond->ndb_item->type) {
+ case(NDB_FUNCTION):
+ switch(cond->ndb_item->qualification.function_type) {
+ case(Item_func::COND_AND_FUNC):
+ case(Item_func::COND_OR_FUNC):
+ simple_cond= FALSE;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
if (simple_cond && filter->begin() == -1)
DBUG_RETURN(1);
if (build_scan_filter_group(cond, filter))
@@ -7078,6 +7296,7 @@ ha_ndbcluster::generate_scan_filter(Ndb_cond_stack *ndb_cond_stack,
DBUG_ENTER("generate_scan_filter");
if (ndb_cond_stack)
{
+ DBUG_PRINT("info", ("Generating scan filter"));
NdbScanFilter filter(op);
bool multiple_cond= FALSE;
// Wrap an AND group around multiple conditions
diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h
index 8012f16e42e..9ea32e61190 100644
--- a/sql/ha_ndbcluster.h
+++ b/sql/ha_ndbcluster.h
@@ -86,6 +86,7 @@ typedef struct ndb_item_field_value {
typedef union ndb_item_value {
const Item *item;
NDB_ITEM_FIELD_VALUE *field_value;
+ uint arg_count;
} NDB_ITEM_VALUE;
struct negated_function_mapping
@@ -144,6 +145,7 @@ class Ndb_item {
}
case(NDB_FUNCTION):
value.item= item_value;
+ value.arg_count= ((Item_func *) item_value)->argument_count();
break;
case(NDB_END_COND):
break;
@@ -162,6 +164,13 @@ class Ndb_item {
{
qualification.function_type= func_type;
value.item= item_value;
+ value.arg_count= ((Item_func *) item_value)->argument_count();
+ };
+ Ndb_item(Item_func::Functype func_type, uint no_args)
+ : type(NDB_FUNCTION)
+ {
+ qualification.function_type= func_type;
+ value.arg_count= no_args;
};
~Ndb_item()
{
@@ -194,7 +203,7 @@ class Ndb_item {
int argument_count()
{
- return ((Item_func *) value.item)->argument_count();
+ return value.arg_count;
};
const char* get_val()
@@ -273,12 +282,28 @@ class Ndb_cond_stack
{
if (ndb_cond) delete ndb_cond;
ndb_cond= NULL;
+ if (next) delete next;
next= NULL;
};
Ndb_cond *ndb_cond;
Ndb_cond_stack *next;
};
+class Ndb_rewrite_context
+{
+public:
+ Ndb_rewrite_context(Item_func *func)
+ : func_item(func), left_hand_item(NULL), count(0) {};
+ ~Ndb_rewrite_context()
+ {
+ if (next) delete next;
+ }
+ const Item_func *func_item;
+ const Item *left_hand_item;
+ uint count;
+ Ndb_rewrite_context *next;
+};
+
/*
This class is used for storing the context when traversing
the Item tree. It stores a reference to the table the condition
@@ -292,11 +317,16 @@ class Ndb_cond_traverse_context
Ndb_cond_traverse_context(TABLE *tab, void* ndb_tab, Ndb_cond_stack* stack)
: table(tab), ndb_table(ndb_tab),
supported(TRUE), stack_ptr(stack), cond_ptr(NULL),
- expect_mask(0), expect_field_result_mask(0), skip(0), collation(NULL)
+ expect_mask(0), expect_field_result_mask(0), skip(0), collation(NULL),
+ rewrite_stack(NULL)
{
if (stack)
cond_ptr= stack->ndb_cond;
};
+ ~Ndb_cond_traverse_context()
+ {
+ if (rewrite_stack) delete rewrite_stack;
+ }
void expect(Item::Type type)
{
expect_mask|= (1 << type);
@@ -357,7 +387,7 @@ class Ndb_cond_traverse_context
uint expect_field_result_mask;
uint skip;
CHARSET_INFO* collation;
-
+ Ndb_rewrite_context *rewrite_stack;
};
/*
diff --git a/sql/handler.cc b/sql/handler.cc
index 965c3d26f49..ffd6fbc5916 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -17,6 +17,8 @@
/* Handler-calling-functions */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/hash_filo.cc b/sql/hash_filo.cc
index ec200768222..34f3cd6b035 100644
--- a/sql/hash_filo.cc
+++ b/sql/hash_filo.cc
@@ -20,6 +20,8 @@
** to usage.
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/item.cc b/sql/item.cc
index e3cedf68d90..a9c1ef7198e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -1025,7 +1027,7 @@ Item_field::Item_field(THD *thd, Field *f)
structure can go away and pop up again between subsequent executions
of a prepared statement).
*/
- if (thd->current_arena->is_stmt_prepare())
+ if (thd->current_arena->is_stmt_prepare_or_first_sp_execute())
{
if (db_name)
orig_db_name= thd->strdup(db_name);
diff --git a/sql/item.h b/sql/item.h
index 18b419dd6d5..4f5ed9934c5 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -584,6 +584,15 @@ public:
Item::maybe_null= TRUE;
}
+ /* For error printing */
+ inline LEX_STRING *my_name(LEX_STRING *get_name)
+ {
+ if (!get_name)
+ return &m_name;
+ (*get_name)= m_name;
+ return get_name;
+ }
+
bool is_splocal() { return 1; } /* Needed for error checking */
Item *this_item();
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 66f0bf9c395..3f25d473792 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -17,6 +17,8 @@
/* This file defines all compare functions */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -1114,8 +1116,8 @@ Item_func_ifnull::fix_length_and_dec()
max_length= (max(args[0]->max_length - args[0]->decimals,
args[1]->max_length - args[1]->decimals) +
decimals);
- agg_result_type(&cached_result_type, args, 2);
- switch (cached_result_type) {
+ agg_result_type(&hybrid_type, args, 2);
+ switch (hybrid_type) {
case STRING_RESULT:
agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV);
break;
@@ -1153,7 +1155,7 @@ Field *Item_func_ifnull::tmp_table_field(TABLE *table)
}
double
-Item_func_ifnull::val_real()
+Item_func_ifnull::real_op()
{
DBUG_ASSERT(fixed == 1);
double value= args[0]->val_real();
@@ -1169,7 +1171,7 @@ Item_func_ifnull::val_real()
}
longlong
-Item_func_ifnull::val_int()
+Item_func_ifnull::int_op()
{
DBUG_ASSERT(fixed == 1);
longlong value=args[0]->val_int();
@@ -1185,7 +1187,7 @@ Item_func_ifnull::val_int()
}
-my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value)
+my_decimal *Item_func_ifnull::decimal_op(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
my_decimal *value= args[0]->val_decimal(decimal_value);
@@ -1202,7 +1204,7 @@ my_decimal *Item_func_ifnull::val_decimal(my_decimal *decimal_value)
String *
-Item_func_ifnull::val_str(String *str)
+Item_func_ifnull::str_op(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res =args[0]->val_str(str);
@@ -1225,9 +1227,16 @@ Item_func_if::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null || args[2]->maybe_null;
decimals= max(args[1]->decimals, args[2]->decimals);
- max_length= (max(args[1]->max_length - args[1]->decimals,
+ if (decimals == NOT_FIXED_DEC)
+ {
+ max_length= max(args[1]->max_length, args[2]->max_length);
+ }
+ else
+ {
+ max_length= (max(args[1]->max_length - args[1]->decimals,
args[2]->max_length - args[2]->decimals) +
decimals);
+ }
enum Item_result arg1_type=args[1]->result_type();
enum Item_result arg2_type=args[2]->result_type();
bool null1=args[1]->const_item() && args[1]->null_value;
@@ -1676,7 +1685,7 @@ void Item_func_case::print(String *str)
Coalesce - return first not NULL argument.
*/
-String *Item_func_coalesce::val_str(String *str)
+String *Item_func_coalesce::str_op(String *str)
{
DBUG_ASSERT(fixed == 1);
null_value=0;
@@ -1690,7 +1699,7 @@ String *Item_func_coalesce::val_str(String *str)
return 0;
}
-longlong Item_func_coalesce::val_int()
+longlong Item_func_coalesce::int_op()
{
DBUG_ASSERT(fixed == 1);
null_value=0;
@@ -1704,7 +1713,7 @@ longlong Item_func_coalesce::val_int()
return 0;
}
-double Item_func_coalesce::val_real()
+double Item_func_coalesce::real_op()
{
DBUG_ASSERT(fixed == 1);
null_value=0;
@@ -1719,7 +1728,7 @@ double Item_func_coalesce::val_real()
}
-my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value)
+my_decimal *Item_func_coalesce::decimal_op(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
null_value= 0;
@@ -1736,8 +1745,8 @@ my_decimal *Item_func_coalesce::val_decimal(my_decimal *decimal_value)
void Item_func_coalesce::fix_length_and_dec()
{
- agg_result_type(&cached_result_type, args, arg_count);
- switch (cached_result_type) {
+ agg_result_type(&hybrid_type, args, arg_count);
+ switch (hybrid_type) {
case STRING_RESULT:
count_only_length();
decimals= NOT_FIXED_DEC;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index a929d509723..7a22e76b217 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -453,23 +453,19 @@ public:
};
-class Item_func_coalesce :public Item_func
+class Item_func_coalesce :public Item_func_numhybrid
{
protected:
- enum Item_result cached_result_type;
- Item_func_coalesce(Item *a, Item *b)
- :Item_func(a, b), cached_result_type(INT_RESULT)
- {}
+ Item_func_coalesce(Item *a, Item *b) :Item_func_numhybrid(a, b) {}
public:
- Item_func_coalesce(List<Item> &list)
- :Item_func(list),cached_result_type(INT_RESULT)
- {}
- double val_real();
- longlong val_int();
- String *val_str(String *);
- my_decimal *val_decimal(my_decimal *);
+ Item_func_coalesce(List<Item> &list) :Item_func_numhybrid(list) {}
+ double real_op();
+ longlong int_op();
+ String *str_op(String *);
+ my_decimal *decimal_op(my_decimal *);
void fix_length_and_dec();
- enum Item_result result_type () const { return cached_result_type; }
+ void find_num_type() {}
+ enum Item_result result_type () const { return hybrid_type; }
const char *func_name() const { return "coalesce"; }
table_map not_null_tables() const { return 0; }
};
@@ -482,10 +478,10 @@ protected:
bool field_type_defined;
public:
Item_func_ifnull(Item *a, Item *b) :Item_func_coalesce(a,b) {}
- double val_real();
- longlong val_int();
- String *val_str(String *str);
- my_decimal *val_decimal(my_decimal *);
+ double real_op();
+ longlong int_op();
+ String *str_op(String *str);
+ my_decimal *decimal_op(my_decimal *);
enum_field_types field_type() const;
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 47dffa679e9..5af99cb8132 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -17,6 +17,8 @@
/* This file defines all numerical functions */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -693,8 +695,8 @@ String *Item_int_func::val_str(String *str)
/*
- Check arguments here to determine result's type for function with two
- arguments.
+ Check arguments here to determine result's type for a numeric
+ function of two arguments.
SYNOPSIS
Item_num_op::find_num_type()
@@ -720,8 +722,9 @@ void Item_num_op::find_num_type(void)
hybrid_type= DECIMAL_RESULT;
result_precision();
}
- else if (r0 == INT_RESULT && r1 == INT_RESULT)
+ else
{
+ DBUG_ASSERT(r0 == INT_RESULT && r1 == INT_RESULT);
decimals= 0;
hybrid_type=INT_RESULT;
result_precision();
@@ -736,7 +739,9 @@ void Item_num_op::find_num_type(void)
/*
- Set result type of function if it (type) is depends only on first argument
+ Set result type for a numeric function of one argument
+ (can be also used by a numeric function of many arguments, if the result
+ type depends only on the first argument)
SYNOPSIS
Item_func_num1::find_num_type()
@@ -815,6 +820,8 @@ String *Item_func_numhybrid::val_str(String *str)
str->set(nr,decimals,&my_charset_bin);
break;
}
+ case STRING_RESULT:
+ return str_op(&str_value);
default:
DBUG_ASSERT(0);
}
@@ -839,6 +846,14 @@ double Item_func_numhybrid::val_real()
return (double)int_op();
case REAL_RESULT:
return real_op();
+ case STRING_RESULT:
+ {
+ char *end_not_used;
+ int err_not_used;
+ String *res= str_op(&str_value);
+ return (res ? my_strntod(res->charset(), (char*) res->ptr(), res->length(),
+ &end_not_used, &err_not_used) : 0.0);
+ }
default:
DBUG_ASSERT(0);
}
@@ -863,6 +878,15 @@ longlong Item_func_numhybrid::val_int()
return int_op();
case REAL_RESULT:
return (longlong)real_op();
+ case STRING_RESULT:
+ {
+ char *end_not_used;
+ int err_not_used;
+ String *res= str_op(&str_value);
+ CHARSET_INFO *cs= str_value.charset();
+ return (res ? (*(cs->cset->strtoll10))(cs, res->ptr(), &end_not_used,
+ &err_not_used) : 0);
+ }
default:
DBUG_ASSERT(0);
}
@@ -891,6 +915,12 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value)
break;
}
case STRING_RESULT:
+ {
+ String *res= str_op(&str_value);
+ str2my_decimal(E_DEC_FATAL_ERROR, (char*) res->ptr(),
+ res->length(), res->charset(), decimal_value);
+ break;
+ }
case ROW_RESULT:
default:
DBUG_ASSERT(0);
@@ -2322,11 +2352,12 @@ void Item_func_locate::print(String *str)
longlong Item_func_field::val_int()
{
DBUG_ASSERT(fixed == 1);
+
if (cmp_type == STRING_RESULT)
{
String *field;
- if (!(field=args[0]->val_str(&value)))
- return 0; // -1 if null ?
+ if (!(field= args[0]->val_str(&value)))
+ return 0;
for (uint i=1 ; i < arg_count ; i++)
{
String *tmp_value=args[i]->val_str(&tmp);
@@ -2337,19 +2368,19 @@ longlong Item_func_field::val_int()
else if (cmp_type == INT_RESULT)
{
longlong val= args[0]->val_int();
- if (args[0]->is_null())
+ if (args[0]->null_value)
return 0;
for (uint i=1; i < arg_count ; i++)
{
- if (val == args[i]->val_int() && ! args[i]->is_null())
- return (longlong) (i);
+ if (!args[i]->is_null() && val == args[i]->val_int())
+ return (longlong) (i);
}
}
else if (cmp_type == DECIMAL_RESULT)
{
my_decimal dec_arg_buf, *dec_arg,
dec_buf, *dec= args[0]->val_decimal(&dec_buf);
- if (args[0]->is_null())
+ if (args[0]->null_value)
return 0;
for (uint i=1; i < arg_count; i++)
{
@@ -2361,12 +2392,12 @@ longlong Item_func_field::val_int()
else
{
double val= args[0]->val_real();
- if (args[0]->is_null())
+ if (args[0]->null_value)
return 0;
for (uint i=1; i < arg_count ; i++)
{
- if (val == args[i]->val_real() && ! args[i]->is_null())
- return (longlong) (i);
+ if (!args[i]->is_null() && val == args[i]->val_real())
+ return (longlong) (i);
}
}
return 0;
@@ -4509,7 +4540,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
!my_strcasecmp(system_charset_info, name.str, "VERSION"))
return new Item_string("@@VERSION", server_version,
(uint) strlen(server_version),
- system_charset_info);
+ system_charset_info, DERIVATION_SYSCONST);
Item *item;
sys_var *var;
diff --git a/sql/item_func.h b/sql/item_func.h
index b53f2a0b9c6..f0c7e25ad53 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -189,10 +189,13 @@ class Item_func_numhybrid: public Item_func
protected:
Item_result hybrid_type;
public:
- Item_func_numhybrid(Item *a) :Item_func(a),hybrid_type(REAL_RESULT)
+ Item_func_numhybrid(Item *a) :Item_func(a), hybrid_type(REAL_RESULT)
{}
Item_func_numhybrid(Item *a,Item *b)
- :Item_func(a,b),hybrid_type(REAL_RESULT)
+ :Item_func(a,b), hybrid_type(REAL_RESULT)
+ {}
+ Item_func_numhybrid(List<Item> &list)
+ :Item_func(list), hybrid_type(REAL_RESULT)
{}
enum Item_result result_type () const { return hybrid_type; }
@@ -208,6 +211,7 @@ public:
virtual longlong int_op()= 0;
virtual double real_op()= 0;
virtual my_decimal *decimal_op(my_decimal *)= 0;
+ virtual String *str_op(String *)= 0;
bool is_null() { (void) val_real(); return null_value; }
};
@@ -220,6 +224,7 @@ public:
void fix_num_length_and_dec();
void find_num_type();
+ String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
};
@@ -231,6 +236,7 @@ class Item_num_op :public Item_func_numhybrid
virtual void result_precision()= 0;
void print(String *str) { print_op(str); }
void find_num_type();
+ String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
};
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index e2b0eb5ce07..3173994f90f 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -17,6 +17,8 @@
/* This file defines all spatial functions */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e870fe5aa43..4808159fe98 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -20,6 +20,8 @@
** (This shouldn't be needed)
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 4556f60a659..4f1e5b9a290 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -22,6 +22,8 @@ SUBSELECT TODO:
(sql_select.h/sql_select.cc)
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -360,7 +362,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
because we do not rollback this changes
TODO: make rollback for it, or special name resolving mode in 5.0.
*/
- !arena->is_stmt_prepare()
+ !arena->is_stmt_prepare_or_first_sp_execute()
)
{
@@ -384,9 +386,6 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
return RES_REDUCE;
}
return RES_OK;
-
-err:
- return RES_ERROR;
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b9f3cc49d64..af3828ab2c6 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -17,6 +17,8 @@
/* Sum functions (COUNT, MIN...) */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 16882e56d88..b07de7eb21d 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -17,6 +17,8 @@
/* This file defines all time functions */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -497,7 +499,6 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
timestamp_type type, String *str)
{
char intbuff[15];
- uint days_i;
uint hours_i;
uint weekday;
ulong length;
@@ -600,8 +601,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
break;
case 'h':
case 'I':
- days_i= l_time->hour/24;
- hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i;
+ hours_i= (l_time->hour%24 + 11)%12+1;
length= int10_to_str(hours_i, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 2, '0');
break;
@@ -622,8 +622,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, TIME *l_time,
str->append_with_prefill(intbuff, length, 1, '0');
break;
case 'l':
- days_i= l_time->hour/24;
- hours_i= (l_time->hour%24 + 11)%12+1 + 24*days_i;
+ hours_i= (l_time->hour%24 + 11)%12+1;
length= int10_to_str(hours_i, intbuff, 10) - intbuff;
str->append_with_prefill(intbuff, length, 1, '0');
break;
diff --git a/sql/item_uniq.cc b/sql/item_uniq.cc
index 8734e671817..f6cf83ebb10 100644
--- a/sql/item_uniq.cc
+++ b/sql/item_uniq.cc
@@ -15,6 +15,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Compability file */
+
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
diff --git a/sql/lock.cc b/sql/lock.cc
index 83a39005cd8..e0a75a42661 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -82,8 +82,24 @@ static int unlock_external(THD *thd, TABLE **table,uint count);
static void print_lock_error(int error, const char *);
-MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
- bool ignore_global_read_lock)
+/*
+ Lock tables.
+
+ SYNOPSIS
+ mysql_lock_tables()
+ thd The current thread.
+ tables An array of pointers to the tables to lock.
+ count The number of tables to lock.
+ flags Options:
+ MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
+ MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
+
+ RETURN
+ A lock structure pointer on success.
+ NULL on error.
+*/
+
+MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
{
MYSQL_LOCK *sql_lock;
TABLE *write_lock_used;
@@ -94,7 +110,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used)))
break;
- if (global_read_lock && write_lock_used && ! ignore_global_read_lock)
+ if (global_read_lock && write_lock_used &&
+ ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
{
/*
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
@@ -128,7 +145,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
thd->some_tables_deleted=1; // Try again
sql_lock->lock_count=0; // Locks are alread freed
}
- else if (!thd->some_tables_deleted)
+ else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
{
thd->locked=0;
break;
@@ -951,48 +968,3 @@ bool make_global_read_lock_block_commit(THD *thd)
}
-
-/*
- Set protection against global read lock.
-
- SYNOPSIS
- set_protect_against_global_read_lock()
- void
-
- RETURN
- FALSE OK, no global read lock exists.
- TRUE Error, global read lock exists already.
-*/
-
-bool set_protect_against_global_read_lock(void)
-{
- bool global_read_lock_exists;
-
- pthread_mutex_lock(&LOCK_open);
- if (! (global_read_lock_exists= test(global_read_lock)))
- protect_against_global_read_lock++;
- pthread_mutex_unlock(&LOCK_open);
- return global_read_lock_exists;
-}
-
-
-/*
- Unset protection against global read lock.
-
- SYNOPSIS
- unset_protect_against_global_read_lock()
- void
-
- RETURN
- void
-*/
-
-void unset_protect_against_global_read_lock(void)
-{
- pthread_mutex_lock(&LOCK_open);
- protect_against_global_read_lock--;
- pthread_mutex_unlock(&LOCK_open);
- pthread_cond_broadcast(&COND_refresh);
-}
-
-
diff --git a/sql/log_event.cc b/sql/log_event.cc
index e9897607800..d4225b39704 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -16,6 +16,9 @@
#ifndef MYSQL_CLIENT
+
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a061a28d346..7adb175ed1b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1166,8 +1166,11 @@ extern pthread_t signal_thread;
extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */
-MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
- bool ignore_global_read_lock= FALSE);
+MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags);
+/* mysql_lock_tables() flags bits */
+#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
+#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
+
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5479a5466f0..6625696c911 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3478,7 +3478,7 @@ static void bootstrap(FILE *file)
thd->client_capabilities=0;
my_net_init(&thd->net,(st_vio*) 0);
thd->max_client_packet_length= thd->net.max_packet;
- thd->master_access= ~0;
+ thd->master_access= ~(ulong)0;
thd->thread_id=thread_id++;
thread_count++;
@@ -5830,7 +5830,6 @@ static void print_version(void)
server_version,SYSTEM_TYPE,MACHINE_TYPE, MYSQL_COMPILATION_COMMENT);
}
-
static void usage(void)
{
if (!(default_charset_info= get_charset_by_csname(default_character_set_name,
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index c250238eb4b..95c9fc5035e 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -36,6 +36,8 @@
QUICK_RANGEs are also created in this step.
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 8d365262334..b639ba6efa7 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -691,7 +691,7 @@ class SQL_SELECT :public Sql_alloc {
~SQL_SELECT();
void cleanup();
bool check_quick(THD *thd, bool force_quick_range, ha_rows limit)
- { return test_quick_select(thd, key_map(~0), 0, limit, force_quick_range) < 0; }
+ { return test_quick_select(thd, key_map(~(uint)0), 0, limit, force_quick_range) < 0; }
inline bool skip_record() { return cond ? cond->val_int() == 0 : 0; }
int test_quick_select(THD *thd, key_map keys, table_map prev_tables,
ha_rows limit, bool force_quick_range=0);
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 554e2cd0565..38a043300bc 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -17,6 +17,8 @@
/* Procedures (functions with changes output of select) */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 57922cdc677..8019f3a123b 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -19,6 +19,8 @@
The actual communction is handled by the net_xxx functions in net_serv.cc
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/protocol.h b/sql/protocol.h
index 01331ef64ba..5b402cb2669 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -159,8 +159,8 @@ public:
MYSQL_ROWS **prev_record;
ulong row_count;
- Protocol_cursor() {}
- Protocol_cursor(THD *thd_arg, MEM_ROOT *ini_alloc) :Protocol_simple(thd_arg), alloc(ini_alloc) {}
+ Protocol_cursor() :data(NULL) {}
+ Protocol_cursor(THD *thd_arg, MEM_ROOT *ini_alloc) :Protocol_simple(thd_arg), alloc(ini_alloc), data(NULL) {}
bool prepare_for_send(List<Item> *item_list)
{
row_count= 0;
diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc
index ed2d0b583d0..c38a7cdecae 100644
--- a/sql/protocol_cursor.cc
+++ b/sql/protocol_cursor.cc
@@ -19,6 +19,8 @@
The actual communction is handled by the net_xxx functions in net_serv.cc
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index de4ad83fdbb..0b6e44c0272 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -71,7 +71,7 @@ static int init_failsafe_rpl_thread(THD* thd)
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
thd->max_client_packet_length=thd->net.max_packet;
- thd->master_access= ~0;
+ thd->master_access= ~(ulong)0;
thd->priv_user = 0;
pthread_mutex_lock(&LOCK_thread_count);
thd->thread_id = thread_id++;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 106fced8e88..0d743f99b73 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -48,6 +48,8 @@
new attribute.
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -1713,7 +1715,8 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
Item_string *tmp;
pthread_mutex_lock(&LOCK_global_system_variables);
char *str= (char*) value_ptr(thd, var_type, base);
- tmp= new Item_string(str, strlen(str), system_charset_info);
+ tmp= new Item_string(str, strlen(str),
+ system_charset_info, DERIVATION_SYSCONST);
pthread_mutex_unlock(&LOCK_global_system_variables);
return tmp;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index 70803c88c3a..60812469671 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2818,7 +2818,7 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->client_capabilities = 0;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
- thd->master_access= ~0;
+ thd->master_access= ~(ulong)0;
thd->slave_thread = 1;
set_slave_thread_options(thd);
/*
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
index 83811e76f9b..c8f0ed6ba2d 100644
--- a/sql/sp_cache.cc
+++ b/sql/sp_cache.cc
@@ -14,11 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "mysql_priv.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
-
-#include "mysql_priv.h"
#include "sp_cache.h"
#include "sp_head.h"
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index fcca1b51d1c..84694d6b386 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -14,11 +14,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "mysql_priv.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
-
-#include "mysql_priv.h"
#include "sp_head.h"
#include "sp.h"
#include "sp_pcontext.h"
@@ -1913,7 +1912,19 @@ sp_instr_copen::execute(THD *thd, uint *nextp)
else
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
- c->post_open(thd, (lex_keeper ? TRUE : FALSE));
+ /*
+ Work around the fact that errors in selects are not returned properly
+ (but instead converted into a warning), so if a condition handler
+ caught, we have lost the result code.
+ */
+ if (!res)
+ {
+ uint dummy1, dummy2;
+
+ if (thd->spcont->found_handler(&dummy1, &dummy2))
+ res= -1;
+ }
+ c->post_open(thd, (lex_keeper && !res ? TRUE : FALSE));
}
DBUG_RETURN(res);
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index f95a43eb903..0de7fe212c0 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -14,6 +14,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "mysql_priv.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
@@ -22,7 +23,6 @@
#undef SAFEMALLOC /* Problems with threads */
#endif
-#include "mysql_priv.h"
#include "sp_pcontext.h"
#include "sp_head.h"
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 2e79a1e2533..0b5e7448d6c 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -14,6 +14,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include "mysql_priv.h"
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation
#endif
@@ -22,7 +23,6 @@
#undef SAFEMALLOC /* Problems with threads */
#endif
-#include "mysql_priv.h"
#include "mysql.h"
#include "sp_head.h"
#include "sp_rcontext.h"
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7caece67599..a11871c55dc 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1104,7 +1104,7 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern)
{
- ulong host_access= ~0, db_access= 0;
+ ulong host_access= ~(ulong)0, db_access= 0;
uint i,key_length;
char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
@@ -5064,7 +5064,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
}
if (replace_user_table(thd, tables[0].table,
- *lex_user, ~0, 1, 0, 0))
+ *lex_user, ~(ulong)0, 1, 0, 0))
{
result= -1;
continue;
@@ -5091,7 +5091,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
- if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1))
+ if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~(ulong)0, 1))
{
/*
Don't increment counter as replace_db_table deleted the
@@ -5125,7 +5125,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
grant_table->db,
grant_table->tname,
- ~0, 0, 1))
+ ~(ulong)0, 0, 1))
{
result= -1;
}
@@ -5141,7 +5141,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
columns,
grant_table->db,
grant_table->tname,
- ~0, 1))
+ ~(ulong)0, 1))
{
revoked= 1;
continue;
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 6706cee8e9d..55e6dfb3cbe 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -23,6 +23,8 @@
** - type set is out of optimization yet
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 8fbe5bbfcb7..036a838b6fc 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1384,7 +1384,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
MYSQL_LOCK *lock;
/* We should always get these locks */
thd->some_tables_deleted=0;
- if ((lock=mysql_lock_tables(thd,tables,(uint) (tables_ptr-tables))))
+ if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), 0)))
{
thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
}
@@ -2022,7 +2022,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
- if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
+ if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0)))
table= 0;
}
}
@@ -2237,7 +2237,7 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
thd->options|= OPTION_TABLE_LOCK;
}
- if (!(thd->lock=mysql_lock_tables(thd,start, (uint) (ptr - start))))
+ if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), 0)))
{
if (thd->lex->requires_prelocking())
{
@@ -3222,7 +3222,8 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
if (!(*leaves))
make_leaves_list(leaves, tables);
- for (TABLE_LIST *table_list= *leaves;
+ TABLE_LIST *table_list;
+ for (table_list= *leaves;
table_list;
table_list= table_list->next_leaf, tablenr++)
{
@@ -3261,7 +3262,7 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
DBUG_RETURN(1);
}
- for (TABLE_LIST *table_list= tables;
+ for (table_list= tables;
table_list;
table_list= table_list->next_local)
{
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index 2fd603d9381..958268fc314 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -28,7 +28,7 @@ template <uint default_width> class Bitmap
uchar buffer[(default_width+7)/8];
public:
Bitmap() { init(); }
- Bitmap(Bitmap& from) { *this=from; }
+ Bitmap(const Bitmap& from) { *this=from; }
explicit Bitmap(uint prefix_to_set) { init(prefix_to_set); }
void init() { bitmap_init(&map, buffer, default_width, 0); }
void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); }
@@ -61,18 +61,17 @@ public:
my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &map2.map); }
char *print(char *buf) const
{
- char *s=buf; int i;
- for (i=sizeof(buffer)-1; i>=0 ; i--)
+ char *s=buf;
+ const uchar *e=buffer, *b=e+sizeof(buffer)-1;
+ while (!*b && b>e)
+ b--;
+ if ((*s=_dig_vec_upper[*b >> 4]) != '0')
+ s++;
+ *s++=_dig_vec_upper[*b & 15];
+ while (--b>=e)
{
- if ((*s=_dig_vec_upper[buffer[i] >> 4]) != '0')
- break;
- if ((*s=_dig_vec_upper[buffer[i] & 15]) != '0')
- break;
- }
- for (s++, i-- ; i>=0 ; i--)
- {
- *s++=_dig_vec_upper[buffer[i] >> 4];
- *s++=_dig_vec_upper[buffer[i] & 15];
+ *s++=_dig_vec_upper[*b >> 4];
+ *s++=_dig_vec_upper[*b & 15];
}
*s=0;
return buf;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 438bfdbcb73..862cf940173 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -22,6 +22,8 @@
**
*****************************************************************************/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 47987f3a0c6..7c8ead7558e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -695,7 +695,8 @@ public:
virtual Type type() const;
virtual ~Item_arena() {};
- inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; }
+ inline bool is_stmt_prepare_or_first_sp_execute() const
+ { return (int)state < (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
inline bool is_stmt_execute() const
{ return state == PREPARED || state == EXECUTED; }
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index f21a109e95d..eda7f0f6bbb 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -23,6 +23,8 @@
needs something like 'ssh'.
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index bb48b7ada77..1aa034ce61c 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -433,7 +433,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
HANDLER_TABLES_HACK(thd);
- lock= mysql_lock_tables(thd, &tables->table, 1);
+ lock= mysql_lock_tables(thd, &tables->table, 1, 0);
HANDLER_TABLES_HACK(thd);
if (!lock)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 5d87a4ca30b..8e4456a42a6 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1211,10 +1211,13 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
Avoid that a global read lock steps in while we are creating the
new thread. It would block trying to open the table. Hence, the
DI thread and this thread would wait until after the global
- readlock is gone. If the read lock exists already, we leave with
- no table and then switch to non-delayed insert.
+ readlock is gone. Since the insert thread needs to wait for a
+ global read lock anyway, we do it right now. Note that
+ wait_if_global_read_lock() sets a protection against a new
+ global read lock when it succeeds. This needs to be released by
+ start_waiting_global_read_lock().
*/
- if (set_protect_against_global_read_lock())
+ if (wait_if_global_read_lock(thd, 0, 1))
goto err;
if (!(tmp=new delayed_insert()))
{
@@ -1256,7 +1259,11 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
pthread_cond_wait(&tmp->cond_client,&tmp->mutex);
}
pthread_mutex_unlock(&tmp->mutex);
- unset_protect_against_global_read_lock();
+ /*
+ Release the protection against the global read lock and wake
+ everyone, who might want to set a global read lock.
+ */
+ start_waiting_global_read_lock(thd);
thd->proc_info="got old table";
if (tmp->thd.killed)
{
@@ -1292,7 +1299,11 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
err1:
thd->fatal_error();
- unset_protect_against_global_read_lock();
+ /*
+ Release the protection against the global read lock and wake
+ everyone, who might want to set a global read lock.
+ */
+ start_waiting_global_read_lock(thd);
err:
pthread_mutex_unlock(&LOCK_delayed_create);
DBUG_RETURN(0); // Continue with normal insert
@@ -1650,7 +1661,8 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
handler will close the table and finish when the outstanding
inserts are done.
*/
- if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, TRUE)))
+ if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1,
+ MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK)))
{
/* Fatal error */
di->dead= 1;
@@ -1764,7 +1776,7 @@ bool delayed_insert::handle_inserts(void)
if (thd.killed || table->s->version != refresh_version)
{
thd.killed= THD::KILL_CONNECTION;
- max_rows= ~0; // Do as much as possible
+ max_rows= ~(uint)0; // Do as much as possible
}
/*
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
index d57a7dfe4e3..485c569f49c 100644
--- a/sql/sql_list.cc
+++ b/sql/sql_list.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/sql_map.cc b/sql/sql_map.cc
index 9346f3df305..556d37a405c 100644
--- a/sql/sql_map.cc
+++ b/sql/sql_map.cc
@@ -15,6 +15,8 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 831b15cf7ef..b349eda0e2e 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -28,6 +28,8 @@
#ifdef DISABLED_UNTIL_REWRITTEN_IN_4_1
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2191eba2f3e..a9e68de3705 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -651,7 +651,6 @@ static bool check_mqh(THD *thd, uint check_command)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool error= 0;
- time_t check_time = thd->start_time ? thd->start_time : time(NULL);
USER_CONN *uc=thd->user_connect;
DBUG_ENTER("check_mqh");
DBUG_ASSERT(uc != 0);
@@ -2773,6 +2772,24 @@ mysql_execute_command(THD *thd)
lex->create_info.default_table_charset= lex->create_info.table_charset;
lex->create_info.table_charset= 0;
}
+ /*
+ The create-select command will open and read-lock the select table
+ and then create, open and write-lock the new table. If a global
+ read lock steps in, we get a deadlock. The write lock waits for
+ the global read lock, while the global read lock waits for the
+ select table to be closed. So we wait until the global readlock is
+ gone before starting both steps. Note that
+ wait_if_global_read_lock() sets a protection against a new global
+ read lock when it succeeds. This needs to be released by
+ start_waiting_global_read_lock(). We protect the normal CREATE
+ TABLE in the same way. That way we avoid that a new table is
+ created during a gobal read lock.
+ */
+ if (wait_if_global_read_lock(thd, 0, 1))
+ {
+ res= -1;
+ goto unsent_create_error;
+ }
if (select_lex->item_list.elements) // With select
{
select_result *result;
@@ -2790,7 +2807,7 @@ mysql_execute_command(THD *thd)
unique_table(create_table, select_tables))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), create_table->table_name);
- goto unsent_create_error;
+ goto unsent_create_error1;
}
/* If we create merge table, we have to test tables in merge, too */
if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
@@ -2803,7 +2820,7 @@ mysql_execute_command(THD *thd)
if (unique_table(tab, select_tables))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), tab->table_name);
- goto unsent_create_error;
+ goto unsent_create_error1;
}
}
}
@@ -2846,9 +2863,21 @@ mysql_execute_command(THD *thd)
if (!res)
send_ok(thd);
}
+ /*
+ Release the protection against the global read lock and wake
+ everyone, who might want to set a global read lock.
+ */
+ start_waiting_global_read_lock(thd);
lex->link_first_table_back(create_table, link_to_local);
break;
+unsent_create_error1:
+ /*
+ Release the protection against the global read lock and wake
+ everyone, who might want to set a global read lock.
+ */
+ start_waiting_global_read_lock(thd);
+
/* put tables back for PS rexecuting */
unsent_create_error:
lex->link_first_table_back(create_table, link_to_local);
@@ -5865,7 +5894,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->db= empty_c_string;
ptr->db_length= 0;
}
- if (thd->current_arena->is_stmt_prepare())
+ if (thd->current_arena->is_stmt_prepare_or_first_sp_execute())
ptr->db= thd->strdup(ptr->db);
ptr->alias= alias_str;
@@ -6936,12 +6965,14 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
{
/* Check permissions for used tables in CREATE TABLE ... SELECT */
+#ifdef NOT_NECESSARY_TO_CHECK_CREATE_TABLE_EXIST_WHEN_PREPARING_STATEMENT
+ /* This code throws an ill error for CREATE TABLE t1 SELECT * FROM t1 */
/*
Only do the check for PS, becasue we on execute we have to check that
against the opened tables to ensure we don't use a table that is part
of the view (which can only be done after the table has been opened).
*/
- if (thd->current_arena->is_stmt_prepare())
+ if (thd->current_arena->is_stmt_prepare_or_first_sp_execute())
{
/*
For temporary tables we don't have to check if the created table exists
@@ -6954,6 +6985,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
goto err;
}
}
+#endif
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
goto err;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index e23d32cca84..27ef3fcea6f 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -17,6 +17,8 @@
/* mysql_select and join optimization */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
@@ -35,7 +37,7 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
};
const key_map key_map_empty(0);
-const key_map key_map_full(~0);
+const key_map key_map_full(~(uint)0);
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, COND *conds,
@@ -5086,7 +5088,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->select_cond=0;
join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
- join_tab->keys.init(~0); /* test everything in quick */
+ join_tab->keys.init(~(uint)0); /* test everything in quick */
join_tab->info=0;
join_tab->on_expr_ref=0;
join_tab->last_inner= 0;
@@ -5219,7 +5221,10 @@ add_found_match_trig_cond(JOIN_TAB *tab, COND *cond, JOIN_TAB *root_tab)
tmp= new Item_func_trig_cond(tmp, &tab->found);
}
if (tmp)
+ {
tmp->quick_fix_field();
+ tmp->update_used_tables();
+ }
return tmp;
}
@@ -5447,11 +5452,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if (!(tmp= add_found_match_trig_cond(first_inner_tab, tmp, 0)))
DBUG_RETURN(1);
tab->select_cond=sel->cond=tmp;
+ /* Push condition to storage engine if this is enabled
+ and the condition is not guarded */
+ tab->table->file->pushed_cond= NULL;
if (thd->variables.engine_condition_pushdown)
{
COND *push_cond=
- make_cond_for_table(cond,current_map,current_map);
- tab->table->file->pushed_cond= NULL;
+ make_cond_for_table(tmp, current_map, current_map);
if (push_cond)
{
/* Push condition to handler */
@@ -5792,6 +5799,7 @@ make_join_readinfo(JOIN *join, uint options)
if (!table->no_keyread)
{
if (tab->select && tab->select->quick &&
+ tab->select->quick->index != MAX_KEY && //not index_merge
table->used_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 51f802e7465..be4354227a5 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -16,11 +16,12 @@
/* This file is originally from the mysql distribution. Coded by monty */
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
#endif
-#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
#include <m_ctype.h>
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index f44d3191375..d98ae778bcf 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -40,6 +40,34 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
ha_rows *copied,ha_rows *deleted);
static bool prepare_blob_field(THD *thd, create_field *sql_field);
+
+/*
+ Build the path to a file for a table (or the base path that can
+ then have various extensions stuck on to it).
+
+ SYNOPSIS
+ build_table_path()
+ buff Buffer to build the path into
+ bufflen sizeof(buff)
+ db Name of database
+ table Name of table
+ ext Filename extension
+
+ RETURN
+ 0 Error
+ # Size of path
+ */
+
+static uint build_table_path(char *buff, size_t bufflen, const char *db,
+ const char *table, const char *ext)
+{
+ strxnmov(buff, bufflen-1, mysql_data_home, "/", db, "/", table, ext,
+ NullS);
+ return unpack_filename(buff,buff);
+}
+
+
+
/*
delete (drop) tables.
@@ -223,8 +251,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove form file and isam files */
- strxmov(path, mysql_data_home, "/", db, "/", alias, reg_ext, NullS);
- (void) unpack_filename(path,path);
+ build_table_path(path, sizeof(path), db, alias, reg_ext);
}
if (drop_temporary ||
(access(path,F_OK) &&
@@ -316,13 +343,10 @@ int quick_rm_table(enum db_type base,const char *db,
{
char path[FN_REFLEN];
int error=0;
- my_snprintf(path, sizeof(path), "%s/%s/%s%s",
- mysql_data_home, db, table_name, reg_ext);
- unpack_filename(path,path);
+ build_table_path(path, sizeof(path), db, table_name, reg_ext);
if (my_delete(path,MYF(0)))
error=1; /* purecov: inspected */
- my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home, db, table_name);
- unpack_filename(path,path);
+ build_table_path(path, sizeof(path), db, table_name, "");
return ha_delete_table(current_thd, base, path, table_name, 0) || error;
}
@@ -1516,11 +1540,9 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
if (!create_info->default_table_charset)
{
HA_CREATE_INFO db_info;
- uint length;
char path[FN_REFLEN];
- strxmov(path, mysql_data_home, "/", db, NullS);
- length= unpack_dirname(path,path); // Convert if not unix
- strmov(path+length, MY_DB_OPT_FILE);
+ /* Abuse build_table_path() to build the path to the db.opt file */
+ build_table_path(path, sizeof(path), db, MY_DB_OPT_FILE, "");
load_db_opt(thd, path, &db_info);
create_info->default_table_charset= db_info.default_table_charset;
}
@@ -1534,17 +1556,18 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
/* Check if table exists */
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
- my_snprintf(path, sizeof(path), "%s%s%lx_%lx_%x%s",
- mysql_tmpdir, tmp_file_prefix, current_pid, thd->thread_id,
- thd->tmp_table++, reg_ext);
+ char tmp_table_name[NAME_LEN+1];
+ my_snprintf(tmp_table_name, sizeof(tmp_table_name), "%s%lx_%lx_%x",
+ tmp_file_prefix, current_pid, thd->thread_id,
+ thd->tmp_table++);
if (lower_case_table_names)
- my_casedn_str(files_charset_info, path);
+ my_casedn_str(files_charset_info, tmp_table_name);
create_info->table_options|=HA_CREATE_DELAY_KEY_WRITE;
+ build_table_path(path, sizeof(path), db, tmp_table_name, reg_ext);
}
else
- my_snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home, db,
- alias, reg_ext);
- unpack_filename(path,path);
+ build_table_path(path, sizeof(path), db, alias, reg_ext);
+
/* Check if table already exists */
if ((create_info->options & HA_LEX_CREATE_TMP_TABLE)
&& find_temporary_table(thd,db,table_name))
@@ -1756,7 +1779,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
}
table->reginfo.lock_type=TL_WRITE;
- if (!((*lock)= mysql_lock_tables(thd, &table,1)))
+ if (! ((*lock)= mysql_lock_tables(thd, &table, 1, MYSQL_LOCK_IGNORE_FLUSH)))
{
VOID(pthread_mutex_lock(&LOCK_open));
hash_delete(&open_cache,(byte*) table);
@@ -1781,40 +1804,43 @@ mysql_rename_table(enum db_type base,
const char *new_db,
const char *new_name)
{
- char from[FN_REFLEN], to[FN_REFLEN];
- char tmp_from[NAME_LEN+1], tmp_to[NAME_LEN+1];
+ char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN];
+ char *from_base= from, *to_base= to;
+ char tmp_name[NAME_LEN+1];
handler *file=(base == DB_TYPE_UNKNOWN ? 0 : get_new_handler((TABLE*) 0, base));
int error=0;
DBUG_ENTER("mysql_rename_table");
+ build_table_path(from, sizeof(from), old_db, old_name, "");
+ build_table_path(to, sizeof(to), new_db, new_name, "");
+
+ /*
+ If lower_case_table_names == 2 (case-preserving but case-insensitive
+ file system) and the storage is not HA_FILE_BASED, we need to provide
+ a lowercase file name, but we leave the .frm in mixed case.
+ */
if (lower_case_table_names == 2 && file &&
!(file->table_flags() & HA_FILE_BASED))
{
- /* Table handler expects to get all file names as lower case */
- strmov(tmp_from, old_name);
- my_casedn_str(files_charset_info, tmp_from);
- old_name= tmp_from;
+ strmov(tmp_name, old_name);
+ my_casedn_str(files_charset_info, tmp_name);
+ build_table_path(lc_from, sizeof(lc_from), old_db, tmp_name, "");
+ from_base= lc_from;
- strmov(tmp_to, new_name);
- my_casedn_str(files_charset_info, tmp_to);
- new_name= tmp_to;
+ strmov(tmp_name, new_name);
+ my_casedn_str(files_charset_info, tmp_name);
+ build_table_path(lc_to, sizeof(lc_to), new_db, tmp_name, "");
+ to_base= lc_to;
}
- my_snprintf(from, sizeof(from), "%s/%s/%s",
- mysql_data_home, old_db, old_name);
- my_snprintf(to, sizeof(to), "%s/%s/%s",
- mysql_data_home, new_db, new_name);
- fn_format(from,from,"","",4);
- fn_format(to,to, "","",4);
- if (!file ||
- !(error=file->rename_table((const char*) from,(const char *) to)))
+ if (!file || !(error=file->rename_table(from_base, to_base)))
{
if (rename_file_ext(from,to,reg_ext))
{
error=my_errno;
/* Restore old file name */
if (file)
- file->rename_table((const char*) to,(const char *) from);
+ file->rename_table(to_base, from_base);
}
}
delete file;
@@ -1991,8 +2017,8 @@ static int prepare_for_repair(THD* thd, TABLE_LIST *table_list,
if (!(table= table_list->table)) /* if open_ltable failed */
{
char name[FN_REFLEN];
- strxmov(name, mysql_data_home, "/", table_list->db, "/",
- table_list->table_name, NullS);
+ build_table_path(name, sizeof(name), table_list->db,
+ table_list->table_name, "");
if (openfrm(thd, name, "", 0, 0, 0, &tmp_table))
DBUG_RETURN(0); // Can't open frm file
table= &tmp_table;
@@ -2327,6 +2353,28 @@ send_result_message:
((result_code= table->table->file->analyze(thd, check_opt)) > 0))
result_code= 0; // analyze went ok
}
+ if (result_code) // either mysql_recreate_table or analyze failed
+ {
+ const char *err_msg;
+ if ((err_msg= thd->net.last_error))
+ {
+ if (!thd->vio_ok())
+ {
+ sql_print_error(err_msg);
+ }
+ else
+ {
+ /* Hijack the row already in-progress. */
+ protocol->store("error", 5, system_charset_info);
+ protocol->store(err_msg, system_charset_info);
+ (void)protocol->write();
+ /* Start off another row for HA_ADMIN_FAILED */
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ }
+ }
+ }
result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
table->next_local= save_next_local;
table->next_global= save_next_global;
@@ -2858,11 +2906,10 @@ int mysql_create_indexes(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
else
{
if (table->file->add_index(table, key_info_buffer, key_count)||
- (my_snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
- table_list->db, (lower_case_table_names == 2) ?
- table_list->alias: table_list->table_name, reg_ext) >=
- (int) sizeof(path)) ||
- ! unpack_filename(path, path) ||
+ build_table_path(path, sizeof(path), table_list->db,
+ (lower_case_table_names == 2) ?
+ table_list->alias : table_list->table_name,
+ reg_ext) != 0 ||
mysql_create_frm(thd, path, &create_info,
fields, key_count, key_info_buffer, table->file))
/* don't need to free((gptr) key_info_buffer);*/
@@ -2960,11 +3007,10 @@ int mysql_drop_indexes(THD *thd, TABLE_LIST *table_list,
&keys, /*tmp_table*/ 0, &db_options, table->file,
&key_info_buffer, key_count,
/*select_field_count*/ 0)||
- (snprintf(path, sizeof(path), "%s/%s/%s%s", mysql_data_home,
- table_list->db, (lower_case_table_names == 2)?
- table_list->alias: table_list->table_name, reg_ext)>=
- (int)sizeof(path))||
- ! unpack_filename(path, path)||
+ build_table_path(path, sizeof(path), table_list->db,
+ (lower_case_table_names == 2) ?
+ table_list->alias : table_list->table_name,
+ reg_ext) != 0 ||
mysql_create_frm(thd, path, &create_info,
fields, key_count, key_info_buffer, table->file))
/*don't need to free((gptr) key_numbers);*/
@@ -3718,9 +3764,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
shutdown.
*/
char path[FN_REFLEN];
- my_snprintf(path, sizeof(path), "%s/%s/%s", mysql_data_home,
- new_db, table_name);
- fn_format(path,path,"","",4);
+ build_table_path(path, sizeof(path), new_db, table_name, "");
table=open_temporary_table(thd, path, new_db, tmp_name,0);
if (table)
{
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 03d54b60318..7c6e88306d9 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -28,6 +28,8 @@
dynamic functions, so this shouldn't be a real problem.
*/
+#include <my_global.h>
+
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: implement sql_udf.h
#endif
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 8d36889df76..56401ced67c 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -323,7 +323,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
}
if (tmp_arena)
thd->restore_backup_item_arena(tmp_arena, &backup);
- if (arena->is_stmt_prepare())
+ if (arena->is_stmt_prepare_or_first_sp_execute())
{
/* prepare fake select to initialize it correctly */
init_prepare_fake_select_lex(thd);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 708dcb7a0d9..2f584bc6b4e 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -4343,7 +4343,18 @@ simple_expr:
| CONVERT_SYM '(' expr USING charset_name ')'
{ $$= new Item_func_conv_charset($3,$5); }
| DEFAULT '(' simple_ident ')'
- { $$= new Item_default_value($3); }
+ {
+ if ($3->is_splocal())
+ {
+ LEX_STRING *name;
+ Item_splocal *il= static_cast<Item_splocal *>($3);
+
+ name= il->my_name(NULL);
+ my_error(ER_WRONG_COLUMN_NAME, MYF(0), name->str);
+ YYABORT;
+ }
+ $$= new Item_default_value($3);
+ }
| VALUES '(' simple_ident ')'
{ $$= new Item_insert_value($3); }
| FUNC_ARG0 '(' ')'
@@ -7078,7 +7089,32 @@ simple_ident_q:
field_ident:
ident { $$=$1;}
- | ident '.' ident { $$=$3;} /* Skip schema name in create*/
+ | ident '.' ident '.' ident
+ {
+ TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first;
+ if (my_strcasecmp(table_alias_charset, $1.str, table->db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
+ YYABORT;
+ }
+ if (my_strcasecmp(table_alias_charset, $3.str,
+ table->table_name))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), $3.str);
+ YYABORT;
+ }
+ $$=$5;
+ }
+ | ident '.' ident
+ {
+ TABLE_LIST *table= (TABLE_LIST*) Select->table_list.first;
+ if (my_strcasecmp(table_alias_charset, $1.str, table->alias))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), $1.str);
+ YYABORT;
+ }
+ $$=$3;
+ }
| '.' ident { $$=$2;} /* For Delphi */;
table_ident:
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 11cdf64de29..a52b9701e8e 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -20,18 +20,20 @@
(We will refer to this code as to elsie-code further.)
*/
-#ifdef USE_PRAGMA_IMPLEMENTATION
-#pragma implementation // gcc: Class implementation
-#endif
-
/*
We should not include mysql_priv.h in mysql_tzinfo_to_sql utility since
it creates unsolved link dependencies on some platforms.
*/
+
+#include <my_global.h>
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
#if !defined(TZINFO2SQL) && !defined(TESTTIME)
#include "mysql_priv.h"
#else
-#include <my_global.h>
#include <my_time.h>
#include "tztime.h"
#include <my_sys.h>