summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <bell@laptop.sanja.is.com.ua>2003-10-06 20:55:06 +0300
committerunknown <bell@laptop.sanja.is.com.ua>2003-10-06 20:55:06 +0300
commitff8c8fa1efc4a622e571381c34c5a4575d0f3b5e (patch)
treef658418875ab7ed1c8c3198dc5135387bf23a7a6 /sql
parent12b769418af82303239d43447def128ed933b440 (diff)
parent6fc8b48c4652d404b38146844d17ed2a01a3b327 (diff)
downloadmariadb-git-ff8c8fa1efc4a622e571381c34c5a4575d0f3b5e.tar.gz
Merge
mysql-test/r/union.result: Auto merged mysql-test/t/union.test: Auto merged sql/item.cc: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_cmpfunc.h: Auto merged sql/item_subselect.cc: Auto merged sql/item_subselect.h: Auto merged sql/item_sum.cc: Auto merged sql/item_sum.h: Auto merged sql/mysql_priv.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_derived.cc: Auto merged sql/sql_union.cc: Auto merged sql/sql_yacc.yy: Auto merged mysql-test/r/subselect.result: SCCS merged mysql-test/t/subselect.test: SCCS merged
Diffstat (limited to 'sql')
-rw-r--r--sql/derror.cc19
-rw-r--r--sql/field.cc47
-rw-r--r--sql/field.h36
-rw-r--r--sql/filesort.cc1
-rw-r--r--sql/gen_lex_hash.cc15
-rw-r--r--sql/ha_berkeley.cc9
-rw-r--r--sql/ha_innodb.cc165
-rw-r--r--sql/ha_myisam.cc10
-rw-r--r--sql/ha_myisam.h1
-rw-r--r--sql/handler.cc89
-rw-r--r--sql/handler.h71
-rw-r--r--sql/hash_filo.h2
-rw-r--r--sql/item.cc130
-rw-r--r--sql/item.h23
-rw-r--r--sql/item_cmpfunc.cc64
-rw-r--r--sql/item_cmpfunc.h37
-rw-r--r--sql/item_create.cc33
-rw-r--r--sql/item_create.h4
-rw-r--r--sql/item_func.cc259
-rw-r--r--sql/item_func.h25
-rw-r--r--sql/item_geofunc.h24
-rw-r--r--sql/item_strfunc.cc326
-rw-r--r--sql/item_strfunc.h80
-rw-r--r--sql/item_subselect.cc77
-rw-r--r--sql/item_subselect.h24
-rw-r--r--sql/item_sum.cc116
-rw-r--r--sql/item_sum.h67
-rw-r--r--sql/item_timefunc.h11
-rw-r--r--sql/item_uniq.h4
-rw-r--r--sql/lex.h12
-rw-r--r--sql/lock.cc4
-rw-r--r--sql/log.cc77
-rw-r--r--sql/log_event.cc234
-rw-r--r--sql/log_event.h27
-rw-r--r--sql/mysql_priv.h94
-rw-r--r--sql/mysqld.cc152
-rw-r--r--sql/net_serv.cc39
-rw-r--r--sql/opt_range.cc100
-rw-r--r--sql/password.c824
-rw-r--r--sql/protocol.cc40
-rw-r--r--sql/protocol.h15
-rw-r--r--sql/records.cc1
-rw-r--r--sql/repl_failsafe.cc40
-rw-r--r--sql/set_var.cc156
-rw-r--r--sql/set_var.h20
-rw-r--r--sql/share/Makefile.am2
-rw-r--r--sql/share/czech/errmsg.txt21
-rw-r--r--sql/share/danish/errmsg.txt19
-rw-r--r--sql/share/dutch/errmsg.txt19
-rw-r--r--sql/share/english/errmsg.txt14
-rw-r--r--sql/share/estonian/errmsg.txt19
-rw-r--r--sql/share/french/errmsg.txt19
-rw-r--r--sql/share/german/errmsg.txt17
-rw-r--r--sql/share/greek/errmsg.txt19
-rw-r--r--sql/share/hungarian/errmsg.txt19
-rw-r--r--sql/share/italian/errmsg.txt19
-rw-r--r--sql/share/japanese/errmsg.txt19
-rw-r--r--sql/share/korean/errmsg.txt19
-rw-r--r--sql/share/norwegian-ny/errmsg.txt19
-rw-r--r--sql/share/norwegian/errmsg.txt19
-rw-r--r--sql/share/polish/errmsg.txt19
-rw-r--r--sql/share/portuguese/errmsg.txt38
-rw-r--r--sql/share/romanian/errmsg.txt19
-rw-r--r--sql/share/russian/errmsg.txt17
-rw-r--r--sql/share/serbian/errmsg.txt19
-rw-r--r--sql/share/slovak/errmsg.txt19
-rw-r--r--sql/share/spanish/errmsg.txt54
-rw-r--r--sql/share/swedish/errmsg.txt17
-rw-r--r--sql/share/ukrainian/errmsg.txt17
-rw-r--r--sql/slave.cc405
-rw-r--r--sql/slave.h96
-rw-r--r--sql/sql_acl.cc768
-rw-r--r--sql/sql_acl.h19
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_cache.cc123
-rw-r--r--sql/sql_cache.h2
-rw-r--r--sql/sql_class.cc10
-rw-r--r--sql/sql_class.h35
-rw-r--r--sql/sql_crypt.cc2
-rw-r--r--sql/sql_db.cc47
-rw-r--r--sql/sql_derived.cc14
-rw-r--r--sql/sql_insert.cc21
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h37
-rw-r--r--sql/sql_load.cc45
-rw-r--r--sql/sql_parse.cc996
-rw-r--r--sql/sql_prepare.cc139
-rw-r--r--sql/sql_repl.cc121
-rw-r--r--sql/sql_select.cc288
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/sql_show.cc212
-rw-r--r--sql/sql_string.cc5
-rw-r--r--sql/sql_table.cc156
-rw-r--r--sql/sql_test.cc2
-rw-r--r--sql/sql_udf.cc13
-rw-r--r--sql/sql_udf.h25
-rw-r--r--sql/sql_union.cc102
-rw-r--r--sql/sql_update.cc14
-rw-r--r--sql/sql_yacc.yy305
-rw-r--r--sql/table.cc10
-rw-r--r--sql/udf_example.cc25
101 files changed, 5007 insertions, 3132 deletions
diff --git a/sql/derror.cc b/sql/derror.cc
index 7ebe6e4b3c5..78efdcc33f3 100644
--- a/sql/derror.cc
+++ b/sql/derror.cc
@@ -49,6 +49,7 @@ static void read_texts(const char *file_name,const char ***point,
char name[FN_REFLEN];
const char *buff;
uchar head[32],*pos;
+ CHARSET_INFO *cset;
DBUG_ENTER("read_texts");
*point=0; // If something goes wrong
@@ -65,6 +66,21 @@ static void read_texts(const char *file_name,const char ***point,
head[2] != 2 || head[3] != 1)
goto err; /* purecov: inspected */
textcount=head[4];
+
+ if (!head[30])
+ {
+ sql_print_error("Character set information not found in '%s'. \
+Please install the latest version of this file.",name);
+ goto err1;
+ }
+
+ if (!(cset= get_charset(head[30],MYF(MY_WME))))
+ {
+ sql_print_error("Character set #%d is not supported for messagefile '%s'",
+ (int)head[30],name);
+ goto err1;
+ }
+
length=uint2korr(head+6); count=uint2korr(head+8);
if (count < error_messages)
@@ -114,9 +130,10 @@ err:
buff="Can't find messagefile '%s'";
break;
}
+ sql_print_error(buff,name);
+err1:
if (file != FERR)
VOID(my_close(file,MYF(MY_WME)));
- sql_print_error(buff,name);
unireg_abort(1);
} /* read_texts */
diff --git a/sql/field.cc b/sql/field.cc
index 051a4fa8057..68c9922e887 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -771,7 +771,7 @@ int Field_decimal::store(double nr)
char buff[320];
fyllchar = zerofill ? (char) '0' : (char) ' ';
-#ifdef HAVE_SNPRINTF_
+#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
length=(uint) strlen(buff);
@@ -2016,9 +2016,16 @@ double Field_longlong::val_real(void)
else
#endif
longlongget(j,ptr);
- return unsigned_flag ? ulonglong2double((ulonglong) j) : (double) j;
+ /* The following is open coded to avoid a bug in gcc 3.3 */
+ if (unsigned_flag)
+ {
+ ulonglong tmp= (ulonglong) j;
+ return ulonglong2double(tmp);
+ }
+ return (double) j;
}
+
longlong Field_longlong::val_int(void)
{
longlong j;
@@ -3968,12 +3975,8 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
char *end=ptr+field_length;
-#ifdef WANT_TRUE_BINARY_STRINGS
- if (!binary)
-#endif
- while (end > ptr && end[-1] == ' ')
- end--;
- val_ptr->set((const char*) ptr,(uint) (end - ptr),field_charset);
+ uint length= field_charset->cset->lengthsp(field_charset, ptr, field_length);
+ val_ptr->set((const char*) ptr, length, field_charset);
return val_ptr;
}
@@ -4413,8 +4416,11 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs)
Field_blob::store_length(length);
if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
{ // Must make a copy
- value.copy(from,length,charset());
- from=value.ptr();
+ if (from != value.ptr()) // For valgrind
+ {
+ value.copy(from,length,charset());
+ from=value.ptr();
+ }
}
bmove(ptr+packlength,(char*) &from,sizeof(char*));
}
@@ -5480,6 +5486,27 @@ create_field::create_field(Field *old_field,Field *orig_field)
if (flags & BLOB_FLAG)
pack_length= (pack_length- old_field->table->blob_ptr_size +
portable_sizeof_char_ptr);
+
+ switch (sql_type)
+ {
+ case FIELD_TYPE_BLOB:
+ switch (pack_length - portable_sizeof_char_ptr)
+ {
+ case 1: sql_type= FIELD_TYPE_TINY_BLOB; break;
+ case 2: sql_type= FIELD_TYPE_BLOB; break;
+ case 3: sql_type= FIELD_TYPE_MEDIUM_BLOB; break;
+ default: sql_type= FIELD_TYPE_LONG_BLOB; break;
+ }
+ length /= charset->mbmaxlen;
+ break;
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ length /= charset->mbmaxlen;
+ break;
+ default:
+ break;
+ }
+
decimals= old_field->decimals();
if (sql_type == FIELD_TYPE_STRING)
{
diff --git a/sql/field.h b/sql/field.h
index 794b4a89542..fe5141e9d80 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -125,6 +125,13 @@ public:
{ return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : table->null_row; }
inline bool is_real_null(uint row_offset=0)
{ return null_ptr ? (null_ptr[row_offset] & null_bit ? 1 : 0) : 0; }
+ inline bool is_null_in_record(const uchar *record)
+ {
+ if (!null_ptr)
+ return 0;
+ return test(record[(uint) (null_ptr - (uchar*) table->record[0])] &
+ null_bit);
+ }
inline void set_null(int row_offset=0)
{ if (null_ptr) null_ptr[row_offset]|= null_bit; }
inline void set_notnull(int row_offset=0)
@@ -305,6 +312,11 @@ public:
unireg_check_arg, field_name_arg, table_arg,
dec_arg, zero_arg,unsigned_arg)
{}
+ Field_decimal(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg,bool unsigned_arg)
+ :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg,0,0,unsigned_arg)
+ {}
enum_field_types type() const { return FIELD_TYPE_DECIMAL;}
enum ha_base_keytype key_type() const
{ return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
@@ -334,6 +346,11 @@ public:
unireg_check_arg, field_name_arg, table_arg,
0, zero_arg,unsigned_arg)
{}
+ Field_tiny(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg,bool unsigned_arg)
+ :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg,0,0,unsigned_arg)
+ {}
enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return FIELD_TYPE_TINY;}
enum ha_base_keytype key_type() const
@@ -364,6 +381,11 @@ public:
unireg_check_arg, field_name_arg, table_arg,
0, zero_arg,unsigned_arg)
{}
+ Field_short(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg,bool unsigned_arg)
+ :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0,0,
+ NONE, field_name_arg, table_arg,0,0,unsigned_arg)
+ {}
enum Item_result result_type () const { return INT_RESULT; }
enum_field_types type() const { return FIELD_TYPE_SHORT;}
enum ha_base_keytype key_type() const
@@ -497,6 +519,11 @@ public:
unireg_check_arg, field_name_arg, table_arg,
dec_arg, zero_arg,unsigned_arg)
{}
+ Field_float(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg, uint8 dec_arg)
+ :Field_num((char*) 0, len_arg, maybe_null_arg ? (uchar*) "": 0, (uint) 0,
+ NONE, field_name_arg, table_arg,dec_arg,0,0)
+ {}
enum_field_types type() const { return FIELD_TYPE_FLOAT;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
int store(const char *to,uint length,CHARSET_INFO *charset);
@@ -558,6 +585,11 @@ public:
:Field_str(ptr_arg, len_arg, null, 1,
unireg_check_arg, field_name_arg, table_arg, cs)
{}
+ Field_null(uint32 len_arg, const char *field_name_arg,
+ struct st_table *table_arg, CHARSET_INFO *cs)
+ :Field_str((char*) 0, len_arg, null, 1,
+ NONE, field_name_arg, table_arg, cs)
+ {}
enum_field_types type() const { return FIELD_TYPE_NULL;}
int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; }
int store(double nr) { null[0]=1; return 0; }
@@ -627,6 +659,10 @@ public:
:Field_tiny(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg, 1, 1)
{}
+ Field_year(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_tiny(len_arg,maybe_null_arg,field_name_arg,table_arg,1)
+ {}
enum_field_types type() const { return FIELD_TYPE_YEAR;}
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(double nr);
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 13989bdae8f..1b481924690 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -1,4 +1,3 @@
-
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index dc4f23db3b2..7126b7ee577 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -430,18 +430,9 @@ int main(int argc,char **argv)
exit(1);
printf("/* Copyright (C) 2001 MySQL AB\n\
- This program is free software; you can redistribute it and/or modify\n\
- it under the terms of the GNU General Public License as published by\n\
- the Free Software Foundation; either version 2 of the License, or\n\
- (at your option) any later version.\n\n\
- This program is distributed in the hope that it will be useful,\n\
- but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
- GNU General Public License for more details.\n\n\
- You should have received a copy of the GNU General Public License\n\
- along with this program; if not, write to the Free Software\n\
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\
- USA */\n\n");
+ This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
+ and you are welcome to modify and redistribute it under the GPL license\n\
+ \n*/\n\n");
printf("/* This code is generated by gen_lex_hash.cc that seeks for\
a perfect\nhash function */\n\n");
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index dbed955c0a9..1b99efeaa43 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -304,11 +304,13 @@ void berkeley_cleanup_log_files(void)
char **names;
int error;
+// by HF. Sometimes it crashes. TODO - find out why
+#ifndef EMBEDDED_LIBRARY
/* XXX: Probably this should be done somewhere else, and
* should be tunable by the user. */
if ((error = db_env->txn_checkpoint(db_env, 0, 0, 0)))
my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error); /* purecov: inspected */
-
+#endif
if ((error = db_env->log_archive(db_env, &names, DB_ARCH_ABS)) != 0)
{
DBUG_PRINT("error", ("log_archive failed (error %d)", error)); /* purecov: inspected */
@@ -1433,6 +1435,8 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
}
if (key_len == key_info->key_length)
{
+ if (find_flag == HA_READ_AFTER_KEY)
+ key_info->handler.bdb_return_if_eq= 1;
error=read_row(cursor->c_get(cursor, pack_key(&last_key,
active_index,
key_buff,
@@ -1441,6 +1445,7 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
(find_flag == HA_READ_KEY_EXACT ?
DB_SET : DB_SET_RANGE)),
(char*) buf, active_index, &row, (DBT*) 0, 0);
+ key_info->handler.bdb_return_if_eq= 0;
}
else
{
@@ -2263,7 +2268,7 @@ static BDB_SHARE *get_share(const char *table_name, TABLE *table)
strmov(share->table_name,table_name);
share->key_file = key_file;
share->key_type = key_type;
- if (hash_insert(&bdb_open_tables, (byte*) share))
+ if (my_hash_insert(&bdb_open_tables, (byte*) share))
{
pthread_mutex_unlock(&bdb_mutex); /* purecov: inspected */
my_free((gptr) share,0); /* purecov: inspected */
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index d870d0debfd..4ff5aba4a32 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -28,7 +28,6 @@ InnoDB */
#include "mysql_priv.h"
#include "slave.h"
-#include "sql_cache.h"
#ifdef HAVE_INNOBASE_DB
#include <m_ctype.h>
@@ -394,7 +393,7 @@ check_trx_exists(
{
trx_t* trx;
- ut_a(thd == current_thd);
+ DBUG_ASSERT(thd == current_thd);
trx = (trx_t*) thd->transaction.all.innobase_tid;
@@ -1541,82 +1540,6 @@ ha_innobase::close(void)
DBUG_RETURN(0);
}
-/* The following accessor functions should really be inside MySQL code! */
-
-/******************************************************************
-Gets field offset for a field in a table. */
-inline
-uint
-get_field_offset(
-/*=============*/
- /* out: offset */
- TABLE* table, /* in: MySQL table object */
- Field* field) /* in: MySQL field object */
-{
- return((uint) (field->ptr - (char*) table->record[0]));
-}
-
-/******************************************************************
-Checks if a field in a record is SQL NULL. Uses the record format
-information in table to track the null bit in record. */
-inline
-uint
-field_in_record_is_null(
-/*====================*/
- /* out: 1 if NULL, 0 otherwise */
- TABLE* table, /* in: MySQL table object */
- Field* field, /* in: MySQL field object */
- char* record) /* in: a row in MySQL format */
-{
- int null_offset;
-
- if (!field->null_ptr) {
-
- return(0);
- }
-
- null_offset = (uint) ((char*) field->null_ptr
- - (char*) table->record[0]);
-
- if (record[null_offset] & field->null_bit) {
-
- return(1);
- }
-
- return(0);
-}
-
-/******************************************************************
-Sets a field in a record to SQL NULL. Uses the record format
-information in table to track the null bit in record. */
-inline
-void
-set_field_in_record_to_null(
-/*========================*/
- TABLE* table, /* in: MySQL table object */
- Field* field, /* in: MySQL field object */
- char* record) /* in: a row in MySQL format */
-{
- int null_offset;
-
- null_offset = (uint) ((char*) field->null_ptr
- - (char*) table->record[0]);
-
- record[null_offset] = record[null_offset] | field->null_bit;
-}
-
-/******************************************************************
-Resets SQL NULL bits in a record to zero. */
-inline
-void
-reset_null_bits(
-/*============*/
- TABLE* table, /* in: MySQL table object */
- char* record) /* in: a row in MySQL format */
-{
- bzero(record, table->null_bytes);
-}
-
extern "C" {
/*****************************************************************
InnoDB uses this function is to compare two data fields for which the
@@ -1826,11 +1749,10 @@ ha_innobase::store_key_val_for_row(
blob_data = row_mysql_read_blob_ref(&blob_len,
(byte*) (record
- + (ulint)get_field_offset(table, field)),
+ + (ulint) field->offset()),
(ulint) field->pack_length());
- ut_a(get_field_offset(table, field)
- == key_part->offset);
+ ut_a(field->offset() == key_part->offset);
if (blob_len > key_part->length) {
blob_len = key_part->length;
}
@@ -1885,7 +1807,7 @@ build_template(
ibool fetch_all_in_key = FALSE;
ulint i;
- ut_a(templ_type != ROW_MYSQL_REC_FIELDS || thd == current_thd);
+ DBUG_ASSERT(templ_type != ROW_MYSQL_REC_FIELDS || thd == current_thd);
clust_index = dict_table_get_first_index_noninline(prebuilt->table);
@@ -2010,9 +1932,7 @@ build_template(
templ->mysql_null_bit_mask = 0;
}
- templ->mysql_col_offset = (ulint)
- get_field_offset(table, field);
-
+ templ->mysql_col_offset = (ulint) field->offset();
templ->mysql_col_len = (ulint) field->pack_length();
templ->type = get_innobase_type_from_mysql_type(field);
templ->is_unsigned = (ulint) (field->flags & UNSIGNED_FLAG);
@@ -2058,8 +1978,8 @@ ha_innobase::write_row(
DBUG_ENTER("ha_innobase::write_row");
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
statistic_increment(ha_write_count, &LOCK_status);
@@ -2349,8 +2269,8 @@ calc_row_difference(
/* goto skip_field;
}*/
- o_ptr = (byte*) old_row + get_field_offset(table, field);
- n_ptr = (byte*) new_row + get_field_offset(table, field);
+ o_ptr = (byte*) old_row + field->offset();
+ n_ptr = (byte*) new_row + field->offset();
o_len = field->pack_length();
n_len = field->pack_length();
@@ -2375,13 +2295,11 @@ calc_row_difference(
}
if (field->null_ptr) {
- if (field_in_record_is_null(table, field,
- (char*) old_row)) {
+ if (field->is_null_in_record((uchar*) old_row)) {
o_len = UNIV_SQL_NULL;
}
- if (field_in_record_is_null(table, field,
- (char*) new_row)) {
+ if (field->is_null_in_record((uchar*) new_row)) {
n_len = UNIV_SQL_NULL;
}
}
@@ -2433,8 +2351,8 @@ ha_innobase::update_row(
DBUG_ENTER("ha_innobase::update_row");
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
if (table->time_stamp) {
update_timestamp(new_row + table->time_stamp - 1);
@@ -2495,8 +2413,8 @@ ha_innobase::delete_row(
DBUG_ENTER("ha_innobase::delete_row");
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -2673,8 +2591,8 @@ ha_innobase::index_read(
DBUG_ENTER("index_read");
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
statistic_increment(ha_read_key_count, &LOCK_status);
@@ -2787,12 +2705,9 @@ ha_innobase::change_active_index(
statistic_increment(ha_read_key_count, &LOCK_status);
DBUG_ENTER("change_active_index");
+ DBUG_ASSERT(user_thd == current_thd);
ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
- ut_a(user_thd == current_thd);
-
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ (trx_t*) user_thd->transaction.all.innobase_tid);
active_index = keynr;
@@ -2877,8 +2792,8 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
innodb_srv_conc_enter_innodb(prebuilt->trx);
@@ -3111,8 +3026,8 @@ ha_innobase::rnd_pos(
statistic_increment(ha_read_rnd_count, &LOCK_status);
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we
@@ -3160,8 +3075,8 @@ ha_innobase::position(
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
uint len;
- ut_a(prebuilt->trx ==
- (trx_t*) current_thd->transaction.all.innobase_tid);
+ DBUG_ASSERT(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
if (prebuilt->clust_index_was_generated) {
/* No primary key was defined for the table and we
@@ -3443,7 +3358,7 @@ ha_innobase::create(
/* Get the transaction associated with the current thd, or create one
if not yet created */
- parent_trx = check_trx_exists(current_thd);
+ parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@@ -3556,10 +3471,10 @@ ha_innobase::create(
}
}
- if (current_thd->query != NULL) {
+ if (thd->query != NULL) {
error = row_table_add_foreign_constraints(trx,
- current_thd->query, norm_name);
+ thd->query, norm_name);
error = convert_error_code_to_mysql(error, NULL);
@@ -3616,13 +3531,13 @@ ha_innobase::delete_table(
trx_t* parent_trx;
trx_t* trx;
char norm_name[1000];
-
+ THD *thd= current_thd;
DBUG_ENTER("ha_innobase::delete_table");
/* Get the transaction associated with the current thd, or create one
if not yet created */
- parent_trx = check_trx_exists(current_thd);
+ parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@@ -3637,8 +3552,8 @@ ha_innobase::delete_table(
trx = trx_allocate_for_mysql();
- trx->mysql_thd = current_thd;
- trx->mysql_query_str = &((*current_thd).query);
+ trx->mysql_thd = thd;
+ trx->mysql_query_str = &(thd->query);
name_len = strlen(name);
@@ -3691,11 +3606,12 @@ innobase_drop_database(
char* ptr;
int error;
char namebuf[10000];
+ THD *thd= current_thd;
/* Get the transaction associated with the current thd, or create one
if not yet created */
- parent_trx = check_trx_exists(current_thd);
+ parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@@ -3718,8 +3634,8 @@ innobase_drop_database(
my_casedn_str(system_charset_info, namebuf);
#endif
trx = trx_allocate_for_mysql();
- trx->mysql_thd = current_thd;
- trx->mysql_query_str = &((*current_thd).query);
+ trx->mysql_thd = thd;
+ trx->mysql_query_str = &(thd->query);
error = row_drop_database_for_mysql(namebuf, trx);
@@ -3759,13 +3675,14 @@ ha_innobase::rename_table(
trx_t* trx;
char norm_from[1000];
char norm_to[1000];
+ THD *thd= current_thd;
DBUG_ENTER("ha_innobase::rename_table");
/* Get the transaction associated with the current thd, or create one
if not yet created */
- parent_trx = check_trx_exists(current_thd);
+ parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
@@ -3779,8 +3696,8 @@ ha_innobase::rename_table(
}
trx = trx_allocate_for_mysql();
- trx->mysql_thd = current_thd;
- trx->mysql_query_str = &((*current_thd).query);
+ trx->mysql_thd = thd;
+ trx->mysql_query_str = &(thd->query);
name_len1 = strlen(from);
name_len2 = strlen(to);
@@ -4666,7 +4583,7 @@ static INNOBASE_SHARE *get_share(const char *table_name)
share->table_name_length=length;
share->table_name=(char*) (share+1);
strmov(share->table_name,table_name);
- if (hash_insert(&innobase_open_tables, (mysql_byte*) share))
+ if (my_hash_insert(&innobase_open_tables, (mysql_byte*) share))
{
pthread_mutex_unlock(&innobase_mutex);
my_free((gptr) share,0);
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index e8e4798c2b2..cec1aefa2d5 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -236,6 +236,8 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
VOID(mi_extra(file, HA_EXTRA_WAIT_LOCK, 0));
if (!table->db_record_offset)
int_table_flags|=HA_REC_NOT_IN_SEQ;
+ if (file->s->options & (HA_OPTION_CHECKSUM | HA_OPTION_COMPRESS_RECORD))
+ int_table_flags|=HA_HAS_CHECKSUM;
return (0);
}
@@ -1109,7 +1111,7 @@ THR_LOCK_DATA **ha_myisam::store_lock(THD *thd,
void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
{
- table->file->info(HA_STATUS_AUTO | HA_STATUS_CONST);
+ ha_myisam::info(HA_STATUS_AUTO | HA_STATUS_CONST);
if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
{
create_info->auto_increment_value=auto_increment_value;
@@ -1414,3 +1416,9 @@ int ha_myisam::ft_read(byte * buf)
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
+
+uint ha_myisam::checksum() const
+{
+ return (uint)file->s->state.checksum;
+}
+
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 8486e25556b..e4e3192af10 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -64,6 +64,7 @@ class ha_myisam: public handler
uint max_keys() const { return MI_MAX_KEY; }
uint max_key_parts() const { return MAX_REF_PARTS; }
uint max_key_length() const { return MI_MAX_KEY_LENGTH; }
+ uint checksum() const;
int open(const char *name, int mode, uint test_if_locked);
int close(void);
diff --git a/sql/handler.cc b/sql/handler.cc
index b4d370491bb..e14e326792d 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -359,7 +359,10 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
my_b_tell(&thd->transaction.trans_log))
{
- mysql_bin_log.write(thd, &thd->transaction.trans_log);
+ if (wait_if_global_read_lock(thd, 0))
+ DBUG_RETURN(1);
+ mysql_bin_log.write(thd, &thd->transaction.trans_log, 1);
+ start_waiting_global_read_lock(thd);
reinit_io_cache(&thd->transaction.trans_log,
WRITE_CACHE, (my_off_t) 0, 0, 1);
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
@@ -442,9 +445,21 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
}
#endif
if (trans == &thd->transaction.all)
+ {
+ /*
+ Update the binary log with a BEGIN/ROLLBACK block if we have cached some
+ queries and we updated some non-transactional table. Such cases should
+ be rare (updating a non-transactional table inside a transaction...).
+ */
+ if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ mysql_bin_log.is_open() &&
+ my_b_tell(&thd->transaction.trans_log)))
+ mysql_bin_log.write(thd, &thd->transaction.trans_log, 0);
+ /* Flushed or not, empty the binlog cache */
reinit_io_cache(&thd->transaction.trans_log,
- WRITE_CACHE, (my_off_t) 0, 0, 1);
- thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
+ WRITE_CACHE, (my_off_t) 0, 0, 1);
+ thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
+ }
thd->variables.tx_isolation=thd->session_tx_isolation;
if (operation_done)
{
@@ -458,9 +473,27 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
/*
-Rolls the current transaction back to a savepoint.
-Return value: 0 if success, 1 if there was not a savepoint of the given
-name.
+ Rolls the current transaction back to a savepoint.
+ Return value: 0 if success, 1 if there was not a savepoint of the given
+ name.
+ NOTE: how do we handle this (unlikely but legal) case:
+ [transaction] + [update to non-trans table] + [rollback to savepoint] ?
+ The problem occurs when a savepoint is before the update to the
+ non-transactional table. Then when there's a rollback to the savepoint, if we
+ simply truncate the binlog cache, we lose the part of the binlog cache where
+ the update is. If we want to not lose it, we need to write the SAVEPOINT
+ command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
+ is easy: it's just write at the end of the binlog cache, but the former should
+ be *inserted* to the place where the user called SAVEPOINT. The solution is
+ that when the user calls SAVEPOINT, we write it to the binlog cache (so no
+ need to later insert it). As transactions are never intermixed in the binary log
+ (i.e. they are serialized), we won't have conflicts with savepoint names when
+ using mysqlbinlog or in the slave SQL thread.
+ Then when ROLLBACK TO SAVEPOINT is called, if we updated some
+ non-transactional table, we don't truncate the binlog cache but instead write
+ ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
+ will chop the SAVEPOINT command from the binlog cache, which is good as in
+ that case there is no need to have it in the binlog).
*/
int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
@@ -485,8 +518,24 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
error=1;
}
else
- reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
- binlog_cache_pos, 0, 0);
+ {
+ /*
+ Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
+ non-transactional table. Otherwise, truncate the binlog cache starting
+ from the SAVEPOINT command.
+ */
+ if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ mysql_bin_log.is_open() &&
+ my_b_tell(&thd->transaction.trans_log)))
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
+ if (mysql_bin_log.write(&qinfo))
+ error= 1;
+ }
+ else
+ reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
+ binlog_cache_pos, 0, 0);
+ }
operation_done=1;
#endif
if (operation_done)
@@ -515,6 +564,13 @@ int ha_savepoint(THD *thd, char *savepoint_name)
#ifdef HAVE_INNOBASE_DB
innobase_savepoint(thd,savepoint_name, binlog_cache_pos);
#endif
+ /* Write it to the binary log (see comments of ha_rollback_to_savepoint). */
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
+ if (mysql_bin_log.write(&qinfo))
+ error= 1;
+ }
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
@@ -1051,14 +1107,25 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
void ha_key_cache(void)
{
- if (keybuff_size)
- (void) init_key_cache((ulong) keybuff_size);
+ /*
+ The following mutex is not really needed as long as keybuff_size is
+ treated as a long value, but we use the mutex here to guard for future
+ changes.
+ */
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ long tmp= (long) keybuff_size;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ if (tmp)
+ (void) init_key_cache(tmp);
}
void ha_resize_key_cache(void)
{
- (void) resize_key_cache((ulong) keybuff_size);
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ long tmp= (long) keybuff_size;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ (void) resize_key_cache(tmp);
}
diff --git a/sql/handler.h b/sql/handler.h
index b1b5cfb02b0..b74e06c6edf 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -42,38 +42,39 @@
#define HA_ADMIN_INVALID -5
/* Bits in table_flags() to show what database can do */
-#define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record
- (To update with RND-read) */
-#define HA_KEYPOS_TO_RNDPOS 2 /* ha_info gives pos to record */
-#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */
-#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber;
- It returns a position to ha_r_rnd */
-#define HA_HAS_GEOMETRY 16
-#define HA_NO_INDEX 32 /* No index needed for next/prev */
-#define HA_KEY_READ_WRONG_STR 64 /* keyread returns converted strings */
-#define HA_NULL_KEY 128 /* One can have keys with NULL */
-#define HA_DUPP_POS 256 /* ha_position() gives dupp row */
-#define HA_NO_BLOBS 512 /* Doesn't support blobs */
-#define HA_BLOB_KEY (HA_NO_BLOBS*2) /* key on blob */
-#define HA_AUTO_PART_KEY (HA_BLOB_KEY*2)
-#define HA_REQUIRE_PRIMARY_KEY (HA_AUTO_PART_KEY*2)
-#define HA_NOT_EXACT_COUNT (HA_REQUIRE_PRIMARY_KEY*2)
-#define HA_NO_WRITE_DELAYED (HA_NOT_EXACT_COUNT*2)
-#define HA_PRIMARY_KEY_IN_READ_INDEX (HA_NO_WRITE_DELAYED*2)
-#define HA_DROP_BEFORE_CREATE (HA_PRIMARY_KEY_IN_READ_INDEX*2)
-#define HA_NOT_READ_AFTER_KEY (HA_DROP_BEFORE_CREATE*2)
-#define HA_NOT_DELETE_WITH_CACHE (HA_NOT_READ_AFTER_KEY*2)
-#define HA_NO_TEMP_TABLES (HA_NOT_DELETE_WITH_CACHE*2)
-#define HA_NO_PREFIX_CHAR_KEYS (HA_NO_TEMP_TABLES*2)
-#define HA_CAN_FULLTEXT (HA_NO_PREFIX_CHAR_KEYS*2)
-#define HA_CAN_SQL_HANDLER (HA_CAN_FULLTEXT*2)
-#define HA_NO_AUTO_INCREMENT (HA_CAN_SQL_HANDLER*2)
+#define HA_READ_RND_SAME 1 /* Read RND-record to KEY-record
+ (To update with RND-read) */
+#define HA_KEYPOS_TO_RNDPOS 2 /* ha_info gives pos to record */
+#define HA_TABLE_SCAN_ON_INDEX 4 /* No separate data/index file */
+#define HA_REC_NOT_IN_SEQ 8 /* ha_info don't return recnumber;
+ It returns a position to ha_r_rnd */
+#define HA_HAS_GEOMETRY (1 << 4)
+#define HA_NO_INDEX (1 << 5) /* No index needed for next/prev */
+#define HA_KEY_READ_WRONG_STR (1 << 6) /* keyread returns converted strings */
+#define HA_NULL_KEY (1 << 7) /* One can have keys with NULL */
+#define HA_DUPP_POS (1 << 8) /* ha_position() gives dupp row */
+#define HA_NO_BLOBS (1 << 9) /* Doesn't support blobs */
+#define HA_BLOB_KEY (1 << 10) /* key on blob */
+#define HA_AUTO_PART_KEY (1 << 11)
+#define HA_REQUIRE_PRIMARY_KEY (1 << 12)
+#define HA_NOT_EXACT_COUNT (1 << 13)
+#define HA_NO_WRITE_DELAYED (1 << 14)
+#define HA_PRIMARY_KEY_IN_READ_INDEX (1 << 15)
+#define HA_DROP_BEFORE_CREATE (1 << 16)
+#define HA_NOT_READ_AFTER_KEY (1 << 17)
+#define HA_NOT_DELETE_WITH_CACHE (1 << 18)
+#define HA_NO_TEMP_TABLES (1 << 19)
+#define HA_NO_PREFIX_CHAR_KEYS (1 << 20)
+#define HA_CAN_FULLTEXT (1 << 21)
+#define HA_CAN_SQL_HANDLER (1 << 22)
+#define HA_NO_AUTO_INCREMENT (1 << 23)
+#define HA_HAS_CHECKSUM (1 << 24)
/*
Next record gives next record according last record read (even
if database is updated after read). Not used at this point.
*/
-#define HA_LASTKEY_ORDER (HA_NO_AUTO_INCREMENT*2)
+#define HA_LASTKEY_ORDER (1 << 25)
/* bits in index_flags(index_number) for what you can do with index */
@@ -306,8 +307,8 @@ public:
virtual bool check_and_repair(THD *thd) {return 1;}
virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt);
virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt);
- virtual int backup(THD* thd, HA_CHECK_OPT* check_opt);
virtual int preload_keys(THD* thd, HA_CHECK_OPT* check_opt);
+ virtual int backup(THD* thd, HA_CHECK_OPT* check_opt);
/*
restore assumes .frm file must exist, and that generate_table() has been
called; It will just copy the data file and run repair.
@@ -325,8 +326,8 @@ public:
virtual char* get_foreign_key_create_info()
{ return(NULL);} /* gets foreign key create string from InnoDB */
virtual void init_table_handle_for_HANDLER()
- { return; } /* prepare InnoDB for HANDLER */
- virtual void free_foreign_key_create_info(char* str) {}
+ { return; } /* prepare InnoDB for HANDLER */
+ virtual void free_foreign_key_create_info(char* str) {}
/* The following can be called without an open handler */
virtual const char *table_type() const =0;
virtual const char **bas_ext() const =0;
@@ -342,6 +343,7 @@ public:
virtual uint max_key_part_length() { return 255; }
virtual uint min_record_length(uint options) const { return 1; }
virtual bool low_byte_first() const { return 1; }
+ virtual uint checksum() const { return 0; }
virtual bool is_crashed() const { return 0; }
virtual bool auto_repair() const { return 0; }
@@ -355,13 +357,12 @@ public:
/* Type of table for caching query */
virtual uint8 table_cache_type() { return HA_CACHE_TBL_NONTRANSACT; }
- /*
- Is query with this cable cachable (have sense only for ASKTRANSACT
+ /*
+ Is query with this table cachable (have sense only for ASKTRANSACT
tables)
*/
- static bool caching_allowed(THD* thd, char* table_key,
+ static bool caching_allowed(THD* thd, char* table_key,
uint key_length, uint8 cahe_type);
-
};
/* Some extern variables used with handlers */
@@ -390,7 +391,7 @@ int ha_delete_table(enum db_type db_type, const char *path);
void ha_drop_database(char* path);
void ha_key_cache(void);
void ha_resize_key_cache(void);
-int ha_start_stmt(THD *thd);
+int ha_start_stmt(THD *thd);
int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name,
my_off_t end_offset);
int ha_commit_complete(THD *thd);
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index 92cd2658967..d1672e1a60c 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -116,7 +116,7 @@ public:
last_link=last_link->prev_used;
hash_delete(&cache,(byte*) tmp);
}
- if (hash_insert(&cache,(byte*) entry))
+ if (my_hash_insert(&cache,(byte*) entry))
{
if (free_element)
(*free_element)(entry); // This should never happen
diff --git a/sql/item.cc b/sql/item.cc
index 1a071174210..29cdbaa1e10 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -23,7 +23,8 @@
#include <m_ctype.h>
#include "my_dir.h"
-static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current,
+static void mark_as_dependent(THD *thd,
+ SELECT_LEX *last, SELECT_LEX *current,
Item_ident *item);
/*****************************************************************************
@@ -489,27 +490,38 @@ String *Item_null::val_str(String *str)
/* Item_param related */
void Item_param::set_null()
-{
- maybe_null=null_value=1;
+{
+ DBUG_ENTER("Item_param::set_null");
+ maybe_null= null_value= 1;
+ DBUG_VOID_RETURN;
}
void Item_param::set_int(longlong i)
-{
- int_value=(longlong)i;
- item_type = INT_ITEM;
+{
+ DBUG_ENTER("Item_param::set_int");
+ int_value= (longlong)i;
+ item_type= INT_ITEM;
+ DBUG_PRINT("info", ("integer: %lld", int_value));
+ DBUG_VOID_RETURN;
}
void Item_param::set_double(double value)
-{
+{
+ DBUG_ENTER("Item_param::set_double");
real_value=value;
- item_type = REAL_ITEM;
+ item_type= REAL_ITEM;
+ DBUG_PRINT("info", ("double: %lg", real_value));
+ DBUG_VOID_RETURN;
}
void Item_param::set_value(const char *str, uint length)
-{
- str_value.set(str,length,default_charset());
- item_type = STRING_ITEM;
+{
+ DBUG_ENTER("Item_param::set_value");
+ str_value.copy(str,length,default_charset());
+ item_type= STRING_ITEM;
+ DBUG_PRINT("info", ("string: %s", str_value.ptr()));
+ DBUG_VOID_RETURN;
}
@@ -751,17 +763,29 @@ bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate)
SYNOPSIS
mark_as_dependent()
+ thd - thread handler
last - select from which current item depend
current - current select
item - item which should be marked
*/
-static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current,
+static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
Item_ident *item)
{
// store pointer on SELECT_LEX from wich item is dependent
item->depended_from= last;
current->mark_as_dependent(last);
+ if (thd->lex.describe)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_WARN_FIELD_RESOLVED),
+ (item->db_name?item->db_name:""), (item->db_name?".":""),
+ (item->table_name?item->table_name:""), (item->table_name?".":""),
+ item->field_name,
+ current->select_number, last->select_number);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_WARN_FIELD_RESOLVED, warn_buff);
+ }
}
@@ -844,12 +868,12 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1))
return 1;
- mark_as_dependent(last, cursel, rf);
+ mark_as_dependent(thd, last, cursel, rf);
return 0;
}
else
{
- mark_as_dependent(last, cursel, this);
+ mark_as_dependent(thd, last, cursel, this);
if (last->having_fix_field)
{
Item_ref *rf;
@@ -903,6 +927,13 @@ void Item::make_field(Send_field *tmp_field)
init_make_field(tmp_field, field_type());
}
+
+void Item_empty_string::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_VAR_STRING);
+}
+
+
enum_field_types Item::field_type() const
{
return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING :
@@ -910,6 +941,73 @@ enum_field_types Item::field_type() const
FIELD_TYPE_DOUBLE);
}
+Field *Item::tmp_table_field_from_field_type(TABLE *table)
+{
+ switch (field_type())
+ {
+ case MYSQL_TYPE_DECIMAL:
+ return new Field_decimal(max_length, maybe_null, name, table,
+ unsigned_flag);
+ case MYSQL_TYPE_TINY:
+ return new Field_tiny(max_length, maybe_null, name, table,
+ unsigned_flag);
+ case MYSQL_TYPE_SHORT:
+ return new Field_short(max_length, maybe_null, name, table,
+ unsigned_flag);
+ case MYSQL_TYPE_LONG:
+ return new Field_long(max_length, maybe_null, name, table,
+ unsigned_flag);
+ case MYSQL_TYPE_FLOAT:
+ return new Field_float(max_length, maybe_null, name, table, decimals);
+ case MYSQL_TYPE_DOUBLE:
+ return new Field_double(max_length, maybe_null, name, table, decimals);
+ case MYSQL_TYPE_NULL:
+ return new Field_null(max_length, name, table, &my_charset_bin);
+#ifdef HAVE_LONG_LONG
+ case MYSQL_TYPE_LONGLONG:
+ return new Field_longlong(max_length, maybe_null, name, table,
+ unsigned_flag);
+#endif
+ case MYSQL_TYPE_NEWDATE:
+ case MYSQL_TYPE_INT24:
+ return new Field_long(max_length, maybe_null, name, table,
+ unsigned_flag);
+ case MYSQL_TYPE_DATE:
+ return new Field_date(maybe_null, name, table, &my_charset_bin);
+ case MYSQL_TYPE_TIME:
+ return new Field_time(maybe_null, name, table, &my_charset_bin);
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ return new Field_datetime(maybe_null, name, table, &my_charset_bin);
+ case MYSQL_TYPE_YEAR:
+ return new Field_year(max_length, maybe_null, name, table);
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ return new Field_long(max_length, maybe_null, name, table,
+ unsigned_flag);
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ return new Field_blob(max_length, maybe_null, name, table, collation.collation);
+ case MYSQL_TYPE_VAR_STRING:
+ if (max_length > 255)
+ return new Field_blob(max_length, maybe_null, name, table, collation.collation);
+ else
+ return new Field_varstring(max_length, maybe_null, name, table, collation.collation);
+ case MYSQL_TYPE_STRING:
+ if (max_length > 255)
+ return new Field_blob(max_length, maybe_null, name, table, collation.collation);
+ else
+ return new Field_string(max_length, maybe_null, name, table, collation.collation);
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
/* ARGSUSED */
void Item_field::make_field(Send_field *tmp_field)
{
@@ -1324,7 +1422,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp)))
return 1;
- mark_as_dependent(last, thd->lex.current_select, fld);
+ mark_as_dependent(thd, last, thd->lex.current_select, fld);
return 0;
}
else
@@ -1335,7 +1433,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list");
return -1;
}
- mark_as_dependent(last, thd->lex.current_select,
+ mark_as_dependent(thd, last, thd->lex.current_select,
this);
ref= last->ref_pointer_array + counter;
}
diff --git a/sql/item.h b/sql/item.h
index 4a1c6ac37b6..a126a61e32e 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003
+/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -120,6 +120,9 @@ public:
Constructor used by Item_field, Item_ref & agregate (sum) functions.
Used for duplicating lists in processing queries with temporary
tables
+ Also it used for Item_cond_and/Item_cond_or for creating
+ top AND/OR ctructure of WHERE clause to protect it of
+ optimisation changes in prepared statements
*/
Item(THD *thd, Item &item);
virtual ~Item() { name=0; } /*lint -e1509 */
@@ -140,7 +143,7 @@ public:
virtual double val()=0;
virtual longlong val_int()=0;
virtual String *val_str(String*)=0;
- virtual Field *tmp_table_field() { return 0; }
+ virtual Field *get_tmp_table_field() { return 0; }
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
virtual double val_result() { return val(); }
@@ -184,6 +187,7 @@ public:
virtual void save_in_result_field(bool no_conversions) {}
virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
+ virtual Item *copy_andor_structure(THD *thd) { return this; }
virtual Item *real_item() { return this; }
virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
@@ -206,6 +210,8 @@ public:
virtual bool null_inside() { return 0; }
// used in row subselects to get value of elements
virtual void bring_value() {}
+
+ Field *tmp_table_field_from_field_type(TABLE *table);
};
@@ -266,7 +272,7 @@ public:
{
return field->type();
}
- Field *tmp_table_field() { return result_field; }
+ Field *get_tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
bool get_date(TIME *ltime,bool fuzzydate);
bool get_date_result(TIME *ltime,bool fuzzydate);
@@ -341,7 +347,11 @@ public:
void set_time(TIME *tm, timestamp_type type);
bool get_time(TIME *tm);
void reset() {}
+#ifndef EMBEDDED_LIBRARY
void (*setup_param_func)(Item_param *param, uchar **pos);
+#else
+ void (*setup_param_func)(Item_param *param, uchar **pos, ulong data_len);
+#endif
enum Item_result result_type () const
{ return item_result_type; }
String *query_val_str(String *str);
@@ -504,6 +514,7 @@ public:
Item_empty_string(const char *header,uint length) :Item_string("",0,
&my_charset_bin)
{ name=(char*) header; max_length=length;}
+ void make_field(Send_field *field);
};
class Item_return_int :public Item_int
@@ -540,12 +551,12 @@ class Item_result_field :public Item /* Item with result field */
public:
Field *result_field; /* Save result here */
Item_result_field() :result_field(0) {}
- // Constructor used for Item_sum (see Item comment)
+ // Constructor used for Item_sum/Item_cond_and/or (see Item comment)
Item_result_field(THD *thd, Item_result_field &item):
Item(thd, item), result_field(item.result_field)
{}
~Item_result_field() {} /* Required with gcc 2.95 */
- Field *tmp_table_field() { return result_field; }
+ Field *get_tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
table_map used_tables() const { return 1; }
virtual void fix_length_and_dec()=0;
@@ -863,6 +874,7 @@ public:
{
value= item->val_int_result();
null_value= item->null_value;
+ collation.set(item->collation);
}
double val() { return (double) value; }
longlong val_int() { return value; }
@@ -880,6 +892,7 @@ public:
{
value= item->val_result();
null_value= item->null_value;
+ collation.set(item->collation);
}
double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); }
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 01428dbf995..37a644256f4 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003
+/* Copyright (C) 2000-2003 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -561,6 +561,7 @@ void Item_func_interval::fix_length_and_dec()
used_tables_cache|= row->used_tables();
not_null_tables_cache&= row->not_null_tables();
with_sum_func= with_sum_func || row->with_sum_func;
+ const_item_cache&= row->const_item();
}
@@ -714,8 +715,21 @@ Item_func_ifnull::fix_length_and_dec()
agg_arg_collations(collation, args, arg_count);
else if (cached_result_type != REAL_RESULT)
decimals= 0;
+
+ cached_field_type= args[0]->field_type();
+ if (cached_field_type != args[1]->field_type())
+ cached_field_type= Item_func::field_type();
}
+enum_field_types Item_func_ifnull::field_type() const
+{
+ return cached_field_type;
+}
+
+Field *Item_func_ifnull::tmp_table_field(TABLE *table)
+{
+ return tmp_table_field_from_field_type(table);
+}
double
Item_func_ifnull::val()
@@ -1461,17 +1475,20 @@ void Item_func_in::fix_length_and_dec()
DBUG_ASSERT(0);
return;
}
- uint j=0;
- for (uint i=1 ; i < arg_count ; i++)
+ if (array && !(current_thd->is_fatal_error)) // If not EOM
{
- array->set(j,args[i]);
- if (!args[i]->null_value) // Skip NULL values
- j++;
- else
- have_null= 1;
+ uint j=0;
+ for (uint i=1 ; i < arg_count ; i++)
+ {
+ array->set(j,args[i]);
+ if (!args[i]->null_value) // Skip NULL values
+ j++;
+ else
+ have_null= 1;
+ }
+ if ((array->used_count=j))
+ array->sort();
}
- if ((array->used_count=j))
- array->sort();
}
else
{
@@ -1552,6 +1569,31 @@ longlong Item_func_bit_and::val_int()
return (longlong) (arg1 & arg2);
}
+Item_cond::Item_cond(THD *thd, Item_cond &item)
+ :Item_bool_func(thd, item),
+ abort_on_null(item.abort_on_null),
+ and_tables_cache(item.and_tables_cache)
+{
+ /*
+ here should be following text:
+
+ List_iterator_fast<Item*> li(item.list);
+ while(Item *it= li++)
+ list.push_back(it);
+
+ but it do not need,
+ because this constructor used only for AND/OR and
+ argument list will be copied by copy_andor_arguments call
+ */
+
+}
+
+void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
+{
+ List_iterator_fast<Item> li(item->list);
+ while(Item *it= li++)
+ list.push_back(it->copy_andor_structure(thd));
+}
bool
Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
@@ -1570,7 +1612,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
and_tables_cache= ~(table_map) 0;
if (thd && check_stack_overrun(thd,buff))
- return 0; // Fatal error flag is set!
+ return 1; // Fatal error flag is set!
while ((item=li++))
{
table_map tmp_table_map;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index f705d046229..42b73c48606 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -82,6 +82,7 @@ public:
Item_bool_func() :Item_int_func() {}
Item_bool_func(Item *a) :Item_int_func(a) {}
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_bool_func(THD *thd, Item_bool_func &item) :Item_int_func(thd, item) {}
void fix_length_and_dec() { decimals=0; max_length=1; }
};
@@ -115,8 +116,8 @@ protected:
String tmp_value1,tmp_value2;
public:
- Item_bool_func2(Item *a,Item *b):
- Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {}
+ Item_bool_func2(Item *a,Item *b)
+ :Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {}
void fix_length_and_dec();
void set_cmp_func()
{
@@ -168,7 +169,7 @@ public:
class Item_func_eq :public Item_bool_rowready_func2
{
public:
- Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
+ Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}
longlong val_int();
enum Functype functype() const { return EQ_FUNC; }
enum Functype rev_functype() const { return EQ_FUNC; }
@@ -290,6 +291,8 @@ public:
class Item_func_ifnull :public Item_func
{
enum Item_result cached_result_type;
+ enum_field_types cached_field_type;
+ bool field_type_defined;
public:
Item_func_ifnull(Item *a,Item *b)
:Item_func(a,b), cached_result_type(INT_RESULT)
@@ -298,8 +301,10 @@ public:
longlong val_int();
String *val_str(String *str);
enum Item_result result_type () const { return cached_result_type; }
+ enum_field_types field_type() const;
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
+ Field *tmp_table_field(TABLE *table);
table_map not_null_tables() const { return 0; }
};
@@ -797,8 +802,13 @@ protected:
public:
/* Item_cond() is only used to create top level items */
Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; }
- Item_cond(Item *i1,Item *i2) :Item_bool_func(), abort_on_null(0)
- { list.push_back(i1); list.push_back(i2); }
+ Item_cond(Item *i1,Item *i2)
+ :Item_bool_func(), abort_on_null(0)
+ {
+ list.push_back(i1);
+ list.push_back(i2);
+ }
+ Item_cond(THD *thd, Item_cond &item);
~Item_cond() { list.delete_elements(); }
bool add(Item *item) { return list.push_back(item); }
bool fix_fields(THD *, struct st_table_list *, Item **ref);
@@ -811,6 +821,7 @@ public:
void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
void top_level_item() { abort_on_null=1; }
+ void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, byte *arg);
};
@@ -821,9 +832,17 @@ class Item_cond_and :public Item_cond
public:
Item_cond_and() :Item_cond() {}
Item_cond_and(Item *i1,Item *i2) :Item_cond(i1,i2) {}
+ Item_cond_and(THD *thd, Item_cond_and &item) :Item_cond(thd, item) {}
enum Functype functype() const { return COND_AND_FUNC; }
longlong val_int();
const char *func_name() const { return "and"; }
+ Item* copy_andor_structure(THD *thd)
+ {
+ Item_cond_and *item;
+ if((item= new Item_cond_and(thd, *this)))
+ item->copy_andor_arguments(thd, this);
+ return item;
+ }
};
class Item_cond_or :public Item_cond
@@ -831,10 +850,18 @@ class Item_cond_or :public Item_cond
public:
Item_cond_or() :Item_cond() {}
Item_cond_or(Item *i1,Item *i2) :Item_cond(i1,i2) {}
+ Item_cond_or(THD *thd, Item_cond_or &item) :Item_cond(thd, item) {}
enum Functype functype() const { return COND_OR_FUNC; }
longlong val_int();
const char *func_name() const { return "or"; }
table_map not_null_tables() const { return and_tables_cache; }
+ Item* copy_andor_structure(THD *thd)
+ {
+ Item_cond_or *item;
+ if((item= new Item_cond_or(thd, *this)))
+ item->copy_andor_arguments(thd, this);
+ return item;
+ }
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e3e3c021a1e..b1173b9c7b8 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -52,13 +52,6 @@ Item *create_func_ord(Item* a)
return new Item_func_ord(a);
}
-Item *create_func_old_password(Item* a)
-{
- return new Item_func_old_password(a);
-}
-
-
-
Item *create_func_asin(Item* a)
{
return new Item_func_asin(a);
@@ -107,14 +100,6 @@ Item *create_func_cot(Item* a)
new Item_func_tan(a));
}
-
-#ifdef HAVE_COMPRESS
-Item *create_func_crc32(Item* a)
-{
- return new Item_func_crc32(a);
-}
-#endif
-
Item *create_func_date_format(Item* a,Item *b)
{
return new Item_func_date_format(a,b,0);
@@ -332,11 +317,6 @@ Item *create_func_quarter(Item* a)
return new Item_func_quarter(a);
}
-Item *create_func_password(Item* a)
-{
- return new Item_func_password(a);
-}
-
Item *create_func_radians(Item *a)
{
return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
@@ -666,13 +646,10 @@ Item *create_func_point(Item *a, Item *b)
return new Item_func_point(a, b);
}
-#if !defined(HAVE_COMPRESS)
-
-Item *create_func_compress (Item*a __attribute__((unused))){return 0;}
-Item *create_func_uncompress (Item*a __attribute__((unused))){return 0;}
-Item *create_func_uncompressed_length(Item*a __attribute__((unused))){return 0;}
-
-#else
+Item *create_func_crc32(Item* a)
+{
+ return new Item_func_crc32(a);
+}
Item *create_func_compress(Item* a)
{
@@ -689,8 +666,6 @@ Item *create_func_uncompressed_length(Item* a)
return new Item_func_uncompressed_length(a);
}
-#endif
-
Item *create_func_datediff(Item *a, Item *b)
{
return new Item_func_minus(new Item_func_to_days(a),
diff --git a/sql/item_create.h b/sql/item_create.h
index 16c4fccf709..c75f4404bad 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -33,9 +33,7 @@ Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
Item *create_func_cot(Item* a);
-#ifdef HAVE_COMPRESS
Item *create_func_crc32(Item* a);
-#endif
Item *create_func_date_format(Item* a,Item *b);
Item *create_func_dayname(Item* a);
Item *create_func_dayofmonth(Item* a);
@@ -69,14 +67,12 @@ Item *create_func_monthname(Item* a);
Item *create_func_nullif(Item* a, Item *b);
Item *create_func_oct(Item *);
Item *create_func_ord(Item* a);
-Item *create_func_old_password(Item* a);
Item *create_func_period_add(Item* a, Item *b);
Item *create_func_period_diff(Item* a, Item *b);
Item *create_func_pi(void);
Item *create_func_pow(Item* a, Item *b);
Item *create_func_current_user(void);
Item *create_func_quarter(Item* a);
-Item *create_func_password(Item* a);
Item *create_func_radians(Item *a);
Item *create_func_release_lock(Item* a);
Item *create_func_repeat(Item* a, Item *b);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 4bda8ae78cd..0f9ee512be1 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -27,22 +27,18 @@
#include <hash.h>
#include <time.h>
#include <ft_global.h>
-#ifdef HAVE_COMPRESS
-#include <zlib.h>
-#endif
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
const char *fname)
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
- c1.collation->name,c1.derivation_name(),
+ c1.collation->name,c1.derivation_name(),
c2.collation->name,c2.derivation_name(),
fname);
}
-
-static void my_coll_agg_error(DTCollation &c1,
+static void my_coll_agg_error(DTCollation &c1,
DTCollation &c2,
DTCollation &c3,
const char *fname)
@@ -134,6 +130,27 @@ Item_func::Item_func(List<Item> &list)
set_arguments(list);
}
+Item_func::Item_func(THD *thd, Item_func &item)
+ :Item_result_field(thd, item),
+ allowed_arg_cols(item.allowed_arg_cols),
+ arg_count(item.arg_count),
+ used_tables_cache(item.used_tables_cache),
+ not_null_tables_cache(item.not_null_tables_cache),
+ const_item_cache(item.const_item_cache)
+{
+ if (arg_count)
+ {
+ if (arg_count <=2)
+ args= tmp_arg;
+ else
+ {
+ if (!(args=(Item**) thd->alloc(sizeof(Item*)*arg_count)))
+ return;
+ }
+ memcpy((char*) args, (char*) item.args, sizeof(Item*)*arg_count);
+ }
+}
+
/*
Resolve references to table column for a function and it's argument
@@ -173,13 +190,15 @@ bool
Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
Item **arg,**arg_end;
+#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
char buff[STACK_BUFF_ALLOC]; // Max argument in function
+#endif
used_tables_cache= not_null_tables_cache= 0;
const_item_cache=1;
if (thd && check_stack_overrun(thd,buff))
- return 0; // Fatal error if flag is set!
+ return 1; // Fatal error if flag is set!
if (arg_count)
{ // Print purify happy
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
@@ -1085,36 +1104,6 @@ longlong Item_func_min_max::val_int()
return value;
}
-
-#ifdef HAVE_COMPRESS
-longlong Item_func_crc32::val_int()
-{
- String *res=args[0]->val_str(&value);
- if (!res)
- {
- null_value=1;
- return 0; /* purecov: inspected */
- }
- null_value=0;
- return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length());
-}
-
-
-longlong Item_func_uncompressed_length::val_int()
-{
- String *res= args[0]->val_str(&value);
- if (!res)
- {
- null_value=1;
- return 0; /* purecov: inspected */
- }
- null_value=0;
- if (res->is_empty()) return 0;
- return uint4korr(res->c_ptr()) & 0x3FFFFFFF;
-}
-#endif /* HAVE_COMPRESS */
-
-
longlong Item_func_length::val_int()
{
String *res=args[0]->val_str(&value);
@@ -1164,7 +1153,6 @@ longlong Item_func_locate::val_int()
{
String *a=args[0]->val_str(&value1);
String *b=args[1]->val_str(&value2);
- bool binary_cmp= (cmp_collation.collation->state & MY_CS_BINSORT) ? 1 : 0;
if (!a || !b)
{
null_value=1;
@@ -1172,55 +1160,27 @@ longlong Item_func_locate::val_int()
}
null_value=0;
uint start=0;
-#ifdef USE_MB
uint start0=0;
-#endif
+ my_match_t match;
+
if (arg_count == 3)
{
- start=(uint) args[2]->val_int()-1;
-#ifdef USE_MB
- if (use_mb(cmp_collation.collation))
- {
- start0=start;
- if (!binary_cmp)
- start=a->charpos(start);
- }
-#endif
+ start0= start =(uint) args[2]->val_int()-1;
+ start=a->charpos(start);
+
if (start > a->length() || start+b->length() > a->length())
return 0;
}
+
if (!b->length()) // Found empty string at start
return (longlong) (start+1);
-#ifdef USE_MB
- if (use_mb(cmp_collation.collation) && !binary_cmp)
- {
- const char *ptr=a->ptr()+start;
- const char *search=b->ptr();
- const char *strend = ptr+a->length();
- const char *end=strend-b->length()+1;
- const char *search_end=search+b->length();
- register uint32 l;
- while (ptr < end)
- {
- if (*ptr == *search)
- {
- register char *i,*j;
- i=(char*) ptr+1; j=(char*) search+1;
- while (j != search_end)
- if (*i++ != *j++) goto skipp;
- return (longlong) start0+1;
- }
- skipp:
- if ((l=my_ismbchar(cmp_collation.collation,ptr,strend)))
- ptr+=l;
- else ++ptr;
- ++start0;
- }
+
+ if (!cmp_collation.collation->coll->instr(cmp_collation.collation,
+ a->ptr()+start, a->length()-start,
+ b->ptr(), b->length(),
+ &match, 1))
return 0;
- }
-#endif /* USE_MB */
- return (longlong) (binary_cmp ? a->strstr(*b,start) :
- (a->strstr_case(*b,start)))+1;
+ return (longlong) match.mblen + start0 + 1;
}
@@ -1431,13 +1391,15 @@ bool
udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
uint arg_count, Item **arguments)
{
+#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
char buff[STACK_BUFF_ALLOC]; // Max argument in function
+#endif
DBUG_ENTER("Item_udf_func::fix_fields");
if (thd)
{
if (check_stack_overrun(thd,buff))
- return 0; // Fatal error flag is set!
+ DBUG_RETURN(1); // Fatal error flag is set!
}
else
thd=current_thd; // In WHERE / const clause
@@ -1751,7 +1713,7 @@ public:
pthread_cond_init(&cond,NULL);
if (key)
{
- if (hash_insert(&hash_user_locks,(byte*) this))
+ if (my_hash_insert(&hash_user_locks,(byte*) this))
{
my_free((gptr) key,MYF(0));
key=0;
@@ -2109,10 +2071,20 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->value=0;
entry->length=0;
entry->update_query_id=0;
+ /*
+ If we are here, we were called from a SET or a query which sets a
+ variable. Imagine it is this:
+ INSERT INTO t SELECT @a:=10, @a:=@a+1.
+ Then when we have a Item_func_get_user_var (because of the @a+1) so we
+ think we have to write the value of @a to the binlog. But before that,
+ we have a Item_func_set_user_var to create @a (@a:=10), in this we mark
+ the variable as "already logged" (line below) so that it won't be logged
+ by Item_func_get_user_var (because that's not necessary).
+ */
entry->used_query_id=current_thd->query_id;
entry->type=STRING_RESULT;
memcpy(entry->name.str, name.str, name.length+1);
- if (hash_insert(hash,(byte*) entry))
+ if (my_hash_insert(hash,(byte*) entry))
{
my_free((char*) entry,MYF(0));
return 0;
@@ -2121,7 +2093,10 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
return entry;
}
-
+/*
+ When a user variable is updated (in a SET command or a query like SELECT @a:=
+ ).
+*/
bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref)
@@ -2131,6 +2106,11 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
!(entry= get_variable(&thd->user_vars, name, 1)))
return 1;
entry->type= cached_result_type;
+ /*
+ Remember the last query which updated it, this way a query can later know
+ if this variable is a constant item in the query (it is if update_query_id
+ is different from query_id).
+ */
entry->update_query_id=thd->query_id;
return 0;
}
@@ -2353,53 +2333,92 @@ longlong Item_func_get_user_var::val_int()
}
+/*
+ When a user variable is invoked from an update query (INSERT, UPDATE etc),
+ stores this variable and its value in thd->user_var_events, so that it can be
+ written to the binlog (will be written just before the query is written, see
+ log.cc).
+*/
+
void Item_func_get_user_var::fix_length_and_dec()
{
- BINLOG_USER_VAR_EVENT *user_var_event;
THD *thd=current_thd;
+ BINLOG_USER_VAR_EVENT *user_var_event;
maybe_null=1;
decimals=NOT_FIXED_DEC;
max_length=MAX_BLOB_WIDTH;
- if ((var_entry= get_variable(&thd->user_vars, name, 0)))
+ var_entry= get_variable(&thd->user_vars, name, 0);
+
+ if (!(opt_bin_log && is_update_query(thd->lex.sql_command)))
+ return;
+
+ if (!var_entry)
{
- if (opt_bin_log && is_update_query(thd->lex.sql_command) &&
- var_entry->used_query_id != thd->query_id)
- {
- uint size;
- /*
- First we need to store value of var_entry, when the next situation
- appers:
- > set @a:=1;
- > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
- We have to write to binlog value @a= 1;
- */
- size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
- if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size)))
- goto err;
-
- user_var_event->value= (char*) user_var_event +
- ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
- user_var_event->user_var_event= var_entry;
- user_var_event->type= var_entry->type;
- user_var_event->charset_number= var_entry->collation.collation->number;
- if (!var_entry->value)
- {
- /* NULL value*/
- user_var_event->length= 0;
- user_var_event->value= 0;
- }
- else
- {
- user_var_event->length= var_entry->length;
- memcpy(user_var_event->value, var_entry->value,
- var_entry->length);
- }
- var_entry->used_query_id= thd->query_id;
- if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
- goto err;
- }
+ /*
+ If the variable does not exist, it's NULL, but we want to create it so
+ that it gets into the binlog (if it didn't, the slave could be
+ influenced by a variable of the same name previously set by another
+ thread).
+ We create it like if it had been explicitely set with SET before.
+ The 'new' mimicks what sql_yacc.yy does when 'SET @a=10;'.
+ sql_set_variables() is what is called from 'case SQLCOM_SET_OPTION'
+ in dispatch_command()). Instead of building a one-element list to pass to
+ sql_set_variables(), we could instead manually call check() and update();
+ this would save memory and time; but calling sql_set_variables() makes one
+ unique place to maintain (sql_set_variables()).
+ */
+
+ List<set_var_base> tmp_var_list;
+ tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name,
+ new Item_null())));
+ if (sql_set_variables(thd, &tmp_var_list)) /* this will create the variable */
+ goto err;
+ if (!(var_entry= get_variable(&thd->user_vars, name, 0)))
+ goto err;
+ }
+ /*
+ If this variable was already stored in user_var_events by this query
+ (because it's used in more than one place in the query), don't store
+ it.
+ */
+ else if (var_entry->used_query_id == thd->query_id)
+ return;
+
+ uint size;
+ /*
+ First we need to store value of var_entry, when the next situation
+ appers:
+ > set @a:=1;
+ > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
+ We have to write to binlog value @a= 1;
+ */
+ size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
+ if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size)))
+ goto err;
+
+ user_var_event->value= (char*) user_var_event +
+ ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
+ user_var_event->user_var_event= var_entry;
+ user_var_event->type= var_entry->type;
+ user_var_event->charset_number= var_entry->collation.collation->number;
+ if (!var_entry->value)
+ {
+ /* NULL value*/
+ user_var_event->length= 0;
+ user_var_event->value= 0;
}
+ else
+ {
+ user_var_event->length= var_entry->length;
+ memcpy(user_var_event->value, var_entry->value,
+ var_entry->length);
+ }
+ /* Mark that this variable has been used by this query */
+ var_entry->used_query_id= thd->query_id;
+ if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
+ goto err;
+
return;
err:
diff --git a/sql/item_func.h b/sql/item_func.h
index 7fedbcf48ee..86cf19d92f3 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -104,6 +104,8 @@ public:
}
}
Item_func(List<Item> &list);
+ // Constructor used for Item_cond_and/or (see Item comment)
+ Item_func(THD *thd, Item_func &item);
~Item_func() {} /* Nothing to do; Items are freed automaticly */
bool fix_fields(THD *,struct st_table_list *, Item **ref);
table_map used_tables() const;
@@ -196,6 +198,7 @@ public:
Item_int_func(Item *a,Item *b) :Item_func(a,b) { max_length=21; }
Item_int_func(Item *a,Item *b,Item *c) :Item_func(a,b,c) { max_length=21; }
Item_int_func(List<Item> &list) :Item_func(list) { max_length=21; }
+ Item_int_func(THD *thd, Item_int_func &item) :Item_func(thd, item) {}
double val() { return (double) val_int(); }
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
@@ -538,6 +541,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
+ table_map not_null_tables() const { return 0; }
};
class Item_func_min :public Item_func_min_max
@@ -555,27 +559,6 @@ public:
};
-#ifdef HAVE_COMPRESS
-class Item_func_crc32 :public Item_int_func
-{
- String value;
-public:
- Item_func_crc32(Item *a) :Item_int_func(a) {}
- longlong val_int();
- const char *func_name() const { return "crc32"; }
- void fix_length_and_dec() { max_length=10; }
-};
-class Item_func_uncompressed_length : public Item_int_func
-{
- String value;
-public:
- Item_func_uncompressed_length(Item *a):Item_int_func(a){}
- longlong val_int();
- const char *func_name() const{return "uncompressed_length";}
- void fix_length_and_dec() { max_length=10; }
-};
-#endif
-
class Item_func_length :public Item_int_func
{
String value;
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index d86914eb6c5..79e45cca26f 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -167,30 +167,6 @@ public:
const char *func_name() const { return "multipoint"; }
};
-#ifdef HAVE_COMPRESS
-
-class Item_func_compress: public Item_str_func
-{
- String buffer;
-public:
- Item_func_compress(Item *a):Item_str_func(a){}
- String *val_str(String *);
- void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;}
- const char *func_name() const{return "compress";}
-};
-
-class Item_func_uncompress: public Item_str_func
-{
- String buffer;
-public:
- Item_func_uncompress(Item *a): Item_str_func(a){}
- String *val_str(String *);
- void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;}
- const char *func_name() const{return "uncompress";}
-};
-
-#endif
-
/*
Spatial relations
*/
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index b0b9cc01bf1..86efde096c5 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -33,8 +33,9 @@
#include "md5.h"
#include "sha1.h"
#include "my_aes.h"
+#include "../mysys/my_static.h" // For soundex_map
-String empty_string("",default_charset_info);
+String my_empty_string("",default_charset_info);
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
{
@@ -359,7 +360,7 @@ String *Item_func_des_encrypt::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0;
if ((res_length=res->length()) == 0)
- return &empty_string;
+ return &my_empty_string;
if (arg_count == 1)
{
@@ -520,7 +521,7 @@ String *Item_func_concat_ws::val_str(String *str)
if ((res= args[i]->val_str(str)))
break;
if (i == arg_count)
- return &empty_string;
+ return &my_empty_string;
for (i++; i < arg_count ; i++)
{
@@ -661,7 +662,7 @@ String *Item_func_reverse::val_str(String *str)
return 0;
/* An empty string is a special case as the string pointer may be null */
if (!res->length())
- return &empty_string;
+ return &my_empty_string;
res=copy_if_not_alloced(str,res,res->length());
ptr = (char *) res->ptr();
end=ptr+res->length();
@@ -914,7 +915,7 @@ String *Item_func_left::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0;
if (length <= 0)
- return &empty_string;
+ return &my_empty_string;
length= res->charpos(length);
if (res->length() > (ulong) length)
{ // Safe even if const arg
@@ -958,7 +959,7 @@ String *Item_func_right::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
if (length <= 0)
- return &empty_string; /* purecov: inspected */
+ return &my_empty_string; /* purecov: inspected */
if (res->length() <= (uint) length)
return res; /* purecov: inspected */
@@ -991,7 +992,7 @@ String *Item_func_substr::val_str(String *str)
start=res->charpos(start);
length=res->charpos(length,start);
if (start < 0 || (uint) start+1 > res->length() || length <= 0)
- return &empty_string;
+ return &my_empty_string;
tmp_length=(int32) res->length()-start;
length=min(length,tmp_length);
@@ -1051,7 +1052,7 @@ String *Item_func_substr_index::val_str(String *str)
null_value=0;
uint delimeter_length=delimeter->length();
if (!res->length() || !delimeter_length || !count)
- return &empty_string; // Wrong parameters
+ return &my_empty_string; // Wrong parameters
res->set_charset(collation.collation);
@@ -1327,95 +1328,49 @@ void Item_func_trim::fix_length_and_dec()
}
-
-
-void Item_func_password::fix_length_and_dec()
-{
- /*
- If PASSWORD() was called with only one argument, it depends on a random
- number so we need to save this random number into the binary log.
- If called with two arguments, it is repeatable.
- */
- if (arg_count == 1)
- {
- THD *thd= current_thd;
- thd->rand_used= 1;
- thd->rand_saved_seed1= thd->rand.seed1;
- thd->rand_saved_seed2= thd->rand.seed2;
- }
- max_length= get_password_length(use_old_passwords);
-}
-
-/*
- Password() function has 2 arguments. Second argument can be used
- to make results repeatable
-*/
+/* Item_func_password */
String *Item_func_password::val_str(String *str)
{
- struct rand_struct rand_st; // local structure for 2 param version
- ulong seed=0; // seed to initialise random generator to
-
- String *res =args[0]->val_str(str);
+ String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
-
- if (arg_count == 1)
- {
- if (res->length() == 0)
- return &empty_string;
- make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
- &current_thd->rand);
- str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
- return str;
- }
- else
- {
- /* We'll need the buffer to get second parameter */
- char key_buff[80];
- String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
- String *key =args[1]->val_str(&tmp_key_value);
-
- /* Check second argument for NULL value. First one is already checked */
- if ((null_value=args[1]->null_value))
- return 0;
-
- /* This shall be done after checking for null for proper results */
- if (res->length() == 0)
- return &empty_string;
-
- /* Generate the seed first this allows to avoid double allocation */
- char* seed_ptr=key->c_ptr();
- while (*seed_ptr)
- {
- seed=(seed*211+*seed_ptr) & 0xffffffffL; /* Use simple hashing */
- seed_ptr++;
- }
-
- /* Use constants which allow nice random values even with small seed */
- randominit(&rand_st,
- (ulong) ((ulonglong) seed*111111+33333333L) & (ulong) 0xffffffff,
- (ulong) ((ulonglong) seed*1111+55555555L) & (ulong) 0xffffffff);
-
- make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
- &rand_st);
- str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
- return str;
- }
+ if (res->length() == 0)
+ return &my_empty_string;
+ make_scrambled_password(tmp_value, res->c_ptr());
+ str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset());
+ return str;
+}
+
+char *Item_func_password::alloc(THD *thd, const char *password)
+{
+ char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
+ if (buff)
+ make_scrambled_password(buff, password);
+ return buff;
}
+/* Item_func_old_password */
+
String *Item_func_old_password::val_str(String *str)
{
- String *res =args[0]->val_str(str);
+ String *res= args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
- return &empty_string;
- make_scrambled_password(tmp_value,res->c_ptr(),1,&current_thd->rand);
- str->set(tmp_value,16,res->charset());
+ return &my_empty_string;
+ make_scrambled_password_323(tmp_value, res->c_ptr());
+ str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset());
return str;
}
+char *Item_func_old_password::alloc(THD *thd, const char *password)
+{
+ char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
+ if (buff)
+ make_scrambled_password_323(buff, password);
+ return buff;
+}
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
@@ -1429,7 +1384,7 @@ String *Item_func_encrypt::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
- return &empty_string;
+ return &my_empty_string;
if (arg_count == 1)
{ // generate random salt
@@ -1500,8 +1455,8 @@ String *Item_func_database::val_str(String *str)
THD *thd= current_thd;
if (!thd->db)
{
- str->length(0);
- str->set_charset(system_charset_info);
+ null_value= 1;
+ return 0;
}
else
str->copy((const char*) thd->db,(uint) strlen(thd->db),system_charset_info);
@@ -1519,7 +1474,7 @@ String *Item_func_user::val_str(String *str)
// For system threads (e.g. replication SQL thread) user may be empty
if (!thd->user)
- return &empty_string;
+ return &my_empty_string;
res_length= (strlen(thd->user)+strlen(host)+2) * cs->mbmaxlen;
if (str->alloc(res_length))
@@ -1542,15 +1497,11 @@ void Item_func_soundex::fix_length_and_dec()
}
- /*
- If alpha, map input letter to soundex code.
- If not alpha and remove_garbage is set then skip to next char
- else return 0
- */
-
-extern "C" {
-extern const char *soundex_map; // In mysys/static.c
-}
+/*
+ If alpha, map input letter to soundex code.
+ If not alpha and remove_garbage is set then skip to next char
+ else return 0
+*/
static char get_scode(CHARSET_INFO *cs,char *ptr)
{
@@ -1582,7 +1533,7 @@ String *Item_func_soundex::val_str(String *str)
while (from != end && my_isspace(cs,*from)) // Skip pre-space
from++; /* purecov: inspected */
if (from == end)
- return &empty_string; // No alpha characters.
+ return &my_empty_string; // No alpha characters.
*to++ = my_toupper(cs,*from); // Copy first letter
last_ch = get_scode(cs,from); // code of the first letter
// for the first 'double-letter check.
@@ -1764,7 +1715,7 @@ String *Item_func_make_set::val_str(String *str)
ulonglong bits;
bool first_found=0;
Item **ptr=args;
- String *result=&empty_string;
+ String *result=&my_empty_string;
bits=item->val_int();
if ((null_value=item->null_value))
@@ -1788,7 +1739,7 @@ String *Item_func_make_set::val_str(String *str)
else
{
if (tmp_str.copy(*res)) // Don't use 'str'
- return &empty_string;
+ return &my_empty_string;
result= &tmp_str;
}
}
@@ -1798,11 +1749,11 @@ String *Item_func_make_set::val_str(String *str)
{ // Copy data to tmp_str
if (tmp_str.alloc(result->length()+res->length()+1) ||
tmp_str.copy(*result))
- return &empty_string;
+ return &my_empty_string;
result= &tmp_str;
}
if (tmp_str.append(',') || tmp_str.append(*res))
- return &empty_string;
+ return &my_empty_string;
}
}
}
@@ -1899,7 +1850,7 @@ String *Item_func_repeat::val_str(String *str)
goto err; // string and/or delim are null
null_value=0;
if (count <= 0) // For nicer SQL code
- return &empty_string;
+ return &my_empty_string;
if (count == 1) // To avoid reallocs
return res;
length=res->length();
@@ -1934,7 +1885,7 @@ void Item_func_rpad::fix_length_and_dec()
if (args[1]->const_item())
{
- uint32 length= (uint32) args[1]->val_int();
+ uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen;
max_length=max(args[0]->max_length,length);
if (max_length >= MAX_BLOB_WIDTH)
{
@@ -1952,36 +1903,46 @@ void Item_func_rpad::fix_length_and_dec()
String *Item_func_rpad::val_str(String *str)
{
- uint32 res_length,length_pad;
+ uint32 res_byte_length,res_char_length,pad_char_length,pad_byte_length;
char *to;
const char *ptr_pad;
int32 count= (int32) args[1]->val_int();
+ int32 byte_count= count * collation.collation->mbmaxlen;
String *res =args[0]->val_str(str);
String *rpad = args[2]->val_str(str);
if (!res || args[1]->null_value || !rpad || count < 0)
goto err;
null_value=0;
- if (count <= (int32) (res_length=res->length()))
+ if (count <= (int32) (res_char_length=res->numchars()))
{ // String to pad is big enough
- res->length(count); // Shorten result if longer
+ res->length(res->charpos(count)); // Shorten result if longer
return (res);
}
- length_pad= rpad->length();
- if ((ulong) count > current_thd->variables.max_allowed_packet ||
- args[2]->null_value || !length_pad)
+ pad_char_length= rpad->numchars();
+ if ((ulong) byte_count > current_thd->variables.max_allowed_packet ||
+ args[2]->null_value || !pad_char_length)
goto err;
- if (!(res= alloc_buffer(res,str,&tmp_value,count)))
+ res_byte_length= res->length(); /* Must be done before alloc_buffer */
+ if (!(res= alloc_buffer(res,str,&tmp_value,byte_count)))
goto err;
- to= (char*) res->ptr()+res_length;
+ to= (char*) res->ptr()+res_byte_length;
ptr_pad=rpad->ptr();
- for (count-= res_length; (uint32) count > length_pad; count-= length_pad)
+ pad_byte_length= rpad->length();
+ count-= res_char_length;
+ for ( ; (uint32) count > pad_char_length; count-= pad_char_length)
{
- memcpy(to,ptr_pad,length_pad);
- to+= length_pad;
+ memcpy(to,ptr_pad,pad_byte_length);
+ to+= pad_byte_length;
}
- memcpy(to,ptr_pad,(size_t) count);
+ if (count)
+ {
+ pad_byte_length= rpad->charpos(count);
+ memcpy(to,ptr_pad,(size_t) pad_byte_length);
+ to+= pad_byte_length;
+ }
+ res->length(to- (char*) res->ptr());
return (res);
err:
@@ -2000,7 +1961,7 @@ void Item_func_lpad::fix_length_and_dec()
if (args[1]->const_item())
{
- uint32 length= (uint32) args[1]->val_int();
+ uint32 length= (uint32) args[1]->val_int() * collation.collation->mbmaxlen;
max_length=max(args[0]->max_length,length);
if (max_length >= MAX_BLOB_WIDTH)
{
@@ -2018,57 +1979,52 @@ void Item_func_lpad::fix_length_and_dec()
String *Item_func_lpad::val_str(String *str)
{
- uint32 res_length,length_pad;
- char *to;
- const char *ptr_pad;
- ulong count= (long) args[1]->val_int();
- String *res= args[0]->val_str(str);
- String *lpad= args[2]->val_str(str);
+ uint32 res_byte_length,res_char_length,pad_byte_length,pad_char_length;
+ ulong count= (long) args[1]->val_int(), byte_count;
+ String a1,a3;
+ String *res= args[0]->val_str(&a1);
+ String *pad= args[2]->val_str(&a3);
- if (!res || args[1]->null_value || !lpad)
+ if (!res || args[1]->null_value || !pad)
goto err;
+
null_value=0;
- if (count <= (res_length=res->length()))
- { // String to pad is big enough
- res->length(count); // Shorten result if longer
- return (res);
+ res_byte_length= res->length();
+ res_char_length= res->numchars();
+
+ if (count <= res_char_length)
+ {
+ res->length(res->charpos(count));
+ return res;
}
- length_pad= lpad->length();
- if (count > current_thd->variables.max_allowed_packet ||
- args[2]->null_value || !length_pad)
+
+ pad_byte_length= pad->length();
+ pad_char_length= pad->numchars();
+ byte_count= count * collation.collation->mbmaxlen;
+
+ if (byte_count > current_thd->variables.max_allowed_packet ||
+ args[2]->null_value || !pad_char_length || str->alloc(byte_count))
goto err;
-
- if (res->alloced_length() < count)
+
+ str->length(0);
+ str->set_charset(collation.collation);
+ count-= res_char_length;
+ while (count >= pad_char_length)
{
- if (str->alloced_length() >= count)
- {
- memcpy((char*) str->ptr()+(count-res_length),res->ptr(),res_length);
- res=str;
- }
- else
- {
- if (tmp_value.alloc(count))
- goto err;
- memcpy((char*) tmp_value.ptr()+(count-res_length),res->ptr(),res_length);
- res=&tmp_value;
- }
+ str->append(*pad);
+ count-= pad_char_length;
}
- else
- bmove_upp((char*) res->ptr()+count,res->ptr()+res_length,res_length);
- res->length(count);
-
- to= (char*) res->ptr();
- ptr_pad= lpad->ptr();
- for (count-= res_length; count > length_pad; count-= length_pad)
+ if (count > 0)
{
- memcpy(to,ptr_pad,length_pad);
- to+= length_pad;
+ pad->length(pad->charpos(count));
+ str->append(*pad);
}
- memcpy(to,ptr_pad,(size_t) count);
- return (res);
+ str->append(*res);
+ null_value= 0;
+ return str;
- err:
- null_value=1;
+err:
+ null_value= 1;
return 0;
}
@@ -2096,7 +2052,7 @@ String *Item_func_conv::val_str(String *str)
dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),from_base,&endptr,&err);
ptr= longlong2str(dec,ans,to_base);
if (str->copy(ans,(uint32) (ptr-ans), default_charset()))
- return &empty_string;
+ return &my_empty_string;
return str;
}
@@ -2286,7 +2242,7 @@ String *Item_func_hex::val_str(String *str)
return 0;
ptr= longlong2str(dec,ans,16);
if (str->copy(ans,(uint32) (ptr-ans),default_charset()))
- return &empty_string; // End of memory
+ return &my_empty_string; // End of memory
return str;
}
@@ -2323,7 +2279,9 @@ String *Item_load_file::val_str(String *str)
DBUG_ENTER("load_file");
if (!(file_name= args[0]->val_str(str)) ||
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
!(current_thd->master_access & FILE_ACL) ||
+#endif
!my_stat(file_name->c_ptr(), &stat_info, MYF(MY_WME)))
goto err;
if (!(stat_info.st_mode & S_IROTH))
@@ -2554,12 +2512,42 @@ null:
return 0;
}
+longlong Item_func_uncompressed_length::val_int()
+{
+ String *res= args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ if (res->is_empty()) return 0;
+ return uint4korr(res->c_ptr()) & 0x3FFFFFFF;
+}
+
+longlong Item_func_crc32::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ return (longlong) crc32(0L, (uchar*)res->ptr(), res->length());
+}
+
#ifdef HAVE_COMPRESS
#include "zlib.h"
String *Item_func_compress::val_str(String *str)
{
String *res= args[0]->val_str(str);
+ if (!res)
+ {
+ null_value= 1;
+ return 0;
+ }
if (res->is_empty()) return res;
int err= Z_OK;
@@ -2581,7 +2569,7 @@ String *Item_func_compress::val_str(String *str)
buffer.realloc((uint32)new_size + 4 + 1);
Byte *body= ((Byte*)buffer.c_ptr()) + 4;
-
+
if ((err= compress(body, &new_size,
(const Bytef*)res->c_ptr(), res->length())) != Z_OK)
{
@@ -2603,19 +2591,24 @@ String *Item_func_compress::val_str(String *str)
}
buffer.length((uint32)new_size + 4);
-
+
return &buffer;
}
String *Item_func_uncompress::val_str(String *str)
{
String *res= args[0]->val_str(str);
+ if (!res)
+ {
+ null_value= 1;
+ return 0;
+ }
if (res->is_empty()) return res;
ulong new_size= uint4korr(res->c_ptr()) & 0x3FFFFFFF;
int err= Z_OK;
uint code;
-
+
if (new_size > MAX_BLOB_WIDTH)
{
push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,
@@ -2624,21 +2617,20 @@ String *Item_func_uncompress::val_str(String *str)
null_value= 0;
return 0;
}
-
+
buffer.realloc((uint32)new_size);
-
- if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size,
+
+ if ((err= uncompress((Byte*)buffer.c_ptr(), &new_size,
((const Bytef*)res->c_ptr())+4,res->length())) == Z_OK)
{
buffer.length((uint32)new_size);
return &buffer;
}
-
- code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR :
+
+ code= err==Z_BUF_ERROR ? ER_ZLIB_Z_BUF_ERROR :
err==Z_MEM_ERROR ? ER_ZLIB_Z_MEM_ERROR : ER_ZLIB_Z_DATA_ERROR;
push_warning(current_thd,MYSQL_ERROR::WARN_LEVEL_ERROR,code,ER(code));
null_value= 1;
return 0;
}
-
#endif
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index f64a145b136..b82dacb4fe0 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -254,30 +254,45 @@ public:
};
+/*
+ Item_func_password -- new (4.1.1) PASSWORD() function implementation.
+ Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new
+ password format, sha1(sha1(password) is so-called hash_stage2 value.
+ Length of returned string is always 41 byte. To find out how entire
+ authentification procedure works, see comments in password.c.
+*/
+
class Item_func_password :public Item_str_func
{
- char tmp_value[64]; /* This should be enough for new password format */
+ char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
public:
Item_func_password(Item *a) :Item_str_func(a) {}
- Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {}
- String *val_str(String *);
- void fix_length_and_dec();
+ String *val_str(String *str);
+ void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }
const char *func_name() const { return "password"; }
+ static char *alloc(THD *thd, const char *password);
};
+/*
+ Item_func_old_password -- PASSWORD() implementation used in MySQL 3.21 - 4.0
+ compatibility mode. This item is created in sql_yacc.yy when
+ 'old_passwords' session variable is set, and to handle OLD_PASSWORD()
+ function.
+*/
+
class Item_func_old_password :public Item_str_func
{
- char tmp_value[17]; /* old password length +1 */
+ char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1];
public:
Item_func_old_password(Item *a) :Item_str_func(a) {}
- String *val_str(String *);
- void fix_length_and_dec() { max_length = get_password_length(1); }
+ String *val_str(String *str);
+ void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; }
const char *func_name() const { return "old_password"; }
+ static char *alloc(THD *thd, const char *password);
};
-
class Item_func_des_encrypt :public Item_str_func
{
String tmp_value;
@@ -624,9 +639,56 @@ public:
Item_func_collation(Item *a) :Item_str_func(a) {}
String *val_str(String *);
const char *func_name() const { return "collation"; }
- void fix_length_and_dec()
+ void fix_length_and_dec()
{
max_length=40; // should be enough
collation.set(system_charset_info);
};
};
+
+class Item_func_crc32 :public Item_int_func
+{
+ String value;
+public:
+ Item_func_crc32(Item *a) :Item_int_func(a) {}
+ const char *func_name() const { return "crc32"; }
+ void fix_length_and_dec() { max_length=10; }
+ longlong val_int();
+};
+
+class Item_func_uncompressed_length : public Item_int_func
+{
+ String value;
+public:
+ Item_func_uncompressed_length(Item *a):Item_int_func(a){}
+ const char *func_name() const{return "uncompressed_length";}
+ void fix_length_and_dec() { max_length=10; }
+ longlong val_int();
+};
+
+#ifdef HAVE_COMPRESS
+#define ZLIB_DEPENDED_FUNCTION ;
+#else
+#define ZLIB_DEPENDED_FUNCTION { null_value=1; return 0; }
+#endif
+
+class Item_func_compress: public Item_str_func
+{
+ String buffer;
+public:
+ Item_func_compress(Item *a):Item_str_func(a){}
+ void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;}
+ const char *func_name() const{return "compress";}
+ String *val_str(String *) ZLIB_DEPENDED_FUNCTION
+};
+
+class Item_func_uncompress: public Item_str_func
+{
+ String buffer;
+public:
+ Item_func_uncompress(Item *a): Item_str_func(a){}
+ void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;}
+ const char *func_name() const{return "uncompress";}
+ String *val_str(String *) ZLIB_DEPENDED_FUNCTION
+};
+
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 5c36ad42f98..324b745778a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -72,7 +72,7 @@ Item_subselect::trans_res
Item_subselect::select_transformer(JOIN *join)
{
DBUG_ENTER("Item_subselect::select_transformer");
- DBUG_RETURN(OK);
+ DBUG_RETURN(RES_OK);
}
@@ -227,14 +227,14 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
cond= join->having;
else
if (!(cond= new Item_cond_and(join->conds, join->having)))
- return ERROR;
+ return RES_ERROR;
if (!(substitution= new Item_func_if(cond, substitution,
new Item_null())))
- return ERROR;
+ return RES_ERROR;
}
- return REDUCE;
+ return RES_REDUCE;
}
- return OK;
+ return RES_OK;
}
void Item_singlerow_subselect::store(uint i, Item *item)
@@ -582,7 +582,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
thd->lex.current_select= current;
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
thd->lex.current_select= current;
@@ -602,7 +602,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (select_lex->item_list.elements > 1)
{
my_error(ER_CARDINALITY_COL, MYF(0), 1);
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
item= (Item*) select_lex->item_list.head();
@@ -620,7 +620,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
select_lex->having_fix_field= 0;
}
@@ -644,15 +644,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
select_lex->having_fix_field= 0;
item= new Item_cond_or(item,
new Item_func_isnull(isnull));
}
+ item->name= (char *)in_additional_cond;
join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd, join->tables_list, &join->conds))
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
else
{
@@ -666,7 +667,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
select_lex->having_fix_field= 0;
}
@@ -684,11 +685,11 @@ Item_in_subselect::single_value_transformer(JOIN *join,
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
- DBUG_RETURN(REDUCE);
+ DBUG_RETURN(RES_REDUCE);
}
}
}
- DBUG_RETURN(OK);
+ DBUG_RETURN(RES_OK);
}
Item_subselect::trans_res
@@ -714,7 +715,7 @@ Item_in_subselect::row_value_transformer(JOIN *join,
if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{
thd->lex.current_select= current;
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
thd->lex.current_select= current;
@@ -753,7 +754,7 @@ Item_in_subselect::row_value_transformer(JOIN *join,
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
select_lex->having_fix_field= 0;
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
select_lex->having_fix_field= 0;
}
@@ -761,9 +762,9 @@ Item_in_subselect::row_value_transformer(JOIN *join,
{
join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd, join->tables_list, &join->having))
- DBUG_RETURN(ERROR);
+ DBUG_RETURN(RES_ERROR);
}
- DBUG_RETURN(OK);
+ DBUG_RETURN(RES_OK);
}
Item_subselect::trans_res
@@ -847,7 +848,7 @@ int subselect_union_engine::prepare()
return unit->prepare(thd, result, 0);
}
-int subselect_simplein_engine::prepare()
+int subselect_uniquesubquery_engine::prepare()
{
//this never should be called
DBUG_ASSERT(0);
@@ -921,7 +922,7 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
SELECT_LEX *sl= unit->first_select();
bool fake= 0;
res_type= set_row(sl, item, row, &fake);
- for (sl= sl->next_select(); sl; sl->next_select())
+ for (sl= sl->next_select(); sl; sl= sl->next_select())
{
List_iterator_fast<Item> li(sl->item_list);
Item *sel_item;
@@ -934,7 +935,7 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row)
}
}
-void subselect_simplein_engine::fix_length_and_dec(Item_cache **row)
+void subselect_uniquesubquery_engine::fix_length_and_dec(Item_cache **row)
{
//this never should be called
DBUG_ASSERT(0);
@@ -993,9 +994,9 @@ int subselect_union_engine::exec()
return res;
}
-int subselect_simplein_engine::exec()
+int subselect_uniquesubquery_engine::exec()
{
- DBUG_ENTER("subselect_simplein_engine::exec");
+ DBUG_ENTER("subselect_uniquesubquery_engine::exec");
int error;
TABLE *table= tab->table;
if ((tab->ref.key_err= (*tab->ref.key_copy)->copy()))
@@ -1023,9 +1024,9 @@ int subselect_simplein_engine::exec()
DBUG_RETURN(end_exec(table) || (error != 0));
}
-int subselect_simplein_engine::end_exec(TABLE *table)
+int subselect_uniquesubquery_engine::end_exec(TABLE *table)
{
- DBUG_ENTER("subselect_simplein_engine::end_exec");
+ DBUG_ENTER("subselect_uniquesubquery_engine::end_exec");
int error=0, tmp;
if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE)))
{
@@ -1042,10 +1043,11 @@ int subselect_simplein_engine::end_exec(TABLE *table)
DBUG_RETURN(error != 0);
}
-int subselect_indexin_engine::exec()
+int subselect_indexsubquery_engine::exec()
{
- DBUG_ENTER("subselect_indexin_engine::exec");
+ DBUG_ENTER("subselect_indexsubselect_engine::exec");
int error;
+ bool null_finding= 0;
TABLE *table= tab->table;
((Item_in_subselect *) item)->value= 0;
@@ -1077,29 +1079,30 @@ int subselect_indexin_engine::exec()
{
if (!cond || cond->val_int())
{
- if (check_null && *tab->null_ref_key)
+ if (null_finding)
((Item_in_subselect *) item)->was_null= 1;
else
((Item_in_subselect *) item)->value= 1;
goto finish;
}
+ error= table->file->index_next_same(table->record[0],
+ tab->ref.key_buff,
+ tab->ref.key_length);
+ if (error && error != HA_ERR_END_OF_FILE)
+ {
+ error= report_error(table, error);
+ goto finish;
+ }
}
else
{
- if (!check_null || *tab->null_ref_key)
+ if (!check_null || null_finding)
goto finish;
*tab->null_ref_key= 1;
+ null_finding= 1;
if (safe_index_read(tab))
goto finish;
}
- error= table->file->index_next_same(table->record[0],
- tab->ref.key_buff,
- tab->ref.key_length);
- if (error && error != HA_ERR_KEY_NOT_FOUND)
- {
- error= report_error(table, error);
- goto finish;
- }
}
}
}
@@ -1147,7 +1150,7 @@ void subselect_union_engine::exclude()
unit->exclude_level();
}
-void subselect_simplein_engine::exclude()
+void subselect_uniquesubquery_engine::exclude()
{
//this never should be called
DBUG_ASSERT(0);
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 9e4c5485405..1b5b9e9bd38 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -51,7 +51,7 @@ public:
/* changed engine indicator */
bool engine_changed;
- enum trans_res {OK, REDUCE, ERROR};
+ enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
EXISTS_SUBS, IN_SUBS, ALL_SUBS, ANY_SUBS};
@@ -193,8 +193,8 @@ public:
void fix_length_and_dec();
friend class select_exists_subselect;
- friend class subselect_simplein_engine;
- friend class subselect_indexin_engine;
+ friend class subselect_uniquesubquery_engine;
+ friend class subselect_indexsubquery_engine;
};
/* IN subselect */
@@ -240,7 +240,7 @@ public:
friend class Item_ref_null_helper;
friend class Item_is_not_null_test;
- friend class subselect_indexin_engine;
+ friend class subselect_indexsubquery_engine;
};
/* ALL/ANY/SOME subselect */
@@ -327,15 +327,15 @@ public:
};
struct st_join_table;
-class subselect_simplein_engine: public subselect_engine
+class subselect_uniquesubquery_engine: public subselect_engine
{
protected:
st_join_table *tab;
Item *cond;
public:
- subselect_simplein_engine(THD *thd, st_join_table *tab_arg,
- Item_subselect *subs, Item *where)
+ subselect_uniquesubquery_engine(THD *thd, st_join_table *tab_arg,
+ Item_subselect *subs, Item *where)
:subselect_engine(thd, subs, 0), tab(tab_arg), cond(where)
{}
@@ -349,14 +349,14 @@ public:
static int end_exec(TABLE *table);
};
-class subselect_indexin_engine: public subselect_simplein_engine
+class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{
bool check_null;
public:
- subselect_indexin_engine(THD *thd, st_join_table *tab_arg,
- Item_subselect *subs, Item *where,
- bool chk_null)
- :subselect_simplein_engine(thd, tab_arg, subs, where),
+ subselect_indexsubquery_engine(THD *thd, st_join_table *tab_arg,
+ Item_subselect *subs, Item *where,
+ bool chk_null)
+ :subselect_uniquesubquery_engine(thd, tab_arg, subs, where),
check_null(chk_null)
{}
int exec();
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b029bcf2b87..967abbc5ab8 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -70,6 +70,8 @@ void Item_sum::make_field(Send_field *tmp_field)
tmp_field->db_name=(char*)"";
tmp_field->org_table_name=tmp_field->table_name=(char*)"";
tmp_field->org_col_name=tmp_field->col_name=name;
+ if (maybe_null)
+ tmp_field->flags&= ~NOT_NULL_FLAG;
}
else
init_make_field(tmp_field, field_type());
@@ -212,7 +214,8 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
max_length=item->max_length;
}
decimals=item->decimals;
- maybe_null=item->maybe_null;
+ /* MIN/MAX can return NULL for empty set indepedent of the used column */
+ maybe_null= 1;
unsigned_flag=item->unsigned_flag;
collation.set(item->collation);
result_field=0;
@@ -238,10 +241,9 @@ Item *Item_sum_sum::copy_or_same(THD* thd)
}
-bool Item_sum_sum::reset()
+void Item_sum_sum::clear()
{
null_value=1; sum=0.0;
- return Item_sum_sum::add();
}
@@ -266,10 +268,9 @@ Item *Item_sum_count::copy_or_same(THD* thd)
}
-bool Item_sum_count::reset()
+void Item_sum_count::clear()
{
- count=0;
- return add();
+ count= 0;
}
@@ -301,10 +302,9 @@ Item *Item_sum_avg::copy_or_same(THD* thd)
}
-bool Item_sum_avg::reset()
+void Item_sum_avg::clear()
{
sum=0.0; count=0;
- return Item_sum_avg::add();
}
@@ -357,11 +357,10 @@ Item *Item_sum_variance::copy_or_same(THD* thd)
}
-bool Item_sum_variance::reset()
+void Item_sum_variance::clear()
{
sum=sum_sqr=0.0;
count=0;
- return Item_sum_variance::add();
}
bool Item_sum_variance::add()
@@ -407,15 +406,15 @@ void Item_sum_variance::reset_field()
}
}
-void Item_sum_variance::update_field(int offset)
+void Item_sum_variance::update_field()
{
double nr,old_nr,old_sqr;
longlong field_count;
char *res=result_field->ptr;
- float8get(old_nr,res+offset);
- float8get(old_sqr,res+offset+sizeof(double));
- field_count=sint8korr(res+offset+sizeof(double)*2);
+ float8get(old_nr, res);
+ float8get(old_sqr, res+sizeof(double));
+ field_count=sint8korr(res+sizeof(double)*2);
nr=args[0]->val();
if (!args[0]->null_value)
@@ -607,10 +606,9 @@ longlong Item_sum_bit::val_int()
}
-bool Item_sum_bit::reset()
+void Item_sum_bit::clear()
{
- bits=reset_bits;
- return add();
+ bits= reset_bits;
}
Item *Item_sum_or::copy_or_same(THD* thd)
@@ -773,12 +771,12 @@ void Item_sum_bit::reset_field()
** calc next value and merge it with field_value
*/
-void Item_sum_sum::update_field(int offset)
+void Item_sum_sum::update_field()
{
double old_nr,nr;
char *res=result_field->ptr;
- float8get(old_nr,res+offset);
+ float8get(old_nr,res);
nr=args[0]->val();
if (!args[0]->null_value)
{
@@ -789,12 +787,12 @@ void Item_sum_sum::update_field(int offset)
}
-void Item_sum_count::update_field(int offset)
+void Item_sum_count::update_field()
{
longlong nr;
char *res=result_field->ptr;
- nr=sint8korr(res+offset);
+ nr=sint8korr(res);
if (!args[0]->maybe_null)
nr++;
else
@@ -807,14 +805,14 @@ void Item_sum_count::update_field(int offset)
}
-void Item_sum_avg::update_field(int offset)
+void Item_sum_avg::update_field()
{
double nr,old_nr;
longlong field_count;
char *res=result_field->ptr;
- float8get(old_nr,res+offset);
- field_count=sint8korr(res+offset+sizeof(double));
+ float8get(old_nr,res);
+ field_count=sint8korr(res+sizeof(double));
nr=args[0]->val();
if (!args[0]->null_value)
@@ -827,77 +825,65 @@ void Item_sum_avg::update_field(int offset)
int8store(res,field_count);
}
-void Item_sum_hybrid::update_field(int offset)
+void Item_sum_hybrid::update_field()
{
if (hybrid_type == STRING_RESULT)
- min_max_update_str_field(offset);
+ min_max_update_str_field();
else if (hybrid_type == INT_RESULT)
- min_max_update_int_field(offset);
+ min_max_update_int_field();
else
- min_max_update_real_field(offset);
+ min_max_update_real_field();
}
void
-Item_sum_hybrid::min_max_update_str_field(int offset)
+Item_sum_hybrid::min_max_update_str_field()
{
String *res_str=args[0]->val_str(&value);
- if (args[0]->null_value)
- result_field->copy_from_tmp(offset); // Use old value
- else
+ if (!args[0]->null_value)
{
res_str->strip_sp();
- result_field->ptr+=offset; // Get old max/min
result_field->val_str(&tmp_value,&tmp_value);
- result_field->ptr-=offset;
if (result_field->is_null() ||
(cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0)
result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
- else
- { // Use old value
- char *res=result_field->ptr;
- memcpy(res,res+offset,result_field->pack_length());
- }
result_field->set_notnull();
}
}
void
-Item_sum_hybrid::min_max_update_real_field(int offset)
+Item_sum_hybrid::min_max_update_real_field()
{
double nr,old_nr;
- result_field->ptr+=offset;
old_nr=result_field->val_real();
nr=args[0]->val();
if (!args[0]->null_value)
{
- if (result_field->is_null(offset) ||
+ if (result_field->is_null(0) ||
(cmp_sign > 0 ? old_nr > nr : old_nr < nr))
old_nr=nr;
result_field->set_notnull();
}
- else if (result_field->is_null(offset))
+ else if (result_field->is_null(0))
result_field->set_null();
- result_field->ptr-=offset;
result_field->store(old_nr);
}
void
-Item_sum_hybrid::min_max_update_int_field(int offset)
+Item_sum_hybrid::min_max_update_int_field()
{
longlong nr,old_nr;
- result_field->ptr+=offset;
old_nr=result_field->val_int();
nr=args[0]->val_int();
if (!args[0]->null_value)
{
- if (result_field->is_null(offset))
+ if (result_field->is_null(0))
old_nr=nr;
else
{
@@ -910,30 +896,29 @@ Item_sum_hybrid::min_max_update_int_field(int offset)
}
result_field->set_notnull();
}
- else if (result_field->is_null(offset))
+ else if (result_field->is_null(0))
result_field->set_null();
- result_field->ptr-=offset;
result_field->store(old_nr);
}
-void Item_sum_or::update_field(int offset)
+void Item_sum_or::update_field()
{
ulonglong nr;
char *res=result_field->ptr;
- nr=uint8korr(res+offset);
+ nr=uint8korr(res);
nr|= (ulonglong) args[0]->val_int();
int8store(res,nr);
}
-void Item_sum_and::update_field(int offset)
+void Item_sum_and::update_field()
{
ulonglong nr;
char *res=result_field->ptr;
- nr=uint8korr(res+offset);
+ nr=uint8korr(res);
nr&= (ulonglong) args[0]->val_int();
int8store(res,nr);
}
@@ -1295,7 +1280,7 @@ Item *Item_sum_count_distinct::copy_or_same(THD* thd)
}
-bool Item_sum_count_distinct::reset()
+void Item_sum_count_distinct::clear()
{
if (use_tree)
reset_tree(tree);
@@ -1305,7 +1290,6 @@ bool Item_sum_count_distinct::reset()
table->file->delete_all_rows();
table->file->extra(HA_EXTRA_WRITE_CACHE);
}
- return add();
}
bool Item_sum_count_distinct::add()
@@ -1368,11 +1352,11 @@ longlong Item_sum_count_distinct::val_int()
#ifdef HAVE_DLOPEN
-bool Item_udf_sum::reset()
+void Item_udf_sum::clear()
{
- DBUG_ENTER("Item_udf_sum::reset");
- udf.reset(&null_value);
- DBUG_RETURN(0);
+ DBUG_ENTER("Item_udf_sum::clear");
+ udf.clear();
+ DBUG_VOID_RETURN;
}
bool Item_udf_sum::add()
@@ -1481,7 +1465,7 @@ int group_concat_key_cmp_with_distinct(void* arg, byte* key1,
for (uint i= 0; i < item->arg_count_field; i++)
{
Item *field_item= item->args[i];
- Field *field= field_item->tmp_table_field();
+ Field *field= field_item->real_item()->get_tmp_table_field();
if (field)
{
uint offset= field->abs_offset;
@@ -1512,7 +1496,7 @@ int group_concat_key_cmp_with_order(void* arg, byte* key1, byte* key2)
{
ORDER *order_item= item->order[i];
Item *item= *order_item->item;
- Field *field= item->tmp_table_field();
+ Field *field= item->real_item()->get_tmp_table_field();
if (field)
{
uint offset= field->abs_offset;
@@ -1563,7 +1547,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)),
Item *show_item= group_concat_item->args[i];
if (!show_item->const_item())
{
- Field *f= show_item->tmp_table_field();
+ Field *f= show_item->real_item()->get_tmp_table_field();
char *sv= f->ptr;
f->ptr= (char *)key + f->abs_offset;
String *res= f->val_str(&tmp,&tmp2);
@@ -1700,7 +1684,7 @@ Item *Item_func_group_concat::copy_or_same(THD* thd)
}
-bool Item_func_group_concat::reset()
+void Item_func_group_concat::clear()
{
result.length(0);
result.copy();
@@ -1714,7 +1698,6 @@ bool Item_func_group_concat::reset()
}
if (tree_mode)
reset_tree(tree);
- return add();
}
@@ -1731,7 +1714,7 @@ bool Item_func_group_concat::add()
Item *show_item= args[i];
if (!show_item->const_item())
{
- Field *f= show_item->tmp_table_field();
+ Field *f= show_item->real_item()->get_tmp_table_field();
if (!f->is_null())
{
record_is_null= FALSE;
@@ -1953,6 +1936,3 @@ String* Item_func_group_concat::val_str(String* str)
}
return &result;
}
-
-
-
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 651124e65f5..d6184bcdbac 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -62,10 +62,11 @@ public:
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
- virtual bool reset()=0;
+ inline bool reset() { clear(); return add(); };
+ virtual void clear()= 0;
virtual bool add()=0;
virtual void reset_field()=0;
- virtual void update_field(int offset)=0;
+ virtual void update_field()=0;
virtual bool keep_field_type(void) const { return 0; }
virtual void fix_length_and_dec() { maybe_null=1; null_value=1; }
virtual const char *func_name() const { return "?"; }
@@ -126,11 +127,11 @@ class Item_sum_sum :public Item_sum_num
Item_sum_sum(THD *thd, Item_sum_sum &item)
:Item_sum_num(thd, item), sum(item.sum) {}
enum Sumfunctype sum_func () const {return SUM_FUNC;}
- bool reset();
+ void clear();
bool add();
double val();
void reset_field();
- void update_field(int offset);
+ void update_field();
void no_rows_in_result() {}
const char *func_name() const { return "sum"; }
Item *copy_or_same(THD* thd);
@@ -153,13 +154,13 @@ class Item_sum_count :public Item_sum_int
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
- bool reset();
+ void clear();
void no_rows_in_result() { count=0; }
bool add();
void make_const(longlong count_arg) { count=count_arg; used_table_cache=0; }
longlong val_int();
void reset_field();
- void update_field(int offset);
+ void update_field();
const char *func_name() const { return "count"; }
Item *copy_or_same(THD* thd);
};
@@ -227,11 +228,11 @@ class Item_sum_count_distinct :public Item_sum_int
table_map used_tables() const { return used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_DISTINCT_FUNC; }
- bool reset();
+ void clear();
bool add();
longlong val_int();
void reset_field() { return ;} // Never called
- void update_field(int offset) { return ; } // Never called
+ void update_field() { return ; } // Never called
const char *func_name() const { return "count_distinct"; }
bool setup(THD *thd);
void make_unique();
@@ -271,11 +272,11 @@ class Item_sum_avg :public Item_sum_num
Item_sum_avg(THD *thd, Item_sum_avg &item)
:Item_sum_num(thd, item), sum(item.sum), count(item.count) {}
enum Sumfunctype sum_func () const {return AVG_FUNC;}
- bool reset();
+ void clear();
bool add();
double val();
void reset_field();
- void update_field(int offset);
+ void update_field();
Item *result_item(Field *field)
{ return new Item_avg_field(this); }
const char *func_name() const { return "avg"; }
@@ -324,11 +325,11 @@ class Item_sum_variance : public Item_sum_num
Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr),
count(item.count) {}
enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
- bool reset();
+ void clear();
bool add();
double val();
void reset_field();
- void update_field(int offset);
+ void update_field();
Item *result_item(Field *field)
{ return new Item_variance_field(this); }
const char *func_name() const { return "variance"; }
@@ -387,19 +388,18 @@ class Item_sum_hybrid :public Item_sum
Item_sum_hybrid(THD *thd, Item_sum_hybrid &item):
Item_sum(thd, item), value(item.value), tmp_value(item.tmp_value),
sum(item.sum), sum_int(item.sum_int), hybrid_type(item.hybrid_type),
- cmp_sign(item.cmp_sign), used_table_cache(used_table_cache),
- cmp_charset(item.cmp_charset) {}
+ hybrid_field_type(item.hybrid_field_type),cmp_sign(item.cmp_sign),
+ used_table_cache(item.used_table_cache), cmp_charset(item.cmp_charset) {}
bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
- bool reset()
+ void clear()
{
sum=0.0;
sum_int=0;
value.length(0);
null_value=1;
- return add();
}
double val();
longlong val_int();
@@ -409,10 +409,10 @@ class Item_sum_hybrid :public Item_sum
bool keep_field_type(void) const { return 1; }
enum Item_result result_type () const { return hybrid_type; }
enum enum_field_types field_type() const { return hybrid_field_type; }
- void update_field(int offset);
- void min_max_update_str_field(int offset);
- void min_max_update_real_field(int offset);
- void min_max_update_int_field(int offset);
+ void update_field();
+ void min_max_update_str_field();
+ void min_max_update_real_field();
+ void min_max_update_int_field();
};
@@ -453,7 +453,7 @@ class Item_sum_bit :public Item_sum_int
Item_sum_bit(THD *thd, Item_sum_bit &item):
Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {}
enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;}
- bool reset();
+ void clear();
longlong val_int();
void reset_field();
void fix_length_and_dec()
@@ -467,7 +467,7 @@ class Item_sum_or :public Item_sum_bit
Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
Item_sum_or(THD *thd, Item_sum_or &item) :Item_sum_bit(thd, item) {}
bool add();
- void update_field(int offset);
+ void update_field();
const char *func_name() const { return "bit_or"; }
Item *copy_or_same(THD* thd);
};
@@ -479,7 +479,7 @@ class Item_sum_and :public Item_sum_bit
Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {}
Item_sum_and(THD *thd, Item_sum_and &item) :Item_sum_bit(thd, item) {}
bool add();
- void update_field(int offset);
+ void update_field();
const char *func_name() const { return "bit_and"; }
Item *copy_or_same(THD* thd);
};
@@ -511,10 +511,10 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
virtual bool have_field_update(void) const { return 0; }
- bool reset();
+ void clear();
bool add();
void reset_field() {};
- void update_field(int offset_arg) {};
+ void update_field() {};
};
@@ -593,9 +593,9 @@ class Item_sum_udf_float :public Item_sum_num
~Item_sum_udf_float() {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
double val() { return 0.0; }
- bool reset() { return 0; }
+ void clear() {}
bool add() { return 0; }
- void update_field(int offset) {}
+ void update_field() {}
};
@@ -610,9 +610,9 @@ public:
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
longlong val_int() { return 0; }
double val() { return 0; }
- bool reset() { return 0; }
+ void clear() {}
bool add() { return 0; }
- void update_field(int offset) {}
+ void update_field() {}
};
@@ -630,9 +630,9 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec() { maybe_null=1; max_length=0; }
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
- bool reset() { return 0; }
+ void clear() {}
bool add() { return 0; }
- void update_field(int offset) {}
+ void update_field() {}
};
#endif /* HAVE_DLOPEN */
@@ -716,13 +716,13 @@ class Item_func_group_concat : public Item_sum
const char *func_name() const { return "group_concat"; }
enum Type type() const { return SUM_FUNC_ITEM; }
virtual Item_result result_type () const { return STRING_RESULT; }
- bool reset();
+ void clear();
bool add();
void reset_field();
bool fix_fields(THD *, TABLE_LIST *, Item **);
bool setup(THD *thd);
void make_unique();
- virtual void update_field(int offset) {};
+ virtual void update_field() {}
double val()
{
String *res; res=val_str(&str_value);
@@ -735,4 +735,5 @@ class Item_func_group_concat : public Item_sum
}
String* val_str(String* str);
Item *copy_or_same(THD* thd);
+ void no_rows_in_result() {}
};
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index d84267a5066..6dcf7d00ce1 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -327,7 +327,6 @@ public:
max_length=10*default_charset()->mbmaxlen;
}
int save_in_field(Field *to, bool no_conversions);
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_date(maybe_null, name, t_arg, default_charset()));
@@ -342,7 +341,6 @@ public:
Item_date_func(Item *a) :Item_str_func(a) {}
Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_datetime(maybe_null, name, t_arg, default_charset()));
@@ -366,7 +364,6 @@ public:
longlong val_int() { return value; }
String *val_str(String *str);
void fix_length_and_dec();
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, default_charset()));
@@ -533,7 +530,6 @@ public:
}
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
const char *func_name() const { return "sec_to_time"; }
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, default_charset()));
@@ -634,7 +630,6 @@ public:
bool get_date(TIME *ltime, bool fuzzy_date);
const char *func_name() const { return "date"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_date(maybe_null, name, t_arg, default_charset()));
@@ -650,7 +645,6 @@ public:
bool get_time(TIME *ltime);
const char *func_name() const { return "time"; }
enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, default_charset()));
@@ -665,7 +659,6 @@ public:
String *val_str(String *str);
const char *func_name() const { return "datetime"; }
enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_datetime(maybe_null, name, t_arg, default_charset()));
@@ -684,7 +677,6 @@ public:
decimals=0;
max_length=8*MY_CHARSET_BIN_MB_MAXLEN;
}
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_date(maybe_null, name, t_arg, &my_charset_bin));
@@ -711,7 +703,6 @@ public:
Change this when we support
microseconds in TIME/DATETIME
*/
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
if (cached_field_type == MYSQL_TYPE_TIME)
@@ -735,7 +726,6 @@ public:
decimals=0;
max_length=17*MY_CHARSET_BIN_MB_MAXLEN;
}
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
@@ -755,7 +745,6 @@ public:
decimals=0;
max_length=8*MY_CHARSET_BIN_MB_MAXLEN;
}
- Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, &my_charset_bin));
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index f2c64c4bde9..9b370b70181 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -41,10 +41,10 @@ public:
:Item_sum_num(thd, item) {}
double val() { return 0.0; }
enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
- bool reset() { return 0;}
+ void clear() {}
bool add() { return 0; }
void reset_field() {}
- void update_field(int offset) {}
+ void update_field() {}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
fixed= 1;
diff --git a/sql/lex.h b/sql/lex.h
index 24bfe796cc0..e11b50ed16d 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -249,6 +249,12 @@ static SYMBOL symbols[] = {
{ "MASTER_PASSWORD", SYM(MASTER_PASSWORD_SYM),0,0},
{ "MASTER_PORT", SYM(MASTER_PORT_SYM),0,0},
{ "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0},
+ { "MASTER_SSL", SYM(MASTER_SSL_SYM),0,0},
+ { "MASTER_SSL_CA", SYM(MASTER_SSL_CA_SYM),0,0},
+ { "MASTER_SSL_CAPATH",SYM(MASTER_SSL_CAPATH_SYM),0,0},
+ { "MASTER_SSL_CERT", SYM(MASTER_SSL_CERT_SYM),0,0},
+ { "MASTER_SSL_CIPHER",SYM(MASTER_SSL_CIPHER_SYM),0,0},
+ { "MASTER_SSL_KEY", SYM(MASTER_SSL_KEY_SYM),0,0},
{ "MASTER_USER", SYM(MASTER_USER_SYM),0,0},
{ "MAX_ROWS", SYM(MAX_ROWS),0,0},
{ "MAX_QUERIES_PER_HOUR", SYM(MAX_QUERIES_PER_HOUR), 0,0},
@@ -287,7 +293,9 @@ static SYMBOL symbols[] = {
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
+ { "NVARCHAR", SYM(NVARCHAR_SYM),0,0},
{ "OFFSET", SYM(OFFSET_SYM),0,0},
+ { "OLD_PASSWORD", SYM(OLD_PASSWORD),0,0},
{ "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
@@ -404,6 +412,7 @@ static SYMBOL symbols[] = {
{ "USE", SYM(USE_SYM),0,0},
{ "USE_FRM", SYM(USE_FRM),0,0},
{ "USER", SYM(USER),0,0},
+ { "UNTIL", SYM(UNTIL_SYM),0,0},
{ "USING", SYM(USING),0,0},
{ "UTC_DATE", SYM(UTC_DATE_SYM),0,0},
{ "UTC_TIME", SYM(UTC_TIME_SYM),0,0},
@@ -473,9 +482,7 @@ static SYMBOL sql_functions[] = {
{ "COUNT", SYM(COUNT_SYM),0,0},
{ "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
-#ifdef HAVE_COMPRESS
{ "CRC32", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_crc32)},
-#endif
{ "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)},
{ "CURDATE", SYM(CURDATE),0,0},
{ "CURTIME", SYM(CURTIME),0,0},
@@ -590,7 +597,6 @@ static SYMBOL sql_functions[] = {
{ "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)},
{ "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)},
- { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)},
{ "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
{ "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
diff --git a/sql/lock.cc b/sql/lock.cc
index 82004298453..29795415720 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -75,8 +75,6 @@ TODO:
#include "../myisammrg/myrg_def.h"
#endif
-extern HASH open_cache;
-
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
bool unlock, TABLE **write_locked);
static int lock_external(THD *thd, TABLE **table,uint count);
@@ -526,7 +524,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
table->locked_by_name=1;
table_list->table=table;
- if (hash_insert(&open_cache, (byte*) table))
+ if (my_hash_insert(&open_cache, (byte*) table))
{
my_free((gptr) table,MYF(0));
DBUG_RETURN(-1);
diff --git a/sql/log.cc b/sql/log.cc
index d3ba5b63e19..608a7e94431 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -31,7 +31,6 @@
#include <m_ctype.h> // For test_if_number
MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
-extern I_List<i_string> binlog_do_db, binlog_ignore_db;
static bool test_if_number(const char *str,
long *res, bool allow_wildcards);
@@ -270,7 +269,8 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
an extension for the binary log files.
In this case we write a standard header to it.
*/
- if (my_b_write(&log_file, (byte*) BINLOG_MAGIC, BIN_LOG_HEADER_SIZE))
+ if (my_b_safe_write(&log_file, (byte*) BINLOG_MAGIC,
+ BIN_LOG_HEADER_SIZE))
goto err;
bytes_written += BIN_LOG_HEADER_SIZE;
write_file_name_to_index_file=1;
@@ -704,6 +704,7 @@ int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli, bool included)
rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
sizeof(rli->group_relay_log_name)-1);
+ rli->notify_group_relay_log_name_update();
}
/* Store where we are in the new file for the execution thread */
@@ -1091,8 +1092,11 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
if (thd)
{ // Normal thread
- if ((thd->options & OPTION_LOG_OFF) &&
- (thd->master_access & SUPER_ACL))
+ if ((thd->options & OPTION_LOG_OFF)
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ && (thd->master_access & SUPER_ACL)
+#endif
+)
{
VOID(pthread_mutex_unlock(&LOCK_log));
return 0; // No logging
@@ -1175,14 +1179,24 @@ bool MYSQL_LOG::write(Log_event* event_info)
*/
if (is_open())
{
- const char *local_db = event_info->get_db();
+ const char *local_db= event_info->get_db();
+ IO_CACHE *file= &log_file;
#ifdef USING_TRANSACTIONS
- IO_CACHE *file = ((event_info->get_cache_stmt()) ?
- &thd->transaction.trans_log :
- &log_file);
-#else
- IO_CACHE *file = &log_file;
-#endif
+ /*
+ Should we write to the binlog cache or to the binlog on disk?
+ Write to the binlog cache if:
+ - it is already not empty (meaning we're in a transaction; note that the
+ present event could be about a non-transactional table, but still we need
+ to write to the binlog cache in that case to handle updates to mixed
+ trans/non-trans table types the best possible in binlogging)
+ - or if the event asks for it (cache_stmt == true).
+ */
+ if (opt_using_transactions &&
+ (event_info->get_cache_stmt() ||
+ (thd && my_b_tell(&thd->transaction.trans_log))))
+ file= &thd->transaction.trans_log;
+#endif
+ DBUG_PRINT("info",("event type=%d",event_info->get_type_code()));
#ifdef HAVE_REPLICATION
/*
In the future we need to add to the following if tests like
@@ -1401,6 +1415,13 @@ uint MYSQL_LOG::next_file_id()
/*
Write a cached log entry to the binary log
+ SYNOPSIS
+ write()
+ thd
+ cache The cache to copy to the binlog
+ commit_or_rollback If true, will write "COMMIT" in the end, if false will
+ write "ROLLBACK".
+
NOTE
- We only come here if there is something in the cache.
- The thing in the cache is always a complete transaction
@@ -1408,10 +1429,13 @@ uint MYSQL_LOG::next_file_id()
IMPLEMENTATION
- To support transaction over replication, we wrap the transaction
- with BEGIN/COMMIT in the binary log.
+ with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
+ We want to write a BEGIN/ROLLBACK block when a non-transactional table was
+ updated in a transaction which was rolled back. This is to ensure that the
+ same updates are run on the slave.
*/
-bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
+bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
{
VOID(pthread_mutex_lock(&LOCK_log));
DBUG_ENTER("MYSQL_LOG::write(cache");
@@ -1465,7 +1489,10 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
*/
{
- Query_log_event qinfo(thd, "COMMIT", 6, TRUE);
+ Query_log_event qinfo(thd,
+ commit_or_rollback ? "COMMIT" : "ROLLBACK",
+ commit_or_rollback ? 6 : 8,
+ TRUE);
qinfo.set_log_pos(this);
if (qinfo.write(&log_file) || flush_io_cache(&log_file))
goto err;
@@ -1528,8 +1555,11 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
int tmp_errno=0;
char buff[80],*end;
end=buff;
- if (!(thd->options & OPTION_UPDATE_LOG) &&
- (thd->master_access & SUPER_ACL))
+ if (!(thd->options & OPTION_UPDATE_LOG)
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ && (thd->master_access & SUPER_ACL)
+#endif
+ )
{
VOID(pthread_mutex_unlock(&LOCK_log));
return 0;
@@ -1556,8 +1586,8 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
tmp_errno=errno;
}
if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
- thd->priv_user,
- thd->user,
+ thd->priv_user ? thd->priv_user : "",
+ thd->user ? thd->user : "",
thd->host ? thd->host : "",
thd->ip ? thd->ip : "") == (uint) -1)
tmp_errno=errno;
@@ -1642,6 +1672,9 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
SYNOPSIS
wait_for_update()
thd Thread variable
+ master_or_slave If 0, the caller is the Binlog_dump thread from master;
+ if 1, the caller is the SQL thread from the slave. This
+ influences only thd->proc_info.
NOTES
One must have a lock on LOCK_log before calling this function.
@@ -1653,11 +1686,15 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
If you don't do it this way, you will get a deadlock in THD::awake()
*/
-void MYSQL_LOG:: wait_for_update(THD* thd)
+void MYSQL_LOG:: wait_for_update(THD* thd, bool master_or_slave)
{
safe_mutex_assert_owner(&LOCK_log);
const char* old_msg = thd->enter_cond(&update_cond, &LOCK_log,
- "Slave: waiting for binlog update");
+ master_or_slave ?
+ "Has read all relay log; waiting for \
+the I/O slave thread to update it" :
+ "Has sent all binlog to slave; \
+waiting for binlog to be updated");
pthread_cond_wait(&update_cond, &LOCK_log);
pthread_mutex_unlock(&LOCK_log); // See NOTES
thd->exit_cond(old_msg);
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 8a52ad9ebca..b5fd78c06a9 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -27,25 +27,6 @@
#define log_cs &my_charset_latin1
/*
- my_b_safe_write()
-*/
-
-inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
- int len)
-{
- /*
- Sasha: We are not writing this with the ? operator to avoid hitting
- a possible compiler bug. At least gcc 2.95 cannot deal with
- several layers of ternary operators that evaluated comma(,) operator
- expressions inside - I do have a test case if somebody wants it
- */
- if (file->type == SEQ_READ_APPEND)
- return my_b_append(file, buf,len);
- return my_b_write(file, buf,len);
-}
-
-
-/*
pretty_print_str()
*/
@@ -239,12 +220,11 @@ const char* Log_event::get_type_str()
#ifndef MYSQL_CLIENT
Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
- :temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg),
- thd(thd_arg)
+ :log_pos(0), temp_buf(0), exec_time(0), cached_event_len(0),
+ flags(flags_arg), thd(thd_arg)
{
server_id= thd->server_id;
when= thd->start_time;
- log_pos= thd->log_pos;
cache_stmt= (using_trans &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)));
}
@@ -331,7 +311,6 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
handler and MyISAM and STOP SLAVE is issued in the middle of the
"transaction". START SLAVE will resume at BEGIN while the MyISAM table
has already been updated.
-
*/
if ((thd->options & OPTION_BEGIN) && opt_using_transactions)
rli->inc_event_relay_log_pos(get_event_len());
@@ -605,6 +584,8 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
ev = new Query_log_event(buf, event_len, old_format);
break;
case LOAD_EVENT:
+ ev = new Create_file_log_event(buf, event_len, old_format);
+ break;
case NEW_LOAD_EVENT:
ev = new Load_log_event(buf, event_len, old_format);
break;
@@ -894,7 +875,6 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
int Query_log_event::exec_event(struct st_relay_log_info* rli)
{
int expected_error,actual_error= 0;
- init_sql_alloc(&thd->mem_root, 8192,0);
thd->db= (char*) rewrite_db(db);
/*
@@ -988,14 +968,14 @@ Default database: '%s'",
*/
} /* End of if (db_ok(... */
-end:
-
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->db= 0; // prevent db from being freed
thd->query= 0; // just to be sure
VOID(pthread_mutex_unlock(&LOCK_thread_count));
// assume no convert for next query unless set explictly
- //thd->variables.convert_set = 0;
+#ifdef TO_BE_REMOVED
+ thd->variables.convert_set = 0;
+#endif
close_thread_tables(thd);
free_root(&thd->mem_root,0);
return (thd->query_error ? thd->query_error : Log_event::exec_event(rli));
@@ -1091,15 +1071,6 @@ int Start_log_event::write_data(IO_CACHE* file)
the use of a bit of memory for a user lock which will not be used
anymore. If the user lock is later used, the old one will be released. In
other words, no deadlock problem.
- - If we have an active transaction at this point, the master died
- in the middle while writing the transaction to the binary log.
- In this case we should stop the slave.
- Guilhem 2003-06: I don't think we should. As the binlog is written before
- the table changes are committed, rollback has occured on the master; we
- should rather rollback on the slave and go on. If we don't rollback, and
- the next query is not BEGIN, then it will be considered as part of the
- unfinished transaction, and so will be rolled back at next BEGIN, which
- is a bug.
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
@@ -1113,14 +1084,25 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli)
This is 4.x, so a Start_log_event is only at master startup,
so we are sure the master has restarted and cleared his temp tables.
*/
-
- /*
- If the master died before writing the COMMIT to the binlog, rollback;
- otherwise it does not hurt to rollback.
- */
- ha_rollback(thd);
close_temporary_tables(thd);
cleanup_load_tmpdir();
+ /*
+ As a transaction NEVER spans on 2 or more binlogs:
+ if we have an active transaction at this point, the master died while
+ writing the transaction to the binary log, i.e. while flushing the binlog
+ cache to the binlog. As the write was started, the transaction had been
+ committed on the master, so we lack of information to replay this
+ transaction on the slave; all we can do is stop with error.
+ */
+ if (thd->options & OPTION_BEGIN)
+ {
+ slave_print_error(rli, 0,
+ "there is an unfinished transaction in the relay log \
+(could find neither COMMIT nor ROLLBACK in the relay log); it could be that \
+the master died while writing the transaction to its binary log. Now the slave \
+is rolling back the transaction.");
+ return(1);
+ }
break;
/*
@@ -1471,6 +1453,13 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
#ifdef MYSQL_CLIENT
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
{
+ print(file, short_form, last_db, 0);
+}
+
+
+void Load_log_event::print(FILE* file, bool short_form, char* last_db,
+ bool commented)
+{
if (!short_form)
{
print_header(file);
@@ -1486,9 +1475,12 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
}
if (db && db[0] && !same_db)
- fprintf(file, "use %s;\n", db);
+ fprintf(file, "%suse %s;\n",
+ commented ? "# " : "",
+ db);
- fprintf(file, "LOAD DATA ");
+ fprintf(file, "%sLOAD DATA ",
+ commented ? "# " : "");
if (check_fname_outside_temp_buf())
fprintf(file, "LOCAL ");
fprintf(file, "INFILE '%-*s' ", fname_len, fname);
@@ -1535,8 +1527,8 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
pretty_print_str(file, sql_ex.line_start, sql_ex.line_start_len);
}
- if ((int)skip_lines > 0)
- fprintf(file, " IGNORE %ld LINES ", (long) skip_lines);
+ if ((long) skip_lines > 0)
+ fprintf(file, " IGNORE %ld LINES", (long) skip_lines);
if (num_fields)
{
@@ -1607,12 +1599,23 @@ void Load_log_event::set_fields(List<Item> &field_list)
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors)
{
- init_sql_alloc(&thd->mem_root, 8192,0);
thd->db= (char*) rewrite_db(db);
DBUG_ASSERT(thd->query == 0);
thd->query = 0; // Should not be needed
thd->query_error = 0;
+ /*
+ We test replicate_*_db rules. Note that we have already prepared the file
+ to load, even if we are going to ignore and delete it now. So it is
+ possible that we did a lot of disk writes for nothing. In other words, a
+ big LOAD DATA INFILE on the master will still consume a lot of space on
+ the slave (space in the relay log + space of temp files: twice the space
+ of the file to load...) even if it will finally be ignored.
+ TODO: fix this; this can be done by testing rules in
+ Create_file_log_event::exec_event() and then discarding Append_block and
+ al. Another way is do the filtering in the I/O thread (more efficient: no
+ disk writes at all).
+ */
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->set_time((time_t)when);
@@ -1642,20 +1645,22 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
else if (sql_ex.opt_flags & IGNORE_FLAG)
handle_dup= DUP_IGNORE;
else
+ {
/*
- Note that when replication is running fine, if it was DUP_ERROR on the
+ When replication is running fine, if it was DUP_ERROR on the
master then we could choose DUP_IGNORE here, because if DUP_ERROR
suceeded on master, and data is identical on the master and slave,
then there should be no uniqueness errors on slave, so DUP_IGNORE is
the same as DUP_ERROR. But in the unlikely case of uniqueness errors
- (because the data on the master and slave happen to be different (user
- error or bug), we want LOAD DATA to print an error message on the
- slave to discover the problem.
+ (because the data on the master and slave happen to be different
+ (user error or bug), we want LOAD DATA to print an error message on
+ the slave to discover the problem.
If reading from net (a 3.23 master), mysql_load() will change this
to DUP_IGNORE.
*/
handle_dup= DUP_ERROR;
+ }
sql_exchange ex((char*)fname, sql_ex.opt_flags & DUMPFILE_FLAG);
String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
@@ -1731,7 +1736,7 @@ Slave: load data infile on table '%s' at log position %s in log \
err=ER(sql_errno);
}
slave_print_error(rli,sql_errno,"\
-Error '%s' running lOAD DATA INFILE on table '%s'. Default database: '%s'",
+Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
err, (char*)table_name, print_slave_db_safe(db));
free_root(&thd->mem_root,0);
return 1;
@@ -1762,14 +1767,13 @@ Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'",
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void Rotate_log_event::pack_info(Protocol *protocol)
{
- char *buf, *b_pos;
- if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME))))
- return;
- memcpy(buf, new_log_ident, ident_len);
- b_pos= strmov(buf + ident_len, ";pos=");
- b_pos= longlong10_to_str(pos, b_pos, 10);
- protocol->store(buf, (uint) (b_pos-buf), &my_charset_bin);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ char buf1[256], buf[22];
+ String tmp(buf1, sizeof(buf1), log_cs);
+ tmp.length(0);
+ tmp.append(new_log_ident, ident_len);
+ tmp.append(";pos=");
+ tmp.append(llstr(pos,buf));
+ protocol->store(tmp.ptr(), tmp.length(), &my_charset_bin);
}
#endif
@@ -1865,16 +1869,31 @@ int Rotate_log_event::write_data(IO_CACHE* file)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
{
- char* log_name = rli->group_master_log_name;
DBUG_ENTER("Rotate_log_event::exec_event");
pthread_mutex_lock(&rli->data_lock);
- memcpy(log_name, new_log_ident, ident_len+1);
- rli->group_master_log_pos = pos;
rli->event_relay_log_pos += get_event_len();
- rli->group_relay_log_pos = rli->event_relay_log_pos;
- DBUG_PRINT("info", ("group_master_log_pos: %lu",
- (ulong) rli->group_master_log_pos));
+ /*
+ If we are in a transaction: the only normal case is when the I/O thread was
+ copying a big transaction, then it was stopped and restarted: we have this
+ in the relay log:
+ BEGIN
+ ...
+ ROTATE (a fake one)
+ ...
+ COMMIT or ROLLBACK
+ In that case, we don't want to touch the coordinates which correspond to the
+ beginning of the transaction.
+ */
+ if (!(thd->options & OPTION_BEGIN))
+ {
+ memcpy(rli->group_master_log_name, new_log_ident, ident_len+1);
+ rli->notify_group_master_log_name_update();
+ rli->group_master_log_pos = pos;
+ rli->group_relay_log_pos = rli->event_relay_log_pos;
+ DBUG_PRINT("info", ("group_master_log_pos: %lu",
+ (ulong) rli->group_master_log_pos));
+ }
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
flush_relay_log_info(rli);
@@ -1894,8 +1913,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
void Intvar_log_event::pack_info(Protocol *protocol)
{
- char buf[64], *pos;
- pos= strmov(buf, get_var_type_name());
+ char buf[256], *pos;
+ pos= strmake(buf, get_var_type_name(), sizeof(buf)-23);
*pos++= '=';
pos= longlong10_to_str(val, pos, -10);
protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
@@ -2462,8 +2481,8 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
Stop_log_event::exec_event()
The master stopped.
- We used to clean up all temporary tables but this is useless as, as the master
- has shut down properly, it has written all DROP TEMPORARY TABLE and DO
+ We used to clean up all temporary tables but this is useless as, as the
+ master has shut down properly, it has written all DROP TEMPORARY TABLE and DO
RELEASE_LOCK (prepared statements' deletion is TODO).
We used to clean up slave_load_tmpdir, but this is useless as it has been
cleared at the end of LOAD DATA INFILE.
@@ -2605,10 +2624,12 @@ void Create_file_log_event::print(FILE* file, bool short_form,
if (enable_local)
{
- if (!check_fname_outside_temp_buf())
- fprintf(file, "#");
- Load_log_event::print(file, 1, last_db);
- fprintf(file, "#");
+ Load_log_event::print(file, 1, last_db, !check_fname_outside_temp_buf());
+ /*
+ That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
+ SHOW BINLOG EVENTS we don't.
+ */
+ fprintf(file, "#");
}
fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len);
@@ -2641,7 +2662,7 @@ void Create_file_log_event::pack_info(Protocol *protocol)
pos= int10_to_str((long) block_len, pos, 10);
protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/*
@@ -2665,7 +2686,7 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
goto err;
}
@@ -2676,7 +2697,9 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
if (write_base(&file))
{
strmov(p, ".info"); // to have it right in the error message
- slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
+ slave_print_error(rli,my_errno,
+ "Error in Create_file event: could not write to file '%s'",
+ fname_buf);
goto err;
}
end_io_cache(&file);
@@ -2686,16 +2709,14 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
MYF(MY_WME))) < 0)
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
goto err;
}
if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
{
- slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
+ slave_print_error(rli,my_errno, "Error in Create_file event: write to '%s' failed", fname_buf);
goto err;
}
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
error=0; // Everything is ok
err:
@@ -2705,7 +2726,7 @@ err:
my_close(fd, MYF(0));
return error ? 1 : Log_event::exec_event(rli);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/**************************************************************************
@@ -2717,11 +2738,12 @@ err:
*/
#ifndef MYSQL_CLIENT
-Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
+Append_block_log_event::Append_block_log_event(THD* thd_arg, const char* db_arg,
+ char* block_arg,
uint block_len_arg,
bool using_trans)
:Log_event(thd_arg,0, using_trans), block(block_arg),
- block_len(block_len_arg), file_id(thd_arg->file_id)
+ block_len(block_len_arg), file_id(thd_arg->file_id), db(db_arg)
{
}
#endif
@@ -2787,7 +2809,7 @@ void Append_block_log_event::pack_info(Protocol *protocol)
block_len));
protocol->store(buf, length, &my_charset_bin);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/*
@@ -2805,16 +2827,14 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
memcpy(p, ".data", 6);
if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ slave_print_error(rli,my_errno, "Error in Append_block event: could not open file '%s'", fname);
goto err;
}
if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
{
- slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
+ slave_print_error(rli,my_errno, "Error in Append_block event: write to '%s' failed", fname);
goto err;
}
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
error=0;
err:
@@ -2834,8 +2854,9 @@ err:
*/
#ifndef MYSQL_CLIENT
-Delete_file_log_event::Delete_file_log_event(THD *thd_arg, bool using_trans)
- :Log_event(thd_arg, 0, using_trans),file_id(thd_arg->file_id)
+Delete_file_log_event::Delete_file_log_event(THD *thd_arg, const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
{
}
#endif
@@ -2908,11 +2929,9 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
(void) my_delete(fname, MYF(MY_WME));
memcpy(p, ".info", 6);
(void) my_delete(fname, MYF(MY_WME));
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
return Log_event::exec_event(rli);
}
-#endif
+#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
/**************************************************************************
@@ -2924,8 +2943,9 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
*/
#ifndef MYSQL_CLIENT
-Execute_load_log_event::Execute_load_log_event(THD *thd_arg, bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
+Execute_load_log_event::Execute_load_log_event(THD *thd_arg, const char* db_arg,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id), db(db_arg)
{
}
#endif
@@ -2997,7 +3017,6 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
char *p= slave_load_file_stem(fname, file_id, server_id);
int fd;
int error = 1;
- ulong save_options;
IO_CACHE file;
Load_log_event* lev = 0;
@@ -3006,7 +3025,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
MYF(MY_WME|MY_NABP)))
{
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ slave_print_error(rli,my_errno, "Error in Exec_load event: could not open file '%s'", fname);
goto err;
}
if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
@@ -3014,21 +3033,16 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
(bool)0)) ||
lev->get_type_code() != NEW_LOAD_EVENT)
{
- slave_print_error(rli,0, "File '%s' appears corrupted", fname);
+ slave_print_error(rli,0, "Error in Exec_load event: file '%s' appears corrupted", fname);
goto err;
}
- /*
- We are going to create a Load_log_event to finally load into the table.
- This event should not go into the binlog: in the binlog we only want the
- Create_file, Append_blocks and Execute_load. We disable binary logging and
- restore the thread's options just after finishing the load.
- */
- save_options = thd->options;
- thd->options &= ~ (ulong) (OPTION_BIN_LOG);
+
lev->thd = thd;
/*
lev->exec_event should use rli only for errors
- i.e. should not advance rli's position
+ i.e. should not advance rli's position.
+ lev->exec_event is the place where the table is loaded (it calls
+ mysql_load()).
*/
if (lev->exec_event(0,rli,1))
{
@@ -3049,15 +3063,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
tmp, fname);
my_free(tmp,MYF(0));
}
- thd->options= save_options;
goto err;
}
- thd->options = save_options;
(void) my_delete(fname, MYF(MY_WME));
memcpy(p, ".data", 6);
(void) my_delete(fname, MYF(MY_WME));
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
error = 0;
err:
diff --git a/sql/log_event.h b/sql/log_event.h
index a58479e2589..8ba5d0379a0 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -590,6 +590,7 @@ public:
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form, char* last_db, bool commented);
#endif
Load_log_event(const char* buf, int event_len, bool old_format);
@@ -934,9 +935,20 @@ public:
char* block;
uint block_len;
uint file_id;
-
+ /*
+ 'db' is filled when the event is created in mysql_load() (the event needs to
+ have a 'db' member to be well filtered by binlog-*-db rules). 'db' is not
+ written to the binlog (it's not used by Append_block_log_event::write()), so
+ it can't be read in the Append_block_log_event(const char* buf, int
+ event_len) constructor.
+ In other words, 'db' is used only for filtering by binlog-*-db rules.
+ Create_file_log_event is different: its 'db' (which is inherited from
+ Load_log_event) is written to the binlog and can be re-read.
+ */
+ const char* db;
+
#ifndef MYSQL_CLIENT
- Append_block_log_event(THD* thd, char* block_arg,
+ Append_block_log_event(THD* thd, const char* db_arg, char* block_arg,
uint block_len_arg, bool using_trans);
#ifdef HAVE_REPLICATION
int exec_event(struct st_relay_log_info* rli);
@@ -952,6 +964,7 @@ public:
int get_data_size() { return block_len + APPEND_BLOCK_HEADER_LEN ;}
bool is_valid() { return block != 0; }
int write_data(IO_CACHE* file);
+ const char* get_db() { return db; }
};
/*****************************************************************************
@@ -963,9 +976,10 @@ class Delete_file_log_event: public Log_event
{
public:
uint file_id;
+ const char* db; /* see comment in Append_block_log_event */
#ifndef MYSQL_CLIENT
- Delete_file_log_event(THD* thd, bool using_trans);
+ Delete_file_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
@@ -981,6 +995,7 @@ public:
int get_data_size() { return DELETE_FILE_HEADER_LEN ;}
bool is_valid() { return file_id != 0; }
int write_data(IO_CACHE* file);
+ const char* get_db() { return db; }
};
/*****************************************************************************
@@ -992,9 +1007,10 @@ class Execute_load_log_event: public Log_event
{
public:
uint file_id;
-
+ const char* db; /* see comment in Append_block_log_event */
+
#ifndef MYSQL_CLIENT
- Execute_load_log_event(THD* thd, bool using_trans);
+ Execute_load_log_event(THD* thd, const char* db_arg, bool using_trans);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
@@ -1009,6 +1025,7 @@ public:
int get_data_size() { return EXEC_LOAD_HEADER_LEN ;}
bool is_valid() { return file_id != 0; }
int write_data(IO_CACHE* file);
+ const char* get_db() { return db; }
};
#ifdef MYSQL_CLIENT
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a28d343ffd6..7961d9c3468 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -74,9 +74,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
****************************************************************************/
#define ACL_CACHE_SIZE 256
-/* Password lengh for 4.1 version previous versions had 16 bytes password hash */
-#define HASH_PASSWORD_LENGTH 45
-#define HASH_OLD_PASSWORD_LENGTH 16
#define MAX_PASSWORD_LENGTH 32
#define HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
@@ -212,16 +209,17 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_NOT_USED 16
#define MODE_ONLY_FULL_GROUP_BY 32
#define MODE_NO_UNSIGNED_SUBTRACTION 64
-#define MODE_POSTGRESQL 128
-#define MODE_ORACLE 256
-#define MODE_MSSQL 512
-#define MODE_DB2 1024
-#define MODE_SAPDB 2048
-#define MODE_NO_KEY_OPTIONS 4096
-#define MODE_NO_TABLE_OPTIONS 8192
-#define MODE_NO_FIELD_OPTIONS 16384
-#define MODE_MYSQL323 32768
-#define MODE_MYSQL40 65536
+#define MODE_NO_DIR_IN_CREATE 128
+#define MODE_POSTGRESQL 256
+#define MODE_ORACLE 512
+#define MODE_MSSQL 1024
+#define MODE_DB2 2048
+#define MODE_SAPDB 4096
+#define MODE_NO_KEY_OPTIONS 8192
+#define MODE_NO_TABLE_OPTIONS 16384
+#define MODE_NO_FIELD_OPTIONS 32768
+#define MODE_MYSQL323 65536
+#define MODE_MYSQL40 (MODE_MYSQL323*2)
#define MODE_ANSI (MODE_MYSQL40*2)
#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
@@ -324,6 +322,15 @@ typedef compare_func_creator (*chooser_compare_func_creator)(bool invert);
#include "opt_range.h"
#ifdef HAVE_QUERY_CACHE
+struct Query_cache_query_flags
+{
+ unsigned int client_long_flag:1;
+ uint character_set_client_num;
+ uint character_set_results_num;
+ uint collation_connection_num;
+ ha_rows limit;
+};
+#define QUERY_CACHE_FLAGS_SIZE sizeof(Query_cache_query_flags)
#include "sql_cache.h"
#define query_cache_store_query(A, B) query_cache.store_query(A, B)
#define query_cache_destroy() query_cache.destroy()
@@ -337,6 +344,7 @@ typedef compare_func_creator (*chooser_compare_func_creator)(bool invert);
#define query_cache_invalidate_by_MyISAM_filename_ref \
&query_cache_invalidate_by_MyISAM_filename
#else
+#define QUERY_CACHE_FLAGS_SIZE 0
#define query_cache_store_query(A, B)
#define query_cache_destroy()
#define query_cache_result_size_limit(A)
@@ -395,22 +403,30 @@ bool check_stack_overrun(THD *thd,char *dummy);
#define check_stack_overrun(A, B) 0
#endif
-bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
- bool *write_to_binlog);
void table_cache_init(void);
void table_cache_free(void);
uint cached_tables(void);
void kill_mysql(void);
void close_connection(THD *thd, uint errcode, bool lock);
-bool check_access(THD *thd, ulong access, const char *db=0, ulong *save_priv=0,
- bool no_grant=0, bool no_errors=0);
+bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
+ bool *write_to_binlog);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv,
+ bool no_grant, bool no_errors);
bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
- bool no_errors=0);
+ bool no_errors);
bool check_global_access(THD *thd, ulong want_access);
+#else
+#define check_access(thd, access, db, save_priv, no_grant, no_errors) false
+#define check_table_access(thd, want_access, tables, no_errors) false
+#define check_global_access(thd, want_access) false
+#endif
int mysql_backup_table(THD* thd, TABLE_LIST* table_list);
int mysql_restore_table(THD* thd, TABLE_LIST* table_list);
+int mysql_checksum_table(THD* thd, TABLE_LIST* table_list,
+ HA_CHECK_OPT* check_opt);
int mysql_check_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt);
int mysql_repair_table(THD* thd, TABLE_LIST* table_list,
@@ -558,7 +574,8 @@ void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
int mysqld_show_variables(THD *thd,const char *wild);
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
- enum enum_var_type value_type);
+ enum enum_var_type value_type,
+ pthread_mutex_t *mutex);
int mysqld_show_charsets(THD *thd,const char *wild);
int mysqld_show_collations(THD *thd,const char *wild);
int mysqld_show_table_types(THD *thd);
@@ -576,6 +593,7 @@ void mysql_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter);
+void setup_param_functions(Item_param *param, uchar param_type);
/* sql_error.cc */
MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
@@ -597,7 +615,8 @@ void set_item_name(Item *item,char *pos,uint length);
bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
char *length, char *decimal,
uint type_modifier,
- Item *default_value, Item *comment,
+ Item *default_value,
+ LEX_STRING *comment,
char *change, TYPELIB *interval,CHARSET_INFO *cs,
uint uint_geom_type);
void store_position_for_column(const char *name);
@@ -705,6 +724,9 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
enum_log_type type, bool read_append,
bool no_auto_events, ulong max_size);
+/* mysqld.cc */
+extern void yyerror(const char*);
+
/*
External variables
*/
@@ -715,10 +737,10 @@ extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
extern MY_TMPDIR mysql_tmpdir_list;
extern const char *command_name[];
-extern const char *first_keyword, *localhost, *delayed_user, *binary_keyword;
+extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
-extern const char *in_left_expr_name;
+extern const char *in_left_expr_name, *in_additional_cond;
extern uchar *days_in_month;
extern char language[LIBLEN],reg_ext[FN_EXTLEN];
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
@@ -747,6 +769,7 @@ extern ulong ha_read_first_count, ha_read_last_count;
extern ulong ha_read_rnd_count, ha_read_rnd_next_count;
extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
+extern ulong slave_net_timeout;
extern ulong max_insert_delayed_threads, max_user_connections;
extern ulong long_query_count, what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
@@ -772,7 +795,7 @@ extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names;
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_readonly;
extern my_bool opt_enable_named_pipe;
-extern my_bool opt_old_passwords, use_old_passwords;
+extern my_bool opt_secure_auth;
extern char *shared_memory_base_name, *mysqld_unix_port;
extern bool opt_enable_shared_memory;
@@ -784,7 +807,7 @@ extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_error_log, LOCK_delayed_insert,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager,
- LOCK_global_system_variables;
+ LOCK_global_system_variables, LOCK_user_conn;
extern rw_lock_t LOCK_grant;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_attr_t connection_attrib;
@@ -792,7 +815,8 @@ extern I_List<THD> threads;
extern I_List<NAMED_LIST> key_caches;
extern MY_BITMAP temp_pool;
extern DATE_FORMAT dayord;
-extern String empty_string;
+extern String my_empty_string;
+extern String my_null_string;
extern SHOW_VAR init_vars[],status_vars[], internal_vars[];
extern struct show_table_type_st table_type_vars[];
extern SHOW_COMP_OPTION have_isam;
@@ -801,6 +825,11 @@ extern SHOW_COMP_OPTION have_berkeley_db;
extern struct system_variables global_system_variables;
extern struct system_variables max_system_variables;
extern struct rand_struct sql_rand;
+extern HASH open_cache;
+extern TABLE *unused_tables;
+extern I_List<i_string> binlog_do_db, binlog_ignore_db;
+extern const char* any_db;
+extern struct my_option my_long_options[];
/* optional things, have_* variables */
@@ -935,6 +964,14 @@ bool flush_error_log(void);
void free_list(I_List <i_string_pair> *list);
void free_list(I_List <i_string> *list);
+/* sql_yacc.cc */
+extern int yyparse(void *thd);
+
+/* frm_crypt.cc */
+#ifdef HAVE_CRYPTED_FRM
+SQL_CRYPT *get_crypt_for_frm(void);
+#endif
+
/* Some inline functions for more speed */
inline bool add_item_to_list(THD *thd, Item *item)
@@ -964,6 +1001,12 @@ inline void mark_as_null_row(TABLE *table)
bfill(table->null_flags,table->null_bytes,255);
}
+inline void table_case_convert(char * name, uint length)
+{
+ if (lower_case_table_names)
+ my_casedn(files_charset_info, name, length);
+}
+
compare_func_creator comp_eq_creator(bool invert);
compare_func_creator comp_ge_creator(bool invert);
compare_func_creator comp_gt_creator(bool invert);
@@ -980,6 +1023,7 @@ compare_func_creator comp_ne_creator(bool invert);
table_list TABLE_LIST structure pointer (owner of TABLE)
tablenr - table number
*/
+
inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
{
table->used_fields= 0;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 41bd9706fc3..6213c43b80b 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -210,6 +210,7 @@ const char *sql_mode_names[] =
{
"REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
"?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
+ "NO_DIR_IN_CREATE",
"POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS",
"NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
"NO_AUTO_VALUE_ON_ZERO", NullS
@@ -217,7 +218,7 @@ const char *sql_mode_names[] =
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
sql_mode_names };
const char *first_keyword= "first", *binary_keyword= "BINARY";
-const char *localhost= "localhost", *delayed_user= "DELAYED";
+const char *my_localhost= "localhost", *delayed_user= "DELAYED";
#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
#define GET_HA_ROWS GET_ULL
#else
@@ -257,9 +258,10 @@ my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool lower_case_table_names, opt_old_rpl_compat;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
-my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
+my_bool opt_log_slave_updates= 0;
my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam;
my_bool opt_readonly, use_temp_pool, relay_log_purge;
+my_bool opt_secure_auth= 0;
volatile bool mqh_used = 0;
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
@@ -319,6 +321,8 @@ const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF";
/* name of reference on left espression in rewritten IN subquery */
const char *in_left_expr_name= "<left expr>";
+/* name of additional condition */
+const char *in_additional_cond= "<IN COND>";
FILE *bootstrap_file;
@@ -362,15 +366,15 @@ pthread_t signal_thread;
pthread_attr_t connection_attrib;
/* replication parameters, if master_host is not NULL, we are a slave */
-my_bool master_ssl;
uint master_port= MYSQL_PORT, master_connect_retry = 60;
uint report_port= MYSQL_PORT;
ulong master_retry_count=0;
char *master_user, *master_password, *master_host, *master_info_file;
-char *relay_log_info_file, *master_ssl_key, *master_ssl_cert;
-char *master_ssl_capath, *master_ssl_cipher, *report_user;
-char *report_password, *report_host;
+char *relay_log_info_file, *report_user, *report_password, *report_host;
char *opt_relay_logname = 0, *opt_relaylog_index_name=0;
+my_bool master_ssl;
+char *master_ssl_key, *master_ssl_cert;
+char *master_ssl_ca, *master_ssl_capath, *master_ssl_cipher;
/* Static variables */
@@ -871,8 +875,10 @@ void clean_up(bool print_message)
if (use_slave_mask)
bitmap_free(&slave_error_mask);
#endif
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
acl_free(1);
grant_free();
+#endif
query_cache_destroy();
table_cache_free();
hostname_cache_free();
@@ -1119,7 +1125,14 @@ static void server_init(void)
IPaddr.sin_family = AF_INET;
IPaddr.sin_addr.s_addr = my_bind_addr;
IPaddr.sin_port = (unsigned short) htons((unsigned short) mysqld_port);
+
+#ifndef __WIN__
+ /*
+ We should not use SO_REUSEADDR on windows as this would enable a
+ user to open two mysqld servers with the same TCP/IP port.
+ */
(void) setsockopt(ip_sock,SOL_SOCKET,SO_REUSEADDR,(char*)&arg,sizeof(arg));
+#endif /* __WIN__ */
if (bind(ip_sock, my_reinterpret_cast(struct sockaddr *) (&IPaddr),
sizeof(IPaddr)) < 0)
{
@@ -1661,6 +1674,7 @@ static void init_signals(void)
}
+#ifndef EMBEDDED_LIBRARY
static void start_signal_handler(void)
{
int error;
@@ -1823,6 +1837,7 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
}
return(0); /* purecov: deadcode */
}
+#endif /*!EMBEDDED_LIBRARY*/
static void check_data_home(const char *path)
{}
@@ -2050,7 +2065,10 @@ static int init_common_variables(const char *conf_file_name, int argc,
max_connections,table_cache_size));
sql_print_error("Warning: Changed limits: max_connections: %ld table_cache: %ld",max_connections,table_cache_size);
}
+ open_files_limit= files;
}
+#else
+ open_files_limit= 0; /* Can't set or detect limit */
#endif
unireg_init(opt_specialflag); /* Set up extern variabels */
init_errmessage(); /* Read error messages from file */
@@ -2080,11 +2098,11 @@ static int init_common_variables(const char *conf_file_name, int argc,
}
default_charset_info= default_collation;
}
- global_system_variables.character_set_server= default_charset_info;
- global_system_variables.character_set_database= default_charset_info;
+ global_system_variables.collation_server= default_charset_info;
+ global_system_variables.collation_database= default_charset_info;
+ global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
- global_system_variables.collation_connection= default_charset_info;
if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
return 1;
@@ -2217,7 +2235,9 @@ Now disabling --log-slave-updates.");
opt_error_log= 1; // Too long file name
else
{
+#ifndef EMBEDDED_LIBRARY
if (freopen(log_error_file, "a+", stdout))
+#endif
freopen(log_error_file, "a+", stderr);
}
}
@@ -2749,7 +2769,6 @@ static int bootstrap(FILE *file)
{
int error= 0;
DBUG_ENTER("bootstrap");
-#ifndef EMBEDDED_LIBRARY // TODO: Enable this
THD *thd= new THD;
thd->bootstrap=1;
@@ -2761,6 +2780,7 @@ static int bootstrap(FILE *file)
thread_count++;
bootstrap_file=file;
+#ifndef EMBEDDED_LIBRARY // TODO: Enable this
if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
(void*) thd))
{
@@ -2775,11 +2795,17 @@ static int bootstrap(FILE *file)
DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
}
(void) pthread_mutex_unlock(&LOCK_thread_count);
+#else
+ thd->mysql= 0;
+ handle_bootstrap((void *)thd);
+#endif
+
error= thd->is_fatal_error;
+#ifndef EMBEDDED_LIBRARY
net_end(&thd->net);
+#endif
thd->cleanup();
delete thd;
-#endif /* EMBEDDED_LIBRARY */
DBUG_RETURN(error);
}
@@ -2819,12 +2845,6 @@ static void create_new_thread(THD *thd)
if (thread_count-delayed_insert_threads > max_used_connections)
max_used_connections=thread_count-delayed_insert_threads;
thd->thread_id=thread_id++;
- for (uint i=0; i < 8 ; i++) // Generate password teststring
- thd->scramble[i]= (char) (my_rnd(&sql_rand)*94+33);
- thd->scramble[8]=0;
- // Back it up as old clients may need it
- memcpy(thd->old_scramble,thd->scramble,9);
-
thd->real_id=pthread_self(); // Keep purify happy
@@ -3103,7 +3123,13 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
continue;
}
if (sock == unix_sock)
- thd->host=(char*) localhost;
+ thd->host=(char*) my_localhost;
+#ifdef __WIN__
+ /* Set default wait_timeout */
+ ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;
+ (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout,
+ sizeof(wait_timeout));
+#endif
create_new_thread(thd);
}
@@ -3187,7 +3213,7 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
continue;
}
/* host name is unknown */
- thd->host = my_strdup(localhost,MYF(0)); /* Host is unknown */
+ thd->host = my_strdup(my_localhost,MYF(0)); /* Host is unknown */
create_new_thread(thd);
}
@@ -3396,7 +3422,7 @@ errorconn:
if (!event_client_read) CloseHandle(event_client_read);
continue;
}
- thd->host = my_strdup(localhost,MYF(0)); /* Host is unknown */
+ thd->host = my_strdup(my_localhost,MYF(0)); /* Host is unknown */
create_new_thread(thd);
uint4korr(connect_number++);
}
@@ -3445,7 +3471,7 @@ enum options
OPT_MASTER_RETRY_COUNT,
OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH,
- OPT_MASTER_SSL_CIPHER,
+ OPT_MASTER_SSL_CIPHER, OPT_MASTER_SSL_CA,
OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES,
OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB,
@@ -3535,7 +3561,8 @@ enum options
OPT_EXPIRE_LOGS_DAYS,
OPT_DEFAULT_WEEK_FORMAT,
OPT_GROUP_CONCAT_MAX_LEN,
- OPT_DEFAULT_COLLATION
+ OPT_DEFAULT_COLLATION,
+ OPT_SECURE_AUTH
};
@@ -3783,31 +3810,32 @@ thread is in the master's binlogs.",
(gptr*) &master_info_file, (gptr*) &master_info_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"master-ssl", OPT_MASTER_SSL,
- "Planned to enable the slave to connect to the master using SSL. Does nothing yet.",
+ "Enable the slave to connect to the master using SSL.",
(gptr*) &master_ssl, (gptr*) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"master-ssl-key", OPT_MASTER_SSL_KEY,
- "Master SSL keyfile name. Only applies if you have enabled master-ssl. Does \
-nothing yet.",
+ "Master SSL keyfile name. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_key, (gptr*) &master_ssl_key, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"master-ssl-cert", OPT_MASTER_SSL_CERT,
"Master SSL certificate file name. Only applies if you have enabled \
-master-ssl. Does nothing yet.",
+master-ssl",
(gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
+ {"master-ssl-ca", OPT_MASTER_SSL_CA,
+ "Master SSL CA file. Only applies if you have enabled master-ssl.",
+ (gptr*) &master_ssl_ca, (gptr*) &master_ssl_ca, 0, GET_STR, OPT_ARG,
+ 0, 0, 0, 0, 0, 0},
{"master-ssl-capath", OPT_MASTER_SSL_CAPATH,
- "Master SSL CA path. Only applies if you have enabled master-ssl. \
-Does nothing yet.",
+ "Master SSL CA path. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"master-ssl-cipher", OPT_MASTER_SSL_CIPHER,
- "Master SSL cipher. Only applies if you have enabled master-ssl. \
-Does nothing yet.",
+ "Master SSL cipher. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG,
0, 0, 0, 0, 0, 0},
{"myisam-recover", OPT_MYISAM_RECOVER,
- "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP or FORCE.",
+ "Syntax: myisam-recover[=option[,option...]], where option can be DEFAULT, BACKUP, FORCE or QUICK.",
(gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"memlock", OPT_MEMLOCK, "Lock mysqld in memory.", (gptr*) &locked_in_memory,
@@ -3844,9 +3872,10 @@ Does nothing yet.",
(gptr*) &opt_no_mix_types, (gptr*) &opt_no_mix_types, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
#endif
- {"old-protocol", 'o', "Use the old (3.20) protocol client/server protocol.",
- (gptr*) &protocol_version, (gptr*) &protocol_version, 0, GET_UINT, NO_ARG,
- PROTOCOL_VERSION, 0, 0, 0, 0, 0},
+ {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).",
+ (gptr*) &global_system_variables.old_passwords,
+ (gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
{"old-rpl-compat", OPT_OLD_RPL_COMPAT,
"Use old LOAD DATA format in the binary log (don't save data in file).",
(gptr*) &opt_old_rpl_compat, (gptr*) &opt_old_rpl_compat, 0, GET_BOOL,
@@ -3913,8 +3942,6 @@ relay logs.",
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).",
- (gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef TO_BE_DELETED
{"safe-show-database", OPT_SAFE_SHOW_DB,
"Deprecated option; One should use GRANT SHOW DATABASES instead...",
@@ -3924,6 +3951,9 @@ relay logs.",
"Don't allow new user creation by the user who has no write privileges to the mysql.user table.",
(gptr*) &opt_safe_user_create, (gptr*) &opt_safe_user_create, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.",
+ (gptr*) &opt_secure_auth, (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG,
+ my_bool(0), 0, 0, 0, 0, 0},
{"server-id", OPT_SERVER_ID,
"Uniquely identifies the server instance in the community of replication partners.",
(gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0,
@@ -4196,7 +4226,7 @@ replicating a LOAD DATA INFILE command.",
"Max packetlength to send/receive from to server.",
(gptr*) &global_system_variables.max_allowed_packet,
(gptr*) &max_system_variables.max_allowed_packet, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L, 80, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
+ REQUIRED_ARG, 1024*1024L, 1024, 1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
{"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
"Can be used to restrict the total size used to cache a multi-transaction query.",
(gptr*) &max_binlog_cache_size, (gptr*) &max_binlog_cache_size, 0,
@@ -4452,14 +4482,15 @@ struct show_var_st status_vars[]= {
{"Bytes_received", (char*) &bytes_received, SHOW_LONG},
{"Bytes_sent", (char*) &bytes_sent, SHOW_LONG},
{"Com_admin_commands", (char*) &com_other, SHOW_LONG},
- {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG},
{"Com_alter_db", (char*) (com_stat+(uint) SQLCOM_ALTER_DB),SHOW_LONG},
+ {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG},
{"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG},
{"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG},
{"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG},
{"Com_change_db", (char*) (com_stat+(uint) SQLCOM_CHANGE_DB),SHOW_LONG},
{"Com_change_master", (char*) (com_stat+(uint) SQLCOM_CHANGE_MASTER),SHOW_LONG},
{"Com_check", (char*) (com_stat+(uint) SQLCOM_CHECK),SHOW_LONG},
+ {"Com_checksum", (char*) (com_stat+(uint) SQLCOM_CHECKSUM),SHOW_LONG},
{"Com_commit", (char*) (com_stat+(uint) SQLCOM_COMMIT),SHOW_LONG},
{"Com_create_db", (char*) (com_stat+(uint) SQLCOM_CREATE_DB),SHOW_LONG},
{"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG},
@@ -4472,6 +4503,7 @@ struct show_var_st status_vars[]= {
{"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG},
{"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
{"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG},
+ {"Com_drop_user", (char*) (com_stat+(uint) SQLCOM_DROP_USER),SHOW_LONG},
{"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG},
{"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG},
{"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
@@ -4486,6 +4518,7 @@ struct show_var_st status_vars[]= {
{"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG},
{"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG},
{"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG},
+ {"Com_preload_keys", (char*) (com_stat+(uint) SQLCOM_PRELOAD_KEYS),SHOW_LONG},
{"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG},
{"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG},
{"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG},
@@ -4495,13 +4528,15 @@ struct show_var_st status_vars[]= {
{"Com_reset", (char*) (com_stat+(uint) SQLCOM_RESET),SHOW_LONG},
{"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG},
{"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG},
+ {"Com_revoke_all", (char*) (com_stat+(uint) SQLCOM_REVOKE_ALL),SHOW_LONG},
{"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG},
{"Com_savepoint", (char*) (com_stat+(uint) SQLCOM_SAVEPOINT),SHOW_LONG},
{"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG},
{"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG},
- {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
{"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG},
+ {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
{"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),SHOW_LONG},
+ {"Com_show_collations", (char*) (com_stat+(uint) SQLCOM_SHOW_COLLATIONS),SHOW_LONG},
{"Com_show_column_types", (char*) (com_stat+(uint) SQLCOM_SHOW_COLUMN_TYPES),SHOW_LONG},
{"Com_show_create_table", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
{"Com_show_create_db", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE_DB),SHOW_LONG},
@@ -4509,6 +4544,7 @@ struct show_var_st status_vars[]= {
{"Com_show_errors", (char*) (com_stat+(uint) SQLCOM_SHOW_ERRORS),SHOW_LONG},
{"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG},
{"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
+ {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
{"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
{"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG},
{"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
@@ -4519,7 +4555,6 @@ struct show_var_st status_vars[]= {
{"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
{"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
{"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
- {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
{"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
{"Com_show_table_types", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLE_TYPES),SHOW_LONG},
{"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
@@ -4708,7 +4743,8 @@ static void mysql_init_variables(void)
opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
opt_disable_networking= opt_skip_show_db=0;
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0;
- opt_bootstrap= opt_myisam_log= use_old_passwords= 0;
+ opt_secure_auth= 0;
+ opt_bootstrap= opt_myisam_log= 0;
mqh_used= 0;
segfaulted= kill_in_progress= 0;
cleanup_done= 0;
@@ -4787,8 +4823,9 @@ static void mysql_init_variables(void)
master_user= (char*) "test";
master_password= master_host= 0;
master_info_file= (char*) "master.info",
- relay_log_info_file= (char*) "relay-log.info",
- master_ssl_key= master_ssl_cert= master_ssl_capath= master_ssl_cipher= 0;
+ relay_log_info_file= (char*) "relay-log.info";
+ master_ssl_key= master_ssl_cert= master_ssl_ca=
+ master_ssl_capath= master_ssl_cipher= 0;
report_user= report_password = report_host= 0; /* TO BE DELETED */
opt_relay_logname= opt_relaylog_index_name= 0;
@@ -4800,17 +4837,18 @@ static void mysql_init_variables(void)
/* Set default values for some option variables */
- global_system_variables.character_set_server= default_charset_info;
- global_system_variables.character_set_database= default_charset_info;
+ global_system_variables.collation_server= default_charset_info;
+ global_system_variables.collation_database= default_charset_info;
+ global_system_variables.collation_connection= default_charset_info;
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
- global_system_variables.collation_connection= default_charset_info;
global_system_variables.table_type= DB_TYPE_MYISAM;
global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
max_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
+ global_system_variables.old_passwords= 0;
/* Variables that depends on compile options */
#ifndef DBUG_OFF
@@ -4932,9 +4970,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case 'L':
strmake(language, argument, sizeof(language)-1);
break;
- case 'o':
- protocol_version=PROTOCOL_VERSION-1;
- break;
#ifdef HAVE_REPLICATION
case OPT_SLAVE_SKIP_ERRORS:
init_slave_skip_errors(argument);
@@ -5157,11 +5192,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
my_use_symdir=0;
break;
case (int) OPT_BIND_ADDRESS:
- if (argument && my_isdigit(mysqld_charset, argument[0]))
- {
- my_bind_addr = (ulong) inet_addr(argument);
- }
- else
+ if (!argument || (my_bind_addr= (ulong) inet_addr(argument)) == INADDR_NONE)
{
struct hostent *ent;
if (argument || argument[0])
@@ -5563,6 +5594,19 @@ static void fix_paths(void)
}
+/*
+ set how many open files we want to be able to handle
+
+ SYNOPSIS
+ set_maximum_open_files()
+ max_file_limit Files to open
+
+ NOTES
+ The request may not fulfilled becasue of system limitations
+
+ RETURN
+ Files available to open
+*/
#ifdef SET_RLIMIT_NOFILE
static uint set_maximum_open_files(uint max_file_limit)
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index f12705572d6..7944a528b83 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -88,10 +88,15 @@ void sql_print_error(const char *format,...);
#ifdef MYSQL_SERVER
#define USE_QUERY_CACHE
+/*
+ The following variables/functions should really not be declared
+ extern, but as it's hard to include mysql_priv.h here, we have to
+ live with this for a while.
+*/
extern uint test_flags;
-extern void query_cache_insert(NET *net, const char *packet, ulong length);
extern ulong bytes_sent, bytes_received, net_big_packet_count;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
+extern void query_cache_insert(NET *net, const char *packet, ulong length);
#else
#undef statistic_add
#undef statistic_increment
@@ -240,10 +245,12 @@ my_bool net_flush(NET *net)
*****************************************************************************/
/*
-** Write a logical packet with packet header
-** Format: Packet length (3 bytes), packet number(1 byte)
-** When compression is used a 3 byte compression length is added
-** NOTE: If compression is used the original package is modified!
+ Write a logical packet with packet header
+ Format: Packet length (3 bytes), packet number(1 byte)
+ When compression is used a 3 byte compression length is added
+
+ NOTE
+ If compression is used the original package is modified!
*/
my_bool
@@ -364,8 +371,8 @@ net_write_command(NET *net,uchar command,
The cached buffer can be sent as it is with 'net_flush()'.
In this code we have to be careful to not send a packet longer than
- MAX_PACKET_LENGTH to net_real_write() if we are using the compressed protocol
- as we store the length of the compressed packet in 3 bytes.
+ MAX_PACKET_LENGTH to net_real_write() if we are using the compressed
+ protocol as we store the length of the compressed packet in 3 bytes.
RETURN
0 ok
@@ -458,7 +465,7 @@ net_real_write(NET *net,const char *packet,ulong len)
#ifdef MYSQL_SERVER
net->last_errno= ER_OUT_OF_RESOURCES;
net->error= 2;
- //TODO is it needed to set this variable if we have no socket
+ /* TODO is it needed to set this variable if we have no socket */
net->report_error= 1;
#endif
net->reading_or_writing= 0;
@@ -483,6 +490,7 @@ net_real_write(NET *net,const char *packet,ulong len)
thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff);
#else
alarmed=0;
+ vio_timeout(net->vio, net->write_timeout);
#endif /* NO_ALARM */
pos=(char*) packet; end=pos+len;
@@ -674,6 +682,8 @@ my_real_read(NET *net, ulong *complen)
#ifndef NO_ALARM
if (net_blocking)
thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
+#else
+ vio_timeout(net->vio, net->read_timeout);
#endif /* NO_ALARM */
pos = net->buff + net->where_b; /* net->packet -4 */
@@ -877,20 +887,23 @@ my_net_read(NET *net)
{
/* We are using the compressed protocol */
- ulong buf_length= net->buf_length;
- ulong start_of_packet= net->buf_length - net->remain_in_buf;
- ulong first_packet_offset=start_of_packet;
+ ulong buf_length;
+ ulong start_of_packet;
+ ulong first_packet_offset;
uint read_length, multi_byte_packet=0;
if (net->remain_in_buf)
{
+ buf_length= net->buf_length; /* Data left in old packet */
+ first_packet_offset= start_of_packet= (net->buf_length -
+ net->remain_in_buf);
/* Restore the character that was overwritten by the end 0 */
- net->buff[start_of_packet]=net->save_char;
+ net->buff[start_of_packet]= net->save_char;
}
else
{
/* reuse buffer, as there is nothing in it that we need */
- buf_length=start_of_packet=first_packet_offset=0;
+ buf_length= start_of_packet= first_packet_offset= 0;
}
for (;;)
{
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 23fb36c0c91..5b1e2c98001 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -341,8 +341,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
DBUG_RETURN(0);
if (!(select= new SQL_SELECT))
{
- *error= 1;
- DBUG_RETURN(0); /* purecov: inspected */
+ *error= 1; // out of memory
+ DBUG_RETURN(0); /* purecov: inspected */
}
select->read_tables=read_tables;
select->const_tables=const_tables;
@@ -456,15 +456,17 @@ SEL_ARG *SEL_ARG::clone(SEL_ARG *new_parent,SEL_ARG **next_arg)
SEL_ARG *tmp;
if (type != KEY_RANGE)
{
- tmp=new SEL_ARG(type);
+ if(!(tmp=new SEL_ARG(type)))
+ return 0; // out of memory
tmp->prev= *next_arg; // Link into next/prev chain
(*next_arg)->next=tmp;
(*next_arg)= tmp;
}
else
{
- tmp=new SEL_ARG(field,part, min_value,max_value,
- min_flag, max_flag, maybe_flag);
+ if(!(tmp=new SEL_ARG(field,part, min_value,max_value,
+ min_flag, max_flag, maybe_flag)))
+ return 0; // out of memory
tmp->parent=new_parent;
tmp->next_key_part=next_key_part;
if (left != &null_element)
@@ -616,6 +618,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
SEL_TREE *tree;
KEY_PART *key_parts;
PARAM param;
+ THD *thd= current_thd;
/* set up parameter that is passed to all functions */
param.baseflag=basflag;
@@ -626,13 +629,13 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
param.keys=0;
param.mem_root= &alloc;
- current_thd->no_errors=1; // Don't warn about NULL
+ thd->no_errors=1; // Don't warn about NULL
init_sql_alloc(&alloc,2048,0);
if (!(param.key_parts = (KEY_PART*) alloc_root(&alloc,
sizeof(KEY_PART)*
head->key_parts)))
{
- current_thd->no_errors=0;
+ thd->no_errors=0;
free_root(&alloc,MYF(0)); // Return memory & allocator
DBUG_RETURN(0); // Can't use range
}
@@ -689,7 +692,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint keynr= param.real_keynr[idx];
if ((*key)->type == SEL_ARG::MAYBE_KEY ||
(*key)->maybe_flag)
- needed_reg|= (key_map) 1 << keynr;
+ needed_reg|= (key_map) 1 << keynr;
found_records=check_quick_select(&param, idx, *key);
if (found_records != HA_POS_ERROR && found_records > 2 &&
@@ -713,7 +716,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
param.range_count,
found_records)+
(double) found_records / TIME_FOR_COMPARE);
- if (read_time > found_read_time)
+ if (read_time > found_read_time && found_records != HA_POS_ERROR)
{
read_time=found_read_time;
records=found_records;
@@ -734,7 +737,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
}
free_root(&alloc,MYF(0)); // Return memory & allocator
my_pthread_setspecific_ptr(THR_MALLOC,old_root);
- current_thd->no_errors=0;
+ thd->no_errors=0;
}
DBUG_EXECUTE("info",print_quick(quick,needed_reg););
/*
@@ -762,6 +765,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
while ((item=li++))
{
SEL_TREE *new_tree=get_mm_tree(param,item);
+ if (current_thd->is_fatal_error)
+ DBUG_RETURN(0); // out of memory
tree=tree_and(param,tree,new_tree);
if (tree && tree->type == SEL_TREE::IMPOSSIBLE)
break;
@@ -777,7 +782,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
SEL_TREE *new_tree=get_mm_tree(param,item);
if (!new_tree)
- DBUG_RETURN(0);
+ DBUG_RETURN(0); // out of memory
tree=tree_or(param,tree,new_tree);
if (!tree || tree->type == SEL_TREE::ALWAYS)
break;
@@ -793,18 +798,16 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
DBUG_RETURN(new SEL_TREE(SEL_TREE::ALWAYS));
DBUG_RETURN(new SEL_TREE(SEL_TREE::IMPOSSIBLE));
}
+
table_map ref_tables=cond->used_tables();
- if (ref_tables & ~(param->prev_tables | param->read_tables |
- param->current_table))
- DBUG_RETURN(0); // Can't be calculated yet
if (cond->type() != Item::FUNC_ITEM)
{ // Should be a field
- if (ref_tables & param->current_table)
+ if ((ref_tables & param->current_table) ||
+ (ref_tables & ~(param->prev_tables | param->read_tables)))
DBUG_RETURN(0);
DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE));
}
- if (!(ref_tables & param->current_table))
- DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
+
Item_func *cond_func= (Item_func*) cond;
if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
DBUG_RETURN(0); // Can't be calculated
@@ -815,12 +818,13 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
{
Field *field=((Item_field*) (cond_func->arguments()[0]))->field;
Item_result cmp_type=field->cmp_type();
- tree= get_mm_parts(param,field,Item_func::GE_FUNC,
- cond_func->arguments()[1],cmp_type);
- DBUG_RETURN(tree_and(param,tree,
+ DBUG_RETURN(tree_and(param,
+ get_mm_parts(param, field,
+ Item_func::GE_FUNC,
+ cond_func->arguments()[1], cmp_type),
get_mm_parts(param, field,
Item_func::LE_FUNC,
- cond_func->arguments()[2],cmp_type)));
+ cond_func->arguments()[2], cmp_type)));
}
DBUG_RETURN(0);
}
@@ -846,6 +850,12 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
DBUG_RETURN(0); // Can't optimize this IN
}
+ if (ref_tables & ~(param->prev_tables | param->read_tables |
+ param->current_table))
+ DBUG_RETURN(0); // Can't be calculated yet
+ if (!(ref_tables & param->current_table))
+ DBUG_RETURN(new SEL_TREE(SEL_TREE::MAYBE)); // This may be false or true
+
/* check field op const */
/* btw, ft_func's arguments()[0] isn't FIELD_ITEM. SerG*/
if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
@@ -877,14 +887,15 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond)
static SEL_TREE *
-get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
- Item_result cmp_type)
+get_mm_parts(PARAM *param, Field *field, Item_func::Functype type,
+ Item *value, Item_result cmp_type)
{
DBUG_ENTER("get_mm_parts");
if (field->table != param->table)
DBUG_RETURN(0);
- KEY_PART *key_part = param->key_parts,*end=param->key_parts_end;
+ KEY_PART *key_part = param->key_parts;
+ KEY_PART *end = param->key_parts_end;
SEL_TREE *tree=0;
if (value &&
value->used_tables() & ~(param->prev_tables | param->read_tables))
@@ -894,8 +905,8 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
if (field->eq(key_part->field))
{
SEL_ARG *sel_arg=0;
- if (!tree)
- tree=new SEL_TREE();
+ if (!tree && !(tree=new SEL_TREE()))
+ DBUG_RETURN(0); // out of memory
if (!value || !(value->used_tables() & ~param->read_tables))
{
sel_arg=get_mm_leaf(param,key_part->field,key_part,type,value);
@@ -907,8 +918,11 @@ get_mm_parts(PARAM *param,Field *field, Item_func::Functype type,Item *value,
DBUG_RETURN(tree);
}
}
- else
- sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY);// This key may be used later
+ else {
+ // This key may be used later
+ if(!(sel_arg=new SEL_ARG(SEL_ARG::MAYBE_KEY)))
+ DBUG_RETURN(0); // out of memory
+ }
sel_arg->part=(uchar) key_part->part;
tree->keys[key_part->key]=sel_add(tree->keys[key_part->key],sel_arg);
}
@@ -995,9 +1009,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(0);
if (!maybe_null) // Not null field
DBUG_RETURN(type == Item_func::ISNULL_FUNC ? &null_element : 0);
- tree=new SEL_ARG(field,is_null_string,is_null_string);
- if (!tree)
- DBUG_RETURN(0);
+ if (!(tree=new SEL_ARG(field,is_null_string,is_null_string)))
+ DBUG_RETURN(0); // out of memory
if (type == Item_func::ISNOTNULL_FUNC)
{
tree->min_flag=NEAR_MIN; /* IS NOT NULL -> X > NULL */
@@ -1035,7 +1048,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
field->get_key_image(str+maybe_null,key_part->part_length,
field->charset(),key_part->image_type);
if (!(tree=new SEL_ARG(field,str,str)))
- DBUG_RETURN(0);
+ DBUG_RETURN(0); // out of memory
switch (type) {
case Item_func::LT_FUNC:
@@ -1475,7 +1488,8 @@ key_or(SEL_ARG *key1,SEL_ARG *key2)
SEL_ARG *key2_next=key2->next;
if (key2_shared)
{
- key2=new SEL_ARG(*key2);
+ if(!(key2=new SEL_ARG(*key2)))
+ return 0; // out of memory
key2->increment_use_count(key1->use_count+1);
key2->next=key2_next; // New copy of key2
}
@@ -2319,16 +2333,16 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
}
/* Get range for retrieving rows in QUICK_SELECT::get_next */
- range= new QUICK_RANGE(param->min_key,
- (uint) (tmp_min_key - param->min_key),
- param->max_key,
- (uint) (tmp_max_key - param->max_key),
- flag);
+ if(!(range= new QUICK_RANGE(param->min_key,
+ (uint) (tmp_min_key - param->min_key),
+ param->max_key,
+ (uint) (tmp_max_key - param->max_key),
+ flag)))
+ return 1; // out of memory
+
set_if_bigger(quick->max_used_key_length,range->min_length);
set_if_bigger(quick->max_used_key_length,range->max_length);
set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1);
- if (!range) // Not enough memory
- return 1;
quick->ranges.push_back(range);
end:
@@ -2389,17 +2403,17 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
uint part;
if (!quick)
- return 0;
+ return 0; /* no ranges found */
if (cp_buffer_from_ref(ref))
{
if (current_thd->is_fatal_error)
- return 0; // End of memory
+ return 0; // out of memory
return quick; // empty range
}
QUICK_RANGE *range= new QUICK_RANGE();
if (!range)
- goto err;
+ goto err; // out of memory
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
diff --git a/sql/password.c b/sql/password.c
index 257547671e5..9f4910d8c60 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -29,28 +29,33 @@
The password is saved (in user.password) by using the PASSWORD() function in
mysql.
+ This is .c file because it's used in libmysqlclient, which is entirely in C.
+ (we need it to be portable to a variety of systems).
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
+ The new autentication is performed in following manner:
- New in MySQL 4.1 authentication works even more secure way.
- At the first step client sends user name to the sever, and password if
- it is empty. So in case of empty password authentication is as fast as before.
- At the second stap servers sends scramble to client, which is encoded with
- password stage2 hash stored in the password database as well as salt, needed
- for client to build stage2 password to decrypt scramble.
- Client decrypts the scramble and encrypts it once again with stage1 password.
- This information is sent to server.
- Server decrypts the scramble to get stage1 password and hashes it to get
- stage2 hash. This hash is when compared to hash stored in the database.
+ SERVER: public_seed=create_random_string()
+ send(public_seed)
- This authentication needs 2 packet round trips instead of one but it is much
- stronger. Now if one will steal mysql database content he will not be able
- to break into MySQL.
+ CLIENT: recv(public_seed)
+ hash_stage1=sha1("password")
+ hash_stage2=sha1(hash_stage1)
+ reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
- New Password handling functions by Peter Zaitsev
+ // this three steps are done in scramble()
+ send(reply)
+
+
+ SERVER: recv(reply)
+ hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
+ candidate_hash2=sha1(hash_stage1)
+ check(candidate_hash2==hash_stage2)
+
+ // this three steps are done in check_scramble()
*****************************************************************************/
@@ -60,31 +65,21 @@
#include <sha1.h>
#include "mysql.h"
-
-
-/* Character to use as version identifier for version 4.1 */
-#define PVERSION41_CHAR '*'
-
-/* Scramble length for new password version */
-
+/************ MySQL 3.23-4.0 authentification routines: untouched ***********/
/*
New (MySQL 3.21+) random generation structure initialization
-
SYNOPSIS
randominit()
rand_st OUT Structure to initialize
seed1 IN First initialization parameter
seed2 IN Second initialization parameter
-
- RETURN
- none
*/
-void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
-{ /* For mysql 3.21.# */
+void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2)
+{ /* For mysql 3.21.# */
#ifdef HAVE_purify
- bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
#endif
rand_st->max_value= 0x3FFFFFFFL;
rand_st->max_value_dbl=(double) rand_st->max_value;
@@ -94,35 +89,12 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
/*
- Old (MySQL 3.20) random generation structure initialization
-
- SYNOPSIS
- old_randominit()
- rand_st OUT Structure to initialize
- seed1 IN First initialization parameter
-
- RETURN
- none
-*/
-
-static void old_randominit(struct rand_struct *rand_st,ulong seed1)
-{ /* For mysql 3.20.# */
- rand_st->max_value= 0x01FFFFFFL;
- rand_st->max_value_dbl=(double) rand_st->max_value;
- seed1%=rand_st->max_value;
- rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
-}
-
-
-/*
- Generate Random number
-
+ Generate random number.
SYNOPSIS
my_rnd()
rand_st INOUT Structure used for number generation
-
- RETURN
- Generated pseudo random number
+ RETURN VALUE
+ generated pseudo random number
*/
double my_rnd(struct rand_struct *rand_st)
@@ -134,73 +106,24 @@ double my_rnd(struct rand_struct *rand_st)
/*
- Generate String of printable random characters of requested length
- String will not be zero terminated.
-
+ Generate binary hash from raw text string
+ Used for Pre-4.1 password handling
SYNOPSIS
- create_random_string()
- length IN Lenght of
- rand_st INOUT Structure used for number generation
- target OUT Buffer for generation
-
- RETURN
- none
+ hash_password()
+ result OUT store hash in this location
+ password IN plain text password to build hash
+ password_len IN password length (password may be not null-terminated)
*/
-void create_random_string(int length,struct rand_struct *rand_st,char *target)
-{
- char *end=target+length;
- /* Use pointer arithmetics as it is faster way to do so. */
- for (; target<end ; target++)
- *target= (char) (my_rnd(rand_st)*94+33);
-}
-
-
-/*
- Encrypt/Decrypt function used for password encryption in authentication
- Simple XOR is used here but it is OK as we crypt random strings
-
- SYNOPSIS
- password_crypt()
- from IN Data for encryption
- to OUT Encrypt data to the buffer (may be the same)
- password IN Password used for encryption (same length)
- length IN Length of data to encrypt
-
- RETURN
- none
-*/
-
-void password_crypt(const char *from,char *to, const char *password,int length)
-{
- const char *from_end=from+length;
-
- while (from < from_end)
- *to++= *(from++) ^* (password++);
-}
-
-
-/*
- Generate binary hash from raw text password
- Used for Pre-4.1 Password handling
-
- SYNOPSIS
- hash_pasword()
- result OUT Store hash in this location
- password IN Plain text password to build hash
-
- RETURN
- none
-*/
-
-void hash_password(ulong *result, const char *password)
+void hash_password(ulong *result, const char *password, uint password_len)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
ulong tmp;
- for (; *password ; password++)
+ const char *password_end= password + password_len;
+ for (; password < password_end; password++)
{
if (*password == ' ' || *password == '\t')
- continue; /* skipp space in password */
+ continue; /* skip space in password */
tmp= (ulong) (uchar) *password;
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
nr2+=(nr2 << 8) ^ nr;
@@ -208,519 +131,388 @@ void hash_password(ulong *result, const char *password)
}
result[0]=nr & (((ulong) 1L << 31) -1L); /* Don't use sign bit (str2int) */;
result[1]=nr2 & (((ulong) 1L << 31) -1L);
- return;
}
/*
- Stage one password hashing.
- Used in MySQL 4.1 password handling
-
+ Create password to be stored in user database from raw string
+ Used for pre-4.1 password handling
SYNOPSIS
- password_hash_stage1()
- to OUT Store stage one hash to this location
- password IN Plain text password to build hash
-
- RETURN
- none
+ make_scrambled_password_323()
+ to OUT store scrambled password here
+ password IN user-supplied password
*/
-void password_hash_stage1(char *to, const char *password)
+void make_scrambled_password_323(char *to, const char *password)
{
- SHA1_CONTEXT context;
- sha1_reset(&context);
- for (; *password ; password++)
- {
- if (*password == ' ' || *password == '\t')
- continue;/* skip space in password */
- sha1_input(&context,(uint8*) &password[0],1);
- }
- sha1_result(&context,(uint8*)to);
+ ulong hash_res[2];
+ hash_password(hash_res, password, strlen(password));
+ sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]);
}
/*
- Stage two password hashing.
- Used in MySQL 4.1 password handling
-
+ Scramble string with password.
+ Used in pre 4.1 authentication phase.
SYNOPSIS
- password_hash_stage2()
- to INOUT Use this as stage one hash and store stage two hash here
- salt IN Salt used for stage two hashing
-
- RETURN
- none
+ scramble_323()
+ to OUT Store scrambled message here. Buffer must be at least
+ SCRAMBLE_LENGTH_323+1 bytes long
+ message IN Message to scramble. Message must be at least
+ SRAMBLE_LENGTH_323 bytes long.
+ password IN Password to use while scrambling
*/
-void password_hash_stage2(char *to, const char *salt)
+void scramble_323(char *to, const char *message, const char *password)
{
- SHA1_CONTEXT context;
- sha1_reset(&context);
- sha1_input(&context,(uint8*) salt, 4);
- sha1_input(&context,(uint8*) to, SHA1_HASH_SIZE);
- sha1_result(&context,(uint8*) to);
+ struct rand_struct rand_st;
+ ulong hash_pass[2], hash_message[2];
+
+ if (password && password[0])
+ {
+ char extra, *to_start=to;
+ const char *message_end= message + SCRAMBLE_LENGTH_323;
+ hash_password(hash_pass,password, strlen(password));
+ hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ for (; message < message_end; message++)
+ *to++= (char) (floor(my_rnd(&rand_st)*31)+64);
+ extra=(char) (floor(my_rnd(&rand_st)*31));
+ while (to_start != to)
+ *(to_start++)^=extra;
+ }
+ *to= 0;
}
/*
- Create password to be stored in user database from raw string
- Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords
-
+ Check scrambled message
+ Used in pre 4.1 password handling
SYNOPSIS
- make_scramble_password()
- to OUT Store scrambled password here
- password IN Raw string password
- force_old_scramle
- IN Force generation of old scramble variant
- rand_st INOUT Structure for temporary number generation.
- RETURN
- none
+ check_scramble_323()
+ scrambled scrambled message to check.
+ message original random message which was used for scrambling; must
+ be exactly SCRAMBLED_LENGTH_323 bytes long and
+ NULL-terminated.
+ hash_pass password which should be used for scrambling
+ All params are IN.
+
+ RETURN VALUE
+ 0 - password correct
+ !0 - password invalid
*/
-void make_scrambled_password(char *to,const char *password,
- my_bool force_old_scramble,
- struct rand_struct *rand_st)
+my_bool
+check_scramble_323(const char *scrambled, const char *message,
+ ulong *hash_pass)
{
- ulong hash_res[2]; /* Used for pre 4.1 password hashing */
- unsigned short salt; /* Salt for 4.1 version password */
- uint8 digest[SHA1_HASH_SIZE];
- if (force_old_scramble) /* Pre 4.1 password encryption */
- {
- hash_password(hash_res,password);
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
- }
- else /* New password 4.1 password scrambling */
+ struct rand_struct rand_st;
+ ulong hash_message[2];
+ char buff[16],*to,extra; /* Big enough for check */
+ const char *pos;
+
+ hash_password(hash_message, message, SCRAMBLE_LENGTH_323);
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ to=buff;
+ for (pos=scrambled ; *pos ; pos++)
+ *to++=(char) (floor(my_rnd(&rand_st)*31)+64);
+ extra=(char) (floor(my_rnd(&rand_st)*31));
+ to=buff;
+ while (*scrambled)
{
- to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
- /* Rnd returns number from 0 to 1 so this would be good salt generation.*/
- salt=(unsigned short) (my_rnd(rand_st)*65535+1);
- /* Use only 2 first bytes from it */
- sprintf(to+1,"%04x",salt);
- /* First hasing is done without salt */
- password_hash_stage1((char*) digest, password);
- /* Second stage is done with salt */
- password_hash_stage2((char*) digest,(char*)to+1),
- /* Print resulting hash into the password*/
- sprintf(to+5,
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],
- digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],
- digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]);
+ if (*scrambled++ != (char) (*to++ ^ extra))
+ return 1; /* Wrong password */
}
+ return 0;
}
+static inline uint8 char_val(uint8 X)
+{
+ return (uint) (X >= '0' && X <= '9' ? X-'0' :
+ X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10);
+}
-/*
- Convert password from binary string form to salt form
- Used for MySQL 4.1 password handling
+/*
+ Convert password from hex string (as stored in mysql.user) to binary form.
SYNOPSIS
- get_salt_from_bin_password()
- res OUT Store salt form password here
- password IN Binary password to be converted
- salt IN hashing-salt to be used for salt form generation
-
- RETURN
- none
+ get_salt_from_password_323()
+ res OUT store salt here
+ password IN password string as stored in mysql.user
+ NOTE
+ This function does not have length check for passwords. It will just crash
+ Password hashes in old format must have length divisible by 8
*/
-void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt)
+void get_salt_from_password_323(ulong *res, const char *password)
{
- unsigned char *password_end=password+SCRAMBLE41_LENGTH;
- *res=salt;
- res++;
-
- /* Process password of known length*/
- while (password<password_end)
+ res[0]= res[1]= 0;
+ if (password)
{
- ulong val=0;
- uint i;
- for (i=0 ; i < 4 ; i++)
- val=(val << 8)+(*password++);
- *res++=val;
+ while (*password)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 8 ; i++)
+ val=(val << 4)+char_val(*password++);
+ *res++=val;
+ }
}
}
/*
- Validate password for MySQL 4.1 password handling.
-
+ Convert scrambled password from binary form to asciiz hex string.
SYNOPSIS
- validate_password()
- password IN Encrypted Scramble which we got from the client
- message IN Original scramble which we have sent to the client before
- salt IN Password in the salted form to match to
-
- RETURN
- 0 for correct password
- !0 for invalid password
+ make_password_from_salt_323()
+ to OUT store resulting string password here, at least 17 bytes
+ salt IN password in salt format, 2 ulongs
*/
-my_bool validate_password(const char *password, const char *message,
- ulong *salt)
+void make_password_from_salt_323(char *to, const ulong *salt)
{
- char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */
- char tmpsalt[8]; /* Temporary value to convert salt to string form */
- ulong salt_candidate[6]; /* Computed candidate salt */
- ulong *sc=salt_candidate; /* we need to be able to increment */
- ulong *salt_end;
-
- /* Now we shall get stage1 encrypted password in buffer*/
- password_crypt(password,buffer,message,SCRAMBLE41_LENGTH);
-
- /* For compatibility reasons we use ulong to store salt while we need char */
- sprintf(tmpsalt,"%04x",(unsigned short)salt[0]);
-
- password_hash_stage2(buffer,tmpsalt);
- /* Convert password to salt to compare */
- get_salt_from_bin_password(salt_candidate,(uchar*) buffer,salt[0]);
-
- /* Now we shall get exactly the same password as we have stored for user */
- for (salt_end=salt+5 ; salt < salt_end; )
- if (*++salt != *++sc)
- return 1;
-
- /* Or password correct*/
- return 0;
+ sprintf(to,"%08lx%08lx", salt[0], salt[1]);
}
/*
- Get length of password string which is stored in mysql.user table
+ **************** MySQL 4.1.1 authentification routines *************
+*/
+/*
+ Generate string of printable random characters of requested length
SYNOPSIS
- get_password_length()
- force_old_scramble IN If we wish to use pre 4.1 scramble format
-
- RETURN
- password length >0
+ create_random_string()
+ to OUT buffer for generation; must be at least length+1 bytes
+ long; result string is always null-terminated
+ length IN how many random characters to put in buffer
+ rand_st INOUT structure used for number generation
*/
-int get_password_length(my_bool force_old_scramble)
+void create_random_string(char *to, uint length, struct rand_struct *rand_st)
{
- return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1;
+ char *end= to + length;
+ /* Use pointer arithmetics as it is faster way to do so. */
+ for (; to < end; to++)
+ *to= (char) (my_rnd(rand_st)*94+33);
+ *to= '\0';
}
-/*
- Get version of the password based on mysql.user password string
-
- SYNOPSIS
- get_password_version()
- password IN Password string as stored in mysql.user
-
- RETURN
- 0 for pre 4.1 passwords
- !0 password version char for newer passwords
-*/
+/* Character to use as version identifier for version 4.1 */
-char get_password_version(const char *password)
-{
- if (password==NULL) return 0;
- if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
- return 0;
-}
+#define PVERSION41_CHAR '*'
/*
- Get integer value of Hex character
-
+ Convert given octet sequence to asciiz string of hex characters;
+ str..str+len and 'to' may not overlap.
SYNOPSIS
- char_val()
- X IN Character to find value for
-
- RETURN
- Appropriate integer value
+ octet2hex()
+ buf OUT output buffer. Must be at least 2*len+1 bytes
+ str, len IN the beginning and the length of the input string
*/
-
-
-static inline unsigned int char_val(char X)
+static void
+octet2hex(char *to, const uint8 *str, uint len)
{
- return (uint) (X >= '0' && X <= '9' ? X-'0' :
- X >= 'A' && X <= 'Z' ? X-'A'+10 :
- X-'a'+10);
+ const uint8 *str_end= str + len;
+ for (; str != str_end; ++str)
+ {
+ *to++= _dig_vec[(*str & 0xF0) >> 4];
+ *to++= _dig_vec[*str & 0x0F];
+ }
+ *to= '\0';
}
/*
- Get Binary salt from password as in mysql.user format
-
+ Convert given asciiz string of hex (0..9 a..f) characters to octet
+ sequence.
SYNOPSIS
- get_salt_from_password()
- res OUT Store binary salt here
- password IN Password string as stored in mysql.user
-
- RETURN
- none
-
- NOTE
- This function does not have length check for passwords. It will just crash
- Password hashes in old format must have length divisible by 8
-*/
-
-void get_salt_from_password(ulong *res,const char *password)
+ hex2octet()
+ to OUT buffer to place result; must be at least len/2 bytes
+ str, len IN begin, length for character string; str and to may not
+ overlap; len % 2 == 0
+*/
+
+static void
+hex2octet(uint8 *to, const char *str, uint len)
{
- if (password) /* zero salt corresponds to empty password */
+ const char *str_end= str + len;
+ while (str < str_end)
{
- if (password[0]==PVERSION41_CHAR) /* if new password */
- {
- uint val=0;
- uint i;
- password++; /* skip version identifier */
-
- /*get hashing salt from password and store in in the start of array */
- for (i=0 ; i < 4 ; i++)
- val=(val << 4)+char_val(*password++);
- *res++=val;
- }
- /* We process old passwords the same way as new ones in other case */
-#ifdef EXTRA_DEBUG
- if (strlen(password)%8!=0)
- fprintf(stderr,"Warning: Incorrect password length for salting: %d\n",
- strlen(password));
-#endif
- while (*password)
- {
- ulong val=0;
- uint i;
- for (i=0 ; i < 8 ; i++)
- val=(val << 4)+char_val(*password++);
- *res++=val;
- }
+ register char tmp= char_val(*str++);
+ *to++= (tmp << 4) | char_val(*str++);
}
- return;
}
/*
- Get string version as stored in mysql.user from salt form
-
+ Encrypt/Decrypt function used for password encryption in authentication.
+ Simple XOR is used here but it is OK as we crypt random strings. Note,
+ that XOR(s1, XOR(s1, s2)) == s2, XOR(s1, s2) == XOR(s2, s1)
SYNOPSIS
- make_password_from_salt()
- to OUT Store resulting string password here
- hash_res IN Password in salt format
- password_version
- IN According to which version salt should be treated
-
- RETURN
- none
+ my_crypt()
+ to OUT buffer to hold crypted string; must be at least len bytes
+ long; to and s1 (or s2) may be the same.
+ s1, s2 IN input strings (of equal length)
+ len IN length of s1 and s2
*/
-void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version)
+static void
+my_crypt(char *to, const uchar *s1, const uchar *s2, uint len)
{
- if (!password_version) /* Handling of old passwords. */
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
- else
- if (password_version==PVERSION41_CHAR)
- sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1],
- hash_res[2],hash_res[3],hash_res[4],hash_res[5]);
- else /* Just use empty password if we can't handle it. This should not happen */
- to[0]='\0';
+ const uint8 *s1_end= s1 + len;
+ while (s1 < s1_end)
+ *to++= *s1++ ^ *s2++;
}
/*
- Convert password in salted form to binary string password and hash-salt
- For old password this involes one more hashing
-
+ MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
+ applied to the password string, and then produced octet sequence is
+ converted to hex string.
+ The result of this function is used as return value from PASSWORD() and
+ is stored in the database.
SYNOPSIS
- get_hash_and_password()
- salt IN Salt to convert from
- pversion IN Password version to use
- hash OUT Store zero ended hash here
- bin_password OUT Store binary password here (no zero at the end)
-
- RETURN
- 0 for pre 4.1 passwords
- !0 password version char for newer passwords
+ make_scrambled_password()
+ buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
+ password IN NULL-terminated password string
*/
-void get_hash_and_password(ulong *salt, uint8 pversion, char *hash,
- unsigned char *bin_password)
+void
+make_scrambled_password(char *to, const char *password)
{
- int t;
- ulong* salt_end;
- ulong val;
- SHA1_CONTEXT context;
-
- if (pversion) /* New password version assumed */
- {
- salt_end=salt+5;
- sprintf(hash,"%04x",(unsigned short)salt[0]);
- while (salt<salt_end)
- {
- val=*(++salt);
- for (t=3; t>=0; t--)
- {
- bin_password[t]= (char) (val & 255);
- val>>=8; /* Scroll 8 bits to get next part*/
- }
- bin_password+=4; /* Get to next 4 chars*/
- }
- }
- else
- {
- unsigned char *bp= bin_password; /* Binary password loop pointer */
-
- /* Use zero starting hash as an indication of old password */
- hash[0]=0;
- salt_end=salt+2;
- /* Encode salt using SHA1 here */
- sha1_reset(&context);
- while (salt<salt_end) /* Iterate over these elements*/
- {
- val= *salt;
- for (t=3;t>=0;t--)
- {
- bp[t]= (uchar) (val & 255);
- val>>=8; /* Scroll 8 bits to get next part*/
- }
- bp+= 4; /* Get to next 4 chars*/
- salt++;
- }
- /* Use 8 bytes of binary password for hash */
- sha1_input(&context,(uint8*)bin_password,8);
- sha1_result(&context,(uint8*)bin_password);
- }
+ SHA1_CONTEXT sha1_context;
+ uint8 hash_stage2[SHA1_HASH_SIZE];
+
+ sha1_reset(&sha1_context);
+ /* stage 1: hash password */
+ sha1_input(&sha1_context, (uint8 *) password, strlen(password));
+ sha1_result(&sha1_context, (uint8 *) to);
+ /* stage 2: hash stage1 output */
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE);
+ /* separate buffer is used to pass 'to' in octet2hex */
+ sha1_result(&sha1_context, hash_stage2);
+ /* convert hash_stage2 to hex string */
+ *to++= PVERSION41_CHAR;
+ octet2hex(to, hash_stage2, SHA1_HASH_SIZE);
}
-
+
/*
- Create key from old password to decode scramble
- Used in 4.1 authentication with passwords stored old way
-
+ Produce an obscure octet sequence from password and random
+ string, recieved from the server. This sequence corresponds to the
+ password, but password can not be easily restored from it. The sequence
+ is then sent to the server for validation. Trailing zero is not stored
+ in the buf as it is not needed.
+ This function is used by client to create authenticated reply to the
+ server's greeting.
SYNOPSIS
- create_key_from_old_password()
- passwd IN Password used for key generation
- key OUT Created 20 bytes key
-
- RETURN
- None
+ scramble()
+ buf OUT store scrambled string here. The buf must be at least
+ SHA1_HASH_SIZE bytes long.
+ message IN random message, must be exactly SCRAMBLE_LENGTH long and
+ NULL-terminated.
+ password IN users' password
*/
-
-void create_key_from_old_password(const char *passwd, char *key)
+void
+scramble(char *to, const char *message, const char *password)
{
- char buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */
- ulong salt[6]; /* Salt (large for safety) */
- /* At first hash password to the string stored in password */
- make_scrambled_password(buffer,passwd,1,(struct rand_struct *)NULL);
- /* Now convert it to the salt form */
- get_salt_from_password(salt,buffer);
- /* Finally get hash and bin password from salt */
- get_hash_and_password(salt,0,buffer,(unsigned char*) key);
+ SHA1_CONTEXT sha1_context;
+ uint8 hash_stage1[SHA1_HASH_SIZE];
+ uint8 hash_stage2[SHA1_HASH_SIZE];
+
+ sha1_reset(&sha1_context);
+ /* stage 1: hash password */
+ sha1_input(&sha1_context, (uint8 *) password, strlen(password));
+ sha1_result(&sha1_context, hash_stage1);
+ /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE);
+ sha1_result(&sha1_context, hash_stage2);
+ /* create crypt string as sha1(message, hash_stage2) */;
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
+ sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
+ /* xor allows 'from' and 'to' overlap: lets take advantage of it */
+ sha1_result(&sha1_context, (uint8 *) to);
+ my_crypt(to, (const uchar *) to, hash_stage1, SCRAMBLE_LENGTH);
}
/*
- Scramble string with password
- Used at pre 4.1 authentication phase.
-
+ Check that scrambled message corresponds to the password; the function
+ is used by server to check that recieved reply is authentic.
+ This function does not check lengths of given strings: message must be
+ null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE
+ long (if not, something fishy is going on).
SYNOPSIS
- scramble()
- to OUT Store scrambled message here
- message IN Message to scramble
- password IN Password to use while scrambling
- old_ver IN Forse old version random number generator
-
- RETURN
- End of scrambled string
+ check_scramble()
+ scramble clients' reply, presumably produced by scramble()
+ message original random string, previously sent to client
+ (presumably second argument of scramble()), must be
+ exactly SCRAMBLE_LENGTH long and NULL-terminated.
+ hash_stage2 hex2octet-decoded database entry
+ All params are IN.
+
+ RETURN VALUE
+ 0 password is correct
+ !0 password is invalid
*/
-char *scramble(char *to,const char *message,const char *password,
- my_bool old_ver)
+my_bool
+check_scramble(const char *scramble, const char *message,
+ const uint8 *hash_stage2)
{
- struct rand_struct rand_st;
- ulong hash_pass[2],hash_message[2];
- char message_buffer[9]; /* Real message buffer */
- char *msg=message_buffer;
-
- /* We use special message buffer now as new server can provide longer hash */
-
- memcpy(message_buffer,message,8);
- message_buffer[8]=0;
-
- if (password && password[0])
- {
- char *to_start=to;
- hash_password(hash_pass,password);
- hash_password(hash_message,message_buffer);
- if (old_ver)
- old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
- else
- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
- hash_pass[1] ^ hash_message[1]);
- while (*msg++)
- *to++= (char) (floor(my_rnd(&rand_st)*31)+64);
- if (!old_ver)
- { /* Make it harder to break */
- char extra=(char) (floor(my_rnd(&rand_st)*31));
- while (to_start != to)
- *(to_start++)^=extra;
- }
- }
- *to=0;
- return to;
+ SHA1_CONTEXT sha1_context;
+ uint8 buf[SHA1_HASH_SIZE];
+ uint8 hash_stage2_reassured[SHA1_HASH_SIZE];
+
+ sha1_reset(&sha1_context);
+ /* create key to encrypt scramble */
+ sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
+ sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
+ sha1_result(&sha1_context, buf);
+ /* encrypt scramble */
+ my_crypt((char *) buf, buf, (const uchar *) scramble, SCRAMBLE_LENGTH);
+ /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
+ sha1_result(&sha1_context, hash_stage2_reassured);
+ return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}
/*
- Check scrambled message
- Used for pre 4.1 password handling
+ Convert scrambled password from asciiz hex string to binary form.
+ SYNOPSIS
+ get_salt_from_password()
+ res OUT buf to hold password. Must be at least SHA1_HASH_SIZE
+ bytes long.
+ password IN 4.1.1 version value of user.password
+*/
+
+void get_salt_from_password(uint8 *hash_stage2, const char *password)
+{
+ hex2octet(hash_stage2, password+1 /* skip '*' */, SHA1_HASH_SIZE * 2);
+}
+/*
+ Convert scrambled password from binary form to asciiz hex string.
SYNOPSIS
- scramble()
- scrambled IN Scrambled message to check
- message IN Original message which was scramble
- hash_pass IN Password which should be used for scrambling
- old_ver IN Forse old version random number generator
-
- RETURN
- 0 Password correct
- !0 Password invalid
+ make_password_from_salt()
+ to OUT store resulting string here, 2*SHA1_HASH_SIZE+2 bytes
+ salt IN password in salt format
*/
-my_bool check_scramble(const char *scrambled, const char *message,
- ulong *hash_pass, my_bool old_ver)
+void make_password_from_salt(char *to, const uint8 *hash_stage2)
{
- struct rand_struct rand_st;
- ulong hash_message[2];
- char buff[16],*to,extra; /* Big enough for check */
- const char *pos;
- char message_buffer[SCRAMBLE_LENGTH+1]; /* Copy of message */
-
- /* We need to copy the message as this function can be called for MySQL 4.1
- scramble which is not zero ended and can have zeroes inside
- We could just write zero to proper place in original message but
- this would make it harder to understand code for next generations
- */
-
- memcpy(message_buffer,message,SCRAMBLE_LENGTH); /* Ignore the rest */
- message_buffer[SCRAMBLE_LENGTH]=0;
-
- /* Check if this exactly N bytes. Overwise this is something fishy */
- if (strlen(message_buffer)!=SCRAMBLE_LENGTH)
- return 1; /* Wrong password */
-
- hash_password(hash_message,message_buffer);
- if (old_ver)
- old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
- else
- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
- hash_pass[1] ^ hash_message[1]);
- to=buff;
- for (pos=scrambled ; *pos ; pos++)
- *to++=(char) (floor(my_rnd(&rand_st)*31)+64);
- if (old_ver)
- extra=0;
- else
- extra=(char) (floor(my_rnd(&rand_st)*31));
- to=buff;
- while (*scrambled)
- {
- if (*scrambled++ != (char) (*to++ ^ extra))
- return 1; /* Wrong password */
- }
- return 0;
+ *to++= PVERSION41_CHAR;
+ octet2hex(to, hash_stage2, SHA1_HASH_SIZE);
}
diff --git a/sql/protocol.cc b/sql/protocol.cc
index e90aa7585e2..79420fb71d5 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -28,6 +28,9 @@
#ifndef EMBEDDED_LIBRARY
bool Protocol::net_store_data(const char *from, uint length)
+#else
+bool Protocol_prep::net_store_data(const char *from, uint length)
+#endif
{
ulong packet_length=packet->length();
/*
@@ -43,7 +46,6 @@ bool Protocol::net_store_data(const char *from, uint length)
packet->length((uint) (to+length-packet->ptr()));
return 0;
}
-#endif
/* Send a error string to client */
@@ -349,10 +351,35 @@ send_eof(THD *thd, bool no_flush)
}
DBUG_VOID_RETURN;
}
+
+/*
+ Please client to send scrambled_password in old format.
+ SYNOPSYS
+ send_old_password_request()
+ thd thread handle
+
+ RETURN VALUE
+ 0 ok
+ !0 error
+*/
+
+bool send_old_password_request(THD *thd)
+{
+ static char buff[1]= { (char) 254 };
+ NET *net= &thd->net;
+ return my_net_write(net, buff, 1) || net_flush(net);
+}
+
#endif /* EMBEDDED_LIBRARY */
/*
- Faster net_store_length when we know length is a 32 bit integer
+ Faster net_store_length when we know that length is less than 65536.
+ We keep a separate version for that range because it's widely used in
+ libmysql.
+ uint is used as agrument type because of MySQL type conventions:
+ uint for 0..65536
+ ulong for 0..4294967296
+ ulonglong for bigger numbers.
*/
char *net_store_length(char *pkg, uint length)
@@ -1105,3 +1132,12 @@ bool Protocol_prep::store_time(TIME *tm)
buff[0]=(char) length; // Length is stored first
return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
}
+
+#ifdef EMBEDDED_LIBRARY
+/* Should be removed when we define the Protocol_cursor's future */
+bool Protocol_cursor::write()
+{
+ return Protocol_simple::write();
+}
+#endif
+
diff --git a/sql/protocol.h b/sql/protocol.h
index 05aee12d3d9..94fd303e259 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -53,7 +53,11 @@ public:
bool store(const char *from, CHARSET_INFO *cs);
String *storage_packet() { return packet; }
inline void free() { packet->free(); }
+#ifndef EMBEDDED_LIBRARY
bool write();
+#else
+ virtual bool write();
+#endif
inline bool store(uint32 from)
{ return store_long((longlong) from); }
inline bool store(longlong from)
@@ -121,6 +125,10 @@ public:
Protocol_prep(THD *thd) :Protocol(thd) {}
virtual bool prepare_for_send(List<Item> *item_list);
virtual void prepare_for_resend();
+#ifdef EMBEDDED_LIBRARY
+ virtual bool write();
+ bool net_store_data(const char *from, uint length);
+#endif
virtual bool store_null();
virtual bool store_tiny(longlong from);
virtual bool store_short(longlong from);
@@ -164,8 +172,15 @@ void net_printf(THD *thd,uint sql_errno, ...);
void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0);
void send_eof(THD *thd, bool no_flush=0);
+bool send_old_password_request(THD *thd);
char *net_store_length(char *packet,ulonglong length);
char *net_store_length(char *packet,uint length);
char *net_store_data(char *to,const char *from, uint length);
char *net_store_data(char *to,int32 from);
char *net_store_data(char *to,longlong from);
+
+#ifdef EMBEDDED_LIBRARY
+bool setup_params_data(struct st_prep_stmt *stmt);
+bool setup_params_data_withlog(struct st_prep_stmt *stmt);
+#endif
+
diff --git a/sql/records.cc b/sql/records.cc
index 72a6d480356..7ba9ff0f42f 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -1,4 +1,3 @@
-
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index e9c3b1ed0b0..7c943d4ae53 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -34,7 +34,6 @@ RPL_STATUS rpl_status=RPL_NULL;
pthread_mutex_t LOCK_rpl_status;
pthread_cond_t COND_rpl_status;
HASH slave_list;
-extern const char* any_db;
const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
@@ -154,9 +153,8 @@ int register_slave(THD* thd, uchar* packet, uint packet_length)
SLAVE_INFO *si;
uchar *p= packet, *p_end= packet + packet_length;
- if (check_access(thd, REPL_SLAVE_ACL, any_db))
+ if (check_access(thd, REPL_SLAVE_ACL, any_db,0,0,0))
return 1;
-
if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
goto err2;
@@ -177,7 +175,7 @@ int register_slave(THD* thd, uchar* packet, uint packet_length)
pthread_mutex_lock(&LOCK_slave_list);
unregister_slave(thd,0,0);
- res= hash_insert(&slave_list, (byte*) si);
+ res= my_hash_insert(&slave_list, (byte*) si);
pthread_mutex_unlock(&LOCK_slave_list);
return res;
@@ -250,6 +248,18 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
/* Impossible */
}
+/*
+ Before 4.0.15 we had a member of THD called log_pos, it was meant for
+ failsafe replication code in repl_failsafe.cc which is disabled until
+ it is reworked. Event's log_pos used to be preserved through
+ log-slave-updates to make code in repl_failsafe.cc work (this
+ function, SHOW NEW MASTER); but on the other side it caused unexpected
+ values in Exec_master_log_pos in A->B->C replication setup,
+ synchronization problems in master_pos_wait(), ... So we
+ (Dmitri & Guilhem) removed it.
+
+ So for now this function is broken.
+*/
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
{
@@ -415,6 +425,9 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
return (Slave_log_event*)ev;
}
+/*
+ This function is broken now. See comment for translate_master().
+ */
int show_new_master(THD* thd)
{
@@ -525,7 +538,7 @@ HOSTS";
goto err;
}
si->server_id = server_id;
- hash_insert(&slave_list, (byte*)si);
+ my_hash_insert(&slave_list, (byte*)si);
}
strmake(si->host, row[1], sizeof(si->host)-1);
si->port = atoi(row[port_ind]);
@@ -670,6 +683,17 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
}
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
+
+#ifdef HAVE_OPENSSL
+ if (mi->ssl)
+ mysql_ssl_set(mysql,
+ mi->ssl_key[0]?mi->ssl_key:0,
+ mi->ssl_cert[0]?mi->ssl_cert:0,
+ mi->ssl_ca[0]?mi->ssl_ca:0,
+ mi->ssl_capath[0]?mi->ssl_capath:0,
+ mi->ssl_cipher[0]?mi->ssl_cipher:0);
+#endif
+
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0,
@@ -903,6 +927,12 @@ int load_master_data(THD* thd)
strmake(active_mi->rli.group_master_log_name,active_mi->master_log_name,
sizeof(active_mi->rli.group_master_log_name)-1);
/*
+ Cancel the previous START SLAVE UNTIL, as the fact to download
+ a new copy logically makes UNTIL irrelevant.
+ */
+ clear_until_condition(&active_mi->rli);
+
+ /*
No need to update rli.event* coordinates, they will be when the slave
threads start ; only rli.group* coordinates are necessary here.
*/
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 91583759c70..a44ee96ea0e 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -116,6 +116,8 @@ sys_var_character_set_client sys_character_set_client("character_set_client");
sys_var_character_set_connection sys_character_set_connection("character_set_connection");
sys_var_character_set_results sys_character_set_results("character_set_results");
sys_var_collation_connection sys_collation_connection("collation_connection");
+sys_var_collation_database sys_collation_database("collation_database");
+sys_var_collation_server sys_collation_server("collation_server");
sys_var_bool_ptr sys_concurrent_insert("concurrent_insert",
&myisam_concurrent_insert);
sys_var_long_ptr sys_connect_timeout("connect_timeout",
@@ -216,6 +218,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
&SV::net_retry_count,
fix_net_retry_count);
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
+sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords);
sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
&SV::preload_buff_size);
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
@@ -242,6 +245,7 @@ sys_var_thd_enum sys_query_cache_type("query_cache_type",
&SV::query_cache_type,
&query_cache_type_typelib);
#endif /* HAVE_QUERY_CACHE */
+sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth);
sys_var_long_ptr sys_server_id("server_id",&server_id);
sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
&opt_slave_compressed_protocol);
@@ -379,6 +383,8 @@ sys_var *sys_variables[]=
&sys_character_set_connection,
&sys_character_set_results,
&sys_collation_connection,
+ &sys_collation_database,
+ &sys_collation_server,
&sys_concurrent_insert,
&sys_connect_timeout,
&sys_default_week_format,
@@ -432,6 +438,7 @@ sys_var *sys_variables[]=
&sys_net_wait_timeout,
&sys_net_write_timeout,
&sys_new_mode,
+ &sys_old_passwords,
&sys_preload_buff_size,
&sys_pseudo_thread_id,
&sys_query_cache_size,
@@ -450,6 +457,7 @@ sys_var *sys_variables[]=
#endif
&sys_rpl_recovery_rank,
&sys_safe_updates,
+ &sys_secure_auth,
&sys_select_limit,
&sys_server_id,
#ifdef HAVE_REPLICATION
@@ -505,6 +513,8 @@ struct show_var_st init_vars[]= {
{sys_character_set_connection.name,(char*) &sys_character_set_connection,SHOW_SYS},
{sys_character_set_results.name,(char*) &sys_character_set_results, SHOW_SYS},
{sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
+ {sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS},
+ {sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS},
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR},
@@ -608,6 +618,7 @@ struct show_var_st init_vars[]= {
{sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS},
{sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS},
{sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS},
+ {sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS},
{"open_files_limit", (char*) &open_files_limit, SHOW_LONG},
{"pid_file", (char*) pidfile_name, SHOW_CHAR},
{"log_error", (char*) log_error_file, SHOW_CHAR},
@@ -615,20 +626,21 @@ struct show_var_st init_vars[]= {
{"protocol_version", (char*) &protocol_version, SHOW_INT},
{sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS},
{sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
- {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
- {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
- {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
-#ifdef HAVE_REPLICATION
- {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
-#endif
- {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
#ifdef HAVE_QUERY_CACHE
{sys_query_cache_limit.name,(char*) &sys_query_cache_limit, SHOW_SYS},
{sys_query_cache_min_res_unit.name, (char*) &sys_query_cache_min_res_unit,
SHOW_SYS},
{sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS},
{sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS},
+ {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS},
#endif /* HAVE_QUERY_CACHE */
+ {sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
+ {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS},
+ {sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
+#ifdef HAVE_REPLICATION
+ {sys_relay_log_purge.name, (char*) &sys_relay_log_purge, SHOW_SYS},
+#endif
+ {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
#ifdef HAVE_SMEM
{"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL},
{"shared_memory_base_name", (char*) &shared_memory_base_name, SHOW_CHAR_PTR},
@@ -845,10 +857,12 @@ void fix_max_relay_log_size(THD *thd, enum_var_type type)
bool sys_var_long_ptr::update(THD *thd, set_var *var)
{
ulonglong tmp= var->value->val_int();
+ pthread_mutex_lock(&LOCK_global_system_variables);
if (option_limits)
*value= (ulong) getopt_ull_limit_value(tmp, option_limits);
else
*value= (ulong) tmp;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
return 0;
}
@@ -862,17 +876,21 @@ void sys_var_long_ptr::set_default(THD *thd, enum_var_type type)
bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var)
{
ulonglong tmp= var->value->val_int();
+ pthread_mutex_lock(&LOCK_global_system_variables);
if (option_limits)
*value= (ulonglong) getopt_ull_limit_value(tmp, option_limits);
else
*value= (ulonglong) tmp;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
return 0;
}
void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type)
{
+ pthread_mutex_lock(&LOCK_global_system_variables);
*value= (ulonglong) option_limits->def_value;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
}
@@ -1164,9 +1182,21 @@ Item *sys_var::item(THD *thd, enum_var_type var_type, LEX_STRING *base)
case SHOW_LONG:
return new Item_uint((int32) *(ulong*) value_ptr(thd, var_type, base));
case SHOW_LONGLONG:
- return new Item_int(*(longlong*) value_ptr(thd, var_type, base));
+ {
+ longlong value;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ value= *(longlong*) value_ptr(thd, var_type, base);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return new Item_int(value);
+ }
case SHOW_HA_ROWS:
- return new Item_int((longlong) *(ha_rows*) value_ptr(thd, var_type, base));
+ {
+ ha_rows value;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ value= *(ha_rows*) value_ptr(thd, var_type, base);
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ return new Item_int((longlong) value);
+ }
case SHOW_MY_BOOL:
return new Item_int((int32) *(my_bool*) value_ptr(thd, var_type, base),1);
case SHOW_CHAR:
@@ -1272,7 +1302,7 @@ bool sys_var_collation::check(THD *thd, set_var *var)
String str(buff,sizeof(buff), system_charset_info), *res;
if (!(res=var->value->val_str(&str)))
- res= &empty_string;
+ res= &my_empty_string;
if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))))
{
@@ -1313,6 +1343,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var)
bool sys_var_character_set::update(THD *thd, set_var *var)
{
ci_ptr(thd,var->type)[0]= var->save_result.charset;
+ thd->update_charset();
return 0;
}
@@ -1398,20 +1429,19 @@ CHARSET_INFO **
sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
- return &global_system_variables.character_set_server;
+ return &global_system_variables.collation_server;
else
- return &thd->variables.character_set_server;
+ return &thd->variables.collation_server;
}
void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
- global_system_variables.character_set_server= default_charset_info;
+ global_system_variables.collation_server= default_charset_info;
else
{
- thd->variables.character_set_server= (global_system_variables.
- character_set_server);
+ thd->variables.collation_server= global_system_variables.collation_server;
thd->update_charset();
}
}
@@ -1421,19 +1451,19 @@ CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd,
enum_var_type type)
{
if (type == OPT_GLOBAL)
- return &global_system_variables.character_set_database;
+ return &global_system_variables.collation_database;
else
- return &thd->variables.character_set_database;
+ return &thd->variables.collation_database;
}
void sys_var_character_set_database::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
- global_system_variables.character_set_database= default_charset_info;
+ global_system_variables.collation_database= default_charset_info;
else
{
- thd->variables.character_set_database= thd->db_charset;
+ thd->variables.collation_database= thd->db_charset;
thd->update_charset();
}
}
@@ -1474,6 +1504,77 @@ void sys_var_collation_connection::set_default(THD *thd, enum_var_type type)
}
}
+bool sys_var_collation_database::update(THD *thd, set_var *var)
+{
+ if (var->type == OPT_GLOBAL)
+ global_system_variables.collation_database= var->save_result.charset;
+ else
+ {
+ thd->variables.collation_database= var->save_result.charset;
+ thd->update_charset();
+ }
+ return 0;
+}
+
+
+byte *sys_var_collation_database::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
+ global_system_variables.collation_database :
+ thd->variables.collation_database);
+ return cs ? (byte*) cs->name : (byte*) "NULL";
+}
+
+
+void sys_var_collation_database::set_default(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.collation_database= default_charset_info;
+ else
+ {
+ thd->variables.collation_database= (global_system_variables.
+ collation_database);
+ thd->update_charset();
+ }
+}
+
+
+bool sys_var_collation_server::update(THD *thd, set_var *var)
+{
+ if (var->type == OPT_GLOBAL)
+ global_system_variables.collation_server= var->save_result.charset;
+ else
+ {
+ thd->variables.collation_server= var->save_result.charset;
+ thd->update_charset();
+ }
+ return 0;
+}
+
+
+byte *sys_var_collation_server::value_ptr(THD *thd, enum_var_type type,
+ LEX_STRING *base)
+{
+ CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
+ global_system_variables.collation_server :
+ thd->variables.collation_server);
+ return cs ? (byte*) cs->name : (byte*) "NULL";
+}
+
+
+void sys_var_collation_server::set_default(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.collation_server= default_charset_info;
+ else
+ {
+ thd->variables.collation_server= (global_system_variables.
+ collation_server);
+ thd->update_charset();
+ }
+}
+
bool sys_var_key_buffer_size::update(THD *thd, set_var *var)
{
@@ -1622,6 +1723,7 @@ byte *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type,
bool sys_var_pseudo_thread_id::check(THD *thd, set_var *var)
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (thd->master_access & SUPER_ACL)
return 0;
else
@@ -1629,6 +1731,9 @@ bool sys_var_pseudo_thread_id::check(THD *thd, set_var *var)
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
return 1;
}
+#else
+ return 0;
+#endif
}
@@ -1812,8 +1917,6 @@ static byte *get_sys_var_length(const sys_var *var, uint *length,
void set_var_init()
{
- extern struct my_option my_long_options[]; // From mysqld
-
hash_init(&system_variable_hash, system_charset_info,
array_elements(sys_variables),0,0,
(hash_get_key) get_sys_var_length,0,0);
@@ -1824,7 +1927,7 @@ void set_var_init()
{
(*var)->name_length= strlen((*var)->name);
(*var)->option_limits= find_option(my_long_options, (*var)->name);
- hash_insert(&system_variable_hash, (byte*) *var);
+ my_hash_insert(&system_variable_hash, (byte*) *var);
}
/*
Special cases
@@ -1927,7 +2030,6 @@ int set_var::check(THD *thd)
}
if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
return 1;
-
/* value is a NULL pointer if we are using SET ... = DEFAULT */
if (!value)
{
@@ -1990,17 +2092,25 @@ int set_var_user::update(THD *thd)
int set_var_password::check(THD *thd)
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!user->host.str)
user->host.str= (char*) thd->host_or_ip;
/* Returns 1 as the function sends error to client */
return check_change_password(thd, user->host.str, user->user.str) ? 1 : 0;
+#else
+ return 0;
+#endif
}
int set_var_password::update(THD *thd)
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Returns 1 as the function sends error to client */
return (change_password(thd, user->host.str, user->user.str, password) ?
1 : 0);
+#else
+ return 0;
+#endif
}
/****************************************************************************
diff --git a/sql/set_var.h b/sql/set_var.h
index f06b5ed22d3..812bd6c9420 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -523,6 +523,23 @@ public:
byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
};
+class sys_var_collation_server :public sys_var_collation
+{
+public:
+ sys_var_collation_server(const char *name_arg) :sys_var_collation(name_arg) {}
+ bool update(THD *thd, set_var *var);
+ void set_default(THD *thd, enum_var_type type);
+ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+};
+
+class sys_var_collation_database :public sys_var_collation
+{
+public:
+ sys_var_collation_database(const char *name_arg) :sys_var_collation(name_arg) {}
+ bool update(THD *thd, set_var *var);
+ void set_default(THD *thd, enum_var_type type);
+ byte *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
+};
class sys_var_key_buffer_size :public sys_var
{
@@ -689,6 +706,9 @@ public:
}
};
+/* updated in sql_acl.cc */
+
+extern sys_var_thd_bool sys_old_passwords;
/* For sql_yacc */
struct sys_var_with_base
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index 35202ff4722..662159a9c63 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -30,7 +30,7 @@ install-data-local:
fix_errors:
for lang in @AVAILABLE_LANGUAGES@; \
do \
- ../../extra/comp_err $(srcdir)/$$lang/errmsg.txt $(srcdir)/$$lang/errmsg.sys; \
+ ../../extra/comp_err -C$(srcdir)/charsets/ $(srcdir)/$$lang/errmsg.txt $(srcdir)/$$lang/errmsg.sys; \
done
# Don't update the files from bitkeeper
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 1beffa81671..5a3976822e5 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -1,4 +1,4 @@
-v/*
+/*
Modifikoval Petr -B©najdr, snajdr@pvt.net, snajdr@cpress.cz v.0.01
ISO LATIN-8852-2
Dal-B¹í verze Jan Pazdziora, adelton@fi.muni.cz
@@ -10,6 +10,8 @@ v/*
Thu Nov 30 14:02:52 MET 2000 podle 3.23.28
*/
+character-set=latin2
+
"hashchk",
"isamchk",
"NE",
@@ -251,7 +253,7 @@ v/*
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -263,13 +265,18 @@ v/*
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -278,3 +285,9 @@ v/*
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index c13141fc669..6f43e3eb7f1 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -4,6 +4,8 @@
/* Knud Riishøjgård knudriis@post.tele.dk 99 &&
Carsten H. Pedersen, carsten.pedersen@bitbybit.dk oct. 1999 / aug. 2001. */
+character-set=latin1
+
"hashchk",
"isamchk",
"NEJ",
@@ -245,7 +247,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -257,13 +259,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -272,3 +279,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index b454566f3ba..d372e1c9ff6 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -12,6 +12,8 @@
Translated new error messages.
*/
+character-set=latin1
+
"hashchk",
"isamchk",
"NEE",
@@ -253,7 +255,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -265,13 +267,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -280,3 +287,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 5655ad32d3d..9506e672a05 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -1,6 +1,8 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
+character-set=latin1
+
"hashchk",
"isamchk",
"NO",
@@ -242,7 +244,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -254,8 +256,8 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client"
"All parts of a SPATIAL KEY must be NOT NULL"
"COLLATION '%s' is not valid for CHARACTER SET '%s'"
-"The slave was already running"
-"The slave was already stopped"
+"Slave is already running"
+"Slave has already been stopped"
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)"
"Z_BUF_ERROR: Not enough memory available for zlib"
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)"
@@ -274,3 +276,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format",
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 8e7a7121dfa..8fbf084320e 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -6,6 +6,8 @@
*/
+character-set=latin7
+
"hashchk",
"isamchk",
"EI",
@@ -247,7 +249,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -259,13 +261,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -274,3 +281,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 8a6d786bee8..3eeecce6c33 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -1,6 +1,8 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
+character-set=latin1
+
"hashchk",
"isamchk",
"NON",
@@ -242,7 +244,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -254,13 +256,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -269,3 +276,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index db20cc5dad9..ebedaad6e94 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -10,6 +10,8 @@
2002-12-11
*/
+character-set=latin1
+
"hashchk",
"isamchk",
"Nein",
@@ -263,13 +265,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -278,3 +285,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index f844ee59dab..dfcd8710a15 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -1,6 +1,8 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
+character-set=greek
+
"hashchk",
"isamchk",
"Ï×É",
@@ -242,7 +244,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -254,13 +256,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -269,3 +276,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 7e60515aace..71877f252f9 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -3,6 +3,8 @@
Updated May, 2000
This file is public domain and comes with NO WARRANTY of any kind */
+character-set=latin2
+
"hashchk",
"isamchk",
"NEM",
@@ -244,7 +246,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -256,13 +258,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -271,3 +278,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index a624d90661d..501630aa3ef 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -1,6 +1,8 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
+character-set=latin1
+
"hashchk",
"isamchk",
"NO",
@@ -242,7 +244,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -254,13 +256,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -269,3 +276,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index b5693fe6e41..4a066e2e13f 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -3,6 +3,8 @@
3.22.10-beta euc-japanese (ujis) text
*/
+character-set=ujis
+
"hashchk",
"isamchk",
"NO",
@@ -244,7 +246,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -256,13 +258,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -271,3 +278,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index bc2d6eb9caa..333da3967dc 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -1,6 +1,8 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This È­ÀÏ is public domain and comes with NO WARRANTY of any kind */
+character-set=euckr
+
"hashchk",
"isamchk",
"¾Æ´Ï¿À",
@@ -242,7 +244,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -254,13 +256,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -269,3 +276,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 9bf0d4845c7..7899ac2862b 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -3,6 +3,8 @@
/* Roy-Magne Mo rmo@www.hivolda.no 97 */
+character-set=latin1
+
"hashchk",
"isamchk",
"NEI",
@@ -244,7 +246,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -256,13 +258,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -271,3 +278,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 4a025e7218f..171d5eb7b3a 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -3,6 +3,8 @@
/* Roy-Magne Mo rmo@www.hivolda.no 97 */
+character-set=latin1
+
"hashchk",
"isamchk",
"NEI",
@@ -244,7 +246,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -256,13 +258,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -271,3 +278,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 1a6634fb96c..3e1a101b9d1 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -5,6 +5,8 @@
Charset ISO-8859-2
*/
+character-set=latin2
+
"hashchk",
"isamchk",
"NIE",
@@ -246,7 +248,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -258,13 +260,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -273,3 +280,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 99a940e62ab..af4e210a5b7 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -1,6 +1,9 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
/* Updated by Thiago Delgado Pinto - thiagodp@ieg.com.br - 06.07.2002 */
+
+character-set=latin1
+
"hashchk",
"isamchk",
"NÃO",
@@ -219,26 +222,26 @@
"Não pode acrescentar uma restrição de chave estrangeira",
"Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou",
"Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou",
-"Erro connectando para o master: %-.128s",
+"Erro conectando com o master: %-.128s",
"Erro rodando consulta no master: %-.128s",
"Erro quando executando comando %s: %-.128s",
"Uso errado de %s e %s",
-"Os comandos SELECT usados têm diferentes números de colunas",
-"Não pode executar a consulta porque você tem um conflitante travamento de leitura",
-"Combinação de tabelas transacionais e não transacionais está desativada",
+"Os comandos SELECT usados têm diferente número de colunas",
+"Não posso executar a consulta porque você tem um conflito de travamento de leitura",
+"Mistura de tabelas transacional e não-transacional está desabilitada",
"Opção '%s' usada duas vezes no comando",
-"Usuário '%-.64s' há excedido o '%s' de recursos (atual valor: %ld)",
-"Acesso negado. Você necessita o privilégio %-.128s para essa operação",
+"Usuário '%-.64s' tem excedido o '%s' recurso (atual valor: %ld)",
+"Acesso negado. Você precisa o privilégio %-.128s para essa operação",
"Variável '%-.64s' é uma LOCAL variável e não pode ser usada com SET GLOBAL",
-"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL",
-"Variável '%-.64s' não tem um valor default (padrão)",
+"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL",
+"Variável '%-.64s' não tem um valor padrão",
"Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'",
-"Tipo de argumento errado para a variável '%-.64s'",
+"Tipo errado de argumento para variável '%-.64s'",
"Variável '%-.64s' somente pode ser configurada, não lida",
-"Uso/localização errada de '%s'",
+"Errado uso/colocação de '%s'",
"Esta versão de MySQL não suporta ainda '%s'",
-"Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
+"Obteve fatal erro %d: '%-.128s' do master quando lendo dados do binary log",
+"Slave SQL thread ignorado a consulta devido às normas de replicação-*-tabela"
"Definição errada da chave estrangeira para '%-.64s': %s",
"Referência da chave e referência da tabela não coincidem",
"Error de cardinalidade (mais/menos que %d colunas)",
@@ -261,6 +264,11 @@
"Z_MEM_ERROR: Não suficiente espaço no buffer emissor para zlib (provavelmente, o comprimento dos dados descomprimidos está corrupto)",
"Z_DATA_ERROR: Dados de entrada está corrupto para zlib",
"%d linha(s) foi(foram) cortada(s) por group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Usando engine de armazenamento %s para tabela '%s'",
"Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'",
"Can't drop one or more of the requested users"
@@ -269,3 +277,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 61591d54d40..0dffb09e9f7 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -5,6 +5,8 @@
e-mail: tzoompy@cs.washington.edu
*/
+character-set=latin2
+
"hashchk",
"isamchk",
"NU",
@@ -246,7 +248,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -258,13 +260,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -273,3 +280,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index b1876f83008..389cb581717 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -3,6 +3,8 @@
This file is public domain and comes with NO WARRANTY of any kind */
/* charset: KOI8-R */
+character-set=koi8r
+
"hashchk",
"isamchk",
"îåô",
@@ -256,13 +258,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -271,3 +278,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ"
+"ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 9e2a37e4053..0f461a9e718 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -7,6 +7,8 @@
Charset: cp1250
*/
+character-set=cp1250
+
"hashchk",
"isamchk",
"NE",
@@ -237,7 +239,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -249,13 +251,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -264,3 +271,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index a96d512cb72..dc07eb0a54e 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -9,6 +9,8 @@
Date: Streda 11. November 1998 20:58:15
*/
+character-set=latin2
+
"hashchk",
"isamchk",
"NIE",
@@ -250,7 +252,7 @@
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -262,13 +264,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -277,3 +284,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index df18b8bf7f0..a1b36887282 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -2,6 +2,9 @@
This file is public domain and comes with NO WARRANTY of any kind
Traduccion por Miguel Angel Fernandez Roiz -- LoboCom Sistemas, s.l.
From June 28, 2001 translated by Miguel Solorzano miguel@mysql.com */
+
+character-set=latin1
+
"hashchk",
"isamchk",
"NO",
@@ -223,27 +226,27 @@
"Error de coneccion a master: %-128s",
"Error executando el query en master: %-128%",
"Error de %s: %-128%",
-"Wrong usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied. You need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Wrong argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Wrong usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
-"Slave SQL thread ignored the query because of replicate-*-table rules",
+"Equivocado uso de %s y %s",
+"El comando SELECT usado tiene diferente número de columnas",
+"No puedo ejecutar el query porque usted tiene conflicto de traba de lectura",
+"Mezla de transancional y no-transancional tablas está deshabilitada",
+"Opción '%s' usada dos veces en el comando",
+"Usuario '%-.64s' ha excedido el recurso '%s' (actual valor: %ld)",
+"Acceso negado. Usted necesita el privilegio %-.128s para esta operación",
+"Variable '%-.64s' es una LOCAL variable y no puede ser usada con SET GLOBAL",
+"Variable '%-.64s' es una GLOBAL variable y no puede ser configurada con SET GLOBAL",
+"Variable '%-.64s' no tiene un valor patrón",
+"Variable '%-.64s' no puede ser configurada para el valor de '%-.64s'",
+"Tipo de argumento equivocado para variable '%-.64s'",
+"Variable '%-.64s' solamente puede ser configurada, no leída",
+"Equivocado uso/colocación de '%s'",
+"Esta versión de MySQL no soporta todavia '%s'",
+"Recibió fatal error %d: '%-.128s' del master cuando leyendo datos del binary log",
+"Slave SQL thread ignorado el query debido a las reglas de replicación-*-tabla"
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
-"Subselect returns more than 1 record",
+"Subquery returns more than 1 row",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
@@ -255,13 +258,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -270,3 +278,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 07187f7ca34..e0d0bea47d2 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -1,6 +1,8 @@
/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
+character-set=latin1
+
"hashchk",
"isamchk",
"NO",
@@ -242,10 +244,10 @@
"Felaktig FOREIGN KEY-definition för '%-.64s': %s",
"Nyckelreferensen och tabellreferensen stämmer inte överens",
"Kardinalitetsfel (fler/färre än %d kolumner)",
-"Subselect returnerade mer än 1 rad",
+"Subquery returnerade mer än 1 rad",
"Okänd PREPARED STATEMENT id (%ld) var given till %s",
"Hjälpdatabasen finns inte eller är skadad",
-"Cyklisk referens i subselect",
+"Cyklisk referens i subqueries",
"Konvertar kolumn '%s' från %s till %s",
"Referens '%-.64s' stöds inte (%s)",
"Varje 'derived table' måste ha sitt eget alias",
@@ -261,6 +263,11 @@
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d rad(er) kapades av group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Använder handler %s för tabell '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -269,3 +276,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index a0604ba862c..a2133049741 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -6,6 +6,8 @@
* Version: 13/09/2001 mysql-3.23.41
*/
+character-set=koi8u
+
"hashchk",
"isamchk",
"î¶",
@@ -259,13 +261,18 @@
"Client does not support authentication protocol requested by server; consider upgrading MySQL client",
"All parts of a SPATIAL KEY must be NOT NULL",
"COLLATION '%s' is not valid for CHARACTER SET '%s'",
-"The slave was already running",
-"The slave was already stopped",
+"Slave is already running",
+"Slave has already been stopped",
"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)",
"Z_BUF_ERROR: Not enough memory available for zlib",
"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)",
"Z_DATA_ERROR: Input data was corrupted for zlib",
"%d line(s) was(were) cut by group_concat()",
+"Record count is fewer than the column count at row %ld";
+"Record count is more than the column count at row %ld";
+"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld";
+"Data truncated, out of range for column '%s' at row %ld";
+"Data truncated for column '%s' at row %ld"
"Using storage engine %s for table '%s'",
"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'",
"Can't drop one or more of the requested users"
@@ -274,3 +281,9 @@
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
"Unknown collation: '%-.64s'",
+"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
+"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
+"óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d",
+"Wrong parameter or combination of parameters for START SLAVE UNTIL"
+"It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart"
+"SQL thread is not to be started so UNTIL options are ignored"
diff --git a/sql/slave.cc b/sql/slave.cc
index d45cf1aa8b9..641707aab2f 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -238,10 +238,12 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
*errmsg=0;
pthread_mutex_t *log_lock=rli->relay_log.get_log_lock();
- pthread_mutex_lock(log_lock);
+
if (need_data_lock)
pthread_mutex_lock(&rli->data_lock);
+ pthread_mutex_lock(log_lock);
+
/* Close log file and free buffers if it's already open */
if (rli->cur_log_fd >= 0)
{
@@ -304,10 +306,12 @@ err:
if (!relay_log_purge)
rli->log_space_limit= 0;
pthread_cond_broadcast(&rli->data_cond);
+
+ pthread_mutex_unlock(log_lock);
+
if (need_data_lock)
pthread_mutex_unlock(&rli->data_lock);
- pthread_mutex_unlock(log_lock);
DBUG_RETURN ((*errmsg) ? 1 : 0);
}
@@ -786,7 +790,7 @@ int add_table_rule(HASH* h, const char* table_spec)
e->tbl_name = e->db + (dot - table_spec) + 1;
e->key_len = len;
memcpy(e->db, table_spec, len);
- (void)hash_insert(h, (byte*)e);
+ (void)my_hash_insert(h, (byte*)e);
return 0;
}
@@ -1505,11 +1509,10 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
DBUG_ENTER("wait_for_relay_log_space");
pthread_mutex_lock(&rli->log_space_lock);
- save_proc_info = thd->proc_info;
- thd->proc_info = "Waiting for relay log space to free";
save_proc_info= thd->enter_cond(&rli->log_space_cond,
&rli->log_space_lock,
- "Waiting for relay log space to free");
+ "\
+Waiting for the SQL slave thread to free enough relay log space");
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
@@ -1544,6 +1547,7 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli)
DBUG_RETURN(0);
}
+
void init_master_info_with_options(MASTER_INFO* mi)
{
mi->master_log_name[0] = 0;
@@ -1554,11 +1558,24 @@ void init_master_info_with_options(MASTER_INFO* mi)
if (master_user)
strmake(mi->user, master_user, sizeof(mi->user) - 1);
if (master_password)
- strmake(mi->password, master_password, HASH_PASSWORD_LENGTH);
+ strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
mi->port = master_port;
mi->connect_retry = master_connect_retry;
+
+ mi->ssl= master_ssl;
+ if (master_ssl_ca)
+ strmake(mi->ssl_ca, master_ssl_ca, sizeof(mi->ssl_ca)-1);
+ if (master_ssl_capath)
+ strmake(mi->ssl_capath, master_ssl_capath, sizeof(mi->ssl_capath)-1);
+ if (master_ssl_cert)
+ strmake(mi->ssl_cert, master_ssl_cert, sizeof(mi->ssl_cert)-1);
+ if (master_ssl_cipher)
+ strmake(mi->ssl_cipher, master_ssl_cipher, sizeof(mi->ssl_cipher)-1);
+ if (master_ssl_key)
+ strmake(mi->ssl_key, master_ssl_key, sizeof(mi->ssl_key)-1);
}
+
void clear_last_slave_error(RELAY_LOG_INFO* rli)
{
//Clear the errors displayed by SHOW SLAVE STATUS
@@ -1566,6 +1583,24 @@ void clear_last_slave_error(RELAY_LOG_INFO* rli)
rli->last_slave_errno=0;
}
+
+/*
+ Reset UNTIL condition for RELAY_LOG_INFO
+ SYNOPSYS
+ clear_until_condition()
+ rli - RELAY_LOG_INFO structure where UNTIL condition should be reset
+ */
+void clear_until_condition(RELAY_LOG_INFO* rli)
+{
+ rli->until_condition= RELAY_LOG_INFO::UNTIL_NONE;
+ rli->until_log_name[0]= 0;
+ rli->until_log_pos= 0;
+}
+
+
+#define LINES_IN_MASTER_INFO_WITH_SSL 14
+
+
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
bool abort_if_no_master_info_file)
@@ -1643,25 +1678,87 @@ file '%s')", fname);
}
mi->fd = fd;
- int port, connect_retry, master_log_pos;
-
+ int port, connect_retry, master_log_pos, ssl= 0, lines;
+ char *first_non_digit;
+
+ /*
+ Starting from 4.1.x master.info has new format. Now its
+ first line contains number of lines in file. By reading this
+ number we will be always distinguish to which version our
+ master.info corresponds to. We can't simply count lines in
+ file since versions before 4.1.x could generate files with more
+ lines than needed.
+ If first line doesn't contain a number or contain number less than
+ 14 then such file is treated like file from pre 4.1.1 version.
+ There is no ambiguity when reading an old master.info, as before
+ 4.1.1, the first line contained the binlog's name, which is either
+ empty or has an extension (contains a '.'), so can't be confused
+ with an integer.
+
+ So we're just reading first line and trying to figure which version
+ is this.
+ */
+
+ /*
+ The first row is temporarily stored in mi->master_log_name,
+ if it is line count and not binlog name (new format) it will be
+ overwritten by the second row later.
+ */
if (init_strvar_from_file(mi->master_log_name,
sizeof(mi->master_log_name), &mi->file,
- "") ||
- init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
+ ""))
+ goto errwithmsg;
+
+ lines= strtoul(mi->master_log_name, &first_non_digit, 10);
+
+ if (mi->master_log_name[0]!='\0' &&
+ *first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
+ { // Seems to be new format
+ if (init_strvar_from_file(mi->master_log_name,
+ sizeof(mi->master_log_name), &mi->file, ""))
+ goto errwithmsg;
+ }
+ else
+ lines= 7;
+
+ if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file,
master_host) ||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
master_user) ||
- init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
- master_password) ||
+ init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
+ &mi->file, master_password) ||
init_intvar_from_file(&port, &mi->file, master_port) ||
init_intvar_from_file(&connect_retry, &mi->file,
master_connect_retry))
- {
- sql_print_error("Error reading master configuration");
- goto err;
- }
+ goto errwithmsg;
+
+ /*
+ If file has ssl part use it even if we have server without
+ SSL support. But these option will be ignored later when
+ slave will try connect to master, so in this case warning
+ is printed.
+ */
+ if (lines >= LINES_IN_MASTER_INFO_WITH_SSL &&
+ (init_intvar_from_file(&ssl, &mi->file, master_ssl) ||
+ init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
+ &mi->file, master_ssl_ca) ||
+ init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
+ &mi->file, master_ssl_capath) ||
+ init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
+ &mi->file, master_ssl_cert) ||
+ init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
+ &mi->file, master_ssl_cipher) ||
+ init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
+ &mi->file, master_ssl_key)))
+ goto errwithmsg;
+#ifndef HAVE_OPENSSL
+ if (ssl)
+ sql_print_error("SSL information in the master info file "
+ "('%s') are ignored because this MySQL slave was compiled "
+ "without SSL support.", fname);
+#endif /* HAVE_OPENSSL */
+
/*
This has to be handled here as init_intvar_from_file can't handle
my_off_t types
@@ -1669,6 +1766,7 @@ file '%s')", fname);
mi->master_log_pos= (my_off_t) master_log_pos;
mi->port= (uint) port;
mi->connect_retry= (uint) connect_retry;
+ mi->ssl= (my_bool) ssl;
}
DBUG_PRINT("master_info",("log_file_name: %s position: %ld",
mi->master_log_name,
@@ -1685,7 +1783,10 @@ file '%s')", fname);
sql_print_error("Failed to flush master info file");
pthread_mutex_unlock(&mi->data_lock);
DBUG_RETURN(error);
-
+
+errwithmsg:
+ sql_print_error("Error reading master configuration");
+
err:
if (fd >= 0)
{
@@ -1820,6 +1921,22 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
MYSQL_TYPE_LONGLONG));
field_list.push_back(new Item_return_int("Relay_log_space", 10,
MYSQL_TYPE_LONGLONG));
+ field_list.push_back(new Item_empty_string("Until_condition", 6));
+ field_list.push_back(new Item_empty_string("Until_Log_File", FN_REFLEN));
+ field_list.push_back(new Item_return_int("Until_Log_pos", 10,
+ MYSQL_TYPE_LONGLONG));
+ field_list.push_back(new Item_empty_string("Master_SSL_Allowed", 7));
+ field_list.push_back(new Item_empty_string("Master_SSL_CA_File",
+ sizeof(mi->ssl_ca)));
+ field_list.push_back(new Item_empty_string("Master_SSL_CA_Path",
+ sizeof(mi->ssl_capath)));
+ field_list.push_back(new Item_empty_string("Master_SSL_Cert",
+ sizeof(mi->ssl_cert)));
+ field_list.push_back(new Item_empty_string("Master_SSL_Cipher",
+ sizeof(mi->ssl_cipher)));
+ field_list.push_back(new Item_empty_string("Master_SSL_Key",
+ sizeof(mi->ssl_key)));
+
if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
@@ -1868,6 +1985,25 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store((uint32) mi->rli.slave_skip_counter);
protocol->store((ulonglong) mi->rli.group_master_log_pos);
protocol->store((ulonglong) mi->rli.log_space_total);
+
+ protocol->store(
+ mi->rli.until_condition==RELAY_LOG_INFO::UNTIL_NONE ? "None":
+ ( mi->rli.until_condition==RELAY_LOG_INFO::UNTIL_MASTER_POS? "Master":
+ "Relay"), &my_charset_bin);
+ protocol->store(mi->rli.until_log_name, &my_charset_bin);
+ protocol->store((ulonglong) mi->rli.until_log_pos);
+
+#ifdef HAVE_OPENSSL
+ protocol->store(mi->ssl? "Yes":"No", &my_charset_bin);
+#else
+ protocol->store(mi->ssl? "Ignored":"No", &my_charset_bin);
+#endif
+ protocol->store(mi->ssl_ca, &my_charset_bin);
+ protocol->store(mi->ssl_capath, &my_charset_bin);
+ protocol->store(mi->ssl_cert, &my_charset_bin);
+ protocol->store(mi->ssl_cipher, &my_charset_bin);
+ protocol->store(mi->ssl_key, &my_charset_bin);
+
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
@@ -1886,11 +2022,22 @@ bool flush_master_info(MASTER_INFO* mi)
DBUG_ENTER("flush_master_info");
DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));
+ /*
+ In certain cases this code may create master.info files that seems
+ corrupted, because of extra lines filled with garbage in the end
+ file (this happens if new contents take less space than previous
+ contents of file). But because of number of lines in the first line
+ of file we don't care about this garbage.
+ */
+
my_b_seek(file, 0L);
- my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
- mi->master_log_name, llstr(mi->master_log_pos, lbuf),
+ my_b_printf(file, "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n",
+ LINES_IN_MASTER_INFO_WITH_SSL,
+ mi->master_log_name, llstr(mi->master_log_pos, lbuf),
mi->host, mi->user,
- mi->password, mi->port, mi->connect_retry);
+ mi->password, mi->port, mi->connect_retry,
+ (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
+ mi->ssl_cipher, mi->ssl_key);
flush_io_cache(file);
DBUG_RETURN(0);
}
@@ -1901,11 +2048,11 @@ st_relay_log_info::st_relay_log_info()
cur_log_old_open_count(0), group_master_log_pos(0), log_space_total(0),
ignore_log_space_limit(0), slave_skip_counter(0), abort_pos_wait(0),
slave_run_id(0), sql_thd(0), last_slave_errno(0), inited(0), abort_slave(0),
- slave_running(0)
+ slave_running(0), until_condition(UNTIL_NONE), until_log_pos(0)
{
group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0;
- last_slave_error[0]=0;
-
+ last_slave_error[0]=0; until_log_name[0]= 0;
+
bzero((char*) &info_file, sizeof(info_file));
bzero((char*) &cache_buf, sizeof(cache_buf));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
@@ -2058,7 +2205,8 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
DBUG_PRINT("info",("Waiting for master update"));
const char* msg = thd->enter_cond(&data_cond, &data_lock,
- "Waiting for master update");
+ "Waiting for the SQL slave thread to \
+advance position");
/*
We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
will wake us up.
@@ -2125,7 +2273,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
thd->master_access= ~0;
thd->priv_user = 0;
thd->slave_thread = 1;
- thd->options = (((opt_log_slave_updates) ? OPTION_BIN_LOG:0) | OPTION_AUTO_IS_NULL) ;
+ thd->options = ((opt_log_slave_updates) ? OPTION_BIN_LOG:0) |
+ OPTION_AUTO_IS_NULL;
+ /*
+ It's nonsense to constraint the slave threads with max_join_size; if a
+ query succeeded on master, we HAVE to execute it.
+ */
+ thd->variables.max_join_size= HA_POS_ERROR;
thd->client_capabilities = CLIENT_LOCAL_FILES;
thd->real_id=pthread_self();
pthread_mutex_lock(&LOCK_thread_count);
@@ -2145,11 +2299,8 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
- if (thd->variables.max_join_size == HA_POS_ERROR)
- thd->options |= OPTION_BIG_SELECTS;
-
if (thd_type == SLAVE_THD_SQL)
- thd->proc_info= "Waiting for the next event in slave queue";
+ thd->proc_info= "Waiting for the next event in relay log";
else
thd->proc_info= "Waiting for master update";
thd->version=refresh_version;
@@ -2303,9 +2454,10 @@ server_errno=%d)",
return packet_error;
}
- if (len == 1)
+ /* Check if eof packet */
+ if (len < 8 && mysql->net.read_pos[0] == 254)
{
- sql_print_error("Slave: received 0 length packet from server, apparent\
+ sql_print_error("Slave: received end packet from server, apparent\
master shutdown: %s",
mysql_error(mysql));
return packet_error;
@@ -2337,13 +2489,126 @@ point. If you are sure that your master is ok, run this query manually on the\
}
}
+/*
+ Check if condition stated in UNTIL clause of START SLAVE is reached.
+ SYNOPSYS
+ st_relay_log_info::is_until_satisfied()
+ DESCRIPTION
+ Checks if UNTIL condition is reached. Uses caching result of last
+ comparison of current log file name and target log file name. So cached
+ value should be invalidated if current log file name changes
+ (see st_relay_log_info::notify_... functions).
+
+ This caching is needed to avoid of expensive string comparisons and
+ strtol() conversions needed for log names comparison. We don't need to
+ compare them each time this function is called, we only need to do this
+ when current log name changes. If we have UNTIL_MASTER_POS condition we
+ need to do this only after Rotate_log_event::exec_event() (which is
+ rare, so caching gives real benifit), and if we have UNTIL_RELAY_POS
+ condition then we should invalidate cached comarison value after
+ inc_group_relay_log_pos() which called for each group of events (so we
+ have some benefit if we have something like queries that use
+ autoincrement or if we have transactions).
+
+ Should be called ONLY if until_condition != UNTIL_NONE !
+ RETURN VALUE
+ true - condition met or error happened (condition seems to have
+ bad log file name)
+ false - condition not met
+*/
+
+bool st_relay_log_info::is_until_satisfied()
+{
+ const char *log_name;
+ ulonglong log_pos;
+
+ DBUG_ASSERT(until_condition != UNTIL_NONE);
+
+ if (until_condition == UNTIL_MASTER_POS)
+ {
+ log_name= group_master_log_name;
+ log_pos= group_master_log_pos;
+ }
+ else
+ { /* until_condition == UNTIL_RELAY_POS */
+ log_name= group_relay_log_name;
+ log_pos= group_relay_log_pos;
+ }
+
+ if (until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_UNKNOWN)
+ {
+ /*
+ We have no cached comaprison results so we should compare log names
+ and cache result
+ */
+
+ DBUG_ASSERT(*log_name || log_pos == 0);
+
+ if (*log_name)
+ {
+ const char *basename= log_name + dirname_length(log_name);
+
+ const char *q= (const char*)(fn_ext(basename)+1);
+ if (strncmp(basename, until_log_name, (int)(q-basename)) == 0)
+ {
+ /* Now compare extensions. */
+ char *q_end;
+ ulong log_name_extension= strtoul(q, &q_end, 10);
+ if (log_name_extension < until_log_name_extension)
+ until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_LESS;
+ else
+ until_log_names_cmp_result=
+ (log_name_extension > until_log_name_extension) ?
+ UNTIL_LOG_NAMES_CMP_GREATER : UNTIL_LOG_NAMES_CMP_EQUAL ;
+ }
+ else
+ {
+ /* Probably error so we aborting */
+ sql_print_error("Slave SQL thread is stopped because UNTIL "
+ "condition is bad.");
+ return true;
+ }
+ }
+ else
+ return until_log_pos == 0;
+ }
+
+ return ((until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_EQUAL &&
+ log_pos >= until_log_pos) ||
+ until_log_names_cmp_result == UNTIL_LOG_NAMES_CMP_GREATER);
+}
+
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
+ /*
+ We acquire this mutex since we need it for all operations except
+ event execution. But we will release it in places where we will
+ wait for something for example inside of next_event().
+ */
+ pthread_mutex_lock(&rli->data_lock);
+
+ if (rli->until_condition!=RELAY_LOG_INFO::UNTIL_NONE &&
+ rli->is_until_satisfied())
+ {
+ sql_print_error("Slave SQL thread stopped because it reached its"
+ " UNTIL position");
+ /*
+ Setting abort_slave flag because we do not want additional message about
+ error in query execution to be printed.
+ */
+ rli->abort_slave= 1;
+ pthread_mutex_unlock(&rli->data_lock);
+ return 1;
+ }
+
Log_event * ev = next_event(rli);
+
DBUG_ASSERT(rli->sql_thd==thd);
+
if (sql_slave_killed(thd,rli))
{
+ pthread_mutex_unlock(&rli->data_lock);
delete ev;
return 1;
}
@@ -2351,7 +2616,6 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
int type_code = ev->get_type_code();
int exec_res;
- pthread_mutex_lock(&rli->data_lock);
/*
Skip queries originating from this server or number of
@@ -2380,7 +2644,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
pthread_mutex_unlock(&rli->data_lock);
delete ev;
return 0; // avoid infinite update loops
- }
+ }
pthread_mutex_unlock(&rli->data_lock);
thd->server_id = ev->server_id; // use the original server id for logging
@@ -2389,7 +2653,6 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
if (!ev->when)
ev->when = time(NULL);
ev->thd = thd;
- thd->log_pos = ev->log_pos;
exec_res = ev->exec_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
delete ev;
@@ -2397,7 +2660,8 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
}
else
{
- sql_print_error("\
+ pthread_mutex_unlock(&rli->data_lock);
+ slave_print_error(rli, 0, "\
Could not parse relay log event entry. The possible reasons are: the master's \
binary log is corrupted (you can check this by running 'mysqlbinlog' on the \
binary log), the slave's relay log is corrupted (you can check this by running \
@@ -2472,7 +2736,7 @@ slave_begin:
}
- thd->proc_info = "connecting to master";
+ thd->proc_info = "Connecting to master";
// we can get killed during safe_connect
if (!safe_connect(thd, mysql, mi))
sql_print_error("Slave I/O thread: connected to master '%s@%s:%d',\
@@ -2519,7 +2783,7 @@ dump");
goto err;
}
- thd->proc_info = "Waiting to reconnect after a failed dump request";
+ thd->proc_info= "Waiting to reconnect after a failed binlog dump request";
end_server(mysql);
/*
First time retry immediately, assuming that we can recover
@@ -2540,7 +2804,7 @@ dump");
goto err;
}
- thd->proc_info = "Reconnecting after a failed dump request";
+ thd->proc_info = "Reconnecting after a failed binlog dump request";
if (!suppress_warnings)
sql_print_error("Slave I/O thread: failed dump request, \
reconnecting to try again, log '%s' at postion %s", IO_RPL_LOG_NAME,
@@ -2559,7 +2823,13 @@ after reconnect");
while (!io_slave_killed(thd,mi))
{
bool suppress_warnings= 0;
- thd->proc_info = "Reading master update";
+ /*
+ We say "waiting" because read_event() will wait if there's nothing to
+ read. But if there's something to read, it will not wait. The important
+ thing is to not confuse users by saying "reading" whereas we're in fact
+ receiving nothing.
+ */
+ thd->proc_info = "Waiting for master to send event";
ulong event_len = read_event(mysql, mi, &suppress_warnings);
if (io_slave_killed(thd,mi))
{
@@ -2586,7 +2856,7 @@ max_allowed_packet",
mysql_error(mysql));
goto err;
}
- thd->proc_info = "Waiting to reconnect after a failed read";
+ thd->proc_info = "Waiting to reconnect after a failed master event read";
end_server(mysql);
if (retry_count++)
{
@@ -2602,7 +2872,7 @@ max_allowed_packet",
reconnect after a failed read");
goto err;
}
- thd->proc_info = "Reconnecting after a failed read";
+ thd->proc_info = "Reconnecting after a failed master event read";
if (!suppress_warnings)
sql_print_error("Slave I/O thread: Failed reading log event, \
reconnecting to retry, log '%s' position %s", IO_RPL_LOG_NAME,
@@ -2619,7 +2889,7 @@ reconnect done to recover from failed read");
} // if (event_len == packet_error)
retry_count=0; // ok event, reset retry counter
- thd->proc_info = "Queueing event from master";
+ thd->proc_info = "Queueing master event to the relay log";
if (queue_event(mi,(const char*)mysql->net.read_pos + 1,
event_len))
{
@@ -2801,7 +3071,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
while (!sql_slave_killed(thd,rli))
{
- thd->proc_info = "Processing master log event";
+ thd->proc_info = "Reading event from the relay log";
DBUG_ASSERT(rli->sql_thd == thd);
THD_CHECK_SENTRY(thd);
if (exec_relay_log_event(thd,rli))
@@ -2833,6 +3103,11 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
/* When master_pos_wait() wakes up it will check this and terminate */
rli->slave_running= 0;
+ /*
+ Going out of the transaction. Necessary to mark it, in case the user
+ restarts replication from a non-transactional statement (with CHANGE
+ MASTER).
+ */
/* Wake up master_pos_wait() */
pthread_mutex_unlock(&rli->data_lock);
DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
@@ -2908,7 +3183,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
in the loop
*/
{
- Append_block_log_event aev(thd,0,0,0);
+ Append_block_log_event aev(thd,0,0,0,0);
for (;;)
{
@@ -2921,7 +3196,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
if (unlikely(!num_bytes)) /* eof */
{
net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
- Execute_load_log_event xev(thd,0);
+ Execute_load_log_event xev(thd,0,0);
xev.log_pos = mi->master_log_pos;
if (unlikely(mi->rli.relay_log.append(&xev)))
{
@@ -3048,6 +3323,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
tmp_buf[event_len]=0; // Create_file constructor wants null-term buffer
buf = (const char*)tmp_buf;
}
+ /*
+ This will transform LOAD_EVENT into CREATE_FILE_EVENT, ask the master to
+ send the loaded file, and write it to the relay log in the form of
+ Append_block/Exec_load (the SQL thread needs the data, as that thread is not
+ connected to the master).
+ */
Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
1 /*old format*/ );
if (unlikely(!ev))
@@ -3075,6 +3356,12 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
inc_pos= 0;
break;
case CREATE_FILE_EVENT:
+ /*
+ Yes it's possible to have CREATE_FILE_EVENT here, even if we're in
+ queue_old_event() which is for 3.23 events which don't comprise
+ CREATE_FILE_EVENT. This is because read_log_event() above has just
+ transformed LOAD_EVENT into CREATE_FILE_EVENT.
+ */
{
/* We come here when and only when tmp_buf != 0 */
DBUG_ASSERT(tmp_buf);
@@ -3273,6 +3560,17 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &slave_net_timeout);
+
+#ifdef HAVE_OPENSSL
+ if (mi->ssl)
+ mysql_ssl_set(mysql,
+ mi->ssl_key[0]?mi->ssl_key:0,
+ mi->ssl_cert[0]?mi->ssl_cert:0,
+ mi->ssl_ca[0]?mi->ssl_ca:0,
+ mi->ssl_capath[0]?mi->ssl_capath:0,
+ mi->ssl_cipher[0]?mi->ssl_cipher:0);
+#endif
+
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset_info->csname);
/* This one is not strictly needed but we have it here for completeness */
mysql_options(mysql, MYSQL_SET_CHARSET_DIR, (char *) charsets_dir);
@@ -3440,17 +3738,18 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
pthread_mutex_t *log_lock = rli->relay_log.get_log_lock();
const char* errmsg=0;
THD* thd = rli->sql_thd;
+
DBUG_ENTER("next_event");
DBUG_ASSERT(thd != 0);
/*
For most operations we need to protect rli members with data_lock,
- so we will hold it for the most of the loop below
- However, we will release it whenever it is worth the hassle,
- and in the cases when we go into a pthread_cond_wait() with the
- non-data_lock mutex
+ so we assume calling function acquired this mutex for us and we will
+ hold it for the most of the loop below However, we will release it
+ whenever it is worth the hassle, and in the cases when we go into a
+ pthread_cond_wait() with the non-data_lock mutex
*/
- pthread_mutex_lock(&rli->data_lock);
+ safe_mutex_assert_owner(&rli->data_lock);
while (!sql_slave_killed(thd,rli))
{
@@ -3509,7 +3808,6 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
DBUG_ASSERT(thd==rli->sql_thd);
if (hot_log)
pthread_mutex_unlock(log_lock);
- pthread_mutex_unlock(&rli->data_lock);
DBUG_RETURN(ev);
}
DBUG_ASSERT(thd==rli->sql_thd);
@@ -3574,7 +3872,7 @@ Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
pthread_mutex_unlock(&rli->log_space_lock);
pthread_cond_broadcast(&rli->log_space_cond);
// Note that wait_for_update unlocks lock_log !
- rli->relay_log.wait_for_update(rli->sql_thd);
+ rli->relay_log.wait_for_update(rli->sql_thd, 1);
// re-acquire data lock since we released it earlier
pthread_mutex_lock(&rli->data_lock);
continue;
@@ -3685,7 +3983,6 @@ event(errno: %d cur_log->error: %d)",
errmsg = "slave SQL thread was killed";
err:
- pthread_mutex_unlock(&rli->data_lock);
if (errmsg)
sql_print_error("Error reading relay log event: %s", errmsg);
DBUG_RETURN(0);
diff --git a/sql/slave.h b/sql/slave.h
index 0cd291a50f8..b52648005d3 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -32,6 +32,30 @@
*****************************************************************************/
+/*
+ MUTEXES in replication:
+
+ LOCK_active_mi: this is meant for multimaster, when we can switch from a
+ master to another. It protects active_mi. We don't care of it for the moment,
+ as active_mi never moves (it's created at startup and deleted at shutdown,
+ and not changed: it always points to the same MASTER_INFO struct), because we
+ don't have multimaster. So for the moment, mi does not move, and mi->rli does
+ not either.
+
+ In MASTER_INFO: run_lock, data_lock
+ run_lock protects all information about the run state: slave_running, and the
+ existence of the I/O thread (to stop/start it, you need this mutex).
+ data_lock protects some moving members of the struct: counters (log name,
+ position) and relay log (MYSQL_LOG object).
+
+ In RELAY_LOG_INFO: run_lock, data_lock
+ see MASTER_INFO
+
+ In MYSQL_LOG: LOCK_log, LOCK_index of the binlog and the relay log
+ LOCK_log: when you write to it. LOCK_index: when you create/delete a binlog
+ (so that you have to update the .index file).
+*/
+
extern ulong master_retry_count;
extern MY_BITMAP slave_error_mask;
extern bool use_slave_mask;
@@ -43,10 +67,6 @@ extern my_bool opt_log_slave_updates;
extern ulonglong relay_log_space_limit;
struct st_master_info;
-extern "C" {
- extern ulong slave_net_timeout;
-};
-
enum enum_binlog_formats {
BINLOG_FORMAT_CURRENT=0, /* 0 is important for easy 'if (mi->old_format)' */
BINLOG_FORMAT_323_LESS_57,
@@ -213,9 +233,55 @@ typedef struct st_relay_log_info
bool inited;
volatile bool abort_slave, slave_running;
+ /*
+ Condition and its parameters from START SLAVE UNTIL clause.
+
+ UNTIL condition is tested with is_until_satisfied() method that is
+ called by exec_relay_log_event(). is_until_satisfied() caches the result
+ of the comparison of log names because log names don't change very often;
+ this cache is invalidated by parts of code which change log names with
+ notify_*_log_name_updated() methods. (They need to be called only if SQL
+ thread is running).
+ */
+
+ enum {UNTIL_NONE= 0, UNTIL_MASTER_POS, UNTIL_RELAY_POS} until_condition;
+ char until_log_name[FN_REFLEN];
+ ulonglong until_log_pos;
+ /* extension extracted from log_name and converted to int */
+ ulong until_log_name_extension;
+ /*
+ Cached result of comparison of until_log_name and current log name
+ -2 means unitialised, -1,0,1 are comarison results
+ */
+ enum
+ {
+ UNTIL_LOG_NAMES_CMP_UNKNOWN= -2, UNTIL_LOG_NAMES_CMP_LESS= -1,
+ UNTIL_LOG_NAMES_CMP_EQUAL= 0, UNTIL_LOG_NAMES_CMP_GREATER= 1
+ } until_log_names_cmp_result;
+
st_relay_log_info();
~st_relay_log_info();
+ /*
+ Invalidate cached until_log_name and group_relay_log_name comparison
+ result. Should be called after any update of group_realy_log_name if
+ there chances that sql_thread is running.
+ */
+ inline void notify_group_relay_log_name_update()
+ {
+ if (until_condition==UNTIL_RELAY_POS)
+ until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
+ }
+
+ /*
+ The same as previous but for group_master_log_name.
+ */
+ inline void notify_group_master_log_name_update()
+ {
+ if (until_condition==UNTIL_MASTER_POS)
+ until_log_names_cmp_result= UNTIL_LOG_NAMES_CMP_UNKNOWN;
+ }
+
inline void inc_event_relay_log_pos(ulonglong val)
{
event_relay_log_pos+= val;
@@ -229,6 +295,9 @@ typedef struct st_relay_log_info
group_relay_log_pos= event_relay_log_pos;
strmake(group_relay_log_name,event_relay_log_name,
sizeof(group_relay_log_name)-1);
+
+ notify_group_relay_log_name_update();
+
/*
If the slave does not support transactions and replicates a transaction,
users should not trust group_master_log_pos (which they can display with
@@ -248,6 +317,10 @@ typedef struct st_relay_log_info
int wait_for_pos(THD* thd, String* log_name, longlong log_pos,
longlong timeout);
+
+ /* Check if UNTIL condition is satisfied. See slave.cc for more. */
+ bool is_until_satisfied();
+
} RELAY_LOG_INFO;
@@ -288,16 +361,19 @@ Log_event* next_event(RELAY_LOG_INFO* rli);
typedef struct st_master_info
{
+ /* the variables below are needed because we can change masters on the fly */
char master_log_name[FN_REFLEN];
char host[HOSTNAME_LENGTH+1];
char user[USERNAME_LENGTH+1];
char password[MAX_PASSWORD_LENGTH+1];
+ my_bool ssl; // enables use of SSL connection if true
+ char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
+ char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
my_off_t master_log_pos;
File fd; // we keep the file open, so we need to remember the file pointer
IO_CACHE file;
- /* the variables below are needed because we can change masters on the fly */
pthread_mutex_t data_lock,run_lock;
pthread_cond_t data_cond,start_cond,stop_cond;
THD *io_thd;
@@ -315,10 +391,13 @@ typedef struct st_master_info
volatile ulong slave_run_id;
st_master_info()
- :fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT),
+ :ssl(0), fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT),
abort_slave(0),slave_running(0), slave_run_id(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
+ ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
+ ssl_cipher[0]= 0; ssl_key[0]= 0;
+
bzero((char*) &file, sizeof(file));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
@@ -431,6 +510,7 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...);
void end_slave(); /* clean up */
void init_master_info_with_options(MASTER_INFO* mi);
+void clear_until_condition(RELAY_LOG_INFO* rli);
void clear_last_slave_error(RELAY_LOG_INFO* rli);
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
@@ -468,6 +548,10 @@ extern my_string master_user, master_password, master_host,
master_info_file, relay_log_info_file, report_user, report_host,
report_password;
+extern my_bool master_ssl;
+extern my_string master_ssl_ca, master_ssl_capath, master_ssl_cert,
+ master_ssl_cipher, master_ssl_key;
+
extern I_List<i_string> replicate_do_db, replicate_ignore_db;
extern I_List<i_string_pair> replicate_rewrite_db;
extern I_List<THD> threads;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 9738c0c5d9e..179da6096de 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -34,6 +34,7 @@
#include <m_ctype.h>
#include <stdarg.h>
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
class acl_entry :public hash_filo_element
{
@@ -51,7 +52,7 @@ static byte* acl_entry_get_key(acl_entry *entry,uint *length,
return (byte*) entry->key;
}
-#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+17)
+#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+USERNAME_LENGTH+1)
static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex;
@@ -68,12 +69,54 @@ static ulong get_sort(uint count,...);
static void init_check_host(void);
static ACL_USER *find_acl_user(const char *host, const char *user);
static bool update_user_table(THD *thd, const char *host, const char *user,
- const char *new_password);
+ const char *new_password, uint new_password_len);
static void update_hostname(acl_host_and_ip *host, const char *hostname);
static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
const char *ip);
/*
+ Convert scrambled password to binary form, according to scramble type,
+ Binary form is stored in user.salt.
+*/
+
+static
+void
+set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
+{
+ if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ {
+ get_salt_from_password(acl_user->salt, password);
+ acl_user->salt_len= SCRAMBLE_LENGTH;
+ }
+ else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
+ {
+ get_salt_from_password_323((ulong *) acl_user->salt, password);
+ acl_user->salt_len= SCRAMBLE_LENGTH_323;
+ }
+ else
+ acl_user->salt_len= 0;
+}
+
+/*
+ This after_update function is used when user.password is less than
+ SCRAMBLE_LENGTH bytes.
+*/
+
+static void restrict_update_of_old_passwords_var(THD *thd,
+ enum_var_type var_type)
+{
+ if (var_type == OPT_GLOBAL)
+ {
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ global_system_variables.old_passwords= 1;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ }
+ else
+ thd->variables.old_passwords= 1;
+}
+
+
+/*
Read grant privileges from the privilege tables in the 'mysql' database.
SYNOPSIS
@@ -114,8 +157,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (!(thd=new THD))
DBUG_RETURN(1); /* purecov: inspected */
thd->store_globals();
- /* Use passwords according to command line option */
- use_old_passwords= opt_old_passwords;
acl_cache->clear(1); // Clear locked hostname cache
thd->db= my_strdup("mysql",MYF(0));
@@ -172,103 +213,126 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
- if (table->field[2]->field_length == 8 &&
- protocol_version == PROTOCOL_VERSION)
+ if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
- sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
- protocol_version=9; /* purecov: tested */
+ sql_print_error("Fatal error: mysql.user table is damaged or in "
+ "unsupported 3.20 format.");
+ goto end;
}
DBUG_PRINT("info",("user table fields: %d, password length: %d",
table->fields, table->field[2]->field_length));
- if (table->field[2]->field_length < 45 && !use_old_passwords)
+
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
+ {
+ if (opt_secure_auth)
+ {
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ sql_print_error("Fatal error: mysql.user table is in old format, "
+ "but server started with --secure-auth option.");
+ goto end;
+ }
+ sys_old_passwords.after_update= restrict_update_of_old_passwords_var;
+ if (global_system_variables.old_passwords)
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ else
+ {
+ global_system_variables.old_passwords= 1;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ sql_print_error("mysql.user table is not updated to new password format; "
+ "Disabling new password usage until "
+ "mysql_fix_privilege_tables is run");
+ }
+ thd->variables.old_passwords= 1;
+ }
+ else
{
- sql_print_error("mysql.user table is not updated to new password format; Disabling new password usage until mysql_fix_privilege_tables is run");
- use_old_passwords= 1;
+ sys_old_passwords.after_update= 0;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
}
allow_all_hosts=0;
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_USER user;
- uint length=0;
- update_hostname(&user.host,get_field(&mem, table->field[0]));
- user.user=get_field(&mem, table->field[1]);
- user.password=get_field(&mem, table->field[2]);
- if (user.password && (length=(uint) strlen(user.password)) == 8 &&
- protocol_version == PROTOCOL_VERSION)
- {
- sql_print_error(
- "Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)",
- user.user ? user.user : ""); /* purecov: tested */
- }
- else /* non empty and not short passwords */
- {
- user.pversion=get_password_version(user.password);
- /* Only passwords of specific lengths depending on version are allowed */
- if ((!user.pversion && (length % 8 || length > 16)) ||
- (user.pversion && length != 45))
- {
- sql_print_error(
- "Found invalid password for user: '%s'@'%s'; Ignoring user",
- user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
- continue; /* purecov: tested */
+ update_hostname(&user.host, get_field(&mem, table->field[0]));
+ user.user= get_field(&mem, table->field[1]);
+ const char *password= get_field(&mem, table->field[2]);
+ uint password_len= password ? strlen(password) : 0;
+ set_user_salt(&user, password, password_len);
+ if (user.salt_len == 0 && password_len != 0)
+ {
+ switch (password_len) {
+ case 45: /* 4.1: to be removed */
+ sql_print_error("Found 4.1 style password for user '%s@%s'. "
+ "Ignoring user. "
+ "You should change password for this user.",
+ user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : "");
+ break;
+ default:
+ sql_print_error("Found invalid password for user: '%s@%s'; "
+ "Ignoring user", user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : "");
+ break;
}
}
- get_salt_from_password(user.salt,user.password);
- user.access=get_access(table,3) & GLOBAL_ACLS;
- user.sort=get_sort(2,user.host.hostname,user.user);
- user.hostname_length= (user.host.hostname ?
- (uint) strlen(user.host.hostname) : 0);
- if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
- {
- char *ssl_type=get_field(&mem, table->field[24]);
- if (!ssl_type)
- user.ssl_type=SSL_TYPE_NONE;
- else if (!strcmp(ssl_type, "ANY"))
- user.ssl_type=SSL_TYPE_ANY;
- else if (!strcmp(ssl_type, "X509"))
- user.ssl_type=SSL_TYPE_X509;
- else /* !strcmp(ssl_type, "SPECIFIED") */
- user.ssl_type=SSL_TYPE_SPECIFIED;
-
- user.ssl_cipher= get_field(&mem, table->field[25]);
- user.x509_issuer= get_field(&mem, table->field[26]);
- user.x509_subject= get_field(&mem, table->field[27]);
-
- char *ptr = get_field(&mem, table->field[28]);
- user.user_resource.questions=atoi(ptr);
- ptr = get_field(&mem, table->field[29]);
- user.user_resource.updates=atoi(ptr);
- ptr = get_field(&mem, table->field[30]);
- user.user_resource.connections=atoi(ptr);
- if (user.user_resource.questions || user.user_resource.updates ||
- user.user_resource.connections)
- mqh_used=1;
- }
- else
+ else // password is correct
{
- user.ssl_type=SSL_TYPE_NONE;
- bzero((char *)&(user.user_resource),sizeof(user.user_resource));
-#ifndef TO_BE_REMOVED
- if (table->fields <= 13)
- { // Without grant
- if (user.access & CREATE_ACL)
- user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
+ user.access= get_access(table,3) & GLOBAL_ACLS;
+ user.sort= get_sort(2,user.host.hostname,user.user);
+ user.hostname_length= (user.host.hostname ?
+ (uint) strlen(user.host.hostname) : 0);
+ if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
+ {
+ char *ssl_type=get_field(&mem, table->field[24]);
+ if (!ssl_type)
+ user.ssl_type=SSL_TYPE_NONE;
+ else if (!strcmp(ssl_type, "ANY"))
+ user.ssl_type=SSL_TYPE_ANY;
+ else if (!strcmp(ssl_type, "X509"))
+ user.ssl_type=SSL_TYPE_X509;
+ else /* !strcmp(ssl_type, "SPECIFIED") */
+ user.ssl_type=SSL_TYPE_SPECIFIED;
+
+ user.ssl_cipher= get_field(&mem, table->field[25]);
+ user.x509_issuer= get_field(&mem, table->field[26]);
+ user.x509_subject= get_field(&mem, table->field[27]);
+
+ char *ptr = get_field(&mem, table->field[28]);
+ user.user_resource.questions=atoi(ptr);
+ ptr = get_field(&mem, table->field[29]);
+ user.user_resource.updates=atoi(ptr);
+ ptr = get_field(&mem, table->field[30]);
+ user.user_resource.connections=atoi(ptr);
+ if (user.user_resource.questions || user.user_resource.updates ||
+ user.user_resource.connections)
+ mqh_used=1;
}
- /* Convert old privileges */
- user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
- if (user.access & FILE_ACL)
- user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
- if (user.access & PROCESS_ACL)
- user.access|= SUPER_ACL | EXECUTE_ACL;
+ else
+ {
+ user.ssl_type=SSL_TYPE_NONE;
+ bzero((char *)&(user.user_resource),sizeof(user.user_resource));
+#ifndef TO_BE_REMOVED
+ if (table->fields <= 13)
+ { // Without grant
+ if (user.access & CREATE_ACL)
+ user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
+ }
+ /* Convert old privileges */
+ user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
+ if (user.access & FILE_ACL)
+ user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
+ if (user.access & PROCESS_ACL)
+ user.access|= SUPER_ACL | EXECUTE_ACL;
#endif
+ }
+ VOID(push_dynamic(&acl_users,(gptr) &user));
+ if (!user.host.hostname || user.host.hostname[0] == wild_many &&
+ !user.host.hostname[1])
+ allow_all_hosts=1; // Anyone can connect
}
- VOID(push_dynamic(&acl_users,(gptr) &user));
- if (!user.host.hostname || user.host.hostname[0] == wild_many &&
- !user.host.hostname[1])
- allow_all_hosts=1; // Anyone can connect
}
qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
sizeof(ACL_USER),(qsort_cmp) acl_compare);
@@ -469,136 +533,109 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/*
- Prepare crypted scramble to be sent to the client
-*/
-
-void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble)
-{
- /* Binary password format to be used for generation*/
- char bin_password[SCRAMBLE41_LENGTH];
- /* Generate new long scramble for the thread */
- create_random_string(SCRAMBLE41_LENGTH,&thd->rand,thd->scramble);
- thd->scramble[SCRAMBLE41_LENGTH]=0;
- /* Get binary form, First 4 bytes of prepared scramble is salt */
- get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble,
- (unsigned char*) bin_password);
- /* Store "*" as identifier for old passwords */
- if (!acl_user->pversion)
- prepared_scramble[0]='*';
- /* Finally encrypt password to get prepared scramble */
- password_crypt(thd->scramble, prepared_scramble+4, bin_password,
- SCRAMBLE41_LENGTH);
-}
-
-
-/*
- Get master privilges for user (priviliges for all tables).
- Required before connecting to MySQL
+ Seek ACL entry for a user, check password, SSL cypher, and if
+ everything is OK, update THD user data and USER_RESOURCES struct.
- As we have 2 stage handshake now we cache user not to lookup
- it second time. At the second stage we do not lookup user in case
- we already know it;
+ IMPLEMENTATION
+ This function does not check if the user has any sensible privileges:
+ only user's existence and validity is checked.
+ Note, that entire operation is protected by acl_cache_lock.
+ SYNOPSIS
+ acl_getroot()
+ thd thread handle. If all checks are OK,
+ thd->priv_user, thd->master_access are updated.
+ thd->host, thd->ip, thd->user are used for checks.
+ mqh user resources; on success mqh is reset, else
+ unchanged
+ passwd scrambled & crypted password, recieved from client
+ (to check): thd->scramble or thd->scramble_323 is
+ used to decrypt passwd, so they must contain
+ original random string,
+ passwd_len length of passwd, must be one of 0, 8,
+ SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
+ 'thd' and 'mqh' are updated on success; other params are IN.
+
+ RETURN VALUE
+ 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
+ updated
+ 1 user not found or authentification failure
+ 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
+ -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
*/
-ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
- const char *password,const char *message,char **priv_user,
- char *priv_host, bool old_ver, USER_RESOURCES *mqh,
- char *prepared_scramble, uint *cur_priv_version,
- ACL_USER **cached_user)
+int acl_getroot(THD *thd, USER_RESOURCES *mqh,
+ const char *passwd, uint passwd_len)
{
- ulong user_access=NO_ACCESS;
- *priv_user= (char*) user;
- bool password_correct= 0;
- int stage= (*cached_user != NULL); /* NULL passed as first stage */
- ACL_USER *acl_user= NULL;
+ ulong user_access= NO_ACCESS;
+ int res= 1;
+ ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot");
- bzero((char*) mqh, sizeof(USER_RESOURCES));
if (!initialized)
{
- // If no data allow anything
- DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */
+ /*
+ here if mysqld's been started with --skip-grant-tables option.
+ */
+ thd->priv_user= (char *) ""; // privileges for
+ *thd->priv_host= '\0'; // the user are unknown
+ thd->master_access= ~NO_ACCESS; // everything is allowed
+ bzero((char*) mqh, sizeof(*mqh));
+ DBUG_RETURN(0);
}
+
VOID(pthread_mutex_lock(&acl_cache->lock));
/*
- Get possible access from user_list. This is or'ed to others not
- fully specified
-
- If we have cached user use it, in other case look it up.
+ Find acl entry in user database. Note, that find_acl_user is not the same,
+ because it doesn't take into account the case when user is not empty,
+ but acl_user->user is empty
*/
- if (stage && (*cur_priv_version == priv_version))
- acl_user= *cached_user;
- else
+ for (uint i=0 ; i < acl_users.elements ; i++)
{
- for (uint i=0 ; i < acl_users.elements ; i++)
+ ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
+ if (!acl_user_tmp->user || !strcmp(thd->user, acl_user_tmp->user))
{
- ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user_search->user || !strcmp(user,acl_user_search->user))
+ if (compare_hostname(&acl_user_tmp->host, thd->host, thd->ip))
{
- if (compare_hostname(&acl_user_search->host,host,ip))
+ /* check password: it should be empty or valid */
+ if (passwd_len == acl_user_tmp->salt_len)
{
- /* Found mathing user */
- acl_user= acl_user_search;
- /* Store it as a cache */
- *cached_user= acl_user;
- *cur_priv_version= priv_version;
- break;
+ if (acl_user_tmp->salt_len == 0 ||
+ acl_user_tmp->salt_len == SCRAMBLE_LENGTH &&
+ check_scramble(passwd, thd->scramble, acl_user_tmp->salt) == 0 ||
+ check_scramble_323(passwd, thd->scramble,
+ (ulong *) acl_user_tmp->salt) == 0)
+ {
+ acl_user= acl_user_tmp;
+ res= 0;
+ }
}
+ else if (passwd_len == SCRAMBLE_LENGTH &&
+ acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
+ res= -1;
+ else if (passwd_len == SCRAMBLE_LENGTH_323 &&
+ acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
+ res= 2;
+ /* linear search complete: */
+ break;
}
}
}
-
- /* Now we have acl_user found and may start our checks */
+ /*
+ This was moved to separate tree because of heavy HAVE_OPENSSL case.
+ If acl_user is not null, res is 0.
+ */
if (acl_user)
{
- /* Password should present for both or absend for both */
- if (!acl_user->password && !*password)
- password_correct=1;
- else if (!acl_user->password || !*password)
- {
- *cached_user= 0; // Impossible to connect
- }
- else
- {
- /* New version password is checked differently */
- if (acl_user->pversion)
- {
- if (stage) /* We check password only on the second stage */
- {
- if (!validate_password(password,message,acl_user->salt))
- password_correct=1;
- }
- else /* First stage - just prepare scramble */
- prepare_scramble(thd,acl_user,prepared_scramble);
- }
- /* Old way to check password */
- else
- {
- /* Checking the scramble at any stage. First - old clients */
- if (!check_scramble(password,message,acl_user->salt,
- (my_bool) old_ver))
- password_correct=1;
- else if (!stage) /* Here if password incorrect */
- {
- /* At the first stage - prepare scramble */
- prepare_scramble(thd,acl_user,prepared_scramble);
- }
- }
- }
- }
-
- /* If user not found password_correct will also be zero */
- if (!password_correct)
- goto unlock_and_exit;
-
- /* OK. User found and password checked continue validation */
-
- {
+ /* OK. User found and password checked continue validation */
Vio *vio=thd->net.vio;
+#ifdef HAVE_OPENSSL
+ SSL *ssl= (SSL*) vio->ssl_arg;
+#endif
+
/*
At this point we know that user is allowed to connect
from given host by given username/password pair. Now
@@ -607,26 +644,26 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
*/
switch (acl_user->ssl_type) {
case SSL_TYPE_NOT_SPECIFIED: // Impossible
- case SSL_TYPE_NONE: /* SSL is not required to connect */
- user_access=acl_user->access;
+ case SSL_TYPE_NONE: // SSL is not required
+ user_access= acl_user->access;
break;
#ifdef HAVE_OPENSSL
- case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ case SSL_TYPE_ANY: // Any kind of SSL is ok
if (vio_type(vio) == VIO_TYPE_SSL)
- user_access=acl_user->access;
+ user_access= acl_user->access;
break;
case SSL_TYPE_X509: /* Client should have any valid certificate. */
/*
Connections with non-valid certificates are dropped already
in sslaccept() anyway, so we do not check validity here.
-
+
We need to check for absence of SSL because without SSL
we should reject connection.
*/
if (vio_type(vio) == VIO_TYPE_SSL &&
- SSL_get_verify_result(vio->ssl_) == X509_V_OK &&
- SSL_get_peer_certificate(vio->ssl_))
- user_access=acl_user->access;
+ SSL_get_verify_result(ssl) == X509_V_OK &&
+ SSL_get_peer_certificate(ssl))
+ user_access= acl_user->access;
break;
case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
/*
@@ -636,89 +673,83 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
use.
*/
if (vio_type(vio) != VIO_TYPE_SSL ||
- SSL_get_verify_result(vio->ssl_) != X509_V_OK)
+ SSL_get_verify_result(ssl) != X509_V_OK)
break;
if (acl_user->ssl_cipher)
{
DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
- if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
- user_access=acl_user->access;
+ acl_user->ssl_cipher,SSL_get_cipher(ssl)));
+ if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
+ user_access= acl_user->access;
else
{
if (global_system_variables.log_warnings)
sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'",
acl_user->ssl_cipher,
- SSL_get_cipher(vio->ssl_));
- user_access=NO_ACCESS;
+ SSL_get_cipher(ssl));
break;
}
}
/* Prepare certificate (if exists) */
DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ X509* cert=SSL_get_peer_certificate(ssl);
DBUG_PRINT("info",("checkpoint 2"));
/* If X509 issuer is speified, we check it... */
if (acl_user->x509_issuer)
{
- DBUG_PRINT("info",("checkpoint 3"));
+ DBUG_PRINT("info",("checkpoint 3"));
char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
acl_user->x509_issuer, ptr));
- if (strcmp(acl_user->x509_issuer, ptr))
- {
- if (global_system_variables.log_warnings)
- sql_print_error("X509 issuer mismatch: should be '%s' but is '%s'",
- acl_user->x509_issuer, ptr);
- user_access=NO_ACCESS;
- free(ptr);
- break;
- }
- user_access=acl_user->access;
- free(ptr);
+ if (strcmp(acl_user->x509_issuer, ptr))
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_error("X509 issuer mismatch: should be '%s' "
+ "but is '%s'", acl_user->x509_issuer, ptr);
+ free(ptr);
+ break;
+ }
+ user_access= acl_user->access;
+ free(ptr);
}
DBUG_PRINT("info",("checkpoint 4"));
/* X509 subject is specified, we check it .. */
if (acl_user->x509_subject)
{
- char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
- acl_user->x509_subject, ptr));
- if (strcmp(acl_user->x509_subject,ptr))
- {
- if (global_system_variables.log_warnings)
- sql_print_error("X509 subject mismatch: '%s' vs '%s'",
- acl_user->x509_subject, ptr);
- user_access=NO_ACCESS;
- }
- else
- user_access=acl_user->access;
- free(ptr);
+ char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
+ acl_user->x509_subject, ptr));
+ if (strcmp(acl_user->x509_subject,ptr))
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_error("X509 subject mismatch: '%s' vs '%s'",
+ acl_user->x509_subject, ptr);
+ }
+ else
+ user_access= acl_user->access;
+ free(ptr);
}
break;
-#else /* HAVE_OPENSSL */
+#else /* HAVE_OPENSSL */
default:
/*
- If we don't have SSL but SSL is required for this user the
- authentication should fail.
- */
+ If we don't have SSL but SSL is required for this user the
+ authentication should fail.
+ */
break;
#endif /* HAVE_OPENSSL */
}
- }
-
- *mqh=acl_user->user_resource;
- if (!acl_user->user)
- *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+ thd->master_access= user_access;
+ thd->priv_user= acl_user->user ? thd->user : (char *) "";
+ *mqh= acl_user->user_resource;
- if (acl_user->host.hostname)
- strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME);
- else
- *priv_host= 0;
-
-unlock_and_exit:
+ if (acl_user->host.hostname)
+ strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ else
+ *thd->priv_host= 0;
+ }
VOID(pthread_mutex_unlock(&acl_cache->lock));
- DBUG_RETURN(user_access);
+ DBUG_RETURN(res);
}
@@ -729,8 +760,9 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
return (byte*) buff->host.hostname;
}
+
static void acl_update_user(const char *user, const char *host,
- const char *password,
+ const char *password, uint password_len,
enum SSL_type ssl_type,
const char *ssl_cipher,
const char *x509_issuer,
@@ -766,20 +798,9 @@ static void acl_update_user(const char *user, const char *host,
acl_user->x509_subject= (x509_subject ?
strdup_root(&mem,x509_subject) : 0);
}
- if (password)
- {
- if (!password[0]) /* If password is empty set it to null */
- {
- acl_user->password=0;
- acl_user->pversion=0; // just initialize
- }
- else
- {
- acl_user->password=(char*) ""; // Just point at something
- get_salt_from_password(acl_user->salt,password);
- acl_user->pversion=get_password_version(acl_user->password);
- }
- }
+
+ set_user_salt(acl_user, password, password_len);
+ /* search complete: */
break;
}
}
@@ -788,7 +809,7 @@ static void acl_update_user(const char *user, const char *host,
static void acl_insert_user(const char *user, const char *host,
- const char *password,
+ const char *password, uint password_len,
enum SSL_type ssl_type,
const char *ssl_cipher,
const char *x509_issuer,
@@ -799,7 +820,6 @@ static void acl_insert_user(const char *user, const char *host,
ACL_USER acl_user;
acl_user.user=*user ? strdup_root(&mem,user) : 0;
update_hostname(&acl_user.host,strdup_root(&mem,host));
- acl_user.password=0;
acl_user.access=privileges;
acl_user.user_resource = *mqh;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
@@ -809,12 +829,8 @@ static void acl_insert_user(const char *user, const char *host,
acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0;
acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
- if (password)
- {
- acl_user.password=(char*) ""; // Just point at something
- get_salt_from_password(acl_user.salt,password);
- acl_user.pversion=get_password_version(password);
- }
+
+ set_user_salt(&acl_user, password, password_len);
VOID(push_dynamic(&acl_users,(gptr) &acl_user));
if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many
@@ -970,51 +986,6 @@ exit:
return (db_access & host_access);
}
-
-int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
-{
- reg3 int flag;
- DBUG_ENTER("wild_case_compare");
- DBUG_PRINT("enter",("str: '%s' wildstr: '%s'",str,wildstr));
- while (*wildstr)
- {
- while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
- {
- if (*wildstr == wild_prefix && wildstr[1])
- wildstr++;
- if (my_toupper(cs, *wildstr++) !=
- my_toupper(cs, *str++)) DBUG_RETURN(1);
- }
- if (! *wildstr ) DBUG_RETURN (*str != 0);
- if (*wildstr++ == wild_one)
- {
- if (! *str++) DBUG_RETURN (1); /* One char; skip */
- }
- else
- { /* Found '*' */
- if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
- flag=(*wildstr != wild_many && *wildstr != wild_one);
- do
- {
- if (flag)
- {
- char cmp;
- if ((cmp= *wildstr) == wild_prefix && wildstr[1])
- cmp=wildstr[1];
- cmp=my_toupper(cs, cmp);
- while (*str && my_toupper(cs, *str) != cmp)
- str++;
- if (!*str) DBUG_RETURN (1);
- }
- if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
- } while (*str++);
- DBUG_RETURN(1);
- }
- }
- DBUG_RETURN (*str != '\0');
-}
-
-
/*
Check if there are any possible matching entries for this host
@@ -1054,7 +1025,7 @@ static void init_check_host(void)
else if (!hash_search(&acl_check_hosts,(byte*) &acl_user->host,
(uint) strlen(acl_user->host.hostname)))
{
- if (hash_insert(&acl_check_hosts,(byte*) acl_user))
+ if (my_hash_insert(&acl_check_hosts,(byte*) acl_user))
{ // End of memory
allow_all_hosts=1; // Should never happen
DBUG_VOID_RETURN;
@@ -1121,7 +1092,7 @@ bool check_change_password(THD *thd, const char *host, const char *user)
(strcmp(thd->user,user) ||
my_strcasecmp(&my_charset_latin1, host, thd->host_or_ip)))
{
- if (check_access(thd, UPDATE_ACL, "mysql",0,1))
+ if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
return(1);
}
if (!thd->slave_thread && !thd->user[0])
@@ -1151,7 +1122,6 @@ bool check_change_password(THD *thd, const char *host, const char *user)
bool change_password(THD *thd, const char *host, const char *user,
char *new_password)
{
- uint length=0;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
host,user,new_password));
@@ -1160,37 +1130,27 @@ bool change_password(THD *thd, const char *host, const char *user,
if (check_change_password(thd, host, user))
DBUG_RETURN(1);
- /*
- password should always be 0,16 or 45 chars;
- Simple hack to avoid cracking
- */
- length=(uint) strlen(new_password);
- if (length != 45)
- new_password[length & 16]=0;
-
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
- if (!(acl_user= find_acl_user(host,user)))
+ if (!(acl_user= find_acl_user(host, user)))
{
- send_error(thd, ER_PASSWORD_NO_MATCH);
VOID(pthread_mutex_unlock(&acl_cache->lock));
+ send_error(thd, ER_PASSWORD_NO_MATCH);
DBUG_RETURN(1);
}
+ /* update loaded acl entry: */
+ uint new_password_len= new_password ? strlen(new_password) : 0;
+ set_user_salt(acl_user, new_password, new_password_len);
+
if (update_user_table(thd,
acl_user->host.hostname ? acl_user->host.hostname : "",
acl_user->user ? acl_user->user : "",
- new_password))
+ new_password, new_password_len))
{
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
send_error(thd,0); /* purecov: deadcode */
DBUG_RETURN(1); /* purecov: deadcode */
}
- get_salt_from_password(acl_user->salt,new_password);
- acl_user->pversion=get_password_version(new_password);
- if (!new_password[0])
- acl_user->password=0;
- else
- acl_user->password=(char*) ""; // Point at something
acl_cache->clear(1); // Clear locked hostname cache
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -1230,7 +1190,7 @@ find_acl_user(const char *host, const char *user)
if (!acl_user->user && !user[0] ||
acl_user->user && !strcmp(user,acl_user->user))
{
- if (compare_hostname(&(acl_user->host),host,host))
+ if (compare_hostname(&acl_user->host,host,host))
{
DBUG_RETURN(acl_user);
}
@@ -1303,7 +1263,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
*/
static bool update_user_table(THD *thd, const char *host, const char *user,
- const char *new_password)
+ const char *new_password, uint new_password_len)
{
TABLE_LIST tables;
TABLE *table;
@@ -1345,7 +1305,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
DBUG_RETURN(1); /* purecov: deadcode */
}
store_record(table,record[1]);
- table->field[2]->store(new_password,(uint) strlen(new_password), &my_charset_latin1);
+ table->field[2]->store(new_password, new_password_len, &my_charset_latin1);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1393,24 +1353,23 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
{
int error = -1;
bool old_row_exists=0;
- char *password,empty_string[1];
+ const char *password= "";
+ uint password_len= 0;
char what= (revoke_grant) ? 'N' : 'Y';
DBUG_ENTER("replace_user_table");
safe_mutex_assert_owner(&acl_cache->lock);
- password=empty_string;
- empty_string[0]=0;
-
if (combo.password.str && combo.password.str[0])
{
- if ((combo.password.length != HASH_PASSWORD_LENGTH)
- && combo.password.length != HASH_OLD_PASSWORD_LENGTH)
+ if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
+ combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
my_printf_error(ER_PASSWORD_NO_MATCH,
- "Password hash should be a %d-digit hexadecimal number",
- MYF(0),HASH_PASSWORD_LENGTH);
+ "Password hash should be a %d-digit hexadecimal number",
+ MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
DBUG_RETURN(-1);
}
+ password_len= combo.password.length;
password=combo.password.str;
}
@@ -1435,17 +1394,20 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
goto end;
}
old_row_exists = 0;
- restore_record(table,default_values); // cp empty row from default_values
- table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
- table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
- table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
+ restore_record(table,default_values); // cp empty row from default_values
+ table->field[0]->store(combo.host.str,combo.host.length,
+ &my_charset_latin1);
+ table->field[1]->store(combo.user.str,combo.user.length,
+ &my_charset_latin1);
+ table->field[2]->store(password, password_len,
+ &my_charset_latin1);
}
else
{
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
if (combo.password.str) // If password given
- table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
+ table->field[2]->store(password, password_len, &my_charset_latin1);
}
/* Update table columns with new privileges */
@@ -1542,10 +1504,8 @@ end:
if (!error)
{
acl_cache->clear(1); // Clear privilege cache
- if (!combo.password.str)
- password=0; // No password given on command
if (old_row_exists)
- acl_update_user(combo.user.str,combo.host.str,password,
+ acl_update_user(combo.user.str, combo.host.str, password, password_len,
thd->lex.ssl_type,
thd->lex.ssl_cipher,
thd->lex.x509_issuer,
@@ -1553,7 +1513,7 @@ end:
&thd->lex.mqh,
rights);
else
- acl_insert_user(combo.user.str,combo.host.str,password,
+ acl_insert_user(combo.user.str, combo.host.str, password, password_len,
thd->lex.ssl_type,
thd->lex.ssl_cipher,
thd->lex.x509_issuer,
@@ -1686,6 +1646,7 @@ class GRANT_TABLE :public Sql_alloc
public:
char *host,*db,*user,*tname, *hash_key;
ulong privs, cols;
+ ulong sort;
uint key_length;
HASH hash_columns;
GRANT_TABLE (const char *h, const char *d,const char *u, const char *t,
@@ -1695,6 +1656,7 @@ public:
host = strdup_root(&memex,h);
db = strdup_root(&memex,d);
user = strdup_root(&memex,u);
+ sort= get_sort(3,host,db,user);
tname= strdup_root(&memex,t);
if (lower_case_table_names)
{
@@ -1717,7 +1679,8 @@ public:
user = get_field(&memex,form->field[2]);
if (!user)
user=(char*) "";
- tname = get_field(&memex,form->field[3]);
+ sort= get_sort(3,host,db,user);
+ tname= get_field(&memex,form->field[3]);
if (!host || !db || !tname)
{
/* Wrong table row; Ignore it */
@@ -1775,7 +1738,7 @@ public:
privs = cols = 0; /* purecov: deadcode */
return; /* purecov: deadcode */
}
- hash_insert(&hash_columns, (byte *) mem_check);
+ my_hash_insert(&hash_columns, (byte *) mem_check);
} while (!col_privs->file->index_next(col_privs->record[0]) &&
!key_cmp(col_privs,key,0,key_len));
}
@@ -1826,10 +1789,11 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
}
else
{
- if ((host && !wild_case_compare(&my_charset_latin1,
- host,grant_table->host)) ||
- (ip && !wild_case_compare(&my_charset_latin1,
- ip,grant_table->host)))
+ if (((host && !wild_case_compare(&my_charset_latin1,
+ host,grant_table->host)) ||
+ (ip && !wild_case_compare(&my_charset_latin1,
+ ip,grant_table->host))) &&
+ (!found || found->sort < grant_table->sort))
found=grant_table; // Host ok
}
}
@@ -1936,7 +1900,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
goto end; /* purecov: inspected */
}
GRANT_COLUMN *grant_column = new GRANT_COLUMN(xx->column,privileges);
- hash_insert(&g_t->hash_columns,(byte*) grant_column);
+ my_hash_insert(&g_t->hash_columns,(byte*) grant_column);
}
}
table->file->index_end();
@@ -2287,7 +2251,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
result= -1; /* purecov: deadcode */
continue; /* purecov: deadcode */
}
- hash_insert(&column_priv_hash,(byte*) grant_table);
+ my_hash_insert(&column_priv_hash,(byte*) grant_table);
}
/* If revoke_grant, calculate the new column privilege for tables_priv */
@@ -2530,7 +2494,7 @@ my_bool grant_init(THD *org_thd)
{
GRANT_TABLE *mem_check;
if (!(mem_check=new GRANT_TABLE(t_table,c_table)) ||
- mem_check->ok() && hash_insert(&column_priv_hash,(byte*) mem_check))
+ mem_check->ok() && my_hash_insert(&column_priv_hash,(byte*) mem_check))
{
/* This could only happen if we are out memory */
grant_option= FALSE; /* purecov: deadcode */
@@ -3024,12 +2988,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append ("'@'",3);
global.append(lex_user->host.str,lex_user->host.length);
global.append ('\'');
- if (acl_user->password)
+ if (acl_user->salt_len)
{
- char passd_buff[HASH_PASSWORD_LENGTH+1];
- make_password_from_salt(passd_buff,acl_user->salt,acl_user->pversion);
+ char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
+ if (acl_user->salt_len == SCRAMBLE_LENGTH)
+ make_password_from_salt(passwd_buff, acl_user->salt);
+ else
+ make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt);
global.append(" IDENTIFIED BY PASSWORD '",25);
- global.append(passd_buff);
+ global.append(passwd_buff);
global.append('\'');
}
/* "show grants" SSL related stuff */
@@ -3083,7 +3050,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
protocol->store(global.ptr(),global.length(),global.charset());
if (protocol->write())
{
- error=-1;
+ error= -1;
goto end;
}
}
@@ -3141,7 +3108,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
protocol->store(db.ptr(),db.length(),db.charset());
if (protocol->write())
{
- error=-1;
+ error= -1;
goto end;
}
}
@@ -3167,15 +3134,19 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if ((table_access | grant_table->cols) != 0)
{
String global(buff,sizeof(buff),&my_charset_latin1);
+ ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
+
global.length(0);
global.append("GRANT ",6);
if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14);
+ else if (!test_access)
+ global.append("USAGE",5);
else
{
int found= 0;
- ulong j,test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
+ ulong j;
for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
{
@@ -3342,7 +3313,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
}
ACL_USER *check_acl_user(LEX_USER *user_name,
- uint *acl_user_idx)
+ uint *acl_acl_userdx)
{
ACL_USER *acl_user= 0;
uint counter;
@@ -3362,14 +3333,14 @@ ACL_USER *check_acl_user(LEX_USER *user_name,
if (counter == acl_users.elements)
return 0;
- *acl_user_idx= counter;
+ *acl_acl_userdx= counter;
return acl_user;
}
int mysql_drop_user(THD *thd, List <LEX_USER> &list)
{
- uint counter, user_id;
+ uint counter, acl_userd;
int result;
ACL_USER *acl_user;
ACL_DB *acl_db;
@@ -3389,7 +3360,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
{
if (!(acl_user= check_acl_user(user_name, &counter)))
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; No such user",
user_name->user.str,
user_name->host.str);
result= -1;
@@ -3397,13 +3368,13 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
}
if ((acl_user->access & ~0))
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Global privileges exists",
user_name->user.str,
user_name->host.str);
result= -1;
continue;
}
- user_id= counter;
+ acl_userd= counter;
for (counter= 0 ; counter < acl_dbs.elements ; counter++)
{
@@ -3420,7 +3391,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
}
if (counter != acl_dbs.elements)
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Database privileges exists",
user_name->user.str,
user_name->host.str);
result= -1;
@@ -3443,7 +3414,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
}
if (counter != column_priv_hash.records)
{
- sql_print_error("DROP USER: Can't drop user: '%s'@'%s'",
+ sql_print_error("DROP USER: Can't drop user: '%s'@'%s'; Table privileges exists",
user_name->user.str,
user_name->host.str);
result= -1;
@@ -3469,7 +3440,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
tables[0].table->file->index_end();
DBUG_RETURN(-1);
}
- delete_dynamic_element(&acl_users, user_id);
+ delete_dynamic_element(&acl_users, acl_userd);
}
tables[0].table->file->index_end();
}
@@ -3590,3 +3561,50 @@ template class List_iterator<LEX_USER>;
template class List<LEX_COLUMN>;
template class List<LEX_USER>;
#endif
+
+#endif /*NO_EMBEDDED_ACCESS_CHECKS */
+
+
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
+{
+ reg3 int flag;
+ DBUG_ENTER("wild_case_compare");
+ DBUG_PRINT("enter",("str: '%s' wildstr: '%s'",str,wildstr));
+ while (*wildstr)
+ {
+ while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
+ {
+ if (*wildstr == wild_prefix && wildstr[1])
+ wildstr++;
+ if (my_toupper(cs, *wildstr++) !=
+ my_toupper(cs, *str++)) DBUG_RETURN(1);
+ }
+ if (! *wildstr ) DBUG_RETURN (*str != 0);
+ if (*wildstr++ == wild_one)
+ {
+ if (! *str++) DBUG_RETURN (1); /* One char; skip */
+ }
+ else
+ { /* Found '*' */
+ if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
+ flag=(*wildstr != wild_many && *wildstr != wild_one);
+ do
+ {
+ if (flag)
+ {
+ char cmp;
+ if ((cmp= *wildstr) == wild_prefix && wildstr[1])
+ cmp=wildstr[1];
+ cmp=my_toupper(cs, cmp);
+ while (*str && my_toupper(cs, *str) != cmp)
+ str++;
+ if (!*str) DBUG_RETURN (1);
+ }
+ if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
+ } while (*str++);
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN (*str != '\0');
+}
+
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 0dc8c058b3d..220eb0d55ad 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -14,7 +14,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
#define SELECT_ACL (1L << 0)
#define INSERT_ACL (1L << 1)
#define UPDATE_ACL (1L << 2)
@@ -59,6 +58,8 @@
#define EXTRA_ACL (1L << 29)
#define NO_ACCESS (1L << 30)
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+
/*
Defines to change the above bits to how things are stored in tables
This is needed as the 'host' and 'db' table is missing a few privileges
@@ -111,9 +112,9 @@ public:
acl_host_and_ip host;
uint hostname_length;
USER_RESOURCES user_resource;
- char *user,*password;
- ulong salt[6]; // New password has longer length
- uint8 pversion; // password version
+ char *user;
+ uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
+ uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 3.23, 20 - 4.1.1
enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject;
};
@@ -135,11 +136,8 @@ void acl_reload(THD *thd);
void acl_free(bool end=0);
ulong acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db, my_bool db_is_pattern);
-ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
- const char *password,const char *scramble,
- char **priv_user, char *priv_host,
- bool old_ver, USER_RESOURCES *max,char* prepared_scramble,
- uint *cur_priv_version, ACL_USER **cached_user);
+int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
+ uint passwd_len);
bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user);
bool change_password(THD *thd, const char *host, const char *user,
@@ -165,3 +163,6 @@ void get_privilege_desc(char *to, uint max_length, ulong access);
void get_mqh(const char *user, const char *host, USER_CONN *uc);
int mysql_drop_user(THD *thd, List <LEX_USER> &list);
int mysql_revoke_all(THD *thd, List <LEX_USER> &list);
+
+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
+
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 2b23b622cc6..4b4e4e7eb8e 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -158,7 +158,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
table_list.grant.privilege=0;
if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list,1))
continue;
-
/* need to check if we haven't already listed it */
for (table= open_list ; table ; table=table->next)
{
@@ -873,7 +872,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
table->version=refresh_version;
table->flush_version=flush_version;
DBUG_PRINT("info", ("inserting table %p into the cache", table));
- VOID(hash_insert(&open_cache,(byte*) table));
+ VOID(my_hash_insert(&open_cache,(byte*) table));
}
table->in_use=thd;
@@ -1696,8 +1695,10 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
else
thd->dupp_field=field;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants && check_grant_column(thd,table,name,length))
return WRONG_GRANT;
+#endif
return field;
}
@@ -2114,11 +2115,12 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
tables->alias) &&
(!db_name || !strcmp(tables->db,db_name))))
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access right to all columns */
if (!(table->grant.privilege & SELECT_ACL) &&
check_grant_all_columns(thd,SELECT_ACL,table))
DBUG_RETURN(-1);
-
+#endif
Field **ptr=table->field,*field;
thd->used_tables|=table->map;
while ((field = *ptr++))
@@ -2343,7 +2345,7 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
- create_info.table_charset= thd->variables.character_set_database;
+ create_info.table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, 0, (ORDER*)0, FALSE,
@@ -2360,7 +2362,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
DBUG_ENTER("mysql_drop_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
- create_info.table_charset= thd->variables.character_set_database;
+ create_info.table_charset= thd->variables.collation_database;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, 0, (ORDER*)0, FALSE,
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 64e8be8e224..069887e689e 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -765,13 +765,30 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
&tables_type)))
{
NET *net= &thd->net;
- byte flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
+ Query_cache_query_flags flags;
+ // fill all gaps between fields with 0 to get repeatable key
+ bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
+ flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ?
+ 1 : 0);
+ flags.character_set_client_num= thd->variables.character_set_client->number;
+ flags.character_set_results_num= thd->variables.character_set_results->number;
+ flags.collation_connection_num= thd->variables.collation_connection->number;
+ flags.limit= thd->variables.select_limit;
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size == 0)
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
+ }
DUMP(this);
+ if (ask_handler_allowance(thd, tables_used))
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+ }
+
/* Key is query + database + flag */
if (thd->db_length)
{
@@ -783,23 +800,19 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
{
DBUG_PRINT("qcache", ("No active database"));
}
+ tot_length= thd->query_length + thd->db_length + 1 +
+ QUERY_CACHE_FLAGS_SIZE;
/*
- Prepare flags:
- most significant bit - CLIENT_LONG_FLAG,
- other - charset number (0 no charset convertion)
+ We should only copy structure (don't use it location directly)
+ because of alignment issue
*/
- flags|= (byte) thd->charset()->number;
- DBUG_ASSERT(thd->charset()->number < 128);
- tot_length= thd->query_length+thd->db_length+2+sizeof(ha_rows);
- thd->query[tot_length-1]= (char) flags;
- memcpy((void *)(thd->query + (tot_length-sizeof(ha_rows)-1)),
- (const void *)&thd->variables.select_limit, sizeof(ha_rows));
+ memcpy((void *)(thd->query + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
+ &flags, QUERY_CACHE_FLAGS_SIZE);
/* Check if another thread is processing the same query? */
Query_cache_block *competitor = (Query_cache_block *)
hash_search(&queries, (byte*) thd->query, tot_length);
- DBUG_PRINT("qcache", ("competitor 0x%lx, flags %x", (ulong) competitor,
- flags));
+ DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor));
if (competitor == 0)
{
/* Query is not in cache and no one is working with it; Store it */
@@ -814,7 +827,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
Query_cache_query *header = query_block->query();
header->init_n_lock();
- if (hash_insert(&queries, (byte*) query_block))
+ if (my_hash_insert(&queries, (byte*) query_block))
{
refused++;
DBUG_PRINT("qcache", ("insertion in query hash"));
@@ -886,7 +899,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_block *first_result_block, *result_block;
Query_cache_block_table *block_table, *block_table_end;
ulong tot_length;
- byte flags;
+ Query_cache_query_flags flags;
bool check_tables;
DBUG_ENTER("Query_cache::send_result_to_client");
@@ -923,7 +936,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
}
Query_cache_block *query_block;
- tot_length= query_length+thd->db_length+2+sizeof(ha_rows);
+ tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
if (thd->db_length)
{
memcpy(sql+query_length+1, thd->db, thd->db_length);
@@ -934,17 +947,17 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
{
DBUG_PRINT("qcache", ("No active database"));
}
- /*
- prepare flags:
- Most significant bit - CLIENT_LONG_FLAG,
- Other - charset number (0 no charset convertion)
- */
- flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
- flags|= (byte) thd->charset()->number;
- DBUG_ASSERT(thd->charset()->number < 128);
- sql[tot_length-1]= (char) flags;
- memcpy((void *)(sql + (tot_length-sizeof(ha_rows)-1)),
- (const void *)&thd->variables.select_limit, sizeof(ha_rows));
+
+ // fill all gaps between fields with 0 to get repeatable key
+ bzero(&flags, QUERY_CACHE_FLAGS_SIZE);
+ flags.client_long_flag= (thd->client_capabilities & CLIENT_LONG_FLAG ?
+ 1 : 0);
+ flags.character_set_client_num= thd->variables.character_set_client->number;
+ flags.character_set_results_num= thd->variables.character_set_results->number;
+ flags.collation_connection_num= thd->variables.collation_connection->number;
+ flags.limit= thd->variables.select_limit;
+ memcpy((void *)(sql + (tot_length - QUERY_CACHE_FLAGS_SIZE)),
+ &flags, QUERY_CACHE_FLAGS_SIZE);
query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql,
tot_length);
/* Quick abort on unlocked data */
@@ -993,6 +1006,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_table *table = block_table->parent;
table_list.db = table->db();
table_list.alias= table_list.real_name= table->table();
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_table_access(thd,SELECT_ACL,&table_list,1))
{
DBUG_PRINT("qcache",
@@ -1012,6 +1026,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
thd->lex.safe_to_cache_query= 0; // Don't try to cache this
goto err_unlock; // Parse query
}
+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
if (check_tables && !handler::caching_allowed(thd, table->db(),
table->key_length(),
table->type()))
@@ -2035,7 +2050,7 @@ Query_cache::insert_table(uint key_len, char *key,
Query_cache_block_table *list_root = table_block->table(0);
list_root->n = 0;
list_root->next = list_root->prev = list_root;
- if (hash_insert(&tables, (const byte *) table_block))
+ if (my_hash_insert(&tables, (const byte *) table_block))
{
DBUG_PRINT("qcache", ("Can't insert table to hash"));
// write_block_data return locked block
@@ -2548,6 +2563,39 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
DBUG_RETURN(0);
}
+/*
+ Check handler allowence to cache query with this tables
+
+ SYNOPSYS
+ Query_cache::ask_handler_allowance()
+ thd - thread handlers
+ tables_used - tables list used in query
+
+ RETURN
+ 0 - caching allowed
+ 1 - caching disallowed
+*/
+my_bool Query_cache::ask_handler_allowance(THD *thd,
+ TABLE_LIST *tables_used)
+{
+ DBUG_ENTER("Query_cache::is_cacheable");
+
+ for (; tables_used; tables_used= tables_used->next)
+ {
+ TABLE *table= tables_used->table;
+ if (!handler::caching_allowed(thd, table->table_cache_key,
+ table->key_length,
+ table->file->table_cache_type()))
+ {
+ DBUG_PRINT("qcache", ("Handler does not allow caching for %s.%s",
+ tables_used->db, tables_used->alias));
+ thd->lex.safe_to_cache_query= 0; // Don't try to cache this
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
/*****************************************************************************
Packing
@@ -3055,20 +3103,21 @@ void Query_cache::queries_dump()
{
uint len;
char *str = (char*) query_cache_query_get_key((byte*) block, &len, 0);
- len--; // Point at flags
- uint flags = (uint) (uchar) str[len];
- str[len]=0;
- DBUG_PRINT("qcache", ("%u (%u,%u) '%s' '%s'",
- ((flags & QUERY_CACHE_CLIENT_LONG_FLAG_MASK)? 1:0),
- (flags & QUERY_CACHE_CHARSET_CONVERT_MASK), len,
- str,strend(str)+1));
+ len-= QUERY_CACHE_FLAGS_SIZE; // Point at flags
+ Query_cache_query_flags flags;
+ memcpy(&flags, str+len, QUERY_CACHE_FLAGS_SIZE);
+ str[len]= 0; // make zero ending DB name
+ DBUG_PRINT("qcache", ("F:%u C:%u L:%lu (%u) '%s' '%s'",
+ flags.client_long_flag,
+ flags.character_set_client_num, (ulong)flags.limit,
+ len, str, strend(str)+1));
DBUG_PRINT("qcache", ("-b- 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx", (ulong) block,
(ulong) block->next, (ulong) block->prev,
(ulong)block->pnext, (ulong)block->pprev));
- str[len]=(char) flags;
- for (TABLE_COUNTER_TYPE t = 0; t < block->n_tables; t++)
+ memcpy(str + len, &flags, QUERY_CACHE_FLAGS_SIZE); // restore flags
+ for (TABLE_COUNTER_TYPE t= 0; t < block->n_tables; t++)
{
- Query_cache_table *table = block->table(t)->parent;
+ Query_cache_table *table= block->table(t)->parent;
DBUG_PRINT("qcache", ("-t- '%s' '%s'", table->db(), table->table()));
}
Query_cache_query *header = block->query();
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index f6eb7c7a0fb..68e69ab523f 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -345,6 +345,8 @@ protected:
TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
LEX *lex, TABLE_LIST *tables_used,
uint8 *tables_type);
+
+ static my_bool ask_handler_allowance(THD *thd, TABLE_LIST *tables_used);
public:
Query_cache(ulong query_cache_limit = ULONG_MAX,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c57934f32cd..ed4f2be16ec 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -107,7 +107,7 @@ THD::THD():user_time(0), is_fatal_error(0),
variables.pseudo_thread_id= 0;
file_id = 0;
warn_id= 0;
- db_charset= global_system_variables.character_set_database;
+ db_charset= global_system_variables.collation_database;
mysys_var=0;
#ifndef DBUG_OFF
dbug_sentry=THD_SENTRY_MAGIC;
@@ -133,11 +133,13 @@ THD::THD():user_time(0), is_fatal_error(0),
where="field list";
server_id = ::server_id;
slave_net = 0;
- log_pos = 0;
command=COM_CONNECT;
set_query_id=1;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access=NO_ACCESS;
+#endif
version=refresh_version; // For boot
+ *scramble= '\0';
init();
/* Initialize sub structures */
@@ -316,7 +318,7 @@ THD::~THD()
#endif
DBUG_PRINT("info", ("freeing host"));
- if (host != localhost) // If not pointer to constant
+ if (host != my_localhost) // If not pointer to constant
safeFree(host);
if (user != delayed_user)
safeFree(user);
@@ -583,7 +585,7 @@ sql_exchange::sql_exchange(char *name,bool flag)
:file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
{
field_term= &default_field_term;
- enclosed= line_start= &empty_string;
+ enclosed= line_start= &my_empty_string;
line_term= &default_line_term;
escaped= &default_escaped;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 3de909ee384..4fb12523086 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -129,7 +129,7 @@ public:
}
void set_max_size(ulong max_size_arg);
void signal_update() { pthread_cond_broadcast(&update_cond);}
- void wait_for_update(THD* thd);
+ void wait_for_update(THD* thd, bool master_or_slave);
void set_need_start_event() { need_start_event = 1; }
void init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg,
@@ -146,7 +146,7 @@ public:
bool write(THD *thd, const char *query, uint query_length,
time_t query_start=0);
bool write(Log_event* event_info); // binary log write
- bool write(THD *thd, IO_CACHE *cache);
+ bool write(THD *thd, IO_CACHE *cache, bool commit_or_rollback);
/*
v stands for vector
@@ -341,7 +341,11 @@ typedef struct st_prep_stmt
char last_error[MYSQL_ERRMSG_SIZE];
bool error_in_prepare, long_data_used;
bool log_full_query;
+#ifndef EMBEDDED_LIBRARY
bool (*setup_params)(st_prep_stmt *stmt, uchar *pos, uchar *read_pos);
+#else
+ bool (*setup_params_data)(st_prep_stmt *stmt);
+#endif
} PREP_STMT;
@@ -385,6 +389,7 @@ struct system_variables
ulong table_type;
ulong tmp_table_size;
ulong tx_isolation;
+ /* Determines if which non-standard SQL behaviour should be enabled */
ulong sql_mode;
ulong default_week_format;
ulong max_seeks_for_key;
@@ -398,11 +403,15 @@ struct system_variables
my_bool log_warnings;
my_bool low_priority_updates;
my_bool new_mode;
+ my_bool old_passwords;
- CHARSET_INFO *character_set_server;
- CHARSET_INFO *character_set_database;
+ /* Only charset part of these variables is sensible */
CHARSET_INFO *character_set_client;
CHARSET_INFO *character_set_results;
+
+ /* Both charset and collation parts of these variables are important */
+ CHARSET_INFO *collation_server;
+ CHARSET_INFO *collation_database;
CHARSET_INFO *collation_connection;
};
@@ -417,6 +426,12 @@ class THD :public ilink
public:
#ifdef EMBEDDED_LIBRARY
struct st_mysql *mysql;
+ struct st_mysql_data *data;
+ unsigned long client_stmt_id;
+ unsigned long client_param_count;
+ struct st_mysql_bind *client_params;
+ char *extra_data;
+ ulong extra_length;
#endif
NET net; // client connection descriptor
LEX lex; // parse tree descriptor
@@ -459,7 +474,6 @@ public:
const char *host_or_ip;
ulong client_capabilities; /* What the client supports */
- /* Determines if which non-standard SQL behaviour should be enabled */
ulong max_client_packet_length;
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
@@ -556,11 +570,10 @@ public:
enum_tx_isolation session_tx_isolation;
/* for user variables replication*/
DYNAMIC_ARRAY user_var_events;
- // extend scramble to handle new auth
- char scramble[SCRAMBLE41_LENGTH+1];
- // old scramble is needed to handle old clients
- char old_scramble[SCRAMBLE_LENGTH+1];
- uint8 query_cache_type; // type of query cache processing
+
+ /* scramble - random string sent to client on handshake */
+ char scramble[SCRAMBLE_LENGTH+1];
+
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
bool last_cuted_field;
@@ -580,7 +593,6 @@ public:
*/
LOG_INFO* current_linfo;
NET* slave_net; // network connection from slave -> m.
- my_off_t log_pos;
/* Used by the sys_var class to store temporary values */
union
{
@@ -981,7 +993,6 @@ typedef struct st_sort_buffer {
SORT_FIELD *sortorder;
} SORT_BUFFER;
-
/* Structure for db & table in sql_yacc */
class Table_ident :public Sql_alloc
diff --git a/sql/sql_crypt.cc b/sql/sql_crypt.cc
index 930ecfffef7..b0b8050e311 100644
--- a/sql/sql_crypt.cc
+++ b/sql/sql_crypt.cc
@@ -32,7 +32,7 @@
SQL_CRYPT::SQL_CRYPT(const char *password)
{
ulong rand_nr[2];
- hash_password(rand_nr,password);
+ hash_password(rand_nr,password, strlen(password));
crypt_init(rand_nr);
}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 34e81402dd0..750dd4ff493 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -62,7 +62,7 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
ulong length;
CHARSET_INFO *cs= (create && create->table_charset) ?
create->table_charset :
- thd->variables.character_set_database;
+ thd->variables.collation_database;
length= my_sprintf(buf,(buf, "default-character-set=%s\ndefault-collation=%s\n", cs->csname,cs->name));
/* Error is written by my_write */
@@ -99,7 +99,7 @@ static bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
uint nbytes;
bzero((char*) create,sizeof(*create));
- create->table_charset= global_system_variables.character_set_database;
+ create->table_charset= global_system_variables.collation_database;
if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0)
{
IO_CACHE cache;
@@ -288,8 +288,8 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
{
thd->db_charset= (create_info && create_info->table_charset) ?
create_info->table_charset :
- global_system_variables.character_set_database;
- thd->variables.character_set_database= thd->db_charset;
+ global_system_variables.collation_database;
+ thd->variables.collation_database= thd->db_charset;
}
mysql_update_log.write(thd,thd->query, thd->query_length);
@@ -391,6 +391,33 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
start_waiting_global_read_lock(thd);
+ /*
+ If this database was the client's selected database, we silently change the
+ client's selected database to nothing (to have an empty SELECT DATABASE() in
+ the future). For this we free() thd->db and set it to 0. But we don't do
+ free() for the slave thread. Indeed, doing a x_free() on it leads to nasty
+ problems (i.e. long painful debugging) because in this thread, thd->db is
+ the same as data_buf and db of the Query_log_event which is dropping the
+ database. So if you free() thd->db, you're freeing data_buf. You set thd->db
+ to 0 but not data_buf (thd->db and data_buf are two distinct pointers which
+ point to the same place). Then in ~Query_log_event(), we have
+ 'if (data_buf) free(data_buf)'
+ data_buf is !=0 so this makes a DOUBLE free().
+ Side effects of this double free() are, randomly (depends on the machine),
+ when the slave is replicating a DROP DATABASE:
+ - garbage characters in the error message:
+ "Error 'Can't drop database 'test2'; database doesn't exist' on query
+ 'h4zI¿'"
+ - segfault
+ - hang in "free(vio)" (yes!) in the I/O or SQL slave threads (so slave
+ server hangs at shutdown etc).
+ */
+ if (thd->db && !strcmp(thd->db, db))
+ {
+ if (!(thd->slave_thread)) /* a slave thread will free it itself */
+ x_free(thd->db);
+ thd->db= 0;
+ }
exit2:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
@@ -587,6 +614,7 @@ bool mysql_change_db(THD *thd, const char *name)
DBUG_RETURN(1);
}
DBUG_PRINT("info",("Use database: %s", dbname));
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (test_all_bits(thd->master_access,DB_ACLS))
db_access=DB_ACLS;
else
@@ -606,7 +634,7 @@ bool mysql_change_db(THD *thd, const char *name)
my_free(dbname,MYF(0));
DBUG_RETURN(1);
}
-
+#endif
(void) sprintf(path,"%s/%s",mysql_data_home,dbname);
length=unpack_dirname(path,path); // Convert if not unix
if (length && path[length-1] == FN_LIBCHAR)
@@ -621,14 +649,15 @@ bool mysql_change_db(THD *thd, const char *name)
x_free(thd->db);
thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->db_access=db_access;
-
+#endif
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
load_db_opt(thd, path, &create);
thd->db_charset= create.table_charset ?
create.table_charset :
- global_system_variables.character_set_database;
- thd->variables.character_set_database= thd->db_charset;
+ global_system_variables.collation_database;
+ thd->variables.collation_database= thd->db_charset;
DBUG_RETURN(0);
}
@@ -651,6 +680,7 @@ int mysqld_show_create_db(THD *thd, char *dbname,
DBUG_RETURN(1);
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (test_all_bits(thd->master_access,DB_ACLS))
db_access=DB_ACLS;
else
@@ -669,6 +699,7 @@ int mysqld_show_create_db(THD *thd, char *dbname,
dbname);
DBUG_RETURN(1);
}
+#endif
(void) sprintf(path,"%s/%s",mysql_data_home, dbname);
length=unpack_dirname(path,path); // Convert if not unix
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index fcbb1bcfdeb..13d3cc27376 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -25,8 +25,6 @@
#include "sql_select.h"
#include "sql_acl.h"
-extern const char *any_db; // Special symbol for check_access
-
/*
Resolve derived tables in all queries
@@ -91,13 +89,15 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
We have to do access checks here as this code is executed before any
sql command is started to execute.
*/
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (tables)
- res= check_table_access(thd,SELECT_ACL, tables);
+ res= check_table_access(thd,SELECT_ACL, tables,0);
else
- res= check_access(thd, SELECT_ACL, any_db);
+ res= check_access(thd, SELECT_ACL, any_db,0,0,0);
if (res)
- DBUG_RETURN(-1);
-
+ DBUG_RETURN(1);
+#endif
+
if (!(res=open_and_lock_tables(thd,tables)))
{
if (is_union || is_subsel)
@@ -206,7 +206,9 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
org_table_list->table=table;
table->derived_select_number= select_cursor->select_number;
table->tmp_table= TMP_TABLE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
org_table_list->grant.privilege= SELECT_ACL;
+#endif
if (lex->describe)
{
// to fix a problem in EXPLAIN
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 947205949f1..af28d48ed8a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -60,9 +60,11 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
MYF(0),counter);
return -1;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option &&
check_grant_all_columns(thd,INSERT_ACL,table))
return -1;
+#endif
table->time_stamp=0; // This is saved by caller
}
else
@@ -96,7 +98,9 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
table->time_stamp= table->timestamp_field->offset()+1;
}
// For the values we need select_priv
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+#endif
return 0;
}
@@ -130,14 +134,15 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_insert");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (thd->master_access & SUPER_ACL)
+#endif
{
if (!(thd->options & OPTION_UPDATE_LOG))
log_on&= ~(int) DELAYED_LOG_UPDATE;
if (!(thd->options & OPTION_BIN_LOG))
log_on&= ~(int) DELAYED_LOG_BIN;
}
-
/*
in safe mode or with skip-new change delayed insert to be regular
if we are told to replace duplicates, the insert cannot be concurrent
@@ -172,7 +177,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
else
res= (table == 0);
else
+ {
+ lock_type=TL_WRITE;
res= open_and_lock_tables(thd, table_list);
+ }
}
else
res= open_and_lock_tables(thd, table_list);
@@ -623,10 +631,11 @@ public:
group_count(0)
{
thd.user=thd.priv_user=(char*) delayed_user;
- thd.host=(char*) localhost;
+ thd.host=(char*) my_localhost;
thd.current_tablenr=0;
thd.version=refresh_version;
thd.command=COM_DELAYED_INSERT;
+ thd.lex.current_select= 0; /* for my_message_sql */
bzero((char*) &thd.net,sizeof(thd.net)); // Safety
thd.system_thread=1;
@@ -1448,6 +1457,8 @@ void select_insert::send_error(uint errcode,const char *err)
table->file->has_transactions());
mysql_bin_log.write(&qinfo);
}
+ if (!table->tmp_table)
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
if (info.copied || info.deleted)
query_cache_invalidate3(thd, table, 1);
@@ -1468,7 +1479,11 @@ bool select_insert::send_eof()
*/
if (info.copied || info.deleted)
+ {
query_cache_invalidate3(thd, table, 1);
+ if (!(table->file->has_transactions() || table->tmp_table))
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ }
if (last_insert_id)
thd->insert_id(last_insert_id); // For binary log
@@ -1559,8 +1574,6 @@ bool select_create::send_data(List<Item> &values)
return 0;
}
-extern HASH open_cache;
-
bool select_create::send_eof()
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d6cfd555c40..80d698dfc26 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -982,6 +982,7 @@ void st_select_lex::init_query()
cond_count= with_wild= 0;
ref_pointer_array= 0;
select_n_having_items= 0;
+ prep_where= 0;
}
void st_select_lex::init_select()
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 7a7071ae56b..8ce028020c2 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -60,7 +60,7 @@ enum enum_sql_command {
SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS,
- SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
+ SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
SQLCOM_COMMIT, SQLCOM_SAVEPOINT,
SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
@@ -73,7 +73,7 @@ enum enum_sql_command {
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
- SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL,
+ SQLCOM_HELP, SQLCOM_DROP_USER, SQLCOM_REVOKE_ALL, SQLCOM_CHECKSUM,
/* This should be the last !!! */
SQLCOM_END
@@ -87,6 +87,13 @@ typedef struct st_lex_master_info
uint port, connect_retry;
ulonglong pos;
ulong server_id;
+ /*
+ Variable for MASTER_SSL option.
+ MASTER_SSL=0 in CHANGE MASTER TO corresponds to SSL_DISABLE
+ MASTER_SSL=1 corresponds to SSL_ENABLE
+ */
+ enum {SSL_UNCHANGED=0, SSL_DISABLE, SSL_ENABLE} ssl;
+ char *ssl_key, *ssl_cert, *ssl_ca, *ssl_capath, *ssl_cipher;
char *relay_log_name;
ulong relay_log_pos;
} LEX_MASTER_INFO;
@@ -272,8 +279,8 @@ protected:
select_result *result;
int res;
- bool describe, found_rows_for_union,
- prepared, // prepare phase already performed for UNION (unit)
+ ulong describe, found_rows_for_union;
+ bool prepared, // prepare phase already performed for UNION (unit)
optimized, // optimize phase already performed for UNION (unit)
executed, // already executed
t_and_f; // used for transferring tables_and_fields_initied UNIT:: methods
@@ -332,6 +339,7 @@ class st_select_lex: public st_select_lex_node
public:
char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */
Item *where, *having; /* WHERE & HAVING clauses */
+ Item *prep_where; /* saved WHERE clause for prepared statement processing */
enum olap_type olap;
SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
List<Item> item_list; /* list of fields & expressions */
@@ -472,15 +480,22 @@ typedef struct st_lex
SELECT_LEX *all_selects_list;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
+ char *help_arg;
char *backup_dir; /* For RESTORE/BACKUP */
char* to_log; /* For PURGE MASTER LOGS TO */
time_t purge_time; /* For PURGE MASTER LOGS BEFORE */
char* x509_subject,*x509_issuer,*ssl_cipher;
char* found_colon; /* For multi queries - next query */
- enum SSL_type ssl_type; /* defined in violite.h */
String *wild;
sql_exchange *exchange;
select_result *result;
+ Item *default_value;
+ LEX_STRING *comment;
+ LEX_USER *grant_user;
+ gptr yacc_yyss,yacc_yyvs;
+ THD *thd;
+ CHARSET_INFO *charset;
+ SQL_LIST *gorder_list;
List<key_part_spec> col_list;
List<key_part_spec> ref_list;
@@ -499,11 +514,6 @@ typedef struct st_lex
TYPELIB *interval;
create_field *last_field;
char *savepoint_name; // Transaction savepoint id
- Item *default_value, *comment;
- uint uint_geom_type;
- LEX_USER *grant_user;
- gptr yacc_yyss,yacc_yyvs;
- THD *thd;
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
HA_CREATE_INFO create_info;
@@ -512,6 +522,7 @@ typedef struct st_lex
ulong thread_id,type;
enum_sql_command sql_command;
thr_lock_type lock_option;
+ enum SSL_type ssl_type; /* defined in violite.h */
enum my_lex_states next_state;
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
@@ -519,17 +530,15 @@ typedef struct st_lex
enum ha_rkey_function ha_rkey_mode;
enum enum_enable_or_disable alter_keys_onoff;
enum enum_var_type option_type;
+ uint uint_geom_type;
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint param_count;
+ uint slave_thd_opt;
bool drop_primary, drop_if_exists, drop_temporary, local_file;
bool in_comment, ignore_space, verbose, simple_alter, no_write_to_binlog;
bool derived_tables, describe;
bool safe_to_cache_query;
- uint slave_thd_opt;
- CHARSET_INFO *charset;
- char *help_arg;
- SQL_LIST *gorder_list;
st_lex() {}
inline void uncacheable()
{
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index d030eaf617c..60e0a7c7e94 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -77,9 +77,6 @@ static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
List<Item> &fields, READ_INFO &read_info,
String &enclosed);
-
-#ifndef EMBEDDED_LIBRARY
-
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
List<Item> &fields, enum enum_duplicates handle_duplicates,
bool read_file_from_client,thr_lock_type lock_type)
@@ -91,7 +88,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
String *field_term=ex->field_term,*escaped=ex->escaped,
*enclosed=ex->enclosed;
bool is_fifo=0;
+#ifndef EMBEDDED_LIBRARY
LOAD_FILE_INFO lf_info;
+#endif
char *db = table_list->db; // This is never null
/* If no current database, use database where table is located */
char *tdb= thd->db ? thd->db : db;
@@ -171,7 +170,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else
#endif
{
- read_file_from_client=0;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
ex->file_name+=dirname_length(ex->file_name);
#endif
@@ -184,6 +182,17 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
else
{
+#ifdef EMBEDDED_LIBRARY
+ char *chk_name= ex->file_name;
+ while ((*chk_name == ' ') || (*chk_name == 't'))
+ chk_name++;
+ if (*chk_name == FN_CURLIB)
+ {
+ sprintf(name, "%s%s", mysql_data_home, ex->file_name);
+ unpack_filename(name, name);
+ }
+ else
+#endif /*EMBEDDED_LIBRARY*/
unpack_filename(name,ex->file_name);
#if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__)
MY_STAT stat_info;
@@ -215,7 +224,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
info.handle_duplicates=handle_duplicates;
info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
- READ_INFO read_info(file,tot_length,thd->variables.character_set_database,
+ READ_INFO read_info(file,tot_length,thd->variables.collation_database,
*field_term,*ex->line_start, *ex->line_term, *enclosed,
info.escape_char, read_file_from_client, is_fifo);
if (read_info.error)
@@ -225,6 +234,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
DBUG_RETURN(-1); // Can't allocate buffers
}
+#ifndef EMBEDDED_LIBRARY
if (!opt_old_rpl_compat && mysql_bin_log.is_open())
{
lf_info.thd = thd;
@@ -238,6 +248,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
lf_info.log_delayed= log_delayed;
read_info.set_io_cache_arg((void*) &lf_info);
}
+#endif /*!EMBEDDED_LIBRARY*/
+
restore_record(table,default_values);
thd->count_cuted_fields=1; /* calc cuted fields */
@@ -293,6 +305,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
{
if (transactional_table)
ha_autocommit_or_rollback(thd,error);
+#ifndef EMBEDDED_LIBRARY
if (!opt_old_rpl_compat && mysql_bin_log.is_open())
{
if (lf_info.wrote_create_file)
@@ -311,10 +324,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
which is nonsense.
*/
read_info.end_io_cache();
- Delete_file_log_event d(thd, log_delayed);
+ Delete_file_log_event d(thd, db, log_delayed);
mysql_bin_log.write(&d);
}
}
+#endif /*!EMBEDDED_LIBRARY*/
error= -1; // Error on read
goto err;
}
@@ -327,6 +341,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
{
if (opt_old_rpl_compat)
@@ -343,11 +358,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache(); // make sure last block gets logged
if (lf_info.wrote_create_file)
{
- Execute_load_log_event e(thd, log_delayed);
+ Execute_load_log_event e(thd, db, log_delayed);
mysql_bin_log.write(&e);
}
}
}
+#endif /*!EMBEDDED_LIBRARY*/
if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
err:
@@ -359,8 +375,6 @@ err:
DBUG_RETURN(error);
}
-#endif /* EMBEDDED_LIBRARY */
-
/****************************************************************************
** Read of rows of fixed size + optional garage + optonal newline
****************************************************************************/
@@ -640,11 +654,12 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
mysys/mf_iocache.c. So we work around the problem with a
manual assignment
*/
+ need_end_io_cache = 1;
+
+#ifndef EMBEDDED_LIBRARY
if (get_it_from_net)
cache.read_function = _my_b_net_read;
- need_end_io_cache = 1;
-#ifndef EMBEDDED_LIBRARY
if (!opt_old_rpl_compat && mysql_bin_log.is_open())
cache.pre_read = cache.pre_close =
(IO_CACHE_CALLBACK) log_loaded_block;
@@ -806,9 +821,13 @@ int READ_INFO::read_field()
row_end= to;
return 0;
}
- /* Copy the found '"' character */
+ /*
+ The string didn't terminate yet.
+ Store back next character for the loop
+ */
PUSH(chr);
- chr='"';
+ /* copy the found term character to 'to' */
+ chr= found_enclosed_char;
}
else if (chr == field_term_char && found_enclosed_char == INT_MAX)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 33e96cc2776..2c15362d9fa 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -44,7 +44,6 @@
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
-extern int yyparse(void *thd);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
@@ -53,15 +52,19 @@ extern "C" int gethostname(char *name, int namelen);
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
+static bool single_table_command_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, int *res);
+#else
+#define check_merge_table_access(thd, db, tables) false
+#define single_table_command_access(thd, privilege, tables, res) false
+#endif
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, char **filename_ptr,
char *table_name);
-static bool single_table_command_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, int *res);
-
const char *any_db="*any*"; // Special symbol for check_access
const char *command_name[]={
@@ -120,7 +123,6 @@ static bool end_active_trans(THD *thd)
static HASH hash_user_connections;
-extern pthread_mutex_t LOCK_user_conn;
static int get_or_create_user_conn(THD *thd, const char *user,
const char *host,
@@ -161,7 +163,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
if (max_user_connections && mqh->connections > max_user_connections)
uc->user_resources.connections = max_user_connections;
uc->intime=thd->thr_create_time;
- if (hash_insert(&hash_user_connections, (byte*) uc))
+ if (my_hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
send_error(thd, 0, NullS); // Out of memory
@@ -176,154 +178,186 @@ end:
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
- Check if user is ok
-
+ Check if user exist and password supplied is correct.
SYNOPSIS
check_user()
- thd Thread handle
- command Command for connection (for log)
- user Name of user trying to connect
- passwd Scrambled password sent from client
- db Database to connect to
- check_count If set to 1, don't allow too many connection
- simple_connect If 1 then client is of old type and we should connect
- using the old method (no challange)
- do_send_error Set to 1 if we should send error to user
- prepared_scramble Buffer to store hash password of new connection
- had_password Set to 1 if the user gave a password
- cur_priv_version Check flag to know if someone flushed the privileges
- since last code
- hint_user Pointer used by acl_getroot() to remmeber user for
- next call
-
- RETURN
- 0 ok
- thd->user, thd->master_access, thd->priv_user, thd->db and
- thd->db_access are updated
- 1 Access denied; Error sent to client
- -1 If do_send_error == 1: Failed connect, error sent to client
- If do_send_error == 0: Prepare for stage of connect
+ thd thread handle, thd->{host,user,ip} are used
+ command originator of the check: now check_user is called
+ during connect and change user procedures; used for
+ logging.
+ passwd scrambled password recieved from client
+ passwd_len length of scrambled password
+ db database name to connect to, may be NULL
+ check_count dont know exactly
+
+ Note, that host, user and passwd may point to communication buffer.
+ Current implementation does not depened on that, but future changes
+ should be done with this in mind; 'thd' is INOUT, all other params
+ are 'IN'.
+
+ RETURN VALUE
+ 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and
+ thd->db_access are updated; OK is sent to client;
+ -1 access denied or handshake error; error is sent to client;
+ >0 error, not sent to client
*/
-static int check_user(THD *thd,enum_server_command command, const char *user,
- const char *passwd, const char *db, bool check_count,
- bool simple_connect, bool do_send_error,
- char *prepared_scramble, bool had_password,
- uint *cur_priv_version, ACL_USER** hint_user)
+int check_user(THD *thd, enum enum_server_command command,
+ const char *passwd, uint passwd_len, const char *db,
+ bool check_count)
{
- thd->db=0;
- thd->db_length=0;
- USER_RESOURCES ur;
- char tmp_passwd[SCRAMBLE41_LENGTH+1];
DBUG_ENTER("check_user");
+ my_bool opt_secure_auth_local;
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ opt_secure_auth_local= opt_secure_auth;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+
/*
- Move password to temporary buffer as it may be stored in communication
- buffer
+ If the server is running in secure auth mode, short scrambles are
+ forbidden.
*/
- strmake(tmp_passwd, passwd, sizeof(tmp_passwd));
- passwd= tmp_passwd; // Use local copy
-
- /* We shall avoid dupplicate user allocations here */
- if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
+ if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
{
- send_error(thd,ER_OUT_OF_RESOURCES);
- DBUG_RETURN(1);
+ net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
}
- thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
- passwd, thd->scramble,
- &thd->priv_user, thd->priv_host,
- (protocol_version == 9 ||
- !(thd->client_capabilities &
- CLIENT_LONG_PASSWORD)),
- &ur,prepared_scramble,
- cur_priv_version,hint_user);
-
- DBUG_PRINT("info",
- ("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'",
- thd->client_capabilities, thd->max_client_packet_length,
- thd->host_or_ip, thd->user, thd->priv_user,
- had_password ? "yes": "no",
- thd->master_access, thd->db ? thd->db : "*none*"));
+ if (passwd_len != 0 &&
+ passwd_len != SCRAMBLE_LENGTH &&
+ passwd_len != SCRAMBLE_LENGTH_323)
+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
/*
- In case we're going to retry we should not send error message at this
- point
+ Clear thd->db as it points to something, that will be freed when
+ connection is closed. We don't want to accidently free a wrong pointer
+ if connect failed. Also in case of 'CHANGE USER' failure, current
+ database will be switched to 'no database selected'.
*/
- if (thd->master_access & NO_ACCESS)
+ thd->db= 0;
+ thd->db_length= 0;
+
+ USER_RESOURCES ur;
+ int res= acl_getroot(thd, &ur, passwd, passwd_len);
+#ifndef EMBEDDED_LIBRARY
+ if (res == -1)
+ {
+ /*
+ This happens when client (new) sends password scrambled with
+ scramble(), but database holds old value (scrambled with
+ scramble_323()). Here we please client to send scrambled_password
+ in old format.
+ */
+ NET *net= &thd->net;
+ if (opt_secure_auth_local)
+ {
+ net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
+ thd->user, thd->host_or_ip);
+ mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
+ thd->user, thd->host_or_ip);
+ DBUG_RETURN(-1);
+ }
+ if (send_old_password_request(thd) ||
+ my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
+ { // specific packet size
+ inc_host_errors(&thd->remote.sin_addr);
+ DBUG_RETURN(ER_HANDSHAKE_ERROR);
+ }
+ /* Final attempt to check the user based on reply */
+ /* So as passwd is short, errcode is always >= 0 */
+ res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
+ }
+#endif /*EMBEDDED_LIBRARY*/
+ /* here res is always >= 0 */
+ if (res == 0)
{
- if (do_send_error || !had_password || !*hint_user)
+ if (!(thd->master_access & NO_ACCESS)) // authentification is OK
{
- DBUG_PRINT("info",("Access denied"));
+ DBUG_PRINT("info",
+ ("Capabilities: %d packet_length: %ld Host: '%s' "
+ "Login user: '%s' Priv_user: '%s' Using password: %s "
+ "Access: %u db: '%s'",
+ thd->client_capabilities, thd->max_client_packet_length,
+ thd->host_or_ip, thd->user, thd->priv_user,
+ passwd_len ? "yes": "no",
+ thd->master_access, thd->db ? thd->db : "*none*"));
+
+ if (check_count)
+ {
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ bool count_ok= thread_count < max_connections + delayed_insert_threads
+ || (thd->master_access & SUPER_ACL);
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ if (!count_ok)
+ { // too many connections
+ send_error(thd, ER_CON_COUNT_ERROR);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ /* Why logging is performed before all checks've passed? */
+ mysql_log.write(thd,command,
+ (thd->priv_user == thd->user ?
+ (char*) "%s@%s on %s" :
+ (char*) "%s@%s as anonymous on %s"),
+ thd->user, thd->host_or_ip,
+ db ? db : (char*) "");
+
/*
- Old client should get nicer error message if password version is
- not supported
+ This is the default access rights for the current database. It's
+ set to 0 here because we don't have an active database yet (and we
+ may not have an active database to set.
*/
- if (simple_connect && *hint_user && (*hint_user)->pversion)
+ thd->db_access=0;
+
+ /* Don't allow user to connect if he has done too many queries */
+ if ((ur.questions || ur.updates ||
+ ur.connections || max_user_connections) &&
+ get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
+ DBUG_RETURN(1);
+ if (thd->user_connect && thd->user_connect->user_resources.connections &&
+ check_for_max_user_connections(thd, thd->user_connect))
+ DBUG_RETURN(1);
+
+ /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
+ if (db && db[0])
{
- net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
- mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ if (mysql_change_db(thd, db))
+ {
+ if (thd->user_connect)
+ decrease_user_connections(thd->user_connect);
+ DBUG_RETURN(-1);
+ }
}
else
- {
- net_printf(thd, ER_ACCESS_DENIED_ERROR,
- thd->user,
- thd->host_or_ip,
- had_password ? ER(ER_YES) : ER(ER_NO));
- mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
- thd->user,
- thd->host_or_ip,
- had_password ? ER(ER_YES) : ER(ER_NO));
- }
- DBUG_RETURN(1); // Error already given
- }
- DBUG_PRINT("info",("Prepare for second part of handshake"));
- DBUG_RETURN(-1); // no report error in special handshake
- }
-
- if (check_count)
- {
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
- !(thd->master_access & SUPER_ACL));
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- if (tmp)
- { // Too many connections
- send_error(thd, ER_CON_COUNT_ERROR);
- DBUG_RETURN(1);
+ send_ok(thd);
+ thd->password= test(passwd_len); // remember for error messages
+ /* Ready to handle queries */
+ DBUG_RETURN(0);
}
}
- mysql_log.write(thd,command,
- (thd->priv_user == thd->user ?
- (char*) "%s@%s on %s" :
- (char*) "%s@%s as anonymous on %s"),
- user,
- thd->host_or_ip,
- db ? db : (char*) "");
- thd->db_access=0;
- /* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.connections || max_user_connections) &&
- get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
- DBUG_RETURN(1);
- if (thd->user_connect && ((thd->user_connect->user_resources.connections) ||
- max_user_connections) &&
- check_for_max_user_connections(thd, thd->user_connect))
- DBUG_RETURN(1);
-
- if (db && db[0])
- {
- int error= test(mysql_change_db(thd,db));
- if (error && thd->user_connect)
- decrease_user_connections(thd->user_connect);
- DBUG_RETURN(error);
- }
- send_ok(thd); // Ready to handle questions
- thd->password= test(passwd[0]); // Remember for error messages
- DBUG_RETURN(0); // ok
+ else if (res == 2) // client gave short hash, server has long hash
+ {
+ net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
+ }
+ net_printf(thd, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
+ mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
+ thd->user,
+ thd->host_or_ip,
+ passwd_len ? ER(ER_YES) : ER(ER_NO));
+ DBUG_RETURN(-1);
}
+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
+
/*
Check for maximum allowable user connections, if the mysqld server is
@@ -433,6 +467,7 @@ bool is_update_query(enum enum_sql_command command)
return uc_update_queries[command];
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check if maximum queries per hour limit has been reached
returns 0 if OK.
@@ -523,54 +558,44 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
}
(void) pthread_mutex_unlock(&LOCK_user_conn);
}
-
+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
/*
- Check connnectionn and get priviliges
-
+ Perform handshake, authorize client and update thd ACL variables.
SYNOPSIS
- check_connections
- thd Thread handle
+ check_connection()
+ thd thread handle
RETURN
- 0 ok
- -1 Error, which is sent to user
- > 0 Error code (not sent to user)
+ 0 success, OK is sent to user, thd is updated.
+ -1 error, which is sent to user
+ > 0 error code (not sent to user)
*/
-#ifndef EMBEDDED_LIBRARY
-static int
-check_connections(THD *thd)
+#ifndef EMBEDDED_LIBRARY
+static int check_connection(THD *thd)
{
- int res;
- uint connect_errors=0;
- uint cur_priv_version;
- bool using_password;
+ uint connect_errors= 0;
NET *net= &thd->net;
- char *end, *user, *passwd, *db;
- char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */
- char db_buff[NAME_LEN+1];
- ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
- DBUG_PRINT("info",("New connection received on %s",
- vio_description(net->vio)));
-
- /* Remove warning from valgrind. TODO: Fix it in password.c */
- bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble));
+
+ DBUG_PRINT("info",
+ ("New connection received on %s", vio_description(net->vio)));
+
if (!thd->host) // If TCP/IP connection
{
char ip[30];
if (vio_peer_addr(net->vio, ip, &thd->peer_port))
return (ER_BAD_HOST_ERROR);
- if (!(thd->ip = my_strdup(ip,MYF(0))))
+ if (!(thd->ip= my_strdup(ip,MYF(0))))
return (ER_OUT_OF_RESOURCES);
- thd->host_or_ip=thd->ip;
+ thd->host_or_ip= thd->ip;
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
/* Fast local hostname resolve for Win32 */
if (!strcmp(thd->ip,"127.0.0.1"))
{
- thd->host= (char*) localhost;
- thd->host_or_ip= localhost;
+ thd->host= (char*) my_localhost;
+ thd->host_or_ip= my_localhost;
}
else
#endif
@@ -600,15 +625,14 @@ check_connections(THD *thd)
DBUG_PRINT("info",("Host: %s",thd->host));
thd->host_or_ip= thd->host;
thd->ip= 0;
- bzero((char*) &thd->remote,sizeof(struct sockaddr));
+ bzero((char*) &thd->remote, sizeof(struct sockaddr));
}
- /* Ensure that wrong hostnames doesn't cause buffer overflows */
vio_keepalive(net->vio, TRUE);
-
- ulong pkt_len=0;
+ ulong pkt_len= 0;
+ char *end;
{
/* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
+ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
@@ -622,19 +646,34 @@ check_connections(THD *thd)
client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
#endif /* HAVE_OPENSSL */
- end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
- int4store((uchar*) end,thd->thread_id);
- end+=4;
- memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
- end+=SCRAMBLE_LENGTH +1;
- int2store(end,client_flags);
+ end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
+ int4store((uchar*) end, thd->thread_id);
+ end+= 4;
+ /*
+ So as check_connection is the only entry point to authorization
+ procedure, scramble is set here. This gives us new scramble for
+ each handshake.
+ */
+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
+ /*
+ Old clients does not understand long scrambles, but can ignore packet
+ tail: that's why first part of the scramble is placed here, and second
+ part at the end of packet.
+ */
+ end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
+
+ int2store(end, client_flags);
+ /* write server characteristics: up to 16 bytes allowed */
end[2]=(char) default_charset_info->number;
- int2store(end+3,thd->server_status);
- bzero(end+5,13);
- end+=18;
-
- // At this point we write connection message and read reply
- if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
+ int2store(end+3, thd->server_status);
+ bzero(end+5, 13);
+ end+= 18;
+ /* write scramble tail */
+ end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
+ SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
+
+ /* At this point we write connection message and read reply */
+ if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
(uint) (end-buff)) ||
(pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
@@ -723,7 +762,7 @@ check_connections(THD *thd)
return(ER_HANDSHAKE_ERROR);
}
DBUG_PRINT("info", ("Reading user information over SSL layer"));
- if ((pkt_len=my_net_read(net)) == packet_error ||
+ if ((pkt_len= my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
{
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
@@ -740,25 +779,6 @@ check_connections(THD *thd)
return(ER_HANDSHAKE_ERROR);
}
- user= end;
- passwd= strend(user)+1;
- db=0;
- using_password= test(passwd[0]);
- if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
- {
- db= strend(passwd)+1;
- uint32 length= copy_and_convert(db_buff, sizeof(db_buff)-1,
- system_charset_info,
- db, strlen(db),
- thd->charset());
- db_buff[length]= 0;
- db= db_buff;
- }
-
- /* We can get only old hash at this point */
- if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
- return ER_HANDSHAKE_ERROR;
-
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
@@ -766,63 +786,37 @@ check_connections(THD *thd)
net->return_status= &thd->server_status;
net->read_timeout=(uint) thd->variables.net_read_timeout;
- /* Simple connect only for old clients. New clients always use secure auth */
- bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
-
- /* Check user permissions. If password failure we'll get scramble back */
- if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
- simple_connect, prepared_scramble, using_password,
- &cur_priv_version,
- &cached_user)) < 0)
- {
- /* Store current used and database as they are erased with next packet */
- char tmp_user[USERNAME_LENGTH+1];
- char tmp_db[NAME_LEN+1];
-
- /* If the client is old we just have to return error */
- if (simple_connect)
- return -1;
-
- DBUG_PRINT("info",("password challenge"));
-
- tmp_user[0]= tmp_db[0]= 0;
- if (user)
- strmake(tmp_user,user,USERNAME_LENGTH);
- if (db)
- strmake(tmp_db,db,NAME_LEN);
+ char *user= end;
+ char *passwd= strend(user)+1;
+ char *db= passwd;
+ char db_buff[NAME_LEN+1]; // buffer to store db in utf8
+ /*
+ Old clients send null-terminated string as password; new clients send
+ the size (1 byte) + string (not null-terminated). Hence in case of empty
+ password both send '\0'.
+ */
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ *passwd++ : strlen(passwd);
+ db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
+ db + passwd_len + 1 : 0;
+
+ /* Since 4.1 all database names are stored in utf8 */
+ if (db)
+ {
+ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info,
+ db, strlen(db),
+ thd->charset())]= 0;
+ db= db_buff;
+ }
- /* Write hash and encrypted scramble to client */
- if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
- net_flush(net))
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
- /* Reading packet back */
- if ((pkt_len= my_net_read(net)) == packet_error)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
- /* We have to get very specific packet size */
- if (pkt_len != SCRAMBLE41_LENGTH)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
- /* Final attempt to check the user based on reply */
- if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
- tmp_db, 1, 0, 1, prepared_scramble, using_password,
- &cur_priv_version,
- &cached_user))
- return -1;
- }
- else if (res)
- return -1; // Error sent from check_user()
- return 0;
+ if (thd->user)
+ x_free(thd->user);
+ if (!(thd->user= my_strdup(user, MYF(0))))
+ return (ER_OUT_OF_RESOURCES);
+ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
}
-
pthread_handler_decl(handle_one_connection,arg)
{
THD *thd=(THD*) arg;
@@ -876,7 +870,7 @@ pthread_handler_decl(handle_one_connection,arg)
NET *net= &thd->net;
thd->thread_stack= (char*) &thd;
- if ((error=check_connections(thd)))
+ if ((error=check_connection(thd)))
{ // Wrong permissions
if (error > 0)
net_printf(thd,error,thd->host_or_ip);
@@ -938,6 +932,8 @@ end_thread:
return(0); /* purecov: deadcode */
}
+#endif /* EMBEDDED_LIBRARY */
+
/*
Execute commands from bootstrap_file.
Used when creating the initial grant tables
@@ -952,12 +948,15 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
/* The following must be called before DBUG_ENTER */
if (my_thread_init() || thd->store_globals())
{
+#ifndef EMBEDDED_LIBRARY
close_connection(thd, ER_OUT_OF_RESOURCES, 1);
+#endif
thd->fatal_error();
goto end;
}
DBUG_ENTER("handle_bootstrap");
+#ifndef EMBEDDED_LIBRARY
pthread_detach_this_thread();
thd->thread_stack= (char*) &thd;
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
@@ -965,6 +964,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
VOID(sigemptyset(&set)); // Get mask in use
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
+#endif /* EMBEDDED_LIBRARY */
if (thd->variables.max_join_size == HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
@@ -986,6 +986,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0';
thd->query_id=query_id++;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
{
thd->net.error = 0;
@@ -993,6 +994,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
break;
}
+#endif
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
@@ -1003,17 +1005,17 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
/* thd->fatal_error should be set in case something went wrong */
end:
+#ifndef EMBEDDED_LIBRARY
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
(void) pthread_mutex_unlock(&LOCK_thread_count);
(void) pthread_cond_broadcast(&COND_thread_count);
my_thread_end();
pthread_exit(0);
+#endif
DBUG_RETURN(0); // Never reached
}
-#endif /* EMBEDDED_LIBRARY */
-
/* This works because items are allocated with sql_alloc() */
void free_items(Item *item)
@@ -1048,11 +1050,12 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
- if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege,0,0))
goto err;
if (grant_option && check_grant(thd, SELECT_ACL, table_list))
goto err;
-
+#endif
thd->free_list = 0;
thd->query_length=(uint) strlen(tbl_name);
thd->query = tbl_name;
@@ -1161,7 +1164,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_log.write(thd,command,"%s",thd->db);
break;
}
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
case COM_REGISTER_SLAVE:
{
if (!register_slave(thd, (uchar*)packet, packet_length))
@@ -1188,116 +1191,73 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CHANGE_USER:
{
thd->change_user();
- thd->clear_error(); // If errors from rollback
+ thd->clear_error(); // if errors from rollback
- statistic_increment(com_other,&LOCK_status);
- char *user= (char*) packet;
+ statistic_increment(com_other, &LOCK_status);
+ char *user= (char*) packet;
char *passwd= strend(user)+1;
- char *db= strend(passwd)+1;
-
- /* Save user and privileges */
- uint save_master_access=thd->master_access;
- uint save_db_access= thd->db_access;
- uint save_db_length= thd->db_length;
- char *save_user= thd->user;
- thd->user=NULL; /* Needed for check_user to allocate new user */
- char *save_priv_user= thd->priv_user;
- char *save_db= thd->db;
- USER_CONN *save_uc= thd->user_connect;
- bool simple_connect;
- bool using_password;
- char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
- char tmp_user[USERNAME_LENGTH+1];
- char tmp_db[NAME_LEN+1];
- ACL_USER* cached_user ; /* Cached user */
- uint cur_priv_version; /* Cached grant version */
- int res;
- ulong pkt_len= 0; /* Length of reply packet */
-
- bzero((char*) prepared_scramble, sizeof(prepared_scramble));
+ /*
+ Old clients send null-terminated string ('\0' for empty string) for
+ password. New clients send the size (1 byte) + string (not null
+ terminated, so also '\0' for empty string).
+ */
+ char db_buff[NAME_LEN+1]; // buffer to store db in utf8
+ char *db= passwd;
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ *passwd++ : strlen(passwd);
+ db+= passwd_len + 1;
/* Small check for incomming packet */
-
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
- goto restore_user_err;
-
- /* Now we shall basically perform authentication again */
-
- /* We can get only old hash at this point */
- if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
- goto restore_user_err;
-
- cached_user= NULL;
-
- /* Simple connect only for old clients. New clients always use sec. auth*/
- simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
-
- /* Store information if we used password. passwd will be dammaged */
- using_password=test(passwd[0]);
+ {
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+ break;
+ }
- if (simple_connect) /* Restore scramble for old clients */
- memcpy(thd->scramble,thd->old_scramble,9);
+ /* Convert database name to utf8 */
+ db_buff[copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info, db, strlen(db),
+ thd->charset())]= 0;
+ db= db_buff;
- /*
- Check user permissions. If password failure we'll get scramble back
- Do not retry if we already have sent error (result>0)
- */
- if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0,
- simple_connect, simple_connect, prepared_scramble,
- using_password, &cur_priv_version, &cached_user)) < 0)
+ /* Save user and privileges */
+ uint save_master_access= thd->master_access;
+ uint save_db_access= thd->db_access;
+ uint save_db_length= thd->db_length;
+ char *save_user= thd->user;
+ char *save_priv_user= thd->priv_user;
+ char *save_db= thd->db;
+ USER_CONN *save_uc= thd->user_connect;
+ thd->user= my_strdup(user, MYF(0));
+ if (!thd->user)
{
- /* If the client is old we just have to have auth failure */
- if (simple_connect)
- goto restore_user; /* Error is already reported */
-
- /* Store current used and database as they are erased with next packet */
- tmp_user[0]= tmp_db[0]= 0;
- if (user)
- strmake(tmp_user,user,USERNAME_LENGTH);
- if (db)
- strmake(tmp_db,db,NAME_LEN);
-
- /* Write hash and encrypted scramble to client */
- if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
- net_flush(net))
- goto restore_user_err;
-
- /* Reading packet back */
- if ((pkt_len=my_net_read(net)) == packet_error)
- goto restore_user_err;
-
- /* We have to get very specific packet size */
- if (pkt_len != SCRAMBLE41_LENGTH)
- goto restore_user;
-
- /* Final attempt to check the user based on reply */
- if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos,
- tmp_db, 0, 0, 1, prepared_scramble, using_password,
- &cur_priv_version, &cached_user))
- goto restore_user;
+ thd->user= save_user;
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ break;
}
- else if (res)
- goto restore_user;
-
- /* Finally we've authenticated new user */
- if (max_connections && save_uc)
- decrease_user_connections(save_uc);
- x_free((gptr) save_db);
- x_free((gptr) save_user);
- thd->password=using_password;
- break;
- /* Bad luck we shall restore old user */
-restore_user_err:
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
-restore_user:
- x_free(thd->user);
- thd->master_access=save_master_access;
- thd->db_access=save_db_access;
- thd->db=save_db;
- thd->db_length=save_db_length;
- thd->user=save_user;
- thd->priv_user=save_priv_user;
+ if (res)
+ {
+ /* authentification failure, we shall restore old user */
+ if (res > 0)
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+ x_free(thd->user);
+ thd->user= save_user;
+ thd->priv_user= save_priv_user;
+ thd->master_access= save_master_access;
+ thd->db_access= save_db_access;
+ thd->db= save_db;
+ thd->db_length= save_db_length;
+ }
+ else
+ {
+ /* we've authenticated new user */
+ if (max_connections && save_uc)
+ decrease_user_connections(save_uc);
+ x_free((gptr) save_db);
+ x_free((gptr) save_user);
+ }
break;
}
#endif /* EMBEDDED_LIBRARY */
@@ -1395,11 +1355,13 @@ restore_user:
my_casedn_str(files_charset_info, table_list.real_name);
remove_escape(table_list.real_name); // This can't have wildcards
- if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access,0,0))
break;
table_list.grant.privilege=thd->col_access;
if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
break;
+#endif /*DONT_ALLOW_SHOW_COMMANDS*/
mysqld_list_fields(thd,&table_list,fields);
free_items(thd->free_list);
break;
@@ -1422,7 +1384,7 @@ restore_user:
net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
- if (check_access(thd,CREATE_ACL,db,0,1))
+ if (check_access(thd,CREATE_ACL,db,0,1,0))
break;
mysql_log.write(thd,command,packet);
mysql_create_db(thd,db,0,0);
@@ -1438,7 +1400,7 @@ restore_user:
net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
- if (check_access(thd,DROP_ACL,db,0,1))
+ if (check_access(thd,DROP_ACL,db,0,1,0))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -1511,12 +1473,15 @@ restore_user:
error=TRUE;
break;
#endif
-#ifndef EMBEDDED_LIBRARY
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
+#ifndef EMBEDDED_LIBRARY
char buff[200];
+#else
+ char *buff= thd->net.last_error;
+#endif
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
"Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f",
@@ -1529,23 +1494,32 @@ restore_user:
sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
(sf_malloc_cur_memory+1023L)/1024L,
(sf_malloc_max_memory+1023L)/1024L);
- #endif
+#endif
+#ifndef EMBEDDED_LIBRARY
VOID(my_net_write(net, buff,(uint) strlen(buff)));
VOID(net_flush(net));
+#endif
break;
}
-#endif
case COM_PING:
statistic_increment(com_other,&LOCK_status);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
+#endif
mysql_log.write(thd,command,NullS);
- mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
- thd->priv_user,0);
+ mysqld_list_processes(thd,
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ thd->master_access & PROCESS_ACL ?
+ NullS : thd->priv_user
+#else
+ NullS
+#endif
+ ,0);
break;
case COM_PROCESS_KILL:
{
@@ -1644,8 +1618,8 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
/* We must allocate some extra memory for query cache */
if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
packet_length,
- thd->db_length+2+
- sizeof(ha_rows))))
+ thd->db_length+ 1 +
+ QUERY_CACHE_FLAGS_SIZE)))
return 1;
thd->query[packet_length]=0;
thd->query_length= packet_length;
@@ -1685,7 +1659,7 @@ mysql_execute_command(THD *thd)
*/
thd->old_total_warn_count= thd->total_warn_count;
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
if (thd->slave_thread)
{
/*
@@ -1711,7 +1685,7 @@ mysql_execute_command(THD *thd)
}
#endif
}
-#endif /* EMBEDDED_LIBRARY */
+#endif /* !HAVE_REPLICATION */
/*
TODO: make derived tables processing 'inside' SELECT processing.
TODO: solve problem with depended derived tables in subselects
@@ -1746,7 +1720,11 @@ mysql_execute_command(THD *thd)
Except for the replication thread and the 'super' users.
*/
if (opt_readonly &&
- !(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
+ !(thd->slave_thread
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ || (thd->master_access & SUPER_ACL)
+#endif
+ ) &&
(uc_update_queries[lex->sql_command] > 0))
{
send_error(thd, ER_CANT_UPDATE_WITH_READLOCK);
@@ -1758,29 +1736,34 @@ mysql_execute_command(THD *thd)
case SQLCOM_SELECT:
{
select_result *result=lex->result;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (tables)
{
res=check_table_access(thd,
lex->exchange ? SELECT_ACL | FILE_ACL :
SELECT_ACL,
- tables);
+ tables,0);
}
else
res=check_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL,
- any_db);
+ any_db,0,0,0);
if (res)
{
res=0;
break; // Error message is given
}
-
+#endif
+ /*
+ In case of single SELECT unit->global_parameters points on first SELECT
+ TODO: move counters to SELECT_LEX
+ */
unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit;
unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+
unit->global_parameters->offset_limit);
if (unit->select_limit_cnt <
(ha_rows) unit->global_parameters->select_limit)
unit->select_limit_cnt= HA_POS_ERROR; // no limit
- if (unit->select_limit_cnt == HA_POS_ERROR)
+ if (unit->select_limit_cnt == HA_POS_ERROR && !select_lex->next_select())
select_lex->options&= ~OPTION_FOUND_ROWS;
if (!(res=open_and_lock_tables(thd,tables)))
@@ -1821,8 +1804,9 @@ mysql_execute_command(THD *thd)
}
break;
}
+
case SQLCOM_DO:
- if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
(res= open_and_lock_tables(thd,tables))))
break;
@@ -1858,7 +1842,6 @@ mysql_execute_command(THD *thd)
break;
}
#endif
-
case SQLCOM_SHOW_WARNS:
{
res= mysqld_show_warnings(thd, (ulong)
@@ -1878,6 +1861,7 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
+ /* This query don't work now. See comment in repl_failsafe.cc */
#ifndef WORKING_NEW_MASTER
net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
res= 1;
@@ -1887,7 +1871,7 @@ mysql_execute_command(THD *thd)
break;
}
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
case SQLCOM_SHOW_SLAVE_HOSTS:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
@@ -1907,7 +1891,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_BACKUP_TABLE:
{
if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables) ||
+ check_table_access(thd,SELECT_ACL, tables,0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
res = mysql_backup_table(thd, tables);
@@ -1917,7 +1901,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_RESTORE_TABLE:
{
if (check_db_used(thd,tables) ||
- check_table_access(thd, INSERT_ACL, tables) ||
+ check_table_access(thd, INSERT_ACL, tables,0) ||
check_global_access(thd, FILE_ACL))
goto error; /* purecov: inspected */
res = mysql_restore_table(thd, tables);
@@ -1926,14 +1910,12 @@ mysql_execute_command(THD *thd)
case SQLCOM_PRELOAD_KEYS:
{
if (check_db_used(thd, tables) ||
- check_access(thd, INDEX_ACL, tables->db, &tables->grant.privilege))
+ check_access(thd, INDEX_ACL, tables->db, &tables->grant.privilege,0,0))
goto error;
res = mysql_preload_keys(thd, tables);
break;
}
-
-
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
case SQLCOM_CHANGE_MASTER:
{
if (check_global_access(thd, SUPER_ACL))
@@ -1970,8 +1952,7 @@ mysql_execute_command(THD *thd)
else
res = load_master_data(thd);
break;
-#endif /* EMBEDDED_LIBRARY */
-
+#endif /* HAVE_REPLICATION */
#ifdef HAVE_INNOBASE_DB
case SQLCOM_SHOW_INNODB_STATUS:
{
@@ -1981,13 +1962,13 @@ mysql_execute_command(THD *thd)
break;
}
#endif
-
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
case SQLCOM_LOAD_MASTER_TABLE:
{
if (!tables->db)
tables->db=thd->db;
- if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,CREATE_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
if (grant_option)
{
@@ -1999,6 +1980,7 @@ mysql_execute_command(THD *thd)
if (error)
goto error;
}
+#endif
if (strlen(tables->real_name) > NAME_LEN)
{
net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
@@ -2014,15 +1996,18 @@ mysql_execute_command(THD *thd)
UNLOCK_ACTIVE_MI;
break;
}
-#endif /* EMBEDDED_LIBRARY */
+#endif /* HAVE_REPLICATION */
case SQLCOM_CREATE_TABLE:
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
CREATE_TMP_ACL : CREATE_ACL);
+#endif
if (!tables->db)
tables->db=thd->db;
- if (check_access(thd,want_priv,tables->db,&tables->grant.privilege) ||
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,want_priv,tables->db,&tables->grant.privilege,0,0) ||
check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
@@ -2037,6 +2022,7 @@ mysql_execute_command(THD *thd)
if (error)
goto error;
}
+#endif
if (strlen(tables->real_name) > NAME_LEN)
{
net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
@@ -2066,11 +2052,13 @@ mysql_execute_command(THD *thd)
net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (tables->next)
{
- if (check_table_access(thd, SELECT_ACL, tables->next))
+ if (check_table_access(thd, SELECT_ACL, tables->next,0))
goto error; // Error message is given
}
+#endif
select_lex->options|= SELECT_NO_UNLOCK;
unit->offset_limit_cnt= select_lex->offset_limit;
unit->select_limit_cnt= select_lex->select_limit+
@@ -2100,14 +2088,6 @@ mysql_execute_command(THD *thd)
(Table_ident *)lex->name);
else
{
- List_iterator<create_field> fields(lex->create_list);
- create_field *field;
- while ((field= fields++))
- {
- if (!field->charset)
- field->charset= lex->create_info.table_charset;
- field->create_length_to_internal_length();
- }
res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
tables->real_name, &lex->create_info,
lex->create_list,
@@ -2121,17 +2101,19 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_INDEX:
if (!tables->db)
tables->db=thd->db;
- if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
if (grant_option && check_grant(thd,INDEX_ACL,tables))
goto error;
+#endif
if (end_active_trans(thd))
res= -1;
else
res = mysql_create_index(thd, tables, lex->key_list);
break;
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
case SQLCOM_SLAVE_START:
{
LOCK_ACTIVE_MI;
@@ -2164,7 +2146,7 @@ mysql_execute_command(THD *thd)
UNLOCK_ACTIVE_MI;
break;
}
-#endif
+#endif /* HAVE_REPLICATION */
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
@@ -2183,14 +2165,15 @@ mysql_execute_command(THD *thd)
tables->db=thd->db;
if (!select_lex->db)
select_lex->db=tables->db;
- if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
- check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
+ if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege,0,0) ||
+ check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv,0,0)||
check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
if (!tables->db)
tables->db=thd->db;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option)
{
if (check_grant(thd,ALTER_ACL,tables))
@@ -2206,6 +2189,7 @@ mysql_execute_command(THD *thd)
goto error;
}
}
+#endif
/* Don't yet allow changing of symlinks with ALTER TABLE */
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
/* ALTER TABLE ends previous transaction */
@@ -2224,18 +2208,19 @@ mysql_execute_command(THD *thd)
}
break;
}
-#endif
+#endif /*DONT_ALLOW_SHOW_COMMANDS*/
case SQLCOM_RENAME_TABLE:
{
TABLE_LIST *table;
if (check_db_used(thd,tables))
goto error;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
for (table=tables ; table ; table=table->next->next)
{
if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
- &table->grant.privilege) ||
+ &table->grant.privilege,0,0) ||
check_access(thd, INSERT_ACL | CREATE_ACL, table->next->db,
- &table->next->grant.privilege))
+ &table->next->grant.privilege,0,0))
goto error;
if (grant_option)
{
@@ -2250,6 +2235,7 @@ mysql_execute_command(THD *thd)
goto error;
}
}
+#endif
query_cache_invalidate3(thd, tables, 0);
if (end_active_trans(thd))
res= -1;
@@ -2279,16 +2265,24 @@ mysql_execute_command(THD *thd)
{
if (check_db_used(thd, tables) ||
check_access(thd, SELECT_ACL | EXTRA_ACL, tables->db,
- &tables->grant.privilege))
+ &tables->grant.privilege,0,0))
goto error;
res = mysqld_show_create(thd, tables);
break;
}
#endif
+ case SQLCOM_CHECKSUM:
+ {
+ if (check_db_used(thd,tables) ||
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
+ goto error; /* purecov: inspected */
+ res = mysql_checksum_table(thd, tables, &lex->check_opt);
+ break;
+ }
case SQLCOM_REPAIR:
{
if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
+ check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
goto error; /* purecov: inspected */
res = mysql_repair_table(thd, tables, &lex->check_opt);
/* ! we write after unlocking the table */
@@ -2306,7 +2300,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_CHECK:
{
if (check_db_used(thd,tables) ||
- check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables))
+ check_table_access(thd, SELECT_ACL | EXTRA_ACL , tables,0))
goto error; /* purecov: inspected */
res = mysql_check_table(thd, tables, &lex->check_opt);
break;
@@ -2314,7 +2308,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_ANALYZE:
{
if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
+ check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
goto error; /* purecov: inspected */
res = mysql_analyze_table(thd, tables, &lex->check_opt);
/* ! we write after unlocking the table */
@@ -2334,7 +2328,7 @@ mysql_execute_command(THD *thd)
{
HA_CREATE_INFO create_info;
if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL | INSERT_ACL, tables))
+ check_table_access(thd,SELECT_ACL | INSERT_ACL, tables,0))
goto error; /* purecov: inspected */
if (specialflag & (SPECIAL_SAFE_MODE | SPECIAL_NO_NEW_FUNC))
{
@@ -2374,7 +2368,6 @@ mysql_execute_command(THD *thd)
if (single_table_command_access(thd, UPDATE_ACL, tables, &res))
goto error;
-
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
@@ -2392,10 +2385,12 @@ mysql_execute_command(THD *thd)
res= -1;
break;
case SQLCOM_UPDATE_MULTI:
- if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege,0,0))
goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
+#endif
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
@@ -2425,13 +2420,16 @@ mysql_execute_command(THD *thd)
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
ulong privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
if (single_table_command_access(thd, privilege, tables, &res))
goto error;
-
+#else
+ my_bool update=(lex->value_list.elements ? 1 : 0);
+#endif
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(thd,ER_WRONG_VALUE_COUNT);
@@ -2452,19 +2450,22 @@ mysql_execute_command(THD *thd)
Check that we have modify privileges for the first table and
select privileges for the rest
*/
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
{
ulong privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL);
TABLE_LIST *save_next=tables->next;
tables->next=0;
if (check_access(thd, privilege,
- tables->db,&tables->grant.privilege) ||
+ tables->db,&tables->grant.privilege,0,0) ||
(grant_option && check_grant(thd, privilege, tables)))
goto error;
+
tables->next=save_next;
- if ((res=check_table_access(thd, SELECT_ACL, save_next)))
+ if ((res=check_table_access(thd, SELECT_ACL, save_next,0)))
goto error;
}
+#endif
/* Don't unlock tables until command is written to binary log */
select_lex->options|= SELECT_NO_UNLOCK;
@@ -2498,10 +2499,12 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_TRUNCATE:
- if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
if (grant_option && check_grant(thd,DELETE_ACL,tables))
goto error;
+#endif
/*
Don't allow this within a transaction because we want to use
re-generate table
@@ -2515,11 +2518,12 @@ mysql_execute_command(THD *thd)
break;
case SQLCOM_DELETE:
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (single_table_command_access(thd, DELETE_ACL, tables, &res))
goto error;
-
// Set privilege for the WHERE clause
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
+#endif
res = mysql_delete(thd,tables, select_lex->where,
(ORDER*) select_lex->order_list.first,
select_lex->select_limit, select_lex->options);
@@ -2536,8 +2540,8 @@ mysql_execute_command(THD *thd)
/* sql_yacc guarantees that tables and aux_tables are not zero */
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
- check_table_access(thd,SELECT_ACL, tables) ||
- check_table_access(thd,DELETE_ACL, aux_tables))
+ check_table_access(thd,SELECT_ACL, tables,0) ||
+ check_table_access(thd,DELETE_ACL, aux_tables,0))
goto error;
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
{
@@ -2614,7 +2618,7 @@ mysql_execute_command(THD *thd)
{
if (!lex->drop_temporary)
{
- if (check_table_access(thd,DROP_ACL,tables))
+ if (check_table_access(thd,DROP_ACL,tables,0))
goto error; /* purecov: inspected */
if (end_active_trans(thd))
{
@@ -2641,10 +2645,12 @@ mysql_execute_command(THD *thd)
case SQLCOM_DROP_INDEX:
if (!tables->db)
tables->db=thd->db;
- if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,INDEX_ACL,tables->db,&tables->grant.privilege,0,0))
goto error; /* purecov: inspected */
if (grant_option && check_grant(thd,INDEX_ACL,tables))
goto error;
+#endif
if (end_active_trans(thd))
res= -1;
else
@@ -2662,10 +2668,18 @@ mysql_execute_command(THD *thd)
break;
#endif
case SQLCOM_SHOW_PROCESSLIST:
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
- mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
- thd->priv_user,lex->verbose);
+#endif
+ mysqld_list_processes(thd,
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ thd->master_access & PROCESS_ACL ? NullS :
+ thd->priv_user
+#else
+ NullS
+#endif
+ ,lex->verbose);
break;
case SQLCOM_SHOW_TABLE_TYPES:
res= mysqld_show_table_types(thd);
@@ -2678,11 +2692,12 @@ mysql_execute_command(THD *thd)
break;
case SQLCOM_SHOW_STATUS:
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
- OPT_GLOBAL);
+ OPT_GLOBAL, &LOCK_status);
break;
case SQLCOM_SHOW_VARIABLES:
res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
- init_vars, lex->option_type);
+ init_vars, lex->option_type,
+ &LOCK_global_system_variables);
break;
case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
@@ -2690,8 +2705,10 @@ mysql_execute_command(THD *thd)
DBUG_VOID_RETURN;
#else
{
- if (grant_option && check_access(thd, FILE_ACL, any_db))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (grant_option && check_access(thd, FILE_ACL, any_db,0,0,0))
goto error;
+#endif
res= mysqld_show_logs(thd);
break;
}
@@ -2715,7 +2732,8 @@ mysql_execute_command(THD *thd)
net_printf(thd,ER_WRONG_DB_NAME, db);
goto error;
}
- if (check_access(thd,SELECT_ACL,db,&thd->col_access))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
goto error; /* purecov: inspected */
if (!thd->col_access && check_grant_db(thd,db))
{
@@ -2725,6 +2743,7 @@ mysql_execute_command(THD *thd)
db);
goto error;
}
+#endif
/* grant is checked in mysqld_show_tables */
if (select_lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
@@ -2758,11 +2777,13 @@ mysql_execute_command(THD *thd)
}
remove_escape(db); // Fix escaped '_'
remove_escape(tables->real_name);
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access,0,0))
goto error; /* purecov: inspected */
tables->grant.privilege=thd->col_access;
if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
goto error;
+#endif
res= mysqld_show_fields(thd,tables,
(lex->wild ? lex->wild->ptr() : NullS),
lex->verbose);
@@ -2785,11 +2806,13 @@ mysql_execute_command(THD *thd)
remove_escape(tables->real_name);
if (!tables->db)
tables->db=thd->db;
- if (check_access(thd,SELECT_ACL,db,&thd->col_access))
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_access(thd,SELECT_ACL,db,&thd->col_access,0,0))
goto error; /* purecov: inspected */
tables->grant.privilege=thd->col_access;
if (grant_option && check_grant(thd,SELECT_ACL,tables,2))
goto error;
+#endif
res= mysqld_show_keys(thd,tables);
break;
}
@@ -2797,15 +2820,16 @@ mysql_execute_command(THD *thd)
case SQLCOM_CHANGE_DB:
mysql_change_db(thd,select_lex->db);
break;
-#ifndef EMBEDDED_LIBRARY
+
case SQLCOM_LOAD:
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
uint privilege= (lex->duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL);
if (!lex->local_file)
{
- if (check_access(thd,privilege | FILE_ACL,tables->db))
+ if (check_access(thd,privilege | FILE_ACL,tables->db,0,0,0))
goto error;
}
else
@@ -2816,17 +2840,18 @@ mysql_execute_command(THD *thd)
send_error(thd,ER_NOT_ALLOWED_COMMAND);
goto error;
}
- if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
+ if (check_access(thd,privilege,tables->db,&tables->grant.privilege,0,0) ||
grant_option && check_grant(thd,privilege,tables))
goto error;
}
+#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
res=mysql_load(thd, lex->exchange, tables, lex->field_list,
lex->duplicates, (bool) lex->local_file, lex->lock_option);
break;
}
-#endif /* EMBEDDED_LIBRARY */
+
case SQLCOM_SET_OPTION:
- if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables,0)) ||
(res= open_and_lock_tables(thd,tables))))
break;
fix_tables_pointers(lex->all_selects_list);
@@ -2851,7 +2876,7 @@ mysql_execute_command(THD *thd)
unlock_locked_tables(thd);
if (check_db_used(thd,tables) || end_active_trans(thd))
goto error;
- if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables))
+ if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, tables,0))
goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
@@ -2888,7 +2913,7 @@ mysql_execute_command(THD *thd)
break;
}
#endif
- if (check_access(thd,CREATE_ACL,lex->name,0,1))
+ if (check_access(thd,CREATE_ACL,lex->name,0,1,0))
break;
res=mysql_create_db(thd,lex->name,&lex->create_info,0);
break;
@@ -2916,7 +2941,7 @@ mysql_execute_command(THD *thd)
break;
}
#endif
- if (check_access(thd,DROP_ACL,lex->name,0,1))
+ if (check_access(thd,DROP_ACL,lex->name,0,1,0))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -2933,7 +2958,7 @@ mysql_execute_command(THD *thd)
net_printf(thd,ER_WRONG_DB_NAME, lex->name);
break;
}
- if (check_access(thd,ALTER_ACL,lex->name,0,1))
+ if (check_access(thd,ALTER_ACL,lex->name,0,1,0))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -2950,7 +2975,7 @@ mysql_execute_command(THD *thd)
net_printf(thd,ER_WRONG_DB_NAME, lex->name);
break;
}
- if (check_access(thd,DROP_ACL,lex->name,0,1))
+ if (check_access(thd,DROP_ACL,lex->name,0,1,0))
break;
if (thd->locked_tables || thd->active_transaction())
{
@@ -2961,7 +2986,7 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_CREATE_FUNCTION:
- if (check_access(thd,INSERT_ACL,"mysql",0,1))
+ if (check_access(thd,INSERT_ACL,"mysql",0,1,0))
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_create_function(thd,&lex->udf)))
@@ -2971,7 +2996,7 @@ mysql_execute_command(THD *thd)
#endif
break;
case SQLCOM_DROP_FUNCTION:
- if (check_access(thd,DELETE_ACL,"mysql",0,1))
+ if (check_access(thd,DELETE_ACL,"mysql",0,1,0))
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_drop_function(thd,&lex->udf.name)))
@@ -2980,9 +3005,10 @@ mysql_execute_command(THD *thd)
res= -1;
#endif
break;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_DROP_USER:
{
- if (check_access(thd, GRANT_ACL,"mysql",0,1))
+ if (check_access(thd, GRANT_ACL,"mysql",0,1,0))
break;
if (!(res= mysql_drop_user(thd, lex->users_list)))
{
@@ -2998,7 +3024,7 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_REVOKE_ALL:
{
- if (check_access(thd, GRANT_ACL ,"mysql",0,1))
+ if (check_access(thd, GRANT_ACL ,"mysql",0,1,0))
break;
if (!(res = mysql_revoke_all(thd, lex->users_list)))
{
@@ -3018,7 +3044,7 @@ mysql_execute_command(THD *thd)
if (check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
tables && tables->db ? tables->db : select_lex->db,
tables ? &tables->grant.privilege : 0,
- tables ? 0 : 1))
+ tables ? 0 : 1,0))
goto error;
/*
@@ -3038,7 +3064,7 @@ mysql_execute_command(THD *thd)
my_strcasecmp(&my_charset_latin1,
user->host.str, thd->host_or_ip)))
{
- if (check_access(thd, UPDATE_ACL, "mysql",0,1))
+ if (check_access(thd, UPDATE_ACL, "mysql",0,1,0))
goto error;
break; // We are allowed to do changes
}
@@ -3092,6 +3118,7 @@ mysql_execute_command(THD *thd)
}
break;
}
+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
case SQLCOM_RESET:
/*
RESET commands are never written to the binary log, so we have to
@@ -3131,18 +3158,20 @@ mysql_execute_command(THD *thd)
case SQLCOM_KILL:
kill_one_thread(thd,lex->thread_id);
break;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
case SQLCOM_SHOW_GRANTS:
res=0;
if ((thd->priv_user &&
!strcmp(thd->priv_user,lex->grant_user->user.str)) ||
- !check_access(thd, SELECT_ACL, "mysql",0,1))
+ !check_access(thd, SELECT_ACL, "mysql",0,1,0))
{
res = mysql_show_grants(thd,lex->grant_user);
}
break;
+#endif
case SQLCOM_HA_OPEN:
if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables))
+ check_table_access(thd,SELECT_ACL, tables,0))
goto error;
res = mysql_ha_open(thd, tables);
break;
@@ -3204,7 +3233,16 @@ mysql_execute_command(THD *thd)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
{
- if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
+ /*
+ If a non-transactional table was updated, warn; don't warn if this is a
+ slave thread (because when a slave thread executes a ROLLBACK, it has
+ been read from the binary log, so it's 100% sure and normal to produce
+ error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
+ slave SQL thread, it would not stop the thread but just be printed in
+ the error log; but we don't want users to wonder why they have this
+ message in the error log, so we don't send it.
+ */
+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
else
send_ok(thd);
@@ -3216,7 +3254,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
{
- if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
+ if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
else
send_ok(thd);
@@ -3243,11 +3281,12 @@ error:
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check grants for commands which work only with one table and all other
tables belong to subselects.
- SYNOPSYS
+ SYNOPSIS
single_table_command_access()
thd - Thread handler
privilege - asked privelage
@@ -3263,7 +3302,7 @@ static bool single_table_command_access(THD *thd, ulong privilege,
TABLE_LIST *tables, int *res)
{
- if (check_access(thd, privilege, tables->db, &tables->grant.privilege))
+ if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
return 1;
// Show only 1 table for check_grant
@@ -3276,7 +3315,7 @@ static bool single_table_command_access(THD *thd, ulong privilege,
if (subselects_tables)
{
tables->next= subselects_tables;
- if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables)))
+ if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables,0)))
return 1;
}
return 0;
@@ -3447,24 +3486,6 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
-
-static bool check_db_used(THD *thd,TABLE_LIST *tables)
-{
- for (; tables ; tables=tables->next)
- {
- if (!tables->db)
- {
- if (!(tables->db=thd->db))
- {
- send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
- return TRUE; /* purecov: tested */
- }
- }
- }
- return FALSE;
-}
-
-
static bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list)
{
@@ -3479,11 +3500,28 @@ static bool check_merge_table_access(THD *thd, char *db,
tmp->db=db;
}
error=check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL,
- table_list);
+ table_list,0);
}
return error;
}
+#endif /*!NO_EMBEDDED_ACCESS_CHECKS*/
+
+static bool check_db_used(THD *thd,TABLE_LIST *tables)
+{
+ for (; tables ; tables=tables->next)
+ {
+ if (!tables->db)
+ {
+ if (!(tables->db=thd->db))
+ {
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
+ return TRUE; /* purecov: tested */
+ }
+ }
+ }
+ return FALSE;
+}
/****************************************************************************
Check stack size; Send error if there isn't enough stack to continue
@@ -3709,12 +3747,14 @@ mysql_parse(THD *thd, char *inBuf, uint length)
LEX *lex=lex_start(thd, (uchar*) inBuf, length);
if (!yyparse((void *)thd) && ! thd->is_fatal_error)
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (mqh_used && thd->user_connect &&
check_mqh(thd, lex->sql_command))
{
thd->net.error = 0;
}
else
+#endif
{
if (thd->net.report_error)
send_error(thd, 0, NullS);
@@ -3751,7 +3791,7 @@ mysql_parse(THD *thd, char *inBuf, uint length)
bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
char *length, char *decimals,
uint type_modifier,
- Item *default_value, Item *comment,
+ Item *default_value, LEX_STRING *comment,
char *change, TYPELIB *interval, CHARSET_INFO *cs,
uint uint_geom_type)
{
@@ -3825,8 +3865,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
else
{
/* In this case comment is always of type Item_string */
- new_field->comment.str= (char*) comment->str_value.ptr();
- new_field->comment.length=comment->str_value.length();
+ new_field->comment.str= (char*) comment->str;
+ new_field->comment.length=comment->length;
}
if (length && !(new_field->length= (uint) atoi(length)))
length=0; /* purecov: inspected */
@@ -4319,7 +4359,6 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
b->natural_join=a;
}
-
/*
Reload/resets privileges and the different caches.
@@ -4346,6 +4385,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
bool result=0;
select_errors=0; /* Write if more errors */
bool tmp_write_to_binlog= 1;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_GRANT)
{
acl_reload(thd);
@@ -4353,6 +4393,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (mqh_used)
reset_mqh(thd,(LEX_USER *) NULL,true);
}
+#endif
if (options & REFRESH_LOG)
{
/*
@@ -4418,7 +4459,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
refresh_status();
if (options & REFRESH_THREADS)
flush_thread_cache();
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
if (options & REFRESH_MASTER)
{
tmp_write_to_binlog= 0;
@@ -4433,7 +4474,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
result=load_des_key_file(des_key_file);
}
#endif
-#ifndef EMBEDDED_LIBRARY
+#ifdef HAVE_REPLICATION
if (options & REFRESH_SLAVE)
{
tmp_write_to_binlog= 0;
@@ -4443,14 +4484,15 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
UNLOCK_ACTIVE_MI;
}
#endif
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_USER_RESOURCES)
reset_mqh(thd,(LEX_USER *) NULL);
+#endif
if (write_to_binlog)
*write_to_binlog= tmp_write_to_binlog;
return result;
}
-
/*
kill on thread
@@ -4480,14 +4522,18 @@ void kill_one_thread(THD *thd, ulong id)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if ((thd->master_access & SUPER_ACL) ||
!strcmp(thd->user,tmp->user))
+#endif
{
tmp->awake(1 /*prepare to die*/);
error=0;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
else
error=ER_KILL_DENIED_ERROR;
+#endif
pthread_mutex_unlock(&tmp->LOCK_delete);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 550e4bbe086..dd8d5613880 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -76,8 +76,15 @@ Long data handling:
#define STMT_QUERY_LOG_LENGTH 8192
-extern int yyparse(void *thd);
-static String null_string("NULL", 4, default_charset_info);
+#ifdef EMBEDDED_LIBRARY
+#define SETUP_PARAM_FUNCTION(fn_name) \
+static void fn_name(Item_param *param, uchar **pos, ulong data_len)
+#else
+#define SETUP_PARAM_FUNCTION(fn_name) \
+static void fn_name(Item_param *param, uchar **pos)
+#endif
+
+String my_null_string("NULL", 4, default_charset_info);
/*
Find prepared statement in thd
@@ -142,6 +149,7 @@ void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used)
Send prepared stmt info to client after prepare
*/
+#ifndef EMBEDDED_LIBRARY
static bool send_prep_stmt(PREP_STMT *stmt, uint columns)
{
NET *net=&stmt->thd->net;
@@ -150,14 +158,22 @@ static bool send_prep_stmt(PREP_STMT *stmt, uint columns)
int4store(buff+1, stmt->stmt_id);
int2store(buff+5, columns);
int2store(buff+7, stmt->param_count);
-#ifndef EMBEDDED_LIBRARY
/* This should be fixed to work with prepared statements
*/
return (my_net_write(net, buff, sizeof(buff)) || net_flush(net));
+}
#else
- return true;
-#endif
+static bool send_prep_stmt(PREP_STMT *stmt, uint columns __attribute__((unused)))
+{
+ THD *thd= stmt->thd;
+
+ thd->client_stmt_id= stmt->stmt_id;
+ thd->client_param_count= stmt->param_count;
+ thd->net.last_errno= 0;
+
+ return 0;
}
+#endif /*!EMBEDDED_LIBRAYR*/
/*
Send information about all item parameters
@@ -182,6 +198,7 @@ static bool send_item_params(PREP_STMT *stmt)
caller by positing the pointer to param data
*/
+#ifndef EMBEDDED_LIBRARY
static ulong get_param_length(uchar **packet)
{
reg1 uchar *pos= *packet;
@@ -203,6 +220,10 @@ static ulong get_param_length(uchar **packet)
(*packet)+=9; // Must be 254 when here
return (ulong) uint4korr(pos+1);
}
+#else
+#define get_param_length(A) data_len
+#endif /*!EMBEDDED_LIBRARY*/
+
/*
Setup param conversion routines
@@ -222,31 +243,31 @@ static ulong get_param_length(uchar **packet)
*/
-static void setup_param_tiny(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_tiny)
{
param->set_int((longlong)(**pos));
*pos+= 1;
}
-static void setup_param_short(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_short)
{
param->set_int((longlong)sint2korr(*pos));
*pos+= 2;
}
-static void setup_param_int32(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_int32)
{
param->set_int((longlong)sint4korr(*pos));
*pos+= 4;
}
-static void setup_param_int64(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_int64)
{
param->set_int((longlong)sint8korr(*pos));
*pos+= 8;
}
-static void setup_param_float(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_float)
{
float data;
float4get(data,*pos);
@@ -254,7 +275,7 @@ static void setup_param_float(Item_param *param, uchar **pos)
*pos+= 4;
}
-static void setup_param_double(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_double)
{
double data;
float8get(data,*pos);
@@ -262,7 +283,7 @@ static void setup_param_double(Item_param *param, uchar **pos)
*pos+= 8;
}
-static void setup_param_time(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_time)
{
ulong length;
@@ -286,7 +307,7 @@ static void setup_param_time(Item_param *param, uchar **pos)
*pos+= length;
}
-static void setup_param_datetime(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_datetime)
{
uint length= get_param_length(pos);
@@ -316,7 +337,7 @@ static void setup_param_datetime(Item_param *param, uchar **pos)
*pos+= length;
}
-static void setup_param_date(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_date)
{
ulong length;
@@ -338,14 +359,14 @@ static void setup_param_date(Item_param *param, uchar **pos)
*pos+= length;
}
-static void setup_param_str(Item_param *param, uchar **pos)
+SETUP_PARAM_FUNCTION(setup_param_str)
{
ulong len= get_param_length(pos);
param->set_value((const char *)*pos, len);
*pos+= len;
}
-static void setup_param_functions(Item_param *param, uchar param_type)
+void setup_param_functions(Item_param *param, uchar param_type)
{
switch (param_type) {
case FIELD_TYPE_TINY:
@@ -391,6 +412,7 @@ static void setup_param_functions(Item_param *param, uchar param_type)
}
}
+#ifndef EMBEDDED_LIBRARY
/*
Update the parameter markers by reading data from client packet
and if binary/update log is set, generate the valid query.
@@ -420,7 +442,7 @@ static bool insert_params_withlog(PREP_STMT *stmt, uchar *pos, uchar *read_pos)
if (IS_PARAM_NULL(pos,param_no))
{
param->maybe_null= param->null_value= 1;
- res= &null_string;
+ res= &my_null_string;
}
else
{
@@ -476,11 +498,7 @@ static bool setup_params_data(PREP_STMT *stmt)
Item_param *param;
DBUG_ENTER("setup_params_data");
-#ifndef EMBEDDED_LIBRARY
uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header
-#else
- uchar *pos= 0; //just to compile TODO code for embedded case
-#endif
uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits
if (*read_pos++) //types supplied / first execute
@@ -500,6 +518,8 @@ static bool setup_params_data(PREP_STMT *stmt)
DBUG_RETURN(0);
}
+#endif /*!EMBEDDED_LIBRARY*/
+
/*
Validate the following information for INSERT statement:
- field existance
@@ -517,16 +537,18 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
List_item *values;
DBUG_ENTER("mysql_test_insert_fields");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
my_bool update=(thd->lex.value_list.elements ? UPDATE_ACL : 0);
ulong privilege= (thd->lex.duplicates == DUP_REPLACE ?
INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
if (check_access(thd,privilege,table_list->db,
- &table_list->grant.privilege) ||
- (grant_option && check_grant(thd,privilege,table_list)) ||
- open_and_lock_tables(thd, table_list))
+ &table_list->grant.privilege,0,0) ||
+ (grant_option && check_grant(thd,privilege,table_list)))
+ DBUG_RETURN(1);
+#endif
+ if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(1);
-
table= table_list->table;
if ((values= its++))
@@ -574,12 +596,14 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
THD *thd= stmt->thd;
DBUG_ENTER("mysql_test_upd_fields");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_access(thd,UPDATE_ACL,table_list->db,
- &table_list->grant.privilege) ||
- (grant_option && check_grant(thd,UPDATE_ACL,table_list)) ||
- open_and_lock_tables(thd, table_list))
+ &table_list->grant.privilege,0,0) ||
+ (grant_option && check_grant(thd,UPDATE_ACL,table_list)))
+ DBUG_RETURN(1);
+#endif
+ if (open_and_lock_tables(thd, table_list))
DBUG_RETURN(1);
-
if (setup_tables(table_list) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
setup_conds(thd, table_list, &conds) || thd->net.report_error)
@@ -620,15 +644,16 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
select_result *result= thd->lex.result;
DBUG_ENTER("mysql_test_select_fields");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
if (tables)
{
- if (check_table_access(thd, privilege, tables))
+ if (check_table_access(thd, privilege, tables,0))
DBUG_RETURN(1);
}
- else if (check_access(thd, privilege, "*any*"))
+ else if (check_access(thd, privilege, "*any*",0,0,0))
DBUG_RETURN(1);
-
+#endif
if ((&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables, 0)))
DBUG_RETURN(1);
@@ -659,13 +684,13 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
wild_num, conds, og_num, order, group, having, proc,
select_lex, unit, 0))
DBUG_RETURN(1);
-#ifndef EMBEDDED_LIBRARY
if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0) ||
+#ifndef EMBEDDED_LIBRARY
net_flush(&thd->net) ||
+#endif
send_item_params(stmt))
DBUG_RETURN(1);
-#endif
join->cleanup();
}
DBUG_RETURN(0);
@@ -784,10 +809,18 @@ static bool init_param_items(PREP_STMT *stmt)
if (mysql_bin_log.is_open() || mysql_update_log.is_open())
{
stmt->log_full_query= 1;
+#ifndef EMBEDDED_LIBRARY
stmt->setup_params= insert_params_withlog;
+#else
+ stmt->setup_params_data= setup_params_data_withlog;
+#endif
}
else
+#ifndef EMBEDDED_LIBRARY
stmt->setup_params= insert_params; // not fully qualified query
+#else
+ stmt->setup_params_data= setup_params_data;
+#endif
if (!stmt->param_count)
stmt->param= (Item_param **)0;
@@ -873,11 +906,21 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
+
+ // save WHERE clause pointers to avoid damaging they by optimisation
+ for (SELECT_LEX *sl= thd->lex.all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ sl->prep_where= sl->where;
+ }
+
if (init_param_items(&stmt))
goto err;
+
- stmt.mem_root= stmt.thd->mem_root;
+ stmt.mem_root= stmt.thd->mem_root;
tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0);
thd->mem_root= thd_root; // restore main mem_root
DBUG_RETURN(0);
@@ -919,10 +962,25 @@ void mysql_stmt_execute(THD *thd, char *packet)
LEX thd_lex= thd->lex;
thd->lex= stmt->lex;
+
+ for (SELECT_LEX *sl= stmt->lex.all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ // copy WHERE clause pointers to avoid damaging they by optimisation
+ if (sl->prep_where)
+ sl->where= sl->prep_where->copy_andor_structure(thd);
+ DBUG_ASSERT(sl->join == 0);
+ }
init_stmt_execute(stmt);
+#ifndef EMBEDDED_LIBRARY
if (stmt->param_count && setup_params_data(stmt))
DBUG_VOID_RETURN;
+#else
+ if (stmt->param_count && (*stmt->setup_params_data)(stmt))
+ DBUG_VOID_RETURN;
+#endif
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
@@ -1030,16 +1088,17 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
PREP_STMT *stmt;
DBUG_ENTER("mysql_stmt_get_longdata");
+#ifndef EMBEDDED_LIBRARY
/* The following should never happen */
if (packet_length < MYSQL_LONG_DATA_HEADER+1)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata");
DBUG_VOID_RETURN;
}
+#endif
ulong stmt_id= uint4korr(pos);
uint param_number= uint2korr(pos+4);
- pos+= MYSQL_LONG_DATA_HEADER; // Point to data
if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
{
@@ -1051,6 +1110,7 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
DBUG_VOID_RETURN;
}
+#ifndef EMBEDDED_LIBRARY
if (param_number >= stmt->param_count)
{
/* Error will be sent in execute call */
@@ -1059,8 +1119,15 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
DBUG_VOID_RETURN;
}
+ pos+= MYSQL_LONG_DATA_HEADER; // Point to data
+#endif
+
Item_param *param= *(stmt->param+param_number);
+#ifndef EMBEDDED_LIBRARY
param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
+#else
+ param->set_longdata(thd->extra_data, thd->extra_length);
+#endif
stmt->long_data_used= 1;
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 3cdf033c477..7bb51989cc3 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -24,8 +24,6 @@
#include "log_event.h"
#include <my_dir.h>
-extern const char* any_db;
-
int max_binlog_dump_events = 0; // unlimited
my_bool opt_sporadic_binlog_dump_fail = 0;
static int binlog_dump_count = 0;
@@ -545,7 +543,7 @@ Increase max_allowed_packet on master";
if (!thd->killed)
{
/* Note that the following call unlocks lock_log */
- mysql_bin_log.wait_for_update(thd);
+ mysql_bin_log.wait_for_update(thd, 0);
}
else
pthread_mutex_unlock(log_lock);
@@ -560,7 +558,7 @@ Increase max_allowed_packet on master";
if (read_packet)
{
- thd->proc_info = "sending update to slave";
+ thd->proc_info = "Sending binlog event to slave";
if (my_net_write(net, (char*)packet->ptr(), packet->length()) )
{
errmsg = "Failed on my_net_write()";
@@ -597,7 +595,7 @@ Increase max_allowed_packet on master";
{
bool loop_breaker = 0;
// need this to break out of the for loop from switch
- thd->proc_info = "switching to next log";
+ thd->proc_info = "Finished reading one binlog; switching to next binlog";
switch (mysql_bin_log.find_next_log(&linfo, 1)) {
case LOG_INFO_EOF:
loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
@@ -636,14 +634,14 @@ end:
(void)my_close(file, MYF(MY_WME));
send_eof(thd);
- thd->proc_info = "waiting to finalize termination";
+ thd->proc_info = "Waiting to finalize termination";
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
err:
- thd->proc_info = "waiting to finalize termination";
+ thd->proc_info = "Waiting to finalize termination";
end_io_cache(&log);
/*
Exclude iteration through thread list
@@ -663,13 +661,13 @@ err:
int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
{
- int slave_errno;
+ int slave_errno= 0;
if (!thd)
thd = current_thd;
int thread_mask;
DBUG_ENTER("start_slave");
- if (check_access(thd, SUPER_ACL, any_db))
+ if (check_access(thd, SUPER_ACL, any_db,0,0,0))
DBUG_RETURN(1);
lock_slave_threads(mi); // this allows us to cleanly read slave_running
// Get a mask of _stopped_ threads
@@ -687,21 +685,88 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
if (init_master_info(mi,master_info_file,relay_log_info_file, 0))
slave_errno=ER_MASTER_INFO;
else if (server_id_supplied && *mi->host)
- slave_errno = start_slave_threads(0 /*no mutex */,
+ {
+ /*
+ If we will start SQL thread we will care about UNTIL options
+ If not and they are specified we will ignore them and warn user
+ about this fact.
+ */
+ if (thread_mask & SLAVE_SQL)
+ {
+ pthread_mutex_lock(&mi->rli.data_lock);
+
+ if (thd->lex.mi.pos)
+ {
+ mi->rli.until_condition= RELAY_LOG_INFO::UNTIL_MASTER_POS;
+ mi->rli.until_log_pos= thd->lex.mi.pos;
+ /*
+ We don't check thd->lex.mi.log_file_name for NULL here
+ since it is checked in sql_yacc.yy
+ */
+ strmake(mi->rli.until_log_name, thd->lex.mi.log_file_name,
+ sizeof(mi->rli.until_log_name)-1);
+ }
+ else if (thd->lex.mi.relay_log_pos)
+ {
+ mi->rli.until_condition= RELAY_LOG_INFO::UNTIL_RELAY_POS;
+ mi->rli.until_log_pos= thd->lex.mi.relay_log_pos;
+ strmake(mi->rli.until_log_name, thd->lex.mi.relay_log_name,
+ sizeof(mi->rli.until_log_name)-1);
+ }
+ else
+ clear_until_condition(&mi->rli);
+
+ if (mi->rli.until_condition != RELAY_LOG_INFO::UNTIL_NONE)
+ {
+ /* Preparing members for effective until condition checking */
+ const char *p= fn_ext(mi->rli.until_log_name);
+ char *p_end;
+ if (*p)
+ {
+ //p points to '.'
+ mi->rli.until_log_name_extension= strtoul(++p,&p_end, 10);
+ /*
+ p_end points to the first invalid character. If it equals
+ to p, no digits were found, error. If it contains '\0' it
+ means conversion went ok.
+ */
+ if(p_end==p || *p_end)
+ slave_errno=ER_BAD_SLAVE_UNTIL_COND;
+ }
+ else
+ slave_errno=ER_BAD_SLAVE_UNTIL_COND;
+
+ /* mark the cached result of the UNTIL comparison as "undefined" */
+ mi->rli.until_log_names_cmp_result=
+ RELAY_LOG_INFO::UNTIL_LOG_NAMES_CMP_UNKNOWN;
+
+ /* Issuing warning then started without --skip-slave-start */
+ if (!opt_skip_slave_start)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_MISSING_SKIP_SLAVE,
+ ER(ER_MISSING_SKIP_SLAVE));
+ }
+
+ pthread_mutex_unlock(&mi->rli.data_lock);
+ }
+ else if (thd->lex.mi.pos || thd->lex.mi.relay_log_pos)
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNTIL_COND_IGNORED,
+ ER(ER_UNTIL_COND_IGNORED));
+
+
+ if(!slave_errno)
+ slave_errno = start_slave_threads(0 /*no mutex */,
1 /* wait for start */,
mi,
master_info_file,relay_log_info_file,
thread_mask);
+ }
else
slave_errno = ER_BAD_SLAVE;
}
else
- {
//no error if all threads are already started, only a warning
- slave_errno= 0;
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING,
ER(ER_SLAVE_WAS_RUNNING));
- }
unlock_slave_threads(mi);
@@ -724,7 +789,7 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
if (!thd)
thd = current_thd;
- if (check_access(thd, SUPER_ACL, any_db))
+ if (check_access(thd, SUPER_ACL, any_db,0,0,0))
return 1;
thd->proc_info = "Killing slave";
int thread_mask;
@@ -814,6 +879,8 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
*/
init_master_info_with_options(mi);
clear_last_slave_error(&mi->rli);
+ clear_until_condition(&mi->rli);
+
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
// and delete these two files
@@ -903,7 +970,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
DBUG_RETURN(1);
}
- thd->proc_info = "changing master";
+ thd->proc_info = "Changing master";
LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
// TODO: see if needs re-write
if (init_master_info(mi, master_info_file, relay_log_info_file, 0))
@@ -949,6 +1016,25 @@ int change_master(THD* thd, MASTER_INFO* mi)
mi->port = lex_mi->port;
if (lex_mi->connect_retry)
mi->connect_retry = lex_mi->connect_retry;
+
+ if (lex_mi->ssl != LEX_MASTER_INFO::SSL_UNCHANGED)
+ mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::SSL_ENABLE);
+ if (lex_mi->ssl_ca)
+ strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1);
+ if (lex_mi->ssl_capath)
+ strmake(mi->ssl_capath, lex_mi->ssl_capath, sizeof(mi->ssl_capath)-1);
+ if (lex_mi->ssl_cert)
+ strmake(mi->ssl_cert, lex_mi->ssl_cert, sizeof(mi->ssl_cert)-1);
+ if (lex_mi->ssl_cipher)
+ strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1);
+ if (lex_mi->ssl_key)
+ strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1);
+#ifndef HAVE_OPENSSL
+ if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath ||
+ lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key )
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS));
+#endif
if (lex_mi->relay_log_name)
{
@@ -969,7 +1055,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
if (need_relay_log_purge)
{
relay_log_purge= 1;
- thd->proc_info="purging old relay logs";
+ thd->proc_info="Purging old relay logs";
if (purge_relay_logs(&mi->rli, thd,
0 /* not only reset, but also reinit */,
&errmsg))
@@ -1008,6 +1094,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
/* Clear the error, for a clean start. */
clear_last_slave_error(&mi->rli);
+ clear_until_condition(&mi->rli);
/*
If we don't write new coordinates to disk now, then old will remain in
relay-log.info until START SLAVE is issued; but if mysqld is shutdown
@@ -1258,7 +1345,7 @@ int log_loaded_block(IO_CACHE* file)
lf_info->last_pos_in_file = file->pos_in_file;
if (lf_info->wrote_create_file)
{
- Append_block_log_event a(lf_info->thd, buffer, block_len,
+ Append_block_log_event a(lf_info->thd, lf_info->db, buffer, block_len,
lf_info->log_delayed);
mysql_bin_log.write(&a);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 15d6b3954ff..ff41e9fd067 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -32,7 +32,7 @@
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext",
- "ref_or_null","simple_in","index_in"
+ "ref_or_null","unique_subquery","index_subquery"
};
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
@@ -117,10 +117,8 @@ static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
-static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order,
+static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit);
-static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order,
- ha_rows select_limit);
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
Item *having);
static int remove_dup_with_compare(THD *thd, TABLE *entry, Field **field,
@@ -160,8 +158,9 @@ static void copy_sum_funcs(Item_sum **func_ptr);
static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab);
static bool init_sum_functions(Item_sum **func, Item_sum **end);
static bool update_sum_func(Item_sum **func);
-static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
+static void select_describe(JOIN *join, bool need_tmp_table,bool need_order,
bool distinct, const char *message=NullS);
+static Item *remove_additional_cond(Item* conds);
/*
@@ -326,8 +325,8 @@ JOIN::prepare(Item ***rref_pointer_array,
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) !=
- Item_subselect::OK)
- DBUG_RETURN((res == Item_subselect::ERROR));
+ Item_subselect::RES_OK)
+ DBUG_RETURN((res == Item_subselect::RES_ERROR));
}
}
@@ -466,8 +465,10 @@ bool JOIN::test_in_subselect(Item **where)
((class Item_func *)this->conds)->functype() ==
Item_func::COND_AND_FUNC)
{
- *where= conds;
- join_tab->info= "Using index; Using where";
+ if ((*where= remove_additional_cond(conds)))
+ join_tab->info= "Using index; Using where";
+ else
+ join_tab->info= "Using index";
return 1;
}
return 0;
@@ -477,8 +478,7 @@ bool JOIN::test_in_subselect(Item **where)
/*
global select optimisation.
return 0 - success
- 1 - go out
- -1 - go out with cleaning
+ 1 - error
error code saved in field 'error'
*/
int
@@ -515,11 +515,9 @@ JOIN::optimize()
conds= optimize_cond(conds,&cond_value);
if (thd->net.report_error)
{
- // quick abort
- delete procedure;
- error= thd->is_fatal_error ? -1 : 1;
+ error= 1;
DBUG_PRINT("error",("Error from optimize_cond"));
- DBUG_RETURN(error);
+ DBUG_RETURN(1);
}
if (cond_value == Item::COND_FALSE ||
@@ -542,8 +540,7 @@ JOIN::optimize()
{
if (res > 1)
{
- delete procedure;
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
if (res < 0)
{
@@ -776,13 +773,14 @@ JOIN::optimize()
{
if (test_in_subselect(&where))
{
- join_tab[0].type= JT_SIMPLE_IN;
+ join_tab[0].type= JT_UNIQUE_SUBQUERY;
error= 0;
DBUG_RETURN(unit->item->
- change_engine(new subselect_simplein_engine(thd,
- join_tab,
- unit->item,
- where)));
+ change_engine(new
+ subselect_uniquesubquery_engine(thd,
+ join_tab,
+ unit->item,
+ where)));
}
}
else if (join_tab[0].type == JT_REF &&
@@ -790,14 +788,15 @@ JOIN::optimize()
{
if (test_in_subselect(&where))
{
- join_tab[0].type= JT_INDEX_IN;
+ join_tab[0].type= JT_INDEX_SUBQUERY;
error= 0;
DBUG_RETURN(unit->item->
- change_engine(new subselect_indexin_engine(thd,
- join_tab,
- unit->item,
- where,
- 0)));
+ change_engine(new
+ subselect_indexsubquery_engine(thd,
+ join_tab,
+ unit->item,
+ where,
+ 0)));
}
}
} else if (join_tab[0].type == JT_REF_OR_NULL &&
@@ -806,14 +805,20 @@ JOIN::optimize()
((Item_func *) having)->functype() ==
Item_func::ISNOTNULLTEST_FUNC)
{
- join_tab[0].type= JT_INDEX_IN;
+ join_tab[0].type= JT_INDEX_SUBQUERY;
error= 0;
+
+ if ((conds= remove_additional_cond(conds)))
+ join_tab->info= "Using index; Using where";
+ else
+ join_tab->info= "Using index";
+
DBUG_RETURN(unit->item->
- change_engine(new subselect_indexin_engine(thd,
- join_tab,
- unit->item,
- conds,
- 1)));
+ change_engine(new subselect_indexsubquery_engine(thd,
+ join_tab,
+ unit->item,
+ conds,
+ 1)));
}
}
@@ -916,7 +921,7 @@ JOIN::optimize()
{
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
- if (create_sort_index(thd, &join_tab[const_tables], group_list,
+ if (create_sort_index(thd, this, group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
alloc_group_fields(this, group_list) ||
make_sum_func_list(all_fields, fields_list, 1))
@@ -931,7 +936,7 @@ JOIN::optimize()
{
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
- if (create_sort_index(thd, &join_tab[const_tables], order,
+ if (create_sort_index(thd, this, order,
HA_POS_ERROR, HA_POS_ERROR))
DBUG_RETURN(1);
order=0;
@@ -1005,12 +1010,6 @@ JOIN::reinit()
/* Reset of sum functions */
first_record= 0;
- if (sum_funcs)
- {
- Item_sum *func, **func_ptr= sum_funcs;
- while ((func= *(func_ptr++)))
- func->null_value= 1;
- }
if (exec_tmp_table1)
{
@@ -1045,6 +1044,7 @@ JOIN::exec()
DBUG_ENTER("JOIN::exec");
error= 0;
+ thd->limit_found_rows= thd->examined_row_count= 0;
if (procedure)
{
if (procedure->change_columns(fields_list) ||
@@ -1235,7 +1235,7 @@ JOIN::exec()
if (curr_join->group_list)
{
thd->proc_info= "Creating sort index";
- if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list,
+ if (create_sort_index(thd, curr_join, curr_join->group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
make_group_fields(this, curr_join))
{
@@ -1416,7 +1416,7 @@ JOIN::exec()
}
}
}
- if (create_sort_index(thd, &curr_join->join_tab[curr_join->const_tables],
+ if (create_sort_index(thd, curr_join,
curr_join->group_list ?
curr_join->group_list : curr_join->order,
curr_join->select_limit, unit->select_limit_cnt))
@@ -1427,6 +1427,8 @@ JOIN::exec()
thd->proc_info="Sending data";
error= thd->net.report_error ||
do_select(curr_join, curr_fields_list, NULL, procedure);
+ thd->limit_found_rows= curr_join->send_records;
+ thd->examined_row_count= curr_join->examined_rows;
DBUG_VOID_RETURN;
}
@@ -1510,7 +1512,7 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
conds, og_num, order, group, having, proc_param,
select_lex, unit, tables_and_fields_initied))
{
- DBUG_RETURN(-1);
+ goto err;
}
}
join->select_options= select_options;
@@ -1525,15 +1527,12 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
conds, og_num, order, group, having, proc_param,
select_lex, unit, tables_and_fields_initied))
{
- DBUG_RETURN(-1);
+ goto err;
}
}
if ((err= join->optimize()))
{
- if (err == -1)
- DBUG_RETURN(join->error);
- DBUG_ASSERT(err == 1);
goto err; // 1
}
@@ -1549,8 +1548,6 @@ err:
(join->tmp_join->error=join->error,join->tmp_join):
join);
- thd->limit_found_rows= curr_join->send_records;
- thd->examined_row_count= curr_join->examined_rows;
thd->proc_info="end";
err= join->cleanup();
if (thd->net.report_error)
@@ -2053,28 +2050,34 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
static void
add_key_field(KEY_FIELD **key_fields,uint and_level,
- Field *field,bool eq_func,Item *value,
+ Field *field,bool eq_func,Item **value, uint num_values,
table_map usable_tables)
{
uint exists_optimize= 0;
if (!(field->flags & PART_KEY_FLAG))
{
// Don't remove column IS NULL on a LEFT JOIN table
- if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
- !field->table->maybe_null || field->null_ptr)
+ if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
+ !field->table->maybe_null || field->null_ptr)
return; // Not a key. Skip it
exists_optimize= KEY_OPTIMIZE_EXISTS;
}
else
{
table_map used_tables=0;
- if (value && ((used_tables=value->used_tables()) &
- (field->table->map | RAND_TABLE_BIT)))
+ bool optimizable=0;
+ for (uint i=0; i<num_values; i++)
+ {
+ used_tables|=(*value)->used_tables();
+ if (!((*value)->used_tables() & (field->table->map | RAND_TABLE_BIT)))
+ optimizable=1;
+ }
+ if (!optimizable)
return;
if (!(usable_tables & field->table->map))
{
- if (!eq_func || !value || value->type() != Item::NULL_ITEM ||
- !field->table->maybe_null || field->null_ptr)
+ if (!eq_func || (*value)->type() != Item::NULL_ITEM ||
+ !field->table->maybe_null || field->null_ptr)
return; // Can't use left join optimize
exists_optimize= KEY_OPTIMIZE_EXISTS;
}
@@ -2085,12 +2088,6 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
field->table->keys_in_use_for_query);
stat[0].keys|= possible_keys; // Add possible keys
- if (!value)
- { // Probably BETWEEN or IN
- stat[0].const_keys |= possible_keys;
- return; // Can't be used as eq key
- }
-
/*
Save the following cases:
Field op constant
@@ -2099,26 +2096,38 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
Field op formula
Field IS NULL
Field IS NOT NULL
+ Field BETWEEN ...
+ Field IN ...
*/
stat[0].key_dependent|=used_tables;
- if (value->const_item())
- stat[0].const_keys |= possible_keys;
+ bool is_const=1;
+ for (uint i=0; i<num_values; i++)
+ is_const&= (*value)->const_item();
+ if (is_const)
+ stat[0].const_keys |= possible_keys;
/*
We can't always use indexes when comparing a string index to a
- number. cmp_type() is checked to allow compare of dates to numbers
- */
+ number. cmp_type() is checked to allow compare of dates to numbers.
+ eq_func is NEVER true when num_values > 1
+ */
if (!eq_func ||
field->result_type() == STRING_RESULT &&
- value->result_type() != STRING_RESULT &&
- field->cmp_type() != value->result_type())
+ (*value)->result_type() != STRING_RESULT &&
+ field->cmp_type() != (*value)->result_type())
return;
}
}
+ DBUG_ASSERT(num_values == 1);
+ /*
+ For the moment eq_func is always true. This slot is reserved for future
+ extensions where we want to remembers other things than just eq comparisons
+ */
+ DBUG_ASSERT(eq_func);
/* Store possible eq field */
(*key_fields)->field= field;
(*key_fields)->eq_func= eq_func;
- (*key_fields)->val= value;
+ (*key_fields)->val= *value;
(*key_fields)->level= and_level;
(*key_fields)->optimize= exists_optimize;
(*key_fields)++;
@@ -2167,12 +2176,14 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
case Item_func::OPTIMIZE_NONE:
break;
case Item_func::OPTIMIZE_KEY:
+ // BETWEEN or IN
if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
add_key_field(key_fields,*and_level,
- ((Item_field*) (cond_func->key_item()->real_item()))
- ->field,
- 0,(Item*) 0,usable_tables);
+ ((Item_field*) (cond_func->key_item()->real_item()))->
+ field, 0,
+ cond_func->arguments()+1, cond_func->argument_count()-1,
+ usable_tables);
break;
case Item_func::OPTIMIZE_OP:
{
@@ -2186,7 +2197,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
((Item_field*) (cond_func->arguments()[0])->real_item())
->field,
equal_func,
- (cond_func->arguments()[1]),usable_tables);
+ cond_func->arguments()+1, 1, usable_tables);
}
if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
cond_func->functype() != Item_func::LIKE_FUNC &&
@@ -2196,7 +2207,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
((Item_field*) (cond_func->arguments()[1])->real_item())
->field,
equal_func,
- (cond_func->arguments()[0]),usable_tables);
+ cond_func->arguments(),1,usable_tables);
}
break;
}
@@ -2205,11 +2216,14 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM &&
!(cond_func->used_tables() & OUTER_REF_TABLE_BIT))
{
+ Item *tmp=new Item_null;
+ if (!tmp) // Should never be true
+ return;
add_key_field(key_fields,*and_level,
((Item_field*) (cond_func->arguments()[0])->real_item())
->field,
cond_func->functype() == Item_func::ISNULL_FUNC,
- new Item_null, usable_tables);
+ &tmp, 1, usable_tables);
}
break;
}
@@ -2461,7 +2475,7 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
Constant tables are ignored.
To avoid bad matches, we don't make ref_table_rows less than 100.
*/
- keyuse->ref_table_rows= ~(table_map) 0; // If no ref
+ keyuse->ref_table_rows= ~(ha_rows) 0; // If no ref
if (keyuse->used_tables &
(map= (keyuse->used_tables & ~join->const_table_map &
~OUTER_REF_TABLE_BIT)))
@@ -3328,13 +3342,33 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
+ /* Join with outer join condition */
+ COND *orig_cond=sel->cond;
+ sel->cond=and_conds(sel->cond,tab->on_expr);
if (sel->test_quick_select(tab->keys,
used_tables & ~ current_map,
(join->select_options &
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
join->unit->select_limit_cnt)) < 0)
- DBUG_RETURN(1); // Impossible range
+ {
+ /*
+ Before reporting "Impossible WHERE" for the whole query
+ we have to check isn't it only "impossible ON" instead
+ */
+ sel->cond=orig_cond;
+ if (!tab->on_expr ||
+ sel->test_quick_select(tab->keys,
+ used_tables & ~ current_map,
+ (join->select_options &
+ OPTION_FOUND_ROWS ?
+ HA_POS_ERROR :
+ join->unit->select_limit_cnt)) < 0)
+ DBUG_RETURN(1); // Impossible WHERE
+ }
+ else
+ sel->cond=orig_cond;
+
/* Fix for EXPLAIN */
if (sel->quick)
join->best_positions[i].records_read= sel->quick->records;
@@ -3997,9 +4031,42 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
}
}
+/*
+ Remove additional condition inserted by IN/ALL/ANY transformation
+
+ SYNOPSIS
+ remove_additional_cond()
+ conds - condition for processing
+
+ RETURN VALUES
+ new conditions
+*/
+
+static Item *remove_additional_cond(Item* conds)
+{
+ if (conds->name == in_additional_cond)
+ return 0;
+ if (conds->type() == Item::COND_ITEM)
+ {
+ Item_cond *cnd= (Item_cond*) conds;
+ List_iterator<Item> li(*(cnd->argument_list()));
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->name == in_additional_cond)
+ {
+ li.remove();
+ if (cnd->argument_list()->elements == 1)
+ return cnd->argument_list()->head();
+ return conds;
+ }
+ }
+ }
+ return conds;
+}
static void
-propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
+propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
COND *cond)
{
if (cond->type() == Item::COND_ITEM)
@@ -4025,7 +4092,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
cond_cmp->cmp_func->arguments()[1]);
}
}
- else if (and_level != cond && !cond->marker) // In a AND group
+ else if (and_father != cond && !cond->marker) // In a AND group
{
if (cond->type() == Item::FUNC_ITEM &&
(((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
@@ -4043,7 +4110,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
func->arguments()[1]=resolve_const_item(func->arguments()[1],
func->arguments()[0]);
func->update_used_tables();
- change_cond_ref_to_const(save_list,and_level,and_level,
+ change_cond_ref_to_const(save_list,and_father,and_father,
func->arguments()[0],
func->arguments()[1]);
}
@@ -4052,7 +4119,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
func->arguments()[0]=resolve_const_item(func->arguments()[0],
func->arguments()[1]);
func->update_used_tables();
- change_cond_ref_to_const(save_list,and_level,and_level,
+ change_cond_ref_to_const(save_list,and_father,and_father,
func->arguments()[1],
func->arguments()[0]);
}
@@ -4796,7 +4863,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->algorithm= HA_KEY_ALG_UNDEF;
for (; group ; group=group->next,key_part_info++)
{
- Field *field=(*group->item)->tmp_table_field();
+ Field *field=(*group->item)->get_tmp_table_field();
bool maybe_null=(*group->item)->maybe_null;
key_part_info->null_bit=0;
key_part_info->field= field;
@@ -5980,8 +6047,7 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!join->first_record)
{
/* No matching rows for group function */
- clear_tables(join);
- copy_fields(&join->tmp_table_param);
+ join->clear();
}
if (join->having && join->having->val_int() == 0)
error= -1; // Didn't satisfy having
@@ -6065,7 +6131,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
Item *item= *group->item;
if (item->maybe_null)
{
- Field *field=item->tmp_table_field();
+ Field *field=item->get_tmp_table_field();
field->ptr[-1]= (byte) (field->is_null() ? 1 : 0);
}
}
@@ -6247,8 +6313,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!join->first_record)
{
/* No matching rows for group function */
- clear_tables(join);
- copy_fields(&join->tmp_table_param);
+ join->clear();
}
copy_sum_funcs(join->sum_funcs);
if (!join->having || join->having->val_int())
@@ -6770,16 +6835,23 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
static int
-create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
+create_sort_index(THD *thd, JOIN *join, ORDER *order,
ha_rows filesort_limit, ha_rows select_limit)
{
SORT_FIELD *sortorder;
uint length;
ha_rows examined_rows;
- TABLE *table=tab->table;
- SQL_SELECT *select=tab->select;
+ TABLE *table;
+ SQL_SELECT *select;
+ JOIN_TAB *tab;
DBUG_ENTER("create_sort_index");
+ if (join->tables == join->const_tables)
+ DBUG_RETURN(0); // One row, no need to sort
+ tab= join->join_tab + join->const_tables;
+ table= tab->table;
+ select= tab->select;
+
if (test_if_skip_sort_order(tab,order,select_limit,0))
DBUG_RETURN(0);
if (!(sortorder=make_unireg_sortorder(order,&length)))
@@ -6928,7 +7000,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
Item *item;
while ((item=it++))
{
- if (item->tmp_table_field() && ! item->const_item())
+ if (item->get_tmp_table_field() && ! item->const_item())
field_count++;
}
@@ -7124,7 +7196,7 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
goto err;
}
else
- (void) hash_insert(&hash, key_pos-key_length);
+ (void) my_hash_insert(&hash, key_pos-key_length);
key_pos+=extra_length;
}
my_free((char*) key_buffer,MYF(0));
@@ -7164,7 +7236,7 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length)
pos->field= ((Item_field*) (*order->item))->field;
else if (order->item[0]->type() == Item::SUM_FUNC_ITEM &&
!order->item[0]->const_item())
- pos->field= ((Item_sum*) order->item[0])->tmp_table_field();
+ pos->field= ((Item_sum*) order->item[0])->get_tmp_table_field();
else if (order->item[0]->type() == Item::COPY_STR_ITEM)
{ // Blob patch
pos->item= ((Item_copy_string*) (*order->item))->item;
@@ -7761,7 +7833,7 @@ calc_group_buffer(JOIN *join,ORDER *group)
join->group= 1;
for (; group ; group=group->next)
{
- Field *field=(*group->item)->tmp_table_field();
+ Field *field=(*group->item)->get_tmp_table_field();
if (field)
{
if (field->type() == FIELD_TYPE_BLOB)
@@ -8105,7 +8177,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
{
item_field= item->get_tmp_table_item(thd);
}
- else if ((field= item->tmp_table_field()))
+ else if ((field= item->get_tmp_table_field()))
{
if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
item_field= ((Item_sum*) item)->result_item(field);
@@ -8208,7 +8280,7 @@ update_tmptable_sum_func(Item_sum **func_ptr,
{
Item_sum *func;
while ((func= *(func_ptr++)))
- func->update_field(0);
+ func->update_field();
}
@@ -8536,6 +8608,26 @@ int JOIN::rollup_send_data(uint idx)
return 0;
}
+/*
+ clear results if there are not rows found for group
+ (end_send_group/end_write_group)
+
+ SYNOPSYS
+ JOIN::clear()
+*/
+
+void JOIN::clear()
+{
+ clear_tables(this);
+ copy_fields(&tmp_table_param);
+
+ if (sum_funcs)
+ {
+ Item_sum *func, **func_ptr= sum_funcs;
+ while ((func= *(func_ptr++)))
+ func->clear();
+ }
+}
/****************************************************************************
EXPLAIN handling
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 208eaaea7bd..6c17a646ee6 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -76,7 +76,7 @@ typedef struct st_join_cache {
enum join_type { JT_UNKNOWN,JT_SYSTEM,JT_CONST,JT_EQ_REF,JT_REF,JT_MAYBE_REF,
JT_ALL, JT_RANGE, JT_NEXT, JT_FT, JT_REF_OR_NULL,
- JT_SIMPLE_IN, JT_INDEX_IN};
+ JT_UNIQUE_SUBQUERY, JT_INDEX_SUBQUERY};
class JOIN;
@@ -279,6 +279,7 @@ class JOIN :public Sql_alloc
Item_sum ***func);
int rollup_send_data(uint idx);
bool test_in_subselect(Item **where);
+ void clear();
};
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 9084269f486..8550973ff88 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -73,10 +73,12 @@ mysqld_show_dbs(THD *thd,const char *wild)
while ((file_name=it++))
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
thd->priv_user, file_name,0) ||
(grant_option && !check_grant_db(thd, file_name)))
+#endif
{
protocol->prepare_for_resend();
protocol->store(file_name, system_charset_info);
@@ -437,6 +439,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
continue;
}
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Don't show tables where we don't have any privileges */
if (db && !(col_access & TABLE_ACLS))
{
@@ -446,6 +449,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
if (check_grant(thd,TABLE_ACLS,&table_list,1,1))
continue;
}
+#endif
if (files->push_back(thd->strdup(file->name)))
{
my_dirend(dirp);
@@ -501,7 +505,9 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
item->maybe_null=1;
field_list.push_back(item=new Item_datetime("Check_time"));
item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("Charset",32));
+ field_list.push_back(item=new Item_empty_string("Collation",32));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Create_options",255));
item->maybe_null=1;
@@ -588,6 +594,10 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
}
str= (table->table_charset ? table->table_charset->name : "default");
protocol->store(str, system_charset_info);
+ if (file->table_flags() & HA_HAS_CHECKSUM)
+ protocol->store((ulonglong)file->checksum());
+ else
+ protocol->store_null(); // Checksum
{
char option_buff[350],*ptr;
ptr=option_buff;
@@ -668,8 +678,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
}
file=table->file;
file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
(void) get_table_grant(thd, table_list);
-
+#endif
List<Item> field_list;
field_list.push_back(new Item_empty_string("Field",NAME_LEN));
field_list.push_back(new Item_empty_string("Type",40));
@@ -749,6 +760,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
{
/* Add grant options & comments */
end=tmp;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
{
@@ -758,6 +770,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
end=strmov(end,grant_types.type_names[bitnr]);
}
}
+#else
+ end=strmov(end,"");
+#endif
protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1),
system_charset_info);
protocol->store(field->comment.str, field->comment.length,
@@ -791,9 +806,14 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(1);
}
+ if (store_create_info(thd, table, &buffer))
+ DBUG_RETURN(-1);
+
List<Item> field_list;
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH));
+ // 1024 is for not to confuse old clients
+ field_list.push_back(new Item_empty_string("Create Table",
+ max(buffer.length(),1024)));
if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(1);
@@ -1017,11 +1037,38 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
}
}
+
+/* Append directory name (if exists) to CREATE INFO */
+
+static void append_directory(THD *thd, String *packet, const char *dir_type,
+ const char *filename)
+{
+ uint length;
+ if (filename && !(thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE))
+ {
+ length= dirname_length(filename);
+ packet->append(' ');
+ packet->append(dir_type);
+ packet->append(" DIRECTORY='", 12);
+ packet->append(filename, length);
+ packet->append('\'');
+ }
+}
+
+
#define LIST_PROCESS_HOST_LEN 64
static int
store_create_info(THD *thd, TABLE *table, String *packet)
{
+ List<Item> field_list;
+ char tmp[MAX_FIELD_WIDTH], *for_str, buff[128], *end;
+ String type(tmp, sizeof(tmp),&my_charset_bin);
+ Field **ptr,*field;
+ uint primary_key;
+ KEY *key_info;
+ handler *file= table->file;
+ HA_CREATE_INFO create_info;
my_bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
MODE_ORACLE |
MODE_MSSQL |
@@ -1037,9 +1084,6 @@ store_create_info(THD *thd, TABLE *table, String *packet)
restore_record(table,default_values); // Get empty record
- List<Item> field_list;
- char tmp[MAX_FIELD_WIDTH];
- String type(tmp, sizeof(tmp),&my_charset_bin);
if (table->tmp_table)
packet->append("CREATE TEMPORARY TABLE ", 23);
else
@@ -1047,13 +1091,14 @@ store_create_info(THD *thd, TABLE *table, String *packet)
append_identifier(thd,packet, table->real_name, strlen(table->real_name));
packet->append(" (\n", 3);
- Field **ptr,*field;
for (ptr=table->field ; (field= *ptr); ptr++)
{
+ bool has_default;
+ uint flags = field->flags;
+
if (ptr != table->field)
packet->append(",\n", 2);
- uint flags = field->flags;
packet->append(" ", 2);
append_identifier(thd,packet,field->field_name, strlen(field->field_name));
packet->append(' ');
@@ -1090,9 +1135,9 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (flags & NOT_NULL_FLAG)
packet->append(" NOT NULL", 9);
- bool has_default = (field->type() != FIELD_TYPE_BLOB &&
- field->type() != FIELD_TYPE_TIMESTAMP &&
- field->unireg_check != Field::NEXT_NUMBER);
+ has_default= (field->type() != FIELD_TYPE_BLOB &&
+ field->type() != FIELD_TYPE_TIMESTAMP &&
+ field->unireg_check != Field::NEXT_NUMBER);
if (has_default)
{
@@ -1122,9 +1167,11 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
}
- KEY *key_info=table->key_info;
- table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
- uint primary_key = table->primary_key;
+ key_info= table->key_info;
+ file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
+ bzero((char*) &create_info, sizeof(create_info));
+ file->update_create_info(&create_info);
+ primary_key= table->primary_key;
for (uint i=0 ; i < table->keys ; i++,key_info++)
{
@@ -1175,9 +1222,10 @@ store_create_info(THD *thd, TABLE *table, String *packet)
table->field[key_part->fieldnr-1]->key_length() &&
!(key_info->flags & HA_FULLTEXT)))
{
- char buff[64];
buff[0] = '(';
- char* end=int10_to_str((long) key_part->length, buff + 1,10);
+ char* end=int10_to_str((long) key_part->length /
+ key_part->field->charset()->mbmaxlen,
+ buff + 1,10);
*end++ = ')';
packet->append(buff,(uint) (end-buff));
}
@@ -1189,10 +1237,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
Get possible foreign key definitions stored in InnoDB and append them
to the CREATE TABLE statement
*/
- handler *file = table->file;
- char* for_str= file->get_foreign_key_create_info();
- if (for_str)
+ if ((for_str= file->get_foreign_key_create_info()))
{
packet->append(for_str, strlen(for_str));
file->free_foreign_key_create_info(for_str);
@@ -1203,8 +1249,6 @@ store_create_info(THD *thd, TABLE *table, String *packet)
{
packet->append(" TYPE=", 6);
packet->append(file->table_type());
- char buff[128];
- char* p;
if (table->table_charset &&
!(thd->variables.sql_mode & MODE_MYSQL323) &&
@@ -1222,21 +1266,22 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (table->min_rows)
{
packet->append(" MIN_ROWS=");
- p = longlong10_to_str(table->min_rows, buff, 10);
- packet->append(buff, (uint) (p - buff));
+ end= longlong10_to_str(table->min_rows, buff, 10);
+ packet->append(buff, (uint) (end- buff));
}
if (table->max_rows)
{
packet->append(" MAX_ROWS=");
- p = longlong10_to_str(table->max_rows, buff, 10);
- packet->append(buff, (uint) (p - buff));
+ end= longlong10_to_str(table->max_rows, buff, 10);
+ packet->append(buff, (uint) (end - buff));
}
+
if (table->avg_row_length)
{
packet->append(" AVG_ROW_LENGTH=");
- p=longlong10_to_str(table->avg_row_length, buff,10);
- packet->append(buff, (uint) (p - buff));
+ end= longlong10_to_str(table->avg_row_length, buff,10);
+ packet->append(buff, (uint) (end - buff));
}
if (table->db_create_options & HA_OPTION_PACK_KEYS)
@@ -1260,12 +1305,15 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
if (file->raid_type)
{
- char buff[100];
- sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
- my_raid_type(file->raid_type), file->raid_chunks,
- file->raid_chunksize/RAID_BLOCK_SIZE);
- packet->append(buff);
+ uint length;
+ length= my_snprintf(buff,sizeof(buff),
+ " RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
+ my_raid_type(file->raid_type), file->raid_chunks,
+ file->raid_chunksize/RAID_BLOCK_SIZE);
+ packet->append(buff, length);
}
+ append_directory(thd, packet, "DATA", create_info.data_file_name);
+ append_directory(thd, packet, "INDEX", create_info.index_file_name);
}
DBUG_RETURN(0);
}
@@ -1458,11 +1506,15 @@ int mysqld_show_collations(THD *thd, const char *wild)
for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
{
CHARSET_INFO **cl;
+ if (!cs[0] || !(cs[0]->state & MY_CS_AVAILABLE) ||
+ !(cs[0]->state & MY_CS_PRIMARY))
+ continue;
for ( cl= all_charsets; cl < all_charsets+255 ;cl ++)
{
- if (!cs[0] || !cl[0] || !my_charset_same(cs[0],cl[0]) || !(cs[0]->state & MY_CS_PRIMARY))
+ if (!cl[0] || !(cl[0]->state & MY_CS_AVAILABLE) ||
+ !my_charset_same(cs[0],cl[0]))
continue;
- if (cs[0] && !(wild && wild[0] &&
+ if (!(wild && wild[0] &&
wild_case_compare(system_charset_info,cl[0]->name,wild)))
{
if (write_collation(protocol, cl[0]))
@@ -1506,8 +1558,10 @@ int mysqld_show_charsets(THD *thd, const char *wild)
for ( cs= all_charsets ; cs < all_charsets+255 ; cs++ )
{
- if (cs[0] && (cs[0]->state & MY_CS_PRIMARY) && !(wild && wild[0] &&
- wild_case_compare(system_charset_info,cs[0]->name,wild)))
+ if (cs[0] && (cs[0]->state & MY_CS_PRIMARY) &&
+ (cs[0]->state & MY_CS_AVAILABLE) &&
+ !(wild && wild[0] &&
+ wild_case_compare(system_charset_info,cs[0]->csname,wild)))
{
if (write_charset(protocol, cs[0]))
goto err;
@@ -1522,7 +1576,8 @@ err:
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
- enum enum_var_type value_type)
+ enum enum_var_type value_type,
+ pthread_mutex_t *mutex)
{
char buff[1024];
List<Item> field_list;
@@ -1536,8 +1591,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
DBUG_RETURN(1); /* purecov: inspected */
null_lex_str.str= 0; // For sys_var->value_ptr()
- /* pthread_mutex_lock(&THR_LOCK_keycache); */
- pthread_mutex_lock(&LOCK_status);
+ pthread_mutex_lock(mutex);
for (; variables->name; variables++)
{
if (!(wild && wild[0] && wild_case_compare(system_charset_info,
@@ -1625,83 +1679,83 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
case SHOW_SSL_CTX_SESS_ACCEPT:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_accept(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_accept_good(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_connect_good(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)),
+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CB_HITS:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_HITS:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_hits(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_CACHE_FULL:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_cache_full(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_MISSES:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
SSL_CTX_sess_misses(ssl_acceptor_fd->
- ssl_context_)),
+ ssl_context)),
buff, 10);
break;
case SHOW_SSL_CTX_SESS_TIMEOUTS:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_SESS_NUMBER:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_SESS_CONNECT:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_GET_VERIFY_MODE:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)),
+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context)),
buff,10);
break;
case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
@@ -1711,7 +1765,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
end= pos+4;
break;
}
- switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
+ switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context))
{
case SSL_SESS_CACHE_OFF:
pos= "OFF";
@@ -1739,40 +1793,50 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
break;
/* First group - functions relying on SSL */
case SHOW_SSL_GET_VERSION:
- pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : "";
+ pos= (thd->net.vio->ssl_arg ?
+ SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
end= strend(pos);
break;
case SHOW_SSL_SESSION_REUSED:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_session_reused(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_session_reused((SSL*) thd->net.vio->
+ ssl_arg) :
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_DEFAULT_TIMEOUT:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_get_default_timeout(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_default_timeout((SSL*) thd->net.vio->
+ ssl_arg) :
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_VERIFY_MODE:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_get_verify_mode(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_verify_mode((SSL*) thd->net.vio->
+ ssl_arg):
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_VERIFY_DEPTH:
- end= int10_to_str((long) (thd->net.vio->ssl_ ?
- SSL_get_verify_depth(thd->net.vio->ssl_):
- 0), buff, 10);
+ end= int10_to_str((long) (thd->net.vio->ssl_arg ?
+ SSL_get_verify_depth((SSL*) thd->net.vio->
+ ssl_arg):
+ 0),
+ buff, 10);
break;
case SHOW_SSL_GET_CIPHER:
- pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : "";
+ pos= (thd->net.vio->ssl_arg ?
+ SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "" );
end= strend(pos);
break;
case SHOW_SSL_GET_CIPHER_LIST:
- if (thd->net.vio->ssl_)
+ if (thd->net.vio->ssl_arg)
{
char *to= buff;
for (int i=0 ; i++ ;)
{
- const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i);
+ const char *p= SSL_get_cipher_list((SSL*) thd->net.vio->ssl_arg,i);
if (p == NULL)
break;
to= strmov(to, p);
@@ -1796,14 +1860,12 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
goto err; /* purecov: inspected */
}
}
- pthread_mutex_unlock(&LOCK_status);
- /* pthread_mutex_unlock(&THR_LOCK_keycache); */
+ pthread_mutex_unlock(mutex);
send_eof(thd);
DBUG_RETURN(0);
err:
- pthread_mutex_unlock(&LOCK_status);
- /* pthread_mutex_unlock(&THR_LOCK_keycache); */
+ pthread_mutex_unlock(mutex);
DBUG_RETURN(1);
}
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index e7d7b08c93c..be9404ce0b8 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -28,6 +28,11 @@
#include <floatingpoint.h>
#endif
+/*
+ The following extern declarations are ok as these are interface functions
+ required by the string function
+*/
+
extern gptr sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 37f8d0d7f4f..b8f4b360dda 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -29,7 +29,6 @@
#include <io.h>
#endif
-extern HASH open_cache;
static const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
@@ -350,10 +349,10 @@ static int sort_keys(KEY *a, KEY *b)
fields List of fields to create
keys List of keys to create
tmp_table Set to 1 if this is an internal temporary table
- (From ALTER TABLE)
+ (From ALTER TABLE)
no_log Don't log the query to binary log.
- DESCRIPTION
+ DESCRIPTION
If one creates a temporary table, this is automaticly opened
no_log is needed for the case of CREATE ... SELECT,
@@ -422,6 +421,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
for (field_no=0; (sql_field=it++) ; field_no++)
{
+ if (!sql_field->charset)
+ sql_field->charset= create_info->table_charset;
+ sql_field->create_length_to_internal_length();
+
/* Don't pack keys in old tables if the user has requested this */
if ((sql_field->flags & BLOB_FLAG) ||
sql_field->sql_type == FIELD_TYPE_VAR_STRING &&
@@ -672,11 +675,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
/*
Make SPATIAL to be RTREE by default
SPATIAL only on BLOB or at least BINARY, this
- actually should be replaced by special GEOM type
+ actually should be replaced by special GEOM type
in near future when new frm file is ready
checking for proper key parts number:
*/
-
+
if (key_info->flags == HA_SPATIAL)
{
if (key_info->key_parts != 1)
@@ -699,7 +702,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0), "RTREE INDEX");
DBUG_RETURN(-1);
}
-
+
List_iterator<key_part_spec> cols(key->columns);
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
@@ -725,6 +728,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
*/
if (key->type == Key::FULLTEXT)
column->length=test(f_is_blob(sql_field->pack_flag));
+ else
+ column->length*= sql_field->charset->mbmaxlen;
+
if (f_is_blob(sql_field->pack_flag))
{
if (!(file->table_flags() & HA_BLOB_KEY))
@@ -745,9 +751,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
{
if (!column->length )
{
- /*
+ /*
BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
- Lately we'll extend this code to support more dimensions
+ Lately we'll extend this code to support more dimensions
*/
column->length=4*sizeof(double);
}
@@ -798,7 +804,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
{
}
else if (column->length > length ||
- ((f_is_packed(sql_field->pack_flag) ||
+ ((f_is_packed(sql_field->pack_flag) ||
((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
(key_info->flags & HA_NOSAME))) &&
column->length != length))
@@ -899,22 +905,27 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
DBUG_RETURN(-1);
}
+ if (wait_if_global_read_lock(thd, 0))
+ DBUG_RETURN(error);
VOID(pthread_mutex_lock(&LOCK_open));
if (!tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
{
if (!access(path,F_OK))
{
- VOID(pthread_mutex_unlock(&LOCK_open));
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
- DBUG_RETURN(0);
- my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
- DBUG_RETURN(-1);
+ error= 0;
+ else
+ my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
+ goto end;
}
}
thd->proc_info="creating table";
+ if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)
+ create_info->data_file_name= create_info->index_file_name= 0;
create_info->table_options=db_options;
+
if (rea_create_table(thd, path, create_info, fields, key_count,
key_info_buffer))
{
@@ -946,6 +957,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
error=0;
end:
VOID(pthread_mutex_unlock(&LOCK_open));
+ start_waiting_global_read_lock(thd);
thd->proc_info="After create";
DBUG_RETURN(error);
}
@@ -1913,19 +1925,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<Key> key_list; // Add new keys here
create_field *def;
- /*
- For each column set charset to the table
- default if the column charset hasn't been specified
- explicitely. Change CREATE length into internal length
- */
- def_it.rewind();
- while ((def= def_it++))
- {
- if (!def->charset)
- def->charset= create_info->table_charset;
- def->create_length_to_internal_length();
- }
-
/*
First collect all fields from table which isn't in drop_list
*/
@@ -2102,10 +2101,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{ // Check if sub key
if (cfield->field->type() != FIELD_TYPE_BLOB &&
(cfield->field->pack_length() == key_part_length ||
- cfield->length != cfield->pack_length ||
- cfield->pack_length <= key_part_length))
+ cfield->length <= key_part_length /
+ key_part->field->charset()->mbmaxlen))
key_part_length=0; // Use whole field
}
+ key_part_length /= key_part->field->charset()->mbmaxlen;
key_parts.push_back(new key_part_spec(cfield->field_name,
key_part_length));
}
@@ -2558,7 +2558,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
delete_count++;
}
else
- found_count++;
+ found_count++;
}
end_read_record(&info);
free_io_cache(from);
@@ -2590,3 +2590,101 @@ copy_data_between_tables(TABLE *from,TABLE *to,
*deleted=delete_count;
DBUG_RETURN(error > 0 ? -1 : 0);
}
+
+
+int mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt)
+{
+ TABLE_LIST *table;
+ List<Item> field_list;
+ Item *item;
+ Protocol *protocol= thd->protocol;
+ DBUG_ENTER("mysql_admin_table");
+
+ field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
+ item->maybe_null= 1;
+ field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
+ item->maybe_null= 1;
+ if (protocol->send_fields(&field_list, 1))
+ DBUG_RETURN(-1);
+
+ for (table= tables; table; table= table->next)
+ {
+ char table_name[NAME_LEN*2+2];
+ bool fatal_error= 0;
+ TABLE *t;
+
+ strxmov(table_name, table->db ,".", table->real_name, NullS);
+
+ t= table->table= open_ltable(thd, table, TL_READ_NO_INSERT);
+ thd->clear_error(); // these errors shouldn't get client
+
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+
+ if (!t)
+ {
+ /* Table didn't exist */
+ protocol->store_null();
+ thd->net.last_error[0]=0;
+ }
+ else
+ {
+ t->pos_in_table_list= table;
+
+ if (t->file->table_flags() & HA_HAS_CHECKSUM &&
+ !(check_opt->flags & T_EXTEND))
+ protocol->store((ulonglong)t->file->checksum());
+ else if (!(t->file->table_flags() & HA_HAS_CHECKSUM) &&
+ (check_opt->flags & T_QUICK))
+ protocol->store_null();
+ else
+ {
+ /* calculating table's checksum */
+ ha_checksum crc= 0;
+ if (t->file->rnd_init(1))
+ protocol->store_null();
+ else
+ {
+ while (!t->file->rnd_next(t->record[0]))
+ {
+ ha_checksum row_crc= 0;
+ if (t->record[0] != t->field[0]->ptr)
+ row_crc= my_checksum(row_crc, t->record[0],
+ t->field[0]->ptr - t->record[0]);
+
+ for (uint i= 0; i < t->fields; i++ )
+ {
+ Field *f= t->field[i];
+ if (f->type() == FIELD_TYPE_BLOB)
+ {
+ String tmp;
+ f->val_str(&tmp,&tmp);
+ row_crc= my_checksum(row_crc, tmp.ptr(), tmp.length());
+ }
+ else
+ row_crc= my_checksum(row_crc, f->ptr, f->pack_length());
+ }
+
+ crc+= row_crc;
+ }
+ protocol->store((ulonglong)crc);
+ }
+ }
+ thd->clear_error();
+ close_thread_tables(thd);
+ table->table=0; // For query cache
+ }
+ if (protocol->write())
+ goto err;
+ }
+
+ send_eof(thd);
+ DBUG_RETURN(0);
+
+ err:
+ close_thread_tables(thd); // Shouldn't be needed
+ if (table)
+ table->table=0;
+ DBUG_RETURN(-1);
+}
+
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index d2f97640010..f991a09398b 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -41,7 +41,6 @@ static const char *lock_descriptions[] =
"High priority write lock",
"Highest priority write lock"
};
-extern HASH open_cache;
#ifndef DBUG_OFF
@@ -65,7 +64,6 @@ print_where(COND *cond,const char *info)
}
/* This is for debugging purposes */
-extern TABLE *unused_tables;
void print_cached_tables(void)
{
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index d191550f396..c237b023e7b 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -92,10 +92,13 @@ static void init_syms(udf_func *tmp)
tmp->func_deinit = dlsym(tmp->dlhandle, nm);
if (tmp->type == UDFTYPE_AGGREGATE)
{
- (void)strmov( end, "_reset" );
- tmp->func_reset = dlsym( tmp->dlhandle, nm );
+ (void)strmov( end, "_clear" );
+ tmp->func_clear = dlsym( tmp->dlhandle, nm );
(void)strmov( end, "_add" );
tmp->func_add = dlsym( tmp->dlhandle, nm );
+ /* Give error if _clear and _add doesn't exists */
+ if (!tmp->func_clear || ! tmp->func_add)
+ tmp->func= 0;
}
}
@@ -342,7 +345,7 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
tmp->returns = ret;
tmp->type = type;
tmp->usage_count=1;
- if (hash_insert(&udf_hash,(byte*) tmp))
+ if (my_hash_insert(&udf_hash,(byte*) tmp))
return 0;
using_udf_functions=1;
return tmp;
@@ -417,7 +420,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
u_d->func=udf->func;
u_d->func_init=udf->func_init;
u_d->func_deinit=udf->func_deinit;
- u_d->func_reset=udf->func_reset;
+ u_d->func_clear=udf->func_clear;
u_d->func_add=udf->func_add;
/* create entry in mysql/func table */
@@ -429,7 +432,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
- restore_record(table,default_values); // Get default values for fields
+ restore_record(table,default_values); // Default values for fields
table->field[0]->store(u_d->name.str, u_d->name.length, system_charset_info);
table->field[1]->store((longlong) u_d->returns);
table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_charset_info);
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index 29a351ac52f..7b10b80f148 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -33,7 +33,7 @@ typedef struct st_udf_func
void *func;
void *func_init;
void *func_deinit;
- void *func_reset;
+ void *func_clear;
void *func_add;
ulong usage_count;
} udf_func;
@@ -49,7 +49,7 @@ class udf_handler :public Sql_alloc
UDF_ARGS f_args;
UDF_INIT initid;
char *num_buffer;
- uchar error;
+ uchar error, is_null;
bool initialized;
Item **args;
@@ -57,7 +57,7 @@ class udf_handler :public Sql_alloc
table_map used_tables_cache;
bool const_item_cache;
udf_handler(udf_func *udf_arg) :u_d(udf_arg), buffers(0), error(0),
- initialized(0)
+ is_null(0), initialized(0)
{}
~udf_handler();
const char *name() const { return u_d ? u_d->name.str : "?"; }
@@ -73,7 +73,6 @@ class udf_handler :public Sql_alloc
*null_value=1;
return 0.0;
}
- uchar is_null=0;
double (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
(double (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func;
double tmp=func(&initid, &f_args, &is_null, &error);
@@ -92,7 +91,6 @@ class udf_handler :public Sql_alloc
*null_value=1;
return LL(0);
}
- uchar is_null=0;
longlong (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
(longlong (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func;
longlong tmp=func(&initid, &f_args, &is_null, &error);
@@ -104,22 +102,15 @@ class udf_handler :public Sql_alloc
*null_value=0;
return tmp;
}
- void reset(my_bool *null_value)
+ void clear()
{
- uchar is_null=0;
- if (get_arguments())
- {
- *null_value=1;
- return;
- }
- void (*func)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)=
- (void (*)(UDF_INIT *, UDF_ARGS *, uchar *, uchar *)) u_d->func_reset;
- func(&initid, &f_args, &is_null, &error);
- *null_value= (my_bool) (is_null || error);
+ is_null= 0;
+ void (*func)(UDF_INIT *, uchar *, uchar *)=
+ (void (*)(UDF_INIT *, uchar *, uchar *)) u_d->func_clear;
+ func(&initid, &is_null, &error);
}
void add(my_bool *null_value)
{
- uchar is_null=0;
if (get_arguments())
{
*null_value=1;
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index e5fe5b13b02..3a903d2e896 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -116,21 +116,20 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
bool tables_and_fields_initied)
{
SELECT_LEX *lex_select_save= thd->lex.current_select;
- SELECT_LEX *select_cursor;
+ SELECT_LEX *select_cursor,*sl;
DBUG_ENTER("st_select_lex_unit::prepare");
if (prepared)
DBUG_RETURN(0);
prepared= 1;
res= 0;
- found_rows_for_union= test(first_select_in_union()->options
- & OPTION_FOUND_ROWS);
+ found_rows_for_union= first_select_in_union()->options & OPTION_FOUND_ROWS;
TMP_TABLE_PARAM tmp_table_param;
result= sel_result;
t_and_f= tables_and_fields_initied;
bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM));
- thd->lex.current_select= select_cursor= first_select_in_union();
+ thd->lex.current_select= sl= select_cursor= first_select_in_union();
/* Global option */
if (t_and_f)
{
@@ -188,7 +187,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
union_result->not_describe=1;
union_result->tmp_table_param=tmp_table_param;
- for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
+ for (;sl; sl= sl->next_select())
{
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
@@ -198,7 +197,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR && !sl->braces)
+ if (select_limit_cnt == HA_POS_ERROR || sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array,
@@ -242,7 +241,7 @@ int st_select_lex_unit::exec()
{
SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor=first_select_in_union();
- ha_rows add_rows=0;
+ ulonglong add_rows=0;
DBUG_ENTER("st_select_lex_unit::exec");
if (executed && !(dependent || uncacheable))
@@ -259,29 +258,52 @@ int st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
- ha_rows rows= 0;
+ ha_rows records_at_start= 0;
thd->lex.current_select= sl;
if (optimized)
res= sl->join->reinit();
else
{
- offset_limit_cnt= sl->offset_limit;
- select_limit_cnt= sl->select_limit+sl->offset_limit;
+ if (sl != global_parameters)
+ {
+ offset_limit_cnt= sl->offset_limit;
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ }
+ else
+ {
+ offset_limit_cnt= 0;
+ /*
+ We can't use LIMIT at this stage if we are using ORDER BY for the
+ whole query
+ */
+ if (sl->order_list.first)
+ select_limit_cnt= HA_POS_ERROR;
+ else
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ }
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR)
+
+ /*
+ When using braces, SQL_CALC_FOUND_ROWS affects the whole query.
+ We don't calculate found_rows() per union part
+ */
+ if (select_limit_cnt == HA_POS_ERROR || sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
- else if (found_rows_for_union)
+ else
{
- rows= sl->select_limit;
- sl->options|= OPTION_FOUND_ROWS;
+ /*
+ We are doing an union without braces. In this case
+ SQL_CALC_FOUND_ROWS should be done on all sub parts
+ */
+ sl->options|= found_rows_for_union;
}
-
- /*
- As far as union share table space we should reassign table map,
- which can be spoiled by 'prepare' of JOIN of other UNION parts
- if it use same tables
+ sl->join->select_options=sl->options;
+ /*
+ As far as union share table space we should reassign table map,
+ which can be spoiled by 'prepare' of JOIN of other UNION parts
+ if it use same tables
*/
uint tablenr=0;
for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first;
@@ -303,8 +325,10 @@ int st_select_lex_unit::exec()
}
if (!res)
{
+ records_at_start= table->file->records;
sl->join->exec();
res= sl->join->error;
+ offset_limit_cnt= sl->offset_limit;
if (!res && union_result->flush())
{
thd->lex.current_select= lex_select_save;
@@ -316,10 +340,19 @@ int st_select_lex_unit::exec()
thd->lex.current_select= lex_select_save;
DBUG_RETURN(res);
}
- if (found_rows_for_union && !sl->braces &&
- (sl->options & OPTION_FOUND_ROWS))
- add_rows+= (sl->join->send_records > rows) ?
- sl->join->send_records - rows : 0;
+ /* Needed for the following test and for records_at_start in next loop */
+ table->file->info(HA_STATUS_VARIABLE);
+ if (found_rows_for_union & sl->options)
+ {
+ /*
+ This is a union without braces. Remember the number of rows that
+ could also have been part of the result set.
+ We get this from the difference of between total number of possible
+ rows and actual rows added to the temporary table.
+ */
+ add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong)
+ ((table->file->records - records_at_start)));
+ }
}
}
optimized= 1;
@@ -332,18 +365,15 @@ int st_select_lex_unit::exec()
List<Item_func_match> empty_list;
empty_list.empty();
- if (!thd->is_fatal_error) // Check if EOM
+ if (!thd->is_fatal_error) // Check if EOM
{
ulong options= thd->options;
thd->lex.current_select= fake_select_lex;
- if (select_cursor->braces)
- {
- offset_limit_cnt= global_parameters->offset_limit;
- select_limit_cnt= global_parameters->select_limit +
- global_parameters->offset_limit;
- if (select_limit_cnt < global_parameters->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
- }
+ offset_limit_cnt= global_parameters->offset_limit;
+ select_limit_cnt= global_parameters->select_limit +
+ global_parameters->offset_limit;
+ if (select_limit_cnt < global_parameters->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
options&= ~OPTION_FOUND_ROWS;
else if (found_rows_for_union && !describe)
@@ -384,12 +414,8 @@ int st_select_lex_unit::exec()
(ORDER*) NULL, NULL, (ORDER*) NULL,
options | SELECT_NO_UNLOCK,
result, this, fake_select_lex, 0);
- if (found_rows_for_union && !res)
- {
- thd->limit_found_rows= table->file->records;
- if (!select_cursor->braces)
- thd->limit_found_rows+= add_rows;
- }
+ if (!res)
+ thd->limit_found_rows = (ulonglong)table->file->records + add_rows;
/*
Mark for slow query log if any of the union parts didn't use
indexes efficiently
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 29138f10989..946107049dc 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -86,8 +86,10 @@ int mysql_update(THD *thd,
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys=table->keys_in_use;
table->quick_keys=0;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
want_privilege=table->grant.want_privilege;
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+#endif
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
tables.table= table;
@@ -122,7 +124,9 @@ int mysql_update(THD *thd,
}
/* Check the fields we are going to modify */
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
table->grant.want_privilege=want_privilege;
+#endif
if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0))
DBUG_RETURN(-1); /* purecov: inspected */
if (table->timestamp_field)
@@ -134,8 +138,10 @@ int mysql_update(THD *thd,
table->timestamp_field->query_id=timestamp_query_id;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check values */
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
+#endif
if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0))
{
free_underlaid_joins(thd, &thd->lex.select_lex);
@@ -418,7 +424,9 @@ int mysql_multi_update(THD *thd,
TABLE_LIST *tl;
DBUG_ENTER("mysql_multi_update");
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
table_list->grant.want_privilege=(SELECT_ACL & ~table_list->grant.privilege);
+#endif
if ((res=open_and_lock_tables(thd,table_list)))
DBUG_RETURN(res);
fix_tables_pointers(thd->lex.all_selects_list);
@@ -600,6 +608,7 @@ multi_update::initialize_tables(JOIN *join)
{
TABLE *table=table_ref->table;
uint cnt= table_ref->shared;
+ Item_field *If;
List<Item> temp_fields= *fields_for_table[cnt];
ORDER group;
@@ -623,7 +632,10 @@ multi_update::initialize_tables(JOIN *join)
/* ok to be on stack as this is not referenced outside of this func */
Field_string offset(table->file->ref_length, 0, "offset",
table, &my_charset_bin);
- if (temp_fields.push_front(new Item_field(((Field *) &offset))))
+ if (!(If=new Item_field(((Field *) &offset))))
+ DBUG_RETURN(1);
+ If->maybe_null=0;
+ if (temp_fields.push_front(If))
DBUG_RETURN(1);
/* Make an unique key over the first field to avoid duplicated updates */
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 543fe1ff2da..5e45a2c4fbb 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -38,7 +38,6 @@
#include <myisam.h>
#include <myisammrg.h>
-extern void yyerror(const char*);
int yylex(void *yylval, void *yythd);
#define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(int*) (F))) { yyerror((char*) (A)); return 2; }
@@ -168,6 +167,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SUPER_SYM
%token TRUNCATE_SYM
%token UNLOCK_SYM
+%token UNTIL_SYM
%token UPDATE_SYM
%token ACTION
@@ -277,6 +277,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MASTER_PORT_SYM
%token MASTER_CONNECT_RETRY_SYM
%token MASTER_SERVER_ID_SYM
+%token MASTER_SSL_SYM
+%token MASTER_SSL_CA_SYM
+%token MASTER_SSL_CAPATH_SYM
+%token MASTER_SSL_CERT_SYM
+%token MASTER_SSL_CIPHER_SYM
+%token MASTER_SSL_KEY_SYM
%token RELAY_LOG_FILE_SYM
%token RELAY_LOG_POS_SYM
%token MATCH
@@ -295,6 +301,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NEW_SYM
%token NCHAR_SYM
%token NCHAR_STRING
+%token NVARCHAR_SYM
%token NOT
%token NO_SYM
%token NULL_SYM
@@ -500,6 +507,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MULTIPOINT
%token MULTIPOLYGON
%token NOW_SYM
+%token OLD_PASSWORD
%token PASSWORD
%token POINTFROMTEXT
%token POINT_SYM
@@ -670,8 +678,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
insert_values update delete truncate rename
show describe load alter optimize preload flush
reset purge begin commit rollback savepoint
- slave master_def master_defs
- repair restore backup analyze check start
+ slave master_def master_defs master_file_def
+ repair restore backup analyze check start checksum
field_list field_list_item field_spec kill column_def key_def
preload_list preload_keys
select_item_list select_item values_list no_braces
@@ -729,23 +737,26 @@ verb_clause:
| begin
| change
| check
+ | checksum
| commit
| create
| delete
| describe
| do
| drop
+ | flush
| grant
+ | handler
+ | help
| insert
- | flush
+ | kill
| load
| lock
- | kill
| optimize
| preload
| purge
| rename
- | repair
+ | repair
| replace
| reset
| restore
@@ -754,15 +765,14 @@ verb_clause:
| savepoint
| select
| set
+ | show
| slave
| start
- | show
| truncate
- | handler
| unlock
| update
| use
- | help;
+ ;
/* help */
@@ -807,52 +817,77 @@ master_def:
Lex->mi.password = $3.str;
}
|
- MASTER_LOG_FILE_SYM EQ TEXT_STRING_sys
- {
- Lex->mi.log_file_name = $3.str;
- }
- |
MASTER_PORT_SYM EQ ULONG_NUM
{
Lex->mi.port = $3;
}
|
- MASTER_LOG_POS_SYM EQ ulonglong_num
- {
- Lex->mi.pos = $3;
- /*
- If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it
- instead of causing subsequent errors.
- We need to do it in this file, because only there we know that
- MASTER_LOG_POS has been explicitely specified. On the contrary
- in change_master() (sql_repl.cc) we cannot distinguish between 0
- (MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified),
- whereas we want to distinguish (specified 0 means "read the binlog
- from 0" (4 in fact), unspecified means "don't change the position
- (keep the preceding value)").
- */
- Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos);
- }
- |
MASTER_CONNECT_RETRY_SYM EQ ULONG_NUM
{
Lex->mi.connect_retry = $3;
}
+ | MASTER_SSL_SYM EQ ULONG_NUM
+ {
+ Lex->mi.ssl= $3 ?
+ LEX_MASTER_INFO::SSL_ENABLE : LEX_MASTER_INFO::SSL_DISABLE;
+ }
+ | MASTER_SSL_CA_SYM EQ TEXT_STRING_sys
+ {
+ Lex->mi.ssl_ca= $3.str;
+ }
+ | MASTER_SSL_CAPATH_SYM EQ TEXT_STRING_sys
+ {
+ Lex->mi.ssl_capath= $3.str;
+ }
+ | MASTER_SSL_CERT_SYM EQ TEXT_STRING_sys
+ {
+ Lex->mi.ssl_cert= $3.str;
+ }
+ | MASTER_SSL_CIPHER_SYM EQ TEXT_STRING_sys
+ {
+ Lex->mi.ssl_cipher= $3.str;
+ }
+ | MASTER_SSL_KEY_SYM EQ TEXT_STRING_sys
+ {
+ Lex->mi.ssl_key= $3.str;
+ }
|
- RELAY_LOG_FILE_SYM EQ TEXT_STRING_sys
- {
- Lex->mi.relay_log_name = $3.str;
- }
- |
- RELAY_LOG_POS_SYM EQ ULONG_NUM
+ master_file_def
+ ;
+
+master_file_def:
+ MASTER_LOG_FILE_SYM EQ TEXT_STRING_sys
{
- Lex->mi.relay_log_pos = $3;
- /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
- Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
+ Lex->mi.log_file_name = $3.str;
}
+ | MASTER_LOG_POS_SYM EQ ulonglong_num
+ {
+ Lex->mi.pos = $3;
+ /*
+ If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it
+ instead of causing subsequent errors.
+ We need to do it in this file, because only there we know that
+ MASTER_LOG_POS has been explicitely specified. On the contrary
+ in change_master() (sql_repl.cc) we cannot distinguish between 0
+ (MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified),
+ whereas we want to distinguish (specified 0 means "read the binlog
+ from 0" (4 in fact), unspecified means "don't change the position
+ (keep the preceding value)").
+ */
+ Lex->mi.pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.pos);
+ }
+ | RELAY_LOG_FILE_SYM EQ TEXT_STRING_sys
+ {
+ Lex->mi.relay_log_name = $3.str;
+ }
+ | RELAY_LOG_POS_SYM EQ ULONG_NUM
+ {
+ Lex->mi.relay_log_pos = $3;
+ /* Adjust if < BIN_LOG_HEADER_SIZE (same comment as Lex->mi.pos) */
+ Lex->mi.relay_log_pos = max(BIN_LOG_HEADER_SIZE, Lex->mi.relay_log_pos);
+ }
;
-
/* create a table */
create:
@@ -878,7 +913,7 @@ create:
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.options=$2 | $4;
lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type;
- lex->create_info.table_charset= thd->variables.character_set_database;
+ lex->create_info.table_charset= thd->variables.collation_database;
lex->name=0;
}
create2
@@ -1099,7 +1134,7 @@ opt_select_from:
| select_from select_lock_type;
udf_func_type:
- /* empty */ { $$ = UDFTYPE_FUNCTION; }
+ /* empty */ { $$ = UDFTYPE_FUNCTION; }
| AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; };
udf_type:
@@ -1163,7 +1198,8 @@ field_spec:
{
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0; lex->interval=0;
- lex->default_value=lex->comment=0;
+ lex->default_value=0;
+ lex->comment=0;
lex->charset=NULL;
}
type opt_attribute
@@ -1304,6 +1340,7 @@ varchar:
nvarchar:
NATIONAL_SYM VARCHAR {}
+ | NVARCHAR_SYM {}
| NCHAR_SYM VARCHAR {}
| NATIONAL_SYM CHAR_SYM VARYING {}
| NCHAR_SYM VARYING {}
@@ -1374,7 +1411,7 @@ attribute:
| opt_primary KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; }
| UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; }
| UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; }
- | COMMENT_SYM text_literal { Lex->comment= $2; }
+ | COMMENT_SYM TEXT_STRING_sys { Lex->comment= &$2; }
| COLLATE_SYM collation_name
{
if (Lex->charset && !my_charset_same(Lex->charset,$2))
@@ -1566,7 +1603,7 @@ opt_ident:
opt_component:
/* empty */ { $$.str= 0; $$.length= 0; }
| '.' ident { $$=$2; };
-
+
string_list:
text_string { Lex->interval_list.push_back($1); }
| string_list ',' text_string { Lex->interval_list.push_back($3); };
@@ -1595,7 +1632,7 @@ alter:
lex->select_lex.db=lex->name=0;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.db_type= DB_TYPE_DEFAULT;
- lex->create_info.table_charset= thd->variables.character_set_database;
+ lex->create_info.table_charset= thd->variables.collation_database;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
lex->alter_keys_onoff=LEAVE_AS_IS;
lex->simple_alter=1;
@@ -1631,7 +1668,8 @@ alter_list_item:
{
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0; lex->interval=0;
- lex->default_value=lex->comment=0;
+ lex->default_value=0;
+ lex->comment=0;
lex->charset= NULL;
lex->simple_alter=0;
}
@@ -1714,23 +1752,41 @@ opt_to:
| AS {};
/*
- The first two deprecate the last two--delete the last two for 4.1 release
+ SLAVE START and SLAVE STOP are deprecated. We keep them for compatibility.
+ To use UNTIL, one must use START SLAVE, not SLAVE START.
*/
slave:
- START_SYM SLAVE slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_START;
- lex->type = 0;
- }
+ START_SYM SLAVE slave_thread_opts
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_START;
+ lex->type = 0;
+ /* We'll use mi structure for UNTIL options */
+ bzero((char*) &lex->mi, sizeof(lex->mi));
+ }
+ slave_until
+ {}
| STOP_SYM SLAVE slave_thread_opts
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_SLAVE_STOP;
lex->type = 0;
}
- ;
+ | SLAVE START_SYM slave_thread_opts
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_START;
+ lex->type = 0;
+ }
+ | SLAVE STOP_SYM slave_thread_opts
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_STOP;
+ lex->type = 0;
+ }
+ ;
+
start:
START_SYM TRANSACTION_SYM { Lex->sql_command = SQLCOM_BEGIN;}
@@ -1740,6 +1796,7 @@ start:
slave_thread_opts:
{ Lex->slave_thd_opt= 0; }
slave_thread_opt_list
+ {}
;
slave_thread_opt_list:
@@ -1753,6 +1810,28 @@ slave_thread_opt:
| RELAY_THREAD { Lex->slave_thd_opt|=SLAVE_IO; }
;
+slave_until:
+ /*empty*/ {}
+ | UNTIL_SYM slave_until_opts
+ {
+ LEX *lex=Lex;
+ if ((lex->mi.log_file_name || lex->mi.pos) &&
+ (lex->mi.relay_log_name || lex->mi.relay_log_pos) ||
+ !((lex->mi.log_file_name && lex->mi.pos) ||
+ (lex->mi.relay_log_name && lex->mi.relay_log_pos)))
+ {
+ send_error(lex->thd, ER_BAD_SLAVE_UNTIL_COND);
+ YYABORT;
+ }
+
+ }
+ ;
+
+slave_until_opts:
+ master_file_def
+ | slave_until_opts ',' master_file_def ;
+
+
restore:
RESTORE_SYM table_or_tables
{
@@ -1773,6 +1852,22 @@ backup:
Lex->backup_dir = $6.str;
};
+checksum:
+ CHECKSUM_SYM table_or_tables
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_CHECKSUM;
+ }
+ table_list opt_checksum_type
+ {}
+ ;
+
+opt_checksum_type:
+ /* nothing */ { Lex->check_opt.flags= 0; }
+ | QUICK { Lex->check_opt.flags= T_QUICK; }
+ | EXTENDED_SYM { Lex->check_opt.flags= T_EXTEND; }
+ ;
+
repair:
REPAIR opt_no_write_to_binlog table_or_tables
{
@@ -1962,8 +2057,9 @@ select_init:
YYABORT;
}
/* select in braces, can't contain global parameters */
- sel->master_unit()->global_parameters=
- sel->master_unit()->fake_select_lex;
+ if (sel->master_unit()->fake_select_lex)
+ sel->master_unit()->global_parameters=
+ sel->master_unit()->fake_select_lex;
} union_opt;
select_init2:
@@ -2576,9 +2672,13 @@ simple_expr:
| NOW_SYM '(' expr ')'
{ $$= new Item_func_now_local($3); Lex->safe_to_cache_query=0;}
| PASSWORD '(' expr ')'
- { $$= new Item_func_password($3); }
- | PASSWORD '(' expr ',' expr ')'
- { $$= new Item_func_password($3,$5); }
+ {
+ $$= YYTHD->variables.old_passwords ?
+ (Item *) new Item_func_old_password($3) :
+ (Item *) new Item_func_password($3);
+ }
+ | OLD_PASSWORD '(' expr ')'
+ { $$= new Item_func_old_password($3); }
| POINT_SYM '(' expr ',' expr ')'
{ $$= new Item_func_point($3,$5); }
| POINTFROMTEXT '(' expr ')'
@@ -2960,6 +3060,13 @@ join_table:
| '(' SELECT_SYM select_derived ')' opt_table_alias
{
LEX *lex=Lex;
+ if (lex->sql_command == SQLCOM_UPDATE &&
+ &lex->select_lex == lex->current_select->outer_select())
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+
SELECT_LEX_UNIT *unit= lex->current_select->master_unit();
lex->current_select= unit->outer_select();
if (!($$= lex->current_select->
@@ -3382,7 +3489,7 @@ do: DO_SYM
*/
drop:
- DROP opt_temporary TABLE_SYM if_exists table_list opt_restrict
+ DROP opt_temporary table_or_tables if_exists table_list opt_restrict
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_TABLE;
@@ -4380,6 +4487,7 @@ keyword:
| BOOL_SYM {}
| BOOLEAN_SYM {}
| BYTE_SYM {}
+ | BTREE_SYM {}
| CACHE_SYM {}
| CHANGED {}
| CHARSET {}
@@ -4408,6 +4516,7 @@ keyword:
| DYNAMIC_SYM {}
| END {}
| ENUM {}
+ | ERRORS {}
| ESCAPE_SYM {}
| EVENTS_SYM {}
| EXECUTE_SYM {}
@@ -4425,6 +4534,7 @@ keyword:
| GRANTS {}
| GLOBAL_SYM {}
| HANDLER_SYM {}
+ | HASH_SYM {}
| HEAP_SYM {}
| HELP_SYM {}
| HOSTS_SYM {}
@@ -4453,6 +4563,12 @@ keyword:
| MASTER_USER_SYM {}
| MASTER_PASSWORD_SYM {}
| MASTER_CONNECT_RETRY_SYM {}
+ | MASTER_SSL_SYM {}
+ | MASTER_SSL_CA_SYM {}
+ | MASTER_SSL_CAPATH_SYM {}
+ | MASTER_SSL_CERT_SYM {}
+ | MASTER_SSL_CIPHER_SYM {}
+ | MASTER_SSL_KEY_SYM {}
| MAX_CONNECTIONS_PER_HOUR {}
| MAX_QUERIES_PER_HOUR {}
| MAX_UPDATES_PER_HOUR {}
@@ -4476,7 +4592,9 @@ keyword:
| NEW_SYM {}
| NO_SYM {}
| NONE_SYM {}
+ | NVARCHAR_SYM {}
| OFFSET_SYM {}
+ | OLD_PASSWORD {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PARTIAL {}
@@ -4507,6 +4625,7 @@ keyword:
| ROWS_SYM {}
| ROW_FORMAT_SYM {}
| ROW_SYM {}
+ | RTREE_SYM {}
| SAVEPOINT_SYM {}
| SECOND_SYM {}
| SERIAL_SYM {}
@@ -4539,10 +4658,12 @@ keyword:
| UDF_SYM {}
| UNCOMMITTED_SYM {}
| UNICODE_SYM {}
+ | UNTIL_SYM {}
| USER {}
| USE_FRM {}
| VARIABLES {}
| VALUE_SYM {}
+ | WARNINGS {}
| WORK_SYM {}
| X509_SYM {}
| YEAR_SYM {}
@@ -4624,7 +4745,7 @@ option_value:
THD *thd= YYTHD;
LEX *lex= Lex;
$2= $2 ? $2: global_system_variables.character_set_client;
- lex->var_list.push_back(new set_var_collation_client($2,thd->variables.character_set_database,$2));
+ lex->var_list.push_back(new set_var_collation_client($2,thd->variables.collation_database,$2));
}
| NAMES_SYM charset_name_or_default opt_collate
{
@@ -4699,15 +4820,15 @@ text_or_password:
TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')'
{
- if (!$3.length)
- $$=$3.str;
- else
- {
- char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
- make_scrambled_password(buff,$3.str,use_old_passwords,
- &YYTHD->rand);
- $$=buff;
- }
+ $$= $3.length ? YYTHD->variables.old_passwords ?
+ Item_func_old_password::alloc(YYTHD, $3.str) :
+ Item_func_password::alloc(YYTHD, $3.str) :
+ $3.str;
+ }
+ | OLD_PASSWORD '(' TEXT_STRING ')'
+ {
+ $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) :
+ $3.str;
}
;
@@ -4883,7 +5004,7 @@ grant_privilege_list:
| grant_privilege_list ',' grant_privilege;
grant_privilege:
- SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {}
+ SELECT_SYM { Lex->which_columns = SELECT_ACL;} opt_column_list {}
| INSERT { Lex->which_columns = INSERT_ACL;} opt_column_list {}
| UPDATE_SYM { Lex->which_columns = UPDATE_ACL; } opt_column_list {}
| REFERENCES { Lex->which_columns = REFERENCES_ACL;} opt_column_list {}
@@ -5015,14 +5136,24 @@ grant_user:
$$=$1; $1->password=$4;
if ($4.length)
{
- char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
- if (buff)
- {
- make_scrambled_password(buff,$4.str,use_old_passwords,
- &YYTHD->rand);
- $1->password.str=buff;
- $1->password.length=HASH_PASSWORD_LENGTH;
- }
+ if (YYTHD->variables.old_passwords)
+ {
+ char *buff=
+ (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
+ if (buff)
+ make_scrambled_password_323(buff, $4.str);
+ $1->password.str= buff;
+ $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+ }
+ else
+ {
+ char *buff=
+ (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
+ if (buff)
+ make_scrambled_password(buff, $4.str);
+ $1->password.str= buff;
+ $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+ }
}
}
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
@@ -5181,7 +5312,7 @@ union_opt:
;
optional_order_or_limit:
- /* Empty */ {}
+ /* Empty */ {}
|
{
THD *thd= YYTHD;
@@ -5190,9 +5321,12 @@ optional_order_or_limit:
SELECT_LEX *sel= lex->current_select;
SELECT_LEX_UNIT *unit= sel->master_unit();
SELECT_LEX *fake= unit->fake_select_lex;
- unit->global_parameters= fake;
- fake->no_table_names_allowed= 1;
- lex->current_select= fake;
+ if (fake)
+ {
+ unit->global_parameters= fake;
+ fake->no_table_names_allowed= 1;
+ lex->current_select= fake;
+ }
thd->where= "global ORDER clause";
}
order_or_limit
@@ -5276,3 +5410,4 @@ subselect_end:
LEX *lex=Lex;
lex->current_select = lex->current_select->return_after_parsing();
};
+
diff --git a/sql/table.cc b/sql/table.cc
index 9d12de1f6c7..c31b68fc2dc 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -236,7 +236,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
#ifdef HAVE_CRYPTED_FRM
else if (*(head+26) == 2)
{
- extern SQL_CRYPT *get_crypt_for_frm(void);
my_pthread_setspecific_ptr(THR_MALLOC,old_root);
crypted=get_crypt_for_frm();
my_pthread_setspecific_ptr(THR_MALLOC,&outparam->mem_root);
@@ -459,7 +458,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (outparam->timestamp_field == reg_field)
outparam->timestamp_field_offset=i;
if (use_hash)
- (void) hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail
+ (void) my_hash_insert(&outparam->name_hash,(byte*) *field_ptr); // Will never fail
}
*field_ptr=0; // End marker
@@ -1207,17 +1206,14 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
char *get_field(MEM_ROOT *mem, Field *field)
{
- char buff[MAX_FIELD_WIDTH], *to;
+ char buff[MAX_FIELD_WIDTH];
String str(buff,sizeof(buff),&my_charset_bin);
uint length;
field->val_str(&str,&str);
if (!(length= str.length()))
return NullS;
- to= (char*) alloc_root(mem,length+1);
- memcpy(to, str.ptr(), (uint) length);
- to[length]=0;
- return to;
+ return strmake_root(mem, str.ptr(), length);
}
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index 7f4417bf8fe..ba056a9d2fd 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -149,6 +149,7 @@ longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
my_bool avgcost_init( UDF_INIT* initid, UDF_ARGS* args, char* message );
void avgcost_deinit( UDF_INIT* initid );
void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
+void avgcost_clear( UDF_INIT* initid, char* is_null, char *error );
void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error );
}
@@ -902,21 +903,29 @@ avgcost_deinit( UDF_INIT* initid )
delete initid->ptr;
}
+
+/* This is only for MySQL 4.0 compability */
void
-avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message )
+avgcost_reset(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message)
{
- struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
- data->totalprice = 0.0;
- data->totalquantity = 0;
- data->count = 0;
+ avgcost_clear(initid, is_null, message);
+ avgcost_add(initid, args, is_null, message);
+}
- *is_null = 0;
- avgcost_add( initid, args, is_null, message );
+/* This is needed to get things to work in MySQL 4.1.1 and above */
+
+void
+avgcost_clear(UDF_INIT* initid, char* is_null, char* message)
+{
+ struct avgcost_data* data = (struct avgcost_data*)initid->ptr;
+ data->totalprice= 0.0;
+ data->totalquantity= 0;
+ data->count= 0;
}
void
-avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message )
+avgcost_add(UDF_INIT* initid, UDF_ARGS* args, char* is_null, char* message)
{
if (args->args[0] && args->args[1])
{