[Commits] f5bc86d: c

sanja at mariadb.com sanja at mariadb.com
Tue Mar 17 15:38:40 EET 2015


revision-id: f5bc86d1caa048d7753060ffc84dff705875af46
parent(s): a21ef88d2a358904f0cdf9cadc701cb263b5e317
committer: Oleksandr Byelkin
branch nick: server
timestamp: 2015-03-17 14:38:38 +0100
message:

c

---
 mysql-test/r/set_statement.result |  57 ++++++---
 mysql-test/t/set_statement.test   |  37 +++---
 sql/sql_class.h                   |   4 +
 sql/sql_lex.cc                    |   6 +
 sql/sql_lex.h                     |   1 +
 sql/sql_parse.cc                  | 257 +++++++++++++++++++++-----------------
 sql/sql_parse.h                   |   1 +
 sql/sql_yacc.yy                   |  10 +-
 sql/sys_vars.cc                   |   8 +-
 9 files changed, 225 insertions(+), 156 deletions(-)

diff --git a/mysql-test/r/set_statement.result b/mysql-test/r/set_statement.result
index 08072fc..d05c1e2 100644
--- a/mysql-test/r/set_statement.result
+++ b/mysql-test/r/set_statement.result
@@ -705,14 +705,27 @@ drop procedure p6;
 SELECT @@sql_mode;
 @@sql_mode
 
-# SET and the statement parsed as one unit before the SET takes effect
 SET STATEMENT sql_mode='ansi' FOR
 CREATE PROCEDURE p6() BEGIN
 SELECT @@sql_mode;
 SELECT "t1".* FROM t1;
 END|
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.* FROM t1;
-END' at line 4
+call p6;
+@@sql_mode
+REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
+v1	v2
+1	2
+3	4
+ALTER TABLE t1 ADD COLUMN v3 int;
+# no reparsing for now
+call p6;
+@@sql_mode
+REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
+v1	v2
+1	2
+3	4
+ALTER TABLE t1 drop COLUMN v3;
+drop procedure p6;
 SELECT @@sql_mode;
 @@sql_mode
 
@@ -739,8 +752,11 @@ BEGIN NOT ATOMIC
 SELECT @@sql_mode;
 SELECT "t1".* FROM t1;
 END|
-ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '.* FROM t1;
-END' at line 4
+@@sql_mode
+REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ANSI
+v1	v2
+1	2
+3	4
 SET STATEMENT sql_mode='ansi' FOR
 BEGIN NOT ATOMIC
 SELECT @@sql_mode;
@@ -895,7 +911,7 @@ SET STATEMENT myisam_sort_buffer_size = 700000, sort_buffer_size = 3000000
 FOR SET STATEMENT myisam_sort_buffer_size=200000
 FOR SELECT @@myisam_sort_buffer_size, @@sort_buffer_size;
 @@myisam_sort_buffer_size	@@sort_buffer_size
-200000	100000
+200000	3000000
 SELECT @@myisam_sort_buffer_size, @@sort_buffer_size;
 @@myisam_sort_buffer_size	@@sort_buffer_size
 500000	100000
@@ -945,10 +961,10 @@ deallocate prepare stmt1;
 set statement binlog_format=row for PREPARE stmt1 FROM 'SELECT @@binlog_format';
 execute stmt1;
 @@binlog_format
-MIXED
+ROW
 execute stmt1;
 @@binlog_format
-MIXED
+ROW
 deallocate prepare stmt1;
 PREPARE stmt1 FROM 'set statement binlog_format=row for SELECT @@binlog_format';
 execute stmt1;
@@ -1126,14 +1142,6 @@ set statement skip_replication=default for select 1;
 ERROR 42000: The system variable skip_replication cannot be set in SET STATEMENT.
 set statement sql_log_off=default for select 1;
 ERROR 42000: The system variable sql_log_off cannot be set in SET STATEMENT.
-set statement character_set_client=default for select 1;
-ERROR 42000: The system variable character_set_client cannot be set in SET STATEMENT.
-set statement character_set_connection=default for select 1;
-ERROR 42000: The system variable character_set_connection cannot be set in SET STATEMENT.
-set statement character_set_filesystem=default for select 1;
-ERROR 42000: The system variable character_set_filesystem cannot be set in SET STATEMENT.
-set statement collation_connection=default for select 1;
-ERROR 42000: The system variable collation_connection cannot be set in SET STATEMENT.
 set statement query_cache_type=default for select 1;
 ERROR 42000: The system variable query_cache_type cannot be set in SET STATEMENT.
 set statement wait_timeout=default for select 1;
