Below is the list of changes that have just been committed into a local
5.0 repository of psergey. When psergey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.1900 05/08/22 18:11:03 sergefp@stripped +16 -0
Merge, will not push
sql/sp_head.cc
1.169 05/08/22 18:10:59 sergefp@stripped +1 -1
Merge, will not push
sql/item_func.cc
1.243 05/08/22 18:10:59 sergefp@stripped +4 -0
Merge, will not push
sql/sql_yacc.yy
1.417 05/08/22 18:06:51 sergefp@stripped +0 -0
Auto merged
sql/sql_parse.cc
1.471 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/sql_lex.h
1.194 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/sql_lex.cc
1.164 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/sql_class.h
1.260 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/sp_rcontext.h
1.23 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/sp_head.h
1.66 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/lex.h
1.140 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/item_create.h
1.43 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/item_create.cc
1.56 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/item.h
1.163 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
sql/item.cc
1.164 05/08/22 18:06:50 sergefp@stripped +0 -0
Auto merged
mysql-test/r/rpl_sp.result
1.7 05/08/22 18:06:49 sergefp@stripped +0 -2
Auto merged
mysql-test/r/query_cache.result
1.64 05/08/22 18:06:49 sergefp@stripped +0 -0
Auto merged
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: sergefp
# Host: newbox.mylan
# Root: /home/psergey/mysql-5.0-bug12335/RESYNC
--- 1.163/sql/item.cc 2005-08-19 23:29:25 +04:00
+++ 1.164/sql/item.cc 2005-08-22 18:06:50 +04:00
@@ -788,7 +788,7 @@
return res;
}
-
+/////////////////////////////////////////////////////////////////////
double Item_splocal::val_real()
{
DBUG_ASSERT(fixed);
@@ -897,6 +897,108 @@
str->qs_append(m_offset);
}
+/////////////////////////////////////////////////////////////////////
+double Item_rename::val_real()
+{
+ DBUG_ASSERT(fixed);
+ double ret= value->val_real();
+ Item::null_value= value->null_value;
+ return ret;
+}
+
+
+longlong Item_rename::val_int()
+{
+ DBUG_ASSERT(fixed);
+ longlong ret= value->val_int();
+ Item::null_value= value->null_value;
+ return ret;
+}
+
+
+String *Item_rename::val_str(String *sp)
+{
+ DBUG_ASSERT(fixed);
+ String *ret= value->val_str(sp);
+ Item::null_value= value->null_value;
+ return ret;
+}
+
+
+my_decimal *Item_rename::val_decimal(my_decimal *decimal_value)
+{
+ DBUG_ASSERT(fixed);
+ my_decimal *val= value->val_decimal(decimal_value);
+ Item::null_value= value->null_value;
+ return val;
+}
+
+
+bool Item_rename::is_null()
+{
+ bool ret= value->is_null();
+ Item::null_value= value->null_value;
+ return ret;
+}
+
+#if 0
+Item **
+Item_rename::this_item_addr(THD *thd, Item **addr)
+{
+ return &m_item; //need this?
+}
+
+Item *
+Item_rename::this_const_item() const
+{
+ return m_item; //need this?
+}
+#endif
+
+Item::Type
+Item_rename::type() const
+{
+ return value->type();
+}
+
+
+bool Item_rename::fix_fields(THD *thd, Item **)
+{
+ Item *it= this_item();
+ //DBUG_ASSERT(it->fixed);
+ //psergey:TODO: rename.
+
+ if (value->fix_fields(thd, &value) ||
+ name_item->fix_fields(thd, &name_item))
+ return TRUE;
+
+ char buf[128];
+ String s(buf, sizeof(buf), &my_charset_bin);
+ s.length(0);
+ String *ps;
+ ps= name_item->val_str(&s);
+ set_name(ps->ptr(), (uint) ps->length(), system_charset_info);
+ max_length= it->max_length;
+ decimals= it->decimals;
+ fixed= 1;
+ return FALSE;
+}
+
+
+void Item_rename::cleanup()
+{
+ fixed= 0;
+}
+
+
+void Item_rename::print(String *str)
+{
+ // str->reserve(m_name.length+8);
+ // str->append("MAKE_NAME");
+ // str->qs_append(m_offset); psergey:TODO
+}
+
+/////////////////////////////////////////////////////////////////////
/*
--- 1.162/sql/item.h 2005-08-19 22:55:19 +04:00
+++ 1.163/sql/item.h 2005-08-22 18:06:50 +04:00
@@ -700,18 +700,27 @@
};
-// A local SP variable (incl. parameters), used in runtime
+/*
+ A local SP variable (incl. parameters), used in runtime
+
+ psergey: it refers to this_item() = thd->spcont->get_item(m_offset) and
+ delegates everything to that item, except for 'name'. If that item is NULL,
+ Item_splocal says it is NULL too.
+*/
class Item_splocal : public Item
{
private:
uint m_offset;
+
+public:
LEX_STRING m_name;
-public:
+ int pos_in_query;
+ int len_in_query;
- Item_splocal(LEX_STRING name, uint offset)
- : m_offset(offset), m_name(name)
+ Item_splocal(LEX_STRING name, uint offset, int pos_in_q=FALSE)
+ : m_offset(offset), m_name(name), pos_in_query(pos_in_q)
{
Item::maybe_null= TRUE;
}
@@ -750,7 +759,7 @@
bool is_null();
void print(String *str);
- inline void make_field(Send_field *field)
+ void make_field(Send_field *field)
{
Item *it= this_item();
@@ -761,27 +770,79 @@
it->make_field(field);
}
- inline Item_result result_type() const
+ Item_result result_type() const
{
return this_const_item()->result_type();
}
- inline bool const_item() const
+ bool const_item() const
{
return TRUE;
}
- inline int save_in_field(Field *field, bool no_conversions)
+ int save_in_field(Field *field, bool no_conversions)
{
return this_item()->save_in_field(field, no_conversions);
}
- inline bool send(Protocol *protocol, String *str)
+ bool send(Protocol *protocol, String *str)
{
return this_item()->send(protocol, str);
}
};
+
+/*
+ A local SP variable (incl. parameters), used in runtime
+
+ psergey: it refers to this_item() = thd->spcont->get_item(m_offset) and
+ delegates everything to that item, except for 'name'. If that item is NULL,
+ Item_splocal says it is NULL too.
+*/
+class Item_rename : public Item
+{
+ Item *value;
+ Item *name_item;
+public:
+ Item_rename(Item *name, Item *val): value(val), name_item(name)
+ {
+ Item::maybe_null= TRUE;
+ }
+
+ bool fix_fields(THD *, Item **);
+ void cleanup();
+
+ // Abstract methods inherited from Item. Just defer the call to
+ // the item in the frame
+ enum Type type() const;
+
+ double val_real();
+ longlong val_int();
+ String *val_str(String *sp);
+ my_decimal *val_decimal(my_decimal *);
+ bool is_null();
+ void print(String *str);
+
+ Item_result result_type() const
+ {
+ return value->result_type();
+ }
+
+ bool const_item() const
+ {
+ return TRUE;
+ }
+
+ int save_in_field(Field *field, bool no_conversions)
+ {
+ return value->save_in_field(field, no_conversions);
+ }
+
+ inline bool send(Protocol *protocol, String *str)
+ {
+ return value->send(protocol, str);
+ }
+};
bool agg_item_collations(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags= 0);
--- 1.55/sql/item_create.cc 2005-08-12 05:58:18 +04:00
+++ 1.56/sql/item_create.cc 2005-08-22 18:06:50 +04:00
@@ -261,6 +261,12 @@
return new Item_func_mod(a,b);
}
+//psergey:
+Item *create_func_make_name(Item *a, Item *b)
+{
+ return new Item_rename(a,b);
+}
+
Item *create_func_monthname(Item* a)
{
return new Item_func_monthname(a);
--- 1.42/sql/item_create.h 2005-08-12 05:58:18 +04:00
+++ 1.43/sql/item_create.h 2005-08-22 18:06:50 +04:00
@@ -145,6 +145,9 @@
#endif /*HAVE_SPATIAL*/
+//psergey:
+Item *create_func_make_name(Item *a, Item *b);
+
Item *create_func_compress(Item *a);
Item *create_func_uncompress(Item *a);
Item *create_func_uncompressed_length(Item *a);
--- 1.242/sql/item_func.cc 2005-08-18 06:56:28 +04:00
+++ 1.243/sql/item_func.cc 2005-08-22 18:10:59 +04:00
@@ -4688,6 +4688,9 @@
return null_value= f->is_null();
}
+#define tmp_disable_binlog_if(A, x) \
+ {ulong tmp_disable_binlog__save_options= (A)->options; \
+ if (x) (A)->options&= ~OPTION_BIN_LOG
int
Item_func_sp::execute(Item **itp)
@@ -4717,6 +4720,19 @@
m_sp->m_db.str, m_sp->m_name.str, 0, 0))
goto error_check_ctx;
#endif
+ /*
+ Disable the binlogging if this is not a SELECT statement. If this is a
+ SELECT, leave binlogging on, so execute_function() code writes the
+ function call into binlog.
+ */
+
+ tmp_disable_binlog_if(thd, !(thd->lex->requires_prelocking() &&
+ (thd->lex->sql_command == SQLCOM_SELECT ||
+ thd->lex->sql_command == SQLCOM_CALL ||
+ thd->lex->sql_command == SQLCOM_END ||
+ thd->lex->sql_command == SQLCOM_DO ||
+ thd->lex->sql_command == SQLCOM_SET_OPTION)));
+ thd->in_sub_stmt= TRUE;
thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION);
res= m_sp->execute_function(thd, args, arg_count, itp);
--- 1.139/sql/lex.h 2005-08-12 05:58:18 +04:00
+++ 1.140/sql/lex.h 2005-08-22 18:06:50 +04:00
@@ -669,6 +669,9 @@
{ "LPAD", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_lpad)},
{ "LTRIM", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ltrim)},
{ "MAKE_SET", SYM(MAKE_SET_SYM)},
+ //psergey:
+ { "MAKE_NAME", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_make_name)},
+
{ "MAKEDATE", F_SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_makedate)},
{ "MAKETIME", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_maketime)},
{ "MASTER_POS_WAIT", SYM(MASTER_POS_WAIT)},
--- 1.259/sql/sql_class.h 2005-08-15 19:31:00 +04:00
+++ 1.260/sql/sql_class.h 2005-08-22 18:06:50 +04:00
@@ -1968,7 +1968,12 @@
ha_rows deleted, found;
uint num_of_tables;
int error;
- bool do_delete, transactional_tables, normal_tables, delete_while_scanning;
+ bool do_delete;
+ /* True if at least one table we delete from is transactional */
+ bool transactional_tables;
+ /* True if at least one table we delete from is not transactional */
+ bool normal_tables;
+ bool delete_while_scanning;
public:
multi_delete(TABLE_LIST *dt, uint num_of_tables);
@@ -1995,7 +2000,14 @@
uint table_count;
Copy_field *copy_field;
enum enum_duplicates handle_duplicates;
- bool do_update, trans_safe, transactional_tables, ignore;
+ bool do_update, trans_safe;
+ /*
+ True if the update operation has modified a transactional table,
+ or if the main_table is a transactional table (TODO: why do we need
+ this? Isn't multitable update completely symmetric?)
+ */
+ bool transactional_tables;
+ bool ignore;
public:
multi_update(TABLE_LIST *ut, TABLE_LIST *leaves_list,
--- 1.163/sql/sql_lex.cc 2005-08-18 22:46:16 +04:00
+++ 1.164/sql/sql_lex.cc 2005-08-22 18:06:50 +04:00
@@ -517,6 +517,10 @@
uchar *ident_map= cs->ident_map;
lex->yylval=yylval; // The global state
+
+ lex->tok_end_prev= lex->tok_end;
+ lex->tok_start_prev= lex->tok_start;
+
lex->tok_start=lex->tok_end=lex->ptr;
state=lex->next_state;
lex->next_state=MY_LEX_OPERATOR_OR_IDENT;
--- 1.193/sql/sql_lex.h 2005-08-15 19:31:01 +04:00
+++ 1.194/sql/sql_lex.h 2005-08-22 18:06:50 +04:00
@@ -703,6 +703,8 @@
SELECT_LEX *all_selects_list;
uchar *buf; /* The beginning of string, used by SPs */
uchar *ptr,*tok_start,*tok_end,*end_of_query;
+ //psergey:
+ uchar *tok_start_prev, *tok_end_prev;
char *length,*dec,*change,*name;
char *help_arg;
char *backup_dir; /* For RESTORE/BACKUP */
--- 1.470/sql/sql_parse.cc 2005-08-19 16:22:26 +04:00
+++ 1.471/sql/sql_parse.cc 2005-08-22 18:06:50 +04:00
@@ -2425,7 +2425,7 @@
{
if (!result && !(result= new select_send()))
goto error;
- query_cache_store_query(thd, all_tables);
+ query_cache_store_query(thd, all_tables); //psergey: it happens here!
res= handle_select(thd, lex, result, 0);
if (result != lex->result)
delete result;
@@ -4211,43 +4211,16 @@
thd->variables.select_limit= HA_POS_ERROR;
thd->row_count_func= 0;
- tmp_disable_binlog(thd); /* don't binlog the substatements */
- res= sp->execute_procedure(thd, &lex->value_list);
- reenable_binlog(thd);
-
- /*
- We write CALL to binlog; on the opposite we didn't write the
- substatements. That choice is necessary because the substatements
- may use local vars.
- Binlogging should happen when all tables are locked. They are locked
- just above, and unlocked by close_thread_tables(). All tables which
- are to be updated are locked like with a table-level write lock, and
- this also applies to InnoDB (I tested - note that it reduces
- InnoDB's concurrency as we don't use row-level locks). So binlogging
- below is safe.
- Note the limitation: if the SP returned an error, but still did some
- updates, we do NOT binlog it. This is because otherwise "permission
- denied", "table does not exist" etc would stop the slave quite
- often. There is no easy way to know if the SP updated something
- (even no_trans_update is not suitable, as it may be a transactional
- autocommit update which happened, and no_trans_update covers only
- INSERT/UPDATE/LOAD).
+
+ /*
+ We never write CALL statements int binlog:
+ - If the mode is non-prelocked, each statement will be logged
+ separately.
+ - If the mode is prelocked, the invoking statement will care
+ about writing into binlog.
+ So just execute the statement.
*/
- if (mysql_bin_log.is_open() &&
- (sp->m_chistics->daccess == SP_CONTAINS_SQL ||
- sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
- {
- if (res)
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_FAILED_ROUTINE_BREAK_BINLOG,
- ER(ER_FAILED_ROUTINE_BREAK_BINLOG));
- else
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
- }
+ res= sp->execute_procedure(thd, &lex->value_list);
/*
If warnings have been cleared, we have to clear total_warn_count
--- 1.416/sql/sql_yacc.yy 2005-08-20 14:38:07 +04:00
+++ 1.417/sql/sql_yacc.yy 2005-08-22 18:06:51 +04:00
@@ -1757,7 +1757,7 @@
sp_pcontext *ctx= lex->spcont;
uint offp;
sp_instr_cpush *i;
-
+
if (ctx->find_cursor(&$2, &offp, TRUE))
{
my_error(ER_SP_DUP_CURS, MYF(0), $2.str);
@@ -1766,6 +1766,17 @@
}
i= new sp_instr_cpush(sp->instructions(), ctx, $5);
sp->add_instr(i);
+
+ /* Extract the query statement from the tokenizer:
+ The end is either lex->tok_end or tok->ptr. */
+ if (lex->ptr - lex->tok_end > 1)
+ i->m_query.length= lex->ptr - sp->m_tmp_query;
+ else
+ i->m_query.length= lex->tok_end - sp->m_tmp_query;
+ i->m_query.str= strmake_root(YYTHD->mem_root,
+ (char *)sp->m_tmp_query,
+ i->m_query.length);
+
ctx->push_cursor(&$2);
$$.vars= $$.conds= $$.hndlrs= 0;
$$.curs= 1;
@@ -1774,7 +1785,10 @@
sp_cursor_stmt:
{
+ uchar *x=Lex->ptr; //this points to query start
+ LEX *lex=Lex;
Lex->sphead->reset_lex(YYTHD);
+ Lex->sphead->m_tmp_query= Lex->ptr;
/* We use statement here just be able to get a better
error message. Using 'select' works too, but will then
@@ -7133,10 +7147,20 @@
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 */
- $$ = (Item*) new Item_splocal($1, spv->offset);
+ {
+ /* We're compiling a stored procedure and found a variable */
+ Item_splocal *splocal;
+ splocal= new Item_splocal($1, spv->offset, lex->tok_start_prev -
+ lex->sphead->m_tmp_query); //lex->buf);
+ if (splocal)
+ {
+ splocal->len_in_query= lex->tok_end_prev - lex->tok_start_prev;
+ fprintf(stderr, "%*s: located splocal(%*s)\n",
+ lex->thd->query_length, lex->thd->query,
+ $1.length, $1.str);
+ }
+ $$ = (Item*) splocal;
lex->variables_used= 1;
lex->safe_to_cache_query=0;
}
--- 1.6/mysql-test/r/rpl_sp.result 2005-08-18 13:23:47 +04:00
+++ 1.7/mysql-test/r/rpl_sp.result 2005-08-22 18:06:49 +04:00
@@ -60,7 +60,8 @@
insert into t1 values (b);
insert into t1 values (unix_timestamp());
end
-master-bin.000001 # Query 1 # use `mysqltest1`; call foo()
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( MAKE_NAME('b',8))
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp())
select * from t1;
a
8
@@ -76,8 +77,10 @@
select * from mysqltest1.t1;
call foo2();
a
-show binlog events from 605;
+show binlog events from 518;
Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( MAKE_NAME('b',8))
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp())
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1
master-bin.000001 # Query 1 # use `mysqltest1`; create procedure foo2()
not deterministic
@@ -110,7 +113,6 @@
show warnings;
Level Code Message
Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1'
-Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
call foo3();
show warnings;
Level Code Message
@@ -119,12 +121,11 @@
show warnings;
Level Code Message
Error 1142 INSERT command denied to user 'zedjzlcsjhd'@'localhost' for table 't1'
-Warning 1417 A routine failed and has neither NO SQL nor READS SQL DATA in its declaration and binary logging is enabled; if non-transactional tables were updated, the binary log will miss their changes
alter procedure foo4 sql security invoker;
call foo4();
show warnings;
Level Code Message
-show binlog events from 841;
+show binlog events from 989;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1
master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int)
@@ -141,9 +142,12 @@
insert into t2 values(3);
insert into t1 values (5);
end
-master-bin.000001 # Query 1 # use `mysqltest1`; call foo3()
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3)
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15)
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3)
master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker
-master-bin.000001 # Query 1 # use `mysqltest1`; call foo4()
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3)
+master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5)
select * from t1;
a
15
@@ -160,6 +164,8 @@
select * from t2;
a
3
+3
+3
select * from mysql.proc where name="foo4" and db='mysqltest1';
db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment
mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES INVOKER begin
@@ -196,6 +202,7 @@
select * from t1;
a
21
+20
select * from t2;
a
23
--- 1.63/mysql-test/r/query_cache.result 2005-08-11 21:42:02 +04:00
+++ 1.64/mysql-test/r/query_cache.result 2005-08-22 18:06:49 +04:00
@@ -5,6 +5,7 @@
flush status;
drop table if exists t1,t2,t3,t4,t11,t21;
drop database if exists mysqltest;
+drop procedure if exists p1;
create table t1 (a int not null);
insert into t1 values (1),(2),(3);
select * from t1;
--- 1.168/sql/sp_head.cc 2005-08-19 17:03:12 +04:00
+++ 1.169/sql/sp_head.cc 2005-08-22 18:10:59 +04:00
@@ -596,8 +596,146 @@
DBUG_RETURN(field);
}
-int
-sp_head::execute(THD *thd)
+// { psergey
+
+template <class Elem> class Dynamic_array
+{
+ DYNAMIC_ARRAY array;
+public:
+ Dynamic_array(uint prealloc=16, uint increment=16)
+ {
+ my_init_dynamic_array(&array, sizeof(Elem), prealloc, increment);
+ }
+
+ Elem& at(int idx)
+ {
+ return *(((Elem*)array.buffer) + idx);
+ }
+
+ Elem *front()
+ {
+ return (Elem*)array.buffer;
+ }
+
+ Elem *back()
+ {
+ return ((Elem*)array.buffer) + array.elements;
+ }
+
+ bool append(Elem &el)
+ {
+ return (insert_dynamic(&array, (gptr)&el));
+ }
+
+ int elements()
+ {
+ return array.elements;
+ }
+
+ ~Dynamic_array()
+ {
+ delete_dynamic(&array);
+ }
+
+ typedef int (*CMP_FUNC)(const Elem *el1, const Elem *el2);
+
+ void sort(CMP_FUNC cmp_func)
+ {
+ qsort(array.buffer, array.elements, sizeof(Elem), (qsort_cmp)cmp_func);
+ }
+};
+
+int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
+{
+ return (int)((*a)->pos_in_query - (*b)->pos_in_query);
+}
+
+
+/*
+ Produce a query string for binlog - substitute local sp variable
+ references with MAKE_NAME('sp_var_name', value) calls.
+
+ SYNOPSIS
+ subst_spvars()
+ thd Current thread.
+ instr Instruction (we look for Item_splocal instances in its
+ free_list)
+ query_str Original query string
+
+*/
+
+void subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str)
+{
+ DBUG_ENTER("subst_spvars");
+ if (thd->prelocked_mode == NON_PRELOCKED /*and binlog is on */)
+ {
+ Dynamic_array<Item_splocal*> sp_vars_uses;
+ DBUG_PRINT("info", ("will add"));
+ for (Item *item= instr->free_list; item; item= item->next)
+ {
+ if (item->is_splocal() && ((Item_splocal*)item)->pos_in_query)
+ sp_vars_uses.append((Item_splocal*)item);
+ }
+ DBUG_PRINT("info", ("will sort"));
+ if (!sp_vars_uses.elements())
+ DBUG_VOID_RETURN;
+ // Sort item_splocal's by their occurences in the query
+ sp_vars_uses.sort(cmp_splocal_locations);
+
+ DBUG_PRINT("info", ("qbuf"));
+ // Replace the lex elements with smth.
+ char buffer[1024];
+ String qbuf(buffer, sizeof(buffer), &my_charset_bin);
+ qbuf.length(0);
+
+ DBUG_PRINT("info", ("loop1"));
+ char *cur= query_str->str;
+ int prev_pos= 0;
+ for (Item_splocal **splocal= sp_vars_uses.front();
+ splocal < sp_vars_uses.back();
+ splocal++)
+ {
+ //append to buffer the 'gap'
+ DBUG_PRINT("info", ("apppend"));
+ qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos);
+ prev_pos= (*splocal)->pos_in_query + (*splocal)->m_name.length;
+
+ //append 'value'
+ qbuf.append(" MAKE_NAME('");
+ qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
+ qbuf.append("',");
+ // ^^^ TODO: psergey: ^ ^ use append_identifier somehow
+ Item *val= (*splocal)->this_item();
+ DBUG_PRINT("info", ("print %p", val));
+ val->print(&qbuf);
+ qbuf.append(')');
+ }
+ qbuf.append(cur + prev_pos, query_str->length - prev_pos);
+
+ DBUG_PRINT("info", ("loop2"));
+ //fprintf(stderr, "SPQ: %s\n", qbuf.c_ptr_safe());
+ char *pbuf= thd->alloc(qbuf.length()+1);
+ DBUG_ASSERT(pbuf);
+ memcpy(pbuf, qbuf.ptr(), qbuf.length()+1);
+ thd->query= pbuf;
+ thd->query_length= qbuf.length();
+ }
+ DBUG_VOID_RETURN;
+}
+
+// } psergey
+
+
+/*
+ Execute the routine. The main instruction jump loop is there
+ Assume the parameters already set.
+
+ RETURN
+ -1 on error
+
+*/
+
+int sp_head::execute(THD *thd)
{
DBUG_ENTER("sp_head::execute");
char olddb[128];
@@ -805,9 +943,29 @@
}
+/*
+ Execute a function:
+ - evaluate parameters
+ - call sp_head::execute
+ - evaluate the return value
+
+ SYNOPSIS
+ sp_head::execute_function()
+ thd Thread handle
+ argp Passed arguments (these are items from containing statement?)
+ argcount Number of passed arguments. We need to check if this is
+ correct.
+ resp OUT Put result item here (q: is it a constant Item always?)
+
+ RETURN
+ 0 on OK
+ other on error
+*/
+
int
sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
{
+ Item **param_values;
DBUG_ENTER("sp_head::execute_function");
DBUG_PRINT("info", ("function %s", m_name.str));
uint csize = m_pcont->max_pvars();
@@ -830,13 +988,18 @@
DBUG_RETURN(-1);
}
+
+ if (!(param_values= (Item**)alloc_root(&call_mem_root, sizeof(Item*)*argcount)))
+ DBUG_RETURN(-1);
// QQ Should have some error checking here? (types, etc...)
nctx= new sp_rcontext(csize, hmax, cmax);
+ tmp_disable_binlog(thd);
for (i= 0 ; i < argcount ; i++)
{
sp_pvar_t *pvar = m_pcont->find_pvar(i);
Item *it= sp_eval_func_item(thd, argp++, pvar->type, NULL, FALSE);
+ param_values[i]= it;
if (it)
nctx->push_item(it);
@@ -862,6 +1025,57 @@
thd->spcont= nctx;
ret= execute(thd);
+ reenable_binlog(thd);
+ /*
+ psergey: TODO: binlog the call here! (tables for function are locked at
+ this point so there will be no problem.
+
+ need_binlog:
+ statement will not be binlogged &&
+ function has modified something.
+ */
+ bool need_binlog= TRUE;
+ if (need_binlog)
+ {
+ char buf[64];
+ String bufstr(buf, sizeof(buf), &my_charset_bin);
+ bufstr.length(0);
+ bufstr.append("DO ", 3);
+ append_identifier(thd, &bufstr, m_name.str, m_name.length);
+ bufstr.append('(');
+ for (uint i=0; i < argcount; i++)
+ {
+ if (i)
+ bufstr.append(',');
+ param_values[i]->print(&bufstr);
+ }
+
+ bufstr.append(')');
+ //fprintf(stderr, "FUNC: %s\n", bufstr.c_ptr_safe());
+ //
+
+ /*
+ Put query into binlog if it uses SP functions.
+ q: No need to analyze thd->prelocked_mode as binlog will be disabled
+ by caller statement in prelocked mode?
+ psergey-todo: what to do with trans_table for FUNCTIONs ?
+ */
+ if (mysql_bin_log.is_open())
+ {
+ /*
+ psergey: TODO: get actual value:
+ Does this mean "transactional table modified during query"?
+ */
+ bool transactional_table= FALSE;
+ Query_log_event qinfo(thd, bufstr.ptr(), bufstr.length(),
+ transactional_table, FALSE);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
+ {
+ fprintf(stderr, " error=1;\n"); //TODO:
+ DBUG_RETURN(-1);
+ }
+ }
+ }
if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
@@ -884,6 +1098,7 @@
DBUG_RETURN(ret);
}
+
static Item_func_get_user_var *
item_is_user_var(Item *it)
{
@@ -897,8 +1112,24 @@
return NULL;
}
-int
-sp_head::execute_procedure(THD *thd, List<Item> *args)
+
+/*
+ Execute a procedure.
+ - Set all parameters
+ - call sp_head::execute
+ - copy back INOUT and OUT parameters if they point to SP or user variables
+
+ SYNOPSIS
+ sp_head::execute_procedure()
+ thd
+ args
+
+ RETURN
+ 0 Ok
+ -1 Error
+*/
+
+int sp_head::execute_procedure(THD *thd, List<Item> *args)
{
DBUG_ENTER("sp_head::execute_procedure");
DBUG_PRINT("info", ("procedure %s", m_name.str));
@@ -1441,8 +1672,12 @@
DBUG_RETURN(res);
}
-void
-sp_head::optimize()
+
+/*
+ TODO: what does this do??
+*/
+
+void sp_head::optimize()
{
List<sp_instr> bp;
sp_instr *i;
@@ -1630,7 +1865,6 @@
return 0;
}
-
/*
sp_instr_stmt class functions
*/
@@ -1640,9 +1874,9 @@
{
char *query;
uint32 query_length;
+ int res;
DBUG_ENTER("sp_instr_stmt::execute");
DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command()));
- int res;
query= thd->query;
query_length= thd->query_length;
@@ -1651,6 +1885,7 @@
if (query_cache_send_result_to_client(thd,
thd->query, thd->query_length) <= 0)
{
+ subst_spvars(thd, this, &m_query);
res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this);
query_cache_end_of_result(thd);
}
@@ -2189,6 +2424,7 @@
the right free_list, and we can cleanup after each open.
*/
thd->current_arena= c->get_instr();
+ subst_spvars(thd, this, &c->get_instr()->m_query);
res= lex_keeper->reset_lex_and_exec_core(thd, nextp, FALSE, this);
/* Cleanup the query's items */
if (thd->current_arena->free_list)
--- 1.65/sql/sp_head.h 2005-08-19 17:03:12 +04:00
+++ 1.66/sql/sp_head.h 2005-08-22 18:06:50 +04:00
@@ -118,7 +118,7 @@
my_bool m_simple_case; // TRUE if parsing simple case, FALSE otherwise
my_bool m_multi_results; // TRUE if a procedure with SELECT(s)
my_bool m_in_handler; // TRUE if parser in a handler body
- uchar *m_tmp_query; // Temporary pointer to sub query string
+ uchar *m_tmp_query; // Temporary pointer to sub query string (why isn't this in pcontext?)
uint m_old_cmq; // Old CLIENT_MULTI_QUERIES value
st_sp_chistics *m_chistics;
ulong m_sql_mode; // For SHOW CREATE and execution
@@ -326,10 +326,22 @@
virtual ~sp_instr()
{ free_items(); }
- // 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.
+
+ /*
+ Execute this instruction
+
+ SYNOPSIS
+ execute()
+ thd Thread handle
+ nextp OUT index of the next instruction to execute. (For most
+ instructions this will be the instruction following this
+ one).
+
+ RETURN
+ 0 on success,
+ other if some error occured
+ */
+
virtual int execute(THD *thd, uint *nextp) = 0;
/*
@@ -339,10 +351,17 @@
Should be implemented for instructions using expressions or whole
statements (thus having to have own LEX). Used in concert with
- sp_lex_keeper class and its descendants.
+ sp_lex_keeper class and its descendants (there are no descendants
+ currently).
*/
virtual int exec_core(THD *thd, uint *nextp);
+ /*
+ psergey: this binlogs puts the statement into binlog, i.e. it converts
+ the statement to some other statement we can write to binary log.
+ */
+ virtual void binlog_stmt() {};
+
virtual void print(String *str) = 0;
virtual void backpatch(uint dest, sp_pcontext *dst_ctx)
@@ -808,6 +827,7 @@
}; // class sp_instr_hreturn : public sp_instr
+/* This is DECLARE CURSOR */
class sp_instr_cpush : public sp_instr
{
sp_instr_cpush(const sp_instr_cpush &); /* Prevent use of these */
@@ -826,10 +846,10 @@
virtual void print(String *str);
+ LEX_STRING m_query;
private:
sp_lex_keeper m_lex_keeper;
-
}; // class sp_instr_cpush : public sp_instr
--- 1.22/sql/sp_rcontext.h 2005-08-18 13:23:47 +04:00
+++ 1.23/sql/sp_rcontext.h 2005-08-22 18:06:50 +04:00
@@ -41,6 +41,16 @@
uint foffset; // Frame offset for the handlers declare level
} sp_handler_t;
+
+/*
+ This is a run context? of one SP ?
+ THis is
+ - a stack of cursors?
+ - a stack of handlers?
+ - a stack of Items ?
+ - a stack of instruction locations in SP?
+*/
+
class sp_rcontext : public Sql_alloc
{
sp_rcontext(const sp_rcontext &); /* Prevent use of these */
| Thread |
|---|
| • bk commit into 5.0 tree (sergefp:1.1900) | Sergey Petrunia | 22 Aug |