summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc12
-rw-r--r--sql/item.h2
-rw-r--r--sql/item_func.cc10
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/set_var.cc6
-rw-r--r--sql/set_var.h1
-rw-r--r--sql/sql_acl.cc39
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_lex.cc32
-rw-r--r--sql/sql_parse.cc22
-rw-r--r--sql/sql_update.cc5
-rw-r--r--sql/sql_yacc.yy2
13 files changed, 120 insertions, 26 deletions
diff --git a/sql/field.cc b/sql/field.cc
index fa0e202d513..34c5d572526 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1776,13 +1776,23 @@ void Field_medium::sql_type(String &res) const
** long int
****************************************************************************/
-
+/*
+ A helper function to check whether the next character
+ in the string "s" is MINUS SIGN.
+*/
+#ifdef HAVE_CHARSET_ucs2
static bool test_if_minus(CHARSET_INFO *cs,
const char *s, const char *e)
{
my_wc_t wc;
return cs->cset->mb_wc(cs, &wc, (uchar*) s, (uchar*) e) > 0 && wc == '-';
}
+#else
+/*
+ If not UCS2 support is compiled then it is easier
+*/
+#define test_if_minus(cs, s, e) (*s == '-')
+#endif
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
diff --git a/sql/item.h b/sql/item.h
index db5010799fa..dd06d4ce61a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -742,7 +742,7 @@ public:
Item *new_item()
{
return new Item_string(name, str_value.ptr(),
- str_value.length(), &my_charset_bin);
+ str_value.length(), collation.collation);
}
Item *safe_charset_converter(CHARSET_INFO *tocs);
String *const_string() { return &str_value; }
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 34c8732a9f2..895740d2e5e 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2361,7 +2361,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->value=0;
entry->length=0;
entry->update_query_id=0;
- entry->collation.set(NULL, DERIVATION_NONE);
+ entry->collation.set(NULL, DERIVATION_IMPLICIT);
/*
If we are here, we were called from a SET or a query which sets a
variable. Imagine it is this:
@@ -2419,8 +2419,8 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
and the variable has previously been initialized.
*/
if (!entry->collation.collation || !args[0]->null_value)
- entry->collation.set(args[0]->collation);
- collation.set(entry->collation);
+ entry->collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
+ collation.set(entry->collation.collation, DERIVATION_IMPLICIT);
cached_result_type= args[0]->result_type();
return 0;
}
@@ -2432,7 +2432,7 @@ Item_func_set_user_var::fix_length_and_dec()
maybe_null=args[0]->maybe_null;
max_length=args[0]->max_length;
decimals=args[0]->decimals;
- collation.set(args[0]->collation);
+ collation.set(args[0]->collation.collation, DERIVATION_IMPLICIT);
}
@@ -2659,7 +2659,7 @@ Item_func_set_user_var::update()
res= update_hash((void*) save_result.vstr->ptr(),
save_result.vstr->length(), STRING_RESULT,
save_result.vstr->charset(),
- args[0]->collation.derivation);
+ DERIVATION_IMPLICIT);
break;
}
case ROW_RESULT:
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 3f7262283b4..6c77a8934dd 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -754,7 +754,7 @@ bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1);
bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db,
const char *table_name);
-void remove_db_from_cache(const my_string db);
+void remove_db_from_cache(const char *db);
void flush_tables();
bool remove_table_from_cache(THD *thd, const char *db, const char *table,
bool return_if_owned_by_thd=0);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index fd3c26c6175..f58b5c15a99 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -950,6 +950,7 @@ void clean_up(bool print_message)
item_user_lock_free();
lex_free(); /* Free some memory */
set_var_free();
+ free_charsets();
#ifdef HAVE_DLOPEN
if (!opt_noacl)
udf_free();
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 5fdb3de3178..29ebb2c8817 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1229,6 +1229,12 @@ static void fix_server_id(THD *thd, enum_var_type type)
server_id_supplied = 1;
}
+bool sys_var_long_ptr::check(THD *thd, set_var *var)
+{
+ longlong v= var->value->val_int();
+ var->save_result.ulonglong_value= v < 0 ? 0 : v;
+ return 0;
+}
bool sys_var_long_ptr::update(THD *thd, set_var *var)
{
diff --git a/sql/set_var.h b/sql/set_var.h
index df2fd41c7bd..080a2a95ae0 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -93,6 +93,7 @@ public:
sys_var_long_ptr(const char *name_arg, ulong *value_ptr,
sys_after_update_func func)
:sys_var(name_arg,func), value(value_ptr) {}
+ bool check(THD *thd, set_var *var);
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
SHOW_TYPE type() { return SHOW_LONG; }
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7c17a4ef275..f6b304406d5 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -139,6 +139,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
MYSQL_LOCK *lock;
my_bool return_val=1;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
+ char tmp_name[NAME_LEN+1];
DBUG_ENTER("acl_init");
@@ -197,6 +198,24 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
ACL_HOST host;
update_hostname(&host.host,get_field(&mem, table->field[0]));
host.db= get_field(&mem, table->field[1]);
+ if (lower_case_table_names)
+ {
+ /*
+ We make a temporary copy of the database, force it to lower case,
+ and then copy it back over the original name. We can't just update
+ the host.db pointer, because tmp_name is allocated on the stack.
+ */
+ (void)strmov(tmp_name, host.db);
+ my_casedn_str(files_charset_info, tmp_name);
+ if (strcmp(host.db, tmp_name) != 0)
+ {
+ sql_print_warning("'host' entry '%s|%s' had database in mixed "
+ "case that has been forced to lowercase because "
+ "lower_case_table_names is set.",
+ host.host.hostname, host.db);
+ (void)strmov(host.db, tmp_name);
+ }
+ }
host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access);
host.sort= get_sort(2,host.host.hostname,host.db);
@@ -380,6 +399,24 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
}
db.access=get_access(table,3);
db.access=fix_rights_for_db(db.access);
+ if (lower_case_table_names)
+ {
+ /*
+ We make a temporary copy of the database, force it to lower case,
+ and then copy it back over the original name. We can't just update
+ the db.db pointer, because tmp_name is allocated on the stack.
+ */
+ (void)strmov(tmp_name, db.db);
+ my_casedn_str(files_charset_info, tmp_name);
+ if (strcmp(db.db, tmp_name) != 0)
+ {
+ sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
+ "case that has been forced to lowercase because "
+ "lower_case_table_names is set.",
+ db.db, db.user, db.host.hostname, db.host.hostname);
+ (void)strmov(db.db, tmp_name);
+ }
+ }
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
#ifndef TO_BE_REMOVED
if (table->fields <= 9)
@@ -1339,7 +1376,7 @@ bool hostname_requires_resolving(const char *hostname)
return FALSE;
for (; (cur=*hostname); hostname++)
{
- if ((cur != '%') && (cur != '_') && (cur != '.') &&
+ if ((cur != '%') && (cur != '_') && (cur != '.') && (cur != '/') &&
((cur < '0') || (cur > '9')))
return TRUE;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 7434897ab90..8d694c48849 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2868,8 +2868,18 @@ static void mysql_rm_tmp_tables(void)
** and afterwards delete those marked unused.
*/
-void remove_db_from_cache(const my_string db)
+void remove_db_from_cache(const char *db)
{
+ char name_buff[NAME_LEN+1];
+ if (db && lower_case_table_names)
+ {
+ /*
+ convert database to lower case for comparision.
+ */
+ strmake(name_buff, db, sizeof(name_buff)-1);
+ my_casedn_str(files_charset_info, name_buff);
+ db= name_buff;
+ }
for (uint idx=0 ; idx < open_cache.records ; idx++)
{
TABLE *table=(TABLE*) hash_element(&open_cache,idx);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index ed974a48ad3..d6dcd9ce9ae 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -295,7 +295,18 @@ static char *get_text(LEX *lex)
found_escape=1;
if (lex->ptr == lex->end_of_query)
return 0;
- yySkip();
+#ifdef USE_MB
+ int l;
+ if (use_mb(cs) &&
+ (l = my_ismbchar(cs,
+ (const char *)lex->ptr,
+ (const char *)lex->end_of_query))) {
+ lex->ptr += l;
+ continue;
+ }
+ else
+#endif
+ yySkip();
}
else if (c == sep)
{
@@ -323,6 +334,10 @@ static char *get_text(LEX *lex)
else
{
uchar *to;
+
+ /* Re-use found_escape for tracking state of escapes */
+ found_escape= 0;
+
for (to=start ; str != end ; str++)
{
#ifdef USE_MB
@@ -336,7 +351,7 @@ static char *get_text(LEX *lex)
continue;
}
#endif
- if (*str == '\\' && str+1 != end)
+ if (!found_escape && *str == '\\' && str+1 != end)
{
switch(*++str) {
case 'n':
@@ -362,15 +377,20 @@ static char *get_text(LEX *lex)
*to++= '\\'; // remember prefix for wildcard
/* Fall through */
default:
- *to++ = *str;
+ found_escape= 1;
+ str--;
break;
}
}
- else if (*str == sep)
- *to++= *str++; // Two ' or "
+ else if (!found_escape && *str == sep)
+ {
+ found_escape= 1;
+ }
else
+ {
*to++ = *str;
-
+ found_escape= 0;
+ }
}
*to=0;
lex->yytoklen=(uint) (to-start);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1329a6cd732..a22feda7d89 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2775,18 +2775,23 @@ unsent_create_error:
select_lex->options |= OPTION_BUFFER_RESULT;
}
- if (!(res= open_and_lock_tables(thd, tables)) &&
- !(res= mysql_prepare_insert(thd, tables, first_local_table,
- tables->table, lex->field_list, 0,
+ if ((res= open_and_lock_tables(thd, tables)))
+ break;
+
+ TABLE *table= tables->table;
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first= (byte*) first_local_table->next;
+ tables= (TABLE_LIST *) lex->select_lex.table_list.first;
+ first_local_table->next= 0;
+
+ if (!(res= mysql_prepare_insert(thd, tables, first_local_table,
+ table, lex->field_list, 0,
lex->update_list, lex->value_list,
lex->duplicates)) &&
- (result= new select_insert(tables->table, &lex->field_list,
+ (result= new select_insert(table, &lex->field_list,
&lex->update_list, &lex->value_list,
lex->duplicates, lex->ignore)))
{
- TABLE *table= tables->table;
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first= (byte*) first_local_table->next;
/*
insert/replace from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT
@@ -2794,7 +2799,6 @@ unsent_create_error:
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
res= handle_select(thd, lex, result);
/* revert changes for SP */
- lex->select_lex.table_list.first= (byte*) first_local_table;
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result;
table->insert_values= 0;
@@ -2803,6 +2807,8 @@ unsent_create_error:
}
else
res= -1;
+ first_local_table->next= tables;
+ lex->select_lex.table_list.first= (byte*) first_local_table;
break;
}
case SQLCOM_TRUNCATE:
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 663f2d2be34..6c12381b4bd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -574,7 +574,10 @@ int mysql_multi_update_lock(THD *thd,
else
{
DBUG_PRINT("info",("setting table `%s` for read-only", tl->alias));
- tl->lock_type= TL_READ;
+ // If we are using the binary log, we need TL_READ_NO_INSERT to get
+ // correct order of statements. Otherwise, we use a TL_READ lock to
+ // improve performance.
+ tl->lock_type= using_update_log ? TL_READ_NO_INSERT : TL_READ;
tl->updating= 0;
wants= SELECT_ACL;
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 988323811ac..9f25e17b6fd 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1111,7 +1111,7 @@ create_select:
SELECT_SYM
{
LEX *lex=Lex;
- lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
+ lex->lock_option= using_update_log ? TL_READ_NO_INSERT : TL_READ;
if (lex->sql_command == SQLCOM_INSERT)
lex->sql_command= SQLCOM_INSERT_SELECT;
else if (lex->sql_command == SQLCOM_REPLACE)