@@ -1220,3 +1228,20 @@ set @rnd=1;
 select @rnd;
 @rnd
 0
+#
+# MDEV-7012 SET STATEMENT character_set_client, character_set_connection,
+# character_set_filesystem, collation_connection have no effect
+#
+set @character_set_client_save= @@character_set_client;
+set names utf8;
+select 'фи';
+фи
+фи
+set statement character_set_client = latin5 for select 'фи';
+фи
+фи
+set character_set_client = latin5;
+select 'фи';
+фи
+фи
+set character_set_client=@character_set_client_save;
diff --git a/mysql-test/t/set_statement.test b/mysql-test/t/set_statement.test
index 13c6d08..dae80af 100644
--- a/mysql-test/t/set_statement.test
+++ b/mysql-test/t/set_statement.test
@@ -660,20 +660,18 @@ drop procedure p6;
 
 SELECT @@sql_mode;
 DELIMITER |;
---echo # SET and the statement parsed as one unit before the SET takes effect
---error ER_PARSE_ERROR
 SET STATEMENT sql_mode='ansi' FOR
               CREATE PROCEDURE p6() BEGIN
               SELECT @@sql_mode;
               SELECT "t1".* FROM t1;
               END|
 DELIMITER ;|
-#call p1;
-#ALTER TABLE t1 ADD COLUMN v3 int;
-#--echo # no reparsing for now
-#call p1;
-#ALTER TABLE t1 drop COLUMN v3;
-#drop procedure p1;
+call p6;
+ALTER TABLE t1 ADD COLUMN v3 int;
+--echo # no reparsing for now
+call p6;
+ALTER TABLE t1 drop COLUMN v3;
+drop procedure p6;
 
 
 # the above test about compound statement
@@ -692,7 +690,7 @@ SET sql_mode=default;
 SELECT @@sql_mode;
 DELIMITER |;
 --echo # SET and the statement parsed as one unit before the SET takes effect
---error ER_PARSE_ERROR
+#--error ER_PARSE_ERROR
 SET STATEMENT sql_mode='ansi' FOR
 BEGIN NOT ATOMIC
               SELECT @@sql_mode;
@@ -1054,14 +1052,6 @@ set statement skip_replication=default for select 1;
 --error ER_SET_STATEMENT_NOT_SUPPORTED
 set statement sql_log_off=default for select 1;
 --error ER_SET_STATEMENT_NOT_SUPPORTED
-set statement character_set_client=default for select 1;
---error ER_SET_STATEMENT_NOT_SUPPORTED
-set statement character_set_connection=default for select 1;
---error ER_SET_STATEMENT_NOT_SUPPORTED
-set statement character_set_filesystem=default for select 1;
---error ER_SET_STATEMENT_NOT_SUPPORTED
-set statement collation_connection=default for select 1;
---error ER_SET_STATEMENT_NOT_SUPPORTED
 set statement query_cache_type=default for select 1;
 --error ER_SET_STATEMENT_NOT_SUPPORTED
 set statement wait_timeout=default for select 1;
@@ -1131,3 +1121,16 @@ while ($1)
 --enable_query_log
 --echo # @rnd should be 0
 select @rnd;
+
+
+--echo #
+--echo # MDEV-7012 SET STATEMENT character_set_client, character_set_connection,
+--echo # character_set_filesystem, collation_connection have no effect
+--echo #
+set @character_set_client_save= @@character_set_client;
+set names utf8;
+select 'фи';
+set statement character_set_client = latin5 for select 'фи';
+set character_set_client = latin5;
+select 'фи';
+set character_set_client=@character_set_client_save;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index a39ba78..88335d2 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3873,6 +3873,10 @@ class THD :public Statement,
   {
     main_lex.restore_set_statement_var();
   }
+  bool is_main_statement()
+  {
+    return (lex == &main_lex);
+  }
 };
 
 
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index f603534..c3e74f6 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -4225,6 +4225,12 @@ int LEX::print_explain(select_result_sink *output, uint8 explain_flags,
 }
 
 
