List:Internals« Previous MessageNext Message »
From:Sergey Petrunia Date:August 22 2005 2:11pm
Subject:bk commit into 5.0 tree (sergefp:1.1900)
View as plain text  
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 Petrunia22 Aug