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.1905 05/08/23 05:01:38 sergefp@stripped +4 -0
Post-merge fixes, will not push
sql/sp_head.cc
1.170 05/08/23 05:01:34 sergefp@stripped +0 -4
Post-merge fixes, will not push
sql/sql_parse.cc
1.473 05/08/23 04:59:40 sergefp@stripped +0 -0
Auto merged
sql/sql_lex.cc
1.165 05/08/23 04:59:39 sergefp@stripped +0 -0
Auto merged
sql/item_create.cc
1.57 05/08/23 04:59:39 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.56/sql/item_create.cc 2005-08-20 02:51:35 +04:00
+++ 1.57/sql/item_create.cc 2005-08-23 04:59:39 +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.164/sql/sql_lex.cc 2005-08-22 02:13:18 +04:00
+++ 1.165/sql/sql_lex.cc 2005-08-23 04:59:39 +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.472/sql/sql_parse.cc 2005-08-22 02:13:18 +04:00
+++ 1.473/sql/sql_parse.cc 2005-08-23 04:59:40 +04:00
@@ -2430,7 +2430,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;
@@ -4216,28 +4216,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.
*/
+ res= sp->execute_procedure(thd, &lex->value_list);
if (mysql_bin_log.is_open() &&
(sp->m_chistics->daccess == SP_CONTAINS_SQL ||
sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA))
@@ -4247,11 +4235,7 @@
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);
- }
}
/*
@@ -6530,6 +6514,11 @@
0 ok
!=0 error. thd->killed or thd->net.report_error is set
*/
+int psergey_oops(int i)
+{
+ fprintf(stderr, "oops %d\n", i);
+ return 0;
+}
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
bool *write_to_binlog)
@@ -6540,6 +6529,7 @@
if (thd->in_sub_stmt)
{
+ psergey_oops(0);
my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
return 1;
}
--- 1.169/sql/sp_head.cc 2005-08-22 02:13:18 +04:00
+++ 1.170/sql/sp_head.cc 2005-08-23 05:01:34 +04:00
@@ -588,8 +588,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];
@@ -797,9 +935,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();
@@ -823,6 +981,9 @@
goto end;
}
+
+ if (!(param_values= (Item**)thd->alloc(sizeof(Item*)*argcount)))
+ DBUG_RETURN(-1);
// QQ Should have some error checking here? (types, etc...)
if (!(nctx= new sp_rcontext(csize, hmax, cmax)))
@@ -831,6 +992,7 @@
{
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)
goto end; // EOM error
@@ -856,6 +1018,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)
{
@@ -893,6 +1106,22 @@
}
+/*
+ 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)
{
int ret= 0;
@@ -1447,8 +1676,12 @@
DBUG_RETURN(res);
}
-void
-sp_head::optimize()
+
+/*
+ TODO: what does this do??
+*/
+
+void sp_head::optimize()
{
List<sp_instr> bp;
sp_instr *i;
@@ -1636,7 +1869,6 @@
return 0;
}
-
/*
sp_instr_stmt class functions
*/
@@ -1646,9 +1878,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;
@@ -1657,6 +1889,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);
}
@@ -2195,6 +2428,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)
| Thread |
|---|
| • bk commit into 5.0 tree (sergefp:1.1905) | Sergey Petrunia | 23 Aug |