+void LEX::switch_arena_for_set_stmt(Query_arena *backup)
+{
+  thd->set_n_backup_active_arena(arena_for_set_stmt, backup);
+}
+
+
 /**
   Allocates and set arena for SET STATEMENT old values.
 
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6eb5bae..46e471f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -2439,6 +2439,7 @@ struct LEX: public Query_tables_list
 public:
   inline bool is_arena_for_set_stmt() {return arena_for_set_stmt != 0;}
   bool set_arena_for_set_stmt(Query_arena *backup);
+  void switch_arena_for_set_stmt(Query_arena *backup);
   void reset_arena_for_set_stmt(Query_arena *backup);
   void free_arena_for_set_stmt();
 
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 30c4416..1e6fde1 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2383,6 +2383,143 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
   return 0;
 }
 
+bool maria_set_statement_variables(THD *thd, bool add_more)
+{
+  LEX *lex= thd->lex;
+  DBUG_ENTER("maria_set_statement_variables");
+
+  if (!lex->stmt_var_list.is_empty() && !thd->slave_thread
+      && (lex->old_var_list.is_empty() || add_more))
+  {
+    Query_arena backup;
+    DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements));
+
+    List_iterator_fast<set_var_base> it(lex->stmt_var_list);
+    set_var_base *var;
+
+    if (lex->is_arena_for_set_stmt())
+    {
+      DBUG_ASSERT(add_more);
+      DBUG_ASSERT(lex->old_var_list.elements);
+      List_iterator_fast<set_var_base> oit(lex->old_var_list);
+      while(oit++)
+        it++;
+      lex->switch_arena_for_set_stmt(&backup);
+    }
+    else
+    {
+      if (lex->set_arena_for_set_stmt(&backup))
+        DBUG_RETURN(TRUE);
+    }
+
+    while ((var= it++))
+    {
+      DBUG_ASSERT(var->is_system());
+      set_var *o= NULL, *v= (set_var*)var;
+      if (!v->var->is_set_stmt_ok())
+      {
+        my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str);
+        lex->reset_arena_for_set_stmt(&backup);
+        lex->old_var_list.empty();
+        lex->free_arena_for_set_stmt();
+        DBUG_RETURN(TRUE);
+      }
+      if (v->var->is_default())
+          o= new set_var(v->type, v->var, &v->base, NULL);
+      else
+      {
+        switch (v->var->option.var_type & GET_TYPE_MASK)
+        {
+        case GET_BOOL:
+        case GET_INT:
+        case GET_LONG:
+        case GET_LL:
+          {
+            bool null_value;
+            longlong val= v->var->val_int(&null_value, thd, v->type, &v->base);
+            o= new set_var(v->type, v->var, &v->base,
+                           (null_value ?
+                            (Item *)new Item_null() :
+                            (Item *)new Item_int(val)));
+          }
+          break;
+        case GET_UINT:
+        case GET_ULONG:
+        case GET_ULL:
+          {
+            bool null_value;
+            ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base);
+            o= new set_var(v->type, v->var, &v->base,
+                           (null_value ?
+                            (Item *)new Item_null() :
+                            (Item *)new Item_uint(val)));
+          }
+          break;
+        case GET_DOUBLE:
+          {
+            bool null_value;
+            double val= v->var->val_real(&null_value, thd, v->type, &v->base);
+            o= new set_var(v->type, v->var, &v->base,
+                           (null_value ?
+                            (Item *)new Item_null() :
+                            (Item *)new Item_float(val, 1)));
+          }
+          break;
+        default:
+        case GET_NO_ARG:
+        case GET_DISABLED:
+          DBUG_ASSERT(0);
+        case 0:
+        case GET_FLAGSET:
+        case GET_ENUM:
+        case GET_SET:
+        case GET_STR:
+        case GET_STR_ALLOC:
+          {
+            char buff[STRING_BUFFER_USUAL_SIZE];
+            String tmp(buff, sizeof(buff), v->var->charset(thd)),*val;
+            val= v->var->val_str(&tmp, thd, v->type, &v->base);
+            if (val)
+            {
+              Item_string *str= new Item_string(v->var->charset(thd),
+                                                val->ptr(), val->length());
+              o= new set_var(v->type, v->var, &v->base, str);
+            }
+            else
+              o= new set_var(v->type, v->var, &v->base, new Item_null());
+          }
+          break;
+        }
+      }
+      DBUG_ASSERT(o);
+      lex->old_var_list.push_back(o);
+    }
+    lex->reset_arena_for_set_stmt(&backup);
+    if (lex->old_var_list.is_empty())
+      lex->free_arena_for_set_stmt();
+    if (thd->is_error() ||
+        sql_set_variables(thd, &lex->stmt_var_list, false))
+    {
+      if (!thd->is_error())
+        my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
+      lex->restore_set_statement_var();
+      DBUG_RETURN(TRUE);
+    }
+    /*
+      The value of last_insert_id is remembered in THD to be written to binlog
+      when it's used *the first time* in the statement. But SET STATEMENT
+      must read the old value of last_insert_id to be able to restore it at
+      the end. This should not count at "reading of last_insert_id" and
+      should not remember last_insert_id for binlog. That is, it should clear
+      stmt_depends_on_first_successful_insert_id_in_prev_stmt flag.
+    */
+    if (!thd->in_sub_stmt)
+    {
+      thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
+    }
+  }
+  DBUG_RETURN(FALSE);
+}
 
 /**
   Execute command saved in thd and lex->sql_command.
@@ -2638,124 +2775,8 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
   thd->get_binlog_format(&orig_binlog_format,
                          &orig_current_stmt_binlog_format);
 
-  if (!lex->stmt_var_list.is_empty() && !thd->slave_thread)
-  {
-    Query_arena backup;
-    DBUG_PRINT("info", ("SET STATEMENT %d vars", lex->stmt_var_list.elements));
-
-    lex->old_var_list.empty();
-    List_iterator_fast<set_var_base> it(lex->stmt_var_list);
-    set_var_base *var;
-
-    if (lex->set_arena_for_set_stmt(&backup))
-      goto error;
-
-    while ((var= it++))
-    {
-      DBUG_ASSERT(var->is_system());
-      set_var *o= NULL, *v= (set_var*)var;
-      if (!v->var->is_set_stmt_ok())
-      {
-        my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str);
-        lex->reset_arena_for_set_stmt(&backup);
-        lex->old_var_list.empty();
-        lex->free_arena_for_set_stmt();
-        goto error;
-      }
-      if (v->var->is_default())
-          o= new set_var(v->type, v->var, &v->base, NULL);
-      else
-      {
-        switch (v->var->option.var_type & GET_TYPE_MASK)
-        {
-        case GET_BOOL:
-        case GET_INT:
-        case GET_LONG:
-        case GET_LL:
-          {
-            bool null_value;
-            longlong val= v->var->val_int(&null_value, thd, v->type, &v->base);
-            o= new set_var(v->type, v->var, &v->base,
-                           (null_value ?
-                            (Item *)new Item_null() :
-                            (Item *)new Item_int(val)));
-          }
-          break;
-        case GET_UINT:
-        case GET_ULONG:
-        case GET_ULL:
-          {
-            bool null_value;
-            ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base);
-            o= new set_var(v->type, v->var, &v->base,
-                           (null_value ?
-                            (Item *)new Item_null() :
-                            (Item *)new Item_uint(val)));
-          }
-          break;
-        case GET_DOUBLE:
-          {
-            bool null_value;
-            double val= v->var->val_real(&null_value, thd, v->type, &v->base);
-            o= new set_var(v->type, v->var, &v->base,
-                           (null_value ?
-                            (Item *)new Item_null() :
-                            (Item *)new Item_float(val, 1)));
-          }
-          break;
-        default:
-        case GET_NO_ARG:
-        case GET_DISABLED:
-          DBUG_ASSERT(0);
-        case 0:
-        case GET_FLAGSET:
-        case GET_ENUM:
-        case GET_SET:
-        case GET_STR:
-        case GET_STR_ALLOC:
-          {
-            char buff[STRING_BUFFER_USUAL_SIZE];
-            String tmp(buff, sizeof(buff), v->var->charset(thd)),*val;
-            val= v->var->val_str(&tmp, thd, v->type, &v->base);
-            if (val)
-            {
-              Item_string *str= new Item_string(v->var->charset(thd),
-                                                val->ptr(), val->length());
-              o= new set_var(v->type, v->var, &v->base, str);
-            }
-            else
-              o= new set_var(v->type, v->var, &v->base, new Item_null());
-          }
-          break;
-        }
-      }
-      DBUG_ASSERT(o);
-      lex->old_var_list.push_back(o);
-    }
-    lex->reset_arena_for_set_stmt(&backup);
-    if (lex->old_var_list.is_empty())
-      lex->free_arena_for_set_stmt();
-    if (thd->is_error() ||
-        (res= sql_set_variables(thd, &lex->stmt_var_list, false)))
-    {
-      if (!thd->is_error())
-        my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
-      lex->restore_set_statement_var();
-      goto error;
-    }
-    /*
-      The value of last_insert_id is remembered in THD to be written to binlog
-      when it's used *the first time* in the statement. But SET STATEMENT
-      must read the old value of last_insert_id to be able to restore it at
-      the end. This should not count at "reading of last_insert_id" and
-      should not remember last_insert_id for binlog. That is, it should clear
-      stmt_depends_on_first_successful_insert_id_in_prev_stmt flag.
-    */
-    if (!thd->in_sub_stmt)
-    {
-      thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
-    }
-  }
+  if (maria_set_statement_variables(thd, FALSE))
+    goto error;
 
   if (thd->lex->mi.connection_name.str == NULL)
       thd->lex->mi.connection_name= thd->variables.default_master_connection;
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 5e1d867..a4e2706 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -178,5 +178,6 @@ inline bool check_some_routine_access(THD *thd, const char *db,
                    bool no_errors)
 { return false; }
 #endif /*NO_EMBEDDED_ACCESS_CHECKS*/
