summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <stewart@mysql.com>2005-07-20 14:04:48 +1000
committerunknown <stewart@mysql.com>2005-07-20 14:04:48 +1000
commit6b434e2a856d71773876e023011036efa619b15d (patch)
tree1ba2b79fe9ff74cf596fbae8a21f2f792e1ee459 /sql
parent3b47b049689ea7c6897065e1edb367bfa6e4ff17 (diff)
parentf03607ea9e72f726ce11b60826bbf30ebabc2806 (diff)
downloadmariadb-git-6b434e2a856d71773876e023011036efa619b15d.tar.gz
Merge ssmith@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/stewart/Documents/MySQL/5.0/main
Diffstat (limited to 'sql')
-rw-r--r--sql/des_key_file.cc25
-rw-r--r--sql/examples/ha_archive.cc12
-rw-r--r--sql/examples/ha_archive.h9
-rw-r--r--sql/examples/ha_example.cc22
-rw-r--r--sql/examples/ha_example.h4
-rw-r--r--sql/examples/ha_tina.cc31
-rw-r--r--sql/examples/ha_tina.h14
-rw-r--r--sql/field.cc211
-rw-r--r--sql/field_conv.cc32
-rw-r--r--sql/ha_berkeley.cc14
-rw-r--r--sql/ha_berkeley.h7
-rw-r--r--sql/ha_blackhole.cc28
-rw-r--r--sql/ha_blackhole.h4
-rw-r--r--sql/ha_federated.cc31
-rw-r--r--sql/ha_federated.h6
-rw-r--r--sql/ha_heap.cc24
-rw-r--r--sql/ha_heap.h3
-rw-r--r--sql/ha_innodb.cc27
-rw-r--r--sql/ha_innodb.h14
-rw-r--r--sql/ha_myisam.cc44
-rw-r--r--sql/ha_myisam.h8
-rw-r--r--sql/ha_myisammrg.cc24
-rw-r--r--sql/ha_myisammrg.h2
-rw-r--r--sql/ha_ndbcluster.cc9
-rw-r--r--sql/handler.cc17
-rw-r--r--sql/handler.h9
-rw-r--r--sql/hostname.cc10
-rw-r--r--sql/item.cc7
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_strfunc.cc106
-rw-r--r--sql/item_timefunc.cc4
-rw-r--r--sql/lex.h1
-rw-r--r--sql/lock.cc19
-rw-r--r--sql/log_event.cc18
-rw-r--r--sql/mysql_priv.h8
-rw-r--r--sql/mysqld.cc48
-rw-r--r--sql/set_var.cc4
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sp.cc4
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_bitmap.h9
-rw-r--r--sql/sql_class.cc20
-rw-r--r--sql/sql_class.h24
-rw-r--r--sql/sql_lex.h1
-rw-r--r--sql/sql_parse.cc41
-rw-r--r--sql/sql_prepare.cc23
-rw-r--r--sql/sql_select.cc32
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_show.cc116
-rw-r--r--sql/sql_table.cc14
-rw-r--r--sql/sql_trigger.cc367
-rw-r--r--sql/sql_trigger.h11
-rw-r--r--sql/sql_yacc.yy32
-rw-r--r--sql/table.h2
55 files changed, 1128 insertions, 439 deletions
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index 34bcbd4fc4b..77cb0c8de0f 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -21,18 +21,6 @@
struct st_des_keyschedule des_keyschedule[10];
uint des_default_key;
-pthread_mutex_t LOCK_des_key_file;
-static int initialized= 0;
-
-void
-init_des_key_file()
-{
- if (!initialized)
- {
- initialized=1;
- pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
- }
-}
/*
Function which loads DES keys from plaintext file into memory on MySQL
@@ -55,8 +43,6 @@ load_des_key_file(const char *file_name)
DBUG_ENTER("load_des_key_file");
DBUG_PRINT("enter",("name: %s",file_name));
- init_des_key_file();
-
VOID(pthread_mutex_lock(&LOCK_des_key_file));
if ((file=my_open(file_name,O_RDONLY | O_BINARY ,MYF(MY_WME))) < 0 ||
init_io_cache(&io, file, IO_SIZE*2, READ_CACHE, 0, 0, MYF(MY_WME)))
@@ -113,15 +99,4 @@ error:
VOID(pthread_mutex_unlock(&LOCK_des_key_file));
DBUG_RETURN(result);
}
-
-
-void free_des_key_file()
-{
- if (initialized)
- {
- initialized= 01;
- pthread_mutex_destroy(&LOCK_des_key_file);
- }
-}
-
#endif /* HAVE_OPENSSL */
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc
index c362985f565..e5c35ae019d 100644
--- a/sql/examples/ha_archive.cc
+++ b/sql/examples/ha_archive.cc
@@ -149,7 +149,8 @@ static handlerton archive_hton = {
0, /* prepare */
0, /* recover */
0, /* commit_by_xid */
- 0 /* rollback_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
};
@@ -208,6 +209,15 @@ bool archive_db_end()
return FALSE;
}
+ha_archive::ha_archive(TABLE *table_arg)
+ :handler(&archive_hton, table_arg), delayed_insert(0), bulk_insert(0)
+{
+ /* Set our original buffer from pre-allocated memory */
+ buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
+
+ /* The size of the offset value we will use for position() */
+ ref_length = sizeof(z_off_t);
+}
/*
This method reads the header of a datafile and returns whether or not it was successful.
diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h
index 3932b62980c..41835c5fb6f 100644
--- a/sql/examples/ha_archive.h
+++ b/sql/examples/ha_archive.h
@@ -58,14 +58,7 @@ class ha_archive: public handler
bool bulk_insert; /* If we are performing a bulk insert */
public:
- ha_archive(TABLE *table): handler(table), delayed_insert(0), bulk_insert(0)
- {
- /* Set our original buffer from pre-allocated memory */
- buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info);
-
- /* The size of the offset value we will use for position() */
- ref_length = sizeof(z_off_t);
- }
+ ha_archive(TABLE *table_arg);
~ha_archive()
{
}
diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc
index 9da297ccd1f..2818c176cd3 100644
--- a/sql/examples/ha_example.cc
+++ b/sql/examples/ha_example.cc
@@ -72,6 +72,24 @@
#ifdef HAVE_EXAMPLE_DB
#include "ha_example.h"
+
+static handlerton example_hton= {
+ "CSV",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
/* Variables for example share methods */
static HASH example_open_tables; // Hash used to track open tables
pthread_mutex_t example_mutex; // This is the mutex we use to init the hash
@@ -179,6 +197,10 @@ static int free_share(EXAMPLE_SHARE *share)
}
+ha_example::ha_example(TABLE *table_arg)
+ :handler(&example_hton, table_arg)
+{}
+
/*
If frm_error() is called then we will use this to to find out what file extentions
exist for the storage engine. This is also used by the default rename_table and
diff --git a/sql/examples/ha_example.h b/sql/examples/ha_example.h
index ae72e5bb275..37f38fe5210 100644
--- a/sql/examples/ha_example.h
+++ b/sql/examples/ha_example.h
@@ -45,9 +45,7 @@ class ha_example: public handler
EXAMPLE_SHARE *share; /* Shared lock info */
public:
- ha_example(TABLE *table): handler(table)
- {
- }
+ ha_example(TABLE *table_arg);
~ha_example()
{
}
diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc
index a030960d08a..9c774c1f75c 100644
--- a/sql/examples/ha_tina.cc
+++ b/sql/examples/ha_tina.cc
@@ -54,6 +54,23 @@ pthread_mutex_t tina_mutex;
static HASH tina_open_tables;
static int tina_init= 0;
+static handlerton tina_hton= {
+ "CSV",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
/*****************************************************************************
** TINA tables
*****************************************************************************/
@@ -228,6 +245,20 @@ byte * find_eoln(byte *data, off_t begin, off_t end)
return 0;
}
+
+ha_tina::ha_tina(TABLE *table_arg)
+ :handler(&tina_hton, table_arg),
+ /*
+ These definitions are found in hanler.h
+ These are not probably completely right.
+ */
+ current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH)
+{
+ /* Set our original buffers from pre-allocated memory */
+ buffer.set(byte_buffer, IO_SIZE, system_charset_info);
+ chain= chain_buffer;
+}
+
/*
Encode a buffer into the quoted format.
*/
diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h
index 22193c01013..5679d77a4dc 100644
--- a/sql/examples/ha_tina.h
+++ b/sql/examples/ha_tina.h
@@ -49,18 +49,8 @@ class ha_tina: public handler
byte chain_alloced;
uint32 chain_size;
- public:
- ha_tina(TABLE *table): handler(table),
- /*
- These definitions are found in hanler.h
- Theses are not probably completely right.
- */
- current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH)
- {
- /* Set our original buffers from pre-allocated memory */
- buffer.set(byte_buffer, IO_SIZE, system_charset_info);
- chain = chain_buffer;
- }
+public:
+ ha_tina(TABLE *table_arg);
~ha_tina()
{
if (chain_alloced)
diff --git a/sql/field.cc b/sql/field.cc
index 52f260e7b2d..a9b22a2fca9 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -4471,13 +4471,13 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
bool in_dst_time_gap;
THD *thd= table->in_use;
+ /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
have_smth_to_conv= (str_to_datetime(from, len, &l_time,
- ((table->in_use->variables.sql_mode &
- MODE_NO_ZERO_DATE) |
- MODE_NO_ZERO_IN_DATE),
- &error) >
+ (table->in_use->variables.sql_mode &
+ MODE_NO_ZERO_DATE) |
+ MODE_NO_ZERO_IN_DATE, &error) >
MYSQL_TIMESTAMP_ERROR);
-
+
if (error || !have_smth_to_conv)
{
error= 1;
@@ -4490,16 +4490,15 @@ int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
if (!(tmp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
{
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
from, len, MYSQL_TIMESTAMP_DATETIME, !error);
-
error= 1;
}
else if (in_dst_time_gap)
{
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_INVALID_TIMESTAMP,
+ ER_WARN_INVALID_TIMESTAMP,
from, len, MYSQL_TIMESTAMP_DATETIME, !error);
error= 1;
}
@@ -4524,8 +4523,8 @@ int Field_timestamp::store(double nr)
int error= 0;
if (nr < 0 || nr > 99991231235959.0)
{
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_OUT_OF_RANGE,
nr, MYSQL_TIMESTAMP_DATETIME);
nr= 0; // Avoid overflow on buff
error= 1;
@@ -4543,35 +4542,35 @@ int Field_timestamp::store(longlong nr)
bool in_dst_time_gap;
THD *thd= table->in_use;
- if (number_to_datetime(nr, &l_time, 0, &error))
+ /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */
+ long tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode &
+ MODE_NO_ZERO_DATE) |
+ MODE_NO_ZERO_IN_DATE, &error);
+ if (tmp < 0)
+ {
+ error= 2;
+ }
+
+ if (!error && tmp)
{
if (!(timestamp= TIME_to_timestamp(thd, &l_time, &in_dst_time_gap)))
{
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_OUT_OF_RANGE,
+ nr, MYSQL_TIMESTAMP_DATETIME, 1);
error= 1;
}
-
if (in_dst_time_gap)
{
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_INVALID_TIMESTAMP,
- nr, MYSQL_TIMESTAMP_DATETIME, !error);
+ ER_WARN_INVALID_TIMESTAMP,
+ nr, MYSQL_TIMESTAMP_DATETIME, 1);
error= 1;
}
- }
- else if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ } else if (error)
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED,
nr, MYSQL_TIMESTAMP_DATETIME, 1);
- if (!error && timestamp == 0 &&
- (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE))
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED,
- nr, MYSQL_TIMESTAMP_DATETIME, 1);
- }
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
@@ -4581,7 +4580,7 @@ int Field_timestamp::store(longlong nr)
else
#endif
longstore(ptr,(uint32) timestamp);
-
+
return error;
}
@@ -5154,14 +5153,14 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
TIME l_time;
uint32 tmp;
int error;
-
+
if (str_to_datetime(from, len, &l_time, TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
MODE_INVALID_DATES)),
&error) <= MYSQL_TIMESTAMP_ERROR)
{
- tmp=0;
+ tmp= 0;
error= 2;
}
else
@@ -5192,56 +5191,50 @@ int Field_date::store(double nr)
if (nr < 0.0 || nr > 99991231.0)
{
tmp=0L;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_OUT_OF_RANGE,
nr, MYSQL_TIMESTAMP_DATE);
error= 1;
}
else
tmp=(long) rint(nr);
- /*
- We don't need to check for zero dates here as this date type is only
- used in .frm tables from very old MySQL versions
- */
-
-#ifdef WORDS_BIGENDIAN
- if (table->s->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
-#endif
- longstore(ptr,tmp);
- return error;
+ return Field_date::store(tmp);
}
int Field_date::store(longlong nr)
{
- long tmp;
- int error= 0;
- if (nr >= LL(19000000000000) && nr < LL(99991231235959))
- nr=nr/LL(1000000); // Timestamp to date
- if (nr < 0 || nr > LL(99991231))
+ TIME not_used;
+ int error;
+ longlong initial_nr= nr;
+
+ nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+
+ if (nr < 0)
{
- tmp=0L;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- nr, MYSQL_TIMESTAMP_DATE, 0);
- error= 1;
+ nr= 0;
+ error= 2;
}
- else
- tmp=(long) nr;
+
+ if (error)
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
+ WARN_DATA_TRUNCATED, initial_nr,
+ MYSQL_TIMESTAMP_DATETIME, 1);
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
- int4store(ptr,tmp);
+ int4store(ptr, nr);
}
else
#endif
- longstore(ptr,tmp);
+ longstore(ptr, nr);
return error;
}
@@ -5365,7 +5358,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
MODE_INVALID_DATES))),
&error) <= MYSQL_TIMESTAMP_ERROR)
{
- tmp=0L;
+ tmp= 0L;
error= 2;
}
else
@@ -5374,7 +5367,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
if (error)
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED,
from, len, MYSQL_TIMESTAMP_DATE, 1);
-
+
int3store(ptr,tmp);
return error;
}
@@ -5385,7 +5378,7 @@ int Field_newdate::store(double nr)
if (nr < 0.0 || nr > 99991231235959.0)
{
int3store(ptr,(int32) 0);
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
WARN_DATA_TRUNCATED, nr, MYSQL_TIMESTAMP_DATE);
return 1;
}
@@ -5395,52 +5388,28 @@ int Field_newdate::store(double nr)
int Field_newdate::store(longlong nr)
{
- int32 tmp;
- int error= 0;
- if (nr >= LL(100000000) && nr <= LL(99991231235959))
- nr=nr/LL(1000000); // Timestamp to date
- if (nr < 0L || nr > 99991231L)
- {
- tmp=0;
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_DATE, 1);
- error= 1;
+ TIME l_time;
+ long tmp;
+ int error;
+ if ((tmp= number_to_datetime(nr, &l_time,
+ (TIME_FUZZY_DATE |
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))),
+ &error) < 0))
+ {
+ tmp= 0L;
+ error= 2;
}
else
- {
- uint month, day;
+ tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
- tmp=(int32) nr;
- if (tmp)
- {
- if (tmp < YY_PART_YEAR*10000L) // Fix short dates
- tmp+= (uint32) 20000000L;
- else if (tmp < 999999L)
- tmp+= (uint32) 19000000L;
-
- month= (uint) ((tmp/100) % 100);
- day= (uint) (tmp%100);
- if (month > 12 || day > 31)
- {
- tmp=0L; // Don't allow date to change
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE, nr,
- MYSQL_TIMESTAMP_DATE, 1);
- error= 1;
- }
- else
- tmp= day + month*32 + (tmp/10000)*16*32;
- }
- else if (table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)
- {
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- 0, MYSQL_TIMESTAMP_DATE);
- error= 1;
- }
- }
- int3store(ptr, tmp);
+ if (error)
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
+ WARN_DATA_TRUNCATED,nr,MYSQL_TIMESTAMP_DATE, 1);
+
+ int3store(ptr,tmp);
return error;
}
@@ -5567,7 +5536,7 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
ulonglong tmp= 0;
enum enum_mysql_timestamp_type func_res;
-
+
func_res= str_to_datetime(from, len, &time_tmp,
(TIME_FUZZY_DATE |
(table->in_use->variables.sql_mode &
@@ -5580,7 +5549,7 @@ int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1; // Fix if invalid zero date
if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARN_DATA_OUT_OF_RANGE,
from, len, MYSQL_TIMESTAMP_DATETIME, 1);
@@ -5617,21 +5586,25 @@ int Field_datetime::store(longlong nr)
TIME not_used;
int error;
longlong initial_nr= nr;
-
- nr= number_to_datetime(nr, &not_used, 1, &error);
- if (error)
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- WARN_DATA_TRUNCATED, initial_nr,
- MYSQL_TIMESTAMP_DATETIME, 1);
- else if (nr == 0 && table->in_use->variables.sql_mode & MODE_NO_ZERO_DATE)
+ nr= number_to_datetime(nr, &not_used, (TIME_FUZZY_DATE |
+ (table->in_use->variables.sql_mode &
+ (MODE_NO_ZERO_IN_DATE |
+ MODE_NO_ZERO_DATE |
+ MODE_INVALID_DATES))), &error);
+
+ if (nr < 0)
{
- set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_OUT_OF_RANGE,
- initial_nr, MYSQL_TIMESTAMP_DATE, 1);
- error= 1;
+ nr= 0;
+ error= 2;
}
+ if (error)
+ set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ error == 2 ? ER_WARN_DATA_OUT_OF_RANGE :
+ WARN_DATA_TRUNCATED, initial_nr,
+ MYSQL_TIMESTAMP_DATETIME, 1);
+
#ifdef WORDS_BIGENDIAN
if (table->s->db_low_byte_first)
{
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 0dc82666f52..fc7347ef9af 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -322,7 +322,34 @@ static void do_field_real(Copy_field *copy)
}
+/*
+ string copy for single byte characters set when to string is shorter than
+ from string
+*/
+
static void do_cut_string(Copy_field *copy)
+{
+ CHARSET_INFO *cs= copy->from_field->charset();
+ memcpy(copy->to_ptr,copy->from_ptr,copy->to_length);
+
+ /* Check if we loosed any important characters */
+ if (cs->cset->scan(cs,
+ copy->from_ptr + copy->to_length,
+ copy->from_ptr + copy->from_length,
+ MY_SEQ_SPACES) < copy->from_length - copy->to_length)
+ {
+ copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
+ WARN_DATA_TRUNCATED, 1);
+ }
+}
+
+
+/*
+ string copy for multi byte characters set when to string is shorter than
+ from string
+*/
+
+static void do_cut_string_complex(Copy_field *copy)
{ // Shorter string field
int well_formed_error;
CHARSET_INFO *cs= copy->from_field->charset();
@@ -349,6 +376,8 @@ static void do_cut_string(Copy_field *copy)
}
+
+
static void do_expand_string(Copy_field *copy)
{
CHARSET_INFO *cs= copy->from_field->charset();
@@ -550,7 +579,8 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*)
do_varstring1 : do_varstring2);
}
else if (to_length < from_length)
- return do_cut_string;
+ return (from->charset()->mbmaxlen == 1 ?
+ do_cut_string : do_cut_string_complex);
else if (to_length > from_length)
return do_expand_string;
}
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 568fb727e63..26e743d4a71 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -120,7 +120,8 @@ static handlerton berkeley_hton = {
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
- NULL /* rollback_by_xid */
+ NULL, /* rollback_by_xid */
+ HTON_CLOSE_CURSORS_AT_COMMIT
};
typedef struct st_berkeley_trx_data {
@@ -372,6 +373,17 @@ void berkeley_cleanup_log_files(void)
/*****************************************************************************
** Berkeley DB tables
*****************************************************************************/
+
+ha_berkeley::ha_berkeley(TABLE *table_arg)
+ :handler(&berkeley_hton, table_arg), alloc_ptr(0), rec_buff(0), file(0),
+ int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
+ HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT |
+ HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
+ HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
+ changed_rows(0), last_dup_key((uint) -1), version(0), using_ignore(0)
+{}
+
+
static const char *ha_berkeley_exts[] = {
ha_berkeley_ext,
NullS
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index f6376939445..aa92908ecde 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -85,12 +85,7 @@ class ha_berkeley: public handler
DBT *get_pos(DBT *to, byte *pos);
public:
- ha_berkeley(TABLE *table): handler(table), alloc_ptr(0),rec_buff(0), file(0),
- int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ |
- HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT |
- HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED |
- HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX),
- changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0) {}
+ ha_berkeley(TABLE *table_arg);
~ha_berkeley() {}
const char *table_type() const { return "BerkeleyDB"; }
ulong index_flags(uint idx, uint part, bool all_parts) const;
diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc
index 6abbe983f48..ae6952d4e5b 100644
--- a/sql/ha_blackhole.cc
+++ b/sql/ha_blackhole.cc
@@ -24,6 +24,34 @@
#include "ha_blackhole.h"
+/* Blackhole storage engine handlerton */
+
+static handlerton blackhole_hton= {
+ "BLACKHOLE",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
+/*****************************************************************************
+** BLACKHOLE tables
+*****************************************************************************/
+
+ha_blackhole::ha_blackhole(TABLE *table_arg)
+ :handler(&blackhole_hton, table_arg)
+{}
+
+
static const char *ha_blackhole_exts[] = {
NullS
};
diff --git a/sql/ha_blackhole.h b/sql/ha_blackhole.h
index 84a386e17f8..2dccabf17cc 100644
--- a/sql/ha_blackhole.h
+++ b/sql/ha_blackhole.h
@@ -28,9 +28,7 @@ class ha_blackhole: public handler
THR_LOCK thr_lock;
public:
- ha_blackhole(TABLE *table): handler(table)
- {
- }
+ ha_blackhole(TABLE *table_arg);
~ha_blackhole()
{
}
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index e0e35c6b866..1d7b8cda8e2 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -679,6 +679,37 @@ error:
}
+/* Federated storage engine handlerton */
+
+static handlerton federated_hton= {
+ "FEDERATED",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
+
+/*****************************************************************************
+** FEDERATED tables
+*****************************************************************************/
+
+ha_federated::ha_federated(TABLE *table_arg)
+ :handler(&federated_hton, table_arg),
+ mysql(0), stored_result(0), scan_flag(0),
+ ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
+{}
+
+
/*
Convert MySQL result set row to handler internal format
diff --git a/sql/ha_federated.h b/sql/ha_federated.h
index 3e55419f266..58b78ab0dde 100644
--- a/sql/ha_federated.h
+++ b/sql/ha_federated.h
@@ -162,11 +162,7 @@ private:
bool records_in_range);
public:
- ha_federated(TABLE *table): handler(table),
- mysql(0), stored_result(0), scan_flag(0),
- ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
- {
- }
+ ha_federated(TABLE *table_arg);
~ha_federated()
{
}
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 6e609a94be3..92a5fe0ea09 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -23,9 +23,33 @@
#include <myisampack.h>
#include "ha_heap.h"
+static handlerton heap_hton= {
+ "MEMORY",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
/*****************************************************************************
** HEAP tables
*****************************************************************************/
+
+ha_heap::ha_heap(TABLE *table_arg)
+ :handler(&heap_hton, table_arg), file(0), records_changed(0),
+ key_stats_ok(0)
+{}
+
+
static const char *ha_heap_exts[] = {
NullS
};
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 7a97c727049..f7368436456 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -31,8 +31,7 @@ class ha_heap: public handler
uint records_changed;
bool key_stats_ok;
public:
- ha_heap(TABLE *table): handler(table), file(0), records_changed(0),
- key_stats_ok(0) {}
+ ha_heap(TABLE *table);
~ha_heap() {}
const char *table_type() const
{
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 98199a22efe..69451493d4b 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -215,7 +215,14 @@ static handlerton innobase_hton = {
innobase_xa_prepare, /* prepare */
innobase_xa_recover, /* recover */
innobase_commit_by_xid, /* commit_by_xid */
- innobase_rollback_by_xid /* rollback_by_xid */
+ innobase_rollback_by_xid, /* rollback_by_xid */
+ /*
+ For now when one opens a cursor, MySQL does not create an own
+ InnoDB consistent read view for it, and uses the view of the
+ currently active transaction. Therefore, cursors can not
+ survive COMMIT or ROLLBACK statements, which free this view.
+ */
+ HTON_CLOSE_CURSORS_AT_COMMIT
};
/*********************************************************************
@@ -765,6 +772,24 @@ check_trx_exists(
return(trx);
}
+
+/*************************************************************************
+Construct ha_innobase handler. */
+
+ha_innobase::ha_innobase(TABLE *table_arg)
+ :handler(&innobase_hton, table_arg),
+ int_table_flags(HA_REC_NOT_IN_SEQ |
+ HA_NULL_IN_KEY |
+ HA_CAN_INDEX_BLOBS |
+ HA_CAN_SQL_HANDLER |
+ HA_NOT_EXACT_COUNT |
+ HA_PRIMARY_KEY_IN_READ_INDEX |
+ HA_TABLE_SCAN_ON_INDEX),
+ last_dup_key((uint) -1),
+ start_of_scan(0),
+ num_write_row(0)
+{}
+
/*************************************************************************
Updates the user_thd field in a handle and also allocates a new InnoDB
transaction handle if needed, and updates the transaction fields in the
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 90cae3998ed..1584a2182c9 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -81,19 +81,7 @@ class ha_innobase: public handler
/* Init values for the class: */
public:
- ha_innobase(TABLE *table): handler(table),
- int_table_flags(HA_REC_NOT_IN_SEQ |
- HA_NULL_IN_KEY |
- HA_CAN_INDEX_BLOBS |
- HA_CAN_SQL_HANDLER |
- HA_NOT_EXACT_COUNT |
- HA_PRIMARY_KEY_IN_READ_INDEX |
- HA_TABLE_SCAN_ON_INDEX),
- last_dup_key((uint) -1),
- start_of_scan(0),
- num_write_row(0)
- {
- }
+ ha_innobase(TABLE *table_arg);
~ha_innobase() {}
/*
Get the row type from the storage engine. If this method returns
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 0d9c32adbfa..fefa05e92b0 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -44,6 +44,29 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"",
** MyISAM tables
*****************************************************************************/
+/* MyISAM handlerton */
+
+static handlerton myisam_hton= {
+ "MyISAM",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ /*
+ MyISAM doesn't support transactions and doesn't have
+ transaction-dependent context: cursors can survive a commit.
+ */
+ HTON_NO_FLAGS
+};
+
// collect errors printed by mi_check routines
static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
@@ -123,6 +146,17 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...)
}
+
+ha_myisam::ha_myisam(TABLE *table_arg)
+ :handler(&myisam_hton, table_arg), file(0),
+ int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
+ HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
+ HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME |
+ HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD),
+ can_enable_indexes(1)
+{}
+
+
static const char *ha_myisam_exts[] = {
".MYI",
".MYD",
@@ -602,7 +636,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
{
ulonglong key_map= ((local_testflag & T_CREATE_MISSING_KEYS) ?
- ((ulonglong) 1L << share->base.keys)-1 :
+ mi_get_mask_all_keys_active(share->base.keys) :
share->state.key_map);
uint testflag=param.testflag;
if (mi_test_if_sort_rep(file,file->state->records,key_map,0) &&
@@ -903,7 +937,7 @@ int ha_myisam::enable_indexes(uint mode)
{
int error;
- if (file->s->state.key_map == set_bits(ulonglong, file->s->base.keys))
+ if (mi_is_all_keys_active(file->s->state.key_map, file->s->base.keys))
{
/* All indexes are enabled already. */
return 0;
@@ -1002,8 +1036,8 @@ void ha_myisam::start_bulk_insert(ha_rows rows)
if (! rows || (rows > MI_MIN_ROWS_TO_USE_WRITE_CACHE))
mi_extra(file, HA_EXTRA_WRITE_CACHE, (void*) &size);
- can_enable_indexes= (file->s->state.key_map ==
- set_bits(ulonglong, file->s->base.keys));
+ can_enable_indexes= mi_is_all_keys_active(file->s->state.key_map,
+ file->s->base.keys);
if (!(specialflag & SPECIAL_SAFE_MODE))
{
@@ -1256,7 +1290,7 @@ void ha_myisam::info(uint flag)
share->db_options_in_use= info.options;
block_size= myisam_block_size;
share->keys_in_use.set_prefix(share->keys);
- share->keys_in_use.intersect(info.key_map);
+ share->keys_in_use.intersect_extended(info.key_map);
share->keys_for_keyread.intersect(share->keys_in_use);
share->db_record_offset= info.record_offset;
if (share->key_parts)
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index bbd9721f8e2..ca684463311 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -43,13 +43,7 @@ class ha_myisam: public handler
int repair(THD *thd, MI_CHECK &param, bool optimize);
public:
- ha_myisam(TABLE *table): handler(table), file(0),
- int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER |
- HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY |
- HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME |
- HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD),
- can_enable_indexes(1)
- {}
+ ha_myisam(TABLE *table_arg);
~ha_myisam() {}
const char *table_type() const { return "MyISAM"; }
const char *index_type(uint key_number);
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 5d3f379081c..8c4b4e790b1 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -32,6 +32,30 @@
** MyISAM MERGE tables
*****************************************************************************/
+/* MyISAM MERGE handlerton */
+
+static handlerton myisammrg_hton= {
+ "MRG_MyISAM",
+ 0, /* slot */
+ 0, /* savepoint size. */
+ 0, /* close_connection */
+ 0, /* savepoint */
+ 0, /* rollback to savepoint */
+ 0, /* release savepoint */
+ 0, /* commit */
+ 0, /* rollback */
+ 0, /* prepare */
+ 0, /* recover */
+ 0, /* commit_by_xid */
+ 0, /* rollback_by_xid */
+ HTON_NO_FLAGS
+};
+
+
+ha_myisammrg::ha_myisammrg(TABLE *table_arg)
+ :handler(&myisammrg_hton, table_arg), file(0)
+{}
+
static const char *ha_myisammrg_exts[] = {
".MRG",
NullS
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index 7348096b695..c762b7c286e 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -28,7 +28,7 @@ class ha_myisammrg: public handler
MYRG_INFO *file;
public:
- ha_myisammrg(TABLE *table): handler(table), file(0) {}
+ ha_myisammrg(TABLE *table_arg);
~ha_myisammrg() {}
const char *table_type() const { return "MRG_MyISAM"; }
const char **bas_ext() const;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index d35b8af80aa..9e6725178d5 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -62,7 +62,8 @@ static handlerton ndbcluster_hton = {
NULL, /* prepare */
NULL, /* recover */
NULL, /* commit_by_xid */
- NULL /* rollback_by_xid */
+ NULL, /* rollback_by_xid */
+ HTON_NO_FLAGS
};
#define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8
@@ -706,8 +707,8 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
blob_ptr= (char*)"";
}
- DBUG_PRINT("value", ("set blob ptr=%x len=%u",
- (unsigned)blob_ptr, blob_len));
+ DBUG_PRINT("value", ("set blob ptr=%p len=%u",
+ blob_ptr, blob_len));
DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26));
if (set_blob_value)
@@ -4174,7 +4175,7 @@ ulonglong ha_ndbcluster::get_auto_increment()
*/
ha_ndbcluster::ha_ndbcluster(TABLE *table_arg):
- handler(table_arg),
+ handler(&ndbcluster_hton, table_arg),
m_active_trans(NULL),
m_active_cursor(NULL),
m_table(NULL),
diff --git a/sql/handler.cc b/sql/handler.cc
index a61dce35501..0d0f9a75e52 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -208,15 +208,8 @@ handler *get_new_handler(TABLE *table, enum db_type db_type)
case DB_TYPE_HASH:
return new ha_hash(table);
#endif
-#ifdef HAVE_ISAM
- case DB_TYPE_MRG_ISAM:
- return new ha_isammrg(table);
- case DB_TYPE_ISAM:
- return new ha_isam(table);
-#else
case DB_TYPE_MRG_ISAM:
return new ha_myisammrg(table);
-#endif
#ifdef HAVE_BERKELEY_DB
case DB_TYPE_BERKELEY_DB:
return new ha_berkeley(table);
@@ -634,6 +627,11 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_RETURN(1);
}
DBUG_EXECUTE_IF("crash_commit_before", abort(););
+
+ /* Close all cursors that can not survive COMMIT */
+ if (is_real_trans) /* not a statement commit */
+ thd->stmt_map.close_transient_cursors();
+
if (!trans->no_2pc && trans->nht > 1)
{
for (; *ht && !error; ht++)
@@ -735,6 +733,10 @@ int ha_rollback_trans(THD *thd, bool all)
#ifdef USING_TRANSACTIONS
if (trans->nht)
{
+ /* Close all cursors that can not survive ROLLBACK */
+ if (is_real_trans) /* not a statement commit */
+ thd->stmt_map.close_transient_cursors();
+
for (handlerton **ht=trans->ht; *ht; ht++)
{
int err;
@@ -2434,6 +2436,7 @@ TYPELIB *ha_known_exts(void)
known_extensions_id= mysys_usage_id;
found_exts.push_back((char*) triggers_file_ext);
+ found_exts.push_back((char*) trigname_file_ext);
for (types= sys_table_types; types->type; types++)
{
if (*types->value == SHOW_OPTION_YES)
diff --git a/sql/handler.h b/sql/handler.h
index df906e284e7..02b2353b890 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -349,8 +349,13 @@ typedef struct
int (*recover)(XID *xid_list, uint len);
int (*commit_by_xid)(XID *xid);
int (*rollback_by_xid)(XID *xid);
+ uint32 flags; /* global handler flags */
} handlerton;
+/* Possible flags of a handlerton */
+#define HTON_NO_FLAGS 0
+#define HTON_CLOSE_CURSORS_AT_COMMIT 1
+
typedef struct st_thd_trans
{
/* number of entries in the ht[] */
@@ -445,6 +450,7 @@ class handler :public Sql_alloc
virtual int rnd_end() { return 0; }
public:
+ const handlerton *ht; /* storage engine of this handler */
byte *ref; /* Pointer to current row */
byte *dupp_ref; /* Pointer to dupp row */
ulonglong data_file_length; /* Length off data file */
@@ -486,7 +492,8 @@ public:
bool implicit_emptied; /* Can be !=0 only if HEAP */
const COND *pushed_cond;
- handler(TABLE *table_arg) :table(table_arg),
+ handler(const handlerton *ht_arg, TABLE *table_arg) :table(table_arg),
+ ht(ht_arg),
ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0),
delete_length(0), auto_increment_value(0),
records(0), deleted(0), mean_rec_length(0),
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 39223556024..12b69a97859 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -130,15 +130,23 @@ void reset_host_errors(struct in_addr *in)
VOID(pthread_mutex_unlock(&hostname_cache->lock));
}
+/* Deal with systems that don't defined INADDR_LOOPBACK */
+#ifndef INADDR_LOOPBACK
+#define INADDR_LOOPBACK 0x7f000001UL
+#endif
my_string ip_to_hostname(struct in_addr *in, uint *errors)
{
uint i;
host_entry *entry;
DBUG_ENTER("ip_to_hostname");
+ *errors=0;
+
+ /* We always treat the loopback address as "localhost". */
+ if (in->s_addr == INADDR_LOOPBACK)
+ return (char *)my_localhost;
/* Check first if we have name in cache */
- *errors=0;
if (!(specialflag & SPECIAL_NO_HOST_CACHE))
{
VOID(pthread_mutex_lock(&hostname_cache->lock));
diff --git a/sql/item.cc b/sql/item.cc
index d26e4ba7c20..0e3907dd5a6 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3323,7 +3323,12 @@ void Item::make_field(Send_field *tmp_field)
void Item_empty_string::make_field(Send_field *tmp_field)
{
- init_make_field(tmp_field, MYSQL_TYPE_VARCHAR);
+ enum_field_types type= FIELD_TYPE_VAR_STRING;
+ if (max_length >= 16777216)
+ type= FIELD_TYPE_LONG_BLOB;
+ else if (max_length >= 65536)
+ type= FIELD_TYPE_MEDIUM_BLOB;
+ init_make_field(tmp_field, type);
}
diff --git a/sql/item.h b/sql/item.h
index f195557fb69..5a1cf193806 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1781,7 +1781,7 @@ public:
*/
enum trg_action_time_type
{
- TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1
+ TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX
};
/*
@@ -1789,7 +1789,7 @@ enum trg_action_time_type
*/
enum trg_event_type
{
- TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2
+ TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX
};
class Table_triggers_list;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index c3bdb11418f..53895cc7331 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4231,14 +4231,15 @@ Item_func_get_system_var(sys_var *var_arg, enum_var_type var_type_arg,
bool
Item_func_get_system_var::fix_fields(THD *thd, Item **ref)
{
- Item *item= var->item(thd, var_type, &component);
+ Item *item;
DBUG_ENTER("Item_func_get_system_var::fix_fields");
+
/*
Evaluate the system variable and substitute the result (a basic constant)
instead of this item. If the variable can not be evaluated,
the error is reported in sys_var::item().
*/
- if (item == 0)
+ if (!(item= var->item(thd, var_type, &component)))
DBUG_RETURN(1); // Impossible
item->set_name(name, 0, system_charset_info); // don't allocate a new name
thd->change_item_tree(ref, item);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 6d519c73b13..eb37609c28e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -335,19 +335,20 @@ null:
void Item_func_concat::fix_length_and_dec()
{
- max_length=0;
+ ulonglong max_result_length= 0;
if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV))
return;
for (uint i=0 ; i < arg_count ; i++)
- max_length+=args[i]->max_length;
+ max_result_length+= args[i]->max_length;
- if (max_length > MAX_BLOB_WIDTH)
+ if (max_result_length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_result_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) max_result_length;
}
/*
@@ -378,9 +379,6 @@ String *Item_func_des_encrypt::val_str(String *str)
if (arg_count == 1)
{
- /* Make sure LOCK_des_key_file was initialized. */
- init_des_key_file();
-
/* Protect against someone doing FLUSH DES_KEY_FILE */
VOID(pthread_mutex_lock(&LOCK_des_key_file));
keyschedule= des_keyschedule[key_number=des_default_key];
@@ -391,10 +389,6 @@ String *Item_func_des_encrypt::val_str(String *str)
key_number= (uint) args[1]->val_int();
if (key_number > 9)
goto error;
-
- /* Make sure LOCK_des_key_file was initialized. */
- init_des_key_file();
-
VOID(pthread_mutex_lock(&LOCK_des_key_file));
keyschedule= des_keyschedule[key_number];
VOID(pthread_mutex_unlock(&LOCK_des_key_file));
@@ -482,9 +476,6 @@ String *Item_func_des_decrypt::val_str(String *str)
if (!(current_thd->master_access & SUPER_ACL) || key_number > 9)
goto error;
- /* Make sure LOCK_des_key_file was initialized. */
- init_des_key_file();
-
VOID(pthread_mutex_lock(&LOCK_des_key_file));
keyschedule= des_keyschedule[key_number];
VOID(pthread_mutex_unlock(&LOCK_des_key_file));
@@ -658,7 +649,7 @@ null:
void Item_func_concat_ws::fix_length_and_dec()
{
- max_length=0;
+ ulonglong max_result_length;
if (agg_arg_charsets(collation, args, arg_count, MY_COLL_ALLOW_CONV))
return;
@@ -668,15 +659,16 @@ void Item_func_concat_ws::fix_length_and_dec()
it is done on parser level in sql_yacc.yy
so, (arg_count - 2) is safe here.
*/
- max_length= args[0]->max_length * (arg_count - 2);
+ max_result_length= (ulonglong) args[0]->max_length * (arg_count - 2);
for (uint i=1 ; i < arg_count ; i++)
- max_length+=args[i]->max_length;
+ max_result_length+=args[i]->max_length;
- if (max_length > MAX_BLOB_WIDTH)
+ if (max_result_length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_result_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) max_result_length;
}
@@ -855,18 +847,19 @@ null:
void Item_func_replace::fix_length_and_dec()
{
- max_length=args[0]->max_length;
+ ulonglong max_result_length= args[0]->max_length;
int diff=(int) (args[2]->max_length - args[1]->max_length);
if (diff > 0 && args[1]->max_length)
{ // Calculate of maxreplaces
- uint max_substrs= max_length/args[1]->max_length;
- max_length+= max_substrs * (uint) diff;
+ ulonglong max_substrs= max_result_length/args[1]->max_length;
+ max_result_length+= max_substrs * (uint) diff;
}
- if (max_length > MAX_BLOB_WIDTH)
+ if (max_result_length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_result_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) max_result_length;
if (agg_arg_charsets(collation, args, 3, MY_COLL_CMP_CONV))
return;
@@ -914,18 +907,22 @@ null:
void Item_func_insert::fix_length_and_dec()
{
Item *cargs[2];
+ ulonglong max_result_length;
+
cargs[0]= args[0];
cargs[1]= args[3];
if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV))
return;
args[0]= cargs[0];
args[3]= cargs[1];
- max_length=args[0]->max_length+args[3]->max_length;
- if (max_length > MAX_BLOB_WIDTH)
+ max_result_length= ((ulonglong) args[0]->max_length+
+ (ulonglong) args[3]->max_length);
+ if (max_result_length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_result_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) max_result_length;
}
@@ -2001,17 +1998,19 @@ void Item_func_repeat::fix_length_and_dec()
collation.set(args[0]->collation);
if (args[1]->const_item())
{
- max_length=(long) (args[0]->max_length * args[1]->val_int());
- if (max_length >= MAX_BLOB_WIDTH)
+ ulonglong max_result_length= ((ulonglong) args[0]->max_length *
+ args[1]->val_int());
+ if (max_result_length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_result_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) max_result_length;
}
else
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
}
@@ -2066,6 +2065,7 @@ err:
void Item_func_rpad::fix_length_and_dec()
{
Item *cargs[2];
+
cargs[0]= args[0];
cargs[1]= args[2];
if (agg_arg_charsets(collation, cargs, 2, MY_COLL_ALLOW_CONV))
@@ -2074,18 +2074,20 @@ void Item_func_rpad::fix_length_and_dec()
args[2]= cargs[1];
if (args[1]->const_item())
{
- uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen;
- max_length=max(args[0]->max_length,length);
- if (max_length >= MAX_BLOB_WIDTH)
+ ulonglong length= ((ulonglong) args[1]->val_int() *
+ collation.collation->mbmaxlen);
+ length= max((ulonglong) args[0]->max_length, length);
+ if (length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) length;
}
else
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
}
@@ -2160,18 +2162,20 @@ void Item_func_lpad::fix_length_and_dec()
if (args[1]->const_item())
{
- uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen;
- max_length=max(args[0]->max_length,length);
- if (max_length >= MAX_BLOB_WIDTH)
+ ulonglong length= ((ulonglong) args[1]->val_int() *
+ collation.collation->mbmaxlen);
+ length= max((ulonglong) args[0]->max_length, length);
+ if (length >= MAX_BLOB_WIDTH)
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
+ max_length= (ulong) length;
}
else
{
- max_length=MAX_BLOB_WIDTH;
- maybe_null=1;
+ max_length= MAX_BLOB_WIDTH;
+ maybe_null= 1;
}
}
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index cac9613f1ad..aa377d0bdd8 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -1555,7 +1555,7 @@ void Item_func_date_format::fix_length_and_dec()
{
fixed_length=0;
/* The result is a binary string (no reason to use collation->mbmaxlen */
- max_length=args[1]->max_length*10;
+ max_length=min(args[1]->max_length,MAX_BLOB_WIDTH) * 10;
set_if_smaller(max_length,MAX_BLOB_WIDTH);
}
maybe_null=1; // If wrong date
@@ -2524,7 +2524,7 @@ void Item_func_add_time::print(String *str)
}
args[0]->print(str);
str->append(',');
- args[0]->print(str);
+ args[1]->print(str);
str->append(')');
}
diff --git a/sql/lex.h b/sql/lex.h
index aa10328ced0..122e7040c80 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -497,6 +497,7 @@ static SYMBOL symbols[] = {
{ "TRAILING", SYM(TRAILING)},
{ "TRANSACTION", SYM(TRANSACTION_SYM)},
{ "TRIGGER", SYM(TRIGGER_SYM)},
+ { "TRIGGERS", SYM(TRIGGERS_SYM)},
{ "TRUE", SYM(TRUE_SYM)},
{ "TRUNCATE", SYM(TRUNCATE_SYM)},
{ "TYPE", SYM(TYPE_SYM)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 7f3fe5ac5da..aa162a23b40 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -103,6 +103,10 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
{
MYSQL_LOCK *sql_lock;
TABLE *write_lock_used;
+ int rc;
+ /* Map the return value of thr_lock to an error from errmsg.txt */
+ const static int thr_lock_errno_to_mysql[]=
+ { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
DBUG_ENTER("mysql_lock_tables");
for (;;)
@@ -135,15 +139,24 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
{
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
- thd->proc_info=0;
break;
}
thd->proc_info="Table lock";
thd->locked=1;
- if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count))
+ rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks,
+ sql_lock->lock_count,
+ thd->lock_id)];
+ if (rc > 1) /* a timeout or a deadlock */
+ {
+ my_error(rc, MYF(0));
+ my_free((gptr) sql_lock,MYF(0));
+ sql_lock= 0;
+ break;
+ }
+ else if (rc == 1) /* aborted */
{
thd->some_tables_deleted=1; // Try again
- sql_lock->lock_count=0; // Locks are alread freed
+ sql_lock->lock_count= 0; // Locks are already freed
}
else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
{
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 0873ee50743..bdf17ba20e3 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,15 +1,15 @@
/* Copyright (C) 2000-2004 MySQL AB
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
@@ -242,7 +242,7 @@ static void print_set_option(FILE* file, uint32 bits_changed, uint32 option,
{
if (*need_comma)
fprintf(file,", ");
- fprintf(file,"%s=%d", name, (bool)(flags & option));
+ fprintf(file,"%s=%d", name, test(flags & option));
*need_comma= 1;
}
}
@@ -2774,6 +2774,16 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
*/
handle_dup= DUP_ERROR;
}
+ /*
+ We need to set thd->lex->sql_command and thd->lex->duplicates
+ since InnoDB tests these variables to decide if this is a LOAD
+ DATA ... REPLACE INTO ... statement even though mysql_parse()
+ is not called. This is not needed in 5.0 since there the LOAD
+ DATA ... statement is replicated using mysql_parse(), which
+ sets the thd->lex fields correctly.
+ */
+ thd->lex->sql_command= SQLCOM_LOAD;
+ thd->lex->duplicates= handle_dup;
sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 49eb50be580..7bd8d76f25d 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -791,9 +791,7 @@ extern char *des_key_file;
extern struct st_des_keyschedule des_keyschedule[10];
extern uint des_default_key;
extern pthread_mutex_t LOCK_des_key_file;
-void init_des_key_file();
bool load_des_key_file(const char *file_name);
-void free_des_key_file();
#endif /* HAVE_OPENSSL */
/* sql_do.cc */
@@ -1082,6 +1080,7 @@ extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond;
extern const char * const triggers_file_ext;
+extern const char * const trigname_file_ext;
extern Eq_creator eq_creator;
extern Ne_creator ne_creator;
extern Gt_creator gt_creator;
@@ -1156,8 +1155,11 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
- LOCK_global_system_variables, LOCK_user_conn,
+ LOCK_global_system_variables, LOCK_user_conn,
LOCK_bytes_sent, LOCK_bytes_received;
+#ifdef HAVE_OPENSSL
+extern pthread_mutex_t LOCK_des_key_file;
+#endif
extern rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_attr_t connection_attrib;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 7c8b2b781e4..798bd25fa7c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -447,6 +447,9 @@ pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
+#ifdef HAVE_OPENSSL
+pthread_mutex_t LOCK_des_key_file;
+#endif
rw_lock_t LOCK_grant, LOCK_sys_init_connect, LOCK_sys_init_slave;
pthread_cond_t COND_refresh,COND_thread_count;
pthread_t signal_thread;
@@ -675,7 +678,11 @@ static void close_connections(void)
end_thr_alarm(0); // Abort old alarms.
end_slave();
- /* First signal all threads that it's time to die */
+ /*
+ First signal all threads that it's time to die
+ This will give the threads some time to gracefully abort their
+ statements and inform their clients that the server is about to die.
+ */
THD *tmp;
(void) pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
@@ -685,13 +692,7 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
- /*
- Re: bug 7403 - close_connection will be called mulitple times
- a wholesale clean up of our network code is a very large project.
- This will wake up the socket on Windows and prevent the printing of
- the error message that we are force closing a connection.
- */
- close_connection(tmp, 0, 0);
+ tmp->killed= THD::KILL_CONNECTION;
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -708,9 +709,13 @@ static void close_connections(void)
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
if (thread_count)
- sleep(1); // Give threads time to die
+ sleep(2); // Give threads time to die
- /* Force remaining threads to die by closing the connection to the client */
+ /*
+ Force remaining threads to die by closing the connection to the client
+ This will ensure that threads that are waiting for a command from the
+ client on a blocking read call are aborted.
+ */
for (;;)
{
@@ -725,8 +730,9 @@ static void close_connections(void)
#ifndef __bsdi__ // Bug in BSDI kernel
if (tmp->vio_ok())
{
- sql_print_error(ER(ER_FORCING_CLOSE),my_progname,
- tmp->thread_id,tmp->user ? tmp->user : "");
+ if (global_system_variables.log_warnings)
+ sql_print_warning(ER(ER_FORCING_CLOSE),my_progname,
+ tmp->thread_id,tmp->user ? tmp->user : "");
close_connection(tmp,0,0);
}
#endif
@@ -1042,7 +1048,6 @@ void clean_up(bool print_message)
#ifdef HAVE_OPENSSL
if (ssl_acceptor_fd)
my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
- free_des_key_file();
#endif /* HAVE_OPENSSL */
#ifdef USE_REGEX
regex_end();
@@ -1114,6 +1119,9 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
+#ifdef HAVE_OPENSSL
+ (void) pthread_mutex_destroy(&LOCK_des_key_file);
+#endif
#ifdef HAVE_REPLICATION
(void) pthread_mutex_destroy(&LOCK_rpl_status);
(void) pthread_cond_destroy(&COND_rpl_status);
@@ -2617,6 +2625,9 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_read_lock, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_uuid_generator, MY_MUTEX_INIT_FAST);
+#ifdef HAVE_OPENSSL
+ (void) pthread_mutex_init(&LOCK_des_key_file,MY_MUTEX_INIT_FAST);
+#endif
(void) my_rwlock_init(&LOCK_sys_init_connect, NULL);
(void) my_rwlock_init(&LOCK_sys_init_slave, NULL);
(void) my_rwlock_init(&LOCK_grant, NULL);
@@ -4342,7 +4353,8 @@ enum options_mysqld
OPT_ENABLE_LARGE_PAGES,
OPT_TIMED_MUTEXES,
OPT_OLD_STYLE_USER_LIMITS,
- OPT_LOG_SLOW_ADMIN_STATEMENTS
+ OPT_LOG_SLOW_ADMIN_STATEMENTS,
+ OPT_TABLE_LOCK_WAIT_TIMEOUT
};
@@ -5595,6 +5607,11 @@ The minimum value for this variable is 4096.",
"The number of open tables for all threads.", (gptr*) &table_cache_size,
(gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L,
0, 1, 0},
+ {"table_lock_wait_timeout", OPT_TABLE_LOCK_WAIT_TIMEOUT, "Timeout in "
+ "seconds to wait for a table level lock before returning an error. Used"
+ " only if the connection has active cursors.",
+ (gptr*) &table_lock_wait_timeout, (gptr*) &table_lock_wait_timeout,
+ 0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0},
{"thread_cache_size", OPT_THREAD_CACHE_SIZE,
"How many threads we should keep in a cache for reuse.",
(gptr*) &thread_cache_size, (gptr*) &thread_cache_size, 0, GET_ULONG,
@@ -5728,6 +5745,7 @@ struct show_var_st status_vars[]= {
{"Com_show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
{"Com_show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
{"Com_show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
+ {"Com_show_triggers", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TRIGGERS]), SHOW_LONG_STATUS},
{"Com_show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
{"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
{"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
@@ -7083,4 +7101,6 @@ template class I_List_iterator<THD>;
template class I_List<i_string>;
template class I_List<i_string_pair>;
template class I_List<NAMED_LIST>;
+template class I_List<Statement>;
+template class I_List_iterator<Statement>;
#endif
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 2d7c3364e41..09581aed217 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -375,6 +375,8 @@ sys_var_thd_ulong sys_sync_replication_timeout(
sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm);
sys_var_long_ptr sys_table_cache_size("table_cache",
&table_cache_size);
+sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout",
+ &table_lock_wait_timeout);
sys_var_long_ptr sys_thread_cache_size("thread_cache_size",
&thread_cache_size);
sys_var_thd_enum sys_tx_isolation("tx_isolation",
@@ -682,6 +684,7 @@ sys_var *sys_variables[]=
#endif
&sys_sync_frm,
&sys_table_cache_size,
+ &sys_table_lock_wait_timeout,
&sys_table_type,
&sys_thread_cache_size,
&sys_time_format,
@@ -972,6 +975,7 @@ struct show_var_st init_vars[]= {
{"system_time_zone", system_time_zone, SHOW_CHAR},
#endif
{"table_cache", (char*) &table_cache_size, SHOW_LONG},
+ {"table_lock_wait_timeout", (char*) &table_lock_wait_timeout, SHOW_LONG },
{sys_table_type.name, (char*) &sys_table_type, SHOW_SYS},
{sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS},
#ifdef HAVE_THR_SETCONCURRENCY
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 489b5ef2fdc..4953004cc24 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5382,3 +5382,5 @@ ER_FOREIGN_DATA_STRING_INVALID
eng "The data source connection string '%-.64s' is not in the correct format"
ER_CANT_CREATE_FEDERATED_TABLE
eng "Can't create federated table. Foreign data src error : '%-.64s'"
+ER_TRG_IN_WRONG_SCHEMA
+ eng "Trigger in wrong schema"
diff --git a/sql/sp.cc b/sql/sp.cc
index 55087f47f5e..a277c6bd253 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1442,8 +1442,8 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{
Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next;
- for (int i= 0; i < 3; i++)
- for (int j= 0; j < 2; j++)
+ for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
+ for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
if (triggers->bodies[i][j])
{
(void)triggers->bodies[i][j]->add_used_tables_to_table_list(thd,
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7021f61a052..576f5a503f0 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1740,7 +1740,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
!my_strcasecmp(system_charset_info, name, "proc"))
entry->s->system_table= 1;
- if (Table_triggers_list::check_n_load(thd, db, name, entry))
+ if (Table_triggers_list::check_n_load(thd, db, name, entry, 0))
goto err;
/*
diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h
index bc1484b4fb0..0f5b6dcd35e 100644
--- a/sql/sql_bitmap.h
+++ b/sql/sql_bitmap.h
@@ -51,6 +51,14 @@ public:
bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0);
bitmap_intersect(&map, &map2);
}
+ /* Use highest bit for all bits above sizeof(ulonglong)*8. */
+ void intersect_extended(ulonglong map2buff)
+ {
+ intersect(map2buff);
+ if (map.bitmap_size > sizeof(ulonglong))
+ bitmap_set_above(&map, sizeof(ulonglong),
+ test(map2buff & (LL(1) << (sizeof(ulonglong) * 8 - 1))));
+ }
void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); }
void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); }
my_bool is_set(uint n) const { return bitmap_is_set(&map, n); }
@@ -116,6 +124,7 @@ public:
void clear_all() { map=(ulonglong)0; }
void intersect(Bitmap<64>& map2) { map&= map2.map; }
void intersect(ulonglong map2) { map&= map2; }
+ void intersect_extended(ulonglong map2) { map&= map2; }
void subtract(Bitmap<64>& map2) { map&= ~map2.map; }
void merge(Bitmap<64>& map2) { map|= map2.map; }
my_bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); }
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d0ac1a16f6b..89d5b543dfc 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -173,6 +173,7 @@ Open_tables_state::Open_tables_state()
THD::THD()
:Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
Open_tables_state(),
+ lock_id(&main_lock_id),
user_time(0), global_read_lock(0), is_fatal_error(0),
rand_used(0), time_zone_used(0),
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
@@ -265,6 +266,8 @@ THD::THD()
tablespace_op=FALSE;
ulong tmp=sql_rnd_with_mutex();
randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
+ thr_lock_info_init(&lock_info); /* safety: will be reset after start */
+ thr_lock_owner_init(&main_lock_id, &lock_info);
}
@@ -406,6 +409,8 @@ THD::~THD()
net_end(&net);
}
#endif
+ stmt_map.destroy(); /* close all prepared statements */
+ DBUG_ASSERT(lock_info.n_cursors == 0);
if (!cleanup_done)
cleanup();
@@ -518,6 +523,7 @@ bool THD::store_globals()
if this is the slave SQL thread.
*/
variables.pseudo_thread_id= thread_id;
+ thr_lock_info_init(&lock_info);
return 0;
}
@@ -1563,6 +1569,12 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup)
}
+void Statement::close_cursor()
+{
+ DBUG_ASSERT("Statement::close_cursor()" == "not implemented");
+}
+
+
void THD::end_statement()
{
/* Cleanup SQL processing state to resuse this statement in next query. */
@@ -1683,6 +1695,14 @@ int Statement_map::insert(Statement *statement)
}
+void Statement_map::close_transient_cursors()
+{
+ Statement *stmt;
+ while ((stmt= transient_cursor_list.head()))
+ stmt->close_cursor(); /* deletes itself from the list */
+}
+
+
bool select_dumpvar::send_data(List<Item> &items)
{
List_iterator_fast<Item_func_set_user_var> li(vars);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 6c4315b95fa..d6847f5fb35 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -756,7 +756,7 @@ class Cursor;
be used explicitly.
*/
-class Statement: public Query_arena
+class Statement: public ilink, public Query_arena
{
Statement(const Statement &rhs); /* not implemented: */
Statement &operator=(const Statement &rhs); /* non-copyable */
@@ -833,6 +833,8 @@ public:
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
virtual Type type() const;
+ /* Close the cursor open for this statement, if there is one */
+ virtual void close_cursor();
};
@@ -884,15 +886,25 @@ public:
}
hash_delete(&st_hash, (byte *) statement);
}
+ void add_transient_cursor(Statement *stmt)
+ { transient_cursor_list.append(stmt); }
+ void erase_transient_cursor(Statement *stmt) { stmt->unlink(); }
+ /*
+ Close all cursors of this connection that use tables of a storage
+ engine that has transaction-specific state and therefore can not
+ survive COMMIT or ROLLBACK. Currently all but MyISAM cursors are closed.
+ */
+ void close_transient_cursors();
/* Erase all statements (calls Statement destructor) */
void reset()
{
my_hash_reset(&names_hash);
my_hash_reset(&st_hash);
+ transient_cursor_list.empty();
last_found_statement= 0;
}
- ~Statement_map()
+ void destroy()
{
hash_free(&names_hash);
hash_free(&st_hash);
@@ -900,6 +912,7 @@ public:
private:
HASH st_hash;
HASH names_hash;
+ I_List<Statement> transient_cursor_list;
Statement *last_found_statement;
};
@@ -1017,8 +1030,7 @@ public:
a thread/connection descriptor
*/
-class THD :public ilink,
- public Statement,
+class THD :public Statement,
public Open_tables_state
{
public:
@@ -1044,6 +1056,10 @@ public:
struct rand_struct rand; // used for authentication
struct system_variables variables; // Changeable local variables
struct system_status_var status_var; // Per thread statistic vars
+ THR_LOCK_INFO lock_info; // Locking info of this thread
+ THR_LOCK_OWNER main_lock_id; // To use for conventional queries
+ THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to
+ // the lock_id of a cursor.
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 45c8182a29c..4bba0c432c7 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -57,6 +57,7 @@ enum enum_sql_command {
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
+ SQLCOM_SHOW_TRIGGERS,
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
SQLCOM_GRANT,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d8c7507fd35..23403e6e00a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -775,29 +775,19 @@ static int check_connection(THD *thd)
return (ER_OUT_OF_RESOURCES);
thd->host_or_ip= thd->ip;
vio_in_addr(net->vio,&thd->remote.sin_addr);
-#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
- /* Fast local hostname resolve for Win32 */
- if (!strcmp(thd->ip,"127.0.0.1"))
+ if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- thd->host= (char*) my_localhost;
- thd->host_or_ip= my_localhost;
- }
- else
-#endif
- {
- if (!(specialflag & SPECIAL_NO_RESOLVE))
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
+ /* Cut very long hostnames to avoid possible overflows */
+ if (thd->host)
{
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
- /* Cut very long hostnames to avoid possible overflows */
- if (thd->host)
- {
- thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
- thd->host_or_ip= thd->host;
- }
- if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
+ if (thd->host != my_localhost)
+ thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
+ thd->host_or_ip= thd->host;
}
+ if (connect_errors > max_connect_errors)
+ return(ER_HOST_IS_BLOCKED);
}
DBUG_PRINT("info",("Host: %s ip: %s",
thd->host ? thd->host : "unknown host",
@@ -2104,6 +2094,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
case SCH_TABLE_NAMES:
case SCH_TABLES:
case SCH_VIEWS:
+ case SCH_TRIGGERS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
@@ -2386,10 +2377,12 @@ mysql_execute_command(THD *thd)
select_result *result=lex->result;
if (all_tables)
{
- res= check_table_access(thd,
- lex->exchange ? SELECT_ACL | FILE_ACL :
- SELECT_ACL,
- all_tables, 0);
+ if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC &&
+ lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC)
+ res= check_table_access(thd,
+ lex->exchange ? SELECT_ACL | FILE_ACL :
+ SELECT_ACL,
+ all_tables, 0);
}
else
res= check_access(thd,
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index aa47b506f73..cec432a86be 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -319,7 +319,7 @@ static void set_param_float(Item_param *param, uchar **pos, ulong len)
return;
float4get(data,*pos);
#else
- data= *(float*) *pos;
+ floatget(data, *pos);
#endif
param->set_double((double) data);
*pos+= 4;
@@ -333,7 +333,7 @@ static void set_param_double(Item_param *param, uchar **pos, ulong len)
return;
float8get(data,*pos);
#else
- data= *(double*) *pos;
+ doubleget(data, *pos);
#endif
param->set_double((double) data);
*pos+= 8;
@@ -601,10 +601,8 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *null_array,
Item_param **begin= stmt->param_array;
Item_param **end= begin + stmt->param_count;
uint32 length= 0;
-
String str;
const String *res;
-
DBUG_ENTER("insert_params_withlog");
if (query->copy(stmt->query, stmt->query_length, default_charset_info))
@@ -2020,6 +2018,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
DBUG_VOID_RETURN;
/* If lex->result is set, mysql_execute_command will use it */
stmt->lex->result= &cursor->result;
+ thd->lock_id= &cursor->lock_id;
}
}
#ifndef EMBEDDED_LIBRARY
@@ -2069,6 +2068,9 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
Cursor::open is buried deep in JOIN::exec of the top level join.
*/
cursor->init_from_thd(thd);
+
+ if (cursor->close_at_commit)
+ thd->stmt_map.add_transient_cursor(stmt);
}
else
{
@@ -2078,6 +2080,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
}
thd->set_statement(&stmt_backup);
+ thd->lock_id= &thd->main_lock_id;
thd->current_arena= thd;
DBUG_VOID_RETURN;
@@ -2252,6 +2255,8 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
the previous calls.
*/
free_root(cursor->mem_root, MYF(0));
+ if (cursor->close_at_commit)
+ thd->stmt_map.erase_transient_cursor(stmt);
}
thd->restore_backup_statement(stmt, &stmt_backup);
@@ -2291,14 +2296,6 @@ void mysql_stmt_reset(THD *thd, char *packet)
DBUG_VOID_RETURN;
stmt->close_cursor(); /* will reset statement params */
- cursor= stmt->cursor;
- if (cursor && cursor->is_open())
- {
- thd->change_list= cursor->change_list;
- cursor->close(FALSE);
- cleanup_stmt_and_thd_after_use(stmt, thd);
- free_root(cursor->mem_root, MYF(0));
- }
stmt->state= Query_arena::PREPARED;
@@ -2478,6 +2475,8 @@ void Prepared_statement::close_cursor()
cursor->close(FALSE);
cleanup_stmt_and_thd_after_use(this, thd);
free_root(cursor->mem_root, MYF(0));
+ if (cursor->close_at_commit)
+ thd->stmt_map.erase_transient_cursor(this);
}
/*
Clear parameters from data which could be set by
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b333e369dc4..f757ccaef8e 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1207,14 +1207,18 @@ JOIN::exec()
else
{
error= (int) result->send_eof();
- send_records=1;
+ send_records= ((select_options & OPTION_FOUND_ROWS) ? 1 :
+ thd->sent_row_count);
}
}
else
+ {
error=(int) result->send_eof();
+ send_records= 0;
+ }
}
- /* Single select (without union and limit) always returns 1 row */
- thd->limit_found_rows= 1;
+ /* Single select (without union) always returns 0 or 1 row */
+ thd->limit_found_rows= send_records;
thd->examined_row_count= 0;
DBUG_VOID_RETURN;
}
@@ -1702,10 +1706,12 @@ JOIN::destroy()
Cursor::Cursor(THD *thd)
:Query_arena(&main_mem_root, INITIALIZED),
- join(0), unit(0)
+ join(0), unit(0),
+ close_at_commit(FALSE)
{
/* We will overwrite it at open anyway. */
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ thr_lock_owner_init(&lock_id, &thd->lock_info);
}
@@ -1739,6 +1745,21 @@ Cursor::init_from_thd(THD *thd)
free_list= thd->free_list;
change_list= thd->change_list;
reset_thd(thd);
+ /* Now we have an active cursor and can cause a deadlock */
+ thd->lock_info.n_cursors++;
+
+ close_at_commit= FALSE; /* reset in case we're reusing the cursor */
+ for (TABLE *table= open_tables; table; table= table->next)
+ {
+ const handlerton *ht= table->file->ht;
+ if (ht)
+ close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
+ else
+ {
+ close_at_commit= TRUE; /* handler status is unknown */
+ break;
+ }
+ }
/*
XXX: thd->locked_tables is not changed.
What problems can we have with it if cursor is open?
@@ -1907,6 +1928,7 @@ Cursor::close(bool is_active)
thd->derived_tables= tmp_derived_tables;
thd->lock= tmp_lock;
}
+ thd->lock_info.n_cursors--; /* Decrease the number of active cursors */
join= 0;
unit= 0;
free_items();
@@ -5182,6 +5204,7 @@ static void add_not_null_conds(JOIN *join)
if (tab->ref.null_rejecting & (1 << keypart))
{
Item *item= tab->ref.items[keypart];
+ Item *notnull;
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
Item_field *not_null_item= (Item_field*)item;
JOIN_TAB *referred_tab= not_null_item->field->table->reginfo.join_tab;
@@ -5192,7 +5215,6 @@ static void add_not_null_conds(JOIN *join)
*/
if (!referred_tab || referred_tab->join != join)
continue;
- Item *notnull;
if (!(notnull= new Item_func_isnotnull(not_null_item)))
DBUG_VOID_RETURN;
/*
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 9285e33be33..7f6d661a4de 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -392,6 +392,8 @@ class Cursor: public Sql_alloc, public Query_arena
public:
Item_change_list change_list;
select_send result;
+ THR_LOCK_OWNER lock_id;
+ my_bool close_at_commit;
/* Temporary implementation as now we replace THD state by value */
/* Save THD state into cursor */
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 1608999eaef..6989eacf334 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -21,6 +21,7 @@
#include "sql_select.h" // For select_describe
#include "repl_failsafe.h"
#include "sp_head.h"
+#include "sql_trigger.h"
#include <my_dir.h>
#ifdef HAVE_BERKELEY_DB
@@ -1696,6 +1697,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values)
break;
case SQLCOM_SHOW_TABLES:
case SQLCOM_SHOW_TABLE_STATUS:
+ case SQLCOM_SHOW_TRIGGERS:
index_field_values->db_value= lex->current_select->db;
index_field_values->table_value= wild;
break;
@@ -2377,6 +2379,7 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
{
const char *tmp_buff;
byte *pos;
+ bool is_blob;
uint flags=field->flags;
char tmp[MAX_FIELD_WIDTH];
char tmp1[MAX_FIELD_WIDTH];
@@ -2455,12 +2458,14 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
"NO" : "YES");
table->field[6]->store((const char*) pos,
strlen((const char*) pos), cs);
- if (field->has_charset())
+ is_blob= (field->type() == FIELD_TYPE_BLOB);
+ if (field->has_charset() || is_blob)
{
- table->field[8]->store((longlong) field->field_length/
- field->charset()->mbmaxlen);
+ longlong c_octet_len= is_blob ? (longlong) field->max_length() :
+ (longlong) field->max_length()/field->charset()->mbmaxlen;
+ table->field[8]->store(c_octet_len);
table->field[8]->set_notnull();
- table->field[9]->store((longlong) field->field_length);
+ table->field[9]->store((longlong) field->max_length());
table->field[9]->set_notnull();
}
@@ -2488,6 +2493,17 @@ static int get_schema_column_record(THD *thd, struct st_table_list *tables,
case FIELD_TYPE_LONG:
case FIELD_TYPE_LONGLONG:
case FIELD_TYPE_INT24:
+ {
+ table->field[10]->store((longlong) field->max_length() - 1);
+ table->field[10]->set_notnull();
+ break;
+ }
+ case FIELD_TYPE_BIT:
+ {
+ table->field[10]->store((longlong) field->max_length());
+ table->field[10]->set_notnull();
+ break;
+ }
case FIELD_TYPE_FLOAT:
case FIELD_TYPE_DOUBLE:
{
@@ -2963,6 +2979,73 @@ static int get_schema_constraints_record(THD *thd, struct st_table_list *tables,
}
+static bool store_trigger(THD *thd, TABLE *table, const char *db,
+ const char *tname, LEX_STRING *trigger_name,
+ enum trg_event_type event,
+ enum trg_action_time_type timing,
+ LEX_STRING *trigger_stmt)
+{
+ CHARSET_INFO *cs= system_charset_info;
+ restore_record(table, s->default_values);
+ table->field[1]->store(db, strlen(db), cs);
+ table->field[2]->store(trigger_name->str, trigger_name->length, cs);
+ table->field[3]->store(trg_event_type_names[event].str,
+ trg_event_type_names[event].length, cs);
+ table->field[5]->store(db, strlen(db), cs);
+ table->field[6]->store(tname, strlen(tname), cs);
+ table->field[9]->store(trigger_stmt->str, trigger_stmt->length, cs);
+ table->field[10]->store("ROW", 3, cs);
+ table->field[11]->store(trg_action_time_type_names[timing].str,
+ trg_action_time_type_names[timing].length, cs);
+ table->field[14]->store("OLD", 3, cs);
+ table->field[15]->store("NEW", 3, cs);
+ return schema_table_store_record(thd, table);
+}
+
+
+static int get_schema_triggers_record(THD *thd, struct st_table_list *tables,
+ TABLE *table, bool res,
+ const char *base_name,
+ const char *file_name)
+{
+ DBUG_ENTER("get_schema_triggers_record");
+ /*
+ res can be non zero value when processed table is a view or
+ error happened during opening of processed table.
+ */
+ if (res)
+ {
+ if (!tables->view)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ thd->net.last_errno, thd->net.last_error);
+ thd->clear_error();
+ DBUG_RETURN(0);
+ }
+ if (!tables->view && tables->table->triggers)
+ {
+ Table_triggers_list *triggers= tables->table->triggers;
+ int event, timing;
+ for (event= 0; event < (int)TRG_EVENT_MAX; event++)
+ {
+ for (timing= 0; timing < (int)TRG_ACTION_MAX; timing++)
+ {
+ LEX_STRING trigger_name;
+ LEX_STRING trigger_stmt;
+ if (triggers->get_trigger_info(thd, (enum trg_event_type) event,
+ (enum trg_action_time_type)timing,
+ &trigger_name, &trigger_stmt))
+ continue;
+ if (store_trigger(thd, table, base_name, file_name, &trigger_name,
+ (enum trg_event_type) event,
+ (enum trg_action_time_type) timing, &trigger_stmt))
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+
void store_key_column_usage(TABLE *table, const char*db, const char *tname,
const char *key_name, uint key_len,
const char *con_type, uint con_len, longlong idx)
@@ -3847,6 +3930,29 @@ ST_FIELD_INFO open_tables_fields_info[]=
};
+ST_FIELD_INFO triggers_fields_info[]=
+{
+ {"TRIGGER_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"TRIGGER_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"TRIGGER_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Trigger"},
+ {"EVENT_MANIPULATION", 6, MYSQL_TYPE_STRING, 0, 0, "Event"},
+ {"EVENT_OBJECT_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"EVENT_OBJECT_SCHEMA",NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"EVENT_OBJECT_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Table"},
+ {"ACTION_ORDER", 4, MYSQL_TYPE_LONG, 0, 0, 0},
+ {"ACTION_CONDITION", 65535, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ACTION_STATEMENT", 65535, MYSQL_TYPE_STRING, 0, 0, "Statement"},
+ {"ACTION_ORIENTATION", 9, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ACTION_TIMING", 6, MYSQL_TYPE_STRING, 0, 0, "Timing"},
+ {"ACTION_REFERENCE_OLD_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ACTION_REFERENCE_NEW_TABLE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0},
+ {"ACTION_REFERENCE_OLD_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"ACTION_REFERENCE_NEW_ROW", 3, MYSQL_TYPE_STRING, 0, 0, 0},
+ {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Created"},
+ {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
+};
+
+
ST_FIELD_INFO variables_fields_info[]=
{
{"Variable_name", 80, MYSQL_TYPE_STRING, 0, 0, "Variable_name"},
@@ -3897,6 +4003,8 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_open_tables, make_old_format, 0, -1, -1, 1},
{"STATUS", variables_fields_info, create_schema_table, fill_status,
make_old_format, 0, -1, -1, 1},
+ {"TRIGGERS", triggers_fields_info, create_schema_table,
+ get_all_tables, make_old_format, get_schema_triggers_record, 5, 6, 0},
{"VARIABLES", variables_fields_info, create_schema_table, fill_variables,
make_old_format, 0, -1, -1, 1},
{0, 0, 0, 0, 0, 0, 0, 0, 0}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 89282d9fcb9..e3f85f05c17 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -23,6 +23,8 @@
#include <hash.h>
#include <myisam.h>
#include <my_dir.h>
+#include "sp_head.h"
+#include "sql_trigger.h"
#ifdef __WIN__
#include <io.h>
@@ -290,16 +292,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (!(new_error=my_delete(path,MYF(MY_WME))))
{
some_tables_deleted=1;
- /*
- Destroy triggers for this table if there are any.
-
- We won't need this as soon as we will have new .FRM format,
- in which we will store trigger definitions in the same .FRM
- files as table descriptions.
- */
- strmov(end, triggers_file_ext);
- if (!access(path, F_OK))
- new_error= my_delete(path, MYF(MY_WME));
+ new_error= Table_triggers_list::drop_all_triggers(thd, db,
+ table->table_name);
}
error|= new_error;
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index fd79fc8b878..a7aee95197e 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -39,6 +39,45 @@ static File_option triggers_file_parameters[]=
/*
+ Structure representing contents of .TRN file which are used to support
+ database wide trigger namespace.
+*/
+
+struct st_trigname
+{
+ LEX_STRING trigger_table;
+};
+
+static const LEX_STRING trigname_file_type= {(char *)"TRIGGERNAME", 11};
+
+const char * const trigname_file_ext= ".TRN";
+
+static File_option trigname_file_parameters[]=
+{
+ {{(char*)"trigger_table", 15}, offsetof(struct st_trigname, trigger_table),
+ FILE_OPTIONS_ESTRING},
+ {{0, 0}, 0, FILE_OPTIONS_STRING}
+};
+
+
+const LEX_STRING trg_action_time_type_names[]=
+{
+ { (char *) STRING_WITH_LEN("BEFORE") },
+ { (char *) STRING_WITH_LEN("AFTER") }
+};
+
+const LEX_STRING trg_event_type_names[]=
+{
+ { (char *) STRING_WITH_LEN("INSERT") },
+ { (char *) STRING_WITH_LEN("UPDATE") },
+ { (char *) STRING_WITH_LEN("DELETE") }
+};
+
+
+static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig);
+
+
+/*
Create or drop trigger for table.
SYNOPSIS
@@ -69,6 +108,10 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
But do we want this ?
*/
+ if (!create &&
+ !(tables= add_table_for_trigger(thd, thd->lex->spname)))
+ DBUG_RETURN(TRUE);
+
/* We should have only one table in table list. */
DBUG_ASSERT(tables->next_global == 0);
@@ -174,28 +217,28 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
- char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
- LEX_STRING dir, file;
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN], trigname_buff[FN_REFLEN],
+ trigname_path[FN_REFLEN];
+ LEX_STRING dir, file, trigname_file;
LEX_STRING *trg_def, *name;
Item_trigger_field *trg_field;
- List_iterator_fast<LEX_STRING> it(names_list);
+ struct st_trigname trigname;
- /* We don't allow creation of several triggers of the same type yet */
- if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
+
+ /* Trigger must be in the same schema as target table. */
+ if (my_strcasecmp(system_charset_info, table->s->db,
+ lex->spname->m_db.str ? lex->spname->m_db.str :
+ thd->db))
{
- my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
+ my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0));
return 1;
}
- /* Let us check if trigger with the same name exists */
- while ((name= it++))
+ /* We don't allow creation of several triggers of the same type yet */
+ if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
{
- if (my_strcasecmp(system_charset_info, lex->ident.str,
- name->str) == 0)
- {
- my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
- return 1;
- }
+ my_message(ER_TRG_ALREADY_EXISTS, ER(ER_TRG_ALREADY_EXISTS), MYF(0));
+ return 1;
}
/*
@@ -234,6 +277,25 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
file.length= strxnmov(file_buff, FN_REFLEN, tables->table_name,
triggers_file_ext, NullS) - file_buff;
file.str= file_buff;
+ trigname_file.length= strxnmov(trigname_buff, FN_REFLEN,
+ lex->spname->m_name.str,
+ trigname_file_ext, NullS) - trigname_buff;
+ trigname_file.str= trigname_buff;
+ strxnmov(trigname_path, FN_REFLEN, dir_buff, trigname_buff, NullS);
+
+ /* Use the filesystem to enforce trigger namespace constraints. */
+ if (!access(trigname_path, F_OK))
+ {
+ my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
+ return 1;
+ }
+
+ trigname.trigger_table.str= tables->table_name;
+ trigname.trigger_table.length= tables->table_name_length;
+
+ if (sql_create_definition_file(&dir, &trigname_file, &trigname_file_type,
+ (gptr)&trigname, trigname_file_parameters, 0))
+ return 1;
/*
Soon we will invalidate table object and thus Table_triggers_list object
@@ -246,13 +308,66 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
sizeof(LEX_STRING))) ||
definitions_list.push_back(trg_def, &table->mem_root))
- return 1;
+ goto err_with_cleanup;
trg_def->str= thd->query;
trg_def->length= thd->query_length;
- return sql_create_definition_file(&dir, &file, &triggers_file_type,
- (gptr)this, triggers_file_parameters, 3);
+ if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
+ (gptr)this, triggers_file_parameters, 3))
+ return 0;
+
+err_with_cleanup:
+ my_delete(trigname_path, MYF(MY_WME));
+ return 1;
+}
+
+
+/*
+ Deletes the .TRG file for a table
+
+ SYNOPSIS
+ rm_trigger_file()
+ path - char buffer of size FN_REFLEN to be used
+ for constructing path to .TRG file.
+ db - table's database name
+ table_name - table's name
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+
+static bool rm_trigger_file(char *path, char *db, char *table_name)
+{
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
+ triggers_file_ext, NullS);
+ unpack_filename(path, path);
+ return my_delete(path, MYF(MY_WME));
+}
+
+
+/*
+ Deletes the .TRN file for a trigger
+
+ SYNOPSIS
+ rm_trigname_file()
+ path - char buffer of size FN_REFLEN to be used
+ for constructing path to .TRN file.
+ db - trigger's database name
+ table_name - trigger's name
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+
+static bool rm_trigname_file(char *path, char *db, char *trigger_name)
+{
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", db, "/", trigger_name,
+ trigname_file_ext, NullS);
+ unpack_filename(path, path);
+ return my_delete(path, MYF(MY_WME));
}
@@ -275,12 +390,13 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
LEX_STRING *name;
List_iterator_fast<LEX_STRING> it_name(names_list);
List_iterator<LEX_STRING> it_def(definitions_list);
+ char path[FN_REFLEN];
while ((name= it_name++))
{
it_def++;
- if (my_strcasecmp(system_charset_info, lex->ident.str,
+ if (my_strcasecmp(system_charset_info, lex->spname->m_name.str,
name->str) == 0)
{
/*
@@ -291,18 +407,14 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
if (definitions_list.is_empty())
{
- char path[FN_REFLEN];
-
/*
TODO: Probably instead of removing .TRG file we should move
to archive directory but this should be done as part of
parse_file.cc functionality (because we will need it
elsewhere).
*/
- strxnmov(path, FN_REFLEN, mysql_data_home, "/", tables->db, "/",
- tables->table_name, triggers_file_ext, NullS);
- unpack_filename(path, path);
- return my_delete(path, MYF(MY_WME));
+ if (rm_trigger_file(path, tables->db, tables->table_name))
+ return 1;
}
else
{
@@ -317,10 +429,15 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
triggers_file_ext, NullS) - file_buff;
file.str= file_buff;
- return sql_create_definition_file(&dir, &file, &triggers_file_type,
- (gptr)this,
- triggers_file_parameters, 3);
+ if (sql_create_definition_file(&dir, &file, &triggers_file_type,
+ (gptr)this, triggers_file_parameters,
+ 3))
+ return 1;
}
+
+ if (rm_trigname_file(path, tables->db, lex->spname->m_name.str))
+ return 1;
+ return 0;
}
}
@@ -331,8 +448,8 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
Table_triggers_list::~Table_triggers_list()
{
- for (int i= 0; i < 3; i++)
- for (int j= 0; j < 2; j++)
+ for (int i= 0; i < (int)TRG_EVENT_MAX; i++)
+ for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
delete bodies[i][j];
if (record1_field)
@@ -389,13 +506,16 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
db - table's database name
table_name - table's name
table - pointer to table object
+ names_only - stop after loading trigger names
RETURN VALUE
False - success
True - error
*/
+
bool Table_triggers_list::check_n_load(THD *thd, const char *db,
- const char *table_name, TABLE *table)
+ const char *table_name, TABLE *table,
+ bool names_only)
{
char path_buff[FN_REFLEN];
LEX_STRING path;
@@ -451,7 +571,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
TODO: This could be avoided if there is no triggers
for UPDATE and DELETE.
*/
- if (triggers->prepare_record1_accessors(table))
+ if (!names_only && triggers->prepare_record1_accessors(table))
DBUG_RETURN(1);
List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
@@ -471,32 +591,20 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
Free lex associated resources
QQ: Do we really need all this stuff here ?
*/
- if (lex.sphead)
- {
- delete lex.sphead;
- lex.sphead= 0;
- }
+ delete lex.sphead;
goto err_with_lex_cleanup;
}
triggers->bodies[lex.trg_chistics.event]
[lex.trg_chistics.action_time]= lex.sphead;
- lex.sphead= 0;
-
- if (!(trg_name_buff= alloc_root(&table->mem_root,
- sizeof(LEX_STRING) +
- lex.ident.length + 1)))
- goto err_with_lex_cleanup;
-
- trg_name_str= (LEX_STRING *)trg_name_buff;
- trg_name_buff+= sizeof(LEX_STRING);
- memcpy(trg_name_buff, lex.ident.str,
- lex.ident.length + 1);
- trg_name_str->str= trg_name_buff;
- trg_name_str->length= lex.ident.length;
+ if (triggers->names_list.push_back(&lex.sphead->m_name, &table->mem_root))
+ goto err_with_lex_cleanup;
- if (triggers->names_list.push_back(trg_name_str, &table->mem_root))
- goto err_with_lex_cleanup;
+ if (names_only)
+ {
+ lex_end(&lex);
+ continue;
+ }
/*
Let us bind Item_trigger_field objects representing access to fields
@@ -537,3 +645,160 @@ err_with_lex_cleanup:
DBUG_RETURN(1);
}
+
+
+/*
+ Obtains and returns trigger metadata
+
+ SYNOPSIS
+ get_trigger_info()
+ thd - current thread context
+ event - trigger event type
+ time_type - trigger action time
+ name - returns name of trigger
+ stmt - returns statement of trigger
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+
+bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
+ trg_action_time_type time_type,
+ LEX_STRING *trigger_name,
+ LEX_STRING *trigger_stmt)
+{
+ sp_head *body;
+ DBUG_ENTER("get_trigger_info");
+ if ((body= bodies[event][time_type]))
+ {
+ *trigger_name= body->m_name;
+ *trigger_stmt= body->m_body;
+ DBUG_RETURN(0);
+ }
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Find trigger's table from trigger identifier and add it to
+ the statement table list.
+
+ SYNOPSIS
+ mysql_table_for_trigger()
+ thd - current thread context
+ trig - identifier for trigger
+
+ RETURN VALUE
+ 0 - error
+ # - pointer to TABLE_LIST object for the table
+*/
+
+static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
+{
+ const char *db= !trig->m_db.str ? thd->db : trig->m_db.str;
+ LEX *lex= thd->lex;
+ char path_buff[FN_REFLEN];
+ LEX_STRING path;
+ File_parser *parser;
+ struct st_trigname trigname;
+ DBUG_ENTER("add_table_for_trigger");
+
+ strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/",
+ trig->m_name.str, trigname_file_ext, NullS);
+ path.length= unpack_filename(path_buff, path_buff);
+ path.str= path_buff;
+
+ if (access(path_buff, F_OK))
+ {
+ my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
+ DBUG_RETURN(0);
+ }
+
+ if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1)))
+ DBUG_RETURN(0);
+
+ if (strncmp(trigname_file_type.str, parser->type()->str,
+ parser->type()->length))
+ {
+ my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext,
+ "TRIGGERNAME");
+ DBUG_RETURN(0);
+ }
+
+ if (parser->parse((gptr)&trigname, thd->mem_root,
+ trigname_file_parameters, 1))
+ DBUG_RETURN(0);
+
+ /* We need to reset statement table list to be PS/SP friendly. */
+ lex->query_tables= 0;
+ lex->query_tables_last= &lex->query_tables;
+ DBUG_RETURN(sp_add_to_query_tables(thd, lex, db,
+ trigname.trigger_table.str, TL_WRITE));
+}
+
+
+/*
+ Drop all triggers for table.
+
+ SYNOPSIS
+ drop_all_triggers()
+ thd - current thread context
+ db - schema for table
+ name - name for table
+
+ NOTE
+ The calling thread should hold the LOCK_open mutex;
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+
+bool Table_triggers_list::drop_all_triggers(THD *thd, char *db, char *name)
+{
+ TABLE table;
+ char path[FN_REFLEN];
+ bool result= 0;
+ DBUG_ENTER("drop_all_triggers");
+
+ bzero(&table, sizeof(table));
+ init_alloc_root(&table.mem_root, 8192, 0);
+
+ safe_mutex_assert_owner(&LOCK_open);
+
+ if (Table_triggers_list::check_n_load(thd, db, name, &table, 1))
+ {
+ result= 1;
+ goto end;
+ }
+ if (table.triggers)
+ {
+ LEX_STRING *trigger;
+ List_iterator_fast<LEX_STRING> it_name(table.triggers->names_list);
+
+ while ((trigger= it_name++))
+ {
+ if (rm_trigname_file(path, db, trigger->str))
+ {
+ /*
+ Instead of immediately bailing out with error if we were unable
+ to remove .TRN file we will try to drop other files.
+ */
+ result= 1;
+ continue;
+ }
+ }
+
+ if (rm_trigger_file(path, db, name))
+ {
+ result= 1;
+ goto end;
+ }
+ }
+end:
+ if (table.triggers)
+ delete table.triggers;
+ free_root(&table.mem_root, MYF(0));
+ DBUG_RETURN(result);
+}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
index 044219d5ac9..e751741fa34 100644
--- a/sql/sql_trigger.h
+++ b/sql/sql_trigger.h
@@ -23,7 +23,7 @@
class Table_triggers_list: public Sql_alloc
{
/* Triggers as SPs grouped by event, action_time */
- sp_head *bodies[3][2];
+ sp_head *bodies[TRG_EVENT_MAX][TRG_ACTION_MAX];
/*
Copy of TABLE::Field array with field pointers set to TABLE::record[1]
buffer instead of TABLE::record[0] (used for OLD values in on UPDATE
@@ -121,9 +121,13 @@ public:
return res;
}
+ bool get_trigger_info(THD *thd, trg_event_type event,
+ trg_action_time_type time_type,
+ LEX_STRING *trigger_name, LEX_STRING *trigger_stmt);
static bool check_n_load(THD *thd, const char *db, const char *table_name,
- TABLE *table);
+ TABLE *table, bool names_only);
+ static bool drop_all_triggers(THD *thd, char *db, char *table_name);
bool has_delete_triggers()
{
@@ -143,3 +147,6 @@ public:
private:
bool prepare_record1_accessors(TABLE *table);
};
+
+extern const LEX_STRING trg_action_time_type_names[];
+extern const LEX_STRING trg_event_type_names[];
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f35a47bf397..b680787b9a3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -599,6 +599,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token TRAILING
%token TRANSACTION_SYM
%token TRIGGER_SYM
+%token TRIGGERS_SYM
%token TRIM
%token TRUE_SYM
%token TRUNCATE_SYM
@@ -1266,7 +1267,7 @@ create:
}
opt_view_list AS select_init check_option
{}
- | CREATE TRIGGER_SYM ident trg_action_time trg_event
+ | CREATE TRIGGER_SYM sp_name trg_action_time trg_event
ON table_ident FOR_SYM EACH_SYM ROW_SYM
{
LEX *lex= Lex;
@@ -1285,6 +1286,7 @@ create:
sp->m_type= TYPE_ENUM_TRIGGER;
lex->sphead= sp;
+ lex->spname= $3;
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
@@ -1295,7 +1297,7 @@ create:
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
- lex->sphead->m_body_begin= lex->tok_start;
+ lex->sphead->m_body_begin= lex->ptr;
}
sp_proc_stmt
{
@@ -1303,14 +1305,12 @@ create:
sp_head *sp= lex->sphead;
lex->sql_command= SQLCOM_CREATE_TRIGGER;
- sp->init_strings(YYTHD, lex, NULL);
+ sp->init_strings(YYTHD, lex, $3);
/* Restore flag if it was cleared above */
if (sp->m_old_cmq)
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
sp->restore_thd_mem_root(YYTHD);
- lex->ident= $3;
-
/*
We have to do it after parsing trigger body, because some of
sp_proc_stmt alternatives are not saving/restoring LEX, so
@@ -5919,19 +5919,11 @@ drop:
lex->sql_command= SQLCOM_DROP_VIEW;
lex->drop_if_exists= $3;
}
- | DROP TRIGGER_SYM ident '.' ident
+ | DROP TRIGGER_SYM sp_name
{
LEX *lex= Lex;
-
lex->sql_command= SQLCOM_DROP_TRIGGER;
- /* QQ: Could we loosen lock type in certain cases ? */
- if (!lex->select_lex.add_table_to_list(YYTHD,
- new Table_ident($3),
- (LEX_STRING*) 0,
- TL_OPTION_UPDATING,
- TL_WRITE))
- YYABORT;
- lex->ident= $5;
+ lex->spname= $3;
}
;
@@ -6296,6 +6288,15 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_TABLE_NAMES))
YYABORT;
}
+ | opt_full TRIGGERS_SYM opt_db wild_and_where
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->orig_sql_command= SQLCOM_SHOW_TRIGGERS;
+ lex->select_lex.db= $3;
+ if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS))
+ YYABORT;
+ }
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
@@ -7590,6 +7591,7 @@ keyword_sp:
| TEMPTABLE_SYM {}
| TEXT_SYM {}
| TRANSACTION_SYM {}
+ | TRIGGERS_SYM {}
| TIMESTAMP {}
| TIMESTAMP_ADD {}
| TIMESTAMP_DIFF {}
diff --git a/sql/table.h b/sql/table.h
index e5653a1f213..13d44766804 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -282,7 +282,7 @@ enum enum_schema_tables
SCH_COLLATION_CHARACTER_SET_APPLICABILITY, SCH_PROCEDURES, SCH_STATISTICS,
SCH_VIEWS, SCH_USER_PRIVILEGES, SCH_SCHEMA_PRIVILEGES, SCH_TABLE_PRIVILEGES,
SCH_COLUMN_PRIVILEGES, SCH_TABLE_CONSTRAINTS, SCH_KEY_COLUMN_USAGE,
- SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_VARIABLES
+ SCH_TABLE_NAMES, SCH_OPEN_TABLES, SCH_STATUS, SCH_TRIGGERS, SCH_VARIABLES
};