summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <pem@mysql.com>2003-08-26 11:51:09 +0200
committerunknown <pem@mysql.com>2003-08-26 11:51:09 +0200
commit138f0adf2d47c995b9e4aca96147c6afe59fdfa7 (patch)
tree64a6fa388e4aab5527ee4bc81489d6cfac07fcf0 /sql
parent3b799e8fd8eb13c7ad6e2bb01a922e37d9101ea7 (diff)
parent970f1abbdb9a67936b66fc96a0c6fa1f0aa1535c (diff)
downloadmariadb-git-138f0adf2d47c995b9e4aca96147c6afe59fdfa7.tar.gz
Merge 4.1 into 5.0
BitKeeper/etc/ignore: auto-union BitKeeper/etc/logging_ok: auto-union client/mysql.cc: Auto merged client/mysqltest.c: Auto merged configure.in: Auto merged include/my_global.h: Auto merged include/my_pthread.h: Auto merged include/mysql_com.h: Auto merged libmysql/libmysql.c: Auto merged libmysqld/Makefile.am: Auto merged myisam/mi_check.c: Auto merged myisam/myisamchk.c: Auto merged myisam/myisamdef.h: Auto merged mysql-test/r/insert.result: Auto merged mysql-test/r/variables.result: Auto merged mysql-test/t/insert.test: Auto merged mysql-test/t/variables.test: Auto merged mysys/my_pthread.c: Auto merged scripts/mysql_install_db.sh: Auto merged sql/Makefile.am: Auto merged sql/filesort.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_myisam.cc: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_create.cc: Auto merged sql/item_func.h: Auto merged sql/lex.h: Auto merged sql/log_event.cc: Auto merged sql/mysql_priv.h: Auto merged sql/protocol.cc: Auto merged sql/records.cc: Auto merged sql/repl_failsafe.cc: Auto merged sql/set_var.cc: Auto merged sql/slave.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_db.cc: Auto merged sql/sql_derived.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_load.cc: Auto merged sql/sql_rename.cc: Auto merged sql/sql_repl.cc: Auto merged sql/sql_repl.h: Auto merged sql/sql_select.cc: Auto merged sql/sql_show.cc: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/filesort.cc10
-rw-r--r--sql/ha_berkeley.cc2
-rw-r--r--sql/ha_innodb.cc4
-rw-r--r--sql/ha_myisam.cc8
-rw-r--r--sql/item.cc42
-rw-r--r--sql/item.h54
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/item_create.cc14
-rw-r--r--sql/item_func.cc80
-rw-r--r--sql/item_func.h66
-rw-r--r--sql/item_subselect.cc26
-rw-r--r--sql/item_sum.cc8
-rw-r--r--sql/lex.h23
-rw-r--r--sql/lock.cc2
-rw-r--r--sql/log.cc13
-rw-r--r--sql/log_event.cc2
-rw-r--r--sql/mysql_priv.h14
-rw-r--r--sql/mysqld.cc78
-rw-r--r--sql/protocol.cc2
-rw-r--r--sql/records.cc2
-rw-r--r--sql/repl_failsafe.cc2
-rw-r--r--sql/set_var.cc30
-rw-r--r--sql/share/czech/errmsg.txt16
-rw-r--r--sql/share/danish/errmsg.txt16
-rw-r--r--sql/share/dutch/errmsg.txt16
-rw-r--r--sql/share/english/errmsg.txt16
-rw-r--r--sql/share/estonian/errmsg.txt16
-rw-r--r--sql/share/french/errmsg.txt16
-rw-r--r--sql/share/german/errmsg.txt16
-rw-r--r--sql/share/greek/errmsg.txt16
-rw-r--r--sql/share/hungarian/errmsg.txt16
-rw-r--r--sql/share/italian/errmsg.txt16
-rw-r--r--sql/share/japanese/errmsg.txt16
-rw-r--r--sql/share/korean/errmsg.txt16
-rw-r--r--sql/share/norwegian-ny/errmsg.txt16
-rw-r--r--sql/share/norwegian/errmsg.txt16
-rw-r--r--sql/share/polish/errmsg.txt16
-rw-r--r--sql/share/portuguese/errmsg.txt16
-rw-r--r--sql/share/romanian/errmsg.txt16
-rw-r--r--sql/share/russian/errmsg.txt16
-rw-r--r--sql/share/serbian/errmsg.txt16
-rw-r--r--sql/share/slovak/errmsg.txt16
-rw-r--r--sql/share/spanish/errmsg.txt16
-rw-r--r--sql/share/swedish/errmsg.txt16
-rw-r--r--sql/share/ukrainian/errmsg.txt16
-rw-r--r--sql/slave.cc4
-rw-r--r--sql/sp.cc450
-rw-r--r--sql/sp.h65
-rw-r--r--sql/sp_cache.cc53
-rw-r--r--sql/sp_cache.h65
-rw-r--r--sql/sp_head.cc645
-rw-r--r--sql/sp_head.h411
-rw-r--r--sql/sp_pcontext.cc115
-rw-r--r--sql/sp_pcontext.h162
-rw-r--r--sql/sp_rcontext.h95
-rw-r--r--sql/sql_acl.cc43
-rw-r--r--sql/sql_base.cc8
-rw-r--r--sql/sql_cache.cc25
-rw-r--r--sql/sql_class.cc90
-rw-r--r--sql/sql_class.h37
-rw-r--r--sql/sql_db.cc3
-rw-r--r--sql/sql_delete.cc29
-rw-r--r--sql/sql_derived.cc8
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_insert.cc61
-rw-r--r--sql/sql_lex.cc26
-rw-r--r--sql/sql_lex.h29
-rw-r--r--sql/sql_load.cc7
-rw-r--r--sql/sql_parse.cc374
-rw-r--r--sql/sql_prepare.cc49
-rw-r--r--sql/sql_rename.cc1
-rw-r--r--sql/sql_repl.cc18
-rw-r--r--sql/sql_repl.h2
-rw-r--r--sql/sql_select.cc43
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_table.cc39
-rw-r--r--sql/sql_union.cc20
-rw-r--r--sql/sql_update.cc28
-rw-r--r--sql/sql_yacc.yy747
80 files changed, 4149 insertions, 463 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 69b9c58dd6d..088e0fa64ab 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -58,6 +58,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
log_event.h sql_repl.h slave.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h
+ sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -86,7 +87,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
client.c sql_client.cc mini_client_errors.c pack.c\
stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
- gstream.cc spatial.cc sql_help.cc protocol_cursor.cc
+ gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
+ sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 13989bdae8f..dee872d2506 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -331,7 +331,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select,
byte *ref_pos,*next_pos,ref_buff[MAX_REFLENGTH];
my_off_t record;
TABLE *sort_form;
- volatile bool *killed= &current_thd->killed;
+ volatile THD::killed_state *killed= &current_thd->killed;
handler *file;
DBUG_ENTER("find_all_keys");
DBUG_PRINT("info",("using: %s",(select?select->quick?"ranges":"where":"every row")));
@@ -775,15 +775,15 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
BUFFPEK *buffpek,**refpek;
QUEUE queue;
qsort2_cmp cmp;
- volatile bool *killed= &current_thd->killed;
- bool not_killable;
+ volatile THD::killed_state *killed= &current_thd->killed;
+ THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
statistic_increment(filesort_merge_passes, &LOCK_status);
if (param->not_killable)
{
killed= &not_killable;
- not_killable= 0;
+ not_killable=THD::NOT_KILLED;
}
error=0;
@@ -1129,7 +1129,7 @@ get_addon_fields(THD *thd, Field **ptabfield, uint sortlength, uint *plength)
The fact is the filter 'field->query_id != thd->query_id'
doesn't work for alter table
*/
- if (thd->lex.sql_command != SQLCOM_SELECT)
+ if (thd->lex->sql_command != SQLCOM_SELECT)
return 0;
for (pfield= ptabfield; (field= *pfield) ; pfield++)
{
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index dbed955c0a9..9057e21d4c2 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -2103,7 +2103,7 @@ static void print_msg(THD *thd, const char *table_name, const char *op_name,
protocol->store(msg_type);
protocol->store(msgbuf);
if (protocol->write())
- thd->killed=1;
+ thd->killed=THD::KILL_CONNECTION;
}
#endif
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index d870d0debfd..826055ae7fe 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2226,8 +2226,8 @@ ha_innobase::write_row(
skip_auto_inc_decr = FALSE;
if (error == DB_DUPLICATE_KEY
- && (user_thd->lex.sql_command == SQLCOM_REPLACE
- || user_thd->lex.sql_command
+ && (user_thd->lex->sql_command == SQLCOM_REPLACE
+ || user_thd->lex->sql_command
== SQLCOM_REPLACE_SELECT)) {
skip_auto_inc_decr= TRUE;
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index e8e4798c2b2..4d5380e8d62 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -89,9 +89,9 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
extern "C" {
-volatile bool *killed_ptr(MI_CHECK *param)
+int *killed_ptr(void *thd)
{
- return &(((THD *)(param->thd))->killed);
+ return (int*)&((THD *)thd)->killed;
}
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
@@ -388,7 +388,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
{
HA_CHECK_OPT tmp_check_opt;
- char* backup_dir = thd->lex.backup_dir;
+ char* backup_dir = thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
int error;
@@ -428,7 +428,7 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
- char* backup_dir = thd->lex.backup_dir;
+ char* backup_dir = thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
int error;
diff --git a/sql/item.cc b/sql/item.cc
index 86fa2d82c41..2fb80416848 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -22,6 +22,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
#include "my_dir.h"
+#include "sp_rcontext.h"
static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current,
Item_ident *item);
@@ -56,10 +57,10 @@ Item::Item():
if (thd->lex.current_select)
{
SELECT_LEX_NODE::enum_parsing_place place=
- thd->lex.current_select->parsing_place;
+ thd->lex->current_select->parsing_place;
if (place == SELECT_LEX_NODE::SELECT_LIST ||
place == SELECT_LEX_NODE::IN_HAVING)
- thd->lex.current_select->select_n_having_items++;
+ thd->lex->current_select->select_n_having_items++;
}
}
@@ -204,6 +205,23 @@ CHARSET_INFO * Item::default_charset() const
return current_thd->variables.collation_connection;
}
+
+Item *
+Item_splocal::this_item()
+{
+ THD *thd= current_thd;
+
+ return thd->spcont->get_item(m_offset);
+}
+
+Item *
+Item_splocal::this_const_item() const
+{
+ THD *thd= current_thd;
+
+ return thd->spcont->get_item(m_offset);
+}
+
bool DTCollation::aggregate(DTCollation &dt)
{
if (!my_charset_same(collation, dt.collation))
@@ -791,7 +809,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Item **refer= (Item **)not_found_item;
uint counter;
// Prevent using outer fields in subselects, that is not supported now
- SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
+ SELECT_LEX *cursel=(SELECT_LEX *) thd->lex->current_select;
if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
for (SELECT_LEX *sl= cursel->outer_select();
sl;
@@ -1252,17 +1270,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
if (!ref)
{
TABLE_LIST *where= 0, *table_list;
- SELECT_LEX *sl= thd->lex.current_select->outer_select();
+ SELECT_LEX *sl= thd->lex->current_select->outer_select();
/*
Finding only in current select will be performed for selects that have
not outer one and for derived tables (which not support using outer
fields for now)
*/
if ((ref= find_item_in_list(this,
- *(thd->lex.current_select->get_item_list()),
+ *(thd->lex->current_select->get_item_list()),
&counter,
((sl &&
- thd->lex.current_select->master_unit()->
+ thd->lex->current_select->master_unit()->
first_select()->linkage !=
DERIVED_TABLE_TYPE) ?
REPORT_EXCEPT_NOT_FOUND :
@@ -1312,7 +1330,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
// Call to report error
find_item_in_list(this,
- *(thd->lex.current_select->get_item_list()),
+ *(thd->lex->current_select->get_item_list()),
&counter,
REPORT_ALL_ERRORS);
ref= 0;
@@ -1324,7 +1342,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp)))
return 1;
- mark_as_dependent(last, thd->lex.current_select, fld);
+ mark_as_dependent(last, thd->lex->current_select, fld);
return 0;
}
else
@@ -1335,7 +1353,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list");
return -1;
}
- mark_as_dependent(last, thd->lex.current_select,
+ mark_as_dependent(last, thd->lex->current_select,
this);
ref= last->ref_pointer_array + counter;
}
@@ -1350,7 +1368,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list");
return -1;
}
- ref= thd->lex.current_select->ref_pointer_array + counter;
+ ref= thd->lex->current_select->ref_pointer_array + counter;
}
}
@@ -1363,8 +1381,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
*/
if (((*ref)->with_sum_func && name &&
(depended_from ||
- !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- thd->lex.current_select->having_fix_field))) ||
+ !(thd->lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
+ thd->lex->current_select->having_fix_field))) ||
!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
diff --git a/sql/item.h b/sql/item.h
index 296ad18b1f1..35ad8818a25 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -196,6 +196,9 @@ public:
virtual bool remove_dependence_processor(byte * arg) { return 0; }
+ virtual Item *this_item() { return this; } /* For SPs mostly. */
+ virtual Item *this_const_item() const { return const_cast<Item*>(this); } /* For SPs mostly. */
+
// Row emulation
virtual uint cols() { return 1; }
virtual Item* el(uint i) { return this; }
@@ -208,6 +211,57 @@ public:
};
+// A local SP variable (incl. parameters), used in runtime
+class Item_splocal : public Item
+{
+private:
+
+ uint m_offset;
+
+public:
+
+ Item_splocal(uint offset)
+ : m_offset(offset)
+ {}
+
+ Item *this_item();
+ Item *this_const_item() const;
+
+ inline uint get_offset()
+ {
+ return m_offset;
+ }
+
+ // Abstract methods inherited from Item. Just defer the call to
+ // the item in the frame
+ inline enum Type type() const
+ {
+ return this_const_item()->type();
+ }
+
+ inline double val()
+ {
+ return this_item()->val();
+ }
+
+ inline longlong val_int()
+ {
+ return this_item()->val_int();
+ }
+
+ inline String *val_str(String *sp)
+ {
+ return this_item()->val_str(sp);
+ }
+
+ inline void make_field(Send_field *field)
+ {
+ this_item()->make_field(field);
+ }
+
+};
+
+
class st_select_lex;
class Item_ident :public Item
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 053eb9e6fef..327b0c16ade 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1583,7 +1583,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
maybe_null=1;
}
if (thd)
- thd->lex.current_select->cond_count+=list.elements;
+ thd->lex->current_select->cond_count+=list.elements;
fix_length_and_dec();
fixed= 1;
return 0;
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e3e3c021a1e..ae49fcb3970 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -83,7 +83,7 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
THD *thd=current_thd;
- thd->lex.safe_to_cache_query=0;
+ thd->lex->safe_to_cache_query=0;
return new Item_int(NullS,(longlong)
((thd->slave_thread) ?
thd->variables.pseudo_thread_id :
@@ -163,7 +163,7 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
THD *thd=current_thd;
- thd->lex.safe_to_cache_query=0;
+ thd->lex->safe_to_cache_query=0;
return new Item_int(NullS,(longlong) thd->found_rows(),21);
}
@@ -174,7 +174,7 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
- current_thd->lex.uncacheable();
+ current_thd->lex->uncacheable();
return new Item_func_get_lock(a, b);
}
@@ -344,7 +344,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
- current_thd->lex.uncacheable();
+ current_thd->lex->uncacheable();
return new Item_func_release_lock(a);
}
@@ -465,7 +465,7 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
- current_thd->lex.uncacheable();
+ current_thd->lex->uncacheable();
return new Item_load_file(a);
}
@@ -491,13 +491,13 @@ Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs
Item *create_func_is_free_lock(Item* a)
{
- current_thd->lex.uncacheable();
+ current_thd->lex->uncacheable();
return new Item_func_is_free_lock(a);
}
Item *create_func_is_used_lock(Item* a)
{
- current_thd->lex.uncacheable();
+ current_thd->lex->uncacheable();
return new Item_func_is_used_lock(a);
}
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 4bda8ae78cd..8bac8fb6e07 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -31,6 +31,9 @@
#include <zlib.h>
#endif
+#include "sp_head.h"
+#include "sp_rcontext.h"
+#include "sp.h"
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
@@ -2363,7 +2366,7 @@ void Item_func_get_user_var::fix_length_and_dec()
if ((var_entry= get_variable(&thd->user_vars, name, 0)))
{
- if (opt_bin_log && is_update_query(thd->lex.sql_command) &&
+ if (opt_bin_log && is_update_query(thd->lex->sql_command) &&
var_entry->used_query_id != thd->query_id)
{
uint size;
@@ -2783,7 +2786,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, LEX_STRING name,
}
if (!(item=var->item(thd, var_type, component_name)))
return 0; // Impossible
- thd->lex.uncacheable();
+ thd->lex->uncacheable();
buff[0]='@';
buff[1]='@';
pos=buff+2;
@@ -2823,7 +2826,7 @@ Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
DBUG_ASSERT(var != 0);
if (!(item=var->item(thd, var_type, &null_lex_string)))
return 0; // Impossible
- thd->lex.uncacheable();
+ thd->lex->uncacheable();
item->set_name(item_name, 0, system_charset_info); // Will use original name
return item;
}
@@ -2884,3 +2887,74 @@ longlong Item_func_is_used_lock::val_int()
null_value=0;
return ull->thread_id;
}
+
+int
+Item_func_sp::execute(Item **itp)
+{
+ DBUG_ENTER("Item_func_sp::execute");
+ THD *thd= current_thd;
+
+ if (! m_sp)
+ m_sp= sp_find_function(thd, &m_name);
+ if (! m_sp)
+ DBUG_RETURN(-1);
+
+ DBUG_RETURN(m_sp->execute_function(thd, args, arg_count, itp));
+}
+
+enum enum_field_types
+Item_func_sp::field_type() const
+{
+ DBUG_ENTER("Item_func_sp::field_type");
+
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name));
+ if (m_sp)
+ {
+ DBUG_PRINT("info", ("m_returns = %d", m_sp->m_returns));
+ DBUG_RETURN(m_sp->m_returns);
+ }
+ DBUG_RETURN(MYSQL_TYPE_STRING);
+}
+
+Item_result
+Item_func_sp::result_type() const
+{
+ DBUG_ENTER("Item_func_sp::result_type");
+ DBUG_PRINT("info", ("m_sp = %p", m_sp));
+
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, const_cast<LEX_STRING*>(&m_name));
+ if (m_sp)
+ {
+ DBUG_RETURN(m_sp->result());
+ }
+ DBUG_RETURN(STRING_RESULT);
+}
+
+void
+Item_func_sp::fix_length_and_dec()
+{
+ DBUG_ENTER("Item_func_sp::fix_length_and_dec");
+
+ if (! m_sp)
+ m_sp= sp_find_function(current_thd, &m_name);
+ if (m_sp)
+ {
+ switch (m_sp->result()) {
+ case STRING_RESULT:
+ maybe_null= 1;
+ max_length= 0;
+ break;
+ case REAL_RESULT:
+ decimals= NOT_FIXED_DEC;
+ max_length= float_length(decimals);
+ break;
+ case INT_RESULT:
+ decimals= 0;
+ max_length= 21;
+ break;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/item_func.h b/sql/item_func.h
index 7fedbcf48ee..71f107db79c 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1076,3 +1076,69 @@ enum Cast_target
ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR
};
+
+
+/*
+ *
+ * Stored FUNCTIONs
+ *
+ */
+
+class sp_head;
+
+class Item_func_sp :public Item_func
+{
+private:
+ LEX_STRING m_name;
+ mutable sp_head *m_sp;
+
+ int execute(Item **itp);
+
+public:
+
+ Item_func_sp(LEX_STRING name)
+ :Item_func(), m_name(name), m_sp(NULL)
+ {}
+
+ Item_func_sp(LEX_STRING name, List<Item> &list)
+ :Item_func(list), m_name(name), m_sp(NULL)
+ {}
+
+ virtual ~Item_func_sp()
+ {}
+
+ const char *func_name() const
+ {
+ return m_name.str;
+ }
+
+ enum enum_field_types field_type() const;
+
+ Item_result result_type() const;
+
+ longlong val_int()
+ {
+ return (longlong)Item_func_sp::val();
+ }
+
+ double val()
+ {
+ Item *it;
+
+ if (execute(&it))
+ return 0.0;
+ return it->val();
+ }
+
+ String *val_str(String *str)
+ {
+ Item *it;
+
+ if (execute(&it))
+ return NULL;
+ return it->val_str(str);
+ }
+
+ void fix_length_and_dec();
+
+};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index cbda995504c..9545ff27f45 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -191,7 +191,7 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
{
have_to_be_excluded= 1;
- if (join->thd->lex.describe)
+ if (join->thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
@@ -503,14 +503,14 @@ Item_in_subselect::single_value_transformer(JOIN *join,
SELECT_LEX *current= thd->lex.current_select, *up;
- thd->lex.current_select= up= current->return_after_parsing();
+ thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
- thd->lex.current_select= current;
+ thd->lex->current_select= current;
DBUG_RETURN(ERROR);
}
- thd->lex.current_select= current;
+ thd->lex->current_select= current;
/*
As far as Item_ref_in_optimizer do not substitude itself on fix_fields
@@ -749,8 +749,8 @@ int subselect_single_select_engine::prepare()
if (prepared)
return 0;
prepared= 1;
- SELECT_LEX *save_select= thd->lex.current_select;
- thd->lex.current_select= select_lex;
+ SELECT_LEX *save_select= thd->lex->current_select;
+ thd->lex->current_select= select_lex;
if (join->prepare(&select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
select_lex->with_wild,
@@ -763,7 +763,7 @@ int subselect_single_select_engine::prepare()
(ORDER*) 0, select_lex,
select_lex->master_unit(), 0))
return 1;
- thd->lex.current_select= save_select;
+ thd->lex->current_select= save_select;
return 0;
}
@@ -869,8 +869,8 @@ int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
char const *save_where= join->thd->where;
- SELECT_LEX *save_select= join->thd->lex.current_select;
- join->thd->lex.current_select= select_lex;
+ SELECT_LEX *save_select= join->thd->lex->current_select;
+ join->thd->lex->current_select= select_lex;
if (!optimized)
{
optimized=1;
@@ -878,7 +878,7 @@ int subselect_single_select_engine::exec()
{
join->thd->where= save_where;
executed= 1;
- join->thd->lex.current_select= save_select;
+ join->thd->lex->current_select= save_select;
DBUG_RETURN(join->error?join->error:1);
}
if (item->engine_changed)
@@ -891,7 +891,7 @@ int subselect_single_select_engine::exec()
if (join->reinit())
{
join->thd->where= save_where;
- join->thd->lex.current_select= save_select;
+ join->thd->lex->current_select= save_select;
DBUG_RETURN(1);
}
item->reset();
@@ -902,11 +902,11 @@ int subselect_single_select_engine::exec()
join->exec();
executed= 1;
join->thd->where= save_where;
- join->thd->lex.current_select= save_select;
+ join->thd->lex->current_select= save_select;
DBUG_RETURN(join->error||thd->is_fatal_error);
}
join->thd->where= save_where;
- join->thd->lex.current_select= save_select;
+ join->thd->lex->current_select= save_select;
DBUG_RETURN(0);
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 0d05d05f0af..7181e927b54 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -57,7 +57,7 @@ Item_sum::Item_sum(THD *thd, Item_sum &item):
void Item_sum::mark_as_sum_func()
{
- current_thd->lex.current_select->with_sum_func= 1;
+ current_thd->lex->current_select->with_sum_func= 1;
with_sum_func= 1;
}
@@ -1117,7 +1117,7 @@ void Item_sum_count_distinct::make_unique()
bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
- SELECT_LEX *select_lex= thd->lex.current_select;
+ SELECT_LEX *select_lex= thd->lex->current_select;
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
return 1;
@@ -1613,7 +1613,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
quick_group= 0;
mark_as_sum_func();
item_thd= current_thd;
- SELECT_LEX *select_lex= item_thd->lex.current_select;
+ SELECT_LEX *select_lex= item_thd->lex->current_select;
order= 0;
group_concat_max_len= item_thd->variables.group_concat_max_len;
@@ -1795,7 +1795,7 @@ bool Item_func_group_concat::setup(THD *thd)
{
DBUG_ENTER("Item_func_group_concat::setup");
List<Item> list;
- SELECT_LEX *select_lex= thd->lex.current_select;
+ SELECT_LEX *select_lex= thd->lex->current_select;
if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
DBUG_RETURN(1);
diff --git a/sql/lex.h b/sql/lex.h
index 24bfe796cc0..ca278a7e911 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -60,6 +60,7 @@ static SYMBOL symbols[] = {
{ "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0},
{ "ASCII", SYM(ASCII_SYM),0,0},
+ { "ASENSITIVE", SYM(ASENSITIVE_SYM),0,0},
{ "AVG", SYM(AVG_SYM),0,0},
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
@@ -81,6 +82,7 @@ static SYMBOL symbols[] = {
{ "BY", SYM(BY),0,0},
{ "BYTE", SYM(BYTE_SYM), 0, 0},
{ "CACHE", SYM(CACHE_SYM),0,0},
+ { "CALL", SYM(CALL_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0},
{ "CHAR", SYM(CHAR_SYM),0,0},
@@ -102,6 +104,7 @@ static SYMBOL symbols[] = {
{ "COMMITTED", SYM(COMMITTED_SYM),0,0},
{ "COMPRESSED", SYM(COMPRESSED_SYM),0,0},
{ "CONCURRENT", SYM(CONCURRENT),0,0},
+ { "CONNECTION", SYM(CONNECTION_SYM),0,0},
{ "CONSTRAINT", SYM(CONSTRAINT),0,0},
{ "CREATE", SYM(CREATE),0,0},
{ "CROSS", SYM(CROSS),0,0},
@@ -109,6 +112,7 @@ static SYMBOL symbols[] = {
{ "CURRENT_DATE", SYM(CURDATE),0,0},
{ "CURRENT_TIME", SYM(CURTIME),0,0},
{ "CURRENT_TIMESTAMP", SYM(NOW_SYM),0,0},
+ { "CURSOR", SYM(CURSOR_SYM),0,0},
{ "DATA", SYM(DATA_SYM),0,0},
{ "DATABASE", SYM(DATABASE),0,0},
{ "DATABASES", SYM(DATABASES),0,0},
@@ -121,6 +125,7 @@ static SYMBOL symbols[] = {
{ "DAY_SECOND", SYM(DAY_SECOND_SYM),0,0},
{ "DEC", SYM(DECIMAL_SYM),0,0},
{ "DECIMAL", SYM(DECIMAL_SYM),0,0},
+ { "DECLARE", SYM(DECLARE_SYM),0,0},
{ "DES_KEY_FILE", SYM(DES_KEY_FILE),0,0},
{ "DEFAULT", SYM(DEFAULT),0,0},
{ "DELAYED", SYM(DELAYED_SYM),0,0},
@@ -143,6 +148,7 @@ static SYMBOL symbols[] = {
{ "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0},
+ { "ELSEIF", SYM(ELSEIF_SYM),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
{ "ESCAPED", SYM(ESCAPED),0,0},
{ "ENABLE", SYM(ENABLE_SYM),0,0},
@@ -173,7 +179,7 @@ static SYMBOL symbols[] = {
{ "FOR", SYM(FOR_SYM),0,0},
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
- { "FUNCTION", SYM(UDF_SYM),0,0},
+ { "FUNCTION", SYM(FUNCTION_SYM),0,0},
{ "GEOMETRY", SYM(GEOMETRY_SYM),0,0},
{ "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0},
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
@@ -200,6 +206,8 @@ static SYMBOL symbols[] = {
{ "INNER", SYM(INNER_SYM),0,0},
{ "INNOBASE", SYM(INNOBASE_SYM),0,0},
{ "INNODB", SYM(INNOBASE_SYM),0,0},
+ { "INOUT", SYM(INOUT_SYM),0,0},
+ { "INSENSITIVE", SYM(INSENSITIVE_SYM),0,0},
{ "INSERT", SYM(INSERT),0,0},
{ "INSERT_METHOD", SYM(INSERT_METHOD),0,0},
{ "INT", SYM(INT_SYM),0,0},
@@ -217,12 +225,14 @@ static SYMBOL symbols[] = {
{ "ISOLATION", SYM(ISOLATION),0,0},
{ "ISAM", SYM(ISAM_SYM),0,0},
{ "ISSUER", SYM(ISSUER_SYM),0,0},
+ { "ITERATE", SYM(ITERATE_SYM),0,0},
{ "JOIN", SYM(JOIN_SYM),0,0},
{ "KEY", SYM(KEY_SYM),0,0},
{ "KEYS", SYM(KEYS),0,0},
{ "KILL", SYM(KILL_SYM),0,0},
{ "LAST", SYM(LAST_SYM),0,0},
{ "LEADING", SYM(LEADING),0,0},
+ { "LEAVE", SYM(LEAVE_SYM),0,0},
{ "LEAVES", SYM(LEAVES),0,0},
{ "LEFT", SYM(LEFT),0,0},
{ "LEVEL", SYM(LEVEL_SYM),0,0},
@@ -239,6 +249,7 @@ static SYMBOL symbols[] = {
{ "LOGS", SYM(LOGS_SYM),0,0},
{ "LONG", SYM(LONG_SYM),0,0},
{ "LONGBLOB", SYM(LONGBLOB),0,0},
+ { "LOOP", SYM(LOOP_SYM),0,0},
{ "LONGTEXT", SYM(LONGTEXT),0,0},
{ "LOW_PRIORITY", SYM(LOW_PRIORITY),0,0},
{ "MASTER", SYM(MASTER_SYM),0,0},
@@ -295,6 +306,7 @@ static SYMBOL symbols[] = {
{ "OPTIONALLY", SYM(OPTIONALLY),0,0},
{ "OR", SYM(OR),0,0},
{ "ORDER", SYM(ORDER_SYM),0,0},
+ { "OUT", SYM(OUT_SYM),0,0},
{ "OUTER", SYM(OUTER),0,0},
{ "OUTFILE", SYM(OUTFILE),0,0},
{ "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
@@ -325,13 +337,15 @@ static SYMBOL symbols[] = {
{ "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0},
{ "REPLICATION", SYM(REPLICATION),0,0},
+ { "REPEAT", SYM(REPEAT_SYM),0,0},
{ "REPEATABLE", SYM(REPEATABLE_SYM),0,0},
{ "REQUIRE", SYM(REQUIRE_SYM),0,0},
{ "RESET", SYM(RESET_SYM),0,0},
{ "USER_RESOURCES", SYM(RESOURCES),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0},
- { "RETURNS", SYM(UDF_RETURNS_SYM),0,0},
+ { "RETURN", SYM(RETURN_SYM),0,0},
+ { "RETURNS", SYM(RETURNS_SYM),0,0},
{ "REVOKE", SYM(REVOKE),0,0},
{ "RIGHT", SYM(RIGHT),0,0},
{ "RLIKE", SYM(REGEXP),0,0}, /* Like in mSQL2 */
@@ -345,6 +359,7 @@ static SYMBOL symbols[] = {
{ "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM),0,0},
{ "SEPARATOR", SYM(SEPARATOR_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
+ { "SENSITIVE", SYM(SENSITIVE_SYM),0,0},
{ "SERIAL", SYM(SERIAL_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
@@ -359,6 +374,7 @@ static SYMBOL symbols[] = {
{ "SOME", SYM(ANY_SYM),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
+ { "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
@@ -401,6 +417,7 @@ static SYMBOL symbols[] = {
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
{ "UNLOCK", SYM(UNLOCK_SYM),0,0},
{ "UNSIGNED", SYM(UNSIGNED),0,0},
+ { "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USE", SYM(USE_SYM),0,0},
{ "USE_FRM", SYM(USE_FRM),0,0},
{ "USER", SYM(USER),0,0},
@@ -423,6 +440,7 @@ static SYMBOL symbols[] = {
{ "WRITE", SYM(WRITE_SYM),0,0},
{ "WHEN", SYM(WHEN_SYM),0,0},
{ "WHERE", SYM(WHERE),0,0},
+ { "WHILE", SYM(WHILE_SYM),0,0},
{ "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG),0,0},
{ "XOR", SYM(XOR),0,0},
{ "X509", SYM(X509_SYM),0,0},
@@ -611,7 +629,6 @@ static SYMBOL sql_functions[] = {
{ "RADIANS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_radians)},
{ "RAND", SYM(RAND),0,0},
{ "RELEASE_LOCK", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_release_lock)},
- { "REPEAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_repeat)},
{ "REVERSE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_reverse)},
{ "ROUND", SYM(ROUND),0,0},
{ "RPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_rpad)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 82004298453..45ffefed14f 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -154,7 +154,7 @@ retry:
thd->proc_info=0;
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
if (sql_lock)
{
mysql_unlock_tables(thd,sql_lock);
diff --git a/sql/log.cc b/sql/log.cc
index d3ba5b63e19..a1b06e1df2e 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -30,7 +30,7 @@
#include <stdarg.h>
#include <m_ctype.h> // For test_if_number
-MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
+MYSQL_LOG mysql_log, mysql_slow_log, mysql_bin_log;
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
static bool test_if_number(const char *str,
@@ -1068,7 +1068,7 @@ err:
/*
Write to normal (not rotable) log
- This is the format for the 'normal', 'slow' and 'update' logs.
+ This is the format for the 'normal' log.
*/
bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
@@ -1511,8 +1511,7 @@ err:
/*
- Write update log in a format suitable for incremental backup
- This is also used by the slow query log.
+ Write to the slow query log.
*/
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
@@ -1528,12 +1527,6 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
int tmp_errno=0;
char buff[80],*end;
end=buff;
- if (!(thd->options & OPTION_UPDATE_LOG) &&
- (thd->master_access & SUPER_ACL))
- {
- VOID(pthread_mutex_unlock(&LOCK_log));
- return 0;
- }
if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg)
{
current_time=time(NULL);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8a52ad9ebca..ad14bd026f4 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -798,7 +798,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans),
data_buf(0), query(query_arg),
db(thd_arg->db), q_len((uint32) query_length),
- error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
+ error_code(thd_arg->killed != THD::NOT_KILLED ? thd->killed_errno() : thd_arg->net.last_errno),
thread_id(thd_arg->thread_id)
{
time_t end_time;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a5d9ce5bce3..cff02a2b4fa 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -49,7 +49,7 @@ char *sql_strmake_with_convert(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs,
uint32 max_res_length,
CHARSET_INFO *to_cs, uint32 *result_length);
-void kill_one_thread(THD *thd, ulong id);
+void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
@@ -374,7 +374,7 @@ bool is_update_query(enum enum_sql_command command);
void free_items(Item *item);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
-void mysql_init_query(THD *thd);
+void mysql_init_query(THD *thd, bool lexonly=0);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
@@ -385,7 +385,7 @@ extern "C" pthread_handler_decl(handle_one_connection,arg);
extern "C" pthread_handler_decl(handle_bootstrap,arg);
void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
-void mysql_execute_command(THD *thd);
+int mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
@@ -938,22 +938,22 @@ void free_list(I_List <i_string> *list);
inline bool add_item_to_list(THD *thd, Item *item)
{
- return thd->lex.current_select->add_item_to_list(thd, item);
+ return thd->lex->current_select->add_item_to_list(thd, item);
}
inline bool add_value_to_list(THD *thd, Item *value)
{
- return thd->lex.value_list.push_back(value);
+ return thd->lex->value_list.push_back(value);
}
inline bool add_order_to_list(THD *thd, Item *item, bool asc)
{
- return thd->lex.current_select->add_order_to_list(thd, item, asc);
+ return thd->lex->current_select->add_order_to_list(thd, item, asc);
}
inline bool add_group_to_list(THD *thd, Item *item, bool asc)
{
- return thd->lex.current_select->add_group_to_list(thd, item, asc);
+ return thd->lex->current_select->add_group_to_list(thd, item, asc);
}
inline void mark_as_null_row(TABLE *table)
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 41bd9706fc3..e8b475db6fc 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -22,6 +22,7 @@
#include "sql_repl.h"
#include "repl_failsafe.h"
#include "stacktrace.h"
+#include "mysys_err.h"
#ifdef HAVE_BERKELEY_DB
#include "ha_berkeley.h"
#endif
@@ -590,7 +591,7 @@ static void close_connections(void)
{
DBUG_PRINT("quit",("Informing thread %ld that it's time to die",
tmp->thread_id));
- tmp->killed=1;
+ tmp->killed= THD::KILL_CONNECTION;
if (tmp->mysys_var)
{
tmp->mysys_var->abort=1;
@@ -773,6 +774,7 @@ static void __cdecl kill_server(int sig_ptr)
unireg_abort(1); /* purecov: inspected */
else
unireg_end();
+
#ifdef __NETWARE__
pthread_join(select_thread, NULL); // wait for main thread
#endif /* __NETWARE__ */
@@ -864,7 +866,6 @@ void clean_up(bool print_message)
mysql_log.cleanup();
mysql_slow_log.cleanup();
- mysql_update_log.cleanup();
mysql_bin_log.cleanup();
#ifdef HAVE_REPLICATION
@@ -1229,12 +1230,12 @@ static void server_init(void)
void yyerror(const char *s)
{
THD *thd=current_thd;
- char *yytext=(char*) thd->lex.tok_start;
+ char *yytext=(char*) thd->lex->tok_start;
/* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
s=ER(ER_SYNTAX_ERROR);
net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
- thd->lex.yylineno);
+ thd->lex->yylineno);
}
@@ -1364,7 +1365,7 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
THD *thd=current_thd;
DBUG_ENTER("abort_thread");
if (thd)
- thd->killed=1;
+ thd->killed= THD::KILL_CONNECTION;
DBUG_VOID_RETURN;
}
#endif
@@ -1849,8 +1850,8 @@ extern "C" int my_message_sql(uint error, const char *str,
thd->lex.current_select equel to zero if lex structure is not inited
(not query command (COM_QUERY))
*/
- if (thd->lex.current_select &&
- thd->lex.current_select->no_error && !thd->is_fatal_error)
+ if (thd->lex->current_select &&
+ thd->lex->current_select->no_error && !thd->is_fatal_error)
{
DBUG_PRINT("error", ("above error converted to warning"));
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, error, str);
@@ -2177,9 +2178,55 @@ static int init_server_components()
LOG_NORMAL, 0, 0, 0);
if (opt_update_log)
{
- open_log(&mysql_update_log, glob_hostname, opt_update_logname, "",
- NullS, LOG_NEW, 0, 0, 0);
- using_update_log=1;
+ /*
+ Update log is removed since 5.0. But we still accept the option.
+ The idea is if the user already uses the binlog and the update log,
+ we completely ignore any option/variable related to the update log, like
+ if the update log did not exist. But if the user uses only the update log,
+ then we translate everything into binlog for him (with warnings).
+ Implementation of the above :
+ - If mysqld is started with --log-update and --log-bin,
+ ignore --log-update (print a warning), push a warning when SQL_LOG_UPDATE
+ is used, and turn off --sql-bin-update-same.
+ This will completely ignore SQL_LOG_UPDATE
+ - If mysqld is started with --log-update only,
+ change it to --log-bin (with the filename passed to log-update,
+ plus '-bin') (print a warning), push a warning when SQL_LOG_UPDATE is
+ used, and turn on --sql-bin-update-same.
+ This will translate SQL_LOG_UPDATE to SQL_LOG_BIN.
+
+ Note that we tell the user that --sql-bin-update-same is deprecated and
+ does nothing, and we don't take into account if he used this option or
+ not; but internally we give this variable a value to have the behaviour we
+ want (i.e. have SQL_LOG_UPDATE influence SQL_LOG_BIN or not).
+ As sql-bin-update-same, log-update and log-bin cannot be changed by the user
+ after starting the server (they are not variables), the user will not
+ later interfere with the settings we do here.
+ */
+ if (opt_bin_log)
+ {
+ opt_sql_bin_update= 0;
+ sql_print_error("The update log is no longer supported by MySQL in \
+version 5.0 and above. It is replaced by the binary log.");
+ }
+ else
+ {
+ opt_sql_bin_update= 1;
+ opt_bin_log= 1;
+ if (opt_update_logname)
+ {
+ // as opt_bin_log==0, no need to free opt_bin_logname
+ if (!(opt_bin_logname= my_strdup(opt_update_logname, MYF(MY_WME))))
+ exit(EXIT_OUT_OF_MEMORY);
+ sql_print_error("The update log is no longer supported by MySQL in \
+version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
+with --log-bin='%s' instead.",opt_bin_logname);
+ }
+ else
+ sql_print_error("The update log is no longer supported by MySQL in \
+version 5.0 and above. It is replaced by the binary log. Now starting MySQL \
+with --log-bin instead.");
+ }
}
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
@@ -2862,7 +2909,7 @@ static void create_new_thread(THD *thd)
("Can't create thread to handle request (error %d)",
error));
thread_count--;
- thd->killed=1; // Safety
+ thd->killed= THD::KILL_CONNECTION; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
statistic_increment(aborted_connects,&LOCK_status);
net_printf(thd,ER_CANT_CREATE_THREAD,error);
@@ -3735,7 +3782,8 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &myisam_log_filename, (gptr*) &myisam_log_filename, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-update", OPT_UPDATE_LOG,
- "Log updates to file.# where # is a unique number if not given.",
+ "The update log is deprecated since version 5.0, is replaced by the binary \
+log and this option justs turns on --log-bin instead.",
(gptr*) &opt_update_logname, (gptr*) &opt_update_logname, 0, GET_STR,
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"log-slow-queries", OPT_SLOW_QUERY_LOG,
@@ -4002,9 +4050,9 @@ replicating a LOAD DATA INFILE command.",
(gptr*) &mysqld_unix_port, (gptr*) &mysqld_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"sql-bin-update-same", OPT_SQL_BIN_UPDATE_SAME,
- "If set, setting SQL_LOG_BIN to a value will automatically set SQL_LOG_UPDATE to the same value and vice versa.",
- (gptr*) &opt_sql_bin_update, (gptr*) &opt_sql_bin_update, 0, GET_BOOL,
- NO_ARG, 0, 0, 0, 0, 0, 0},
+ "The update log is deprecated since version 5.0, is replaced by the binary \
+log and this option does nothing anymore.",
+ 0, 0, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"sql-mode", OPT_SQL_MODE,
"Syntax: sql-mode=option[,option[,option...]] where option can be one of: REAL_AS_FLOAT, PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, ONLY_FULL_GROUP_BY, NO_UNSIGNED_SUBTRACTION.",
(gptr*) &sql_mode_str, (gptr*) &sql_mode_str, 0, GET_STR, REQUIRED_ARG, 0,
diff --git a/sql/protocol.cc b/sql/protocol.cc
index e90aa7585e2..940f9035f7a 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -336,7 +336,7 @@ send_eof(THD *thd, bool no_flush)
uint tmp= min(thd->total_warn_count, 65535);
buff[0]=254;
int2store(buff+1, tmp);
- int2store(buff+3, 0); // No flags yet
+ int2store(buff+3, thd->server_status);
VOID(my_net_write(net,(char*) buff,5));
VOID(net_flush(net));
}
diff --git a/sql/records.cc b/sql/records.cc
index 72a6d480356..facca3815fb 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -175,7 +175,7 @@ static int rr_sequential(READ_RECORD *info)
{
if (info->thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ info->thd->send_kill_message();
return 1;
}
if (tmp != HA_ERR_RECORD_DELETED)
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index e9c3b1ed0b0..0db138a8879 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -422,7 +422,7 @@ int show_new_master(THD* thd)
DBUG_ENTER("show_new_master");
List<Item> field_list;
char errmsg[SLAVE_ERRMSG_SIZE];
- LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
+ LEX_MASTER_INFO* lex_mi = &thd->lex->mi;
errmsg[0]=0; // Safety
if (translate_master(thd, lex_mi, errmsg))
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 91583759c70..960e1f8e1b7 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -78,6 +78,7 @@ static void sys_set_default_charset(THD *thd, enum_var_type type);
static bool set_option_bit(THD *thd, set_var *var);
static bool set_option_autocommit(THD *thd, set_var *var);
static bool set_log_update(THD *thd, set_var *var);
+static bool set_log_bin(THD *thd, set_var *var);
static void fix_low_priority_updates(THD *thd, enum_var_type type);
static void fix_tx_isolation(THD *thd, enum_var_type type);
static void fix_net_read_timeout(THD *thd, enum_var_type type);
@@ -300,7 +301,7 @@ static sys_var_thd_bit sys_log_update("sql_log_update",
set_log_update,
OPTION_UPDATE_LOG);
static sys_var_thd_bit sys_log_binlog("sql_log_bin",
- set_log_update,
+ set_log_bin,
OPTION_BIN_LOG);
static sys_var_thd_bit sys_sql_warnings("sql_warnings",
set_option_bit,
@@ -1213,7 +1214,7 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type,
bool sys_var_thd_bit::update(THD *thd, set_var *var)
{
int res= (*update_func)(thd, var);
- thd->lex.select_lex.options=thd->options;
+ thd->lex->select_lex.options=thd->options;
return res;
}
@@ -1731,6 +1732,30 @@ static bool set_option_autocommit(THD *thd, set_var *var)
static bool set_log_update(THD *thd, set_var *var)
{
+ /*
+ The update log is not supported anymore since 5.0.
+ See sql/mysqld.cc/, comments in function init_server_components() for an
+ explaination of the different warnings we send below
+ */
+
+ if (opt_sql_bin_update)
+ {
+ ((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG |
+ OPTION_UPDATE_LOG);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_UPDATE_LOG_DEPRECATED_TRANSLATED,
+ ER(ER_UPDATE_LOG_DEPRECATED_TRANSLATED));
+ }
+ else
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_UPDATE_LOG_DEPRECATED_IGNORED,
+ ER(ER_UPDATE_LOG_DEPRECATED_IGNORED));
+ set_option_bit(thd, var);
+ return 0;
+}
+
+static bool set_log_bin(THD *thd, set_var *var)
+{
if (opt_sql_bin_update)
((sys_var_thd_bit*) var->var)->bit_flag|= (OPTION_BIN_LOG |
OPTION_UPDATE_LOG);
@@ -1738,6 +1763,7 @@ static bool set_log_update(THD *thd, set_var *var)
return 0;
}
+
static byte *get_warning_count(THD *thd)
{
thd->sys_var_tmp.long_value=
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 1beffa81671..dbe4ed7c508 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -278,3 +278,19 @@ v/*
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index c13141fc669..9c95f966273 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -272,3 +272,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index b454566f3ba..7da1db7a5b1 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -280,3 +280,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 5655ad32d3d..52d4b315c7d 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -274,3 +274,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 8e7a7121dfa..74fdb0336d1 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -274,3 +274,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 8a6d786bee8..83e05270e1f 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -269,3 +269,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index db20cc5dad9..207c5653631 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -278,3 +278,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index f844ee59dab..861f4dd1cbf 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -269,3 +269,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 7e60515aace..2f655ec47cb 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -271,3 +271,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index a624d90661d..e1b2696a1c3 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -269,3 +269,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index b5693fe6e41..bec7512eefd 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -271,3 +271,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index bc2d6eb9caa..42614efd8b5 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -269,3 +269,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 9bf0d4845c7..3f103c1bc7e 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -271,3 +271,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 4a025e7218f..35b06835084 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -271,3 +271,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 1a6634fb96c..6574a9abaf4 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -273,3 +273,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 99a940e62ab..bbc487b77c2 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -269,3 +269,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 61591d54d40..e49a67b92d2 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -273,3 +273,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index b1876f83008..9319898c0a8 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -271,3 +271,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 9e2a37e4053..0aae9b64a6d 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -264,3 +264,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index a96d512cb72..66a58812004 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -277,3 +277,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index df18b8bf7f0..ef9fd53e0b3 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -270,3 +270,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 07187f7ca34..2bf66db0183 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -269,3 +269,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index a0604ba862c..0f9f26b76b5 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -274,3 +274,19 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"Can't create a %s from within another stored routine"
+"%s %s already exists"
+"%s %s does not exist"
+"Failed to DROP %s %s"
+"Failed to CREATE %s %s"
+"%s with no matching label: %s"
+"Redefining label %s"
+"End-label %s without match"
+"Referring to uninitialized variable %s"
+"SELECT in a stored procedure must have INTO"
+"RETURN is only allowed in a FUNCTION"
+"Queries, like SELECT, INSERT, UPDATE (and others), are not allowed in a FUNCTION"
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been ignored."
+"The update log is deprecated and replaced by the binary log. SET SQL_LOG_UPDATE has been translated to SET SQL_LOG_BIN."
+"Query execution was interrupted"
+"Wrong number of arguments for %s %s, expected %u, got %u"
diff --git a/sql/slave.cc b/sql/slave.cc
index d45cf1aa8b9..cdf34817949 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -563,7 +563,7 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
if (thd->killed)
{
pthread_mutex_unlock(cond_lock);
- DBUG_RETURN(ER_SERVER_SHUTDOWN);
+ DBUG_RETURN(thd->killed_errno());
}
}
}
@@ -2096,7 +2096,7 @@ err:
pthread_mutex_unlock(&data_lock);
DBUG_PRINT("exit",("killed: %d abort: %d slave_running: %d \
improper_arguments: %d timed_out: %d",
- (int) thd->killed,
+ thd->killed_errno(),
(int) (init_abort_pos_wait != abort_pos_wait),
(int) slave_running,
(int) (error == -2),
diff --git a/sql/sp.cc b/sql/sp.cc
new file mode 100644
index 00000000000..092a3b0989b
--- /dev/null
+++ b/sql/sp.cc
@@ -0,0 +1,450 @@
+/* Copyright (C) 2002 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 */
+
+
+#include "mysql_priv.h"
+#include "sp.h"
+#include "sp_head.h"
+#include "sp_cache.h"
+
+/*
+ *
+ * DB storage of Stored PROCEDUREs and FUNCTIONs
+ *
+ */
+
+// *opened=true means we opened ourselves
+static int
+db_find_routine_aux(THD *thd, int type, char *name, uint namelen,
+ enum thr_lock_type ltype, TABLE **tablep, bool *opened)
+{
+ DBUG_ENTER("db_find_routine_aux");
+ DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
+ TABLE *table;
+ byte key[65]; // We know name is 64 and the enum is 1 byte
+ uint keylen;
+ int ret;
+
+ // Put the key together
+ keylen= namelen;
+ if (keylen > sizeof(key)-1)
+ keylen= sizeof(key)-1;
+ memcpy(key, name, keylen);
+ memset(key+keylen, (int)' ', sizeof(key)-1 - keylen); // Pad with space
+ key[sizeof(key)-1]= type;
+ keylen= sizeof(key);
+
+ for (table= thd->open_tables ; table ; table= table->next)
+ if (strcmp(table->table_cache_key, "mysql") == 0 &&
+ strcmp(table->real_name, "proc") == 0)
+ break;
+ if (table)
+ *opened= FALSE;
+ else
+ {
+ TABLE_LIST tables;
+
+ memset(&tables, 0, sizeof(tables));
+ tables.db= (char*)"mysql";
+ tables.real_name= tables.alias= (char*)"proc";
+ if (! (table= open_ltable(thd, &tables, ltype)))
+ {
+ *tablep= NULL;
+ DBUG_RETURN(SP_OPEN_TABLE_FAILED);
+ }
+ *opened= TRUE;
+ }
+
+ if (table->file->index_read_idx(table->record[0], 0,
+ key, keylen,
+ HA_READ_KEY_EXACT))
+ {
+ *tablep= NULL;
+ DBUG_RETURN(SP_KEY_NOT_FOUND);
+ }
+ *tablep= table;
+
+ DBUG_RETURN(SP_OK);
+}
+
+static int
+db_find_routine(THD *thd, int type, char *name, uint namelen, sp_head **sphp)
+{
+ DBUG_ENTER("db_find_routine");
+ DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
+ extern int yyparse(void *thd);
+ TABLE *table;
+ const char *defstr;
+ int ret;
+ bool opened;
+ const char *creator;
+ longlong created;
+ longlong modified;
+ bool suid= 1;
+ char *ptr;
+ uint length;
+ char buff[65];
+ String str(buff, sizeof(buff), &my_charset_bin);
+
+ ret= db_find_routine_aux(thd, type, name, namelen, TL_READ, &table, &opened);
+ if (ret != SP_OK)
+ goto done;
+ if ((defstr= get_field(&thd->mem_root, table->field[2])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+
+ // Get additional information
+ if ((creator= get_field(&thd->mem_root, table->field[3])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+
+ modified= table->field[4]->val_int();
+ created= table->field[5]->val_int();
+
+ if ((ptr= get_field(&thd->mem_root, table->field[6])) == NULL)
+ {
+ ret= SP_GET_FIELD_FAILED;
+ goto done;
+ }
+ if (ptr[0] == 'N')
+ suid= 0;
+
+ table->field[7]->val_str(&str, &str);
+ ptr= 0;
+ if ((length= str.length()))
+ ptr= strmake_root(&thd->mem_root, str.ptr(), length);
+
+ if (opened)
+ {
+ close_thread_tables(thd, 0, 1);
+ table= NULL;
+ }
+
+ {
+ LEX *oldlex= thd->lex;
+ enum enum_sql_command oldcmd= thd->lex->sql_command;
+
+ lex_start(thd, (uchar*)defstr, strlen(defstr));
+ if (yyparse(thd) || thd->is_fatal_error || thd->lex->sphead == NULL)
+ {
+ LEX *newlex= thd->lex;
+ sp_head *sp= newlex->sphead;
+
+ if (sp)
+ {
+ if (oldlex != newlex)
+ sp->restore_lex(thd);
+ delete sp;
+ newlex->sphead= NULL;
+ }
+ ret= SP_PARSE_ERROR;
+ }
+ else
+ {
+ *sphp= thd->lex->sphead;
+ (*sphp)->sp_set_info((char *) creator, (uint) strlen(creator),
+ created, modified, suid,
+ ptr, length);
+ }
+ thd->lex->sql_command= oldcmd;
+ }
+
+ done:
+ if (table && opened)
+ close_thread_tables(thd);
+ DBUG_RETURN(ret);
+}
+
+static int
+db_create_routine(THD *thd, int type,
+ char *name, uint namelen, char *def, uint deflen,
+ char *comment, uint commentlen, bool suid)
+{
+ DBUG_ENTER("db_create_routine");
+ DBUG_PRINT("enter", ("type: %d name: %*s def: %*s", type, namelen, name, deflen, def));
+ int ret;
+ TABLE *table;
+ TABLE_LIST tables;
+ char creator[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
+
+ memset(&tables, 0, sizeof(tables));
+ tables.db= (char*)"mysql";
+ tables.real_name= tables.alias= (char*)"proc";
+
+ if (! (table= open_ltable(thd, &tables, TL_WRITE)))
+ ret= SP_OPEN_TABLE_FAILED;
+ else
+ {
+ restore_record(table, default_values); // Get default values for fields
+ strxmov(creator, thd->user, "@", thd->host_or_ip, NullS);
+
+ table->field[0]->store(name, namelen, system_charset_info);
+ table->field[1]->store((longlong)type);
+ table->field[2]->store(def, deflen, system_charset_info);
+ table->field[3]->store(creator, (uint)strlen(creator), system_charset_info);
+ ((Field_timestamp *)table->field[5])->set_time();
+ if (suid)
+ table->field[6]->store((longlong)suid);
+ if (comment)
+ table->field[7]->store(comment, commentlen, system_charset_info);
+
+ if (table->file->write_row(table->record[0]))
+ ret= SP_WRITE_ROW_FAILED;
+ else
+ ret= SP_OK;
+ }
+
+ close_thread_tables(thd);
+ DBUG_RETURN(ret);
+}
+
+static int
+db_drop_routine(THD *thd, int type, char *name, uint namelen)
+{
+ DBUG_ENTER("db_drop_routine");
+ DBUG_PRINT("enter", ("type: %d name: %*s", type, namelen, name));
+ TABLE *table;
+ int ret;
+ bool opened;
+
+ ret= db_find_routine_aux(thd, type, name, namelen, TL_WRITE, &table, &opened);
+ if (ret == SP_OK)
+ {
+ if (table->file->delete_row(table->record[0]))
+ ret= SP_DELETE_ROW_FAILED;
+ }
+
+ if (opened)
+ close_thread_tables(thd);
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ *
+ * PROCEDURE
+ *
+ */
+
+sp_head *
+sp_find_procedure(THD *thd, LEX_STRING *name)
+{
+ DBUG_ENTER("sp_find_procedure");
+ sp_head *sp;
+
+ DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
+
+ sp= thd->sp_proc_cache->lookup(name->str, name->length);
+ if (! sp)
+ {
+ if (db_find_routine(thd, TYPE_ENUM_PROCEDURE,
+ name->str, name->length, &sp) == SP_OK)
+ {
+ thd->sp_proc_cache->insert(sp);
+ }
+ }
+
+ DBUG_RETURN(sp);
+}
+
+int
+sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen,
+ char *comment, uint commentlen, bool suid)
+{
+ DBUG_ENTER("sp_create_procedure");
+ DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
+ int ret;
+
+ ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, def, deflen,
+ comment, commentlen, suid);
+
+ DBUG_RETURN(ret);
+}
+
+int
+sp_drop_procedure(THD *thd, char *name, uint namelen)
+{
+ DBUG_ENTER("sp_drop_procedure");
+ DBUG_PRINT("enter", ("name: %*s", namelen, name));
+ sp_head *sp;
+ int ret;
+
+ sp= thd->sp_proc_cache->lookup(name, namelen);
+ if (sp)
+ {
+ thd->sp_proc_cache->remove(sp);
+ delete sp;
+ }
+ ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen);
+
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ *
+ * FUNCTION
+ *
+ */
+
+sp_head *
+sp_find_function(THD *thd, LEX_STRING *name)
+{
+ DBUG_ENTER("sp_find_function");
+ sp_head *sp;
+
+ DBUG_PRINT("enter", ("name: %*s", name->length, name->str));
+
+ sp= thd->sp_func_cache->lookup(name->str, name->length);
+ if (! sp)
+ {
+ if (db_find_routine(thd, TYPE_ENUM_FUNCTION,
+ name->str, name->length, &sp) != SP_OK)
+ sp= NULL;
+ }
+ DBUG_RETURN(sp);
+}
+
+int
+sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen,
+ char *comment, uint commentlen, bool suid)
+{
+ DBUG_ENTER("sp_create_function");
+ DBUG_PRINT("enter", ("name: %*s def: %*s", namelen, name, deflen, def));
+ int ret;
+
+ ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, def, deflen,
+ comment, commentlen, suid);
+
+ DBUG_RETURN(ret);
+}
+
+int
+sp_drop_function(THD *thd, char *name, uint namelen)
+{
+ DBUG_ENTER("sp_drop_function");
+ DBUG_PRINT("enter", ("name: %*s", namelen, name));
+ sp_head *sp;
+ int ret;
+
+ sp= thd->sp_func_cache->lookup(name, namelen);
+ if (sp)
+ {
+ thd->sp_func_cache->remove(sp);
+ delete sp;
+ }
+ ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen);
+
+ DBUG_RETURN(ret);
+}
+
+// QQ Temporary until the function call detection in sql_lex has been reworked.
+bool
+sp_function_exists(THD *thd, LEX_STRING *name)
+{
+ TABLE *table;
+ bool ret= FALSE;
+ bool opened= FALSE;
+
+ if (thd->sp_func_cache->lookup(name->str, name->length) ||
+ db_find_routine_aux(thd, TYPE_ENUM_FUNCTION,
+ name->str, name->length, TL_READ,
+ &table, &opened) == SP_OK)
+ {
+ ret= TRUE;
+ }
+ if (opened)
+ close_thread_tables(thd, 0, 1);
+ return ret;
+}
+
+
+byte *
+sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first)
+{
+ LEX_STRING *lsp= (LEX_STRING *)ptr;
+ *plen= lsp->length;
+ return (byte *)lsp->str;
+}
+
+void
+sp_add_fun_to_lex(LEX *lex, LEX_STRING fun)
+{
+ if (! hash_search(&lex->spfuns, (byte *)fun.str, fun.length))
+ {
+ LEX_STRING *ls= (LEX_STRING *)sql_alloc(sizeof(LEX_STRING));
+ ls->str= sql_strmake(fun.str, fun.length);
+ ls->length= fun.length;
+
+ hash_insert(&lex->spfuns, (byte *)ls);
+ }
+}
+
+void
+sp_merge_funs(LEX *dst, LEX *src)
+{
+ for (uint i=0 ; i < src->spfuns.records ; i++)
+ {
+ LEX_STRING *ls= (LEX_STRING *)hash_element(&src->spfuns, i);
+
+ if (! hash_search(&dst->spfuns, (byte *)ls->str, ls->length))
+ hash_insert(&dst->spfuns, (byte *)ls);
+ }
+}
+
+int
+sp_cache_functions(THD *thd, LEX *lex)
+{
+ HASH *h= &lex->spfuns;
+ int ret= 0;
+
+ for (uint i=0 ; i < h->records ; i++)
+ {
+ LEX_STRING *ls= (LEX_STRING *)hash_element(h, i);
+
+ if (! thd->sp_func_cache->lookup(ls->str, ls->length))
+ {
+ sp_head *sp;
+ LEX *oldlex= thd->lex;
+ LEX *newlex= new st_lex;
+
+ thd->lex= newlex;
+ if (db_find_routine(thd, TYPE_ENUM_FUNCTION, ls->str, ls->length, &sp)
+ == SP_OK)
+ {
+ ret= sp_cache_functions(thd, newlex);
+ delete newlex;
+ thd->lex= oldlex;
+ if (ret)
+ break;
+ thd->sp_func_cache->insert(sp);
+ }
+ else
+ {
+ delete newlex;
+ thd->lex= oldlex;
+ net_printf(thd, ER_SP_DOES_NOT_EXIST, "FUNCTION", ls->str);
+ ret= 1;
+ break;
+ }
+ }
+ }
+ return ret;
+}
diff --git a/sql/sp.h b/sql/sp.h
new file mode 100644
index 00000000000..bbf8832d55d
--- /dev/null
+++ b/sql/sp.h
@@ -0,0 +1,65 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 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 */
+
+#ifndef _SP_H_
+#define _SP_H_
+
+// Return codes from sp_create_* and sp_drop_*:
+#define SP_OK 0
+#define SP_KEY_NOT_FOUND -1
+#define SP_OPEN_TABLE_FAILED -2
+#define SP_WRITE_ROW_FAILED -3
+#define SP_DELETE_ROW_FAILED -4
+#define SP_GET_FIELD_FAILED -5
+#define SP_PARSE_ERROR -6
+
+sp_head *
+sp_find_procedure(THD *thd, LEX_STRING *name);
+
+int
+sp_create_procedure(THD *thd, char *name, uint namelen, char *def, uint deflen,
+ char *comment, uint commentlen, bool suid);
+
+int
+sp_drop_procedure(THD *thd, char *name, uint namelen);
+
+
+sp_head *
+sp_find_function(THD *thd, LEX_STRING *name);
+
+int
+sp_create_function(THD *thd, char *name, uint namelen, char *def, uint deflen,
+ char *comment, uint commentlen, bool suid);
+
+int
+sp_drop_function(THD *thd, char *name, uint namelen);
+
+// QQ Temporary until the function call detection in sql_lex has been reworked.
+bool
+sp_function_exists(THD *thd, LEX_STRING *name);
+
+
+// This is needed since we have to read the functions before we
+// do anything else.
+void
+sp_add_fun_to_lex(LEX *lex, LEX_STRING fun);
+void
+sp_merge_funs(LEX *dst, LEX *src);
+int
+sp_cache_functions(THD *thd, LEX *lex);
+
+#endif /* _SP_H_ */
diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc
new file mode 100644
index 00000000000..1b8816ee0f4
--- /dev/null
+++ b/sql/sp_cache.cc
@@ -0,0 +1,53 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sp_cache.h"
+#include "sp_head.h"
+
+static byte *
+hash_get_key_for_sp_head(const byte *ptr, uint *plen,
+ my_bool first)
+{
+ return ((sp_head*)ptr)->name(plen);
+}
+
+sp_cache::sp_cache()
+{
+ init();
+}
+
+sp_cache::~sp_cache()
+{
+ hash_free(&m_hashtable);
+}
+
+void
+sp_cache::init()
+{
+ hash_init(&m_hashtable, system_charset_info, 0, 0, 0,
+ hash_get_key_for_sp_head, 0, 0);
+}
+
+void
+sp_cache::cleanup()
+{
+ hash_free(&m_hashtable);
+}
diff --git a/sql/sp_cache.h b/sql/sp_cache.h
new file mode 100644
index 00000000000..68a97839ed8
--- /dev/null
+++ b/sql/sp_cache.h
@@ -0,0 +1,65 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 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 */
+
+#ifndef _SP_CACHE_H_
+#define _SP_CACHE_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class sp_head;
+
+class sp_cache
+{
+public:
+
+ sp_cache();
+
+ ~sp_cache();
+
+ void
+ init();
+
+ void
+ cleanup();
+
+ inline void
+ insert(sp_head *sp)
+ {
+ hash_insert(&m_hashtable, (const byte *)sp);
+ }
+
+ inline sp_head *
+ lookup(char *name, uint namelen)
+ {
+ return (sp_head *)hash_search(&m_hashtable, (const byte *)name, namelen);
+ }
+
+ inline void
+ remove(sp_head *sp)
+ {
+ hash_delete(&m_hashtable, (byte *)sp);
+ }
+
+private:
+
+ HASH m_hashtable;
+
+}; // class sp_cache
+
+#endif /* _SP_CACHE_H_ */
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
new file mode 100644
index 00000000000..1c2baa1c0dd
--- /dev/null
+++ b/sql/sp_head.cc
@@ -0,0 +1,645 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sp_head.h"
+#include "sp.h"
+#include "sp_pcontext.h"
+#include "sp_rcontext.h"
+
+Item_result
+sp_map_result_type(enum enum_field_types type)
+{
+ switch (type)
+ {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ return INT_RESULT;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ return REAL_RESULT;
+ default:
+ return STRING_RESULT;
+ }
+}
+
+/* Evaluate a (presumed) func item. Always returns an item, the parameter
+** if nothing else.
+*/
+static Item *
+eval_func_item(THD *thd, Item *it, enum enum_field_types type)
+{
+ DBUG_ENTER("eval_func_item");
+ it= it->this_item();
+ DBUG_PRINT("info", ("type: %d", type));
+
+ if (it->fix_fields(thd, 0, &it))
+ {
+ DBUG_PRINT("info", ("fix_fields() failed"));
+ DBUG_RETURN(it); // Shouldn't happen?
+ }
+
+ /* QQ How do we do this? Is there some better way? */
+ if (type == MYSQL_TYPE_NULL)
+ it= new Item_null();
+ else
+ {
+ switch (sp_map_result_type(type)) {
+ case INT_RESULT:
+ DBUG_PRINT("info", ("INT_RESULT: %d", it->val_int()));
+ it= new Item_int(it->val_int());
+ break;
+ case REAL_RESULT:
+ DBUG_PRINT("info", ("REAL_RESULT: %g", it->val()));
+ it= new Item_real(it->val());
+ break;
+ default:
+ {
+ char buffer[MAX_FIELD_WIDTH];
+ String tmp(buffer, sizeof(buffer), it->charset());
+ String *s= it->val_str(&tmp);
+
+ DBUG_PRINT("info",("default result: %*s",s->length(),s->c_ptr_quick()));
+ it= new Item_string(thd->strmake(s->c_ptr_quick(), s->length()),
+ s->length(), it->charset());
+ break;
+ }
+ }
+ }
+
+ DBUG_RETURN(it);
+}
+
+void *
+sp_head::operator new(size_t size)
+{
+ DBUG_ENTER("sp_head::operator new");
+ MEM_ROOT own_root;
+ sp_head *sp;
+
+ bzero((char *)&own_root, sizeof(own_root));
+ init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ sp= (sp_head *)alloc_root(&own_root, size);
+ sp->m_mem_root= own_root;
+
+ DBUG_RETURN(sp);
+}
+
+void
+sp_head::operator delete(void *ptr, size_t size)
+{
+ DBUG_ENTER("sp_head::operator delete");
+ MEM_ROOT own_root;
+ sp_head *sp= (sp_head *)ptr;
+
+ memcpy(&own_root, (const void *)&sp->m_mem_root, sizeof(MEM_ROOT));
+ free_root(&own_root, MYF(0));
+
+ DBUG_VOID_RETURN;
+}
+
+sp_head::sp_head()
+ : Sql_alloc(), m_simple_case(FALSE), m_multi_query(FALSE), m_free_list(NULL)
+{
+ DBUG_ENTER("sp_head::sp_head");
+
+ m_backpatch.empty();
+ m_lex.empty();
+ DBUG_VOID_RETURN;
+}
+
+void
+sp_head::init(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid)
+{
+ DBUG_ENTER("sp_head::init");
+ const char *dstr = (const char*)lex->buf;
+
+ DBUG_PRINT("info", ("name: %*s", name->length, name->str));
+ m_name.length= name->length;
+ m_name.str= lex->thd->strmake(name->str, name->length);
+ m_defstr.length= lex->end_of_query - lex->buf;
+ m_defstr.str= lex->thd->strmake(dstr, m_defstr.length);
+
+ m_comment.length= 0;
+ m_comment.str= 0;
+ if (comment)
+ {
+ m_comment.length= comment->length;
+ m_comment.str= comment->str;
+ }
+
+ m_suid= suid;
+ lex->spcont= m_pcont= new sp_pcontext();
+ my_init_dynamic_array(&m_instr, sizeof(sp_instr *), 16, 8);
+ DBUG_VOID_RETURN;
+}
+
+int
+sp_head::create(THD *thd)
+{
+ DBUG_ENTER("sp_head::create");
+ int ret;
+
+ DBUG_PRINT("info", ("type: %d name: %s def: %s",
+ m_type, m_name.str, m_defstr.str));
+ if (m_type == TYPE_ENUM_FUNCTION)
+ ret= sp_create_function(thd,
+ m_name.str, m_name.length,
+ m_defstr.str, m_defstr.length,
+ m_comment.str, m_comment.length,
+ m_suid);
+ else
+ ret= sp_create_procedure(thd,
+ m_name.str, m_name.length,
+ m_defstr.str, m_defstr.length,
+ m_comment.str, m_comment.length,
+ m_suid);
+
+ DBUG_RETURN(ret);
+}
+
+sp_head::~sp_head()
+{
+ destroy();
+ if (m_thd)
+ restore_thd_mem_root(m_thd);
+}
+
+void
+sp_head::destroy()
+{
+ DBUG_ENTER("sp_head::destroy");
+ DBUG_PRINT("info", ("name: %s", m_name.str));
+ sp_instr *i;
+ LEX *lex;
+
+ for (uint ip = 0 ; (i = get_instr(ip)) ; ip++)
+ delete i;
+ delete_dynamic(&m_instr);
+ m_pcont->destroy();
+ free_items(m_free_list);
+ while ((lex= (LEX *)m_lex.pop()))
+ {
+ if (lex != &m_thd->main_lex) // We got interrupted and have lex'es left
+ delete lex;
+ }
+ DBUG_VOID_RETURN;
+}
+
+int
+sp_head::execute(THD *thd)
+{
+ DBUG_ENTER("sp_head::execute");
+ char olddbname[128];
+ char *olddbptr= thd->db;
+ int ret= 0;
+ uint ip= 0;
+
+ if (olddbptr)
+ {
+ uint i= 0;
+ char *p= olddbptr;
+
+ /* Fast inline strncpy without padding... */
+ while (*p && i < sizeof(olddbname))
+ olddbname[i++]= *p++;
+ if (i == sizeof(olddbname))
+ i-= 1; // QQ Error or warning for truncate?
+ olddbname[i]= '\0';
+ }
+
+ do
+ {
+ sp_instr *i;
+
+ i = get_instr(ip); // Returns NULL when we're done.
+ if (i == NULL)
+ break;
+ DBUG_PRINT("execute", ("Instruction %u", ip));
+ ret= i->execute(thd, &ip);
+ } while (ret == 0 && !thd->killed);
+
+ DBUG_PRINT("info", ("ret=%d killed=%d", ret, thd->killed));
+ if (thd->killed)
+ ret= -1;
+ /* If the DB has changed, the pointer has changed too, but the
+ original thd->db will then have been freed */
+ if (olddbptr && olddbptr != thd->db)
+ {
+ /* QQ Maybe we should issue some special error message or warning here,
+ if this fails?? */
+ if (! thd->killed)
+ ret= mysql_change_db(thd, olddbname);
+ }
+ DBUG_RETURN(ret);
+}
+
+
+int
+sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
+{
+ DBUG_ENTER("sp_head::execute_function");
+ DBUG_PRINT("info", ("function %s", m_name.str));
+ uint csize = m_pcont->max_framesize();
+ uint params = m_pcont->params();
+ sp_rcontext *octx = thd->spcont;
+ sp_rcontext *nctx = NULL;
+ uint i;
+ int ret;
+
+ if (argcount != params)
+ {
+ // Need to use my_printf_error here, or it will not terminate the
+ // invoking query properly.
+ my_printf_error(ER_SP_WRONG_NO_OF_ARGS, ER(ER_SP_WRONG_NO_OF_ARGS), MYF(0),
+ "FUNCTION", m_name.str, params, argcount);
+ DBUG_RETURN(-1);
+ }
+
+ // QQ Should have some error checking here? (types, etc...)
+ nctx= new sp_rcontext(csize);
+ for (i= 0 ; i < params && i < argcount ; i++)
+ {
+ sp_pvar_t *pvar = m_pcont->find_pvar(i);
+
+ nctx->push_item(eval_func_item(thd, *argp++, pvar->type));
+ }
+ // Close tables opened for subselect in argument list
+ close_thread_tables(thd);
+
+ // The rest of the frame are local variables which are all IN.
+ // QQ See comment in execute_procedure below.
+ for (; i < csize ; i++)
+ nctx->push_item(NULL);
+ thd->spcont= nctx;
+
+ ret= execute(thd);
+ if (ret == 0)
+ *resp= nctx->get_result();
+
+ thd->spcont= octx;
+ DBUG_RETURN(ret);
+}
+
+int
+sp_head::execute_procedure(THD *thd, List<Item> *args)
+{
+ DBUG_ENTER("sp_head::execute_procedure");
+ DBUG_PRINT("info", ("procedure %s", m_name.str));
+ int ret;
+ sp_instr *p;
+ uint csize = m_pcont->max_framesize();
+ uint params = m_pcont->params();
+ sp_rcontext *octx = thd->spcont;
+ sp_rcontext *nctx = NULL;
+ my_bool tmp_octx = FALSE; // True if we have allocated a temporary octx
+
+ if (args->elements != params)
+ {
+ net_printf(thd, ER_SP_WRONG_NO_OF_ARGS, "PROCEDURE", m_name.str,
+ params, args->elements);
+ DBUG_RETURN(-1);
+ }
+
+ if (csize > 0)
+ {
+ uint i;
+ List_iterator_fast<Item> li(*args);
+ Item *it;
+
+ nctx = new sp_rcontext(csize);
+ if (! octx)
+ { // Create a temporary old context
+ octx = new sp_rcontext(csize);
+ tmp_octx = TRUE;
+ }
+ // QQ: Should do type checking?
+ for (i = 0 ; (it= li++) && i < params ; i++)
+ {
+ sp_pvar_t *pvar = m_pcont->find_pvar(i);
+
+ if (! pvar)
+ nctx->set_oindex(i, -1); // Shouldn't happen
+ else
+ {
+ if (pvar->mode == sp_param_out)
+ nctx->push_item(NULL); // OUT
+ else
+ nctx->push_item(eval_func_item(thd, it, pvar->type)); // IN or INOUT
+ // Note: If it's OUT or INOUT, it must be a variable.
+ // QQ: Need to handle "global" user/host variables too!!!
+ if (pvar->mode == sp_param_in)
+ nctx->set_oindex(i, -1); // IN
+ else // OUT or INOUT
+ nctx->set_oindex(i, static_cast<Item_splocal *>(it)->get_offset());
+ }
+ }
+ // Close tables opened for subselect in argument list
+ close_thread_tables(thd);
+
+ // The rest of the frame are local variables which are all IN.
+ // QQ We haven't found any hint of what the value is when unassigned,
+ // so we set it to NULL for now. It's an error to refer to an
+ // unassigned variable anyway (which should be detected by the parser).
+ for (; i < csize ; i++)
+ nctx->push_item(NULL);
+ thd->spcont= nctx;
+ }
+
+ ret= execute(thd);
+
+ // Don't copy back OUT values if we got an error
+ if (ret == 0 && csize > 0)
+ {
+ List_iterator_fast<Item> li(*args);
+ Item *it;
+
+ // Copy back all OUT or INOUT values to the previous frame, or
+ // set global user variables
+ for (uint i = 0 ; (it= li++) && i < params ; i++)
+ {
+ int oi = nctx->get_oindex(i);
+
+ if (oi >= 0)
+ {
+ if (! tmp_octx)
+ octx->set_item(nctx->get_oindex(i), nctx->get_item(i));
+ else
+ { // A global user variable
+#if NOT_USED_NOW
+ // QQ This works if the parameter really is a user variable, but
+ // for the moment we can't assure that, so it will crash if it's
+ // something else. So for now, we just do nothing, to avoid a crash.
+ // Note: This also assumes we have a get_name() method in
+ // the Item_func_get_user_var class.
+ Item *item= nctx->get_item(i);
+ Item_func_set_user_var *suv;
+ Item_func_get_user_var *guv= static_cast<Item_func_get_user_var*>(it);
+
+ suv= new Item_func_set_user_var(guv->get_name(), item);
+ suv->fix_fields(thd, NULL, &item);
+ suv->fix_length_and_dec();
+ suv->update();
+#endif
+ }
+ }
+ }
+
+ if (tmp_octx)
+ thd->spcont= NULL;
+ else
+ thd->spcont= octx;
+ }
+
+ DBUG_RETURN(ret);
+}
+
+
+// Reset lex during parsing, before we parse a sub statement.
+void
+sp_head::reset_lex(THD *thd)
+{
+ DBUG_ENTER("sp_head::reset_lex");
+ LEX *sublex;
+ LEX *oldlex= thd->lex;
+
+ (void)m_lex.push_front(oldlex);
+ thd->lex= sublex= new st_lex;
+ sublex->yylineno= oldlex->yylineno;
+ /* Reset most stuff. The length arguments doesn't matter here. */
+ lex_start(thd, oldlex->buf, oldlex->end_of_query - oldlex->ptr);
+ /* We must reset ptr and end_of_query again */
+ sublex->ptr= oldlex->ptr;
+ sublex->end_of_query= oldlex->end_of_query;
+ sublex->tok_start= oldlex->tok_start;
+ /* And keep the SP stuff too */
+ sublex->sphead= oldlex->sphead;
+ sublex->spcont= oldlex->spcont;
+ mysql_init_query(thd, true); // Only init lex
+ sublex->sp_lex_in_use= FALSE;
+ DBUG_VOID_RETURN;
+}
+
+// Restore lex during parsing, after we have parsed a sub statement.
+void
+sp_head::restore_lex(THD *thd)
+{
+ DBUG_ENTER("sp_head::restore_lex");
+ LEX *sublex= thd->lex;
+ LEX *oldlex= (LEX *)m_lex.pop();
+
+ if (! oldlex)
+ return; // Nothing to restore
+
+ // Update some state in the old one first
+ oldlex->ptr= sublex->ptr;
+ oldlex->next_state= sublex->next_state;
+
+ // Collect some data from the sub statement lex.
+ sp_merge_funs(oldlex, sublex);
+#ifdef NOT_USED_NOW
+ // QQ We're not using this at the moment.
+ if (sublex.sql_command == SQLCOM_CALL)
+ {
+ // It would be slightly faster to keep the list sorted, but we need
+ // an "insert before" method to do that.
+ char *proc= sublex.udf.name.str;
+
+ List_iterator_fast<char *> li(m_calls);
+ char **it;
+
+ while ((it= li++))
+ if (my_strcasecmp(system_charset_info, proc, *it) == 0)
+ break;
+ if (! it)
+ m_calls.push_back(&proc);
+
+ }
+ // Merge used tables
+ // QQ ...or just open tables in thd->open_tables?
+ // This is not entirerly clear at the moment, but for now, we collect
+ // tables here.
+ for (SELECT_LEX *sl= sublex.all_selects_list ;
+ sl ;
+ sl= sl->next_select())
+ {
+ for (TABLE_LIST *tables= sl->get_table_list() ;
+ tables ;
+ tables= tables->next)
+ {
+ List_iterator_fast<char *> li(m_tables);
+ char **tb;
+
+ while ((tb= li++))
+ if (my_strcasecmp(system_charset_info, tables->real_name, *tb) == 0)
+ break;
+ if (! tb)
+ m_tables.push_back(&tables->real_name);
+ }
+ }
+#endif
+ if (! sublex->sp_lex_in_use)
+ delete sublex;
+ thd->lex= oldlex;
+ DBUG_VOID_RETURN;
+}
+
+void
+sp_head::push_backpatch(sp_instr *i, sp_label_t *lab)
+{
+ bp_t *bp= (bp_t *)sql_alloc(sizeof(bp_t));
+
+ if (bp)
+ {
+ bp->lab= lab;
+ bp->instr= i;
+ (void)m_backpatch.push_front(bp);
+ }
+}
+
+void
+sp_head::backpatch(sp_label_t *lab)
+{
+ bp_t *bp;
+ uint dest= instructions();
+ List_iterator_fast<bp_t> li(m_backpatch);
+
+ while ((bp= li++))
+ if (bp->lab == lab)
+ {
+ sp_instr_jump *i= static_cast<sp_instr_jump *>(bp->instr);
+
+ i->set_destination(dest);
+ }
+}
+
+
+// ------------------------------------------------------------------
+
+//
+// sp_instr_stmt
+//
+sp_instr_stmt::~sp_instr_stmt()
+{
+ if (m_lex)
+ delete m_lex;
+}
+
+int
+sp_instr_stmt::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_stmt::execute");
+ DBUG_PRINT("info", ("command: %d", m_lex->sql_command));
+ LEX *olex; // The other lex
+ int res;
+
+ olex= thd->lex; // Save the other lex
+ thd->lex= m_lex; // Use my own lex
+ thd->lex->thd = thd; // QQ Not reentrant!
+ thd->lex->unit.thd= thd; // QQ Not reentrant
+
+ res= mysql_execute_command(thd);
+ if (thd->lock || thd->open_tables || thd->derived_tables)
+ {
+ thd->proc_info="closing tables";
+ close_thread_tables(thd); /* Free tables */
+ }
+
+ thd->lex= olex; // Restore the other lex
+
+ *nextp = m_ip+1;
+ DBUG_RETURN(res);
+}
+
+//
+// sp_instr_set
+//
+int
+sp_instr_set::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_set::execute");
+ DBUG_PRINT("info", ("offset: %u", m_offset));
+ thd->spcont->set_item(m_offset, eval_func_item(thd, m_value, m_type));
+ *nextp = m_ip+1;
+ DBUG_RETURN(0);
+}
+
+//
+// sp_instr_jump
+//
+int
+sp_instr_jump::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_jump::execute");
+ DBUG_PRINT("info", ("destination: %u", m_dest));
+
+ *nextp= m_dest;
+ DBUG_RETURN(0);
+}
+
+//
+// sp_instr_jump_if
+//
+int
+sp_instr_jump_if::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_jump_if::execute");
+ DBUG_PRINT("info", ("destination: %u", m_dest));
+ Item *it= eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
+
+ if (it->val_int())
+ *nextp = m_dest;
+ else
+ *nextp = m_ip+1;
+ DBUG_RETURN(0);
+}
+
+//
+// sp_instr_jump_if_not
+//
+int
+sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_jump_if_not::execute");
+ DBUG_PRINT("info", ("destination: %u", m_dest));
+ Item *it= eval_func_item(thd, m_expr, MYSQL_TYPE_TINY);
+
+ if (! it->val_int())
+ *nextp = m_dest;
+ else
+ *nextp = m_ip+1;
+ DBUG_RETURN(0);
+}
+
+//
+// sp_instr_return
+//
+int
+sp_instr_return::execute(THD *thd, uint *nextp)
+{
+ DBUG_ENTER("sp_instr_return::execute");
+ thd->spcont->set_result(eval_func_item(thd, m_value, m_type));
+ *nextp= UINT_MAX;
+ DBUG_RETURN(0);
+}
diff --git a/sql/sp_head.h b/sql/sp_head.h
new file mode 100644
index 00000000000..bdb9e2e4eb1
--- /dev/null
+++ b/sql/sp_head.h
@@ -0,0 +1,411 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 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 */
+
+#ifndef _SP_HEAD_H_
+#define _SP_HEAD_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#include <stddef.h>
+
+// Values for the type enum. This reflects the order of the enum declaration
+// in the CREATE TABLE command.
+#define TYPE_ENUM_FUNCTION 1
+#define TYPE_ENUM_PROCEDURE 2
+
+Item_result
+sp_map_result_type(enum enum_field_types type);
+
+struct sp_label;
+
+class sp_instr;
+
+class sp_head : public Sql_alloc
+{
+ sp_head(const sp_head &); /* Prevent use of these */
+ void operator=(sp_head &);
+
+public:
+
+ int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE
+ enum enum_field_types m_returns; // For FUNCTIONs only
+ my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
+ my_bool m_multi_query; // TRUE if a procedure with SELECT(s)
+ uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
+#if NOT_USED_NOW
+ // QQ We're not using this at the moment.
+ List<char *> m_calls; // Called procedures.
+ List<char *> m_tables; // Used tables.
+#endif
+
+ static void *
+ operator new(size_t size);
+
+ static void
+ operator delete(void *ptr, size_t size);
+
+ sp_head();
+
+ // Initialize after we have reset mem_root
+ void
+ init(LEX_STRING *name, LEX *lex, LEX_STRING *comment, char suid);
+
+ int
+ create(THD *thd);
+
+ virtual ~sp_head();
+
+ // Free memory
+ void
+ destroy();
+
+ int
+ execute_function(THD *thd, Item **args, uint argcount, Item **resp);
+
+ int
+ execute_procedure(THD *thd, List<Item> *args);
+
+ inline void
+ add_instr(sp_instr *i)
+ {
+ insert_dynamic(&m_instr, (gptr)&i);
+ }
+
+ inline uint
+ instructions()
+ {
+ return m_instr.elements;
+ }
+
+ // Resets lex in 'thd' and keeps a copy of the old one.
+ void
+ reset_lex(THD *thd);
+
+ // Restores lex in 'thd' from our copy, but keeps some status from the
+ // one in 'thd', like ptr, tables, fields, etc.
+ void
+ restore_lex(THD *thd);
+
+ // Put the instruction on the backpatch list, associated with the label.
+ void
+ push_backpatch(sp_instr *, struct sp_label *);
+
+ // Update all instruction with this label in the backpatch list to
+ // the current position.
+ void
+ backpatch(struct sp_label *);
+
+ char *name(uint *lenp = 0) const
+ {
+ if (lenp)
+ *lenp= m_name.length;
+ return m_name.str;
+ }
+
+ inline Item_result result()
+ {
+ return sp_map_result_type(m_returns);
+ }
+
+ void sp_set_info(char *creator, uint creatorlen,
+ longlong created, longlong modified,
+ bool suid, char *comment, uint commentlen)
+ {
+ m_creator= creator;
+ m_creatorlen= creatorlen;
+ m_created= created;
+ m_modified= modified;
+ m_comment.length= commentlen;
+ m_comment.str= comment;
+ m_suid= suid;
+ }
+
+ inline void reset_thd_mem_root(THD *thd)
+ {
+ m_thd_root= thd->mem_root;
+ thd->mem_root= m_mem_root;
+ m_free_list= thd->free_list; // Keep the old list
+ thd->free_list= NULL; // Start a new one
+ m_thd= thd;
+ }
+
+ inline void restore_thd_mem_root(THD *thd)
+ {
+ Item *flist= m_free_list; // The old list
+ m_free_list= thd->free_list; // Get the new one
+ thd->free_list= flist; // Restore the old one
+ m_mem_root= thd->mem_root;
+ thd->mem_root= m_thd_root;
+ m_thd= NULL;
+ }
+
+private:
+
+ MEM_ROOT m_mem_root; // My own mem_root
+ MEM_ROOT m_thd_root; // Temp. store for thd's mem_root
+ Item *m_free_list; // Where the items go
+ THD *m_thd; // Set if we have reset mem_root
+
+ LEX_STRING m_name;
+ LEX_STRING m_defstr;
+ LEX_STRING m_comment;
+ char *m_creator;
+ uint m_creatorlen;
+ longlong m_created;
+ longlong m_modified;
+ bool m_suid;
+
+ sp_pcontext *m_pcont; // Parse context
+ List<LEX> m_lex; // Temp. store for the other lex
+ DYNAMIC_ARRAY m_instr; // The "instructions"
+ typedef struct
+ {
+ struct sp_label *lab;
+ sp_instr *instr;
+ } bp_t;
+ List<bp_t> m_backpatch; // Instructions needing backpatching
+
+ inline sp_instr *
+ get_instr(uint i)
+ {
+ sp_instr *ip;
+
+ if (i < m_instr.elements)
+ get_dynamic(&m_instr, (gptr)&ip, i);
+ else
+ ip= NULL;
+ return ip;
+ }
+
+ int
+ execute(THD *thd);
+
+}; // class sp_head : public Sql_alloc
+
+
+//
+// "Instructions"...
+//
+
+class sp_instr : public Sql_alloc
+{
+ sp_instr(const sp_instr &); /* Prevent use of these */
+ void operator=(sp_instr &);
+
+public:
+
+ // Should give each a name or type code for debugging purposes?
+ sp_instr(uint ip)
+ : Sql_alloc(), m_ip(ip)
+ {}
+
+ virtual ~sp_instr()
+ {}
+
+ // Execute this instrution. '*nextp' will be set to the index of the next
+ // instruction to execute. (For most instruction this will be the
+ // instruction following this one.)
+ // Returns 0 on success, non-zero if some error occured.
+ virtual int
+ execute(THD *thd, uint *nextp)
+ { // Default is a no-op.
+ *nextp = m_ip+1; // Next instruction
+ return 0;
+ }
+
+protected:
+
+ uint m_ip; // My index
+
+}; // class sp_instr : public Sql_alloc
+
+
+//
+// Call out to some prepared SQL statement.
+//
+class sp_instr_stmt : public sp_instr
+{
+ sp_instr_stmt(const sp_instr_stmt &); /* Prevent use of these */
+ void operator=(sp_instr_stmt &);
+
+public:
+
+ sp_instr_stmt(uint ip)
+ : sp_instr(ip), m_lex(NULL)
+ {}
+
+ virtual ~sp_instr_stmt();
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ inline void
+ set_lex(LEX *lex)
+ {
+ m_lex= lex;
+ }
+
+ inline LEX *
+ get_lex()
+ {
+ return m_lex;
+ }
+
+private:
+
+ LEX *m_lex; // My own lex
+
+}; // class sp_instr_stmt : public sp_instr
+
+
+class sp_instr_set : public sp_instr
+{
+ sp_instr_set(const sp_instr_set &); /* Prevent use of these */
+ void operator=(sp_instr_set &);
+
+public:
+
+ sp_instr_set(uint ip, uint offset, Item *val, enum enum_field_types type)
+ : sp_instr(ip), m_offset(offset), m_value(val), m_type(type)
+ {}
+
+ virtual ~sp_instr_set()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+private:
+
+ uint m_offset; // Frame offset
+ Item *m_value;
+ enum enum_field_types m_type; // The declared type
+
+}; // class sp_instr_set : public sp_instr
+
+
+class sp_instr_jump : public sp_instr
+{
+ sp_instr_jump(const sp_instr_jump &); /* Prevent use of these */
+ void operator=(sp_instr_jump &);
+
+public:
+
+ sp_instr_jump(uint ip)
+ : sp_instr(ip)
+ {}
+
+ sp_instr_jump(uint ip, uint dest)
+ : sp_instr(ip), m_dest(dest)
+ {}
+
+ virtual ~sp_instr_jump()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void
+ set_destination(uint dest)
+ {
+ m_dest= dest;
+ }
+
+protected:
+
+ int m_dest; // Where we will go
+
+}; // class sp_instr_jump : public sp_instr
+
+
+class sp_instr_jump_if : public sp_instr_jump
+{
+ sp_instr_jump_if(const sp_instr_jump_if &); /* Prevent use of these */
+ void operator=(sp_instr_jump_if &);
+
+public:
+
+ sp_instr_jump_if(uint ip, Item *i)
+ : sp_instr_jump(ip), m_expr(i)
+ {}
+
+ sp_instr_jump_if(uint ip, Item *i, uint dest)
+ : sp_instr_jump(ip, dest), m_expr(i)
+ {}
+
+ virtual ~sp_instr_jump_if()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+private:
+
+ Item *m_expr; // The condition
+
+}; // class sp_instr_jump_if : public sp_instr_jump
+
+
+class sp_instr_jump_if_not : public sp_instr_jump
+{
+ sp_instr_jump_if_not(const sp_instr_jump_if_not &); /* Prevent use of these */
+ void operator=(sp_instr_jump_if_not &);
+
+public:
+
+ sp_instr_jump_if_not(uint ip, Item *i)
+ : sp_instr_jump(ip), m_expr(i)
+ {}
+
+ sp_instr_jump_if_not(uint ip, Item *i, uint dest)
+ : sp_instr_jump(ip, dest), m_expr(i)
+ {}
+
+ virtual ~sp_instr_jump_if_not()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+private:
+
+ Item *m_expr; // The condition
+
+}; // class sp_instr_jump_if_not : public sp_instr_jump
+
+
+class sp_instr_return : public sp_instr
+{
+ sp_instr_return(const sp_instr_return &); /* Prevent use of these */
+ void operator=(sp_instr_return &);
+
+public:
+
+ sp_instr_return(uint ip, Item *val, enum enum_field_types type)
+ : sp_instr(ip), m_value(val), m_type(type)
+ {}
+
+ virtual ~sp_instr_return()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+protected:
+
+ Item *m_value;
+ enum enum_field_types m_type;
+
+}; // class sp_instr_return : public sp_instr
+
+#endif /* _SP_HEAD_H_ */
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
new file mode 100644
index 00000000000..3973f05b74b
--- /dev/null
+++ b/sql/sp_pcontext.cc
@@ -0,0 +1,115 @@
+/* Copyright (C) 2002 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 */
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#if defined(WIN32) || defined(__WIN__)
+#undef SAFEMALLOC /* Problems with threads */
+#endif
+
+#include "mysql_priv.h"
+#include "sp_pcontext.h"
+#include "sp_head.h"
+
+sp_pcontext::sp_pcontext()
+ : Sql_alloc(), m_params(0), m_framesize(0), m_genlab(0)
+{
+ VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
+ m_label.empty();
+}
+
+void
+sp_pcontext::destroy()
+{
+ delete_dynamic(&m_pvar);
+ m_label.empty();
+}
+
+
+/* This does a linear search (from newer to older variables, in case
+** we have shadowed names).
+** It's possible to have a more efficient allocation and search method,
+** but it might not be worth it. The typical number of parameters and
+** variables will in most cases be low (a handfull).
+** And this is only called during parsing.
+*/
+sp_pvar_t *
+sp_pcontext::find_pvar(LEX_STRING *name)
+{
+ uint i = m_pvar.elements;
+
+ while (i-- > 0)
+ {
+ sp_pvar_t *p= find_pvar(i);
+
+ if (my_strnncoll(system_charset_info,
+ (const uchar *)name->str, name->length,
+ (const uchar *)p->name.str, p->name.length) == 0)
+ {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+void
+sp_pcontext::push(LEX_STRING *name, enum enum_field_types type,
+ sp_param_mode_t mode)
+{
+ sp_pvar_t *p= (sp_pvar_t *)sql_alloc(sizeof(sp_pvar_t));
+
+ if (p)
+ {
+ if (m_pvar.elements == m_framesize)
+ m_framesize += 1;
+ p->name.str= name->str;
+ p->name.length= name->length;
+ p->type= type;
+ p->mode= mode;
+ p->offset= m_pvar.elements;
+ p->isset= (mode == sp_param_out ? FALSE : TRUE);
+ insert_dynamic(&m_pvar, (gptr)&p);
+ }
+}
+
+sp_label_t *
+sp_pcontext::push_label(char *name, uint ip)
+{
+ sp_label_t *lab = (sp_label_t *)sql_alloc(sizeof(sp_label_t));
+
+ if (lab)
+ {
+ lab->name= name;
+ lab->ip= ip;
+ m_label.push_front(lab);
+ }
+ return lab;
+}
+
+sp_label_t *
+sp_pcontext::find_label(char *name)
+{
+ List_iterator_fast<sp_label_t> li(m_label);
+ sp_label_t *lab;
+
+ while ((lab= li++))
+ if (my_strcasecmp(system_charset_info, name, lab->name) == 0)
+ return lab;
+
+ return NULL;
+}
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
new file mode 100644
index 00000000000..6900e18aa93
--- /dev/null
+++ b/sql/sp_pcontext.h
@@ -0,0 +1,162 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 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 */
+
+#ifndef _SP_PCONTEXT_H_
+#define _SP_PCONTEXT_H_
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+typedef enum
+{
+ sp_param_in,
+ sp_param_out,
+ sp_param_inout
+} sp_param_mode_t;
+
+typedef struct
+{
+ LEX_STRING name;
+ enum enum_field_types type;
+ sp_param_mode_t mode;
+ uint offset; // Offset in current frame
+ my_bool isset;
+} sp_pvar_t;
+
+typedef struct sp_label
+{
+ char *name;
+ uint ip; // Instruction index
+} sp_label_t;
+
+class sp_pcontext : public Sql_alloc
+{
+ sp_pcontext(const sp_pcontext &); /* Prevent use of these */
+ void operator=(sp_pcontext &);
+
+ public:
+
+ sp_pcontext();
+
+ // Free memory
+ void
+ destroy();
+
+ inline uint
+ max_framesize()
+ {
+ return m_framesize;
+ }
+
+ inline uint
+ current_framesize()
+ {
+ return m_pvar.elements;
+ }
+
+ inline uint
+ params()
+ {
+ return m_params;
+ }
+
+ // Set the number of parameters to the current esize
+ inline void
+ set_params()
+ {
+ m_params= m_pvar.elements;
+ }
+
+ inline void
+ set_type(uint i, enum enum_field_types type)
+ {
+ sp_pvar_t *p= find_pvar(i);
+
+ if (p)
+ p->type= type;
+ }
+
+ inline void
+ set_isset(uint i, my_bool val)
+ {
+ sp_pvar_t *p= find_pvar(i);
+
+ if (p)
+ p->isset= val;
+ }
+
+ void
+ push(LEX_STRING *name, enum enum_field_types type, sp_param_mode_t mode);
+
+ // Pop the last 'num' slots of the frame
+ inline void
+ pop(uint num = 1)
+ {
+ while (num--)
+ pop_dynamic(&m_pvar);
+ }
+
+ // Find by name
+ sp_pvar_t *
+ find_pvar(LEX_STRING *name);
+
+ // Find by index
+ sp_pvar_t *
+ find_pvar(uint i)
+ {
+ sp_pvar_t *p;
+
+ if (i < m_pvar.elements)
+ get_dynamic(&m_pvar, (gptr)&p, i);
+ else
+ p= NULL;
+ return p;
+ }
+
+ sp_label_t *
+ push_label(char *name, uint ip);
+
+ sp_label_t *
+ find_label(char *name);
+
+ inline sp_label_t *
+ last_label()
+ {
+ return m_label.head();
+ }
+
+ inline sp_label_t *
+ pop_label()
+ {
+ return m_label.pop();
+ }
+
+private:
+
+ uint m_params; // The number of parameters
+ uint m_framesize; // The maximum framesize
+
+ DYNAMIC_ARRAY m_pvar;
+
+ List<sp_label_t> m_label; // The label list
+ uint m_genlab; // Gen. label counter
+
+}; // class sp_pcontext : public Sql_alloc
+
+
+#endif /* _SP_PCONTEXT_H_ */
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
new file mode 100644
index 00000000000..78485fdd090
--- /dev/null
+++ b/sql/sp_rcontext.h
@@ -0,0 +1,95 @@
+/* -*- C++ -*- */
+/* Copyright (C) 2002 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 */
+
+#ifndef _SP_RCONTEXT_H_
+#define _SP_RCONTEXT_H_
+
+class sp_rcontext : public Sql_alloc
+{
+ sp_rcontext(const sp_rcontext &); /* Prevent use of these */
+ void operator=(sp_rcontext &);
+
+ public:
+
+ sp_rcontext(uint size)
+ : m_count(0), m_size(size), m_result(NULL)
+ {
+ m_frame = (Item **)sql_alloc(size * sizeof(Item*));
+ m_outs = (int *)sql_alloc(size * sizeof(int));
+ }
+
+ ~sp_rcontext()
+ {
+ // Not needed?
+ //sql_element_free(m_frame);
+ }
+
+ inline void
+ push_item(Item *i)
+ {
+ if (m_count < m_size)
+ m_frame[m_count++] = i;
+ }
+
+ inline void
+ set_item(uint idx, Item *i)
+ {
+ if (idx < m_count)
+ m_frame[idx] = i;
+ }
+
+ inline Item *
+ get_item(uint idx)
+ {
+ return m_frame[idx];
+ }
+
+ inline void
+ set_oindex(uint idx, int oidx)
+ {
+ m_outs[idx] = oidx;
+ }
+
+ inline int
+ get_oindex(uint idx)
+ {
+ return m_outs[idx];
+ }
+
+ inline void
+ set_result(Item *it)
+ {
+ m_result= it;
+ }
+
+ inline Item *
+ get_result()
+ {
+ return m_result;
+ }
+
+private:
+
+ uint m_count;
+ uint m_size;
+ Item **m_frame;
+ int *m_outs;
+ Item *m_result; // For FUNCTIONs
+
+}; // class sp_rcontext : public Sql_alloc
+
+#endif /* _SP_RCONTEXT_H_ */
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 9738c0c5d9e..81fdeb0943a 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1202,7 +1202,6 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->user ? acl_user->user : "",
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
- mysql_update_log.write(thd, buff, query_length);
Query_log_event qinfo(thd, buff, query_length, 0);
mysql_bin_log.write(&qinfo);
DBUG_RETURN(0);
@@ -1465,7 +1464,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (table->fields >= 31) /* From 4.0.0 we have more fields */
{
/* We write down SSL related ACL stuff */
- switch (thd->lex.ssl_type) {
+ switch (thd->lex->ssl_type) {
case SSL_TYPE_ANY:
table->field[24]->store("ANY",3, &my_charset_latin1);
table->field[25]->store("", 0, &my_charset_latin1);
@@ -1483,15 +1482,15 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
table->field[25]->store("", 0, &my_charset_latin1);
table->field[26]->store("", 0, &my_charset_latin1);
table->field[27]->store("", 0, &my_charset_latin1);
- if (thd->lex.ssl_cipher)
- table->field[25]->store(thd->lex.ssl_cipher,
- strlen(thd->lex.ssl_cipher), &my_charset_latin1);
- if (thd->lex.x509_issuer)
- table->field[26]->store(thd->lex.x509_issuer,
- strlen(thd->lex.x509_issuer), &my_charset_latin1);
- if (thd->lex.x509_subject)
- table->field[27]->store(thd->lex.x509_subject,
- strlen(thd->lex.x509_subject), &my_charset_latin1);
+ if (thd->lex->ssl_cipher)
+ table->field[25]->store(thd->lex->ssl_cipher,
+ strlen(thd->lex->ssl_cipher), &my_charset_latin1);
+ if (thd->lex->x509_issuer)
+ table->field[26]->store(thd->lex->x509_issuer,
+ strlen(thd->lex->x509_issuer), &my_charset_latin1);
+ if (thd->lex->x509_subject)
+ table->field[27]->store(thd->lex->x509_subject,
+ strlen(thd->lex->x509_subject), &my_charset_latin1);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
@@ -1503,7 +1502,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
break;
}
- USER_RESOURCES mqh = thd->lex.mqh;
+ USER_RESOURCES mqh = thd->lex->mqh;
if (mqh.bits & 1)
table->field[28]->store((longlong) mqh.questions);
if (mqh.bits & 2)
@@ -1546,19 +1545,19 @@ end:
password=0; // No password given on command
if (old_row_exists)
acl_update_user(combo.user.str,combo.host.str,password,
- thd->lex.ssl_type,
- thd->lex.ssl_cipher,
- thd->lex.x509_issuer,
- thd->lex.x509_subject,
- &thd->lex.mqh,
+ thd->lex->ssl_type,
+ thd->lex->ssl_cipher,
+ thd->lex->x509_issuer,
+ thd->lex->x509_subject,
+ &thd->lex->mqh,
rights);
else
acl_insert_user(combo.user.str,combo.host.str,password,
- thd->lex.ssl_type,
- thd->lex.ssl_cipher,
- thd->lex.x509_issuer,
- thd->lex.x509_subject,
- &thd->lex.mqh,
+ thd->lex->ssl_type,
+ thd->lex->ssl_cipher,
+ thd->lex->x509_issuer,
+ thd->lex->x509_subject,
+ &thd->lex->mqh,
rights);
}
table->file->index_end();
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index dc6e791c4be..475a40414a7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2147,7 +2147,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
- thd->lex.current_select->cond_count= 0;
+ thd->lex->current_select->cond_count= 0;
if (*conds)
{
thd->where="where clause";
@@ -2166,7 +2166,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
if (table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
table->on_expr->check_cols(1))
DBUG_RETURN(1);
- thd->lex.current_select->cond_count++;
+ thd->lex->current_select->cond_count++;
/*
If it's a normal join or a LEFT JOIN which can be optimized away
@@ -2218,7 +2218,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
}
}
cond_and->used_tables_cache= t1->map | t2->map;
- thd->lex.current_select->cond_count+=cond_and->list.elements;
+ thd->lex->current_select->cond_count+=cond_and->list.elements;
if (!table->outer_join) // Not left join
{
if (!(*conds=and_conds(*conds, cond_and)))
@@ -2426,7 +2426,7 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
/* Kill delayed insert threads */
if (in_use->system_thread && ! in_use->killed)
{
- in_use->killed=1;
+ in_use->killed= THD::KILL_CONNECTION;
pthread_mutex_lock(&in_use->mysys_var->mutex);
if (in_use->mysys_var->current_cond)
{
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 64e8be8e224..dc8c4690c16 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -761,7 +761,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
uint8 tables_type= 0;
if ((local_tables= is_cacheable(thd, thd->query_length,
- thd->query, &thd->lex, tables_used,
+ thd->query, thd->lex, tables_used,
&tables_type)))
{
NET *net= &thd->net;
@@ -897,7 +897,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/* Check that we haven't forgot to reset the query cache variables */
DBUG_ASSERT(thd->net.query_cache_query == 0);
- if (!thd->lex.safe_to_cache_query)
+ if (!thd->lex->safe_to_cache_query)
{
DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
goto err;
@@ -905,11 +905,16 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/*
Test if the query is a SELECT
- (pre-space is removed in dispatch_command)
+ (pre-space is removed in dispatch_command).
+
+ First '/' looks like comment before command it is not
+ frequently appeared in real lihe, consequently we can
+ check all such queries, too.
*/
- if (my_toupper(system_charset_info, sql[0]) != 'S' ||
- my_toupper(system_charset_info, sql[1]) != 'E' ||
- my_toupper(system_charset_info,sql[2]) !='L')
+ if ((my_toupper(system_charset_info, sql[0]) != 'S' ||
+ my_toupper(system_charset_info, sql[1]) != 'E' ||
+ my_toupper(system_charset_info,sql[2]) !='L') &&
+ sql[0] != '/')
{
DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
goto err;
@@ -1000,7 +1005,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
table_list.db, table_list.alias));
refused++; // This is actually a hit
STRUCT_UNLOCK(&structure_guard_mutex);
- thd->lex.safe_to_cache_query=0; // Don't try to cache this
+ thd->lex->safe_to_cache_query=0; // Don't try to cache this
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(-1); // Privilege error
}
@@ -1009,7 +1014,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
- thd->lex.safe_to_cache_query= 0; // Don't try to cache this
+ thd->lex->safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
if (check_tables && !handler::caching_allowed(thd, table->db(),
@@ -1019,7 +1024,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
- thd->lex.safe_to_cache_query= 0; // Don't try to cache this
+ thd->lex->safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
else
@@ -2959,7 +2964,7 @@ void Query_cache::wreck(uint line, const char *message)
DBUG_PRINT("warning", ("%5d QUERY CACHE WRECK => DISABLED",line));
DBUG_PRINT("warning", ("=================================="));
if (thd)
- thd->killed = 1;
+ thd->killed= THD::KILL_CONNECTION;
cache_dump();
/* check_integrity(0); */ /* Can't call it here because of locks */
bins_dump();
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 763408dc5c2..fe7cd551f13 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -36,6 +36,9 @@
#endif
#include <mysys_err.h>
+#include <sp_rcontext.h>
+#include <sp_cache.h>
+
/*
The following is used to initialise Table_ident with a internal
table name
@@ -86,12 +89,14 @@ extern "C" void free_user_var(user_var_entry *entry)
THD::THD():user_time(0), is_fatal_error(0),
last_insert_id_used(0),
insert_id_used(0), rand_used(0), in_lock_tables(0),
- global_read_lock(0), bootstrap(0)
+ global_read_lock(0), bootstrap(0), spcont(NULL)
{
+ lex= &main_lex;
host=user=priv_user=db=query=ip=0;
host_or_ip= "connecting host";
- locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
+ locked=count_cuted_fields=some_tables_deleted=no_errors=password=
query_start_used=prepare_command=0;
+ killed= NOT_KILLED;
db_length=query_length=col_access=0;
query_error= tmp_table_used= 0;
next_insert_id=last_insert_id=0;
@@ -147,9 +152,12 @@ THD::THD():user_time(0), is_fatal_error(0),
bzero((char*) &warn_root,sizeof(warn_root));
init_alloc_root(&warn_root, 1024, 0);
user_connect=(USER_CONN *)0;
- hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
+ hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
- (hash_free_key) free_user_var,0);
+ (hash_free_key) free_user_var, 0);
+
+ sp_proc_cache= new sp_cache();
+ sp_func_cache= new sp_cache();
/* For user vars replication*/
if (opt_bin_log)
@@ -178,7 +186,7 @@ THD::THD():user_time(0), is_fatal_error(0),
if (open_cached_file(&transaction.trans_log,
mysql_tmpdir, LOG_PREFIX, binlog_cache_size,
MYF(MY_WME)))
- killed=1;
+ killed= KILL_CONNECTION;
transaction.trans_log.end_of_file= max_binlog_cache_size;
}
#endif
@@ -249,9 +257,11 @@ void THD::change_user(void)
cleanup();
cleanup_done= 0;
init();
- hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0,
+ hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(hash_free_key) free_user_var, 0);
+ sp_proc_cache->init();
+ sp_func_cache->init();
}
@@ -275,6 +285,8 @@ void THD::cleanup(void)
close_temporary_tables(this);
delete_dynamic(&user_var_events);
hash_free(&user_vars);
+ sp_proc_cache->cleanup();
+ sp_func_cache->cleanup();
if (global_read_lock)
unlock_global_read_lock(this);
if (ull)
@@ -284,6 +296,7 @@ void THD::cleanup(void)
pthread_mutex_unlock(&LOCK_user_locks);
ull= 0;
}
+
cleanup_done=1;
DBUG_VOID_RETURN;
}
@@ -315,6 +328,9 @@ THD::~THD()
}
#endif
+ delete sp_proc_cache;
+ delete sp_func_cache;
+
DBUG_PRINT("info", ("freeing host"));
if (host != localhost) // If not pointer to constant
safeFree(host);
@@ -335,14 +351,14 @@ THD::~THD()
}
-void THD::awake(bool prepare_to_die)
+void THD::awake(THD::killed_state state_to_set)
{
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
- if (prepare_to_die)
- killed = 1;
- thr_alarm_kill(real_id);
+ killed= state_to_set;
+ if (state_to_set != THD::KILL_QUERY)
+ thr_alarm_kill(real_id);
#ifdef SIGNAL_WITH_VIO_CLOSE
close_active_vio();
#endif
@@ -512,7 +528,7 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
{
my_error(EE_OUTOFMEMORY, MYF(ME_BELL),
ALIGN_SIZE(sizeof(TABLE_LIST)) + key_length + 1);
- killed= 1;
+ killed= KILL_CONNECTION;
return 0;
}
@@ -1058,9 +1074,12 @@ bool select_exists_subselect::send_data(List<Item> &items)
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
List_iterator_fast<Item> li(list);
- List_iterator_fast<LEX_STRING> gl(var_list);
+ List_iterator_fast<my_var> gl(var_list);
Item *item;
+ my_var *mv;
LEX_STRING *ls;
+
+ row_count= 0;
if (var_list.elements != list.elements)
{
my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0));
@@ -1069,19 +1088,39 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
unit=u;
while ((item=li++))
{
- ls= gl++;
- Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
- xx->fix_fields(thd,(TABLE_LIST*) thd->lex.select_lex.table_list.first,&item);
- xx->fix_length_and_dec();
- vars.push_back(xx);
+ mv=gl++;
+ ls= &mv->s;
+ if (mv->local)
+ {
+ (void)local_vars.push_back(new Item_splocal(mv->offset));
+ }
+ else
+ {
+ Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
+ xx->fix_fields(thd,(TABLE_LIST*) thd->lex->select_lex.table_list.first,&item);
+ xx->fix_length_and_dec();
+ vars.push_back(xx);
+ }
}
return 0;
}
+
bool select_dumpvar::send_data(List<Item> &items)
{
List_iterator_fast<Item_func_set_user_var> li(vars);
+ List_iterator_fast<Item_splocal> var_li(local_vars);
+ List_iterator_fast<my_var> my_li(var_list);
+ List_iterator_fast<Item> it(items);
Item_func_set_user_var *xx;
+ Item_splocal *yy;
+ Item *item;
+ my_var *zz;
DBUG_ENTER("send_data");
+ if (unit->offset_limit_cnt)
+ { // using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
if (unit->offset_limit_cnt)
{ // Using limit offset,count
@@ -1093,8 +1132,21 @@ bool select_dumpvar::send_data(List<Item> &items)
my_error(ER_TOO_MANY_ROWS, MYF(0));
DBUG_RETURN(1);
}
- while ((xx=li++))
- xx->update();
+ while ((zz=my_li++) && (item=it++))
+ {
+ if (zz->local)
+ {
+ if ((yy=var_li++))
+ {
+ thd->spcont->set_item(yy->get_offset(), item);
+ }
+ }
+ else
+ {
+ if ((xx=li++))
+ xx->update();
+ }
+ }
DBUG_RETURN(0);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e10795c4d9d..a32258f52ae 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -26,6 +26,8 @@
class Query_log_event;
class Load_log_event;
class Slave_log_event;
+class sp_rcontext;
+class sp_cache;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
@@ -419,7 +421,8 @@ public:
struct st_mysql *mysql;
#endif
NET net; // client connection descriptor
- LEX lex; // parse tree descriptor
+ LEX main_lex;
+ LEX *lex; // parse tree descriptor
MEM_ROOT mem_root; // 1 command-life memory pool
MEM_ROOT con_root; // connection-life memory
MEM_ROOT warn_root; // For warnings and errors
@@ -568,11 +571,26 @@ public:
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
- bool volatile killed;
+
+ enum killed_state { NOT_KILLED=0, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
+ killed_state volatile killed;
+ inline int killed_errno() const
+ {
+ return killed;
+ }
+ inline void send_kill_message() const
+ {
+ my_error(killed_errno(), MYF(0));
+ }
+
bool prepare_command;
bool tmp_table_used;
bool charset_is_system_charset, charset_is_collation_connection;
+ sp_rcontext *spcont; // SP runtime context
+ sp_cache *sp_proc_cache;
+ sp_cache *sp_func_cache;
+
/*
If we do a purge of binary logs, log index info of the threads
that are currently reading it needs to be adjusted. To do that
@@ -611,7 +629,7 @@ public:
}
void close_active_vio();
#endif
- void awake(bool prepare_to_die);
+ void awake(THD::killed_state state_to_set);
inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
const char* msg)
{
@@ -1091,13 +1109,22 @@ public:
bool send_eof();
};
+class my_var : public Sql_alloc {
+public:
+ LEX_STRING s;
+ bool local;
+ uint offset;
+ my_var (LEX_STRING& j, bool i, uint o) : s(j), local(i), offset(o) {}
+ ~my_var() {}
+};
class select_dumpvar :public select_result {
ha_rows row_count;
public:
- List<LEX_STRING> var_list;
+ List<my_var> var_list;
List<Item_func_set_user_var> vars;
- select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;}
+ List<Item_splocal> local_vars;
+ select_dumpvar(void) { var_list.empty(); local_vars.empty(); vars.empty(); row_count=0;}
~select_dumpvar() {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list, uint flag) {return 0;}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 34e81402dd0..7d2f7007276 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -238,7 +238,6 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
query= thd->query;
query_length= thd->query_length;
}
- mysql_update_log.write(thd, query, query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0);
@@ -292,7 +291,6 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
thd->variables.character_set_database= thd->db_charset;
}
- mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -378,7 +376,6 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
query=thd->query;
query_length=thd->query_length;
}
- mysql_update_log.write(thd, query, query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, query, query_length, 0);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 48ef5b4b74c..ba92c1de9e1 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -38,18 +38,18 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
bool transactional_table, log_delayed, safe_update, const_cond;
ha_rows deleted;
TABLE_LIST *delete_table_list= (TABLE_LIST*)
- thd->lex.select_lex.table_list.first;
+ thd->lex->select_lex.table_list.first;
DBUG_ENTER("mysql_delete");
if ((open_and_lock_tables(thd, table_list)))
DBUG_RETURN(-1);
- fix_tables_pointers(thd->lex.all_selects_list);
+ fix_tables_pointers(thd->lex->all_selects_list);
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
table->map=1;
if (setup_conds(thd, delete_table_list, &conds) ||
- setup_ftfuncs(&thd->lex.select_lex))
+ setup_ftfuncs(&thd->lex->select_lex))
DBUG_RETURN(-1);
if (find_real_table_in_list(table_list->next,
table_list->db, table_list->real_name))
@@ -92,7 +92,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
if ((select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
send_ok(thd,0L);
DBUG_RETURN(0); // Nothing to delete
}
@@ -100,11 +100,11 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
/* If running in safe sql mode, don't allow updates without keys */
if (!table->quick_keys)
{
- thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
+ thd->lex->select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
{
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
@@ -126,8 +126,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (thd->lex.select_lex.setup_ref_array(thd, 0) ||
- setup_order(thd, thd->lex.select_lex.ref_pointer_array, &tables,
+ if (thd->lex->select_lex.setup_ref_array(thd, 0) ||
+ setup_order(thd, thd->lex->select_lex.ref_pointer_array, &tables,
fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->sort.found_records = filesort(thd, table, sortorder, length,
@@ -136,14 +136,14 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
== HA_POS_ERROR)
{
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
DBUG_RETURN(-1); // This will force out message
}
}
init_read_record(&info,thd,table,select,1,1);
deleted=0L;
- init_ftfuncs(thd, &thd->lex.select_lex, 1);
+ init_ftfuncs(thd, &thd->lex->select_lex, 1);
thd->proc_info="updating";
while (!(error=info.read_record(&info)) && !thd->killed &&
!thd->net.report_error)
@@ -198,7 +198,6 @@ cleanup:
log_delayed= (transactional_table || table->tmp_table);
if (deleted && (error <= 0 || !transactional_table))
{
- mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -221,9 +220,9 @@ cleanup:
thd->lock=0;
}
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
if (error >= 0 || thd->net.report_error)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
+ send_error(thd,thd->killed_errno());
else
{
send_ok(thd,deleted);
@@ -311,7 +310,7 @@ multi_delete::initialize_tables(JOIN *join)
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
- init_ftfuncs(thd, thd->lex.current_select, 1);
+ init_ftfuncs(thd, thd->lex->current_select, 1);
DBUG_RETURN(thd->is_fatal_error != 0);
}
@@ -503,7 +502,6 @@ bool multi_delete::send_eof()
*/
if (deleted && (error <= 0 || normal_tables))
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -615,7 +613,6 @@ end:
{
if (!error)
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 771d68e8462..6415a7e7428 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -217,7 +217,13 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
else
unit->exclude_level();
org_table_list->db= (char *)"";
-#ifndef DBUG_OFF
+#if 0
+ /* QQ This was #ifndef DBUG_OFF, but that caused crashes with
+ * certain subselect args to SPs. Since ->derived is tested
+ * for non-null value in some places in the code, this seems
+ * to be the wrong way to do it. Simply letting derived be 0
+ * appears to work fine. /pem
+ */
/* Try to catch errors if this is accessed */
org_table_list->derived=(SELECT_LEX_UNIT *) 1;
#endif
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index db0dbe0dedc..3676f4644d2 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -184,7 +184,7 @@ my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
DBUG_RETURN(1);
MYSQL_ERROR *err;
- SELECT_LEX *sel= &thd->lex.select_lex;
+ SELECT_LEX *sel= &thd->lex->select_lex;
ha_rows offset= sel->offset_limit, limit= sel->select_limit;
Protocol *protocol=thd->protocol;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 947205949f1..7e1283d5f24 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -23,7 +23,7 @@
static int check_null_fields(THD *thd,TABLE *entry);
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
static int write_delayed(THD *thd,TABLE *table, enum_duplicates dup,
- char *query, uint query_length, int log_on);
+ char *query, uint query_length, bool log_on);
static void end_delayed_insert(THD *thd);
extern "C" pthread_handler_decl(handle_delayed_insert,arg);
static void unlink_blobs(register TABLE *table);
@@ -38,9 +38,6 @@ static void unlink_blobs(register TABLE *table);
#define my_safe_afree(ptr, size, min_length) if (size > min_length) my_free(ptr,MYF(0))
#endif
-#define DELAYED_LOG_UPDATE 1
-#define DELAYED_LOG_BIN 2
-
/*
Check if insert fields are correct
Updates table->time_stamp to point to timestamp field or 0, depending on
@@ -114,8 +111,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
By default, both logs are enabled (this won't cause problems if the server
runs without --log-update or --log-bin).
*/
- int log_on= DELAYED_LOG_UPDATE | DELAYED_LOG_BIN ;
-
+ bool log_on= (thd->options & OPTION_BIN_LOG) || (!(thd->master_access & SUPER_ACL));
bool transactional_table, log_delayed, bulk_insert;
uint value_count;
ulong counter = 1;
@@ -127,17 +123,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
char *query=thd->query;
thr_lock_type lock_type = table_list->lock_type;
TABLE_LIST *insert_table_list= (TABLE_LIST*)
- thd->lex.select_lex.table_list.first;
+ thd->lex->select_lex.table_list.first;
DBUG_ENTER("mysql_insert");
- if (thd->master_access & SUPER_ACL)
- {
- if (!(thd->options & OPTION_UPDATE_LOG))
- log_on&= ~(int) DELAYED_LOG_UPDATE;
- if (!(thd->options & OPTION_BIN_LOG))
- log_on&= ~(int) DELAYED_LOG_BIN;
- }
-
/*
in safe mode or with skip-new change delayed insert to be regular
if we are told to replace duplicates, the insert cannot be concurrent
@@ -178,7 +166,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
res= open_and_lock_tables(thd, table_list);
if (res)
DBUG_RETURN(-1);
- fix_tables_pointers(thd->lex.all_selects_list);
+ fix_tables_pointers(thd->lex->all_selects_list);
table= table_list->table;
thd->proc_info="init";
@@ -362,7 +350,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
log_delayed= (transactional_table || table->tmp_table);
if ((info.copied || info.deleted) && (error <= 0 || !transactional_table))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -412,14 +399,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
(ulong) info.deleted, (ulong) thd->cuted_fields);
::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff);
}
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0;
DBUG_RETURN(0);
abort:
if (lock_type == TL_WRITE_DELAYED)
end_delayed_insert(thd);
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
table->insert_values=0;
DBUG_RETURN(-1);
}
@@ -588,13 +575,12 @@ public:
char *record,*query;
enum_duplicates dup;
time_t start_time;
- bool query_start_used,last_insert_id_used,insert_id_used;
- int log_query;
+ bool query_start_used,last_insert_id_used,insert_id_used, log_query;
ulonglong last_insert_id;
ulong time_stamp;
uint query_length;
- delayed_row(enum_duplicates dup_arg, int log_query_arg)
+ delayed_row(enum_duplicates dup_arg, bool log_query_arg)
:record(0),query(0),dup(dup_arg),log_query(log_query_arg) {}
~delayed_row()
{
@@ -900,7 +886,7 @@ TABLE *delayed_insert::get_local_table(THD* client_thd)
/* Put a question in queue */
static int write_delayed(THD *thd,TABLE *table,enum_duplicates duplic,
- char *query, uint query_length, int log_on)
+ char *query, uint query_length, bool log_on)
{
delayed_row *row=0;
delayed_insert *di=thd->di;
@@ -980,7 +966,7 @@ void kill_delayed_threads(void)
{
/* Ensure that the thread doesn't kill itself while we are looking at it */
pthread_mutex_lock(&tmp->mutex);
- tmp->thd.killed=1;
+ tmp->thd.killed= THD::KILL_CONNECTION;
if (tmp->thd.mysys_var)
{
pthread_mutex_lock(&tmp->thd.mysys_var->mutex);
@@ -1019,7 +1005,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
thd->thread_id=thread_id++;
thd->end_time();
threads.append(thd);
- thd->killed=abort_loop;
+ thd->killed=abort_loop ? THD::KILL_CONNECTION : THD::NOT_KILLED;
pthread_mutex_unlock(&LOCK_thread_count);
pthread_mutex_lock(&di->mutex);
@@ -1072,7 +1058,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
for (;;)
{
- if (thd->killed)
+ if (thd->killed == THD::KILL_CONNECTION)
{
uint lock_count;
/*
@@ -1120,7 +1106,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
break;
if (error == ETIME || error == ETIMEDOUT)
{
- thd->killed=1;
+ thd->killed= THD::KILL_CONNECTION;
break;
}
}
@@ -1139,7 +1125,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
/* request for new delayed insert */
if (!(thd->lock=mysql_lock_tables(thd,&di->table,1)))
{
- di->dead=thd->killed=1; // Fatal error
+ di->dead=thd->killed= THD::KILL_CONNECTION; // Fatal error
}
pthread_cond_broadcast(&di->cond_client);
}
@@ -1147,7 +1133,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
{
if (di->handle_inserts())
{
- di->dead=thd->killed=1; // Some fatal error
+ di->dead=thd->killed=THD::KILL_CONNECTION; // Some fatal error
}
}
di->status=0;
@@ -1174,7 +1160,7 @@ end:
close_thread_tables(thd); // Free the table
di->table=0;
- di->dead=thd->killed=1; // If error
+ di->dead=thd->killed= THD::KILL_CONNECTION; // If error
pthread_cond_broadcast(&di->cond_client); // Safety
pthread_mutex_unlock(&di->mutex);
@@ -1243,7 +1229,7 @@ bool delayed_insert::handle_inserts(void)
max_rows=delayed_insert_limit;
if (thd.killed || table->version != refresh_version)
{
- thd.killed=1;
+ thd.killed= THD::KILL_CONNECTION;
max_rows= ~0; // Do as much as possible
}
@@ -1287,15 +1273,10 @@ bool delayed_insert::handle_inserts(void)
using_ignore=0;
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
}
- if (row->query)
+ if (row->query && row->log_query && using_bin_log)
{
- if (row->log_query & DELAYED_LOG_UPDATE)
- mysql_update_log.write(&thd,row->query, row->query_length);
- if (row->log_query & DELAYED_LOG_BIN && using_bin_log)
- {
- Query_log_event qinfo(&thd, row->query, row->query_length,0);
- mysql_bin_log.write(&qinfo);
- }
+ Query_log_event qinfo(&thd, row->query, row->query_length,0);
+ mysql_bin_log.write(&qinfo);
}
if (table->blob_fields)
free_delayed_insert_blobs(table);
@@ -1441,7 +1422,6 @@ void select_insert::send_error(uint errcode,const char *err)
{
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -1473,7 +1453,6 @@ bool select_insert::send_eof()
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
/* Write to binlog before commiting transaction */
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d6cfd555c40..ade5c41398b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -21,6 +21,8 @@
#include "item_create.h"
#include <m_ctype.h>
#include <hash.h>
+#include "sp.h"
+#include "sp_head.h"
LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};
@@ -106,9 +108,10 @@ void lex_free(void)
LEX *lex_start(THD *thd, uchar *buf,uint length)
{
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
lex->thd= thd;
lex->next_state=MY_LEX_START;
+ lex->buf= buf;
lex->end_of_query=(lex->ptr=buf)+length;
lex->yylineno = 1;
lex->select_lex.parsing_place= SELECT_LEX_NODE::NO_MATTER;
@@ -123,6 +126,14 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
lex->sql_command=SQLCOM_END;
lex->duplicates= DUP_ERROR;
+ lex->sphead= NULL;
+ lex->spcont= NULL;
+
+ extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
+ hash_free(&lex->spfuns);
+ hash_init(&lex->spfuns, system_charset_info, 0, 0, 0,
+ sp_lex_spfuns_key, 0, 0);
+
return lex;
}
@@ -146,6 +157,17 @@ static int find_keyword(LEX *lex, uint len, bool function)
lex->yylval->symbol.length=len;
return symbol->tok;
}
+
+ LEX_STRING ls;
+ ls.str = (char *)tok; ls.length= len;
+ if (function && sp_function_exists(current_thd, &ls)) // QQ temp fix
+ {
+ lex->safe_to_cache_query= 0;
+ lex->yylval->lex_str.str= lex->thd->strmake((char*)lex->tok_start, len);
+ lex->yylval->lex_str.length= len;
+ return SP_FUNC;
+ }
+
#ifdef HAVE_DLOPEN
udf_func *udf;
if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
@@ -421,7 +443,7 @@ int yylex(void *arg, void *yythd)
int tokval;
uint length;
enum my_lex_states state,prev_state;
- LEX *lex= &(((THD *)yythd)->lex);
+ LEX *lex= (((THD *)yythd)->lex);
YYSTYPE *yylval=(YYSTYPE*) arg;
CHARSET_INFO *cs= ((THD *) yythd)->charset();
uchar *state_map= cs->state_map;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7a7071ae56b..16f1e7548b9 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -21,6 +21,9 @@
class Table_ident;
class sql_exchange;
class LEX_COLUMN;
+class sp_head;
+class sp_instr;
+class sp_pcontext;
/*
The following hack is needed because mysql_yacc.cc does not define
@@ -74,6 +77,8 @@ enum enum_sql_command {
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL,
+ SQLCOM_CREATE_PROCEDURE, SQLCOM_CREATE_SPFUNCTION, SQLCOM_CALL,
+ SQLCOM_DROP_PROCEDURE, SQLCOM_ALTER_PROCEDURE,SQLCOM_ALTER_FUNCTION,
/* This should be the last !!! */
SQLCOM_END
@@ -315,7 +320,7 @@ public:
int exec();
int cleanup();
- friend void mysql_init_query(THD *thd);
+ friend void mysql_init_query(THD *thd, bool lexonly);
friend int subselect_union_engine::exec();
private:
bool create_total_list_n_last_return(THD *thd, st_lex *lex,
@@ -446,7 +451,7 @@ public:
bool test_limit();
- friend void mysql_init_query(THD *thd);
+ friend void mysql_init_query(THD *thd, bool lexonly);
st_select_lex() {}
void make_empty_select()
{
@@ -470,6 +475,7 @@ typedef struct st_lex
SELECT_LEX *current_select;
/* list of all SELECT_LEX */
SELECT_LEX *all_selects_list;
+ uchar *buf; /* The beginning of string, used by SPs */
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */
@@ -530,7 +536,22 @@ typedef struct st_lex
CHARSET_INFO *charset;
char *help_arg;
SQL_LIST *gorder_list;
- st_lex() {}
+ sp_head *sphead;
+ bool sp_lex_in_use; /* Keep track on lex usage in SPs for error handling */
+ sp_pcontext *spcont;
+ HASH spfuns; /* Called functions */
+
+ st_lex()
+ {
+ bzero((char *)&spfuns, sizeof(spfuns));
+ }
+
+ ~st_lex()
+ {
+ if (spfuns.array.buffer)
+ hash_free(&spfuns);
+ }
+
inline void uncacheable()
{
safe_to_cache_query= 0;
@@ -561,4 +582,4 @@ extern pthread_key(LEX*,THR_LEX);
extern LEX_STRING tmp_table_alias;
-#define current_lex (&current_thd->lex)
+#define current_lex (current_thd->lex)
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index d030eaf617c..252e357ca25 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -321,9 +321,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
sprintf(name, ER(ER_LOAD_INFO), (ulong) info.records, (ulong) info.deleted,
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
send_ok(thd,info.copied+info.deleted,0L,name);
- // on the slave thd->query is never initialized
- if (!thd->slave_thread)
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
@@ -384,7 +381,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
DBUG_RETURN(1);
}
it.rewind();
@@ -472,7 +469,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
DBUG_RETURN(1);
}
while ((sql_field=(Item_field*) it++))
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 33e96cc2776..7882135e401 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -26,6 +26,9 @@
#include "ha_innodb.h"
#endif
+#include "sp_head.h"
+#include "sp.h"
+
#ifdef HAVE_OPENSSL
/*
Without SSL the handshake consists of one packet. This packet
@@ -44,6 +47,15 @@
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
+/* Used in error handling only */
+#define SP_TYPE_STRING(LP) \
+ ((LP)->sphead->m_type == TYPE_ENUM_FUNCTION ? "FUNCTION" : "PROCEDURE")
+#define SP_COM_STRING(LP) \
+ ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION || \
+ (LP)->sql_command == SQLCOM_ALTER_FUNCTION || \
+ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \
+ "FUNCTION" : "PROCEDURE")
+
extern int yyparse(void *thd);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
@@ -900,7 +912,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->version=refresh_version;
thd->set_time();
thd->init_for_queries();
- while (!net->error && net->vio != 0 && !thd->killed)
+ while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION))
{
if (do_command(thd))
break;
@@ -1088,7 +1100,7 @@ bool do_command(THD *thd)
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
*/
- thd->lex.current_select= 0;
+ thd->lex->current_select= 0;
packet=0;
old_timeout=net->read_timeout;
@@ -1114,6 +1126,9 @@ bool do_command(THD *thd)
}
else
{
+ if (thd->killed == THD::KILL_QUERY)
+ thd->killed= THD::NOT_KILLED;
+
packet=(char*) net->read_pos;
command = (enum enum_server_command) (uchar) packet[0];
if (command >= COM_END)
@@ -1149,7 +1164,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thread_running++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
- thd->lex.select_lex.options=0; // We store status here
+ thd->lex->select_lex.options=0; // We store status here
switch (command) {
case COM_INIT_DB:
{
@@ -1334,16 +1349,16 @@ restore_user:
DBUG_PRINT("query",("%-.4096s",thd->query));
mysql_parse(thd,thd->query, thd->query_length);
- while (!thd->killed && !thd->is_fatal_error && thd->lex.found_colon)
+ while (!thd->killed && !thd->is_fatal_error && thd->lex->found_colon)
{
- char *packet= thd->lex.found_colon;
+ char *packet= thd->lex->found_colon;
/*
Multiple queries exits, execute them individually
*/
if (thd->lock || thd->open_tables || thd->derived_tables)
close_thread_tables(thd);
- ulong length= thd->query_length-(ulong)(thd->lex.found_colon-thd->query);
+ ulong length= thd->query_length-(ulong)(thd->lex->found_colon-thd->query);
/* Remove garbage at start of query */
while (my_isspace(thd->charset(), *packet) && length > 0)
@@ -1551,7 +1566,7 @@ restore_user:
{
statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
ulong id=(ulong) uint4korr(packet);
- kill_one_thread(thd,id);
+ kill_one_thread(thd,id,false);
break;
}
case COM_DEBUG:
@@ -1590,7 +1605,7 @@ restore_user:
if ((ulong) (thd->start_time - thd->time_after_lock) >
thd->variables.long_query_time ||
- ((thd->lex.select_lex.options &
+ ((thd->lex->select_lex.options &
(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED)) &&
(specialflag & SPECIAL_LONG_LOG_FORMAT)))
{
@@ -1606,6 +1621,7 @@ restore_user:
thread_running--;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
+
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_RETURN(error);
}
@@ -1661,16 +1677,23 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/
-void
+int
mysql_execute_command(THD *thd)
{
int res= 0;
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
SELECT_LEX *select_lex= &lex->select_lex;
SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_execute_command");
+ if (lex->sql_command != SQLCOM_CREATE_PROCEDURE &&
+ lex->sql_command != SQLCOM_CREATE_SPFUNCTION)
+ {
+ if (sp_cache_functions(thd, lex))
+ DBUG_RETURN(-1);
+ }
+
/*
Reset warning count for each query that uses tables
A better approach would be to reset this for any commands
@@ -1696,7 +1719,7 @@ mysql_execute_command(THD *thd)
{
/* we warn the slave SQL thread */
my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
}
#ifndef TO_BE_DELETED
/*
@@ -1732,14 +1755,14 @@ mysql_execute_command(THD *thd)
{
if (res < 0 || thd->net.report_error)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(res);
}
}
}
}
if (&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables, 0))
- DBUG_VOID_RETURN;
+ DBUG_RETURN(0);
/*
When option readonly is set deny operations which change tables.
@@ -1750,7 +1773,7 @@ mysql_execute_command(THD *thd)
(uc_update_queries[lex->sql_command] > 0))
{
send_error(thd, ER_CANT_UPDATE_WITH_READLOCK);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(-1);
}
statistic_increment(com_stat[lex->sql_command],&LOCK_status);
@@ -1790,12 +1813,12 @@ mysql_execute_command(THD *thd)
if (!(result= new select_send()))
{
send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_VOID_RETURN;
+ goto error;
}
else
thd->send_explain_fields(result);
fix_tables_pointers(lex->all_selects_list);
- res= mysql_explain_union(thd, &thd->lex.unit, result);
+ res= mysql_explain_union(thd, &thd->lex->unit, result);
MYSQL_LOCK *save_lock= thd->lock;
thd->lock= (MYSQL_LOCK *)0;
result->send_eof();
@@ -2064,7 +2087,7 @@ mysql_execute_command(THD *thd)
find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(-1);
}
if (tables->next)
{
@@ -2156,7 +2179,7 @@ mysql_execute_command(THD *thd)
if (thd->locked_tables || thd->active_transaction())
{
send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
- break;
+ goto error;
}
{
LOCK_ACTIVE_MI;
@@ -2169,7 +2192,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- break;
+ goto error;
#else
{
ulong priv=0;
@@ -2261,7 +2284,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
{
if (check_global_access(thd, SUPER_ACL))
@@ -2274,7 +2297,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_CREATE:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
{
if (check_db_used(thd, tables) ||
@@ -2294,7 +2317,6 @@ mysql_execute_command(THD *thd)
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -2320,7 +2342,6 @@ mysql_execute_command(THD *thd)
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -2359,7 +2380,6 @@ mysql_execute_command(THD *thd)
/* ! we write after unlocking the table */
if (!res && !lex->no_write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -2378,7 +2398,7 @@ mysql_execute_command(THD *thd)
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
- DBUG_VOID_RETURN;
+ goto error;
}
res= mysql_update(thd,tables,
select_lex->item_list,
@@ -2399,7 +2419,7 @@ mysql_execute_command(THD *thd)
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
- DBUG_VOID_RETURN;
+ goto error;
}
{
const char *msg= 0;
@@ -2435,7 +2455,7 @@ mysql_execute_command(THD *thd)
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
- DBUG_VOID_RETURN;
+ goto error;
}
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
select_lex->item_list, lex->value_list,
@@ -2529,7 +2549,7 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_DELETE_MULTI:
{
- TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex.auxilliary_table_list.first;
+ TABLE_LIST *aux_tables=(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
TABLE_LIST *auxi;
uint table_count=0;
multi_delete *result;
@@ -2653,7 +2673,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_DATABASES:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
check_global_access(thd, SHOW_DB_ACL))
@@ -2687,7 +2707,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
{
if (grant_option && check_access(thd, FILE_ACL, any_db))
@@ -2700,7 +2720,7 @@ mysql_execute_command(THD *thd)
/* FALL THROUGH */
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
{
char *db=select_lex->db ? select_lex->db : thd->db;
@@ -2747,7 +2767,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
{
char *db=tables->db;
@@ -2772,7 +2792,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
- DBUG_VOID_RETURN;
+ goto error;
#else
{
char *db=tables->db;
@@ -2960,33 +2980,30 @@ mysql_execute_command(THD *thd)
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
break;
}
- case SQLCOM_CREATE_FUNCTION:
- if (check_access(thd,INSERT_ACL,"mysql",0,1))
- break;
-#ifdef HAVE_DLOPEN
- if (!(res = mysql_create_function(thd,&lex->udf)))
- send_ok(thd);
-#else
- res= -1;
-#endif
- break;
- case SQLCOM_DROP_FUNCTION:
- if (check_access(thd,DELETE_ACL,"mysql",0,1))
- break;
+ case SQLCOM_CREATE_FUNCTION: // UDF function
+ {
+ if (check_access(thd,INSERT_ACL,"mysql",0,1))
+ break;
#ifdef HAVE_DLOPEN
- if (!(res = mysql_drop_function(thd,&lex->udf.name)))
- send_ok(thd);
+ sp_head *sph= sp_find_function(thd, &lex->udf.name);
+ if (sph)
+ {
+ net_printf(thd, ER_UDF_EXISTS, lex->udf.name.str);
+ goto error;
+ }
+ if (!(res = mysql_create_function(thd,&lex->udf)))
+ send_ok(thd);
#else
- res= -1;
+ res= -1;
#endif
break;
+ }
case SQLCOM_DROP_USER:
{
if (check_access(thd, GRANT_ACL,"mysql",0,1))
break;
if (!(res= mysql_drop_user(thd, lex->users_list)))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -3002,7 +3019,6 @@ mysql_execute_command(THD *thd)
break;
if (!(res = mysql_revoke_all(thd, lex->users_list)))
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -3053,14 +3069,11 @@ mysql_execute_command(THD *thd)
goto error;
if (!(res = mysql_table_grant(thd,tables,lex->users_list, lex->columns,
lex->grant,
- lex->sql_command == SQLCOM_REVOKE)))
+ lex->sql_command == SQLCOM_REVOKE)) &&
+ mysql_bin_log.is_open())
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
- mysql_bin_log.write(&qinfo);
- }
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ mysql_bin_log.write(&qinfo);
}
}
else
@@ -3075,7 +3088,6 @@ mysql_execute_command(THD *thd)
lex->sql_command == SQLCOM_REVOKE);
if (!res)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -3117,7 +3129,6 @@ mysql_execute_command(THD *thd)
*/
if (!lex->no_write_to_binlog && write_to_binlog)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -3129,7 +3140,7 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_KILL:
- kill_one_thread(thd,lex->thread_id);
+ kill_one_thread(thd,lex->thread_id, lex->type & ONLY_KILL_QUERY);
break;
case SQLCOM_SHOW_GRANTS:
res=0;
@@ -3230,16 +3241,193 @@ mysql_execute_command(THD *thd)
else
res= -1;
break;
+ case SQLCOM_CREATE_PROCEDURE:
+ case SQLCOM_CREATE_SPFUNCTION:
+ if (!lex->sphead)
+ {
+ res= -1; // Shouldn't happen
+ break;
+ }
+ else
+ {
+ uint namelen;
+ char *name= lex->sphead->name(&namelen);
+#ifdef HAVE_DLOPEN
+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION)
+ {
+ udf_func *udf = find_udf(name, namelen);
+
+ if (udf)
+ {
+ net_printf(thd, ER_UDF_EXISTS, name);
+ goto error;
+ }
+ }
+#endif
+ res= lex->sphead->create(thd);
+
+ switch (res)
+ {
+ case SP_OK:
+ send_ok(thd);
+ break;
+ case SP_WRITE_ROW_FAILED:
+ net_printf(thd, ER_SP_ALREADY_EXISTS, SP_TYPE_STRING(lex), name);
+ goto error;
+ default:
+ net_printf(thd, ER_SP_STORE_FAILED, SP_TYPE_STRING(lex), name);
+ goto error;
+ }
+ break;
+ }
+ case SQLCOM_CALL:
+ {
+ sp_head *sp;
+
+ sp= sp_find_procedure(thd, &lex->udf.name);
+ if (! sp)
+ {
+ net_printf(thd, ER_SP_DOES_NOT_EXIST, "PROCEDURE", lex->udf.name);
+ goto error;
+ }
+ else
+ {
+ uint smrx;
+ LINT_INIT(smrx);
+
+ // In case the arguments are subselects...
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ (res= open_and_lock_tables(thd, tables))))
+ {
+ break;
+ }
+ fix_tables_pointers(lex->all_selects_list);
+
+#ifndef EMBEDDED_LIBRARY
+ // When executing substatements, they're assumed to send_error when
+ // it happens, but not to send_ok.
+ my_bool nsok= thd->net.no_send_ok;
+ thd->net.no_send_ok= TRUE;
+#endif
+ if (sp->m_multi_query)
+ {
+ if (! (thd->client_capabilities & CLIENT_MULTI_QUERIES))
+ {
+ send_error(thd, ER_SP_BADSELECT);
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ goto error;
+ }
+ smrx= thd->server_status & SERVER_MORE_RESULTS_EXISTS;
+ thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
+ }
+
+ res= sp->execute_procedure(thd, &lex->value_list);
+
+#ifndef EMBEDDED_LIBRARY
+ thd->net.no_send_ok= nsok;
+#endif
+ if (sp->m_multi_query)
+ {
+ if (! smrx)
+ thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
+ }
+
+ if (res == 0)
+ send_ok(thd);
+ else
+ goto error; // Substatement should already have sent error
+ }
+ break;
+ }
+ case SQLCOM_ALTER_PROCEDURE:
+ case SQLCOM_ALTER_FUNCTION:
+ {
+ sp_head *sp;
+
+ if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
+ sp= sp_find_procedure(thd, &lex->udf.name);
+ else
+ sp= sp_find_function(thd, &lex->udf.name);
+ if (! sp)
+ {
+ net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),lex->udf.name);
+ goto error;
+ }
+ else
+ {
+ /* QQ This is an no-op right now, since we haven't
+ put the characteristics in yet. */
+ send_ok(thd);
+ }
+ break;
+ }
+ case SQLCOM_DROP_PROCEDURE:
+ case SQLCOM_DROP_FUNCTION:
+ {
+ if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
+ res= sp_drop_procedure(thd, lex->udf.name.str, lex->udf.name.length);
+ else
+ {
+ res= sp_drop_function(thd, lex->udf.name.str, lex->udf.name.length);
+#ifdef HAVE_DLOPEN
+ if (res == SP_KEY_NOT_FOUND)
+ {
+ udf_func *udf = find_udf(lex->udf.name.str, lex->udf.name.length);
+ if (udf)
+ {
+ if (check_access(thd, DELETE_ACL, "mysql", 0, 1))
+ goto error;
+ if (!(res = mysql_drop_function(thd,&lex->udf.name)))
+ {
+ send_ok(thd);
+ break;
+ }
+ }
+ }
+#endif
+ }
+ switch (res)
+ {
+ case SP_OK:
+ send_ok(thd);
+ break;
+ case SP_KEY_NOT_FOUND:
+ if (lex->drop_if_exists)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
+ SP_COM_STRING(lex), lex->udf.name.str);
+ res= 0;
+ send_ok(thd);
+ break;
+ }
+ net_printf(thd, ER_SP_DOES_NOT_EXIST, SP_COM_STRING(lex),
+ lex->udf.name.str);
+ goto error;
+ default:
+ net_printf(thd, ER_SP_DROP_FAILED, SP_COM_STRING(lex),
+ lex->udf.name.str);
+ goto error;
+ }
+ break;
+ }
default: /* Impossible */
send_ok(thd);
break;
}
thd->proc_info="query end"; // QQ
+
+ // We end up here if res == 0 and send_ok() has been done,
+ // or res != 0 and no send_error() has yet been done.
if (res < 0)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ send_error(thd,thd->killed_errno());
+ DBUG_RETURN(res);
error:
- DBUG_VOID_RETURN;
+ // We end up here if send_error() has already been done.
+ DBUG_RETURN(-1);
}
@@ -3548,10 +3736,10 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
****************************************************************************/
void
-mysql_init_query(THD *thd)
+mysql_init_query(THD *thd, bool lexonly)
{
DBUG_ENTER("mysql_init_query");
- LEX *lex=&thd->lex;
+ LEX *lex=thd->lex;
lex->unit.init_query();
lex->unit.init_select();
lex->unit.thd= thd;
@@ -3572,17 +3760,20 @@ mysql_init_query(THD *thd)
lex->lock_option= TL_READ;
lex->found_colon= 0;
lex->safe_to_cache_query= 1;
- thd->select_number= lex->select_lex.select_number= 1;
- thd->free_list= 0;
- thd->total_warn_count=0; // Warnings for this query
- thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
- thd->sent_row_count= thd->examined_row_count= 0;
- thd->is_fatal_error= thd->rand_used= 0;
- thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
- thd->tmp_table_used= 0;
- if (opt_bin_log)
- reset_dynamic(&thd->user_var_events);
- thd->clear_error();
+ if (! lexonly)
+ {
+ thd->select_number= lex->select_lex.select_number= 1;
+ thd->free_list= 0;
+ thd->total_warn_count=0; // Warnings for this query
+ thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
+ thd->sent_row_count= thd->examined_row_count= 0;
+ thd->is_fatal_error= thd->rand_used= 0;
+ thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
+ thd->tmp_table_used= 0;
+ if (opt_bin_log)
+ reset_dynamic(&thd->user_var_events);
+ thd->clear_error();
+ }
DBUG_VOID_RETURN;
}
@@ -3717,7 +3908,16 @@ mysql_parse(THD *thd, char *inBuf, uint length)
else
{
if (thd->net.report_error)
+ {
send_error(thd, 0, NullS);
+ if (thd->lex->sphead)
+ {
+ if (lex != thd->lex)
+ thd->lex->sphead->restore_lex(thd);
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+ }
else
{
mysql_execute_command(thd);
@@ -3733,6 +3933,13 @@ mysql_parse(THD *thd, char *inBuf, uint length)
thd->is_fatal_error));
#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
query_cache_abort(&thd->net);
+ if (thd->lex->sphead)
+ {
+ if (lex != thd->lex)
+ thd->lex->sphead->restore_lex(thd);
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
#endif
}
thd->proc_info="freeing items";
@@ -3756,7 +3963,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
uint uint_geom_type)
{
register create_field *new_field;
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
uint allowed_type_modifier=0;
char warn_buff[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("add_field_to_list");
@@ -4084,7 +4291,7 @@ add_proc_to_list(THD* thd, Item *item)
*item_ptr= item;
order->item=item_ptr;
order->free_me=0;
- thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
+ thd->lex->proc_list.link_in_list((byte*) order,(byte**) &order->next);
return 0;
}
@@ -4367,7 +4574,6 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
*/
tmp_write_to_binlog= 0;
mysql_log.new_file(1);
- mysql_update_log.new_file(1);
mysql_bin_log.new_file(1);
mysql_slow_log.new_file(1);
#ifdef HAVE_REPLICATION
@@ -4463,7 +4669,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
This is written such that we have a short lock on LOCK_thread_count
*/
-void kill_one_thread(THD *thd, ulong id)
+void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
@@ -4483,7 +4689,7 @@ void kill_one_thread(THD *thd, ulong id)
if ((thd->master_access & SUPER_ACL) ||
!strcmp(thd->user,tmp->user))
{
- tmp->awake(1 /*prepare to die*/);
+ tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
error=0;
}
else
@@ -4553,11 +4759,11 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
bool check_simple_select()
{
THD *thd= current_thd;
- if (thd->lex.current_select != &thd->lex.select_lex)
+ if (thd->lex->current_select != &thd->lex->select_lex)
{
char command[80];
- strmake(command, thd->lex.yylval->symbol.str,
- min(thd->lex.yylval->symbol.length, sizeof(command)-1));
+ strmake(command, thd->lex->yylval->symbol.str,
+ min(thd->lex->yylval->symbol.length, sizeof(command)-1));
net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
return 1;
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 550e4bbe086..9d36985f6bf 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -71,6 +71,7 @@ Long data handling:
#include "sql_acl.h"
#include "sql_select.h" // for JOIN
#include <m_ctype.h> // for isspace()
+#include "sp_head.h"
#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
@@ -399,7 +400,7 @@ static void setup_param_functions(Item_param *param, uchar param_type)
static bool insert_params_withlog(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
{
THD *thd= stmt->thd;
- List<Item> &params= thd->lex.param_list;
+ List<Item> &params= thd->lex->param_list;
List_iterator<Item> param_iterator(params);
Item_param *param;
DBUG_ENTER("insert_params_withlog");
@@ -445,7 +446,7 @@ static bool insert_params_withlog(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
static bool insert_params(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
{
THD *thd= stmt->thd;
- List<Item> &params= thd->lex.param_list;
+ List<Item> &params= thd->lex->param_list;
List_iterator<Item> param_iterator(params);
Item_param *param;
DBUG_ENTER("insert_params");
@@ -471,7 +472,7 @@ static bool insert_params(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
static bool setup_params_data(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
- List<Item> &params= thd->lex.param_list;
+ List<Item> &params= thd->lex->param_list;
List_iterator<Item> param_iterator(params);
Item_param *param;
DBUG_ENTER("setup_params_data");
@@ -517,8 +518,8 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
List_item *values;
DBUG_ENTER("mysql_test_insert_fields");
- my_bool update=(thd->lex.value_list.elements ? UPDATE_ACL : 0);
- ulong privilege= (thd->lex.duplicates == DUP_REPLACE ?
+ my_bool update=(thd->lex->value_list.elements ? UPDATE_ACL : 0);
+ ulong privilege= (thd->lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
if (check_access(thd,privilege,table_list->db,
@@ -616,8 +617,8 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
SELECT_LEX *select_lex)
{
THD *thd= stmt->thd;
- LEX *lex= &thd->lex;
- select_result *result= thd->lex.result;
+ LEX *lex= thd->lex;
+ select_result *result= thd->lex->result;
DBUG_ENTER("mysql_test_select_fields");
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
@@ -643,7 +644,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
}
else
{
- fix_tables_pointers(thd->lex.all_selects_list);
+ fix_tables_pointers(thd->lex->all_selects_list);
if (!result && !(result= new select_send()))
{
delete select_lex->having;
@@ -679,8 +680,8 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
static bool send_prepare_results(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
- LEX *lex= &thd->lex;
- enum enum_sql_command sql_command= thd->lex.sql_command;
+ LEX *lex= thd->lex;
+ enum enum_sql_command sql_command= thd->lex->sql_command;
DBUG_ENTER("send_prepare_results");
DBUG_PRINT("enter",("command: %d, param_count: %ld",
sql_command, lex->param_count));
@@ -741,7 +742,7 @@ static bool send_prepare_results(PREP_STMT *stmt)
DBUG_RETURN(0);
abort:
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ send_error(thd,thd->killed_errno());
DBUG_RETURN(1);
}
@@ -761,9 +762,19 @@ static bool parse_prepare_query(PREP_STMT *stmt,
LEX *lex=lex_start(thd, (uchar*) packet, length);
lex->safe_to_cache_query= 0;
thd->prepare_command= TRUE;
- thd->lex.param_count= 0;
+ thd->lex->param_count= 0;
if (!yyparse((void *)thd) && !thd->is_fatal_error)
error= send_prepare_results(stmt);
+ else
+ {
+ if (thd->lex->sphead)
+ {
+ if (lex != thd->lex)
+ thd->lex->sphead->restore_lex(thd);
+ delete thd->lex->sphead;
+ thd->lex->sphead= NULL;
+ }
+ }
lex_end(lex);
DBUG_RETURN(error);
}
@@ -775,13 +786,13 @@ static bool parse_prepare_query(PREP_STMT *stmt,
static bool init_param_items(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
- List<Item> &params= thd->lex.param_list;
+ List<Item> &params= thd->lex->param_list;
Item_param **to;
uint32 length= thd->query_length;
- stmt->lex= thd->lex;
+ stmt->lex= *thd->lex;
- if (mysql_bin_log.is_open() || mysql_update_log.is_open())
+ if (mysql_bin_log.is_open())
{
stmt->log_full_query= 1;
stmt->setup_params= insert_params_withlog;
@@ -820,7 +831,7 @@ static bool init_param_items(PREP_STMT *stmt)
static void init_stmt_execute(PREP_STMT *stmt)
{
THD *thd= stmt->thd;
- TABLE_LIST *tables= (TABLE_LIST*) thd->lex.select_lex.table_list.first;
+ TABLE_LIST *tables= (TABLE_LIST*) thd->lex->select_lex.table_list.first;
/*
TODO: When the new table structure is ready, then have a status bit
@@ -917,8 +928,8 @@ void mysql_stmt_execute(THD *thd, char *packet)
DBUG_VOID_RETURN;
}
- LEX thd_lex= thd->lex;
- thd->lex= stmt->lex;
+ LEX *old_thd_lex= thd->lex;
+ thd->lex= &stmt->lex;
init_stmt_execute(stmt);
if (stmt->param_count && setup_params_data(stmt))
@@ -940,7 +951,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- thd->lex= thd_lex;
+ thd->lex= old_thd_lex;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 19b4d299e59..5ef8d5d1c1d 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -79,7 +79,6 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
/* Lets hope this doesn't fail as the result will be messy */
if (!error)
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 3cdf033c477..81a2569e253 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -680,8 +680,8 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
was running (as we don't wan't to touch the other thread), so set the
bit to 0 for the other thread
*/
- if (thd->lex.slave_thd_opt)
- thread_mask &= thd->lex.slave_thd_opt;
+ if (thd->lex->slave_thd_opt)
+ thread_mask &= thd->lex->slave_thd_opt;
if (thread_mask) //some threads are stopped, start them
{
if (init_master_info(mi,master_info_file,relay_log_info_file, 0))
@@ -737,8 +737,8 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
was stopped (as we don't wan't to touch the other thread), so set the
bit to 0 for the other thread
*/
- if (thd->lex.slave_thd_opt)
- thread_mask &= thd->lex.slave_thd_opt;
+ if (thd->lex->slave_thd_opt)
+ thread_mask &= thd->lex->slave_thd_opt;
if (thread_mask)
{
@@ -881,7 +881,7 @@ void kill_zombie_dump_threads(uint32 slave_server_id)
it will be slow because it will iterate through the list
again. We just to do kill the thread ourselves.
*/
- tmp->awake(1/*prepare to die*/);
+ tmp->awake(THD::KILL_QUERY);
pthread_mutex_unlock(&tmp->LOCK_delete);
}
}
@@ -904,7 +904,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
}
thd->proc_info = "changing master";
- LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
+ LEX_MASTER_INFO* lex_mi = &thd->lex->mi;
// TODO: see if needs re-write
if (init_master_info(mi, master_info_file, relay_log_info_file, 0))
{
@@ -1068,7 +1068,7 @@ int show_binlog_events(THD* thd)
if (mysql_bin_log.is_open())
{
- LEX_MASTER_INFO *lex_mi = &thd->lex.mi;
+ LEX_MASTER_INFO *lex_mi = &thd->lex->mi;
ha_rows event_count, limit_start, limit_end;
my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
char search_file_name[FN_REFLEN], *name;
@@ -1077,8 +1077,8 @@ int show_binlog_events(THD* thd)
LOG_INFO linfo;
Log_event* ev;
- limit_start = thd->lex.current_select->offset_limit;
- limit_end = thd->lex.current_select->select_limit + limit_start;
+ limit_start = thd->lex->current_select->offset_limit;
+ limit_end = thd->lex->current_select->select_limit + limit_start;
name= search_file_name;
if (log_file_name)
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index fe1b7167d4a..2ff38029b7b 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -20,7 +20,7 @@ extern I_List<i_string> binlog_do_db, binlog_ignore_db;
extern int max_binlog_dump_events;
extern my_bool opt_sporadic_binlog_dump_fail;
-#define KICK_SLAVE(thd) { pthread_mutex_lock(&(thd)->LOCK_delete); (thd)->awake(0 /* do not prepare to die*/); pthread_mutex_unlock(&(thd)->LOCK_delete); }
+#define KICK_SLAVE(thd) { pthread_mutex_lock(&(thd)->LOCK_delete); (thd)->awake(THD::NOT_KILLED); pthread_mutex_unlock(&(thd)->LOCK_delete); }
File open_binlog(IO_CACHE *log, const char *log_file_name,
const char **errmsg);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 15d6b3954ff..4acba0b6dfc 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -196,7 +196,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
send_error(thd, 0, NullS);
res= 1;
}
- delete result;
+ if (result != lex->result)
+ delete result;
return res;
}
@@ -491,8 +492,8 @@ JOIN::optimize()
optimized= 1;
// Ignore errors of execution if option IGNORE present
- if (thd->lex.duplicates == DUP_IGNORE)
- thd->lex.current_select->no_error= 1;
+ if (thd->lex->duplicates == DUP_IGNORE)
+ thd->lex->current_select->no_error= 1;
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
if (having && !group_list && !sum_func_count)
@@ -964,7 +965,7 @@ JOIN::optimize()
}
}
- if (select_lex != &thd->lex.select_lex &&
+ if (select_lex != &thd->lex->select_lex &&
select_lex->linkage != DERIVED_TABLE_TYPE)
{
if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN))))
@@ -2367,7 +2368,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
if (!(key_fields=(KEY_FIELD*)
thd->alloc(sizeof(key_fields[0])*
- (thd->lex.current_select->cond_count+1)*2)))
+ (thd->lex->current_select->cond_count+1)*2)))
return TRUE; /* purecov: inspected */
and_level=0; end=key_fields;
if (cond)
@@ -3380,7 +3381,7 @@ static void
make_join_readinfo(JOIN *join, uint options)
{
uint i;
- SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
+ SELECT_LEX *select_lex = &(join->thd->lex->select_lex);
DBUG_ENTER("make_join_readinfo");
for (i=join->const_tables ; i < join->tables ; i++)
@@ -5105,7 +5106,7 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
thd->proc_info="converting HEAP to MyISAM";
if (create_myisam_tmp_table(&new_table,param,
- thd->lex.select_lex.options | thd->options))
+ thd->lex->select_lex.options | thd->options))
goto err2;
if (open_tmp_table(&new_table))
goto err1;
@@ -5301,7 +5302,7 @@ sub_select_cache(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
}
if (join->thd->killed) // If aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
return -2; /* purecov: inspected */
}
if (join_tab->use_quick != 2 || test_if_quick_select(join_tab) <= 0)
@@ -5341,7 +5342,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
{
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
return -2; /* purecov: inspected */
}
join->examined_rows++;
@@ -5422,7 +5423,7 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skipp_last)
{
if (join->thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
return -2; // Aborted by user /* purecov: inspected */
}
SQL_SELECT *select=join_tab->select;
@@ -6047,7 +6048,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
DBUG_RETURN(-2); /* purecov: inspected */
}
if (!end_of_records)
@@ -6115,7 +6116,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(0);
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
DBUG_RETURN(-2); /* purecov: inspected */
}
@@ -6185,7 +6186,7 @@ end_unique_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(0);
if (join->thd->killed) // Aborted by user
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
DBUG_RETURN(-2); /* purecov: inspected */
}
@@ -6232,7 +6233,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (join->thd->killed)
{ // Aborted by user
- my_error(ER_SERVER_SHUTDOWN,MYF(0)); /* purecov: inspected */
+ join->thd->send_kill_message();
DBUG_RETURN(-2); /* purecov: inspected */
}
if (!join->first_record || end_of_records ||
@@ -6978,7 +6979,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
error=0;
goto err;
}
@@ -7090,7 +7091,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
error=0;
goto err;
}
@@ -8549,7 +8550,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
List<Item> field_list;
List<Item> item_list;
THD *thd=join->thd;
- SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
+ SELECT_LEX *select_lex = &(join->thd->lex->select_lex);
select_result *result=join->result;
Item *item_null= new Item_null();
CHARSET_INFO *cs= &my_charset_latin1;
@@ -8734,8 +8735,8 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
sl= sl->next_select())
{
res= mysql_explain_select(thd, sl,
- (((&thd->lex.select_lex)==sl)?
- ((thd->lex.all_selects_list != sl)?"PRIMARY":
+ (((&thd->lex->select_lex)==sl)?
+ ((thd->lex->all_selects_list != sl)?"PRIMARY":
"SIMPLE"):
((sl == first)?
((sl->linkage == DERIVED_TABLE_TYPE) ?
@@ -8763,7 +8764,7 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
DBUG_ENTER("mysql_explain_select");
DBUG_PRINT("info", ("Select 0x%lx, type %s", (ulong)select_lex, type))
select_lex->type= type;
- thd->lex.current_select= select_lex;
+ thd->lex->current_select= select_lex;
SELECT_LEX_UNIT *unit= select_lex->master_unit();
int res= mysql_select(thd, &select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
@@ -8774,7 +8775,7 @@ int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
(ORDER*) select_lex->order_list.first,
(ORDER*) select_lex->group_list.first,
select_lex->having,
- (ORDER*) thd->lex.proc_list.first,
+ (ORDER*) thd->lex->proc_list.first,
select_lex->options | thd->options | SELECT_DESCRIBE,
result, unit, select_lex, 0);
DBUG_RETURN(res);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9084269f486..a0f15f205e4 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1352,7 +1352,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
thd_info->command=(int) tmp->command;
if ((mysys_var= tmp->mysys_var))
pthread_mutex_lock(&mysys_var->mutex);
- thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
+ thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
#ifndef EMBEDDED_LIBRARY
thd_info->state_info= (char*) (tmp->locked ? "Locked" :
tmp->net.reading_or_writing ?
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 37f8d0d7f4f..8c577375ddb 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -256,15 +256,11 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (some_tables_deleted || tmp_table_deleted)
{
query_cache_invalidate3(thd, tables, 0);
- if (!dont_log_query)
+ if (!dont_log_query && mysql_bin_log.is_open())
{
- mysql_update_log.write(thd, thd->query,thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length,
- tmp_table_deleted && !some_tables_deleted);
- mysql_bin_log.write(&qinfo);
- }
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ tmp_table_deleted && !some_tables_deleted);
+ mysql_bin_log.write(&qinfo);
}
}
@@ -931,17 +927,13 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
thd->tmp_table_used= 1;
}
- if (!tmp_table && !no_log)
- {
+ if (!tmp_table && !no_log && mysql_bin_log.is_open())
// Must be written before unlock
- mysql_update_log.write(thd,thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length,
- test(create_info->options &
- HA_LEX_CREATE_TMP_TABLE));
- mysql_bin_log.write(&qinfo);
- }
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ test(create_info->options &
+ HA_LEX_CREATE_TMP_TABLE));
+ mysql_bin_log.write(&qinfo);
}
error=0;
end:
@@ -1187,7 +1179,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
}
else
{
- char* backup_dir = thd->lex.backup_dir;
+ char* backup_dir = thd->lex->backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->real_name;
char* db = thd->db ? thd->db : table->db;
@@ -1880,7 +1872,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
if (!error)
{
- mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -2275,7 +2266,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
my_free((gptr) new_table,MYF(0));
goto err;
}
- mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -2407,7 +2397,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
goto err;
}
thd->proc_info="end";
- mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
@@ -2505,8 +2494,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
tables.db = from->table_cache_key;
error=1;
- if (thd->lex.select_lex.setup_ref_array(thd, order_num) ||
- setup_order(thd, thd->lex.select_lex.ref_pointer_array,
+ if (thd->lex.select_lex->setup_ref_array(thd, order_num) ||
+ setup_order(thd, thd->lex->select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(from->sort.found_records = filesort(thd, from, sortorder, length,
@@ -2536,7 +2525,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
{
if (thd->killed)
{
- my_error(ER_SERVER_SHUTDOWN,MYF(0));
+ thd->send_kill_message();
error= 1;
break;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index ae91b0b3ace..3448128e03d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -115,7 +115,7 @@ bool select_union::flush()
int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
bool tables_and_fields_initied)
{
- SELECT_LEX *lex_select_save= thd->lex.current_select;
+ SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *select_cursor;
DBUG_ENTER("st_select_lex_unit::prepare");
@@ -130,7 +130,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
t_and_f= tables_and_fields_initied;
bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM));
- thd->lex.current_select= select_cursor= first_select_in_union();
+ thd->lex->current_select= select_cursor= first_select_in_union();
/* Global option */
if (t_and_f)
{
@@ -190,7 +190,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
union_result);
- thd->lex.current_select= sl;
+ thd->lex->current_select= sl;
offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
@@ -215,7 +215,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
}
item_list.empty();
- thd->lex.current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
{
List_iterator<Item> it(select_cursor->item_list);
Field **field;
@@ -230,14 +230,14 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
DBUG_RETURN(res || thd->is_fatal_error ? 1 : 0);
err:
- thd->lex.current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
DBUG_RETURN(-1);
}
int st_select_lex_unit::exec()
{
- SELECT_LEX *lex_select_save= thd->lex.current_select;
+ SELECT_LEX *lex_select_save= thd->lex->current_select;
SELECT_LEX *select_cursor=first_select_in_union();
ha_rows add_rows=0;
DBUG_ENTER("st_select_lex_unit::exec");
@@ -305,13 +305,13 @@ int st_select_lex_unit::exec()
res= sl->join->error;
if (!res && union_result->flush())
{
- thd->lex.current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
DBUG_RETURN(1);
}
}
if (res)
{
- thd->lex.current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
DBUG_RETURN(res);
}
if (found_rows_for_union && !sl->braces &&
@@ -333,7 +333,7 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
ulong options= thd->options;
- thd->lex.current_select= fake_select_lex;
+ thd->lex->current_select= fake_select_lex;
if (select_cursor->braces)
{
offset_limit_cnt= global_parameters->offset_limit;
@@ -394,7 +394,7 @@ int st_select_lex_unit::exec()
*/
}
}
- thd->lex.current_select= lex_select_save;
+ thd->lex->current_select= lex_select_save;
DBUG_RETURN(res);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 29138f10989..fb19c53ec2b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -68,7 +68,7 @@ int mysql_update(THD *thd,
SQL_SELECT *select;
READ_RECORD info;
TABLE_LIST *update_table_list= ((TABLE_LIST*)
- thd->lex.select_lex.table_list.first);
+ thd->lex->select_lex.table_list.first);
TABLE_LIST tables;
List<Item> all_fields;
DBUG_ENTER("mysql_update");
@@ -79,7 +79,7 @@ int mysql_update(THD *thd,
if ((open_and_lock_tables(thd, table_list)))
DBUG_RETURN(-1);
thd->proc_info="init";
- fix_tables_pointers(thd->lex.all_selects_list);
+ fix_tables_pointers(thd->lex->all_selects_list);
table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
@@ -95,10 +95,10 @@ int mysql_update(THD *thd,
if (setup_tables(update_table_list) ||
setup_conds(thd,update_table_list,&conds) ||
- thd->lex.select_lex.setup_ref_array(thd, order_num) ||
- setup_order(thd, thd->lex.select_lex.ref_pointer_array,
+ thd->lex.select_lex->setup_ref_array(thd, order_num) ||
+ setup_order(thd, thd->lex->select_lex.ref_pointer_array,
&tables, all_fields, all_fields, order) ||
- setup_ftfuncs(&thd->lex.select_lex))
+ setup_ftfuncs(&thd->lex->select_lex))
DBUG_RETURN(-1); /* purecov: inspected */
/* Check that we are not using table that we are updating in a sub select */
@@ -138,7 +138,7 @@ int mysql_update(THD *thd,
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0))
{
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
DBUG_RETURN(-1); /* purecov: inspected */
}
@@ -149,7 +149,7 @@ int mysql_update(THD *thd,
(select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
if (error)
{
DBUG_RETURN(-1); // Error in where
@@ -160,7 +160,7 @@ int mysql_update(THD *thd,
/* If running in safe sql mode, don't allow updates without keys */
if (!table->quick_keys)
{
- thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
+ thd->lex->select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
{
my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,
@@ -168,7 +168,7 @@ int mysql_update(THD *thd,
goto err;
}
}
- init_ftfuncs(thd, &thd->lex.select_lex, 1);
+ init_ftfuncs(thd, &thd->lex->select_lex, 1);
/* Check if we are modifying a key that we are used to search with */
if (select && select->quick)
used_key_is_modified= (!select->quick->unique_key_range() &&
@@ -343,7 +343,6 @@ int mysql_update(THD *thd,
log_delayed= (transactional_table || table->tmp_table);
if (updated && (error <= 0 || !transactional_table))
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
@@ -367,9 +366,9 @@ int mysql_update(THD *thd,
}
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
if (error >= 0)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
+ send_error(thd,thd->killed_errno()); /* purecov: inspected */
else
{
char buff[80];
@@ -386,7 +385,7 @@ int mysql_update(THD *thd,
err:
delete select;
- free_underlaid_joins(thd, &thd->lex.select_lex);
+ free_underlaid_joins(thd, &thd->lex->select_lex);
if (table->key_read)
{
table->key_read=0;
@@ -421,7 +420,7 @@ int mysql_multi_update(THD *thd,
table_list->grant.want_privilege=(SELECT_ACL & ~table_list->grant.privilege);
if ((res=open_and_lock_tables(thd,table_list)))
DBUG_RETURN(res);
- fix_tables_pointers(thd->lex.all_selects_list);
+ fix_tables_pointers(thd->lex->all_selects_list);
select_lex->select_limit= HA_POS_ERROR;
if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
@@ -966,7 +965,6 @@ bool multi_update::send_eof()
if (updated && (local_error <= 0 || !trans_safe))
{
- mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 539bb90d907..75ff156cc63 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -28,13 +28,16 @@
#define MYSQL_YACC
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
-#define Lex (&(YYTHD->lex))
+#define Lex ((YYTHD->lex))
#define Select Lex->current_select
#include "mysql_priv.h"
#include "slave.h"
#include "sql_acl.h"
#include "lex_symbol.h"
#include "item_create.h"
+#include "sp_head.h"
+#include "sp_pcontext.h"
+#include "sp.h"
#include <myisam.h>
#include <myisammrg.h>
@@ -121,6 +124,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token AVG_SYM
%token BEGIN_SYM
%token BINLOG_SYM
+%token CALL_SYM
%token CHANGE
%token CLIENT_SYM
%token COMMENT_SYM
@@ -200,10 +204,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token COLUMNS
%token COLUMN_SYM
%token CONCURRENT
+%token CONNECTION_SYM
%token CONSTRAINT
%token CONVERT_SYM
%token DATABASES
%token DATA_SYM
+%token DECLARE_SYM
%token DEFAULT
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
@@ -249,6 +255,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token INFILE
%token INNER_SYM
%token INNOBASE_SYM
+%token INOUT_SYM
%token INTO
%token IN_SYM
%token ISOLATION
@@ -264,6 +271,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token LIKE
%token LINES
%token LOCAL_SYM
+%token LOCATOR_SYM
%token LOG_SYM
%token LOGS_SYM
%token LONG_NUM
@@ -307,6 +315,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token OR
%token OR_OR_CONCAT
%token ORDER_SYM
+%token OUT_SYM
%token OUTER
%token OUTFILE
%token DUMPFILE
@@ -346,6 +355,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SIMPLE_SYM
%token SHUTDOWN
%token SPATIAL_SYM
+%token SPECIFIC_SYM
%token SSL_SYM
%token STARTING
%token STATUS_SYM
@@ -366,9 +376,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FUNC_ARG1
%token FUNC_ARG2
%token FUNC_ARG3
-%token UDF_RETURNS_SYM
+%token RETURN_SYM
+%token RETURNS_SYM
%token UDF_SONAME_SYM
-%token UDF_SYM
+%token FUNCTION_SYM
%token UNCOMMITTED_SYM
%token UNDERSCORE_CHARSET
%token UNICODE_SYM
@@ -514,6 +525,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SECOND_SYM
%token SECOND_MICROSECOND_SYM
%token SHARE_SYM
+%token SP_FUNC
%token SUBDATE_SYM
%token SUBSTRING
%token SUBSTRING_INDEX
@@ -547,6 +559,18 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_SMALL_RESULT
%token SQL_BUFFER_RESULT
+%token CURSOR_SYM
+%token ELSEIF_SYM
+%token ITERATE_SYM
+%token LEAVE_SYM
+%token LOOP_SYM
+%token REPEAT_SYM
+%token UNTIL_SYM
+%token WHILE_SYM
+%token ASENSITIVE_SYM
+%token INSENSITIVE_SYM
+%token SENSITIVE_SYM
+
%token ISSUER_SYM
%token SUBJECT_SYM
%token CIPHER_SYM
@@ -573,6 +597,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component
+ SP_FUNC ident_or_spfunc
%type <lex_str_ptr>
opt_table_alias
@@ -608,7 +633,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
table_wild no_in_expr expr_expr simple_expr no_and_expr
using_list expr_or_default set_expr_or_default interval_expr
param_marker singlerow_subselect singlerow_subselect_init
- exists_subselect exists_subselect_init
+ exists_subselect exists_subselect_init sp_opt_default
%type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg
@@ -696,8 +721,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
union_clause union_list union_option
precision subselect_start opt_and charset
subselect_end select_var_list select_var_list_init help opt_len
+ statement
END_OF_INPUT
+%type <NONE> call sp_proc_stmts sp_proc_stmt
+%type <num> sp_decls sp_decl sp_decl_idents sp_opt_inout
+
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM
@@ -710,23 +739,29 @@ query:
{
THD *thd= YYTHD;
if (!thd->bootstrap &&
- (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
+ (!(thd->lex->select_lex.options & OPTION_FOUND_COMMENT)))
{
send_error(thd,ER_EMPTY_QUERY);
YYABORT;
}
else
{
- thd->lex.sql_command = SQLCOM_EMPTY_QUERY;
+ thd->lex->sql_command = SQLCOM_EMPTY_QUERY;
}
}
| verb_clause END_OF_INPUT {};
verb_clause:
+ statement
+ | begin
+ ;
+
+/* Verb clauses, except begin */
+statement:
alter
| analyze
| backup
- | begin
+ | call
| change
| check
| commit
@@ -911,20 +946,560 @@ create:
lex->name=$4.str;
lex->create_info.options=$3;
}
- | CREATE udf_func_type UDF_SYM IDENT_sys
+ | CREATE udf_func_type FUNCTION_SYM ident_or_spfunc
{
LEX *lex=Lex;
- lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = $4;
lex->udf.type= $2;
}
- UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
+ create_function_tail
+ {}
+ | CREATE PROCEDURE ident
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "PROCEDURE");
+ YYABORT;
+ }
+ /* Order is important here: new - reset - init */
+ sp= new sp_head();
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(&$3, lex, 0, 0);
+
+ sp->m_type= TYPE_ENUM_PROCEDURE;
+ lex->sphead= sp;
+ /*
+ * We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ * stored procedure, otherwise yylex will chop it into pieces
+ * at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
+ }
+ '(' sp_pdparam_list ')'
+ {
+ Lex->spcont->set_params();
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+
+ lex->sql_command= SQLCOM_CREATE_PROCEDURE;
+ /* Restore flag if it was cleared above */
+ if (lex->sphead->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ lex->sphead->restore_thd_mem_root(YYTHD);
+ }
+ ;
+
+ident_or_spfunc:
+ IDENT_sys { $$= $1; }
+ | SP_FUNC { $$= $1; }
+ ;
+
+create_function_tail:
+ RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING_sys
{
LEX *lex=Lex;
- lex->udf.returns=(Item_result) $7;
- lex->udf.dl=$9.str;
+ lex->sql_command = SQLCOM_CREATE_FUNCTION;
+ lex->udf.returns=(Item_result) $2;
+ lex->udf.dl=$4.str;
}
- ;
+ | '('
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "FUNCTION");
+ YYABORT;
+ }
+ /* Order is important here: new - reset - init */
+ sp= new sp_head();
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(&lex->udf.name, lex, 0, 0);
+
+ sp->m_type= TYPE_ENUM_FUNCTION;
+ lex->sphead= sp;
+ /*
+ * We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ * stored procedure, otherwise yylex will chop it into pieces
+ * at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+ }
+ sp_fdparam_list ')'
+ {
+ Lex->spcont->set_params();
+ }
+ RETURNS_SYM type
+ {
+ Lex->sphead->m_returns= (enum enum_field_types)$7;
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+
+ lex->sql_command = SQLCOM_CREATE_SPFUNCTION;
+ /* Restore flag if it was cleared above */
+ if (lex->sphead->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ lex->sphead->restore_thd_mem_root(YYTHD);
+ }
+ ;
+
+call:
+ CALL_SYM ident_or_spfunc
+ {
+ LEX *lex = Lex;
+
+ lex->sql_command= SQLCOM_CALL;
+ lex->udf.name= $2;
+ lex->value_list.empty();
+ }
+ '(' sp_cparam_list ')' {}
+ ;
+
+/* CALL parameters */
+sp_cparam_list:
+ /* Empty */
+ | sp_cparams
+ ;
+
+sp_cparams:
+ sp_cparams ',' expr
+ {
+ Lex->value_list.push_back($3);
+ }
+ | expr
+ {
+ Lex->value_list.push_back($1);
+ }
+ ;
+
+/* Stored FUNCTION parameter declaration list */
+sp_fdparam_list:
+ /* Empty */
+ | sp_fdparams
+ ;
+
+sp_fdparams:
+ sp_fdparams ',' sp_fdparam
+ | sp_fdparam
+ ;
+
+sp_fdparam:
+ ident type sp_opt_locator
+ {
+ Lex->spcont->push(&$1, (enum enum_field_types)$2, sp_param_in);
+ }
+ ;
+
+/* Stored PROCEDURE parameter declaration list */
+sp_pdparam_list:
+ /* Empty */
+ | sp_pdparams
+ ;
+
+sp_pdparams:
+ sp_pdparams ',' sp_pdparam
+ | sp_pdparam
+ ;
+
+sp_pdparam:
+ sp_opt_inout ident type sp_opt_locator
+ {
+ Lex->spcont->push(&$2,
+ (enum enum_field_types)$3,
+ (sp_param_mode_t)$1);
+ }
+ ;
+
+sp_opt_inout:
+ /* Empty */ { $$= sp_param_in; }
+ | IN_SYM { $$= sp_param_in; }
+ | OUT_SYM { $$= sp_param_out; }
+ | INOUT_SYM { $$= sp_param_inout; }
+ ;
+
+sp_opt_locator:
+ /* Empty */
+ | AS LOCATOR_SYM
+ ;
+
+sp_proc_stmts:
+ sp_proc_stmt ';'
+ | sp_proc_stmts sp_proc_stmt ';'
+ ;
+
+sp_decls:
+ /* Empty */
+ {
+ $$= 0;
+ }
+ | sp_decls sp_decl ';'
+ {
+ $$= $1 + $2;
+ }
+ ;
+
+sp_decl:
+ DECLARE_SYM sp_decl_idents type sp_opt_default
+ {
+ LEX *lex= Lex;
+ uint max= lex->spcont->current_framesize();
+ enum enum_field_types type= (enum enum_field_types)$3;
+ Item *it= $4;
+
+ for (uint i = max-$2 ; i < max ; i++)
+ {
+ lex->spcont->set_type(i, type);
+ if (! it)
+ lex->spcont->set_isset(i, FALSE);
+ else
+ {
+ sp_instr_set *in= new sp_instr_set(lex->sphead->instructions(),
+ i, it, type);
+
+ lex->sphead->add_instr(in);
+ lex->spcont->set_isset(i, TRUE);
+ }
+ }
+ $$= $2;
+ }
+ ;
+
+sp_decl_idents:
+ ident
+ {
+ Lex->spcont->push(&$1, (enum_field_types)0, sp_param_in);
+ $$= 1;
+ }
+ | sp_decl_idents ',' ident
+ {
+ Lex->spcont->push(&$3, (enum_field_types)0, sp_param_in);
+ $$= $1 + 1;
+ }
+ ;
+
+sp_opt_default:
+ /* Empty */ { $$ = NULL; }
+ | DEFAULT expr { $$ = $2; }
+ ;
+
+sp_proc_stmt:
+ {
+ Lex->sphead->reset_lex(YYTHD);
+ }
+ statement
+ {
+ LEX *lex= Lex;
+
+ if (lex->sql_command == SQLCOM_SELECT && !lex->result)
+ {
+ /* We maybe have one or more SELECT without INTO */
+ lex->sphead->m_multi_query= TRUE;
+ }
+ /* Don't add an instruction for empty SET statements.
+ ** (This happens if the SET only contained local variables,
+ ** which get their set instructions generated separately.)
+ */
+ if (lex->sql_command != SQLCOM_SET_OPTION ||
+ ! lex->var_list.is_empty())
+ {
+ /* Currently we can't handle queries inside a FUNCTION,
+ ** because of the way table locking works.
+ ** This is unfortunate, and limits the usefulness of functions
+ ** a great deal, but it's nothing we can do about this at the
+ ** moment.
+ */
+ if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
+ lex->sql_command != SQLCOM_SET_OPTION)
+ {
+ send_error(YYTHD, ER_SP_BADQUERY);
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_stmt *i=new sp_instr_stmt(lex->sphead->instructions());
+
+ i->set_lex(lex);
+ lex->sphead->add_instr(i);
+ lex->sp_lex_in_use= TRUE;
+ }
+ }
+ lex->sphead->restore_lex(YYTHD);
+ }
+ | RETURN_SYM expr
+ {
+ LEX *lex= Lex;
+
+ if (lex->sphead->m_type == TYPE_ENUM_PROCEDURE)
+ {
+ send_error(YYTHD, ER_SP_BADRETURN);
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_return *i=
+ new sp_instr_return(lex->sphead->instructions(),
+ $2, lex->sphead->m_returns);
+
+ lex->sphead->add_instr(i);
+ }
+ }
+ | IF sp_if END IF {}
+ | CASE_SYM WHEN_SYM
+ {
+ Lex->sphead->m_simple_case= FALSE;
+ }
+ sp_case END CASE_SYM {}
+ | CASE_SYM expr WHEN_SYM
+ {
+ /* We "fake" this by using an anonymous variable which we
+ set to the expression. Note that all WHENs are evaluate
+ at the same frame level, so we then know that it's the
+ top-most variable in the frame. */
+ LEX *lex= Lex;
+ uint offset= lex->spcont->current_framesize();
+ sp_instr_set *i = new sp_instr_set(lex->sphead->instructions(),
+ offset, $2, MYSQL_TYPE_STRING);
+ LEX_STRING dummy;
+
+ dummy.str= (char *)"";
+ dummy.length= 0;
+ lex->spcont->push(&dummy, MYSQL_TYPE_STRING, sp_param_in);
+ lex->sphead->add_instr(i);
+ lex->sphead->m_simple_case= TRUE;
+ }
+ sp_case END CASE_SYM
+ {
+ Lex->spcont->pop();
+ }
+ | sp_labeled_control
+ {}
+ | { /* Unlabeled controls get a secret label. */
+ LEX *lex= Lex;
+
+ lex->spcont->push_label((char *)"", lex->sphead->instructions());
+ }
+ sp_unlabeled_control
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ | LEAVE_SYM IDENT
+ {
+ LEX *lex= Lex;
+ sp_head *sp = lex->sphead;
+ sp_label_t *lab= lex->spcont->find_label($2.str);
+
+ if (! lab)
+ {
+ net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "LEAVE", $2.str);
+ YYABORT;
+ }
+ else
+ {
+ sp_instr_jump *i= new sp_instr_jump(sp->instructions());
+
+ sp->push_backpatch(i, lab); /* Jumping forward */
+ sp->add_instr(i);
+ }
+ }
+ | ITERATE_SYM IDENT
+ {
+ LEX *lex= Lex;
+ sp_label_t *lab= lex->spcont->find_label($2.str);
+
+ if (! lab)
+ {
+ net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "ITERATE", $2.str);
+ YYABORT;
+ }
+ else
+ {
+ uint ip= lex->sphead->instructions();
+ sp_instr_jump *i= new sp_instr_jump(ip, lab->ip); /* Jump back */
+
+ lex->sphead->add_instr(i);
+ }
+ }
+ ;
+
+sp_if:
+ expr THEN_SYM
+ {
+ sp_head *sp= Lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $1);
+
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_instr(i);
+ }
+ sp_proc_stmts
+ {
+ sp_head *sp= Lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump *i = new sp_instr_jump(ip);
+
+ sp->add_instr(i);
+ sp->backpatch(ctx->pop_label());
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ }
+ sp_elseifs
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ ;
+
+sp_elseifs:
+ /* Empty */
+ | ELSEIF_SYM sp_if
+ | ELSE sp_proc_stmts
+ ;
+
+sp_case:
+ expr THEN_SYM
+ {
+ sp_head *sp= Lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i;
+
+ if (! sp->m_simple_case)
+ i= new sp_instr_jump_if_not(ip, $1);
+ else
+ { /* Simple case: <caseval> = <whenval> */
+ Item *var= (Item*) new Item_splocal(ctx->current_framesize()-1);
+ Item *expr= Item_bool_func2::eq_creator(var, $1);
+
+ i= new sp_instr_jump_if_not(ip, expr);
+ }
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ sp->add_instr(i);
+ }
+ sp_proc_stmts
+ {
+ sp_head *sp= Lex->sphead;
+ sp_pcontext *ctx= Lex->spcont;
+ uint ip= sp->instructions();
+ sp_instr_jump *i = new sp_instr_jump(ip);
+
+ sp->add_instr(i);
+ sp->backpatch(ctx->pop_label());
+ sp->push_backpatch(i, ctx->push_label((char *)"", 0));
+ }
+ sp_whens
+ {
+ LEX *lex= Lex;
+
+ lex->sphead->backpatch(lex->spcont->pop_label());
+ }
+ ;
+
+sp_whens:
+ /* Empty */ {}
+ | WHEN_SYM sp_case {}
+ | ELSE sp_proc_stmts {}
+ ;
+
+sp_labeled_control:
+ IDENT ':'
+ {
+ LEX *lex= Lex;
+ sp_label_t *lab= lex->spcont->find_label($1.str);
+
+ if (lab)
+ {
+ net_printf(YYTHD, ER_SP_LABEL_REDEFINE, $1.str);
+ YYABORT;
+ }
+ else
+ {
+ lex->spcont->push_label($1.str,
+ lex->sphead->instructions());
+ }
+ }
+ sp_unlabeled_control IDENT
+ {
+ LEX *lex= Lex;
+ sp_label_t *lab= lex->spcont->find_label($5.str);
+
+ if (!lab ||
+ my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+ {
+ net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str);
+ YYABORT;
+ }
+ else
+ {
+ lex->spcont->pop_label();
+ lex->sphead->backpatch(lab);
+ }
+ }
+ ;
+
+sp_unlabeled_control:
+ BEGIN_SYM
+ sp_decls
+ sp_proc_stmts
+ END
+ { /* QQ This is just a dummy for grouping declarations and statements
+ together. No [[NOT] ATOMIC] yet, and we need to figure out how
+ make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
+ Lex->spcont->pop($2);
+ }
+ | LOOP_SYM
+ sp_proc_stmts END LOOP_SYM
+ {
+ LEX *lex= Lex;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_instr_jump *i = new sp_instr_jump(ip, lab->ip);
+
+ lex->sphead->add_instr(i);
+ }
+ | WHILE_SYM expr DO_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+ uint ip= sp->instructions();
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $2);
+
+ /* Jumping forward */
+ sp->push_backpatch(i, lex->spcont->last_label());
+ sp->add_instr(i);
+ }
+ sp_proc_stmts END WHILE_SYM
+ {
+ LEX *lex= Lex;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_instr_jump *i = new sp_instr_jump(ip, lab->ip);
+
+ lex->sphead->add_instr(i);
+ }
+ | REPEAT_SYM sp_proc_stmts UNTIL_SYM expr END REPEAT_SYM
+ {
+ LEX *lex= Lex;
+ uint ip= lex->sphead->instructions();
+ sp_label_t *lab= lex->spcont->last_label(); /* Jumping back */
+ sp_instr_jump_if_not *i = new sp_instr_jump_if_not(ip, $4, lab->ip);
+
+ lex->sphead->add_instr(i);
+ }
+ ;
create2:
'(' create2a {}
@@ -1579,7 +2154,7 @@ alter:
ALTER opt_ignore TABLE_SYM table_ident
{
THD *thd= YYTHD;
- LEX *lex=&thd->lex;
+ LEX *lex= thd->lex;
lex->sql_command = SQLCOM_ALTER_TABLE;
lex->name=0;
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
@@ -1607,8 +2182,30 @@ alter:
LEX *lex=Lex;
lex->sql_command=SQLCOM_ALTER_DB;
lex->name=$3.str;
- };
+ }
+ | ALTER PROCEDURE ident
+ /* QQ Characteristics missing for now */
+ opt_restrict
+ {
+ LEX *lex=Lex;
+ /* This is essensially an no-op right now, since we haven't
+ put the characteristics in yet. */
+ lex->sql_command= SQLCOM_ALTER_PROCEDURE;
+ lex->udf.name= $3;
+ }
+ | ALTER FUNCTION_SYM ident
+ /* QQ Characteristics missing for now */
+ opt_restrict
+ {
+ LEX *lex=Lex;
+
+ /* This is essensially an no-op right now, since we haven't
+ put the characteristics in yet. */
+ lex->sql_command= SQLCOM_ALTER_FUNCTION;
+ lex->udf.name= $3;
+ }
+ ;
alter_list:
| alter_list_item
@@ -2080,7 +2677,7 @@ select_item_list:
THD *thd= YYTHD;
if (add_item_to_list(thd, new Item_field(NULL, NULL, "*")))
YYABORT;
- (thd->lex.current_select->with_wild)++;
+ (thd->lex->current_select->with_wild)++;
};
@@ -2388,6 +2985,8 @@ simple_expr:
{ $$= new Item_date_add_interval($3, $5, INTERVAL_DAY, 0);}
| ADDDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3, $6, $7, 0); }
+ | REPEAT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_repeat($3,$5); }
| ATAN '(' expr ')'
{ $$= new Item_func_atan($3); }
| ATAN '(' expr ',' expr ')'
@@ -2647,6 +3246,14 @@ simple_expr:
{ $$= new Item_func_round($3,$5,1); }
| TRUE_SYM
{ $$= new Item_int((char*) "TRUE",1,1); }
+ | SP_FUNC '(' udf_expr_list ')'
+ {
+ sp_add_fun_to_lex(Lex, $1);
+ if ($3)
+ $$= new Item_func_sp($1, *$3);
+ else
+ $$= new Item_func_sp($1);
+ }
| UDA_CHAR_SUM '(' udf_expr_list ')'
{
if ($3 != NULL)
@@ -3322,11 +3929,33 @@ select_var_list:
| select_var_ident {}
;
-select_var_ident: '@' ident_or_text
+select_var_ident:
+ '@' ident_or_text
{
LEX *lex=Lex;
- if (lex->result && ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING))))
+ if (lex->result)
+ ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($2,0,0));
+ else
+ YYABORT;
+ }
+ | ident_or_text
+ {
+ LEX *lex=Lex;
+ if (!lex->spcont)
+ YYABORT;
+ sp_pvar_t *t;
+ if (!(t=lex->spcont->find_pvar(&$1)))
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ if (! lex->result)
YYABORT;
+ else
+ {
+ ((select_dumpvar *)lex->result)->var_list.push_back( new my_var($1,1,t->offset));
+ t->isset= TRUE;
+ }
}
;
@@ -3407,11 +4036,19 @@ drop:
lex->drop_if_exists=$3;
lex->name=$4.str;
}
- | DROP UDF_SYM IDENT_sys
+ | DROP FUNCTION_SYM if_exists IDENT_sys opt_restrict
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_FUNCTION;
- lex->udf.name = $3;
+ lex->drop_if_exists= $3;
+ lex->udf.name= $4;
+ }
+ | DROP PROCEDURE if_exists IDENT_sys opt_restrict
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_DROP_PROCEDURE;
+ lex->drop_if_exists= $3;
+ lex->udf.name= $4;
}
| DROP USER
{
@@ -3423,7 +4060,6 @@ drop:
{}
;
-
table_list:
table_name
| table_list ',' table_name;
@@ -3482,7 +4118,6 @@ replace:
}
insert_field_spec
{}
- {}
;
insert_lock_option:
@@ -3836,8 +4471,8 @@ show_param:
| opt_var_type VARIABLES wild
{
THD *thd= YYTHD;
- thd->lex.sql_command= SQLCOM_SHOW_VARIABLES;
- thd->lex.option_type= (enum_var_type) $1;
+ thd->lex->sql_command= SQLCOM_SHOW_VARIABLES;
+ thd->lex->option_type= (enum_var_type) $1;
}
| charset wild
{ Lex->sql_command= SQLCOM_SHOW_CHARSETS; }
@@ -4021,18 +4656,23 @@ purge_option:
/* kill threads */
kill:
- KILL_SYM expr
+ KILL_SYM kill_option expr
{
LEX *lex=Lex;
- if ($2->fix_fields(lex->thd, 0, &$2) || $2->check_cols(1))
+ if ($3->fix_fields(lex->thd, 0, &$3) || $3->check_cols(1))
{
send_error(lex->thd, ER_SET_CONSTANTS_ONLY);
YYABORT;
}
lex->sql_command=SQLCOM_KILL;
- lex->thread_id= (ulong) $2->val_int();
+ lex->thread_id= (ulong) $3->val_int();
};
+kill_option:
+ /* empty */ { Lex->type= 0; }
+ | CONNECTION_SYM { Lex->type= 0; }
+ | QUERY_SYM { Lex->type= ONLY_KILL_QUERY; };
+
/* change database */
use: USE_SYM ident
@@ -4218,16 +4858,33 @@ order_ident:
simple_ident:
ident
{
- SELECT_LEX *sel=Select;
- $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
- sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(NullS,NullS,$1.str) :
- (Item*) new Item_ref(NullS,NullS,$1.str);
+ sp_pvar_t *spv;
+ LEX *lex = Lex;
+ sp_pcontext *spc = lex->spcont;
+
+ if (spc && (spv = spc->find_pvar(&$1)))
+ { /* We're compiling a stored procedure and found a variable */
+ if (lex->sql_command != SQLCOM_CALL && ! spv->isset)
+ {
+ net_printf(YYTHD, ER_SP_UNINIT_VAR, $1.str);
+ YYABORT;
+ }
+ else
+ $$ = (Item*) new Item_splocal(spv->offset);
+ }
+ else
+ {
+ SELECT_LEX *sel=Select;
+ $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING ||
+ sel->get_in_sum_expr() > 0) ?
+ (Item*) new Item_field(NullS,NullS,$1.str) :
+ (Item*) new Item_ref(NullS,NullS,$1.str);
+ }
}
| ident '.' ident
{
THD *thd= YYTHD;
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
@@ -4243,7 +4900,7 @@ simple_ident:
| '.' ident '.' ident
{
THD *thd= YYTHD;
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
@@ -4259,7 +4916,7 @@ simple_ident:
| ident '.' ident '.' ident
{
THD *thd= YYTHD;
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
@@ -4536,7 +5193,7 @@ keyword:
| TIMESTAMP {}
| TIME_SYM {}
| TYPE_SYM {}
- | UDF_SYM {}
+ | FUNCTION_SYM {}
| UNCOMMITTED_SYM {}
| UNICODE_SYM {}
| USER {}
@@ -4592,16 +5249,12 @@ opt_var_ident_type:
;
option_value:
- '@' ident_or_text equal expr
- {
- Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
- }
- | internal_variable_name equal set_expr_or_default
+ '@' ident_or_text equal expr
{
- LEX *lex=Lex;
- lex->var_list.push_back(new set_var(lex->option_type, $1.var,
- &$1.base_name, $3));
+ Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
}
+ | internal_or_splocal
+ {}
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{
LEX *lex=Lex;
@@ -4647,7 +5300,7 @@ option_value:
YYABORT;
user->host.str=0;
user->user.str=thd->priv_user;
- thd->lex.var_list.push_back(new set_var_password(user, $3));
+ thd->lex->var_list.push_back(new set_var_password(user, $3));
}
| PASSWORD FOR_SYM user equal text_or_password
{
@@ -5185,7 +5838,7 @@ optional_order_or_limit:
|
{
THD *thd= YYTHD;
- LEX *lex= &thd->lex;
+ LEX *lex= thd->lex;
DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
SELECT_LEX *sel= lex->current_select;
SELECT_LEX_UNIT *unit= sel->master_unit();
@@ -5198,7 +5851,7 @@ optional_order_or_limit:
order_or_limit
{
THD *thd= YYTHD;
- thd->lex.current_select->no_table_names_allowed= 0;
+ thd->lex->current_select->no_table_names_allowed= 0;
thd->where= "";
}
;