+bool maria_set_statement_variables(THD *thd, bool add_more);
 
 #endif /* SQL_PARSE_INCLUDED */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index fe44fd2..2a48285 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -14537,7 +14537,15 @@ set:
             lex->stmt_var_list= lex->var_list;
             lex->var_list.empty();
           }
-          FOR_SYM verb_clause
+          FOR_SYM
+          {
+            if (thd->is_main_statement() &&
+                maria_set_statement_variables(thd, TRUE))
+            {
+              MYSQL_YYABORT;
+            }
+          }
+          verb_clause
 	  {}
         ;
 
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 734b6ed..612e468 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -635,7 +635,7 @@ static bool fix_thd_charset(sys_var *self, THD *thd, enum_var_type type)
 static Sys_var_struct Sys_character_set_client(
        "character_set_client", "The character set for statements "
        "that arrive from the client",
-       NO_SET_STMT SESSION_VAR(character_set_client), NO_CMD_LINE,
+       SESSION_VAR(character_set_client), NO_CMD_LINE,
        offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
        NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_cs_client),
        ON_UPDATE(fix_thd_charset));
@@ -644,7 +644,7 @@ static Sys_var_struct Sys_character_set_connection(
        "character_set_connection", "The character set used for "
        "literals that do not have a character set introducer and for "
        "number-to-string conversion",
-       NO_SET_STMT SESSION_VAR(collation_connection), NO_CMD_LINE,
+       SESSION_VAR(collation_connection), NO_CMD_LINE,
        offsetof(CHARSET_INFO, csname), DEFAULT(&default_charset_info),
        NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_charset_not_null),
        ON_UPDATE(fix_thd_charset));
@@ -658,7 +658,7 @@ static Sys_var_struct Sys_character_set_results(
 
 static Sys_var_struct Sys_character_set_filesystem(
        "character_set_filesystem", "The filesystem character set",
-       NO_SET_STMT SESSION_VAR(character_set_filesystem), NO_CMD_LINE,
+       SESSION_VAR(character_set_filesystem), NO_CMD_LINE,
        offsetof(CHARSET_INFO, csname), DEFAULT(&character_set_filesystem),
        NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_charset_not_null),
        ON_UPDATE(fix_thd_charset));
@@ -704,7 +704,7 @@ static bool check_collation_not_null(sys_var *self, THD *thd, set_var *var)
 static Sys_var_struct Sys_collation_connection(
        "collation_connection", "The collation of the connection "
        "character set",
-       NO_SET_STMT SESSION_VAR(collation_connection), NO_CMD_LINE,
+       SESSION_VAR(collation_connection), NO_CMD_LINE,
        offsetof(CHARSET_INFO, name), DEFAULT(&default_charset_info),
        NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(check_collation_not_null),
        ON_UPDATE(fix_thd_charset));


More information about the commits mailing list