summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am11
-rw-r--r--sql/convert.cc12
-rw-r--r--sql/field.cc440
-rw-r--r--sql/field.h21
-rw-r--r--sql/field_conv.cc38
-rw-r--r--sql/filesort.cc22
-rw-r--r--sql/gen_lex_hash.cc748
-rw-r--r--sql/ha_berkeley.cc21
-rw-r--r--sql/ha_berkeley.h3
-rw-r--r--sql/ha_heap.cc24
-rw-r--r--sql/ha_heap.h1
-rw-r--r--sql/ha_innodb.cc355
-rw-r--r--sql/ha_innodb.h2
-rw-r--r--sql/ha_isam.cc3
-rw-r--r--sql/ha_isammrg.cc12
-rw-r--r--sql/ha_myisam.cc49
-rw-r--r--sql/ha_myisammrg.cc76
-rw-r--r--sql/ha_myisammrg.h6
-rw-r--r--sql/handler.cc8
-rw-r--r--sql/handler.h3
-rw-r--r--sql/hash_filo.h4
-rw-r--r--sql/hostname.cc2
-rw-r--r--sql/item.cc293
-rw-r--r--sql/item.h133
-rw-r--r--sql/item_cmpfunc.cc410
-rw-r--r--sql/item_cmpfunc.h158
-rw-r--r--sql/item_create.cc22
-rw-r--r--sql/item_create.h1
-rw-r--r--sql/item_func.cc229
-rw-r--r--sql/item_func.h105
-rw-r--r--sql/item_row.cc66
-rw-r--r--sql/item_row.h66
-rw-r--r--sql/item_strfunc.cc196
-rw-r--r--sql/item_strfunc.h70
-rw-r--r--sql/item_subselect.cc227
-rw-r--r--sql/item_subselect.h72
-rw-r--r--sql/item_sum.cc68
-rw-r--r--sql/item_sum.h16
-rw-r--r--sql/item_timefunc.cc155
-rw-r--r--sql/item_timefunc.h213
-rw-r--r--sql/item_uniq.h6
-rw-r--r--sql/lex.h21
-rw-r--r--sql/lock.cc12
-rw-r--r--sql/log.cc106
-rw-r--r--sql/log_event.cc167
-rw-r--r--sql/log_event.h50
-rw-r--r--sql/mini_client.cc115
-rw-r--r--sql/mysql_priv.h128
-rw-r--r--sql/mysqld.cc596
-rw-r--r--sql/nt_servc.cc28
-rw-r--r--sql/opt_range.cc182
-rw-r--r--sql/opt_sum.cc13
-rw-r--r--sql/password.c574
-rw-r--r--sql/procedure.h35
-rw-r--r--sql/repl_failsafe.cc9
-rw-r--r--sql/set_var.cc60
-rw-r--r--sql/set_var.h37
-rw-r--r--sql/share/czech/errmsg.txt16
-rw-r--r--sql/share/danish/errmsg.txt14
-rw-r--r--sql/share/dutch/errmsg.txt14
-rw-r--r--sql/share/english/errmsg.txt14
-rw-r--r--sql/share/estonian/errmsg.txt14
-rw-r--r--sql/share/french/errmsg.txt14
-rw-r--r--sql/share/german/errmsg.txt14
-rw-r--r--sql/share/greek/errmsg.txt14
-rw-r--r--sql/share/hungarian/errmsg.txt14
-rw-r--r--sql/share/italian/errmsg.txt14
-rw-r--r--sql/share/japanese/errmsg.txt14
-rw-r--r--sql/share/korean/errmsg.txt14
-rw-r--r--sql/share/norwegian-ny/errmsg.txt14
-rw-r--r--sql/share/norwegian/errmsg.txt14
-rw-r--r--sql/share/polish/errmsg.txt14
-rw-r--r--sql/share/portuguese/errmsg.txt14
-rw-r--r--sql/share/romanian/errmsg.txt14
-rw-r--r--sql/share/russian/errmsg.txt14
-rw-r--r--sql/share/serbian/errmsg.txt12
-rw-r--r--sql/share/slovak/errmsg.txt14
-rw-r--r--sql/share/spanish/errmsg.txt14
-rw-r--r--sql/share/swedish/errmsg.txt40
-rw-r--r--sql/share/ukrainian/errmsg.txt16
-rw-r--r--sql/slave.cc25
-rw-r--r--sql/slave.h4
-rw-r--r--sql/sql_acl.cc621
-rw-r--r--sql/sql_acl.h58
-rw-r--r--sql/sql_analyse.cc26
-rw-r--r--sql/sql_base.cc293
-rw-r--r--sql/sql_cache.cc140
-rw-r--r--sql/sql_cache.h4
-rw-r--r--sql/sql_class.cc136
-rw-r--r--sql/sql_class.h139
-rw-r--r--sql/sql_db.cc54
-rw-r--r--sql/sql_delete.cc203
-rw-r--r--sql/sql_derived.cc41
-rw-r--r--sql/sql_error.cc48
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_insert.cc174
-rw-r--r--sql/sql_lex.cc135
-rw-r--r--sql/sql_lex.h49
-rw-r--r--sql/sql_load.cc31
-rw-r--r--sql/sql_manager.cc2
-rw-r--r--sql/sql_olap.cc4
-rw-r--r--sql/sql_parse.cc902
-rw-r--r--sql/sql_prepare.cc385
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_repl.cc7
-rw-r--r--sql/sql_repl.h4
-rw-r--r--sql/sql_select.cc623
-rw-r--r--sql/sql_select.h36
-rw-r--r--sql/sql_show.cc12
-rw-r--r--sql/sql_string.cc328
-rw-r--r--sql/sql_string.h10
-rw-r--r--sql/sql_table.cc89
-rw-r--r--sql/sql_test.cc2
-rw-r--r--sql/sql_udf.cc6
-rw-r--r--sql/sql_union.cc30
-rw-r--r--sql/sql_update.cc848
-rw-r--r--sql/sql_yacc.yy1086
-rw-r--r--sql/stacktrace.c2
-rw-r--r--sql/table.cc18
-rw-r--r--sql/table.h19
-rw-r--r--sql/unireg.cc2
121 files changed, 8599 insertions, 4855 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 09fedd393c2..c5af51e8397 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -22,9 +22,8 @@ MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
INCLUDES = @MT_INCLUDES@ \
@bdb_includes@ @innodb_includes@ \
- -I$(srcdir)/../include \
- -I$(srcdir)/../regex \
- -I$(srcdir) -I../include -I. $(openssl_includes)
+ -I$(top_srcdir)/include -I$(top_srcdir)/regex \
+ -I$(srcdir) $(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
@@ -46,7 +45,8 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.h \
- item_create.h item_subselect.h mysql_priv.h \
+ item_create.h item_subselect.h item_row.h \
+ mysql_priv.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
field.h handler.h \
@@ -61,7 +61,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
- thr_malloc.cc item_create.cc item_subselect.cc\
+ thr_malloc.cc item_create.cc item_subselect.cc \
+ item_row.cc \
field.cc key.cc sql_class.cc sql_list.cc \
net_serv.cc net_pkg.cc lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
diff --git a/sql/convert.cc b/sql/convert.cc
index 13a6dfe0392..155cb57f9fe 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -433,17 +433,7 @@ CONVERT *get_convert_set(const char *name)
{
for (CONVERT **ptr=convert_tables ; *ptr ; ptr++)
{
- /*
- BAR TODO: Monty's comments:
- Why is this using system_charset_info ?
- Isn't the character-set string given in the users default charset?
- Please add a TODO note to the code that this has to be fixed when the user
- will be able to cast strings to different character sets...
- The current code will also not work if/when we introduce support for
- 16 bit characters...
- (I know that there is a LOT of changes to do if we ever want do this...)
- */
- if (!my_strcasecmp(system_charset_info,(*ptr)->name,name))
+ if (!my_strcasecmp(my_charset_latin1,(*ptr)->name,name))
return (*ptr);
}
return 0;
diff --git a/sql/field.cc b/sql/field.cc
index d8742d487f9..3cb51757b4e 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -15,16 +15,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*
- NOTES:
- Some of the number class uses the system functions strtol(), strtoll()...
- To avoid patching the end \0 or copying the buffer unnecessary, all calls
- to system functions are wrapped to a String object that adds the end null
- if it only if it isn't there.
- This adds some overhead when assigning numbers from strings but makes
- everything simpler.
- */
-
/*****************************************************************************
** This file implements classes defined in field.h
*****************************************************************************/
@@ -41,6 +31,11 @@
#include <floatingpoint.h>
#endif
+// Maximum allowed exponent value for converting string to decimal
+#define MAX_EXPONENT 1024
+
+
+
/*****************************************************************************
Instansiate templates and static variables
*****************************************************************************/
@@ -75,12 +70,14 @@ void Field_num::prepend_zeros(String *value)
This is only used to give warnings in ALTER TABLE or LOAD DATA...
*/
-bool test_if_int(const char *str,int length)
+bool test_if_int(const char *str,int length, CHARSET_INFO *cs)
{
const char *end=str+length;
+ cs=system_charset_info; // QQ move test_if_int into CHARSET_INFO struct
+
// Allow start space
- while (str != end && my_isspace(system_charset_info,*str))
+ while (str != end && my_isspace(cs,*str))
str++; /* purecov: inspected */
if (str != end && (*str == '-' || *str == '+'))
str++;
@@ -88,7 +85,7 @@ bool test_if_int(const char *str,int length)
return 0; // Error: Empty string
for (; str != end ; str++)
{
- if (!my_isdigit(system_charset_info,*str))
+ if (!my_isdigit(cs,*str))
{
if (*str == '.')
{ // Allow '.0000'
@@ -96,10 +93,10 @@ bool test_if_int(const char *str,int length)
if (str == end)
return 1;
}
- if (!my_isspace(system_charset_info,*str))
+ if (!my_isspace(cs,*str))
return 0;
for (str++ ; str != end ; str++)
- if (!my_isspace(system_charset_info,*str))
+ if (!my_isspace(cs,*str))
return 0;
return 1;
}
@@ -108,9 +105,11 @@ bool test_if_int(const char *str,int length)
}
-static bool test_if_real(const char *str,int length)
+static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
{
- while (length && my_isspace(system_charset_info,*str))
+ cs=system_charset_info; // QQ move test_if_int into CHARSET_INFO struct
+
+ while (length && my_isspace(cs,*str))
{ // Allow start space
length--; str++;
}
@@ -119,10 +118,10 @@ static bool test_if_real(const char *str,int length)
if (*str == '+' || *str == '-')
{
length--; str++;
- if (!length || !(my_isdigit(system_charset_info,*str) || *str == '.'))
+ if (!length || !(my_isdigit(cs,*str) || *str == '.'))
return 0;
}
- while (length && my_isdigit(system_charset_info,*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
@@ -131,7 +130,7 @@ static bool test_if_real(const char *str,int length)
if (*str == '.')
{
length--; str++;
- while (length && my_isdigit(system_charset_info,*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
@@ -141,18 +140,18 @@ static bool test_if_real(const char *str,int length)
if (*str == 'E' || *str == 'e')
{
if (length < 3 || (str[1] != '+' && str[1] != '-') ||
- !my_isdigit(system_charset_info,str[2]))
+ !my_isdigit(cs,str[2]))
return 0;
length-=3;
str+=3;
- while (length && my_isdigit(system_charset_info,*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
}
for (; length ; length--, str++)
{ // Allow end space
- if (!my_isspace(system_charset_info,*str))
+ if (!my_isspace(cs,*str))
return 0;
}
return 1;
@@ -295,23 +294,23 @@ void Field::store_time(TIME *ltime,timestamp_type type)
char buff[25];
switch (type) {
case TIMESTAMP_NONE:
- store("",0,default_charset_info); // Probably an error
+ store("",0,my_charset_latin1); // Probably an error
break;
case TIMESTAMP_DATE:
sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
- store(buff,10,default_charset_info);
+ store(buff,10,my_charset_latin1);
break;
case TIMESTAMP_FULL:
sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
ltime->year,ltime->month,ltime->day,
ltime->hour,ltime->minute,ltime->second);
- store(buff,19,default_charset_info);
+ store(buff,19,my_charset_latin1);
break;
case TIMESTAMP_TIME:
{
ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
ltime->hour,ltime->minute,ltime->second));
- store(buff,(uint) length, default_charset_info);
+ store(buff,(uint) length, my_charset_latin1);
break;
}
}
@@ -331,7 +330,7 @@ bool Field::optimize_range(uint idx)
void
Field_decimal::reset(void)
{
- Field_decimal::store("0",1,default_charset_info);
+ Field_decimal::store("0",1,my_charset_latin1);
}
void Field_decimal::overflow(bool negative)
@@ -392,7 +391,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
const char *frac_digits_from, *frac_digits_end;
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0;
- uint exponent=0; // value of the exponent
+ uint exponent=0; // value of the exponent
/*
Pointers used when digits move from the left of the '.' to the
right of the '.' (explained below)
@@ -488,13 +487,17 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
else
expo_sign_char= '+';
/*
- Read digits of the exponent and compute its value
- 'exponent' overflow (e.g. if 1E10000000000000000) is not a problem
- (the value of the field will be overflow anyway, or 0 anyway,
- it does not change anything if the exponent is 2^32 or more
+ Read digits of the exponent and compute its value. We must care about
+ 'exponent' overflow, because as unsigned arithmetic is "modulo", big
+ exponents will become small (e.g. 1e4294967296 will become 1e0, and the
+ field will finally contain 1 instead of its max possible value).
*/
- for (;from!=end && my_isdigit(system_charset_info, (*from)); from++)
+ for (;from!=end && my_isdigit(system_charset_info, *from); from++)
+ {
exponent=10*exponent+(*from-'0');
+ if (exponent>MAX_EXPONENT)
+ break;
+ }
}
/*
@@ -536,6 +539,13 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
int_digits_added_zeros=2 (to make 1234500).
*/
+ /*
+ Below tmp_uint cannot overflow with small enough MAX_EXPONENT setting,
+ as int_digits_added_zeros<=exponent<4G and
+ (int_digits_end-int_digits_from)<=max_allowed_packet<=2G and
+ (frac_digits_from-int_digits_tail_from)<=max_allowed_packet<=2G
+ */
+
if (!expo_sign_char)
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
else if (expo_sign_char == '-')
@@ -544,7 +554,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
frac_digits_added_zeros=exponent-tmp_uint;
int_digits_end -= tmp_uint;
frac_digits_head_end=int_digits_end+tmp_uint;
- tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
+ tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
}
else // (expo_sign_char=='+')
{
@@ -571,9 +581,9 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
int_digits_added_zeros=0;
}
}
- tmp_uint=(tmp_dec+(uint)(int_digits_end-int_digits_from)
- +(uint)(frac_digits_from-int_digits_tail_from)+
- int_digits_added_zeros);
+ tmp_uint= (tmp_dec+(int_digits_end-int_digits_from)+
+ (uint)(frac_digits_from-int_digits_tail_from)+
+ int_digits_added_zeros);
}
/*
@@ -584,7 +594,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
If the sign is defined and '-', we need one position for it
*/
- if (field_length < tmp_uint + (int) (sign_char == '-'))
+ if (field_length < tmp_uint + (int) (sign_char == '-'))
{
// too big number, change to max or min number
Field_decimal::overflow(sign_char == '-');
@@ -647,69 +657,67 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
*pos--=' '; //fill with blanks
}
- if (tmp_dec) // This field has decimals
- {
- /*
- Write digits of the frac_% parts ;
- Depending on current_thd->count_cutted_fields, we may also want
- to know if some non-zero tail of these parts will
- be truncated (for example, 0.002->0.00 will generate a warning,
- while 0.000->0.00 will not)
- (and 0E1000000000 will not, while 1E-1000000000 will)
- */
+ /*
+ Write digits of the frac_% parts ;
+ Depending on current_thd->count_cutted_fields, we may also want
+ to know if some non-zero tail of these parts will
+ be truncated (for example, 0.002->0.00 will generate a warning,
+ while 0.000->0.00 will not)
+ (and 0E1000000000 will not, while 1E-1000000000 will)
+ */
- pos=to+(uint)(field_length-tmp_dec); // Calculate post to '.'
+ pos=to+(uint)(field_length-tmp_dec); // Calculate post to '.'
+ right_wall=to+field_length;
+ if (pos != right_wall)
*pos++='.';
- right_wall=to+field_length;
- if (expo_sign_char == '-')
+ if (expo_sign_char == '-')
+ {
+ while (frac_digits_added_zeros-- > 0)
{
- while (frac_digits_added_zeros-- > 0)
+ if (pos == right_wall)
{
- if (pos == right_wall)
- {
- if (current_thd->count_cuted_fields && !is_cuted_fields_incr)
- break; // Go on below to see if we lose non zero digits
- return 0;
- }
- *pos++='0';
+ if (current_thd->count_cuted_fields && !is_cuted_fields_incr)
+ break; // Go on below to see if we lose non zero digits
+ return 0;
}
- while (int_digits_end != frac_digits_head_end)
+ *pos++='0';
+ }
+ while (int_digits_end != frac_digits_head_end)
+ {
+ tmp_char= *int_digits_end++;
+ if (pos == right_wall)
{
- tmp_char= *int_digits_end++;
- if (pos == right_wall)
- {
- if (tmp_char != '0') // Losing a non zero digit ?
- {
- if (!is_cuted_fields_incr)
- current_thd->cuted_fields++;
- return 0;
- }
- continue;
- }
- *pos++= tmp_char;
+ if (tmp_char != '0') // Losing a non zero digit ?
+ {
+ if (!is_cuted_fields_incr)
+ current_thd->cuted_fields++;
+ return 0;
+ }
+ continue;
}
+ *pos++= tmp_char;
}
+ }
- for (;frac_digits_from!=frac_digits_end;)
+ for (;frac_digits_from!=frac_digits_end;)
+ {
+ tmp_char= *frac_digits_from++;
+ if (pos == right_wall)
{
- tmp_char= *frac_digits_from++;
- if (pos == right_wall)
+ if (tmp_char != '0') // Losing a non zero digit ?
{
- if (tmp_char != '0') // Losing a non zero digit ?
- {
- if (!is_cuted_fields_incr)
- current_thd->cuted_fields++;
- return 0;
- }
- continue;
+ if (!is_cuted_fields_incr)
+ current_thd->cuted_fields++;
+ return 0;
}
- *pos++= tmp_char;
+ continue;
}
-
- while (pos != right_wall)
- *pos++='0'; // Fill with zeros at right of '.'
+ *pos++= tmp_char;
}
+
+ while (pos != right_wall)
+ *pos++='0'; // Fill with zeros at right of '.'
return 0;
}
@@ -794,22 +802,17 @@ int Field_decimal::store(longlong nr)
double Field_decimal::val_real(void)
{
- char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
- double nr=atod(ptr);
- *(ptr+field_length)=temp;
- return(nr);
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr,field_length,NULL);
}
longlong Field_decimal::val_int(void)
{
- char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
- longlong nr;
+ CHARSET_INFO *cs=charset();
if (unsigned_flag)
- nr=(longlong) strtoull(ptr,NULL,10);
+ return my_strntoull(cs,ptr,field_length,NULL,10);
else
- nr=strtoll(ptr,NULL,10);
- *(ptr+field_length)=temp;
- return(nr);
+ return my_strntoll(cs,ptr,field_length,NULL,10);
}
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
@@ -907,8 +910,7 @@ void Field_decimal::sql_type(String &res) const
int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len,default_charset_info);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ long tmp= my_strntol(cs,from,len,(char **)NULL,10);
int error= 0;
if (unsigned_flag)
@@ -925,7 +927,7 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -945,7 +947,7 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -1055,13 +1057,17 @@ longlong Field_tiny::val_int(void)
String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs=current_thd->thd_charset;
uint length;
- val_buffer->alloc(max(field_length+1,5));
+ uint mlength=max(field_length+1,5*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
+
if (unsigned_flag)
- length= (uint) (int10_to_str((long) *((uchar*) ptr),to,10)-to);
+ length= (uint) cs->l10tostr(cs,to,mlength, 10,(long) *((uchar*) ptr));
else
- length= (uint) (int10_to_str((long) *((signed char*) ptr),to,-10)-to);
+ length= (uint) cs->l10tostr(cs,to,mlength,-10,(long) *((signed char*) ptr));
+
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1097,13 +1103,11 @@ void Field_tiny::sql_type(String &res) const
****************************************************************************/
-// Note: Sometimes this should be fixed to use one strtol() to use
-// len and check for garbage after number.
+// Note: Sometimes this should be fixed to check for garbage after number.
int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len,default_charset_info);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ long tmp= my_strntol(cs,from,len,NULL,10);
int error= 0;
if (unsigned_flag)
{
@@ -1119,7 +1123,7 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -1139,7 +1143,7 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -1284,8 +1288,10 @@ longlong Field_short::val_int(void)
String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs=current_thd->thd_charset;
uint length;
- val_buffer->alloc(max(field_length+1,7));
+ uint mlength=max(field_length+1,7*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
short j;
#ifdef WORDS_BIGENDIAN
@@ -1296,9 +1302,9 @@ String *Field_short::val_str(String *val_buffer,
shortget(j,ptr);
if (unsigned_flag)
- length=(uint) (int10_to_str((long) (uint16) j,to,10)-to);
+ length=(uint) cs->l10tostr(cs,to,mlength, 10, (long) (uint16) j);
else
- length=(uint) (int10_to_str((long) j,to,-10)-to);
+ length=(uint) cs->l10tostr(cs,to,mlength,-10, (long) j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1361,13 +1367,11 @@ void Field_short::sql_type(String &res) const
** medium int
****************************************************************************/
-// Note: Sometimes this should be fixed to use one strtol() to use
-// len and check for garbage after number.
+// Note: Sometimes this should be fixed to check for garbage after number.
int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len,default_charset_info);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ long tmp= my_strntol(cs,from,len,NULL,10);
int error= 0;
if (unsigned_flag)
@@ -1384,7 +1388,7 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -1404,7 +1408,7 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
error= 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -1519,12 +1523,14 @@ longlong Field_medium::val_int(void)
String *Field_medium::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs=current_thd->thd_charset;
uint length;
- val_buffer->alloc(max(field_length+1,10));
+ uint mlength=max(field_length+1,10*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
- length=(uint) (int10_to_str(j,to,-10)-to);
+ length=(uint) cs->l10tostr(cs,to,mlength,-10,j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
@@ -1570,18 +1576,19 @@ void Field_medium::sql_type(String &res) const
****************************************************************************/
-// Note: Sometimes this should be fixed to use one strtol() to use
-// len and check for garbage after number.
+// Note: Sometimes this should be fixed to check for garbage after number.
int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
- while (len && my_isspace(system_charset_info,*from))
+ char *end;
+ while (len && my_isspace(cs,*from))
{
len--; from++;
}
long tmp;
+ String tmp_str(from, len, cs);
+ from= tmp_str.c_ptr(); // Add end null if needed
int error= 0;
- String tmp_str(from,len,default_charset_info);
errno=0;
if (unsigned_flag)
{
@@ -1592,11 +1599,13 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1;
}
else
- tmp=(long) strtoul(tmp_str.c_ptr(),NULL,10);
+ tmp=(long) my_strntoul(cs,from,len,&end,10);
}
else
- tmp=strtol(tmp_str.c_ptr(),NULL,10);
- if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
+ tmp=my_strntol(cs,from,len,&end,10);
+ if (errno ||
+ (from+len != end && current_thd->count_cuted_fields &&
+ !test_if_int(from,len,cs)))
{
current_thd->cuted_fields++;
error= 1;
@@ -1741,8 +1750,10 @@ longlong Field_long::val_int(void)
String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs=current_thd->thd_charset;
uint length;
- val_buffer->alloc(max(field_length+1,12));
+ uint mlength=max(field_length+1,12*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
int32 j;
#ifdef WORDS_BIGENDIAN
@@ -1752,9 +1763,10 @@ String *Field_long::val_str(String *val_buffer,
#endif
longget(j,ptr);
- length=(uint) (int10_to_str((unsigned_flag ? (long) (uint32) j : (long) j),
- to,
- unsigned_flag ? 10 : -10)-to);
+ if (unsigned_flag)
+ length=cs->l10tostr(cs,to,mlength, 10,(long) (uint32)j);
+ else
+ length=cs->l10tostr(cs,to,mlength,-10,(long) j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1821,12 +1833,14 @@ void Field_long::sql_type(String &res) const
int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
{
- while (len && my_isspace(system_charset_info,*from))
+ char *end;
+ while (len && my_isspace(cs,*from))
{ // For easy error check
len--; from++;
}
longlong tmp;
- String tmp_str(from,len,default_charset_info);
+ String tmp_str(from, len, cs);
+ from= tmp_str.c_ptr(); // Add end null if needed
int error= 0;
errno=0;
if (unsigned_flag)
@@ -1838,15 +1852,14 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
error= 1;
}
else
- tmp=(longlong) strtoull(tmp_str.c_ptr(),NULL,10);
+ tmp=(longlong) my_strntoull(cs,from,len,&end,10);
}
else
- tmp=strtoll(tmp_str.c_ptr(),NULL,10);
- if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
- {
- current_thd->cuted_fields++;
- error= 1;
- }
+ tmp=my_strntoll(cs,from,len,&end,10);
+ if (errno ||
+ (from+len != end && current_thd->count_cuted_fields &&
+ !test_if_int(from,len,cs)))
+ current_thd->cuted_fields++;
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1954,8 +1967,10 @@ longlong Field_longlong::val_int(void)
String *Field_longlong::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs=current_thd->thd_charset;
uint length;
- val_buffer->alloc(max(field_length+1,22));
+ uint mlength=max(field_length+1,22*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
longlong j;
#ifdef WORDS_BIGENDIAN
@@ -1965,7 +1980,7 @@ String *Field_longlong::val_str(String *val_buffer,
#endif
longlongget(j,ptr);
- length=(uint) (longlong10_to_str(j,to,unsigned_flag ? 10 : -10)-to);
+ length=(uint) cs->ll10tostr(cs,to,mlength,unsigned_flag ? 10 : -10, j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -2041,10 +2056,9 @@ void Field_longlong::sql_type(String &res) const
int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len,default_charset_info);
errno=0;
- Field_float::store(atof(tmp_str.c_ptr()));
- if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
+ Field_float::store(my_strntod(cs,from,len,(char**)NULL));
+ if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
{
current_thd->cuted_fields++;
return 1;
@@ -2303,11 +2317,10 @@ void Field_float::sql_type(String &res) const
int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len,default_charset_info);
errno=0;
int error= 0;
- double j= atof(tmp_str.c_ptr());
- if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
+ double j= my_strntod(cs,from,len,(char**)0);
+ if (errno || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
{
current_thd->cuted_fields++;
error= 1;
@@ -3083,8 +3096,7 @@ void Field_time::sql_type(String &res) const
int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len,default_charset_info);
- long nr= strtol(tmp_str.c_ptr(),NULL,10);
+ long nr= my_strntol(cs,from,len,NULL,10);
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
@@ -3092,7 +3104,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
current_thd->cuted_fields++;
return 1;
}
- else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,cs))
current_thd->cuted_fields++;
if (nr != 0 || len != 4)
{
@@ -3777,37 +3789,32 @@ int Field_string::store(double nr)
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
end=strcend(buff,' ');
- return Field_string::store(buff,(uint) (end - buff), default_charset_info);
+ return Field_string::store(buff,(uint) (end - buff), my_charset_latin1);
}
int Field_string::store(longlong nr)
{
- char buff[22];
- char *end=longlong10_to_str(nr,buff,-10);
- return Field_string::store(buff,(uint) (end-buff), default_charset_info);
+ char buff[64];
+ int l;
+ CHARSET_INFO *cs=charset();
+ l=cs->ll10tostr(cs,buff,sizeof(buff),-10,nr);
+ return Field_string::store(buff,(uint)l,cs);
}
double Field_string::val_real(void)
{
- double value;
- char save=ptr[field_length]; // Ok to patch record
- ptr[field_length]=0;
- value=atof(ptr);
- ptr[field_length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr,field_length,(char**)0);
}
longlong Field_string::val_int(void)
{
longlong value;
- char save=ptr[field_length]; // Ok to patch record
- ptr[field_length]=0;
- value=strtoll(ptr,NULL,10);
- ptr[field_length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,ptr,field_length,NULL,10);
}
@@ -3930,12 +3937,12 @@ int Field_string::pack_cmp(const char *b, uint length)
}
-uint Field_string::packed_col_length(const char *ptr, uint length)
+uint Field_string::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
- return uint2korr(ptr)+2;
+ return uint2korr(data_ptr)+2;
else
- return (uint) ((uchar) *ptr)+1;
+ return (uint) ((uchar) *data_ptr)+1;
}
uint Field_string::max_packed_col_length(uint max_length)
@@ -3981,39 +3988,33 @@ int Field_varstring::store(double nr)
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
end=strcend(buff,' ');
- return Field_varstring::store(buff,(uint) (end - buff), default_charset_info);
+ return Field_varstring::store(buff,(uint) (end - buff), my_charset_latin1);
}
int Field_varstring::store(longlong nr)
{
- char buff[22];
- char *end=longlong10_to_str(nr,buff,-10);
- return Field_varstring::store(buff,(uint) (end-buff), default_charset_info);
+ char buff[64];
+ int l;
+ CHARSET_INFO *cs=charset();
+ l=cs->ll10tostr(cs,buff,sizeof(buff),-10,nr);
+ return Field_varstring::store(buff,(uint)l,cs);
}
double Field_varstring::val_real(void)
{
- double value;
uint length=uint2korr(ptr)+2;
- char save=ptr[length]; // Ok to patch record
- ptr[length]=0;
- value=atof(ptr+2);
- ptr[length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr+2,length,(char**)0);
}
longlong Field_varstring::val_int(void)
{
- longlong value;
uint length=uint2korr(ptr)+2;
- char save=ptr[length]; // Ok to patch record
- ptr[length]=0;
- value=strtoll(ptr+2,NULL,10);
- ptr[length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,ptr+2,length,NULL,10);
}
@@ -4162,12 +4163,12 @@ int Field_varstring::pack_cmp(const char *b, uint key_length)
(const uchar *)b,b_length);
}
-uint Field_varstring::packed_col_length(const char *ptr, uint length)
+uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
- return uint2korr(ptr)+2;
+ return uint2korr(data_ptr)+2;
else
- return (uint) ((uchar) *ptr)+1;
+ return (uint) ((uchar) *data_ptr)+1;
}
uint Field_varstring::max_packed_col_length(uint max_length)
@@ -4302,7 +4303,7 @@ int Field_blob::store(const char *from,uint len,CHARSET_INFO *cs)
}
}
#endif /* USE_TIS620 */
- value.copy(from,len);
+ value.copy(from,len,charset());
from=value.ptr();
#ifdef USE_TIS620
my_free(th_ptr,MYF(MY_ALLOW_ZERO_PTR));
@@ -4316,14 +4317,14 @@ int Field_blob::store(const char *from,uint len,CHARSET_INFO *cs)
int Field_blob::store(double nr)
{
- value.set(nr,2,my_thd_charset);
+ value.set(nr,2,current_thd->thd_charset);
return Field_blob::store(value.ptr(),(uint) value.length(), value.charset());
}
int Field_blob::store(longlong nr)
{
- value.set(nr,my_thd_charset);
+ value.set(nr,current_thd->thd_charset);
return Field_blob::store(value.ptr(), (uint) value.length(), value.charset());
}
@@ -4336,12 +4337,8 @@ double Field_blob::val_real(void)
if (!blob)
return 0.0;
uint32 length=get_length(ptr);
-
- char save=blob[length]; // Ok to patch blob in NISAM
- blob[length]=0;
- double nr=atof(blob);
- blob[length]=save;
- return nr;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,blob,length,(char**)0);
}
@@ -4352,12 +4349,8 @@ longlong Field_blob::val_int(void)
if (!blob)
return 0;
uint32 length=get_length(ptr);
-
- char save=blob[length]; // Ok to patch blob in NISAM
- blob[length]=0;
- longlong nr=strtoll(blob,NULL,10);
- blob[length]=save;
- return nr;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,blob,length,NULL,10);
}
@@ -4561,7 +4554,7 @@ void Field_blob::sql_type(String &res) const
case 3: str="medium"; break;
case 4: str="long"; break;
}
- res.set(str,(uint) strlen(str),default_charset_info);
+ res.set(str,(uint) strlen(str),my_charset_latin1);
res.append(binary() ? "blob" : "text");
if (!binary())
{
@@ -4698,12 +4691,12 @@ char *Field_blob::pack_key_from_key_image(char *to, const char *from,
return to+length;
}
-uint Field_blob::packed_col_length(const char *ptr, uint length)
+uint Field_blob::packed_col_length(const char *data_ptr, uint length)
{
if (length > 255)
- return uint2korr(ptr)+2;
+ return uint2korr(data_ptr)+2;
else
- return (uint) ((uchar) *ptr)+1;
+ return (uint) ((uchar) *data_ptr)+1;
}
uint Field_blob::max_packed_col_length(uint max_length)
@@ -4800,16 +4793,10 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
if (length < 6) // Can't be more than 99999 enums
{
/* This is for reading numbers with LOAD DATA INFILE */
- char buff[7], *end;
- const char *conv=from;
- if (from[length])
- {
- strmake(buff, from, length);
- conv=buff;
- }
+ char *end;
my_errno=0;
- tmp=(uint) strtoul(conv,&end,10);
- if (my_errno || end != conv+length || tmp > typelib->count)
+ tmp=(uint) my_strntoul(cs,from,length,&end,10);
+ if (my_errno || end != from+length || tmp > typelib->count)
{
tmp=0;
current_thd->cuted_fields++;
@@ -5004,16 +4991,10 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
if (!tmp && length && length < 22)
{
/* This is for reading numbers with LOAD DATA INFILE */
- char buff[22], *end;
- const char *conv=from;
- if (from[length])
- {
- strmake(buff, from, length);
- conv=buff;
- }
+ char *end;
my_errno=0;
- tmp=strtoull(conv,&end,10);
- if (my_errno || end != conv+length ||
+ tmp=my_strntoull(cs,from,length,&end,10);
+ if (my_errno || end != from+length ||
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
{
tmp=0;
@@ -5294,10 +5275,11 @@ Field *make_field(char *ptr, uint32 field_length,
return new Field_datetime(ptr,null_pos,null_bit,
unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NULL:
- default: // Impossible (Wrong version)
return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
+ default: // Impossible (Wrong version)
+ break;
}
- return 0; // Impossible (Wrong version)
+ return 0;
}
@@ -5336,7 +5318,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
orig_field)
{
char buff[MAX_FIELD_WIDTH],*pos;
- CHARSET_INFO *field_charset= charset ? charset : default_charset_info;
+ CHARSET_INFO *field_charset= charset;
String tmp(buff,sizeof(buff),field_charset);
/* Get the value from record[2] (the default value row) */
diff --git a/sql/field.h b/sql/field.h
index 6505b2c8462..c3f107ebb46 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -126,10 +126,12 @@ public:
Field *tmp= (Field*) memdup_root(root,(char*) this,size_of());
if (tmp)
{
- tmp->table=new_table;
- tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=0;
+ tmp->table= new_table;
+ tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0;
tmp->unireg_check=Field::NONE;
- tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | ENUM_FLAG | SET_FLAG);
+ tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
+ ZEROFILL_FLAG | ENUM_FLAG | SET_FLAG);
+ tmp->table_name= new_table->table_name;
tmp->reset_fields();
}
return tmp;
@@ -198,7 +200,8 @@ public:
uint fill_cache_field(struct st_cache_field *copy);
virtual bool get_date(TIME *ltime,bool fuzzydate);
virtual bool get_time(TIME *ltime);
- virtual CHARSET_INFO *charset(void) { return my_charset_bin; }
+ virtual CHARSET_INFO *charset(void) const { return my_charset_bin; }
+ virtual void set_charset(CHARSET_INFO *charset) { }
friend bool reopen_table(THD *,struct st_table *,bool);
friend int cre_myisam(my_string name, register TABLE *form, uint options,
ulonglong auto_increment_value);
@@ -260,9 +263,9 @@ public:
uint decimals() const { return NOT_FIXED_DEC; }
void make_field(Send_field *);
uint size_of() const { return sizeof(*this); }
- CHARSET_INFO *charset(void) { return field_charset; }
+ CHARSET_INFO *charset(void) const { return field_charset; }
- inline void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
+ void set_charset(CHARSET_INFO *charset) { field_charset=charset; }
bool binary() const { return field_charset->state & MY_CS_BINSORT ? 1 : 0; }
inline int cmp_image(char *buff,uint length)
{
@@ -886,7 +889,7 @@ public:
inline bool copy()
{ char *tmp;
get_ptr(&tmp);
- if (value.copy(tmp,get_length()))
+ if (value.copy(tmp,get_length(),charset()))
{
Field_blob::reset();
return 1;
@@ -1066,10 +1069,10 @@ Field *make_field(char *ptr, uint32 field_length,
uint pack_length_to_packflag(uint type);
uint32 calc_pack_length(enum_field_types type,uint32 length);
bool set_field_to_null(Field *field);
-bool set_field_to_null_with_conversions(Field *field);
+bool set_field_to_null_with_conversions(Field *field, bool no_conversions);
uint find_enum(TYPELIB *typelib,const char *x, uint length);
ulonglong find_set(TYPELIB *typelib,const char *x, uint length);
-bool test_if_int(const char *str,int length);
+bool test_if_int(const char *str,int length,CHARSET_INFO *cs);
/*
The following are for the interface with the .frm file
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index efb7401779c..0a8c122812c 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -122,8 +122,26 @@ set_field_to_null(Field *field)
}
+/*
+ Set field to NULL or TIMESTAMP or to next auto_increment number
+
+ SYNOPSIS
+ set_field_to_null_with_conversions()
+ field Field to update
+ no_conversion Set to 1 if we should return 1 if field can't
+ take null values.
+ If set to 0 we will do store the 'default value'
+ if the field is a special field. If not we will
+ give an error.
+
+ RETURN VALUES
+ 0 Field could take 0 or an automatic conversion was used
+ 1 Field could not take NULL and no conversion was used.
+ If no_conversion was not set, an error message is printed
+*/
+
bool
-set_field_to_null_with_conversions(Field *field)
+set_field_to_null_with_conversions(Field *field, bool no_conversions)
{
if (field->real_maybe_null())
{
@@ -131,6 +149,8 @@ set_field_to_null_with_conversions(Field *field)
field->reset();
return 0;
}
+ if (no_conversions)
+ return 1;
/*
Check if this is a special type, which will get a special walue
@@ -156,8 +176,6 @@ set_field_to_null_with_conversions(Field *field)
}
-
-
static void do_skip(Copy_field *copy __attribute__((unused)))
{
}
@@ -245,7 +263,8 @@ static void do_conv_blob(Copy_field *copy)
{
copy->from_field->val_str(&copy->tmp,&copy->tmp);
((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
- copy->tmp.length(),default_charset_info);
+ copy->tmp.length(),
+ copy->tmp.charset());
}
/* Save blob in copy->tmp for GROUP BY */
@@ -257,7 +276,8 @@ static void do_save_blob(Copy_field *copy)
copy->from_field->val_str(&res,&res);
copy->tmp.copy(res);
((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
- copy->tmp.length(),default_charset_info);
+ copy->tmp.length(),
+ copy->tmp.charset());
}
@@ -266,7 +286,7 @@ static void do_field_string(Copy_field *copy)
char buff[MAX_FIELD_WIDTH];
copy->tmp.set_quick(buff,sizeof(buff),default_charset_info);
copy->from_field->val_str(&copy->tmp,&copy->tmp);
- copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),default_charset_info);
+ copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),copy->tmp.charset());
}
@@ -525,8 +545,7 @@ void field_conv(Field *to,Field *from)
if (!blob->value.is_alloced() &&
from->real_type() != FIELD_TYPE_STRING)
blob->value.copy();
- blob->store(blob->value.ptr(),blob->value.length(),
- to->binary()?default_charset_info:((Field_str*)to)->charset());
+ blob->store(blob->value.ptr(),blob->value.length(),to->charset());
return;
}
if ((from->result_type() == STRING_RESULT &&
@@ -538,8 +557,7 @@ void field_conv(Field *to,Field *from)
char buff[MAX_FIELD_WIDTH];
String result(buff,sizeof(buff),default_charset_info);
from->val_str(&result,&result);
- to->store(result.c_ptr_quick(),result.length(),
- to->binary()?default_charset_info:((Field_str*)to)->charset());
+ to->store(result.c_ptr_quick(),result.length(),to->charset());
// QQ: what to do if "from" and "to" are of dirrent charsets?
}
else if (from->result_type() == REAL_RESULT)
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 13c48b745cd..97e06997617 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -23,6 +23,7 @@
#endif
#include <m_ctype.h>
#include "sql_sort.h"
+#include "assert.h"
#ifndef THREAD
#define SKIP_DBUG_IN_FILESORT
@@ -75,7 +76,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
uchar **sort_keys;
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
SORTPARAM param;
- CHARSET_INFO *charset=table->table_charset;
+ CHARSET_INFO *charset=my_charset_bin;
DBUG_ENTER("filesort");
DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length););
#ifdef SKIP_DBUG_IN_FILESORT
@@ -83,10 +84,9 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
#endif
// BAR TODO: this is not absolutely correct, but OK for now
- for(i=0;i<table->fields;i++)
+ for (i=0;i<table->fields;i++)
if (!table->field[i]->binary())
- charset=((Field_str*)(table->field[i]))->charset();
- charset=charset?charset:default_charset_info;
+ charset=table->field[i]->charset();
// /BAR TODO
outfile= table->io_cache;
@@ -224,7 +224,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (error)
my_error(ER_FILSORT_ABORT,MYF(ME_ERROR+ME_WAITTANG));
else
- statistic_add(filesort_rows, records, &LOCK_status);
+ statistic_add(filesort_rows, (ulong) records, &LOCK_status);
*examined_rows= param.examined_rows;
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP(); /* Ok to DBUG */
@@ -580,6 +580,10 @@ static void make_sortkey(register SORTPARAM *param,
change_double_for_sort(value,(byte*) to);
break;
}
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
}
if (sort_field->reverse)
@@ -725,7 +729,7 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
org_max_rows=max_rows=param->max_rows;
if (init_queue(&queue,(uint) (Tb-Fb)+1,offsetof(BUFFPEK,key),0,
- (int (*) (void *, byte *,byte*))
+ (queue_compare)
(cmp=get_ptr_compare(sort_length)),(void*) &sort_length))
DBUG_RETURN(1); /* purecov: inspected */
for (buffpek= Fb ; buffpek <= Tb ; buffpek++)
@@ -930,7 +934,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
#ifdef USE_STRCOLL
if (!sortorder->field->binary())
{
- CHARSET_INFO *cs=((Field_str*)(sortorder->field))->charset();
+ CHARSET_INFO *cs=sortorder->field->charset();
if (use_strnxfrm(cs))
sortorder->length= sortorder->length*cs->strxfrm_multiply;
}
@@ -966,6 +970,10 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
case REAL_RESULT:
sortorder->length=sizeof(double);
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
if (sortorder->item->maybe_null)
length++; // Place for NULL marker
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 4da5496c201..7daab228093 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -14,11 +14,68 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/*
+
+The idea of presented algorithm see in
+"The Art of Computer Programming" by Donald E. Knuth
+Volume 3 "Sorting and searching"
+(chapter 6.3 "Digital searching" - name and number of chapter
+ is back translation from Russian edition :))
+
+as illustration of data structures, imagine next table:
+
+static SYMBOL symbols[] = {
+ { "ADD", SYM(ADD),0,0},
+ { "AND", SYM(AND),0,0},
+ { "DAY", SYM(DAY_SYM),0,0},
+};
+
+for this structure, presented program generate next searching-structure:
+
++-----------+-+-+-+
+| len |1|2|3|
++-----------+-+-+-+
+|first_char |0|0|a|
+|last_char |0|0|d|
+|link |0|0|+|
+ |
+ V
+ +----------+-+-+-+--+
+ | 1 char|a|b|c|d |
+ +----------+-+-+-+--+
+ |first_char|b|0|0|0 |
+ |last_char |n|0|0|-1|
+ |link |+|0|0|+ |
+ | |
+ | V
+ | symbols[2] ( "DAY" )
+ V
++----------+--+-+-+-+-+-+-+-+-+-+--+
+| 2 char|d |e|f|j|h|i|j|k|l|m|n |
++----------+--+-+-+-+-+-+-+-+-+-+--+
+|first_char|0 |0|0|0|0|0|0|0|0|0|0 |
+|last_char |-1|0|0|0|0|0|0|0|0|0|-1|
+|link |+ |0|0|0|0|0|0|0|0|0|+ |
+ | |
+ V V
+ symbols[0] ( "ADD" ) symbols[1] ( "AND" )
+
+for optimization, link is the 16-bit index in 'symbols' or 'sql_functions'
+or search-array..
+
+So, we can read full search-structure as 32-bit word
+
+TODO:
+1. use instead to_upper_lex, special array
+ (substitute chars) without skip codes..
+2. try use reverse order of comparing..
+
+*/
#define NO_YACC_SYMBOLS
-#include <my_global.h>
-#include <my_sys.h>
-#include <m_string.h>
+#include "my_global.h"
+#include "my_sys.h"
+#include "m_string.h"
#ifndef __GNU_LIBRARY__
#define __GNU_LIBRARY__ // Skip warnings in getopt.h
#endif
@@ -26,324 +83,228 @@
#include "mysql_version.h"
#include "lex.h"
-my_bool opt_search;
-int opt_verbose;
-ulong opt_count;
-
-#define max_allowed_array 16000 // Don't generate bigger arrays than this
-#define max_symbol 32767 // Use this for 'not found'
-#define how_much_for_plus 8 // 2-8
-#define type_count 1 // 1-5
-#define char_table_count 5
-#define total_symbols (sizeof(symbols)/sizeof(SYMBOL) +\
- sizeof(sql_functions)/sizeof(SYMBOL))
-
-#define how_much_and INT_MAX24
-
-/*
- The following only have to work with characters in the set
- used by SQL commands
-*/
-
-#undef tolower
-#define tolower(a) ((a) >= 'A' && (a) <= 'Z') ? ((a)- 'A' + 'a') : (a)
-
-static uint how_long_symbols,function_plus,function_mod,function_type;
-static uint char_table[256];
-static uchar unique_length[256];
-static uchar bits[how_much_and/8+1];
-static uint primes[max_allowed_array+1];
-static ulong hash_results[type_count][how_much_for_plus+1][total_symbols];
-static ulong start_value=0;
-static uint best_type;
-static ulong best_t1,best_t2, best_start_value;
-
static struct my_option my_long_options[] =
{
{"help", '?', "Display help and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"count", 'c', "Try count times to find a optimal hash table",
- (gptr*) &opt_count, (gptr*) &opt_count, 0, GET_ULONG, REQUIRED_ARG,
- 100000, 0, 0, 0, 0, 0},
- {"search", 'S', "Search after good rnd1 and rnd2 values",
- (gptr*) &opt_search, (gptr*) &opt_search, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
- 0, 0},
- {"verbose", 'v', "Write some information while the program executes",
- (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, GET_INT, NO_ARG, 0, 0, 0,
- 0, 0, 0},
{"version", 'V', "Output version information and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
-struct rand_struct {
- unsigned long seed1,seed2,max_value;
- double max_value_dbl;
+struct hash_lex_struct
+{
+ char first_char;
+ char last_char;
+ union{
+ hash_lex_struct *char_tails;
+ int iresult;
+ };
+ int ithis;
};
-
-void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
-{ /* For mysql 3.21.# */
- rand_st->max_value= 0x3FFFFFFFL;
- rand_st->max_value_dbl=(double) rand_st->max_value;
- rand_st->seed1=seed1%rand_st->max_value ;
- rand_st->seed2=seed2%rand_st->max_value;
-}
-
-double rnd(struct rand_struct *rand_st)
+
+hash_lex_struct *get_hash_struct_by_len(hash_lex_struct **root_by_len,
+ int len, int *max_len)
{
- rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
- rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value;
- return (((double) rand_st->seed1)/rand_st->max_value_dbl);
+ if (*max_len<len){
+ *root_by_len= (hash_lex_struct *)realloc((char*)*root_by_len,
+ sizeof(hash_lex_struct)*len);
+ hash_lex_struct *cur, *end= *root_by_len + len;
+ for (cur= *root_by_len + *max_len; cur<end; cur++)
+ cur->first_char= 0;
+ *max_len= len;
+ }
+ return (*root_by_len)+(len-1);
}
-
-static void make_char_table(ulong t1,ulong t2,int type)
+void insert_into_hash(hash_lex_struct *root, const char *name,
+ int len_from_begin, int index, int function)
{
- uint i;
- struct rand_struct rand_st;
- randominit(&rand_st,t1,t2);
+ hash_lex_struct *end, *cur, *tails;
- for (i=0 ; i < 256 ; i++)
- {
- switch (type) {
- case 0: char_table[i]= i + (i << 8); break;
- case 1: char_table[i]= i + ((i ^255 ) << 8); break;
- case 2: char_table[i]= i; break;
- case 3: char_table[i]= i + ((uint) (rnd(&rand_st)*255) << 8); break;
- case 4: char_table[i]= (uint) (rnd(&rand_st)*255) + (i << 8); break;
- }
- }
- char_table[0]|=1+257; // Avoid problems with 0
- for (i=0 ; i < 256 ; i++)
- {
- uint tmp=(uint) (rnd(&rand_st)*255);
- swap(uint,char_table[i],char_table[tmp]);
- }
- /* lower characters should be mapped to upper */
- for (i= 'a' ; i <= 'z' ; i++)
- {
- /* This loop is coded with extra variables to avoid a bug in gcc 2.96 */
- uchar tmp= (uchar) (i - 'a'); // Assume ascii
- tmp+='A';
- char_table[i]=char_table[tmp];
+ if (!root->first_char){
+ root->first_char= -1;
+ root->iresult= index;
+ return;
}
-}
-/* Fill array primes with primes between start and 'max_allowed_array' */
-
-static void make_prime_array(uint start)
-{
- uint i,j,*to;
- uint max_index=(uint) sqrt((double) max_allowed_array);
+ if (root->first_char==-1){
+ int index2= root->iresult;
+ const char *name2=
+ (index2<0 ? sql_functions[-index2-1] : symbols[index2]).name + len_from_begin;
+ root->first_char= name2[0];
+ root->last_char= root->first_char;
+ tails= (hash_lex_struct*)malloc(sizeof(hash_lex_struct));
+ root->char_tails= tails;
+ tails->first_char= -1;
+ tails->iresult= index2;
+ }
- bzero((char*) primes,sizeof(primes[0])*max_allowed_array);
+ size_t real_size= (root->last_char-root->first_char+1);
+
+ if (root->first_char>(*name)){
+ size_t new_size= root->last_char-(*name)+1;
+ if (new_size<real_size) printf("error!!!!\n");
+ tails= root->char_tails;
+ tails= (hash_lex_struct*)realloc((char*)tails,
+ sizeof(hash_lex_struct)*new_size);
+ root->char_tails= tails;
+ memmove(tails+(new_size-real_size),tails,real_size*sizeof(hash_lex_struct));
+ end= tails + new_size - real_size;
+ for (cur= tails; cur<end; cur++)
+ cur->first_char= 0;
+ root->first_char= (*name);
+ }
- i=2;
- while (i < max_index)
- {
- for (j=i+i ; j <= max_allowed_array ; j+=i)
- primes[j]=1;
- while (primes[++i]) ;
+ if (root->last_char<(*name)){
+ size_t new_size= (*name)-root->first_char+1;
+ if (new_size<real_size) printf("error!!!!\n");
+ tails= root->char_tails;
+ tails= (hash_lex_struct*)realloc((char*)tails,
+ sizeof(hash_lex_struct)*new_size);
+ root->char_tails= tails;
+ end= tails + new_size;
+ for (cur= tails+real_size; cur<end; cur++)
+ cur->first_char= 0;
+ root->last_char= (*name);
}
- to=primes;
- for (i=start ; i <= max_allowed_array ; i++)
- if (!primes[i])
- *to++=i;
- *to=0; // end marker
+ insert_into_hash (root->char_tails+(*name)-root->first_char,
+ name+1,len_from_begin+1,index,function);
}
-#define USE_char_table
+hash_lex_struct *root_by_len= 0;
+int max_len=0;
-static ulong tab_index_function(const char *s,uint add, uint type)
+hash_lex_struct *root_by_len2= 0;
+int max_len2=0;
+
+void insert_symbols()
{
- register ulong nr=start_value+char_table[(uchar) *s]; // Nice value
- ulong pos=3;
- uint tmp_length=unique_length[(uchar) *s]-1;
- while (*++s && tmp_length-- > 0)
- {
- switch (type) {
- case 0:
- nr= (nr ^ (char_table[(uchar) *s] + (nr << add)));
- break;
- case 1:
- nr= (nr + (char_table[(uchar) *s] + (nr << add)));
- break;
- case 2:
- nr= (nr ^ (char_table[(uchar) *s] ^ (nr << add)));
- break;
- case 3:
- nr= (char_table[(uchar) *s] ^ (nr << add));
- break;
- case 4:
- nr+= nr+nr+((nr & 63)+pos)*((ulong) char_table[(uchar) *s]);
- pos+=add;
- break;
- }
+ size_t i= 0;
+ SYMBOL *cur;
+ for (cur= symbols; i<array_elements(symbols); cur++, i++){
+ hash_lex_struct *root=
+ get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
+ insert_into_hash(root,cur->name,0,i,0);
}
- return nr & INT_MAX24;
}
-static int search(bool write_warning)
+void insert_sql_functions()
{
- uint size_symbols = sizeof(symbols)/sizeof(SYMBOL);
- uint size_functions = sizeof(sql_functions)/sizeof(SYMBOL);
- uint size=size_symbols + size_functions;
- uint i=0,found,*prime,type;
- int igra[max_allowed_array],test_count=INT_MAX;
- uint possible_plus[how_much_for_plus*type_count+type_count];
+ size_t i= 0;
+ SYMBOL *cur;
+ for (cur= sql_functions; i<array_elements(sql_functions); cur++, i++){
+ hash_lex_struct *root=
+ get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
+ insert_into_hash(root,cur->name,0,-i-1,1);
+ }
+}
- how_long_symbols = sizeof(symbols)/sizeof(SYMBOL);
+void generate_find_structs()
+{
+ root_by_len= 0;
+ max_len=0;
+ size_t i;
+
+ SYMBOL *cur, *end= symbols + array_elements(symbols);
+ for (cur= symbols; cur < end; cur++)
+ cur->length=(uchar) strlen(cur->name);
+ end= sql_functions + array_elements(sql_functions);
+ for (cur= sql_functions; cur<end; cur++)
+ cur->length=(uchar) strlen(cur->name);
+
+ insert_symbols();
+
+ root_by_len2= root_by_len;
+ max_len2= max_len;
+
+ root_by_len= 0;
+ max_len= 0;
+
+ insert_symbols();
+ insert_sql_functions();
+}
- bzero((char*) possible_plus,sizeof(possible_plus));
- found=0;
+char *hash_map= 0;
+int size_hash_map= 0;
- /* Check first which function_plus are possible */
- for (type=0 ; type < type_count ; type ++)
+void add_struct_to_map(hash_lex_struct *st)
+{
+ st->ithis= size_hash_map/4;
+ size_hash_map+= 4;
+ hash_map= (char*)realloc((char*)hash_map,size_hash_map);
+ hash_map[size_hash_map-4]= st->first_char==-1 ? 0 : st->first_char;
+ hash_map[size_hash_map-3]=
+ st->first_char==-1 || st->first_char==0 ? 0 : st->last_char;
+ if (st->first_char==-1)
{
- for (function_plus = 1;
- function_plus <= how_much_for_plus;
- function_plus++)
- {
- bzero((char*) bits,sizeof(bits));
- for (i=0; i < size; i++)
- {
- ulong order= tab_index_function ((i < how_long_symbols) ?
- symbols[i].name :
- sql_functions[i-how_long_symbols].name,
- function_plus, type);
- hash_results[type][function_plus][i]=order;
- uint pos=order/8;
- uint bit=order & 7;
- if (bits[pos] & (1 << bit))
- break;
- bits[pos]|=1 << bit;
- }
- if (i == size)
- {
- possible_plus[found++]=function_plus;
- }
- }
- possible_plus[found++]=0; // End marker
+ hash_map[size_hash_map-2]= ((unsigned int)(int16)st->iresult)&255;
+ hash_map[size_hash_map-1]= ((unsigned int)(int16)st->iresult)>>8;
}
- if (found == type_count)
+ else if (st->first_char==0)
{
- if (write_warning)
- fprintf(stderr,"\
-The hash function didn't return a unique value for any parameter\n\
-You have to change gen_lex_code.cc, function 'tab_index_function' to\n\
-generate unique values for some parameter. When you have succeeded in this,\n\
-you have to change 'main' to print out the new function\n");
- return(1);
+ hash_map[size_hash_map-2]= ((unsigned int)(int16)array_elements(symbols))&255;
+ hash_map[size_hash_map-1]= ((unsigned int)(int16)array_elements(symbols))>>8;
}
+};
- if (opt_verbose > 1)
- fprintf (stderr,"Info: Possible add values: %d\n",found-type_count);
+void add_structs_to_map(hash_lex_struct *st, int len)
+{
+ hash_lex_struct *cur, *end= st+len;
+ for (cur= st; cur<end; cur++)
+ add_struct_to_map(cur);
+ for (cur= st; cur<end; cur++)
+ if (cur->first_char && cur->first_char!=-1)
+ add_structs_to_map(cur->char_tails,cur->last_char-cur->first_char+1);
+}
- for (prime=primes; (function_mod=*prime) ; prime++)
- {
- uint *plus_ptr=possible_plus;
- for (type=0 ; type < type_count ; type++ )
- {
- while ((function_plus= *plus_ptr++))
- {
- ulong *order_pos= &hash_results[type][function_plus][0];
- if (test_count++ == INT_MAX)
- {
- test_count=1;
- bzero((char*) igra,sizeof(igra));
- }
- for (i=0; i<size ;i++)
- {
- ulong order;
- order = *order_pos++ % function_mod;
- if (igra[order] == test_count)
- break;
- igra[order] = test_count;
- }
- if (i == size)
- {
- *prime=0; // Mark this used
- function_type=type;
- return 0; // Found ok value
- }
- }
+void set_links(hash_lex_struct *st, int len)
+{
+ hash_lex_struct *cur, *end= st+len;
+ for (cur= st; cur<end; cur++)
+ if (cur->first_char!=0 && cur->first_char!=-1){
+ int ilink= cur->char_tails->ithis;
+ hash_map[cur->ithis*4+2]= ilink%256;
+ hash_map[cur->ithis*4+3]= ilink/256;
+ set_links(cur->char_tails,cur->last_char-cur->first_char+1);
}
- }
-
- function_mod=max_allowed_array;
- if (write_warning)
- fprintf (stderr,"Fatal error when generating hash for symbols\n\
-Didn't find suitable values for perfect hashing:\n\
-You have to edit gen_lex_hash.cc to generate a new hashing function.\n\
-You can try running gen_lex_hash with --search to find a suitable value\n\
-Symbol array size = %d\n",function_mod);
- return -1;
}
-
-void print_arrays()
+void print_hash_map(const char *name)
{
- uint size_symbols = sizeof(symbols)/sizeof(SYMBOL);
- uint size_functions = sizeof(sql_functions)/sizeof(SYMBOL);
- uint size=size_symbols + size_functions;
- uint i;
-
- fprintf(stderr,"Symbols: %d Functions: %d; Total: %d\nShifts per char: %d, Array size: %d\n",
- size_symbols,size_functions,size_symbols+size_functions,
- function_plus,function_mod);
-
- int *prva= (int*) my_alloca(sizeof(int)*function_mod);
- for (i=0 ; i <= function_mod; i++)
- prva[i]= max_symbol;
-
- for (i=0;i<size;i++)
- {
- const char *name= ((i < how_long_symbols) ?
- symbols[i].name :
- sql_functions[i - how_long_symbols].name);
- ulong order = tab_index_function(name,function_plus,function_type);
- order %= function_mod;
- /* This should never be true */
- if (prva[order] != max_symbol)
- {
- fprintf(stderr,"Error: Got duplicate value for symbol '%s'\n",name);
- exit(1);
+ printf("uchar %s[%d]= {\n",name,size_hash_map);
+ char *cur;
+ int i;
+ for (i=0, cur= hash_map; i<size_hash_map; i++, cur++){
+ switch(i%4){
+ case 0: case 1:
+ if (!*cur)
+ printf("0, ");
+ else
+ printf("\'%c\', ",*cur);
+ break;
+ case 2: printf("%u, ",(uint)(uchar)*cur); break;
+ case 3: printf("%u,\n",(uint)(uchar)*cur); break;
}
- prva [order] = i;
}
+ printf("};\n");
+}
-#ifdef USE_char_table
- printf("static uint16 char_table[] = {\n");
- for (i=0; i < 255 ;i++) // < 255 is correct
- {
- printf("%u,",char_table[i]);
- if (((i+1) & 15) == 0)
- puts("");
- }
- printf("%d\n};\n\n\n",char_table[i]);
-#endif
+void print_find_structs()
+{
+ add_structs_to_map(root_by_len,max_len);
+ set_links(root_by_len,max_len);
+ print_hash_map("sql_functions_map");
- printf("static uchar unique_length[] = {\n");
- for (i=0; i < 255 ;i++) // < 255 is correct
- {
- printf("%u,",unique_length[i]);
- if (((i+1) & 15) == 0)
- puts("");
- }
- printf("%d\n};\n\n\n",unique_length[i]);
+ hash_map= 0;
+ size_hash_map= 0;
- printf("static uint16 my_function_table[] = {\n");
- for (i=0; i < function_mod-1 ;i++)
- {
- printf("%d,",prva[i]);
- if (((i+1) % 12) == 0)
- puts("");
- }
- printf("%d\n};\n\n\n",prva[i]);
- my_afree((gptr) prva);
-}
+ printf("\n");
+ add_structs_to_map(root_by_len2,max_len2);
+ set_links(root_by_len2,max_len2);
+ print_hash_map("symbols_map");
+}
static void usage(int version)
{
@@ -351,23 +312,19 @@ static void usage(int version)
my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
if (version)
return;
- puts("Copyright (C) 2001 MySQL AB, by Sinisa and Monty");
- puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
+ puts("Copyright (C) 2001 MySQL AB, by VVA and Monty");
+ puts("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");
puts("This program generates a perfect hashing function for the sql_lex.cc");
printf("Usage: %s [OPTIONS]\n\n", my_progname);
my_print_help(my_long_options);
- my_print_variables(my_long_options);
}
-
-static my_bool
+extern "C" my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument __attribute__((unused)))
{
- switch (optid) {
- case 'v':
- opt_verbose++;
- break;
+ switch(optid) {
case 'V':
usage(1);
exit(0);
@@ -379,7 +336,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
return 0;
}
-
static int get_options(int argc, char **argv)
{
int ho_error;
@@ -389,139 +345,19 @@ static int get_options(int argc, char **argv)
if (argc >= 1)
{
- fprintf(stderr,"%s: Too many arguments\n", my_progname);
usage(0);
- exit(1);
+ exit(1);
}
return(0);
}
-static uint max_prefix(const char *name)
-{
- uint i;
- uint max_length=1;
- for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++)
- {
- const char *str=symbols[i].name;
- if (str != name)
- {
- const char *str2=name;
- uint length;
- while (*str && *str == *str2)
- {
- str++;
- str2++;
- }
- length=(uint) (str2 - name)+1;
- if (length > max_length)
- max_length=length;
- }
- }
- for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++)
- {
- const char *str=sql_functions[i].name;
- if (str != name)
- {
- const char *str2=name;
- uint length;
- while (*str && *str == *str2)
- {
- str++;
- str2++;
- }
- length=(uint) (str2 - name)+1;
- if (length > max_length)
- max_length=length;
- }
- }
- return max_length;
-}
-
-
-static void make_max_length_table(void)
-{
- uint i;
- for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++)
- {
- uint length=max_prefix(symbols[i].name);
- if (length > unique_length[(uchar) symbols[i].name[0]])
- {
- unique_length[(uchar) symbols[i].name[0]]=length;
- unique_length[(uchar) tolower(symbols[i].name[0])]=length;
- }
- }
- for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++)
- {
- uint length=max_prefix(sql_functions[i].name);
- if (length > unique_length[(uchar) sql_functions[i].name[0]])
- {
- unique_length[(uchar) sql_functions[i].name[0]]=length;
- unique_length[(uchar) tolower(sql_functions[i].name[0])]=length;
- }
- }
-}
-
-
int main(int argc,char **argv)
{
- struct rand_struct rand_st;
- static uint best_mod,best_add,best_functype;
- int error;
-
MY_INIT(argv[0]);
- start_value=2925024L; best_t1=654916L; best_t2=1723390L; best_type=3; /* mode=4943 add=1 type: 0 */
+
if (get_options(argc,(char **) argv))
exit(1);
- make_max_length_table();
- make_char_table(best_t1,best_t2,best_type);
- make_prime_array(sizeof(symbols)/sizeof(SYMBOL) +
- sizeof(sql_functions)/sizeof(SYMBOL));
-
- if ((error=search(1)) > 0 || error && !opt_search)
- exit(1); // This should work
- best_mod=function_mod; best_add=function_plus; best_functype=function_type;
-
- if (opt_search)
- {
- time_t start_time=time((time_t*) 0);
- randominit(&rand_st,start_time,start_time/2); // Some random values
- printf("start_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n",
- start_value, best_t1,best_t2,best_type,best_mod,best_add,
- best_functype);
- best_start_value=start_value;
- for (uint i=1 ; i <= opt_count ; i++)
- {
- if (i % 10 == 0)
- {
- putchar('.');
- fflush(stdout);
- }
- ulong t1=(ulong) (rnd(&rand_st)*INT_MAX24);
- ulong t2=(ulong) (rnd(&rand_st)*INT_MAX24);
- uint type=(int) (rnd(&rand_st)*char_table_count);
- start_value=(ulong) (rnd(&rand_st)*INT_MAX24);
- make_char_table(t1,t2,type);
- if (!search(0))
- {
- best_mod=function_mod; best_add=function_plus;
- best_functype=function_type;
- best_t1=t1; best_t2=t2; best_type=type;
- best_start_value=start_value;
- printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n",
- best_start_value,best_t1,best_t2,best_type,best_mod,best_add,
- best_functype);
- }
- if (opt_verbose && (i % 20000) == 0)
- printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n",
- best_start_value,best_t1,best_t2,best_type,best_mod,best_add,
- best_functype);
- }
- }
-
- function_mod=best_mod; function_plus=best_add;
- make_char_table(best_t1,best_t2,best_type);
-
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\
@@ -533,38 +369,84 @@ int main(int argc,char **argv)
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");
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\
+ USA */\n\n");
-printf("/* This code is generated by gen_lex_hash.cc that seeks for a perfect\nhash function */\n\n");
+ printf("/* This code is generated by gen_lex_hash.cc that seeks for\
+ a perfect\nhash function */\n\n");
printf("#include \"lex.h\"\n\n");
- print_arrays();
+ generate_find_structs();
+ print_find_structs();
- printf("/* start_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; */ /* mode=%d add=%d type: %d */\n\n",
- best_start_value, best_t1, best_t2, best_type,
- best_mod, best_add, best_functype);
+ printf("\nunsigned int sql_functions_max_len=%d;\n",max_len);
+ printf("\nunsigned int symbols_max_len=%d;\n\n",max_len2);
- printf("inline SYMBOL *get_hash_symbol(const char *s,unsigned int length,bool function)\n\
+ printf
+(
+"inline SYMBOL *get_hash_symbol(const char *s,\n\
+ unsigned int len,bool function)\n\
{\n\
- ulong idx = %lu+char_table[(uchar) *s];\n\
- SYMBOL *sim;\n\
- const char *start=s;\n\
- int i=unique_length[(uchar) *s++];\n\
- if (i > (int) length) i=(int) length;\n\
- while (--i > 0)\n\
- idx= (idx ^ (char_table[(uchar) *s++] + (idx << %d)));\n\
- idx=my_function_table[(idx & %d) %% %d];\n\
- if (idx >= %d)\n\
- {\n\
- if (!function || idx >= %d) return (SYMBOL*) 0;\n\
- sim=sql_functions + (idx - %d);\n\
+ register uchar *hash_map;\n\
+ register const char *cur_str= s;\n\
+ if (function){\n\
+ if (len>sql_functions_max_len) return 0;\n\
+ hash_map= sql_functions_map;\n\
+ register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\
+\n\
+ for(;;){\n\
+ register uchar first_char= (uchar)cur_struct;\n\
+\n\
+ if (first_char==0){\n\
+ register int16 ires= (int16)(cur_struct>>16);\n\
+ if (ires==array_elements(symbols)) return 0;\n\
+ register SYMBOL *res;\n\
+ if (ires>=0) \n\
+ res= symbols+ires;\n\
+ else\n\
+ res= sql_functions-ires-1;\n\
+ register uint count= cur_str-s;\n\
+ return lex_casecmp(cur_str,res->name+count,len-count) ? 0 : res;\n\
+ }\n\
+\n\
+ register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\
+ if (cur_char<first_char) return 0;\n\
+ cur_struct>>=8;\n\
+ if (cur_char>(uchar)cur_struct) return 0;\n\
+\n\
+ cur_struct>>=8;\n\
+ cur_struct= uint4korr(hash_map+\n\
+ (((uint16)cur_struct + cur_char - first_char)*4));\n\
+ cur_str++;\n\
+ }\n\
+ }else{\n\
+ if (len>symbols_max_len) return 0;\n\
+ hash_map= symbols_map;\n\
+ register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\
+\n\
+ for(;;){\n\
+ register uchar first_char= (uchar)cur_struct;\n\
+\n\
+ if (first_char==0){\n\
+ register int16 ires= (int16)(cur_struct>>16);\n\
+ if (ires==array_elements(symbols)) return 0;\n\
+ register SYMBOL *res= symbols+ires;\n\
+ register uint count= cur_str-s;\n\
+ return lex_casecmp(cur_str,res->name+count,len-count)!=0 ? 0 : res;\n\
+ }\n\
+\n\
+ register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\
+ if (cur_char<first_char) return 0;\n\
+ cur_struct>>=8;\n\
+ if (cur_char>(uchar)cur_struct) return 0;\n\
+\n\
+ cur_struct>>=8;\n\
+ cur_struct= uint4korr(hash_map+\n\
+ (((uint16)cur_struct + cur_char - first_char)*4));\n\
+ cur_str++;\n\
+ }\n\
}\n\
- else\n\
- sim=symbols + idx;\n\
- if ((length != sim->length) || lex_casecmp(start,sim->name,length))\n\
- return (SYMBOL *)0;\n\
- return sim;\n\
-}\n",(ulong) start_value,(int) function_plus,(int) how_much_and,function_mod,how_long_symbols,max_symbol,how_long_symbols);
- exit(0);
- return 0;
+}\n"
+);
}
+
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 6d5b469a913..8edb63b23d6 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -1416,10 +1416,21 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
DBT row;
int error;
KEY *key_info= &table->key_info[active_index];
+ int do_prev= 0;
DBUG_ENTER("ha_berkeley::index_read");
statistic_increment(ha_read_key_count,&LOCK_status);
bzero((char*) &row,sizeof(row));
+ if (find_flag == HA_READ_BEFORE_KEY)
+ {
+ find_flag= HA_READ_KEY_OR_NEXT;
+ do_prev= 1;
+ }
+ else if (find_flag == HA_READ_PREFIX_LAST_OR_PREV)
+ {
+ find_flag= HA_READ_AFTER_KEY;
+ do_prev= 1;
+ }
if (key_len == key_info->key_length)
{
error=read_row(cursor->c_get(cursor, pack_key(&last_key,
@@ -1453,6 +1464,12 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
error=HA_ERR_KEY_NOT_FOUND;
}
}
+ if (do_prev)
+ {
+ bzero((char*) &row, sizeof(row));
+ error= read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
+ (char*) buf, active_index, &row, &last_key, 1);
+ }
DBUG_RETURN(error);
}
@@ -1931,7 +1948,7 @@ int ha_berkeley::delete_table(const char *name)
double ha_berkeley::scan_time()
{
- return records/3;
+ return rows2double(records/3);
}
ha_rows ha_berkeley::records_in_range(int keynr,
@@ -2206,7 +2223,7 @@ static BDB_SHARE *get_share(const char *table_name, TABLE *table)
if (!(share=(BDB_SHARE*) hash_search(&bdb_open_tables, (byte*) table_name,
length)))
{
- ha_rows *rec_per_key;
+ ulong *rec_per_key;
char *tmp_name;
DB **key_file;
u_int32_t *key_type;
diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h
index 06776240751..351c7a96e7d 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -27,7 +27,8 @@
typedef struct st_berkeley_share {
ulonglong auto_ident;
- ha_rows rows, org_rows, *rec_per_key;
+ ha_rows rows, org_rows;
+ ulong *rec_per_key;
THR_LOCK lock;
pthread_mutex_t mutex;
char *table_name;
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 6cfd3c881cc..fb4061b31e0 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -81,6 +81,15 @@ int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
return error;
}
+int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
+{
+ statistic_increment(ha_read_key_count, &LOCK_status);
+ int error= heap_rkey(file, buf, active_index, key, key_len,
+ HA_READ_PREFIX_LAST);
+ table->status= error ? STATUS_NOT_FOUND : 0;
+ return error;
+}
+
int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
@@ -90,7 +99,6 @@ int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
return error;
}
-
int ha_heap::index_next(byte * buf)
{
statistic_increment(ha_read_next_count,&LOCK_status);
@@ -245,7 +253,7 @@ int ha_heap::create(const char *name, TABLE *table,
{
uint key, parts, mem_per_row= 0;
uint auto_key= 0, auto_key_type= 0;
- ulong max_rows;
+ ha_rows max_rows;
HP_KEYDEF *keydef;
HA_KEYSEG *seg;
char buff[FN_REFLEN];
@@ -291,7 +299,7 @@ int ha_heap::create(const char *name, TABLE *table,
seg->start= (uint) key_part->offset;
seg->length= (uint) key_part->length;
seg->flag = 0;
- seg->charset= field->binary() ? NULL : ((Field_str*)field)->charset();
+ seg->charset= field->charset();
if (field->null_ptr)
{
seg->null_bit= field->null_bit;
@@ -310,8 +318,8 @@ int ha_heap::create(const char *name, TABLE *table,
}
}
mem_per_row+= MY_ALIGN(table->reclength + 1, sizeof(char*));
- max_rows = (ulong) (current_thd->variables.max_heap_table_size /
- mem_per_row);
+ max_rows = (ha_rows) (current_thd->variables.max_heap_table_size /
+ mem_per_row);
HP_CREATE_INFO hp_create_info;
hp_create_info.auto_key= auto_key;
hp_create_info.auto_key_type= auto_key_type;
@@ -319,9 +327,9 @@ int ha_heap::create(const char *name, TABLE *table,
create_info->auto_increment_value - 1 : 0);
error= heap_create(fn_format(buff,name,"","",4+2),
table->keys,keydef, table->reclength,
- ((table->max_rows < max_rows && table->max_rows) ?
- table->max_rows : max_rows),
- table->min_rows, &hp_create_info);
+ (ulong) ((table->max_rows < max_rows && table->max_rows) ?
+ table->max_rows : max_rows),
+ (ulong) table->min_rows, &hp_create_info);
my_free((gptr) keydef, MYF(0));
if (file)
info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index f82a1a460d8..fe874dab3f2 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -67,6 +67,7 @@ class ha_heap: public handler
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index c624cee2954..0b84f0010c1 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -40,17 +40,12 @@ InnoDB */
#include "ha_innodb.h"
-/* We must declare this here because we undef SAFE_MUTEX below */
pthread_mutex_t innobase_mutex;
/* Store MySQL definition of 'byte': in Linux it is char while InnoDB
uses unsigned char */
typedef byte mysql_byte;
-#ifdef SAFE_MUTEX
-#undef pthread_mutex_t
-#endif
-
#define INSIDE_HA_INNOBASE_CC
/* Include necessary InnoDB headers */
@@ -95,8 +90,11 @@ long innobase_mirrored_log_groups, innobase_log_files_in_group,
are determined in innobase_init below: */
char* innobase_data_home_dir = NULL;
+char* innobase_data_file_path = NULL;
char* innobase_log_group_home_dir = NULL;
char* innobase_log_arch_dir = NULL;
+/* The following has a misleading name: starting from 4.0.5, this also
+affects Windows: */
char* innobase_unix_file_flush_method = NULL;
/* Below we have boolean-valued start-up parameters, and their default
@@ -107,14 +105,7 @@ my_bool innobase_log_archive = FALSE;
my_bool innobase_use_native_aio = FALSE;
my_bool innobase_fast_shutdown = TRUE;
-/*
- Set default InnoDB data file size to 10 MB and let it be
- auto-extending. Thus users can use InnoDB without having to
- specify any startup options.
-*/
-
-char *innobase_data_file_path= (char*) "ibdata1:10M:autoextend";
-static char *internal_innobase_data_file_path=0;
+static char *internal_innobase_data_file_path = NULL;
/* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call
@@ -253,6 +244,10 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_TOO_BIG_RECORD) {
return(HA_ERR_TO_BIG_ROW);
+
+ } else if (error == (int) DB_CORRUPTION) {
+
+ return(HA_ERR_CRASHED);
} else {
return(-1); // Unknown error
}
@@ -346,7 +341,8 @@ check_trx_exists(
trx = trx_allocate_for_mysql();
trx->mysql_thd = thd;
-
+ trx->mysql_query_str = &((*thd).query);
+
thd->transaction.all.innobase_tid = trx;
/* The execution of a single SQL statement is denoted by
@@ -648,46 +644,59 @@ innobase_init(void)
DBUG_ENTER("innobase_init");
- os_innodb_umask = (ulint)my_umask;
+ os_innodb_umask = (ulint)my_umask;
- /*
- When using the embedded server, the datadirectory is not
- in the current directory.
- */
- if (mysql_embedded)
- default_path=mysql_real_data_home;
- else
- {
- /* It's better to use current lib, to keep path's short */
- current_dir[0] = FN_CURLIB;
- current_dir[1] = FN_LIBCHAR;
- current_dir[2] = 0;
- default_path=current_dir;
+ /* First calculate the default path for innodb_data_home_dir etc.,
+ in case the user has not given any value.
+
+ Note that when using the embedded server, the datadirectory is not
+ necessarily the current directory of this program. */
+
+ if (mysql_embedded) {
+ default_path = mysql_real_data_home;
+ } else {
+ /* It's better to use current lib, to keep paths short */
+ current_dir[0] = FN_CURLIB;
+ current_dir[1] = FN_LIBCHAR;
+ current_dir[2] = 0;
+ default_path = current_dir;
}
+ ut_a(default_path);
+
if (specialflag & SPECIAL_NO_PRIOR) {
srv_set_thread_priorities = FALSE;
} else {
srv_set_thread_priorities = TRUE;
srv_query_thread_priority = QUERY_PRIOR;
}
+
+ /* Set InnoDB initialization parameters according to the values
+ read from MySQL .cnf file */
- /*
- Set InnoDB initialization parameters according to the values
- read from MySQL .cnf file
- */
+ /*--------------- Data files -------------------------*/
- // Make a copy of innobase_data_file_path to not modify the original
- internal_innobase_data_file_path=my_strdup(innobase_data_file_path,
- MYF(MY_WME));
+ /* The default dir for data files is the datadir of MySQL */
srv_data_home = (innobase_data_home_dir ? innobase_data_home_dir :
default_path);
- srv_arch_dir = (innobase_log_arch_dir ? innobase_log_arch_dir :
- default_path);
- ret = (bool)
- srv_parse_data_file_paths_and_sizes(internal_innobase_data_file_path,
+ /* Set default InnoDB data file size to 10 MB and let it be
+ auto-extending. Thus users can use InnoDB in >= 4.0 without having
+ to specify any startup options. */
+
+ if (!innobase_data_file_path) {
+ innobase_data_file_path = (char*) "ibdata1:10M:autoextend";
+ }
+
+ /* Since InnoDB edits the argument in the next call, we make another
+ copy of it: */
+
+ internal_innobase_data_file_path = my_strdup(innobase_data_file_path,
+ MYF(MY_WME));
+
+ ret = (bool) srv_parse_data_file_paths_and_sizes(
+ internal_innobase_data_file_path,
&srv_data_file_names,
&srv_data_file_sizes,
&srv_data_file_is_raw_partition,
@@ -695,12 +704,26 @@ innobase_init(void)
&srv_auto_extend_last_data_file,
&srv_last_file_size_max);
if (ret == FALSE) {
- sql_print_error("InnoDB: syntax error in innodb_data_file_path");
- DBUG_RETURN(TRUE);
+ sql_print_error(
+ "InnoDB: syntax error in innodb_data_file_path");
+ DBUG_RETURN(TRUE);
}
- if (!innobase_log_group_home_dir)
- innobase_log_group_home_dir= default_path;
+ /* -------------- Log files ---------------------------*/
+
+ /* The default dir for log files is the datadir of MySQL */
+
+ if (!innobase_log_group_home_dir) {
+ innobase_log_group_home_dir = default_path;
+ }
+
+ /* Since innodb_log_arch_dir has no relevance under MySQL,
+ starting from 4.0.6 we always set it the same as
+ innodb_log_group_home_dir: */
+
+ innobase_log_arch_dir = innobase_log_group_home_dir;
+
+ srv_arch_dir = innobase_log_arch_dir;
ret = (bool)
srv_parse_log_group_home_dirs(innobase_log_group_home_dir,
@@ -713,9 +736,10 @@ innobase_init(void)
DBUG_RETURN(TRUE);
}
- srv_unix_file_flush_method_str = (innobase_unix_file_flush_method ?
- innobase_unix_file_flush_method :
- (char*)"fdatasync");
+
+ /* --------------------------------------------------*/
+
+ srv_file_flush_method_str = innobase_unix_file_flush_method;
srv_n_log_groups = (ulint) innobase_mirrored_log_groups;
srv_n_log_files = (ulint) innobase_log_files_in_group;
@@ -725,8 +749,6 @@ innobase_init(void)
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
srv_flush_log_at_trx_commit = (ulint) innobase_flush_log_at_trx_commit;
- srv_use_native_aio = 0;
-
srv_pool_size = (ulint) innobase_buffer_pool_size;
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
@@ -740,7 +762,9 @@ innobase_init(void)
srv_fast_shutdown = (ibool) innobase_fast_shutdown;
srv_print_verbose_log = mysql_embedded ? 0 : 1;
+
if (strcmp(default_charset_info->name, "latin1") == 0) {
+
/* Store the character ordering table to InnoDB.
For non-latin1 charsets we use the MySQL comparison
functions, and consequently we do not need to know
@@ -750,6 +774,14 @@ innobase_init(void)
default_charset_info->sort_order, 256);
}
+ /* Since we in this module access directly the fields of a trx
+ struct, and due to different headers and flags it might happen that
+ mutex_t has a different size in this module and in InnoDB
+ modules, we check at run time that the size is the same in
+ these compilation modules. */
+
+ srv_sizeof_trx_t_in_ha_innodb_cc = sizeof(trx_t);
+
err = innobase_start_or_create_for_mysql();
if (err != DB_SUCCESS) {
@@ -1147,15 +1179,15 @@ ha_innobase::open(
ib_table = dict_table_get_and_increment_handle_count(
norm_name, NULL);
if (NULL == ib_table) {
-
- sql_print_error("InnoDB error:\n\
-Cannot find table %s from the internal data dictionary\n\
-of InnoDB though the .frm file for the table exists. Maybe you\n\
-have deleted and recreated InnoDB data files but have forgotten\n\
-to delete the corresponding .frm files of InnoDB tables, or you\n\
-have moved .frm files to another database?\n\
-Look from section 15.1 of http://www.innodb.com/ibman.html\n\
-how you can resolve the problem.\n",
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB error:\n"
+"Cannot find table %s from the internal data dictionary\n"
+"of InnoDB though the .frm file for the table exists. Maybe you\n"
+"have deleted and recreated InnoDB data files but have forgotten\n"
+"to delete the corresponding .frm files of InnoDB tables, or you\n"
+"have moved .frm files to another database?\n"
+"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
+"how you can resolve the problem.\n",
norm_name);
free_share(share);
@@ -1168,7 +1200,10 @@ how you can resolve the problem.\n",
((row_prebuilt_t*)innobase_prebuilt)->mysql_row_len = table->reclength;
- primary_key = MAX_KEY;
+ /* Looks like MySQL-3.23 sometimes has primary key number != 0 */
+
+ primary_key = table->primary_key;
+ key_used_on_scan = primary_key;
/* Allocate a buffer for a 'row reference'. A row reference is
a string of bytes of length ref_length which uniquely specifies
@@ -1177,13 +1212,14 @@ how you can resolve the problem.\n",
of length ref_length! */
if (!row_table_got_default_clust_index(ib_table)) {
+ if (primary_key >= MAX_KEY) {
+ fprintf(stderr,
+ "InnoDB: Error: table %s has a primary key in InnoDB\n"
+ "InnoDB: data dictionary, but not in MySQL!\n", name);
+ }
((row_prebuilt_t*)innobase_prebuilt)
->clust_index_was_generated = FALSE;
-
- primary_key = 0;
- key_used_on_scan = 0;
-
/*
MySQL allocates the buffer for ref. key_info->key_length
includes space for all key columns + one byte for each column
@@ -1192,8 +1228,14 @@ how you can resolve the problem.\n",
based on ref_length.
*/
- ref_length = table->key_info->key_length;
+ ref_length = table->key_info[primary_key].key_length;
} else {
+ if (primary_key != MAX_KEY) {
+ fprintf(stderr,
+ "InnoDB: Error: table %s has no primary key in InnoDB\n"
+ "InnoDB: data dictionary, but has one in MySQL!\n", name);
+ }
+
((row_prebuilt_t*)innobase_prebuilt)
->clust_index_was_generated = TRUE;
@@ -1501,7 +1543,8 @@ ha_innobase::store_key_val_for_row(
are equal
*/
bzero(buff, (ref_length- (uint) (buff - buff_start)));
- DBUG_RETURN(ref_length);
+
+ DBUG_RETURN((uint)(buff - buff_start));
}
/******************************************************************
@@ -1679,6 +1722,7 @@ ha_innobase::write_row(
longlong dummy;
ibool incremented_auto_inc_for_stat = FALSE;
ibool incremented_auto_inc_counter = FALSE;
+ ibool skip_auto_inc_decr;
DBUG_ENTER("ha_innobase::write_row");
@@ -1843,13 +1887,31 @@ ha_innobase::write_row(
if (error != DB_SUCCESS) {
/* If the insert did not succeed we restore the value of
the auto-inc counter we used; note that this behavior was
- introduced only in version 4.0.4 */
+ introduced only in version 4.0.4.
+ NOTE that a REPLACE command handles a duplicate key error
+ itself, and we must not decrement the autoinc counter
+ if we are performing a REPLACE statement.
+ NOTE 2: if there was an error, for example a deadlock,
+ which caused InnoDB to roll back the whole transaction
+ already in the call of row_insert_for_mysql(), we may no
+ longer have the AUTO-INC lock, and cannot decrement
+ the counter here. */
+
+ skip_auto_inc_decr = FALSE;
+
+ if (error == DB_DUPLICATE_KEY) {
+ ut_a(user_thd->query);
+ dict_accept(user_thd->query, "REPLACE",
+ &skip_auto_inc_decr);
+ }
- if (incremented_auto_inc_counter) {
+ if (!skip_auto_inc_decr && incremented_auto_inc_counter
+ && prebuilt->trx->auto_inc_lock) {
dict_table_autoinc_decrement(prebuilt->table);
}
- if (incremented_auto_inc_for_stat) {
+ if (!skip_auto_inc_decr && incremented_auto_inc_for_stat
+ && prebuilt->trx->auto_inc_lock) {
auto_inc_counter_for_this_stat--;
}
}
@@ -2181,8 +2243,16 @@ convert_search_mode_to_innobase(
case HA_READ_AFTER_KEY: return(PAGE_CUR_G);
case HA_READ_BEFORE_KEY: return(PAGE_CUR_L);
case HA_READ_PREFIX: return(PAGE_CUR_GE);
- case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE);
- /* HA_READ_PREFIX_LAST does not yet work in InnoDB! */
+ case HA_READ_PREFIX_LAST:
+ /* ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Warning: Using HA_READ_PREFIX_LAST\n"); */
+ return(PAGE_CUR_LE);
+
+ /* InnoDB does not yet support ..PREFIX_LAST!
+ We have to add a new search flag
+ PAGE_CUR_LE_OR_PREFIX to InnoDB. */
+
/* the above PREFIX flags mean that the last
field in the key value may just be a prefix
of the complete fixed length field */
@@ -2751,7 +2821,11 @@ ha_innobase::position(
that len is always fixed for this table. The following assertion
checks this. */
- ut_a(len == ref_length);
+ if (len != ref_length) {
+ fprintf(stderr,
+ "InnoDB: Error: stored ref len is %lu, but table ref len is %lu\n",
+ (ulint)len, (ulint)ref_length);
+ }
}
@@ -2935,16 +3009,21 @@ ha_innobase::create(
trx->check_unique_secondary = FALSE;
}
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
fn_format(name2, name, "", "",2); // Remove the .frm extension
normalize_table_name(norm_name, name2);
- /* Latch the InnoDB data dictionary exclusive so that no deadlocks
+ /* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during a table create operation.
- (Drop table etc. do this latching in row0mysql.c.) */
+ Drop table etc. do this latching in row0mysql.c. */
- row_mysql_lock_data_dictionary();
+ row_mysql_lock_data_dictionary(trx);
/* Create the table definition in InnoDB */
@@ -2953,7 +3032,7 @@ ha_innobase::create(
if (error) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -2983,7 +3062,7 @@ ha_innobase::create(
if (error) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -2998,7 +3077,7 @@ ha_innobase::create(
(uint) primary_key_no))) {
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3014,7 +3093,7 @@ ha_innobase::create(
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3023,24 +3102,27 @@ ha_innobase::create(
}
}
- error = row_table_add_foreign_constraints(trx,
- create_info->create_statement, norm_name);
+ if (current_thd->query != NULL) {
+
+ error = row_table_add_foreign_constraints(trx,
+ current_thd->query, norm_name);
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, NULL);
- if (error) {
- innobase_commit_low(trx);
+ if (error) {
+ innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
- trx_free_for_mysql(trx);
+ trx_free_for_mysql(trx);
- DBUG_RETURN(error);
+ DBUG_RETURN(error);
+ }
}
innobase_commit_low(trx);
- row_mysql_unlock_data_dictionary();
+ row_mysql_unlock_data_dictionary(trx);
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
@@ -3082,6 +3164,12 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table");
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
+
trx = trx_allocate_for_mysql();
name_len = strlen(name);
@@ -3095,7 +3183,7 @@ ha_innobase::delete_table(
/* Drop the table in InnoDB */
- error = row_drop_table_for_mysql(norm_name, trx, FALSE);
+ error = row_drop_table_for_mysql(norm_name, trx);
/* Flush the log to reduce probability that the .frm files and
the InnoDB data dictionary get out-of-sync if the user runs
@@ -3192,6 +3280,12 @@ ha_innobase::rename_table(
DBUG_ENTER("ha_innobase::rename_table");
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
+
trx = trx_allocate_for_mysql();
name_len1 = strlen(from);
@@ -3318,7 +3412,7 @@ ha_innobase::estimate_number_of_rows(void)
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
dict_index_t* index;
ulonglong estimate;
- ulonglong data_file_length;
+ ulonglong local_data_file_length;
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
@@ -3328,7 +3422,7 @@ ha_innobase::estimate_number_of_rows(void)
index = dict_table_get_first_index_noninline(prebuilt->table);
- data_file_length = ((ulonglong) index->stat_n_leaf_pages)
+ local_data_file_length = ((ulonglong) index->stat_n_leaf_pages)
* UNIV_PAGE_SIZE;
/* Calculate a minimum length for a clustered index record and from
@@ -3337,7 +3431,7 @@ ha_innobase::estimate_number_of_rows(void)
by a threshold factor, we must add a safety factor 2 in front
of the formula below. */
- estimate = 2 * data_file_length / dict_index_calc_min_rec_len(index);
+ estimate = 2 * local_data_file_length / dict_index_calc_min_rec_len(index);
DBUG_RETURN((ha_rows) estimate);
}
@@ -3374,12 +3468,21 @@ ha_innobase::info(
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
dict_table_t* ib_table;
dict_index_t* index;
- ulong rec_per_key;
+ ha_rows rec_per_key;
ulong j;
ulong i;
DBUG_ENTER("info");
+ /* If we are forcing recovery at a high level, we will suppress
+ statistics calculation on tables, because that may crash the
+ server if an index is badly corrupted. */
+
+ if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
+
+ return;
+ }
+
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
obsolete! */
@@ -3426,7 +3529,7 @@ ha_innobase::info(
rec_per_key = records;
} else {
- rec_per_key = (ulong)(records /
+ rec_per_key = (ha_rows)(records /
index->stat_n_diff_key_vals[j + 1]);
}
@@ -3441,8 +3544,9 @@ ha_innobase::info(
rec_per_key = 1;
}
- table->key_info[i].rec_per_key[j]
- = rec_per_key;
+ table->key_info[i].rec_per_key[j]=
+ rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 :
+ rec_per_key;
}
index = dict_table_get_next_index_noninline(index);
@@ -3641,7 +3745,6 @@ ha_innobase::reset(void)
return(0);
}
-
/**********************************************************************
When we create a temporary table inside MySQL LOCK TABLES, MySQL will
not call external_lock for the temporary table when it uses it. Instead,
@@ -3663,12 +3766,20 @@ ha_innobase::start_stmt(
innobase_release_stat_resources(trx);
trx_mark_sql_stat_end(trx);
+ if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
+ && trx->read_view) {
+ /* At low transaction isolation levels we let
+ each consistent read set its own snapshot */
+
+ read_view_close_for_mysql(trx);
+ }
+
auto_inc_counter_for_this_stat = 0;
prebuilt->sql_stat_start = TRUE;
prebuilt->hint_no_need_to_fetch_extra_cols = TRUE;
prebuilt->read_just_key = 0;
- if (prebuilt->select_lock_type == LOCK_NONE) {
+ if (!prebuilt->mysql_has_locked) {
/* This handle is for a temporary table created inside
this same LOCK TABLES; since MySQL does NOT call external_lock
in this case, we must use x-row locks inside InnoDB to be
@@ -3683,6 +3794,24 @@ ha_innobase::start_stmt(
}
/**********************************************************************
+Maps a MySQL trx isolation level code to the InnoDB isolation level code */
+inline
+ulint
+innobase_map_isolation_level(
+/*=========================*/
+ /* out: InnoDB isolation level */
+ enum_tx_isolation iso) /* in: MySQL isolation level code */
+{
+ switch(iso) {
+ case ISO_READ_COMMITTED: return(TRX_ISO_READ_COMMITTED);
+ case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
+ case ISO_SERIALIZABLE: return(TRX_ISO_SERIALIZABLE);
+ case ISO_READ_UNCOMMITTED: return(TRX_ISO_READ_UNCOMMITTED);
+ default: ut_a(0); return(0);
+ }
+}
+
+/**********************************************************************
As MySQL will execute an external lock for every new table it uses when it
starts to process an SQL statement (an exception is when MySQL calls
start_stmt for the handle) we can use this function to store the pointer to
@@ -3703,6 +3832,7 @@ ha_innobase::external_lock(
trx_t* trx;
DBUG_ENTER("ha_innobase::external_lock");
+ DBUG_PRINT("enter",("lock_type: %d", lock_type));
update_thd(thd);
@@ -3727,8 +3857,15 @@ ha_innobase::external_lock(
thd->transaction.all.innodb_active_trans = 1;
trx->n_mysql_tables_in_use++;
+ prebuilt->mysql_has_locked = TRUE;
+
+ if (thd->variables.tx_isolation != ISO_REPEATABLE_READ) {
+ trx->isolation_level = innobase_map_isolation_level(
+ (enum_tx_isolation)
+ thd->variables.tx_isolation);
+ }
- if (thd->variables.tx_isolation == ISO_SERIALIZABLE
+ if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE) {
/* To get serializable execution we let InnoDB
@@ -3744,6 +3881,7 @@ ha_innobase::external_lock(
}
} else {
trx->n_mysql_tables_in_use--;
+ prebuilt->mysql_has_locked = FALSE;
auto_inc_counter_for_this_stat = 0;
if (trx->n_mysql_tables_in_use == 0) {
@@ -3755,6 +3893,15 @@ ha_innobase::external_lock(
innobase_release_stat_resources(trx);
+ if (trx->isolation_level <= TRX_ISO_READ_COMMITTED
+ && trx->read_view) {
+
+ /* At low transaction isolation levels we let
+ each consistent read set its own snapshot */
+
+ read_view_close_for_mysql(trx);
+ }
+
if (!(thd->options
& (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
@@ -3779,14 +3926,13 @@ innodb_show_status(
char* buf;
DBUG_ENTER("innodb_show_status");
-
+
if (innodb_skip) {
-
- fprintf(stderr,
- "Cannot call SHOW INNODB STATUS because skip-innodb is defined\n");
-
- DBUG_RETURN(-1);
- }
+ my_message(ER_NOT_SUPPORTED_YET,
+ "Cannot call SHOW INNODB STATUS because skip-innodb is defined",
+ MYF(0));
+ DBUG_RETURN(-1);
+ }
/* We let the InnoDB Monitor to output at most 100 kB of text, add
a safety margin of 10 kB for buffer overruns */
@@ -4056,3 +4202,4 @@ ha_innobase::get_auto_increment()
}
#endif /* HAVE_INNOBASE_DB */
+
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 9055c8b8239..62bebfc9968 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -96,7 +96,7 @@ class ha_innobase: public handler
ulong index_flags(uint idx) const
{
return (HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER |
- HA_KEY_READ_ONLY | HA_NOT_READ_PREFIX_LAST);
+ HA_KEY_READ_ONLY);
}
uint max_record_length() const { return HA_MAX_REC_LENGTH; }
uint max_keys() const { return MAX_KEY; }
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index 052e6a4b9ec..6fa54d18aac 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -380,7 +380,8 @@ int ha_isam::create(const char *name, register TABLE *form,
}
recinfo_pos->base.type= (int) FIELD_LAST; /* End of fieldinfo */
error=nisam_create(fn_format(buff,name,"","",2+4+16),form->keys,keydef,
- recinfo,form->max_rows,form->min_rows,0,0,0L);
+ recinfo,(ulong) form->max_rows, (ulong) form->min_rows,
+ 0, 0, 0L);
my_free((gptr) recinfo,MYF(0));
DBUG_RETURN(error);
diff --git a/sql/ha_isammrg.cc b/sql/ha_isammrg.cc
index b110ffba2f9..94e394e7665 100644
--- a/sql/ha_isammrg.cc
+++ b/sql/ha_isammrg.cc
@@ -190,13 +190,15 @@ THR_LOCK_DATA **ha_isammrg::store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
- MRG_TABLE *table;
+ MRG_TABLE *open_table;
- for (table=file->open_tables ; table != file->end_table ; table++)
+ for (open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
{
- *(to++)= &table->table->lock;
- if (lock_type != TL_IGNORE && table->table->lock.type == TL_UNLOCK)
- table->table->lock.type=lock_type;
+ *(to++)= &open_table->table->lock;
+ if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
+ open_table->table->lock.type=lock_type;
}
return to;
}
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 64dbcfe2056..ae71e362875 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -576,7 +576,6 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
}
if (!optimize ||
- //memcmp(file->state, & share->state.state, sizeof(MI_STATUS_INFO)) ||
((file->state->del || share->state.split != file->state->records) &&
(!(param.testflag & T_QUICK) ||
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
@@ -635,7 +634,12 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
STATE_CRASHED_ON_REPAIR);
file->update|=HA_STATE_CHANGED | HA_STATE_ROW_CHANGED;
}
- //file->save_state=file->s->state.state;
+ /*
+ the following 'if', thought conceptually wrong,
+ is a useful optimization nevertheless.
+ */
+ if (file->state != &file->s->state.state);
+ file->s->state.state = *file->state;
if (file->s->base.auto_key)
update_auto_increment_key(&param, file, 1);
if (optimize_done)
@@ -914,7 +918,7 @@ void ha_myisam::info(uint flag)
if (table->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
(char*) info.rec_per_key,
- sizeof(ulong)*table->key_parts);
+ sizeof(table->key_info[0].rec_per_key)*table->key_parts);
raid_type=info.raid_type;
raid_chunks=info.raid_chunks;
raid_chunksize=info.raid_chunksize;
@@ -1014,7 +1018,7 @@ void ha_myisam::update_create_info(HA_CREATE_INFO *create_info)
}
-int ha_myisam::create(const char *name, register TABLE *table,
+int ha_myisam::create(const char *name, register TABLE *table_arg,
HA_CREATE_INFO *info)
{
int error;
@@ -1026,20 +1030,20 @@ int ha_myisam::create(const char *name, register TABLE *table,
MI_KEYDEF *keydef;
MI_COLUMNDEF *recinfo,*recinfo_pos;
HA_KEYSEG *keyseg;
- uint options=table->db_options_in_use;
+ uint options=table_arg->db_options_in_use;
DBUG_ENTER("ha_myisam::create");
type=HA_KEYTYPE_BINARY; // Keep compiler happy
if (!(my_multi_malloc(MYF(MY_WME),
- &recinfo,(table->fields*2+2)*sizeof(MI_COLUMNDEF),
- &keydef, table->keys*sizeof(MI_KEYDEF),
+ &recinfo,(table_arg->fields*2+2)*sizeof(MI_COLUMNDEF),
+ &keydef, table_arg->keys*sizeof(MI_KEYDEF),
&keyseg,
- ((table->key_parts + table->keys) * sizeof(HA_KEYSEG)),
+ ((table_arg->key_parts + table_arg->keys) * sizeof(HA_KEYSEG)),
0)))
DBUG_RETURN(1);
- pos=table->key_info;
- for (i=0; i < table->keys ; i++, pos++)
+ pos=table_arg->key_info;
+ for (i=0; i < table_arg->keys ; i++, pos++)
{
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
keydef[i].key_alg=pos->algorithm == HA_KEY_ALG_UNDEF ?
@@ -1078,14 +1082,13 @@ int ha_myisam::create(const char *name, register TABLE *table,
keydef[i].seg[j].start= pos->key_part[j].offset;
keydef[i].seg[j].length= pos->key_part[j].length;
keydef[i].seg[j].bit_start=keydef[i].seg[j].bit_end=0;
- keydef[i].seg[j].language = field->binary() ? MY_CHARSET_CURRENT :
- ((Field_str*)field)->charset()->number;
+ keydef[i].seg[j].language = field->charset()->number;
if (field->null_ptr)
{
keydef[i].seg[j].null_bit=field->null_bit;
keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
- (uchar*) table->record[0]);
+ (uchar*) table_arg->record[0]);
}
else
{
@@ -1103,19 +1106,19 @@ int ha_myisam::create(const char *name, register TABLE *table,
keydef[i].seg[j].flag|=HA_BLOB_PART;
/* save number of bytes used to pack length */
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
- table->blob_ptr_size);
+ table_arg->blob_ptr_size);
}
}
keyseg+=pos->key_parts;
}
recpos=0; recinfo_pos=recinfo;
- while (recpos < (uint) table->reclength)
+ while (recpos < (uint) table_arg->reclength)
{
Field **field,*found=0;
- minpos=table->reclength; length=0;
+ minpos=table_arg->reclength; length=0;
- for (field=table->field ; *field ; field++)
+ for (field=table_arg->field ; *field ; field++)
{
if ((fieldpos=(*field)->offset()) >= recpos &&
fieldpos <= minpos)
@@ -1161,7 +1164,7 @@ int ha_myisam::create(const char *name, register TABLE *table,
{
recinfo_pos->null_bit=found->null_bit;
recinfo_pos->null_pos= (uint) (found->null_ptr-
- (uchar*) table->record[0]);
+ (uchar*) table_arg->record[0]);
}
else
{
@@ -1176,13 +1179,13 @@ int ha_myisam::create(const char *name, register TABLE *table,
}
MI_CREATE_INFO create_info;
bzero((char*) &create_info,sizeof(create_info));
- create_info.max_rows=table->max_rows;
- create_info.reloc_rows=table->min_rows;
+ create_info.max_rows=table_arg->max_rows;
+ create_info.reloc_rows=table_arg->min_rows;
create_info.auto_increment=(info->auto_increment_value ?
info->auto_increment_value -1 :
(ulonglong) 0);
- create_info.data_file_length= ((ulonglong) table->max_rows *
- table->avg_row_length);
+ create_info.data_file_length= ((ulonglong) table_arg->max_rows *
+ table_arg->avg_row_length);
create_info.raid_type=info->raid_type;
create_info.raid_chunks= (info->raid_chunks ? info->raid_chunks :
RAID_DEFAULT_CHUNKS);
@@ -1192,7 +1195,7 @@ int ha_myisam::create(const char *name, register TABLE *table,
create_info.index_file_name=info->index_file_name;
error=mi_create(fn_format(buff,name,"","",2+4),
- table->keys,keydef,
+ table_arg->keys,keydef,
(uint) (recinfo_pos-recinfo), recinfo,
0, (MI_UNIQUEDEF*) 0,
&create_info,
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index c35bf657445..4398aaecf4d 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -160,6 +160,16 @@ int ha_myisammrg::index_last(byte * buf)
return error;
}
+int ha_myisammrg::index_next_same(byte * buf,
+ const byte *key __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ int error=myrg_rnext_same(file,buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
int ha_myisammrg::rnd_init(bool scan)
{
return myrg_extra(file,HA_EXTRA_RESET,0);
@@ -187,6 +197,19 @@ void ha_myisammrg::position(const byte *record)
ha_store_ptr(ref, ref_length, (my_off_t) position);
}
+ha_rows ha_myisammrg::records_in_range(int inx,
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag)
+{
+ return (ha_rows) myrg_records_in_range(file,
+ inx,
+ start_key,start_key_len,
+ start_search_flag,
+ end_key,end_key_len,
+ end_search_flag);
+}
void ha_myisammrg::info(uint flag)
{
@@ -262,13 +285,15 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)
{
- MYRG_TABLE *table;
+ MYRG_TABLE *open_table;
- for (table=file->open_tables ; table != file->end_table ; table++)
+ for (open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
{
- *(to++)= &table->table->lock;
- if (lock_type != TL_IGNORE && table->table->lock.type == TL_UNLOCK)
- table->table->lock.type=lock_type;
+ *(to++)= &open_table->table->lock;
+ if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
+ open_table->table->lock.type=lock_type;
}
return to;
}
@@ -279,14 +304,16 @@ void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
DBUG_ENTER("ha_myisammrg::update_create_info");
if (!(create_info->used_fields & HA_CREATE_USED_UNION))
{
- MYRG_TABLE *table;
+ MYRG_TABLE *open_table;
THD *thd=current_thd;
create_info->merge_list.next= &create_info->merge_list.first;
create_info->merge_list.elements=0;
- for (table=file->open_tables ; table != file->end_table ; table++)
+ for (open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
{
- char *name=table->table->filename;
+ char *name=open_table->table->filename;
char buff[FN_REFLEN];
TABLE_LIST *ptr;
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
@@ -323,7 +350,28 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
sizeof(char*))))
DBUG_RETURN(1);
for (pos=table_names ; tables ; tables=tables->next)
- *pos++= tables->real_name;
+ {
+ char *table_name;
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ TABLE **tbl=find_temporary_table(current_thd,
+ tables->db, tables->real_name);
+ if (!tbl)
+ {
+ table_name=sql_alloc(1+
+ my_snprintf(buff,FN_REFLEN,"%s/%s/%s",mysql_real_data_home,
+ tables->db, tables->real_name));
+ if (!table_name)
+ DBUG_RETURN(1);
+ strcpy(table_name, buff);
+ }
+ else
+ table_name=(*tbl)->path;
+ }
+ else
+ table_name=tables->real_name;
+ *pos++= table_name;
+ }
*pos=0;
DBUG_RETURN(myrg_create(fn_format(buff,name,"","",2+4+16),
(const char **) table_names,
@@ -340,13 +388,15 @@ void ha_myisammrg::append_create_info(String *packet)
packet->append(get_type(&merge_insert_method,file->merge_insert_method-1));
}
packet->append(" UNION=(",8);
- MYRG_TABLE *table,*first;
+ MYRG_TABLE *open_table,*first;
- for (first=table=file->open_tables ; table != file->end_table ; table++)
+ for (first=open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
{
- char *name=table->table->filename;
+ char *name= open_table->table->filename;
fn_format(buff,name,"","",3);
- if (table != first)
+ if (open_table != first)
packet->append(',');
packet->append(buff,(uint) strlen(buff));
}
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index b75d5360097..008f5339caf 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -65,10 +65,16 @@ class ha_myisammrg: public handler
int index_prev(byte * buf);
int index_first(byte * buf);
int index_last(byte * buf);
+ int index_next_same(byte *buf, const byte *key, uint keylen);
int rnd_init(bool scan=1);
int rnd_next(byte *buf);
int rnd_pos(byte * buf, byte *pos);
void position(const byte *record);
+ ha_rows records_in_range(int inx,
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
my_off_t row_position() { return myrg_position(file); }
void info(uint);
int extra(enum ha_extra_function operation);
diff --git a/sql/handler.cc b/sql/handler.cc
index 10313201bf2..deee5110113 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -295,7 +295,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
}
else
if (!(thd->options & OPTION_BEGIN))
- transaction_commited= 1;
+ transaction_commited= 1;
trans->bdb_tid=0;
}
#endif
@@ -314,7 +314,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
}
#endif
#ifdef HAVE_QUERY_CACHE
- if (transaction_commited)
+ if (transaction_commited && thd->transaction.changed_tables)
query_cache.invalidate(thd->transaction.changed_tables);
#endif /*HAVE_QUERY_CACHE*/
if (error && trans == &thd->transaction.all && mysql_bin_log.is_open())
@@ -893,13 +893,13 @@ int ha_create_table(const char *name, HA_CREATE_INFO *create_info,
void ha_key_cache(void)
{
if (keybuff_size)
- (void) init_key_cache(keybuff_size);
+ (void) init_key_cache((ulong) keybuff_size);
}
void ha_resize_key_cache(void)
{
- (void) resize_key_cache(keybuff_size);
+ (void) resize_key_cache((ulong) keybuff_size);
}
diff --git a/sql/handler.h b/sql/handler.h
index 7fffd1a0cb9..3aaa1c6c1e1 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -158,7 +158,6 @@ typedef struct st_ha_create_information
CHARSET_INFO *table_charset;
char *comment,*password;
char *data_file_name, *index_file_name;
- char *create_statement;
ulonglong max_rows,min_rows;
ulonglong auto_increment_value;
ulong table_options;
@@ -235,7 +234,7 @@ public:
void change_table_ptr(TABLE *table_arg) { table=table_arg; }
virtual double scan_time()
{ return ulonglong2double(data_file_length) / IO_SIZE + 1; }
- virtual double read_time(ha_rows rows) { return rows; }
+ virtual double read_time(ha_rows rows) { return rows2double(rows); }
virtual bool fast_key_read() { return 0;}
virtual key_map keys_to_use_for_scanning() { return 0; }
virtual bool has_transactions(){ return 0;}
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index 4d746d9b9bd..f7384cc6e32 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -40,7 +40,7 @@ class hash_filo
{
const uint size, key_offset, key_length;
const hash_get_key get_key;
- void (*free_element)(void*);
+ hash_free_key free_element;
bool init;
hash_filo_element *first_link,*last_link;
@@ -49,7 +49,7 @@ public:
HASH cache;
hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
- hash_get_key get_key_arg,void (*free_element_arg)(void*))
+ hash_get_key get_key_arg, hash_free_key free_element_arg)
:size(size_arg), key_offset(key_offset_arg), key_length(key_length_arg),
get_key(get_key_arg), free_element(free_element_arg),init(0)
{
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 3da752f3b64..609532a67d6 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -63,7 +63,7 @@ bool hostname_cache_init()
if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
sizeof(struct in_addr),NULL,
- (void (*)(void*)) free)))
+ (hash_free_key) free)))
return 1;
hostname_cache->clear();
return 0;
diff --git a/sql/item.cc b/sql/item.cc
index 037e57b2b8a..5e74820a3f8 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -34,7 +34,8 @@ void item_init(void)
item_user_lock_init();
}
-Item::Item()
+Item::Item():
+ fixed(0)
{
marker=0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
@@ -42,6 +43,30 @@ Item::Item()
decimals=0; max_length=0;
next=current_thd->free_list; // Put in free list
current_thd->free_list=this;
+ loop_id= 0;
+}
+
+bool Item::check_loop(uint id)
+{
+ DBUG_ENTER("Item::check_loop");
+ DBUG_PRINT("info", ("id %u, name %s", id, name));
+ if (loop_id == id)
+ {
+ DBUG_PRINT("info", ("id match"));
+ DBUG_RETURN(1);
+ }
+ loop_id= id;
+ DBUG_RETURN(0);
+}
+
+bool Item::check_cols(uint c)
+{
+ if (c != 1)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
}
void Item::set_name(const char *str,uint length)
@@ -117,9 +142,15 @@ bool Item::get_time(TIME *ltime)
return 0;
}
+CHARSET_INFO * Item::thd_charset() const
+{
+ return current_thd->thd_charset;
+}
+
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
{
set_field(f);
+ fixed= 1; // This item is not needed in fix_fields
}
@@ -234,7 +265,7 @@ table_map Item_field::used_tables() const
String *Item_int::val_str(String *str)
{
- str->set(value, my_thd_charset);
+ str->set(value, thd_charset());
return str;
}
@@ -242,7 +273,7 @@ void Item_int::print(String *str)
{
if (!name)
{
- str_value.set(value, my_thd_charset);
+ str_value.set(value, thd_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -250,7 +281,7 @@ void Item_int::print(String *str)
String *Item_uint::val_str(String *str)
{
- str->set((ulonglong) value, my_thd_charset);
+ str->set((ulonglong) value, thd_charset());
return str;
}
@@ -258,7 +289,7 @@ void Item_uint::print(String *str)
{
if (!name)
{
- str_value.set((ulonglong) value, my_thd_charset);
+ str_value.set((ulonglong) value, thd_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -267,7 +298,7 @@ void Item_uint::print(String *str)
String *Item_real::val_str(String *str)
{
- str->set(value,decimals,my_thd_charset);
+ str->set(value,decimals,thd_charset());
return str;
}
@@ -296,36 +327,31 @@ void Item_param::set_null()
void Item_param::set_int(longlong i)
{
int_value=(longlong)i;
- item_result_type = INT_RESULT;
item_type = INT_ITEM;
}
void Item_param::set_double(double value)
{
real_value=value;
- item_result_type = REAL_RESULT;
item_type = REAL_ITEM;
}
void Item_param::set_value(const char *str, uint length)
{
- str_value.set(str,length,default_charset_info);
- item_result_type = STRING_RESULT;
+ str_value.set(str,length,thd_charset());
item_type = STRING_ITEM;
}
void Item_param::set_longdata(const char *str, ulong length)
-{
- /* TODO: Fix this for binary handling by making use of
- buffer_type..
- */
- str_value.append(str,length);
+{
+ str_value.append(str,length);
+ long_data_supplied= 1;
}
-int Item_param::save_in_field(Field *field)
+int Item_param::save_in_field(Field *field, bool no_conversions)
{
if (null_value)
return (int) set_field_to_null(field);
@@ -341,10 +367,8 @@ int Item_param::save_in_field(Field *field)
double nr=val();
return (field->store(nr)) ? -1 : 0;
}
- String *result;
- CHARSET_INFO *cs=default_charset_info; //fix this
- result=val_str(&str_value);
- return (field->store(result->ptr(),result->length(),cs)) ? -1 : 0;
+ String *result=val_str(&str_value);
+ return (field->store(result->ptr(),result->length(),field->charset())) ? -1 : 0;
}
@@ -358,7 +382,7 @@ double Item_param::val()
{
switch (item_result_type) {
case STRING_RESULT:
- return (double)atof(str_value.ptr());
+ return (double)my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),(char**)0);
case INT_RESULT:
return (double)int_value;
default:
@@ -371,7 +395,7 @@ longlong Item_param::val_int()
{
switch (item_result_type) {
case STRING_RESULT:
- return strtoll(str_value.ptr(),(char**) 0,10);
+ return my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10);
case REAL_RESULT:
return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5));
default:
@@ -384,10 +408,10 @@ String *Item_param::val_str(String* str)
{
switch (item_result_type) {
case INT_RESULT:
- str->set(int_value, my_thd_charset);
+ str->set(int_value, thd_charset());
return str;
case REAL_RESULT:
- str->set(real_value, 2, my_thd_charset);
+ str->set(real_value, 2, thd_charset());
return str;
default:
return (String*) &str_value;
@@ -421,9 +445,77 @@ bool Item::fix_fields(THD *thd,
struct st_table_list *list,
Item ** ref)
{
+ fixed= 1;
return 0;
}
+bool Item_outer_select_context_saver::fix_fields(THD *thd,
+ struct st_table_list *list,
+ Item ** ref)
+{
+ DBUG_ENTER("Item_outer_select_context_saver::fix_fields");
+ bool res= item->fix_fields(thd,
+ 0, // do not show current subselect fields
+ &item);
+ *ref= item;
+ DBUG_RETURN(res);
+}
+
+bool Item_asterisk_remover::fix_fields(THD *thd,
+ struct st_table_list *list,
+ Item ** ref)
+{
+ DBUG_ENTER("Item_asterisk_remover::fix_fields");
+
+ bool res= 1;
+ if (item)
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ Item_field *fitem= (Item_field*) item;
+ if (list)
+ if (!list->next || fitem->db_name || fitem->table_name)
+ {
+ TABLE_LIST *table= find_table_in_list(list,
+ fitem->db_name,
+ fitem->table_name);
+ if (table)
+ {
+ TABLE * tb= table->table;
+ if (find_table_in_list(table->next, fitem->db_name,
+ fitem->table_name) != 0 ||
+ tb->fields == 1)
+ {
+ if ((item= new Item_field(tb->field[0])))
+ {
+ res= 0;
+ tb->field[0]->query_id= thd->query_id;
+ tb->used_keys&= tb->field[0]->part_of_key;
+ tb->used_fields= tb->fields;
+ }
+ else
+ thd->fatal_error= 1; // can't create Item => out of memory
+ }
+ else
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ }
+ else
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), fitem->table_name);
+ }
+ else
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ else
+ my_error(ER_NO_TABLES_USED, MYF(0));
+ }
+ else
+ res= item->fix_fields(thd, list, &item);
+ else
+ thd->fatal_error= 1; // no item given => out of memory
+ *ref= item;
+ DBUG_RETURN(res);
+}
+
+
bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (!field) // If field is not checked
@@ -441,21 +533,51 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
*/
SELECT_LEX *last= 0;
- for (SELECT_LEX *sl= thd->lex.current_select->outer_select();
- sl;
- sl= sl->outer_select())
- if ((tmp= find_field_in_tables(thd, this,
- (last= sl)->get_table_list(),
- 0)) != not_found_field)
- break;
+
+ Item **refer= (Item **)not_found_item;
+ // Prevent using outer fields in subselects, that is not supported now
+ SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
+ if (cursel->linkage != DERIVED_TABLE_TYPE)
+ for (SELECT_LEX *sl=cursel->outer_select();
+ sl;
+ sl= sl->outer_select())
+ {
+ if ((tmp= find_field_in_tables(thd, this,
+ (last= sl)->get_table_list(),
+ 0)) != not_found_field)
+ break;
+ if ((refer= find_item_in_list(this, sl->item_list,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item)
+ break;
+ if (sl->linkage == DERIVED_TABLE_TYPE)
+ break; // do not look over derived table
+ }
if (!tmp)
return -1;
- else if (tmp == not_found_field)
+ else if (!refer)
+ return 1;
+ else if (tmp == not_found_field && refer == (Item **)not_found_item)
{
// call to return error code
find_field_in_tables(thd, this, tables, 1);
return -1;
}
+ else if (refer != (Item **)not_found_item)
+ {
+ Item_ref *r;
+ *ref= r= new Item_ref(refer, (char *)table_name,
+ (char *)field_name);
+ if (!r)
+ return 1;
+ int res;
+ if (r->check_cols(1) || r->fix_fields(thd, tables, ref))
+ return 1;
+ r->depended_from= last;
+ cursel->mark_as_dependent(last);
+ thd->add_possible_loop(r);
+ return 0;
+ }
else
{
depended_from= last;
@@ -485,8 +607,9 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(char *)field_name);
if (!*ref)
return 1;
- return (*ref)->fix_fields(thd, tables, ref);
+ return (*ref)->check_cols(1) || (*ref)->fix_fields(thd, tables, ref);
}
+ fixed= 1;
return 0;
}
@@ -578,7 +701,7 @@ void Item_field::save_org_in_field(Field *to)
if (field->is_null())
{
null_value=1;
- set_field_to_null_with_conversions(to);
+ set_field_to_null_with_conversions(to, 1);
}
else
{
@@ -588,12 +711,12 @@ void Item_field::save_org_in_field(Field *to)
}
}
-int Item_field::save_in_field(Field *to)
+int Item_field::save_in_field(Field *to, bool no_conversions)
{
if (result_field->is_null())
{
null_value=1;
- return set_field_to_null_with_conversions(to);
+ return set_field_to_null_with_conversions(to, no_conversions);
}
else
{
@@ -621,9 +744,9 @@ int Item_field::save_in_field(Field *to)
1 Field doesn't support NULL values and can't handle 'field = NULL'
*/
-int Item_null::save_in_field(Field *field)
+int Item_null::save_in_field(Field *field, bool no_conversions)
{
- return set_field_to_null_with_conversions(field);
+ return set_field_to_null_with_conversions(field, no_conversions);
}
@@ -645,7 +768,7 @@ int Item_null::save_safe_in_field(Field *field)
}
-int Item::save_in_field(Field *field)
+int Item::save_in_field(Field *field, bool no_conversions)
{
int error;
if (result_type() == STRING_RESULT ||
@@ -653,12 +776,12 @@ int Item::save_in_field(Field *field)
field->result_type() == STRING_RESULT)
{
String *result;
- CHARSET_INFO *cs=field->binary()?my_charset_bin:((Field_str*)field)->charset();
+ CHARSET_INFO *cs=charset();
char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
str_value.set_quick(buff,sizeof(buff),cs);
result=val_str(&str_value);
if (null_value)
- return set_field_to_null_with_conversions(field);
+ return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
error=field->store(result->ptr(),result->length(),cs);
str_value.set_quick(0, 0, cs);
@@ -675,25 +798,26 @@ int Item::save_in_field(Field *field)
{
longlong nr=val_int();
if (null_value)
- return set_field_to_null_with_conversions(field);
+ return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
error=field->store(nr);
}
return (error) ? -1 : 0;
}
-int Item_string::save_in_field(Field *field)
+
+int Item_string::save_in_field(Field *field, bool no_conversions)
{
String *result;
- CHARSET_INFO *cs=field->binary()?my_charset_bin:((Field_str*)field)->charset();
result=val_str(&str_value);
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- return (field->store(result->ptr(),result->length(),cs)) ? -1 : 0;
+ return (field->store(result->ptr(),result->length(),charset())) ? -1 : 0;
}
-int Item_int::save_in_field(Field *field)
+
+int Item_int::save_in_field(Field *field, bool no_conversions)
{
longlong nr=val_int();
if (null_value)
@@ -702,7 +826,8 @@ int Item_int::save_in_field(Field *field)
return (field->store(nr)) ? -1 : 0;
}
-int Item_real::save_in_field(Field *field)
+
+int Item_real::save_in_field(Field *field, bool no_conversions)
{
double nr=val();
if (null_value)
@@ -755,14 +880,13 @@ longlong Item_varbinary::val_int()
}
-int Item_varbinary::save_in_field(Field *field)
+int Item_varbinary::save_in_field(Field *field, bool no_conversions)
{
int error;
- CHARSET_INFO *cs=field->binary()?default_charset_info:((Field_str*)field)->charset();
field->set_notnull();
if (field->result_type() == STRING_RESULT)
{
- error=field->store(str_value.ptr(),str_value.length(),cs);
+ error=field->store(str_value.ptr(),str_value.length(),charset());
}
else
{
@@ -809,12 +933,21 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
if (!ref)
{
SELECT_LEX *sl= thd->lex.current_select->outer_select();
+ /*
+ Finding only in current select will be performed for selects that have
+ not outer one and for derived tables (which not support using outer
+ fields for now)
+ */
if ((ref= find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
- (sl ? REPORT_EXCEPT_NOT_FOUND :
- REPORT_ALL_ERRORS))) ==
+ ((sl &&
+ thd->lex.current_select->linkage !=
+ DERIVED_TABLE_TYPE) ?
+ REPORT_EXCEPT_NOT_FOUND :
+ REPORT_ALL_ERRORS))) ==
(Item **)not_found_item)
{
+ Field *tmp= (Field*) not_found_field;
/*
We can't find table field in table list of current select,
consequently we have to find it in outer subselect(s).
@@ -826,16 +959,23 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
*/
SELECT_LEX *last=0;
for ( ; sl ; sl= sl->outer_select())
- if((ref= find_item_in_list(this, (last= sl)->item_list,
+ {
+ if ((ref= find_item_in_list(this, (last= sl)->item_list,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **)not_found_item)
break;
+ if ((tmp= find_field_in_tables(thd, this,
+ sl->get_table_list(),
+ 0)) != not_found_field);
+ if (sl->linkage == DERIVED_TABLE_TYPE)
+ break; // do not look over derived table
+ }
if (!ref)
- {
return 1;
- }
- else if (ref == (Item **)not_found_item)
+ else if (!tmp)
+ return -1;
+ else if (ref == (Item **)not_found_item && tmp == not_found_field)
{
// Call to report error
find_item_in_list(this,
@@ -844,10 +984,21 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
ref= 0;
return 1;
}
+ else if (tmp != not_found_field)
+ {
+ ref= 0; // To prevent "delete *ref;" on ~Item_erf() of this item
+ Item_field* f;
+ if (!((*reference)= f= new Item_field(tmp)))
+ return 1;
+ f->depended_from= last;
+ thd->lex.current_select->mark_as_dependent(last);
+ return 0;
+ }
else
{
depended_from= last;
thd->lex.current_select->mark_as_dependent(last);
+ thd->add_possible_loop(this);
}
}
else if (!ref)
@@ -856,12 +1007,36 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
}
+ if (((*ref)->with_sum_func &&
+ (depended_from ||
+ !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
+ thd->lex.current_select->select_lex()->having_fix_field))) ||
+ !(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ ((*ref)->with_sum_func?
+ "reference on group function":
+ "forward reference in item list"));
+ return 1;
+ }
+ fixed= 1;
+ if (ref && (*ref)->check_cols(1))
+ return 1;
return 0;
}
+bool Item_ref::check_loop(uint id)
+{
+ DBUG_ENTER("Item_ref::check_loop");
+ if (Item_ident::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN((*ref)->check_loop(id));
+}
+
+
/*
-** If item is a const function, calculate it and return a const item
-** The original item is freed if not returned
+ If item is a const function, calculate it and return a const item
+ The original item is freed if not returned
*/
Item_result item_cmp_type(Item_result a,Item_result b)
@@ -870,6 +1045,8 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return STRING_RESULT;
else if (a == INT_RESULT && b == INT_RESULT)
return INT_RESULT;
+ else if (a == ROW_RESULT || b == ROW_RESULT)
+ return ROW_RESULT;
else
return REAL_RESULT;
}
diff --git a/sql/item.h b/sql/item.h
index fc36148e443..4dff0591c09 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -20,10 +20,11 @@
#endif
struct st_table_list;
-void item_init(void); /* Init item functions */
+void item_init(void); /* Init item functions */
class Item {
- Item(const Item &); /* Prevent use of these */
+ uint loop_id; /* Used to find selfrefering loops */
+ Item(const Item &); /* Prevent use of these */
void operator=(Item &);
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
@@ -33,7 +34,7 @@ public:
INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM,
COPY_STR_ITEM,FIELD_AVG_ITEM, DEFAULT_ITEM,
PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM,
- SUBSELECT_ITEM};
+ SUBSELECT_ITEM, ROW_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
String str_value; /* used to store value */
@@ -45,6 +46,7 @@ public:
my_bool null_value; /* if item is null */
my_bool unsigned_flag;
my_bool with_sum_func;
+ my_bool fixed; /* If item fixed with fix_fields */
// alloc & destruct is done as start of select using sql_alloc
Item();
@@ -52,11 +54,11 @@ public:
void set_name(const char *str,uint length=0);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual bool fix_fields(THD *, struct st_table_list *, Item **);
- virtual int save_in_field(Field *field);
+ virtual int save_in_field(Field *field, bool no_conversions);
virtual void save_org_in_field(Field *field)
- { (void) save_in_field(field); }
+ { (void) save_in_field(field, 1); }
virtual int save_safe_in_field(Field *field)
- { return save_in_field(field); }
+ { return save_in_field(field, 1); }
virtual bool send(THD *thd, String *str);
virtual bool eq(const Item *, bool binary_cmp) const;
virtual Item_result result_type () const { return REAL_RESULT; }
@@ -84,12 +86,71 @@ public:
virtual bool get_date(TIME *ltime,bool fuzzydate);
virtual bool get_time(TIME *ltime);
virtual bool is_null() { return 0; };
- virtual CHARSET_INFO *charset() const { return str_value.charset(); };
- virtual bool binary() const { return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
- virtual void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
+ virtual bool check_loop(uint id);
+ virtual void top_level_item() {}
+
+ virtual bool binary() const
+ { return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
+ CHARSET_INFO *thd_charset() const;
+ CHARSET_INFO *charset() const { return str_value.charset(); };
+ void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
+
+ // Row emulation
+ virtual uint cols() { return 1; }
+ virtual Item* el(uint i) { return this; }
+ virtual Item** addr(uint i) { return 0; }
+ virtual bool check_cols(uint c);
};
+/*
+ Wrapper base class
+*/
+
+class Item_wrapper :public Item
+{
+protected:
+ Item *item;
+public:
+ /*
+ Following methods should not be used, because fix_fields exclude this
+ item (it assign '*ref' with field 'item' in derived classes)
+ */
+ enum Type type() const { return item->type(); }
+ double val() { return item->val(); }
+ longlong val_int() { return item->val_int(); }
+ String* val_str(String* s) { return item->val_str(s); }
+ void make_field(Send_field* f) { item->make_field(f); }
+ bool check_cols(uint col) { return item->check_cols(col); }
+};
+
+
+/*
+ Save context of name resolution for Item, used in subselect transformer.
+*/
+class Item_outer_select_context_saver :public Item_wrapper
+{
+public:
+ Item_outer_select_context_saver(Item *it)
+ {
+ item= it;
+ }
+ bool fix_fields(THD *, struct st_table_list *, Item ** ref);
+};
+
+/*
+ To resolve '*' field moved to condition
+*/
+class Item_asterisk_remover :public Item_wrapper
+{
+public:
+ Item_asterisk_remover(Item *it)
+ {
+ item= it;
+ }
+ bool fix_fields(THD *, struct st_table_list *, Item ** ref);
+};
+
class st_select_lex;
class Item_ident :public Item
{
@@ -134,7 +195,7 @@ public:
}
void make_field(Send_field *field);
bool fix_fields(THD *, struct st_table_list *, Item **);
- int save_in_field(Field *field);
+ int save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
table_map used_tables() const;
enum Item_result result_type () const
@@ -159,7 +220,7 @@ public:
longlong val_int();
String *val_str(String *str);
void make_field(Send_field *field);
- int save_in_field(Field *field);
+ int save_in_field(Field *field, bool no_conversions);
int save_safe_in_field(Field *field);
enum Item_result result_type () const
{ return STRING_RESULT; }
@@ -182,8 +243,8 @@ public:
Item_param(char *name_par=0)
{
name= name_par ? name_par : (char*) "?";
- long_data_supplied = false;
- item_type = STRING_ITEM;
+ long_data_supplied= false;
+ item_type= STRING_ITEM;
item_result_type = STRING_RESULT;
}
enum Type type() const { return item_type; }
@@ -191,18 +252,19 @@ public:
longlong val_int();
String *val_str(String*);
void make_field(Send_field *field);
- int save_in_field(Field *field);
+ int save_in_field(Field *field, bool no_conversions);
void set_null();
void set_int(longlong i);
void set_double(double i);
- void set_value(const char *str, uint length);
+ void set_value(const char *str, uint length);
void set_long_str(const char *str, ulong length);
void set_long_binary(const char *str, ulong length);
void set_longdata(const char *str, ulong length);
- void set_long_end();
+ void set_long_end();
void reset() {}
+ void (*setup_param_func)(Item_param *param, uchar **pos);
enum Item_result result_type () const
- { return item_result_type; }
+ { return item_result_type; }
Item *new_item() { return new Item_param(name); }
};
@@ -228,7 +290,7 @@ public:
double val() { return (double) value; }
String *val_str(String*);
void make_field(Send_field *field);
- int save_in_field(Field *field);
+ int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); }
void print(String *str);
@@ -268,7 +330,7 @@ public:
max_length=length;
}
Item_real(double value_par) :value(value_par) {}
- int save_in_field(Field *field);
+ int save_in_field(Field *field, bool no_conversions);
enum Type type() const { return REAL_ITEM; }
double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));}
@@ -308,10 +370,16 @@ public:
}
~Item_string() {}
enum Type type() const { return STRING_ITEM; }
- double val() { return atof(str_value.ptr()); }
- longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); }
+ double val()
+ {
+ return my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),(char**)NULL);
+ }
+ longlong val_int()
+ {
+ return my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10);
+ }
String *val_str(String*) { return (String*) &str_value; }
- int save_in_field(Field *field);
+ int save_in_field(Field *field, bool no_conversions);
void make_field(Send_field *field);
enum Item_result result_type () const { return STRING_RESULT; }
bool basic_const_item() const { return 1; }
@@ -331,7 +399,7 @@ public:
Item_default() { name= (char*) "DEFAULT"; }
enum Type type() const { return DEFAULT_ITEM; }
void make_field(Send_field *field) {}
- int save_in_field(Field *field)
+ int save_in_field(Field *field, bool no_conversions)
{
field->set_default();
return 0;
@@ -369,7 +437,7 @@ public:
double val() { return (double) Item_varbinary::val_int(); }
longlong val_int();
String *val_str(String*) { return &str_value; }
- int save_in_field(Field *field);
+ int save_in_field(Field *field, bool no_conversions);
void make_field(Send_field *field);
enum Item_result result_type () const { return INT_RESULT; }
};
@@ -397,8 +465,8 @@ public:
:Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
- { return (*ref)->eq(item, binary_cmp); }
- ~Item_ref() { if (ref) delete *ref; }
+ { return ref && (*ref)->eq(item, binary_cmp); }
+ ~Item_ref() { if (ref && (*ref) != this) delete *ref; }
double val()
{
double tmp=(*ref)->val_result();
@@ -429,10 +497,12 @@ public:
bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); }
void make_field(Send_field *field) { (*ref)->make_field(field); }
bool fix_fields(THD *, struct st_table_list *, Item **);
- int save_in_field(Field *field) { return (*ref)->save_in_field(field); }
+ int save_in_field(Field *field, bool no_conversions)
+ { return (*ref)->save_in_field(field, no_conversions); }
void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
enum Item_result result_type () const { return (*ref)->result_type(); }
table_map used_tables() const { return (*ref)->used_tables(); }
+ bool check_loop(uint id);
};
@@ -448,9 +518,9 @@ class Item_int_with_ref :public Item_int
public:
Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg)
{}
- int save_in_field(Field *field)
+ int save_in_field(Field *field, bool no_conversions)
{
- return ref->save_in_field(field);
+ return ref->save_in_field(field, no_conversions);
}
};
@@ -464,6 +534,7 @@ public:
#include "item_timefunc.h"
#include "item_uniq.h"
#include "item_subselect.h"
+#include "item_row.h"
class Item_copy_string :public Item
{
@@ -480,9 +551,9 @@ public:
enum Type type() const { return COPY_STR_ITEM; }
enum Item_result result_type () const { return STRING_RESULT; }
double val()
- { return null_value ? 0.0 : atof(str_value.c_ptr()); }
+ { return null_value ? 0.0 : my_strntod(str_value.charset(),str_value.ptr(),str_value.length(),NULL); }
longlong val_int()
- { return null_value ? LL(0) : strtoll(str_value.c_ptr(),(char**) 0,10); }
+ { return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),(char**) 0,10); }
String *val_str(String*);
void make_field(Send_field *field) { item->make_field(field); }
void copy();
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index b6ea4beb339..dd8d1aeff02 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -23,12 +23,36 @@
#include "mysql_priv.h"
#include <m_ctype.h>
-
+#include "assert.h"
+Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b)
+{
+ return new Item_func_eq(a, b);
+}
+Item_bool_func2* Item_bool_func2::ne_creator(Item *a, Item *b)
+{
+ return new Item_func_ne(a, b);
+}
+Item_bool_func2* Item_bool_func2::gt_creator(Item *a, Item *b)
+{
+ return new Item_func_gt(a, b);
+}
+Item_bool_func2* Item_bool_func2::lt_creator(Item *a, Item *b)
+{
+ return new Item_func_lt(a, b);
+}
+Item_bool_func2* Item_bool_func2::ge_creator(Item *a, Item *b)
+{
+ return new Item_func_ge(a, b);
+}
+Item_bool_func2* Item_bool_func2::le_creator(Item *a, Item *b)
+{
+ return new Item_func_le(a, b);
+}
/*
Test functions
- These returns 0LL if false and 1LL if true and null if some arg is null
- 'AND' and 'OR' never return null
+ Most of these returns 0LL if false and 1LL if true and
+ NULL if some arg is NULL.
*/
longlong Item_func_not::val_int()
@@ -53,7 +77,7 @@ static bool convert_constant_item(Field *field, Item **item)
{
if ((*item)->const_item() && (*item)->type() != Item::INT_ITEM)
{
- if (!(*item)->save_in_field(field) && !((*item)->null_value))
+ if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
Item *tmp=new Item_int_with_ref(field->val_int(), *item);
if (tmp)
@@ -64,7 +88,6 @@ static bool convert_constant_item(Field *field, Item **item)
return 0;
}
-
void Item_bool_func2::fix_length_and_dec()
{
max_length=1; // Function returns 0 or 1
@@ -83,7 +106,8 @@ void Item_bool_func2::fix_length_and_dec()
{
if (convert_constant_item(field,&args[1]))
{
- cmp_func= &Item_bool_func2::compare_int; // Works for all types.
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
return;
}
}
@@ -95,88 +119,154 @@ void Item_bool_func2::fix_length_and_dec()
{
if (convert_constant_item(field,&args[0]))
{
- cmp_func= &Item_bool_func2::compare_int; // Works for all types.
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
return;
}
}
}
- set_cmp_func(item_cmp_type(args[0]->result_type(),args[1]->result_type()));
+ set_cmp_func();
}
-
-void Item_bool_func2::set_cmp_func(Item_result type)
+int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
{
- switch (type) {
- case STRING_RESULT:
- cmp_func=&Item_bool_func2::compare_string;
- break;
- case REAL_RESULT:
- cmp_func=&Item_bool_func2::compare_real;
- break;
- case INT_RESULT:
- cmp_func=&Item_bool_func2::compare_int;
- break;
+ owner= item;
+ func= comparator_matrix[type][(owner->functype() == Item_func::EQUAL_FUNC)?
+ 1:0];
+ if (type == ROW_RESULT)
+ {
+ uint n= (*a)->cols();
+ if (n != (*b)->cols())
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), n);
+ comparators= 0;
+ return 1;
+ }
+ if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n)))
+ for (uint i=0; i < n; i++)
+ comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
+ else
+ {
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ current_thd->fatal_error= 1;
+ return 1;
+ }
}
+ return 0;
}
-
-int Item_bool_func2::compare_string()
+int Arg_comparator::compare_string()
{
String *res1,*res2;
- if ((res1=args[0]->val_str(&tmp_value1)))
+ if ((res1= (*a)->val_str(&owner->tmp_value1)))
{
- if ((res2=args[1]->val_str(&tmp_value2)))
+ if ((res2= (*b)->val_str(&owner->tmp_value2)))
{
- null_value=0;
- return binary() ? stringcmp(res1,res2) : sortcmp(res1,res2);
+ owner->null_value= 0;
+ return owner->binary() ? stringcmp(res1,res2) : sortcmp(res1,res2);
}
}
- null_value=1;
+ owner->null_value= 1;
return -1;
}
-int Item_bool_func2::compare_real()
+int Arg_comparator::compare_e_string()
{
- double val1=args[0]->val();
- if (!args[0]->null_value)
+ String *res1,*res2;
+ res1= (*a)->val_str(&owner->tmp_value1);
+ res2= (*b)->val_str(&owner->tmp_value2);
+ if (!res1 || !res2)
+ return test(res1 == res2);
+ return (owner->binary() ? test(stringcmp(res1, res2) == 0) :
+ test(sortcmp(res1, res2) == 0));
+}
+
+
+int Arg_comparator::compare_real()
+{
+ double val1= (*a)->val();
+ if (!(*a)->null_value)
{
- double val2=args[1]->val();
- if (!args[1]->null_value)
+ double val2= (*b)->val();
+ if (!(*b)->null_value)
{
- null_value=0;
+ owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
- null_value=1;
+ owner->null_value= 1;
return -1;
}
+int Arg_comparator::compare_e_real()
+{
+ double val1= (*a)->val();
+ double val2= (*b)->val();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2);
+}
-int Item_bool_func2::compare_int()
+int Arg_comparator::compare_int()
{
- longlong val1=args[0]->val_int();
- if (!args[0]->null_value)
+ longlong val1= (*a)->val_int();
+ if (!(*a)->null_value)
{
- longlong val2=args[1]->val_int();
- if (!args[1]->null_value)
+ longlong val2= (*b)->val_int();
+ if (!(*b)->null_value)
{
- null_value=0;
+ owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
- null_value=1;
+ owner->null_value= 1;
return -1;
}
+int Arg_comparator::compare_e_int()
+{
+ longlong val1= (*a)->val_int();
+ longlong val2= (*b)->val_int();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2);
+}
+
+
+int Arg_comparator::compare_row()
+{
+ int res= 0;
+ uint n= (*a)->cols();
+ for (uint i= 0; i<n; i++)
+ {
+ if ((res= comparators[i].compare()))
+ return res;
+ if (owner->null_value)
+ return -1;
+ }
+ return res;
+}
+
+int Arg_comparator::compare_e_row()
+{
+ int res= 0;
+ uint n= (*a)->cols();
+ for (uint i= 0; i<n; i++)
+ {
+ if ((res= comparators[i].compare()))
+ return 1;
+ }
+ return 1;
+}
longlong Item_func_eq::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value == 0 ? 1 : 0;
}
@@ -185,74 +275,45 @@ longlong Item_func_eq::val_int()
void Item_func_equal::fix_length_and_dec()
{
Item_bool_func2::fix_length_and_dec();
- cmp_result_type=item_cmp_type(args[0]->result_type(),args[1]->result_type());
maybe_null=null_value=0;
+ set_cmp_func();
}
longlong Item_func_equal::val_int()
{
- switch (cmp_result_type) {
- case STRING_RESULT:
- {
- String *res1,*res2;
- res1=args[0]->val_str(&tmp_value1);
- res2=args[1]->val_str(&tmp_value2);
- if (!res1 || !res2)
- return test(res1 == res2);
- return (binary() ? test(stringcmp(res1,res2) == 0) :
- test(sortcmp(res1,res2) == 0));
- }
- case REAL_RESULT:
- {
- double val1=args[0]->val();
- double val2=args[1]->val();
- if (args[0]->null_value || args[1]->null_value)
- return test(args[0]->null_value && args[1]->null_value);
- return test(val1 == val2);
- }
- case INT_RESULT:
- {
- longlong val1=args[0]->val_int();
- longlong val2=args[1]->val_int();
- if (args[0]->null_value || args[1]->null_value)
- return test(args[0]->null_value && args[1]->null_value);
- return test(val1 == val2);
- }
- }
- return 0; // Impossible
+ return cmp.compare();
}
-
longlong Item_func_ne::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value != 0 && !null_value ? 1 : 0;
}
longlong Item_func_ge::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value >= 0 ? 1 : 0;
}
longlong Item_func_gt::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value > 0 ? 1 : 0;
}
longlong Item_func_le::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value <= 0 && !null_value ? 1 : 0;
}
longlong Item_func_lt::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value < 0 && !null_value ? 1 : 0;
}
@@ -344,6 +405,14 @@ void Item_func_interval::update_used_tables()
const_item_cache&=item->const_item();
}
+bool Item_func_interval::check_loop(uint id)
+{
+ DBUG_ENTER("Item_func_interval::check_loop");
+ if (Item_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(item->check_loop(id));
+}
+
void Item_func_between::fix_length_and_dec()
{
max_length=1;
@@ -354,13 +423,19 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
- cmp_type=args[0]->result_type();
- if (args[0]->binary())
+ cmp_type=item_cmp_type(args[0]->result_type(),
+ item_cmp_type(args[1]->result_type(),
+ args[2]->result_type()));
+ if (args[0]->binary() | args[1]->binary() | args[2]->binary())
string_compare=stringcmp;
else
string_compare=sortcmp;
- // Make a special case of compare with fields to get nicer DATE comparisons
+ /*
+ Make a special case of compare with date/time and longlong fields.
+ They are compared as integers, so for const item this time-consuming
+ conversion can be done only once, not for every single comparison
+ */
if (args[0]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
@@ -442,15 +517,29 @@ longlong Item_func_between::val_int()
return 0;
}
+static Item_result item_store_type(Item_result a,Item_result b)
+{
+ if (a == STRING_RESULT || b == STRING_RESULT)
+ return STRING_RESULT;
+ else if (a == REAL_RESULT || b == REAL_RESULT)
+ return REAL_RESULT;
+ else
+ return INT_RESULT;
+}
+
void
Item_func_ifnull::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null;
max_length=max(args[0]->max_length,args[1]->max_length);
decimals=max(args[0]->decimals,args[1]->decimals);
- cached_result_type=args[0]->result_type();
+ if ((cached_result_type=item_store_type(args[0]->result_type(),
+ args[1]->result_type())) !=
+ REAL_RESULT)
+ decimals= 0;
}
+
double
Item_func_ifnull::val()
{
@@ -587,7 +676,7 @@ double
Item_func_nullif::val()
{
double value;
- if (!(this->*cmp_func)() || null_value)
+ if (!cmp.compare() || null_value)
{
null_value=1;
return 0.0;
@@ -601,7 +690,7 @@ longlong
Item_func_nullif::val_int()
{
longlong value;
- if (!(this->*cmp_func)() || null_value)
+ if (!cmp.compare() || null_value)
{
null_value=1;
return 0;
@@ -615,7 +704,7 @@ String *
Item_func_nullif::val_str(String *str)
{
String *res;
- if (!(this->*cmp_func)() || null_value)
+ if (!cmp.compare() || null_value)
{
null_value=1;
return 0;
@@ -694,6 +783,11 @@ Item *Item_func_case::find_item(String *str)
}
if (args[i]->val()==first_expr_real && !args[i]->null_value)
return args[i+1];
+ break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
}
// No, WHEN clauses all missed, return ELSE expression
@@ -756,8 +850,10 @@ double Item_func_case::val()
bool
Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- if (first_expr && first_expr->fix_fields(thd, tables, &first_expr) ||
- else_expr && else_expr->fix_fields(thd, tables, &else_expr))
+ if (first_expr && (first_expr->check_cols(1) ||
+ first_expr->fix_fields(thd, tables, &first_expr)) ||
+ else_expr && (else_expr->check_cols(1) ||
+ else_expr->fix_fields(thd, tables, &else_expr)))
return 1;
if (Item_func::fix_fields(thd, tables, ref))
return 1;
@@ -776,6 +872,16 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
+bool Item_func_case::check_loop(uint id)
+{
+ DBUG_ENTER("Item_func_case::check_loop");
+ if (Item_func::check_loop(id))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN((first_expr && first_expr->check_loop(id)) ||
+ (else_expr && else_expr->check_loop(id)));
+}
+
void Item_func_case::update_used_tables()
{
Item_func::update_used_tables();
@@ -989,6 +1095,10 @@ void Item_func_in::fix_length_and_dec()
case REAL_RESULT:
array= new in_double(arg_count);
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
uint j=0;
for (uint i=0 ; i < arg_count ; i++)
@@ -1015,6 +1125,10 @@ void Item_func_in::fix_length_and_dec()
case REAL_RESULT:
in_item= new cmp_item_real;
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
}
maybe_null= item->maybe_null;
@@ -1061,6 +1175,18 @@ void Item_func_in::update_used_tables()
const_item_cache&=item->const_item();
}
+void Item_func_in::split_sum_func(List<Item> &fields)
+{
+ if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
+ item->split_sum_func(fields);
+ else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
+ {
+ fields.push_front(item);
+ item=new Item_ref((Item**) fields.head_ref(),0,item->name);
+ }
+ Item_func::split_sum_func(fields);
+}
+
longlong Item_func_bit_or::val_int()
{
@@ -1123,7 +1249,9 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
#endif
item= *li.ref(); // new current item
}
- if (item->fix_fields(thd, tables, li.ref()))
+ if (abort_on_null)
+ item->top_level_item();
+ if (item->check_cols(1) || item->fix_fields(thd, tables, li.ref()))
return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func;
@@ -1134,9 +1262,24 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (thd)
thd->cond_count+=list.elements;
fix_length_and_dec();
+ fixed= 1;
return 0;
}
+bool Item_cond::check_loop(uint id)
+{
+ DBUG_ENTER("Item_cond::check_loop");
+ if (Item_func::check_loop(id))
+ DBUG_RETURN(1);
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ {
+ if (item->check_loop(id))
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
void Item_cond::split_sum_func(List<Item> &fields)
{
@@ -1198,28 +1341,41 @@ void Item_cond::print(String *str)
str->append(')');
}
+/*
+ Evalution of AND(expr, expr, expr ...)
+
+ NOTES:
+ abort_if_null is set for AND expressions for which we don't care if the
+ result is NULL or 0. This is set for:
+ - WHERE clause
+ - HAVING clause
+ - IF(expression)
+
+ RETURN VALUES
+ 1 If all expressions are true
+ 0 If all expressions are false or if we find a NULL expression and
+ 'abort_on_null' is set.
+ NULL if all expression are either 1 or NULL
+*/
+
longlong Item_cond_and::val_int()
{
List_iterator_fast<Item> li(list);
Item *item;
+ null_value= 0;
while ((item=li++))
{
if (item->val_int() == 0)
{
- /*
- TODO: In case of NULL, ANSI would require us to continue evaluation
- until we get a FALSE value or run out of values; This would
- require a lot of unnecessary evaluation, which we skip for now
- */
- null_value=item->null_value;
- return 0;
+ if (abort_on_null || !(null_value= item->null_value))
+ return 0; // return FALSE
}
}
- null_value=0;
- return 1;
+ return null_value ? 0 : 1;
}
+
longlong Item_cond_or::val_int()
{
List_iterator_fast<Item> li(list);
@@ -1238,6 +1394,45 @@ longlong Item_cond_or::val_int()
return 0;
}
+/*
+ Create an AND expression from two expressions
+
+ SYNOPSIS
+ and_expressions()
+ a expression or NULL
+ b expression.
+ org_item Don't modify a if a == *org_item
+ If a == NULL, org_item is set to point at b,
+ to ensure that future calls will not modify b.
+
+ NOTES
+ This will not modify item pointed to by org_item or b
+ The idea is that one can call this in a loop and create and
+ 'and' over all items without modifying any of the original items.
+
+ RETURN
+ NULL Error
+ Item
+*/
+
+Item *and_expressions(Item *a, Item *b, Item **org_item)
+{
+ if (!a)
+ return (*org_item= (Item*) b);
+ if (a == *org_item)
+ {
+ Item_cond *res;
+ if ((res= new Item_cond_and(a, (Item*) b)))
+ res->used_tables_cache= a->used_tables() | b->used_tables();
+ return res;
+ }
+ if (((Item_cond_and*) a)->add((Item*) b))
+ return 0;
+ ((Item_cond_and*) a)->used_tables_cache|= b->used_tables();
+ return a;
+}
+
+
longlong Item_func_isnull::val_int()
{
/*
@@ -1281,10 +1476,10 @@ longlong Item_func_like::val_int()
set_charset(my_charset_bin);
if (canDoTurboBM)
return turboBM_matches(res->ptr(), res->length()) ? 1 : 0;
- if (binary())
- return wild_compare(*res,*res2,escape) ? 0 : 1;
- else
- return wild_case_compare(*res,*res2,escape) ? 0 : 1;
+ return my_wildcmp(charset(),
+ res->ptr(),res->ptr()+res->length(),
+ res2->ptr(),res2->ptr()+res2->length(),
+ escape,wild_one,wild_many) ? 0 : 1;
}
@@ -1358,7 +1553,9 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
bool
Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- if (args[0]->fix_fields(thd, tables, args) ||
+ if (args[0]->check_cols(1) ||
+ args[1]->check_cols(1) ||
+ args[0]->fix_fields(thd, tables, args) ||
args[1]->fix_fields(thd,tables, args + 1))
return 1; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
@@ -1393,6 +1590,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
else
maybe_null=1;
+ fixed= 1;
return 0;
}
@@ -1623,7 +1821,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
i -= u;
}
if (i < 0)
- return true;
+ return 1;
register const int v = plm1 - i;
turboShift = u - v;
@@ -1640,7 +1838,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
}
j += shift;
}
- return false;
+ return 0;
}
else
{
@@ -1654,7 +1852,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
i -= u;
}
if (i < 0)
- return true;
+ return 1;
register const int v = plm1 - i;
turboShift = u - v;
@@ -1671,7 +1869,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
}
j += shift;
}
- return false;
+ return 0;
}
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c0dcc2bba8f..b4f4872bd95 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -21,6 +21,63 @@
#pragma interface /* gcc class implementation */
#endif
+extern Item_result item_cmp_type(Item_result a,Item_result b);
+class Item_bool_func2;
+class Arg_comparator;
+
+typedef int (Arg_comparator::*arg_cmp_func)();
+
+class Arg_comparator: public Sql_alloc
+{
+ Item **a, **b;
+ arg_cmp_func func;
+ Item_bool_func2 *owner;
+ Arg_comparator *comparators; // used only for compare_row()
+
+public:
+ Arg_comparator() {};
+ Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {};
+
+ inline void seta(Item **item) { a= item; }
+ inline void setb(Item **item) { b= item; }
+
+ int set_compare_func(Item_bool_func2 *owner, Item_result type);
+ inline int set_compare_func(Item_bool_func2 *owner)
+ {
+ return set_compare_func(owner, item_cmp_type((*a)->result_type(),
+ (*b)->result_type()));
+ }
+
+ inline int set_cmp_func(Item_bool_func2 *owner,
+ Item **a1, Item **a2,
+ Item_result type)
+ {
+ a= a1;
+ b= a2;
+ return set_compare_func(owner, type);
+ }
+ inline int set_cmp_func(Item_bool_func2 *owner,
+ Item **a1, Item **a2)
+ {
+ return set_cmp_func(owner, a1, a2, item_cmp_type((*a1)->result_type(),
+ (*a2)->result_type()));
+ }
+ inline int compare() { return (this->*func)(); }
+
+ int compare_string(); // compare args[0] & args[1]
+ int compare_real(); // compare args[0] & args[1]
+ int compare_int(); // compare args[0] & args[1]
+ int compare_row(); // compare args[0] & args[1]
+ int compare_e_string(); // compare args[0] & args[1]
+ int compare_e_real(); // compare args[0] & args[1]
+ int compare_e_int(); // compare args[0] & args[1]
+ int compare_e_row(); // compare args[0] & args[1]
+
+ static arg_cmp_func comparator_matrix [4][2];
+
+ friend class Item_func;
+};
+
class Item_bool_func :public Item_int_func
{
public:
@@ -33,22 +90,40 @@ public:
class Item_bool_func2 :public Item_int_func
{ /* Bool with 2 string args */
protected:
+ Arg_comparator cmp;
String tmp_value1,tmp_value2;
public:
- Item_bool_func2(Item *a,Item *b) :Item_int_func(a,b) {}
+ 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(Item_result type);
- int (Item_bool_func2::*cmp_func)();
- int compare_string(); /* compare arg[0] & arg[1] */
- int compare_real(); /* compare arg[0] & arg[1] */
- int compare_int(); /* compare arg[0] & arg[1] */
+ void set_cmp_func()
+ {
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1);
+ }
optimize_type select_optimize() const { return OPTIMIZE_OP; }
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); }
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
+
+ static Item_bool_func2* eq_creator(Item *a, Item *b);
+ static Item_bool_func2* ne_creator(Item *a, Item *b);
+ static Item_bool_func2* gt_creator(Item *a, Item *b);
+ static Item_bool_func2* lt_creator(Item *a, Item *b);
+ static Item_bool_func2* ge_creator(Item *a, Item *b);
+ static Item_bool_func2* le_creator(Item *a, Item *b);
+
+ friend class Arg_comparator;
};
+class Item_bool_rowready_func2 :public Item_bool_func2
+{
+public:
+ Item_bool_rowready_func2(Item *a,Item *b) :Item_bool_func2(a,b)
+ {
+ allowed_arg_cols= a->cols();
+ }
+};
class Item_func_not :public Item_bool_func
{
@@ -58,10 +133,10 @@ public:
const char *func_name() const { return "not"; }
};
-class Item_func_eq :public Item_bool_func2
+class Item_func_eq :public Item_bool_rowready_func2
{
public:
- Item_func_eq(Item *a,Item *b) :Item_bool_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; }
@@ -69,11 +144,10 @@ public:
const char *func_name() const { return "="; }
};
-class Item_func_equal :public Item_bool_func2
+class Item_func_equal :public Item_bool_rowready_func2
{
- Item_result cmp_result_type;
public:
- Item_func_equal(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_equal(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
longlong val_int();
void fix_length_and_dec();
enum Functype functype() const { return EQUAL_FUNC; }
@@ -83,10 +157,10 @@ public:
};
-class Item_func_ge :public Item_bool_func2
+class Item_func_ge :public Item_bool_rowready_func2
{
public:
- Item_func_ge(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_ge(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { };
longlong val_int();
enum Functype functype() const { return GE_FUNC; }
enum Functype rev_functype() const { return LE_FUNC; }
@@ -95,10 +169,10 @@ public:
};
-class Item_func_gt :public Item_bool_func2
+class Item_func_gt :public Item_bool_rowready_func2
{
public:
- Item_func_gt(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_gt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { };
longlong val_int();
enum Functype functype() const { return GT_FUNC; }
enum Functype rev_functype() const { return LT_FUNC; }
@@ -107,10 +181,10 @@ public:
};
-class Item_func_le :public Item_bool_func2
+class Item_func_le :public Item_bool_rowready_func2
{
public:
- Item_func_le(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_le(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { };
longlong val_int();
enum Functype functype() const { return LE_FUNC; }
enum Functype rev_functype() const { return GE_FUNC; }
@@ -119,10 +193,10 @@ public:
};
-class Item_func_lt :public Item_bool_func2
+class Item_func_lt :public Item_bool_rowready_func2
{
public:
- Item_func_lt(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ Item_func_lt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { }
longlong val_int();
enum Functype functype() const { return LT_FUNC; }
enum Functype rev_functype() const { return GT_FUNC; }
@@ -131,10 +205,10 @@ public:
};
-class Item_func_ne :public Item_bool_func2
+class Item_func_ne :public Item_bool_rowready_func2
{
public:
- Item_func_ne(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ Item_func_ne(Item *a,Item *b) :Item_bool_rowready_func2(a,b) { }
longlong val_int();
enum Functype functype() const { return NE_FUNC; }
cond_result eq_cmp_result() const { return COND_FALSE; }
@@ -179,13 +253,15 @@ public:
longlong val_int();
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref)
{
- return (item->fix_fields(thd, tlist, &item) ||
+ return (item->check_cols(1) ||
+ item->fix_fields(thd, tlist, &item) ||
Item_func::fix_fields(thd, tlist, ref));
}
void fix_length_and_dec();
~Item_func_interval() { delete item; }
const char *func_name() const { return "interval"; }
void update_used_tables();
+ bool check_loop(uint id);
};
@@ -212,6 +288,11 @@ public:
longlong val_int();
String *val_str(String *str);
enum Item_result result_type () const { return cached_result_type; }
+ bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
+ {
+ args[0]->top_level_item();
+ return Item_func::fix_fields(thd, tlist, ref);
+ }
void fix_length_and_dec();
const char *func_name() const { return "if"; }
};
@@ -262,6 +343,7 @@ public:
void print(String *str);
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
Item *find_item(String *str);
+ bool check_loop(uint id);
};
@@ -284,9 +366,9 @@ public:
virtual void set(uint pos,Item *item)=0;
virtual byte *get_value(Item *item)=0;
void sort()
- {
- qsort(base,used_count,size,compare);
- }
+ {
+ qsort(base,used_count,size,compare);
+ }
int find(Item *item);
};
@@ -412,8 +494,11 @@ class Item_func_in :public Item_int_func
longlong val_int();
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref)
{
- return (item->fix_fields(thd, tlist, &item) ||
- Item_func::fix_fields(thd, tlist, ref));
+ bool res=(item->check_cols(1) ||
+ item->fix_fields(thd, tlist, &item) ||
+ Item_func::fix_fields(thd, tlist, ref));
+ with_sum_func= with_sum_func || item->with_sum_func;
+ return res;
}
void fix_length_and_dec();
~Item_func_in() { delete item; delete array; delete in_item; }
@@ -424,6 +509,14 @@ class Item_func_in :public Item_int_func
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
void update_used_tables();
+ void split_sum_func(List<Item> &fields);
+ bool check_loop(uint id)
+ {
+ DBUG_ENTER("Item_func_in::check_loop");
+ if (Item_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(item->check_loop(id));
+ }
};
@@ -548,10 +641,12 @@ class Item_cond :public Item_bool_func
{
protected:
List<Item> list;
+ bool abort_on_null;
public:
- Item_cond() : Item_bool_func() { const_item_cache=0; }
- Item_cond(Item *i1,Item *i2) :Item_bool_func()
- { list.push_back(i1); list.push_back(i2); }
+ /* 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() { list.delete_elements(); }
bool add(Item *item) { return list.push_back(item); }
bool fix_fields(THD *, struct st_table_list *, Item **ref);
@@ -563,6 +658,8 @@ public:
void print(String *str);
void split_sum_func(List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
+ bool check_loop(uint id);
+ void top_level_item() { abort_on_null=1; }
};
@@ -610,6 +707,7 @@ inline Item *and_conds(Item *a,Item *b)
return cond;
}
+Item *and_expressions(Item *a, Item *b, Item **org_item);
/**************************************************************
Spatial relations
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e4c9a160686..259427af901 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -52,6 +52,13 @@ 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);
@@ -76,7 +83,7 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
THD *thd=current_thd;
- thd->safe_to_cache_query=0;
+ thd->lex.safe_to_cache_query=0;
return new Item_int("CONNECTION_ID()",(longlong) thd->thread_id,10);
}
@@ -149,7 +156,7 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
THD *thd=current_thd;
- thd->safe_to_cache_query=0;
+ thd->lex.safe_to_cache_query=0;
return new Item_int("FOUND_ROWS()",(longlong) thd->found_rows(),21);
}
@@ -160,7 +167,7 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.safe_to_cache_query=0;
return new Item_func_get_lock(a, b);
}
@@ -308,7 +315,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.safe_to_cache_query=0;
return new Item_func_release_lock(a);
}
@@ -416,13 +423,13 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.safe_to_cache_query=0;
return new Item_load_file(a);
}
Item *create_wait_for_master_pos(Item* a, Item* b)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.safe_to_cache_query=0;
return new Item_master_pos_wait(a, b);
}
@@ -432,6 +439,7 @@ Item *create_func_cast(Item *a, Item_cast cast_type)
LINT_INIT(res);
switch (cast_type) {
case ITEM_CAST_BINARY: res= new Item_func_binary(a); break;
+ case ITEM_CAST_CHAR: res= new Item_char_typecast(a); break;
case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break;
case ITEM_CAST_UNSIGNED_INT: res= new Item_func_unsigned(a); break;
case ITEM_CAST_DATE: res= new Item_date_typecast(a); break;
@@ -443,7 +451,7 @@ Item *create_func_cast(Item *a, Item_cast cast_type)
Item *create_func_is_free_lock(Item* a)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.safe_to_cache_query=0;
return new Item_func_is_free_lock(a);
}
diff --git a/sql/item_create.h b/sql/item_create.h
index 6d9cef04c13..937ea782273 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -66,6 +66,7 @@ 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);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8b2b2fc83a3..c84b554b522 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -39,7 +39,8 @@ eval_const_cond(COND *cond)
}
-Item_func::Item_func(List<Item> &list)
+Item_func::Item_func(List<Item> &list):
+ allowed_arg_cols(1)
{
arg_count=list.elements;
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
@@ -107,11 +108,10 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Set return character set to first argument if we are returning a
string.
*/
- if (result_type() == STRING_RESULT)
- set_charset((*args)->charset());
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
- if ((*arg)->fix_fields(thd, tables, arg))
+ if ((*arg)->check_cols(allowed_arg_cols) ||
+ (*arg)->fix_fields(thd, tables, arg))
return 1; /* purecov: inspected */
if ((*arg)->maybe_null)
maybe_null=1;
@@ -121,11 +121,30 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
used_tables_cache|=(*arg)->used_tables();
const_item_cache&= (*arg)->const_item();
}
+ if (result_type() == STRING_RESULT)
+ set_charset((*args)->charset());
}
fix_length_and_dec();
+ fixed= 1;
return 0;
}
+bool Item_func::check_loop(uint id)
+{
+ DBUG_ENTER("Item_func::check_loop");
+ if (Item_result_field::check_loop(id))
+ DBUG_RETURN(1);
+ if (arg_count)
+ {
+ Item **arg,**arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ {
+ if ((*arg)->check_loop(id))
+ DBUG_RETURN(1);
+ }
+ }
+ DBUG_RETURN(0);
+}
void Item_func::split_sum_func(List<Item> &fields)
{
@@ -232,6 +251,10 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
else
res= new Field_string(max_length, maybe_null, name, t_arg, charset());
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
return res;
}
@@ -243,7 +266,7 @@ String *Item_real_func::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -256,9 +279,9 @@ String *Item_num_func::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else if (!unsigned_flag)
- str->set(nr,my_thd_charset);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr,my_thd_charset);
+ str->set((ulonglong) nr,thd_charset());
}
else
{
@@ -266,7 +289,7 @@ String *Item_num_func::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
}
return str;
}
@@ -286,9 +309,9 @@ String *Item_int_func::val_str(String *str)
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr,my_thd_charset);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr,my_thd_charset);
+ str->set((ulonglong) nr,thd_charset());
return str;
}
@@ -315,9 +338,9 @@ String *Item_num_op::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else if (!unsigned_flag)
- str->set(nr,my_thd_charset);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr,my_thd_charset);
+ str->set((ulonglong) nr,thd_charset());
}
else
{
@@ -325,7 +348,7 @@ String *Item_num_op::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
}
return str;
}
@@ -439,6 +462,25 @@ void Item_func_div::fix_length_and_dec()
maybe_null=1;
}
+
+/* Integer division */
+longlong Item_func_int_div::val_int()
+{
+ longlong value=args[0]->val_int();
+ longlong val2=args[1]->val_int();
+ if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value))
+ return 0;
+ return value/val2;
+}
+
+
+void Item_func_int_div::fix_length_and_dec()
+{
+ max_length=args[0]->max_length - args[0]->decimals;
+ maybe_null=1;
+}
+
+
double Item_func_mod::val()
{
double value= floor(args[0]->val()+0.5);
@@ -737,33 +779,39 @@ double Item_func_round::val()
}
-double Item_func_rand::val()
+void Item_func_rand::fix_length_and_dec()
{
- THD* thd = current_thd;
+ decimals=NOT_FIXED_DEC;
+ max_length=float_length(decimals);
if (arg_count)
{ // Only use argument once in query
uint32 tmp= (uint32) (args[0]->val_int());
- randominit(&thd->rand,(uint32) (tmp*0x10001L+55555555L),
- (uint32) (tmp*0x10000001L));
-#ifdef DELETE_ITEMS
- delete args[0];
-#endif
- arg_count=0;
+ if ((rand= (struct rand_struct*) sql_alloc(sizeof(*rand))))
+ randominit(rand,(uint32) (tmp*0x10001L+55555555L),
+ (uint32) (tmp*0x10000001L));
}
- else if (!thd->rand_used)
+ else
{
- // no need to send a Rand log event if seed was given eg: RAND(seed),
- // as it will be replicated in the query as such.
-
- // save the seed only the first time RAND() is used in the query
+ THD *thd= current_thd;
+ /*
+ No need to send a Rand log event if seed was given eg: RAND(seed),
+ as it will be replicated in the query as such.
- // once events are forwarded rather than recreated,
- // the following can be skipped if inside the slave thread
+ Save the seed only the first time RAND() is used in the query
+ Once events are forwarded rather than recreated,
+ the following can be skipped if inside the slave thread
+ */
thd->rand_used=1;
thd->rand_saved_seed1=thd->rand.seed1;
thd->rand_saved_seed2=thd->rand.seed2;
+ rand= &thd->rand;
}
- return rnd(&thd->rand);
+}
+
+
+double Item_func_rand::val()
+{
+ return rnd(rand);
}
longlong Item_func_sign::val_int()
@@ -813,9 +861,9 @@ String *Item_func_min_max::val_str(String *str)
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr,my_thd_charset);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr,my_thd_charset);
+ str->set((ulonglong) nr,thd_charset());
return str;
}
case REAL_RESULT:
@@ -824,7 +872,7 @@ String *Item_func_min_max::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
case STRING_RESULT:
@@ -853,6 +901,11 @@ String *Item_func_min_max::val_str(String *str)
}
return res;
}
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
+
}
return 0; // Keep compiler happy
}
@@ -1260,7 +1313,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
- if ((*arg)->fix_fields(thd, tables, arg))
+ if ((*arg)->check_cols(1) || (*arg)->fix_fields(thd, tables, arg))
return 1;
if ((*arg)->binary())
func->set_charset(my_charset_bin);
@@ -1389,6 +1442,10 @@ bool udf_handler::get_arguments()
to+= ALIGN_SIZE(sizeof(double));
}
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ ;
}
}
return 0;
@@ -1447,7 +1504,7 @@ String *Item_func_udf_float::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -1468,9 +1525,9 @@ String *Item_func_udf_int::val_str(String *str)
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr,my_thd_charset);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr,my_thd_charset);
+ str->set((ulonglong) nr,thd_charset());
return str;
}
@@ -1568,10 +1625,10 @@ void item_user_lock_release(ULL *ull)
char buf[256];
const char *command="DO RELEASE_LOCK(\"";
String tmp(buf,sizeof(buf), system_charset_info);
- tmp.copy(command, strlen(command));
+ tmp.copy(command, strlen(command), tmp.charset());
tmp.append(ull->key,ull->key_length);
tmp.append("\")");
- Query_log_event qev(current_thd,tmp.ptr(), tmp.length());
+ Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1);
qev.error_code=0; // this query is always safe to run on slave
mysql_bin_log.write(&qev);
}
@@ -1841,6 +1898,10 @@ longlong Item_func_benchmark::val_int()
case STRING_RESULT:
(void) args[0]->val_str(&tmp);
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
}
return 0;
@@ -1967,11 +2028,17 @@ Item_func_set_user_var::update()
(void) val_int();
break;
case STRING_RESULT:
+ {
char buffer[MAX_FIELD_WIDTH];
String tmp(buffer,sizeof(buffer),default_charset_info);
(void) val_str(&tmp);
break;
}
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
+ }
return current_thd->fatal_error;
}
@@ -2016,13 +2083,13 @@ void Item_func_set_user_var::print(String *str)
user_var_entry *Item_func_get_user_var::get_entry()
{
- if (!entry || ! entry->value)
+ if (!var_entry || ! var_entry->value)
{
null_value=1;
return 0;
}
null_value=0;
- return entry;
+ return var_entry;
}
@@ -2034,18 +2101,21 @@ Item_func_get_user_var::val_str(String *str)
return NULL;
switch (entry->type) {
case REAL_RESULT:
- str->set(*(double*) entry->value,decimals,my_thd_charset);
+ str->set(*(double*) entry->value,decimals,thd_charset());
break;
case INT_RESULT:
- str->set(*(longlong*) entry->value,my_thd_charset);
+ str->set(*(longlong*) entry->value,thd_charset());
break;
case STRING_RESULT:
- if (str->copy(entry->value, entry->length-1))
+ if (str->copy(entry->value, entry->length-1, entry->var_charset))
{
null_value=1;
return NULL;
}
- str->set_charset(entry->var_charset);
+ break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
break;
}
return str;
@@ -2064,6 +2134,10 @@ double Item_func_get_user_var::val()
return (double) *(longlong*) entry->value;
case STRING_RESULT:
return atof(entry->value); // This is null terminated
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
return 0.0; // Impossible
}
@@ -2081,6 +2155,10 @@ longlong Item_func_get_user_var::val_int()
return *(longlong*) entry->value;
case STRING_RESULT:
return strtoull(entry->value,NULL,10); // String is null terminated
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
return LL(0); // Impossible
}
@@ -2092,8 +2170,8 @@ void Item_func_get_user_var::fix_length_and_dec()
maybe_null=1;
decimals=NOT_FIXED_DEC;
max_length=MAX_BLOB_WIDTH;
- if ((entry= get_variable(&thd->user_vars, name, 0)))
- const_var_flag= thd->query_id != entry->update_query_id;
+ if ((var_entry= get_variable(&thd->user_vars, name, 0)))
+ const_var_flag= thd->query_id != var_entry->update_query_id;
}
@@ -2241,7 +2319,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
while ((item=li++))
{
- if (item->fix_fields(thd, tlist, li.ref()))
+ if (item->check_cols(1) || item->fix_fields(thd, tlist, li.ref()))
return 1;
if (item->type() == Item::REF_ITEM)
li.replace(item= *((Item_ref *)item)->ref);
@@ -2265,23 +2343,36 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
return 0;
}
+bool Item_func_match::check_loop(uint id)
+{
+ DBUG_ENTER("Item_func_match::check_loop");
+ if (Item_real_func::check_loop(id))
+ DBUG_RETURN(1);
+
+ List_iterator<Item> li(fields);
+ Item *item;
+ while ((item= li++))
+ if (item->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
bool Item_func_match::fix_index()
{
List_iterator_fast<Item> li(fields);
Item_field *item;
- uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key;
+ uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, keynr;
uint max_cnt=0, mkeys=0;
- if (this->key == NO_SUCH_KEY)
+ if (key == NO_SUCH_KEY)
return 0;
- for (key=0 ; key<table->keys ; key++)
+ for (keynr=0 ; keynr < table->keys ; keynr++)
{
- if ((table->key_info[key].flags & HA_FULLTEXT) &&
- (table->keys_in_use_for_query & (((key_map)1) << key)))
+ if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
+ (table->keys_in_use_for_query & (((key_map)1) << keynr)))
{
- ft_to_key[fts]=key;
+ ft_to_key[fts]=keynr;
ft_cnt[fts]=0;
fts++;
}
@@ -2292,45 +2383,45 @@ bool Item_func_match::fix_index()
while ((item=(Item_field*)(li++)))
{
- for (key=0 ; key<fts ; key++)
+ for (keynr=0 ; keynr < fts ; keynr++)
{
- KEY *ft_key=&table->key_info[ft_to_key[key]];
+ KEY *ft_key=&table->key_info[ft_to_key[keynr]];
uint key_parts=ft_key->key_parts;
for (uint part=0 ; part < key_parts ; part++)
{
if (item->field->eq(ft_key->key_part[part].field))
- ft_cnt[key]++;
+ ft_cnt[keynr]++;
}
}
}
- for (key=0 ; key<fts ; key++)
+ for (keynr=0 ; keynr < fts ; keynr++)
{
- if (ft_cnt[key] > max_cnt)
+ if (ft_cnt[keynr] > max_cnt)
{
mkeys=0;
- max_cnt=ft_cnt[mkeys]=ft_cnt[key];
- ft_to_key[mkeys]=ft_to_key[key];
+ max_cnt=ft_cnt[mkeys]=ft_cnt[keynr];
+ ft_to_key[mkeys]=ft_to_key[keynr];
continue;
}
- if (max_cnt && ft_cnt[key] == max_cnt)
+ if (max_cnt && ft_cnt[keynr] == max_cnt)
{
mkeys++;
- ft_cnt[mkeys]=ft_cnt[key];
- ft_to_key[mkeys]=ft_to_key[key];
+ ft_cnt[mkeys]=ft_cnt[keynr];
+ ft_to_key[mkeys]=ft_to_key[keynr];
continue;
}
}
- for (key=0 ; key<=mkeys ; key++)
+ for (keynr=0 ; keynr <= mkeys ; keynr++)
{
// for now, partial keys won't work. SerG
if (max_cnt < fields.elements ||
- max_cnt < table->key_info[ft_to_key[key]].key_parts)
+ max_cnt < table->key_info[ft_to_key[keynr]].key_parts)
continue;
- this->key=ft_to_key[key];
+ key=ft_to_key[keynr];
return 0;
}
@@ -2338,7 +2429,7 @@ bool Item_func_match::fix_index()
err:
if (mode == FT_BOOL)
{
- this->key=NO_SUCH_KEY;
+ key=NO_SUCH_KEY;
return 0;
}
my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND,
@@ -2422,7 +2513,7 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name)
}
if (!(item=var->item(thd, var_type)))
return 0; // Impossible
- thd->safe_to_cache_query=0;
+ thd->lex.safe_to_cache_query=0;
buff[0]='@';
buff[1]='@';
pos=buff+2;
@@ -2448,7 +2539,7 @@ Item *get_system_var(enum_var_type var_type, const char *var_name, uint length,
DBUG_ASSERT(var != 0);
if (!(item=var->item(thd, var_type)))
return 0; // Impossible
- thd->safe_to_cache_query=0;
+ thd->lex.safe_to_cache_query=0;
item->set_name(item_name); // Will use original name
return item;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 1e1f2ba39fc..98e56af368c 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -31,7 +31,8 @@ extern "C" /* Bug in BSDI include file */
class Item_func :public Item_result_field
{
protected:
- Item **args,*tmp_arg[2];
+ Item **args, *tmp_arg[2];
+ uint allowed_arg_cols;
public:
uint arg_count;
table_map used_tables_cache;
@@ -49,53 +50,57 @@ public:
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
- Item_func(void)
+ Item_func(void):
+ allowed_arg_cols(1), arg_count(0)
{
- arg_count=0; with_sum_func=0;
+ with_sum_func= 0;
}
- Item_func(Item *a)
+ Item_func(Item *a):
+ allowed_arg_cols(1), arg_count(1)
{
- arg_count=1;
- args=tmp_arg;
- args[0]=a;
- with_sum_func=a->with_sum_func;
+ args= tmp_arg;
+ args[0]= a;
+ with_sum_func= a->with_sum_func;
}
- Item_func(Item *a,Item *b)
+ Item_func(Item *a,Item *b):
+ allowed_arg_cols(1), arg_count(2)
{
- arg_count=2;
- args=tmp_arg;
- args[0]=a; args[1]=b;
- with_sum_func=a->with_sum_func || b->with_sum_func;
+ args= tmp_arg;
+ args[0]= a; args[1]= b;
+ with_sum_func= a->with_sum_func || b->with_sum_func;
}
- Item_func(Item *a,Item *b,Item *c)
+ Item_func(Item *a,Item *b,Item *c):
+ allowed_arg_cols(1)
{
- arg_count=0;
- if ((args=(Item**) sql_alloc(sizeof(Item*)*3)))
+ arg_count= 0;
+ if ((args= (Item**) sql_alloc(sizeof(Item*)*3)))
{
- arg_count=3;
- args[0]=a; args[1]=b; args[2]=c;
- with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func;
+ arg_count= 3;
+ args[0]= a; args[1]= b; args[2]= c;
+ with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func;
}
}
- Item_func(Item *a,Item *b,Item *c,Item *d)
+ Item_func(Item *a,Item *b,Item *c,Item *d):
+ allowed_arg_cols(1)
{
- arg_count=0;
- if ((args=(Item**) sql_alloc(sizeof(Item*)*4)))
+ arg_count= 0;
+ if ((args= (Item**) sql_alloc(sizeof(Item*)*4)))
{
- arg_count=4;
- args[0]=a; args[1]=b; args[2]=c; args[3]=d;
- with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func ||
- d->with_sum_func;
+ arg_count= 4;
+ args[0]= a; args[1]= b; args[2]= c; args[3]= d;
+ with_sum_func= a->with_sum_func || b->with_sum_func ||
+ c->with_sum_func || d->with_sum_func;
}
}
- Item_func(Item *a,Item *b,Item *c,Item *d,Item* e)
+ Item_func(Item *a,Item *b,Item *c,Item *d,Item* e):
+ allowed_arg_cols(1)
{
- arg_count=5;
- if ((args=(Item**) sql_alloc(sizeof(Item*)*5)))
+ arg_count= 5;
+ if ((args= (Item**) sql_alloc(sizeof(Item*)*5)))
{
- args[0]=a; args[1]=b; args[2]=c; args[3]=d; args[4]=e;
- with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func ||
- d->with_sum_func || e->with_sum_func ;
+ args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e;
+ with_sum_func= a->with_sum_func || b->with_sum_func ||
+ c->with_sum_func || d->with_sum_func || e->with_sum_func ;
}
}
Item_func(List<Item> &list);
@@ -128,6 +133,7 @@ public:
bool is_null() { (void) val_int(); return null_value; }
friend class udf_handler;
Field *tmp_table_field(TABLE *t_arg);
+ bool check_loop(uint id);
};
@@ -253,6 +259,18 @@ public:
};
+class Item_func_int_div :public Item_num_op
+{
+public:
+ Item_func_int_div(Item *a,Item *b) :Item_num_op(a,b)
+ { hybrid_type=INT_RESULT; }
+ double val() { return (double) val_int(); }
+ longlong val_int();
+ const char *func_name() const { return "DIV"; }
+ void fix_length_and_dec();
+};
+
+
class Item_func_mod :public Item_num_op
{
public:
@@ -466,14 +484,15 @@ public:
class Item_func_rand :public Item_real_func
{
+ struct rand_struct *rand;
public:
Item_func_rand(Item *a) :Item_real_func(a) {}
Item_func_rand() :Item_real_func() {}
double val();
const char *func_name() const { return "rand"; }
- void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
bool const_item() const { return 0; }
table_map used_tables() const { return RAND_TABLE_BIT; }
+ void fix_length_and_dec();
};
@@ -589,7 +608,8 @@ public:
longlong val_int();
bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
{
- return (item->fix_fields(thd, tlist, &item) ||
+ return (item->check_cols(1) ||
+ item->fix_fields(thd, tlist, &item) ||
Item_func::fix_fields(thd, tlist, ref));
}
void update_used_tables()
@@ -606,6 +626,13 @@ public:
const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
}
+ bool check_loop(uint id)
+ {
+ DBUG_ENTER("Item_func_field::check_loop");
+ if (Item_int_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(item->check_loop(id));
+ }
};
@@ -734,6 +761,7 @@ public:
bool res= udf.fix_fields(thd, tables, this, arg_count, args);
used_tables_cache= udf.used_tables_cache;
const_item_cache= udf.const_item_cache;
+ fixed= 1;
return res;
}
Item_result result_type () const { return udf.result_type(); }
@@ -780,12 +808,12 @@ public:
double val()
{
String *res; res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(),res->ptr(),res->length(),0) : 0.0;
}
longlong val_int()
{
String *res; res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),(char**) 0,10) : (longlong) 0;
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
@@ -898,7 +926,7 @@ public:
class Item_func_get_user_var :public Item_func
{
LEX_STRING name;
- user_var_entry *entry;
+ user_var_entry *var_entry;
bool const_var_flag;
public:
@@ -971,6 +999,7 @@ public:
bool fix_index();
void init_search(bool no_order);
+ bool check_loop(uint id);
};
@@ -1102,5 +1131,5 @@ public:
enum Item_cast
{
ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
- ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME
+ ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME, ITEM_CAST_CHAR
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
new file mode 100644
index 00000000000..464a8fd0ec5
--- /dev/null
+++ b/sql/item_row.cc
@@ -0,0 +1,66 @@
+/* Copyright (C) 2000 MySQL 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysql_priv.h"
+#include "assert.h"
+
+Item_row::Item_row(List<Item> &arg):
+ Item(), array_holder(1)
+{
+ if ((arg_count= arg.elements))
+ items= (Item**) sql_alloc(sizeof(Item*)*arg_count);
+ else
+ items= 0;
+ List_iterator<Item> li(arg);
+ uint i= 0;
+ Item *item;
+ while ((item= li++))
+ {
+ items[i]= item;
+ i++;
+ }
+}
+
+void Item_row::illegal_method_call(const char *method)
+{
+ DBUG_ENTER("Item_row::illegal_method_call");
+ DBUG_PRINT("error", ("!!! %s method was called for row item", method));
+ DBUG_ASSERT(0);
+ my_error(ER_CARDINALITY_COL, MYF(0), arg_count);
+ DBUG_VOID_RETURN;
+}
+
+bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
+{
+ tables= 0;
+ for (uint i= 0; i < arg_count; i++)
+ {
+ if (items[i]->fix_fields(thd, tabl, items+i))
+ return 1;
+ tables |= items[i]->used_tables();
+ }
+ return 0;
+}
+
+bool Item_row::check_cols(uint c)
+{
+ if (c != arg_count)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
diff --git a/sql/item_row.h b/sql/item_row.h
new file mode 100644
index 00000000000..5580250b4fb
--- /dev/null
+++ b/sql/item_row.h
@@ -0,0 +1,66 @@
+/* Copyright (C) 2000 MySQL 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+class Item_row: public Item
+{
+ bool array_holder;
+ table_map tables;
+ uint arg_count;
+ Item **items;
+public:
+ Item_row(List<Item> &);
+ Item_row(Item_row *item):
+ Item(), array_holder(0), tables(item->tables), arg_count(item->arg_count),
+ items(item->items)
+ {}
+
+ ~Item_row()
+ {
+ if(array_holder && items)
+ sql_element_free(items);
+ }
+
+ enum Type type() const { return ROW_ITEM; };
+ void illegal_method_call(const char *);
+ bool is_null() { return null_value; }
+ void make_field(Send_field *)
+ {
+ illegal_method_call((const char*)"make_field");
+ };
+ double val()
+ {
+ illegal_method_call((const char*)"val");
+ return 0;
+ };
+ longlong val_int()
+ {
+ illegal_method_call((const char*)"val_int");
+ return 0;
+ };
+ String *val_str(String *)
+ {
+ illegal_method_call((const char*)"val_str");
+ return 0;
+ };
+ bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+ table_map used_tables() const { return tables; };
+ enum Item_result result_type() const { return ROW_RESULT; }
+
+ virtual uint cols() { return arg_count; }
+ virtual Item* el(uint i) { return items[i]; }
+ virtual Item** addr(uint i) { return items + i; }
+ virtual bool check_cols(uint c);
+};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 20b01c9f1e8..473c4538ab1 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -54,14 +54,14 @@ double Item_str_func::val()
{
String *res;
res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(),res->ptr(),res->length(),NULL) : 0.0;
}
longlong Item_str_func::val_int()
{
String *res;
res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),NULL,10) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),NULL,10) : (longlong) 0;
}
@@ -124,12 +124,12 @@ String *Item_func_sha::val_str(String *str)
digest[8], digest[9], digest[10], digest[11],
digest[12], digest[13], digest[14], digest[15],
digest[16], digest[17], digest[18], digest[19]);
-
+
str->length((uint) SHA1_HASH_SIZE*2);
null_value=0;
return str;
}
- }
+ }
null_value=1;
return 0;
}
@@ -153,13 +153,13 @@ String *Item_func_aes_encrypt::val_str(String *str)
{
null_value=0;
aes_length=my_aes_get_size(sptr->length()); // Calculate result length
-
+
if (!str_value.alloc(aes_length)) // Ensure that memory is free
{
// finally encrypt directly to allocated buffer.
if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str_value.ptr(),
key->ptr(), key->length()) == aes_length)
- {
+ {
// We got the expected result length
str_value.length((uint) aes_length);
return &str_value;
@@ -197,7 +197,7 @@ String *Item_func_aes_decrypt::val_str(String *str)
(char*) str_value.ptr(),
key->ptr(), key->length());
if (length >= 0) // if we got correct data data
- {
+ {
str_value.length((uint) length);
DBUG_RETURN(&str_value);
}
@@ -328,7 +328,7 @@ void Item_func_concat::fix_length_and_dec()
}
}
-/*
+/*
Function des_encrypt() by tonu@spam.ee & monty
Works only if compiled with OpenSSL library support.
This returns a binary string where first character is CHAR(128 | key-number).
@@ -385,10 +385,10 @@ String *Item_func_des_encrypt::val_str(String *str)
des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
}
- /*
+ /*
The problem: DES algorithm requires original data to be in 8-bytes
- chunks. Missing bytes get filled with '*'s and result of encryption
- can be up to 8 bytes longer than original string. When decrypted,
+ chunks. Missing bytes get filled with '*'s and result of encryption
+ can be up to 8 bytes longer than original string. When decrypted,
we do not know the size of original string :(
We add one byte with value 0x1..0x8 as the last byte of the padded
string marking change of string length.
@@ -459,7 +459,7 @@ String *Item_func_des_decrypt::val_str(String *str)
// Here we set all 64-bit keys (56 effective) one by one
des_set_key_unchecked(&keyblock.key1,keyschedule.ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule.ks2);
- des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
+ des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
}
if (tmp_value.alloc(length-1))
goto error;
@@ -485,7 +485,7 @@ error:
}
-/*
+/*
concat with separator. First arg is the separator
concat_ws takes at least two arguments.
*/
@@ -683,7 +683,7 @@ String *Item_func_replace::val_str(String *str)
#ifdef USE_MB
const char *ptr,*end,*strend,*search,*search_end;
register uint32 l;
- bool binary_str;
+ bool binary_str;
#endif
null_value=0;
@@ -1279,11 +1279,26 @@ String *Item_func_password::val_str(String *str)
return 0;
if (res->length() == 0)
return &empty_string;
- make_scrambled_password(tmp_value,res->c_ptr());
+ make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords,
+ &current_thd->rand);
+ str->set(tmp_value,get_password_length(opt_old_passwords),res->charset());
+ return str;
+}
+
+String *Item_func_old_password::val_str(String *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 str;
}
+
+
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
String *Item_func_encrypt::val_str(String *str)
@@ -1363,20 +1378,30 @@ String *Item_func_decode::val_str(String *str)
String *Item_func_database::val_str(String *str)
{
- if (!current_thd->db)
+ THD *thd= current_thd;
+ if (!thd->db)
str->length(0);
else
- str->set((const char*) current_thd->db,(uint) strlen(current_thd->db), default_charset_info);
+ str->copy((const char*) thd->db,(uint) strlen(thd->db),
+ system_charset_info, thd->thd_charset);
return str;
}
String *Item_func_user::val_str(String *str)
{
- THD *thd=current_thd;
- if (str->copy((const char*) thd->user,(uint) strlen(thd->user)) ||
- str->append('@') ||
- str->append(thd->host ? thd->host : thd->ip ? thd->ip : ""))
- return &empty_string;
+ THD *thd=current_thd;
+ CHARSET_INFO *cs=thd->thd_charset;
+ const char *host=thd->host ? thd->host : thd->ip ? thd->ip : "";
+ uint32 res_length=(strlen(thd->user)+strlen(host)+10) * cs->mbmaxlen;
+
+ if (str->alloc(res_length))
+ {
+ null_value=1;
+ return 0;
+ }
+ res_length=cs->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s",thd->user,host);
+ str->length(res_length);
+ str->set_charset(cs);
return str;
}
@@ -1469,7 +1494,7 @@ String *Item_func_format::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
dec= decimals ? decimals+1 : 0;
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
str_length=str->length();
if (nr < 0)
str_length--; // Don't count sign
@@ -1637,7 +1662,7 @@ String *Item_func_char::val_str(String *str)
int32 num=(int32) args[i]->val_int();
if (!args[i]->null_value)
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ if (use_mb(charset()))
{
if (num&0xFF000000L) {
str->append((char)(num>>24));
@@ -1645,7 +1670,7 @@ String *Item_func_char::val_str(String *str)
} else if (num&0xFF0000L) {
b2: str->append((char)(num>>16));
goto b1;
- } else if (num&0xFF00L) {
+ } else if (num&0xFF00L) {
b1: str->append((char)(num>>8));
}
}
@@ -1895,11 +1920,11 @@ String *Item_func_conv::val_str(String *str)
}
null_value=0;
if (from_base < 0)
- dec= strtoll(res->c_ptr(),&endptr,-from_base);
+ dec= my_strntoll(res->charset(),res->ptr(),res->length(),&endptr,-from_base);
else
- dec= (longlong) strtoull(res->c_ptr(),&endptr,from_base);
+ dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),&endptr,from_base);
ptr= longlong2str(dec,ans,to_base);
- if (str->copy(ans,(uint32) (ptr-ans)))
+ if (str->copy(ans,(uint32) (ptr-ans), thd_charset()))
return &empty_string;
return str;
}
@@ -1914,25 +1939,25 @@ String *Item_func_conv_charset::val_str(String *str)
uint32 dmaxlen;
String *arg= args[0]->val_str(str);
CHARSET_INFO *from,*to;
-
+
if (!arg)
{
null_value=1;
return 0;
}
null_value=0;
-
+
from=arg->charset();
to=conv_charset;
s=(const uchar*)arg->ptr();
se=s+arg->length();
-
- dmaxlen=arg->length()*(to->mbmaxlen?to->mbmaxlen:1)+1;
+
+ dmaxlen=arg->length()*to->mbmaxlen+1;
str->alloc(dmaxlen);
d0=d=(unsigned char*)str->ptr();
de=d+dmaxlen;
-
+
while( s < se && d < de){
cnvres=from->mb_wc(from,&wc,s,se);
@@ -1962,7 +1987,7 @@ outp:
else
break;
};
-
+
str->length((uint32) (d-d0));
str->set_charset(to);
return str;
@@ -1970,7 +1995,7 @@ outp:
void Item_func_conv_charset::fix_length_and_dec()
{
- max_length = args[0]->max_length*(conv_charset->mbmaxlen?conv_charset->mbmaxlen:1);
+ max_length = args[0]->max_length*conv_charset->mbmaxlen;
set_charset(conv_charset);
}
@@ -1988,9 +2013,9 @@ String *Item_func_conv_charset3::val_str(String *str)
String *from_cs= args[2]->val_str(str);
CHARSET_INFO *from_charset;
CHARSET_INFO *to_charset;
-
- if (!arg || args[0]->null_value ||
- !to_cs || args[1]->null_value ||
+
+ if (!arg || args[0]->null_value ||
+ !to_cs || args[1]->null_value ||
!from_cs || args[2]->null_value ||
!(from_charset=get_charset_by_name(from_cs->ptr(), MYF(MY_WME))) ||
!(to_charset=get_charset_by_name(to_cs->ptr(), MYF(MY_WME))))
@@ -2001,12 +2026,12 @@ String *Item_func_conv_charset3::val_str(String *str)
s=(const uchar*)arg->ptr();
se=s+arg->length();
-
- dmaxlen=arg->length()*(to_charset->mbmaxlen?to_charset->mbmaxlen:1)+1;
+
+ dmaxlen=arg->length()*to_charset->mbmaxlen+1;
str->alloc(dmaxlen);
d0=d=(unsigned char*)str->ptr();
de=d+dmaxlen;
-
+
while( s < se && d < de){
cnvres=from_charset->mb_wc(from_charset,&wc,s,se);
@@ -2036,7 +2061,7 @@ outp:
else
break;
};
-
+
str->length((uint32) (d-d0));
str->set_charset(to_charset);
return str;
@@ -2048,15 +2073,16 @@ bool Item_func_conv_charset::fix_fields(THD *thd,struct st_table_list *tables, I
char buff[STACK_BUFF_ALLOC]; // Max argument in function
used_tables_cache=0;
const_item_cache=1;
-
+
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error if flag is set!
- if (args[0]->fix_fields(thd, tables, args))
+ if (args[0]->check_cols(1) || args[0]->fix_fields(thd, tables, args))
return 1;
maybe_null=args[0]->maybe_null;
const_item_cache=args[0]->const_item();
set_charset(conv_charset);
fix_length_and_dec();
+ fixed= 1;
return 0;
}
@@ -2080,10 +2106,10 @@ bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables,
char buff[STACK_BUFF_ALLOC]; // Max argument in function
used_tables_cache=0;
const_item_cache=1;
-
+
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error if flag is set!
- if (args[0]->fix_fields(thd, tables, args))
+ if (args[0]->check_cols(1) || args[0]->fix_fields(thd, tables, args))
return 1;
maybe_null=args[0]->maybe_null;
set_charset(set_collation);
@@ -2091,6 +2117,7 @@ bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables,
used_tables_cache=args[0]->used_tables();
const_item_cache=args[0]->const_item();
fix_length_and_dec();
+ fixed= 1;
return 0;
}
@@ -2120,7 +2147,8 @@ String *Item_func_charset::val_str(String *str)
if ((null_value=(args[0]->null_value || !res->charset())))
return 0;
- str->copy(res->charset()->name,strlen(res->charset()->name));
+ str->copy(res->charset()->name,strlen(res->charset()->name),
+ my_charset_latin1, thd_charset());
return str;
}
@@ -2135,7 +2163,7 @@ String *Item_func_hex::val_str(String *str)
if ((null_value= args[0]->null_value))
return 0;
ptr= longlong2str(dec,ans,16);
- if (str->copy(ans,(uint32) (ptr-ans)))
+ if (str->copy(ans,(uint32) (ptr-ans),default_charset_info))
return &empty_string; // End of memory
return str;
}
@@ -2209,11 +2237,11 @@ err:
String* Item_func_export_set::val_str(String* str)
{
ulonglong the_set = (ulonglong) args[0]->val_int();
- String yes_buf, *yes;
+ String yes_buf, *yes;
yes = args[1]->val_str(&yes_buf);
- String no_buf, *no;
+ String no_buf, *no;
no = args[2]->val_str(&no_buf);
- String *sep = NULL, sep_buf ;
+ String *sep = NULL, sep_buf ;
uint num_set_values = 64;
ulonglong mask = 0x1;
@@ -2287,7 +2315,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
int4store(buf,n);
/* Now we can assume little endian. */
-
+
num[3]='.';
for (p=buf+4 ; p-- > buf ; )
{
@@ -2316,7 +2344,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
DESCRIPTION
Adds a \ before all characters that needs to be escaped in a SQL string.
We also escape '^Z' (END-OF-FILE in windows) to avoid probelms when
- running commands from a file in windows.
+ running commands from a file in windows.
This function is very useful when you want to generate SQL statements
@@ -2332,7 +2360,7 @@ String *Item_func_quote::val_str(String *str)
/*
Bit mask that has 1 for set for the position of the following characters:
0, \, ' and ^Z
- */
+ */
static uchar escmask[32]=
{
@@ -2430,7 +2458,7 @@ String *Item_func_as_text::val_str(String *str)
Geometry geom;
if ((null_value=(args[0]->null_value ||
- geom.create_from_wkb(wkt->ptr(),wkt->length()))))
+ geom.create_from_wkb(wkt->ptr(),wkt->length()))))
return 0;
str->length(0);
@@ -2454,7 +2482,9 @@ String *Item_func_geometry_type::val_str(String *str)
if ((null_value=(args[0]->null_value ||
geom.create_from_wkb(wkt->ptr(),wkt->length()))))
return 0;
- str->copy(geom.get_class_info()->m_name,strlen(geom.get_class_info()->m_name));
+ str->copy(geom.get_class_info()->m_name,
+ strlen(geom.get_class_info()->m_name),
+ default_charset_info);
return str;
}
@@ -2465,7 +2495,7 @@ String *Item_func_envelope::val_str(String *str)
Geometry geom;
null_value = args[0]->null_value ||
- geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
geom.envelope(str);
return null_value ? 0 : str;
@@ -2478,7 +2508,7 @@ String *Item_func_centroid::val_str(String *str)
Geometry geom;
null_value = args[0]->null_value ||
- geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
!GEOM_METHOD_PRESENT(geom,centroid) ||
geom.centroid(str);
@@ -2522,7 +2552,7 @@ String *Item_func_spatial_decomp::val_str(String *str)
}
null_value=0;
-ret:
+ret:
return null_value ? 0 : str;
}
@@ -2533,7 +2563,7 @@ String *Item_func_spatial_decomp_n::val_str(String *str)
long n = (long) args[1]->val_int();
Geometry geom;
- if ((null_value = (args[0]->null_value ||
+ if ((null_value = (args[0]->null_value ||
args[1]->null_value ||
geom.create_from_wkb(wkb->ptr(),wkb->length()) )))
return 0;
@@ -2543,19 +2573,19 @@ String *Item_func_spatial_decomp_n::val_str(String *str)
switch(decomp_func_n)
{
case SP_POINTN:
- if (!GEOM_METHOD_PRESENT(geom,point_n) ||
+ if (!GEOM_METHOD_PRESENT(geom,point_n) ||
geom.point_n(n,str))
goto ret;
break;
case SP_GEOMETRYN:
- if (!GEOM_METHOD_PRESENT(geom,geometry_n) ||
+ if (!GEOM_METHOD_PRESENT(geom,geometry_n) ||
geom.geometry_n(n,str))
goto ret;
break;
case SP_INTERIORRINGN:
- if (!GEOM_METHOD_PRESENT(geom,interior_ring_n) ||
+ if (!GEOM_METHOD_PRESENT(geom,interior_ring_n) ||
geom.interior_ring_n(n,str))
goto ret;
break;
@@ -2583,7 +2613,7 @@ Functions to concatinate various spatial objects
String *Item_func_point::val_str(String *str)
{
- if ( (null_value = (args[0]->null_value ||
+ if ( (null_value = (args[0]->null_value ||
args[1]->null_value ||
str->realloc(1+4+8+8))))
return 0;
@@ -2598,12 +2628,12 @@ String *Item_func_point::val_str(String *str)
/*
- Concatinates various items into various collections
+ Concatinates various items into various collections
with checkings for valid wkb type of items.
For example, MultiPoint can be a collection of Points only.
coll_type contains wkb type of target collection.
item_type contains a valid wkb type of items.
- In the case when coll_type is wkbGeometryCollection,
+ In the case when coll_type is wkbGeometryCollection,
we do not check wkb type of items, any is valid.
*/
@@ -2630,14 +2660,14 @@ String *Item_func_spatial_collection::val_str(String *str)
if ( coll_type == Geometry::wkbGeometryCollection )
{
- /*
- In the case of GeometryCollection we don't need
+ /*
+ In the case of GeometryCollection we don't need
any checkings for item types, so just copy them
into target collection
*/
if ((null_value=(str->reserve(res->length(),512))))
goto ret;
-
+
str->q_append(res->ptr(),res->length());
}
else
@@ -2646,12 +2676,12 @@ String *Item_func_spatial_collection::val_str(String *str)
uint32 len=res->length();
const char *data=res->ptr()+1;
- /*
- In the case of named collection we must to
+ /*
+ In the case of named collection we must to
check that items are of specific type, let's
do this checking now
*/
-
+
if (len < 5)
goto ret;
wkb_type= (Geometry::wkbType) uint4korr(data);
@@ -2659,14 +2689,14 @@ String *Item_func_spatial_collection::val_str(String *str)
len-=5;
if (wkb_type != item_type)
goto ret;
-
+
switch (coll_type) {
case Geometry::wkbMultiPoint:
case Geometry::wkbMultiLineString:
case Geometry::wkbMultiPolygon:
- if (len < WKB_HEADER_SIZE)
+ if (len < WKB_HEADER_SIZE)
goto ret;
-
+
data+=WKB_HEADER_SIZE;
len-=WKB_HEADER_SIZE;
if (str->reserve(len,512))
@@ -2681,43 +2711,43 @@ String *Item_func_spatial_collection::val_str(String *str)
break;
case Geometry::wkbPolygon:
- {
+ {
uint32 n_points;
double x1, y1, x2, y2;
- if (len < WKB_HEADER_SIZE + 4 + 8 + 8)
+ if (len < WKB_HEADER_SIZE + 4 + 8 + 8)
goto ret;
data+=WKB_HEADER_SIZE;
len-=WKB_HEADER_SIZE;
uint32 llen=len;
const char *ldata=data;
-
+
n_points=uint4korr(data);
data+=4;
float8get(x1,data);
data+=8;
float8get(y1,data);
data+=8;
-
+
len-= 4 + 8 + 8;
-
+
if (len < n_points * POINT_DATA_SIZE)
goto ret;
data+=(n_points-2) * POINT_DATA_SIZE;
float8get(x2,data);
float8get(y2,data+8);
-
+
if ((x1 != x2) || (y1 != y2))
goto ret;
-
+
if (str->reserve(llen,512))
goto ret;
str->q_append(ldata, llen);
}
break;
-
+
default:
goto ret;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 14dadc96891..c8706c2c933 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -21,6 +21,9 @@
#pragma interface /* gcc class implementation */
#endif
+extern my_bool opt_old_passwords; /* Need this variable for some functions */
+
+
class Item_str_func :public Item_func
{
public:
@@ -101,10 +104,18 @@ public:
void update_used_tables();
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- return (separator->fix_fields(thd, tlist, &separator)
- || Item_func::fix_fields(thd, tlist, ref));
+ return (separator->check_cols(1) ||
+ separator->fix_fields(thd, tlist, &separator) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
const char *func_name() const { return "concat_ws"; }
+ bool check_loop(uint id)
+ {
+ DBUG_ENTER("Item_func_concat_ws::check_loop");
+ if (Item_str_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(separator->check_loop(id));
+ }
};
class Item_func_reverse :public Item_str_func
@@ -243,14 +254,27 @@ public:
class Item_func_password :public Item_str_func
{
- char tmp_value[17];
+ char tmp_value[64]; /* This should be enough for new password format */
public:
Item_func_password(Item *a) :Item_str_func(a) {}
String *val_str(String *);
- void fix_length_and_dec() { max_length = 16; }
+ void fix_length_and_dec() { max_length = get_password_length(opt_old_passwords); }
const char *func_name() const { return "password"; }
};
+
+class Item_func_old_password :public Item_str_func
+{
+ char tmp_value[16]; /* old password length */
+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); }
+ const char *func_name() const { return "old_password"; }
+};
+
+
+
class Item_func_des_encrypt :public Item_str_func
{
String tmp_value;
@@ -310,7 +334,11 @@ class Item_func_database :public Item_str_func
public:
Item_func_database() {}
String *val_str(String *);
- void fix_length_and_dec() { max_length= MAX_FIELD_NAME; }
+ void fix_length_and_dec()
+ {
+ max_length= MAX_FIELD_NAME * thd_charset()->mbmaxlen;
+ set_charset(thd_charset());
+ }
const char *func_name() const { return "database"; }
};
@@ -319,7 +347,11 @@ class Item_func_user :public Item_str_func
public:
Item_func_user() {}
String *val_str(String *);
- void fix_length_and_dec() { max_length= USERNAME_LENGTH+HOSTNAME_LENGTH+1; }
+ void fix_length_and_dec()
+ {
+ max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*thd_charset()->mbmaxlen;
+ set_charset(thd_charset());
+ }
const char *func_name() const { return "user"; }
};
@@ -347,12 +379,20 @@ public:
String *val_str(String *str);
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- return (item->fix_fields(thd, tlist, &item) ||
+ return (item->check_cols(1) ||
+ item->fix_fields(thd, tlist, &item) ||
Item_func::fix_fields(thd, tlist, ref));
}
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "elt"; }
+ bool check_loop(uint id)
+ {
+ DBUG_ENTER("Item_func_elt::check_loop");
+ if (Item_str_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(item->check_loop(id));
+ }
};
@@ -367,12 +407,20 @@ public:
String *val_str(String *str);
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- return (item->fix_fields(thd, tlist, &item) ||
+ return (item->check_cols(1) ||
+ item->fix_fields(thd, tlist, &item) ||
Item_func::fix_fields(thd, tlist, ref));
}
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "make_set"; }
+ bool check_loop(uint id)
+ {
+ DBUG_ENTER("Item_func_make_set::check_loop");
+ if (Item_str_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(item->check_loop(id));
+ }
};
@@ -465,8 +513,9 @@ public:
{
String *tmp=args[0]->val_str(a);
null_value=args[0]->null_value;
+ tmp->set_charset(my_charset_bin);
return tmp;
- }
+ }
void fix_length_and_dec()
{
set_charset(my_charset_bin);
@@ -567,7 +616,8 @@ public:
const char *func_name() const { return "charset"; }
void fix_length_and_dec()
{
- max_length=20; // should be enough
+ max_length=40; // should be enough
+ set_charset(thd_charset());
};
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f45f386fe46..e087664e060 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -33,7 +33,7 @@ SUBSELECT TODO:
#include "sql_select.h"
Item_subselect::Item_subselect():
- Item(), engine_owner(1), value_assigned(0)
+ Item_result_field(), engine_owner(1), value_assigned(0), substitution(0)
{
assign_null();
/*
@@ -44,12 +44,13 @@ Item_subselect::Item_subselect():
}
void Item_subselect::init(THD *thd, st_select_lex *select_lex,
- select_subselect *result)
+ select_subselect *result)
{
DBUG_ENTER("Item_subselect::init");
- DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
+ DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
+ select_transformer(select_lex);
if (select_lex->next_select())
engine= new subselect_union_engine(thd, select_lex->master_unit(), result,
this);
@@ -65,6 +66,13 @@ Item_subselect::~Item_subselect()
delete engine;
}
+void Item_subselect::select_transformer(st_select_lex *select_lex)
+{
+ DBUG_ENTER("Item_subselect::select_transformer");
+ DBUG_VOID_RETURN;
+}
+
+
void Item_subselect::make_field (Send_field *tmp_field)
{
if (null_value)
@@ -81,20 +89,40 @@ void Item_subselect::make_field (Send_field *tmp_field)
bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ if (substitution)
+ {
+ (*ref)= substitution;
+ substitution->name= name;
+ engine->exclude();
+ return substitution->fix_fields(thd, tables, ref);
+ }
+
+ char const *save_where= thd->where;
int res= engine->prepare();
if (!res)
{
// Is it one field subselect?
if (engine->cols() > max_columns)
{
- my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
return 1;
}
fix_length_and_dec();
}
+ fixed= 1;
+ thd->where= save_where;
return res;
}
+bool Item_subselect::check_loop(uint id)
+{
+ DBUG_ENTER("Item_subselect::check_loop");
+ if (Item_result_field::check_loop(id))
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(engine->check_loop(id));
+}
+
void Item_subselect::fix_length_and_dec()
{
engine->fix_length_and_dec();
@@ -109,9 +137,11 @@ Item_singleval_subselect::Item_singleval_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect()
{
+ DBUG_ENTER("Item_singleval_subselect::Item_singleval_subselect");
init(thd, select_lex, new select_singleval_subselect(this));
max_columns= 1;
maybe_null= 1;
+ DBUG_VOID_RETURN;
}
void Item_singleval_subselect::fix_length_and_dec()
@@ -159,18 +189,55 @@ Item_exists_subselect::Item_exists_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect()
{
+ DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
init(thd, select_lex, new select_exists_subselect(this));
max_columns= UINT_MAX;
null_value= 0; //can't be NULL
maybe_null= 0; //can't be NULL
value= 0;
- select_lex->select_limit= 1; // we need only 1 row to determinate existence
+ // We need only 1 row to determinate existence
+ select_lex->master_unit()->global_parameters->select_limit= 1;
+ DBUG_VOID_RETURN;
}
+Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
+ st_select_lex *select_lex):
+ Item_exists_subselect()
+{
+ DBUG_ENTER("Item_in_subselect::Item_in_subselect");
+ left_expr= left_exp;
+ init(thd, select_lex, new select_exists_subselect(this));
+ max_columns= UINT_MAX;
+ null_value= 0; //can't be NULL
+ maybe_null= 0; //can't be NULL
+ value= 0;
+ // We need only 1 row to determinate existence
+ select_lex->master_unit()->global_parameters->select_limit= 1;
+ DBUG_VOID_RETURN;
+}
+
+Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
+ compare_func_creator f,
+ st_select_lex *select_lex):
+ Item_in_subselect()
+{
+ DBUG_ENTER("Item_in_subselect::Item_in_subselect");
+ left_expr= left_exp;
+ func= f;
+ init(thd, select_lex, new select_exists_subselect(this));
+ max_columns= UINT_MAX;
+ null_value= 0; //can't be NULL
+ maybe_null= 0; //can't be NULL
+ value= 0;
+ // We need only 1 row to determinate existence
+ select_lex->master_unit()->global_parameters->select_limit= 1;
+ DBUG_VOID_RETURN;
+}
+
+
void Item_exists_subselect::fix_length_and_dec()
{
max_length= 1;
-
}
double Item_exists_subselect::val ()
@@ -200,10 +267,112 @@ String *Item_exists_subselect::val_str(String *str)
assign_null();
return 0;
}
- str->set(value,my_thd_charset);
+ str->set(value,thd_charset());
return str;
}
+Item_in_subselect::Item_in_subselect(Item_in_subselect *item):
+ Item_exists_subselect(item)
+{
+ left_expr= item->left_expr;
+}
+
+Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item):
+ Item_in_subselect(item)
+{
+ func= item->func;
+}
+
+void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
+ Item *left_expr,
+ compare_func_creator func)
+{
+ DBUG_ENTER("Item_in_subselect::single_value_transformer");
+ for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select())
+ {
+ Item *item;
+ if (sl->item_list.elements > 1)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ DBUG_VOID_RETURN;
+ }
+ else
+ item= (Item*) sl->item_list.pop();
+
+ Item *expr= new Item_outer_select_context_saver(left_expr);
+
+ if (sl->having || sl->with_sum_func || sl->group_list.first ||
+ sl->order_list.first)
+ {
+ sl->item_list.push_back(item);
+ item= (*func)(expr, new Item_ref(sl->item_list.head_ref(),
+ 0, (char*)"<result>"));
+ if (sl->having || sl->with_sum_func || sl->group_list.first)
+ if (sl->having)
+ sl->having= new Item_cond_and(sl->having, item);
+ else
+ sl->having= item;
+ else
+ if (sl->where)
+ sl->where= new Item_cond_and(sl->having, item);
+ else
+ sl->where= item;
+ }
+ else
+ {
+ sl->item_list.empty();
+ sl->item_list.push_back(new Item_int(1));
+ if (sl->table_list.elements)
+ {
+ item= (*func)(expr, new Item_asterisk_remover(item));
+ if (sl->where)
+ sl->where= new Item_cond_and(sl->where, item);
+ else
+ sl->where= item;
+ }
+ else
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ my_error(ER_NO_TABLES_USED, MYF(0));
+ DBUG_VOID_RETURN;
+ }
+ if (select_lex->next_select())
+ {
+ // it is in union => we should perform it
+ sl->having= (*func)(expr, item);
+ }
+ else
+ {
+ // it is single select without tables => possible optimization
+ item= (*func)(left_expr, item);
+ substitution= item;
+ THD *thd= current_thd;
+ if (thd->lex.describe)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_SELECT_REDUCED), sl->select_number);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SELECT_REDUCED, warn_buff);
+ }
+ }
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+void Item_in_subselect::select_transformer(st_select_lex *select_lex)
+{
+ single_value_transformer(select_lex, left_expr,
+ &Item_bool_func2::eq_creator);
+}
+
+void Item_allany_subselect::select_transformer(st_select_lex *select_lex)
+{
+ single_value_transformer(select_lex, left_expr, func);
+}
subselect_single_select_engine::subselect_single_select_engine(THD *thd,
st_select_lex *select,
@@ -228,6 +397,7 @@ subselect_single_select_engine::subselect_single_select_engine(THD *thd,
thd->fatal_error= 1;
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
}
+ unit->item= item;
this->select_lex= select_lex;
}
@@ -284,7 +454,7 @@ void subselect_union_engine::fix_length_and_dec()
{
uint32 mlen= 0, len;
Item *sel_item= 0;
- for(SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
{
List_iterator_fast<Item> li(sl->item_list);
Item *s_item= li++;
@@ -301,11 +471,13 @@ void subselect_union_engine::fix_length_and_dec()
int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
+ char const *save_where= join->thd->where;
if (!optimized)
{
optimized=1;
if (join->optimize())
{
+ join->thd->where= save_where;
executed= 1;
DBUG_RETURN(join->error?join->error:1);
}
@@ -313,7 +485,10 @@ int subselect_single_select_engine::exec()
if (select_lex->dependent && executed)
{
if (join->reinit())
+ {
+ join->thd->where= save_where;
DBUG_RETURN(1);
+ }
item->assign_null();
item->assigned((executed= 0));
}
@@ -324,14 +499,19 @@ int subselect_single_select_engine::exec()
join->exec();
join->thd->lex.current_select= save_select;
executed= 1;
+ join->thd->where= save_where;
DBUG_RETURN(join->error||thd->fatal_error);
}
+ join->thd->where= save_where;
DBUG_RETURN(0);
}
int subselect_union_engine::exec()
{
- return unit->exec();
+ char const *save_where= unit->thd->where;
+ int res= unit->exec();
+ unit->thd->where= save_where;
+ return res;
}
uint subselect_single_select_engine::cols()
@@ -353,3 +533,32 @@ bool subselect_union_engine::depended()
{
return unit->dependent;
}
+
+bool subselect_single_select_engine::check_loop(uint id)
+{
+ DBUG_ENTER("subselect_single_select_engine::check_loop");
+ DBUG_RETURN(join->check_loop(id));
+}
+
+bool subselect_union_engine::check_loop(uint id)
+{
+ DBUG_ENTER("subselect_union_engine::check_loop");
+ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+ if (sl->join && sl->join->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+void subselect_single_select_engine::exclude()
+{
+ select_lex->master_unit()->exclude_level();
+ //if (current_thd->lex->describe)
+}
+
+void subselect_union_engine::exclude()
+{
+ unit->exclude_level();
+ // for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+ // if (sl->join && sl->join->check_loop(id))
+ // DBUG_RETURN(1);
+}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 33f82982708..d323dab51f1 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -25,14 +25,19 @@ class st_select_lex_unit;
class JOIN;
class select_subselect;
class subselect_engine;
+class Item_bool_func2;
+
+typedef Item_bool_func2* (*compare_func_creator)(Item*, Item*);
/* base class for subselects */
-class Item_subselect :public Item
+class Item_subselect :public Item_result_field
{
my_bool engine_owner; /* Is this item owner of engine */
my_bool value_assigned; /* value already assigned to subselect */
protected:
+ /* substitution instead of subselect in case of optimization */
+ Item *substitution;
/* engine that perform execution of subselect (single select or union) */
subselect_engine *engine;
/* allowed number of columns (1 for single value subqueries) */
@@ -42,6 +47,7 @@ public:
Item_subselect();
Item_subselect(Item_subselect *item)
{
+ substitution= item->substitution;
null_value= item->null_value;
decimals= item->decimals;
max_columns= item->max_columns;
@@ -55,13 +61,15 @@ public:
pointer in constructor initialization list, but we need pass pointer
to subselect Item class to select_subselect classes constructor.
*/
- void init (THD *thd, st_select_lex *select_lex, select_subselect *result);
+ virtual void init (THD *thd, st_select_lex *select_lex,
+ select_subselect *result);
~Item_subselect();
virtual void assign_null()
{
null_value= 1;
}
+ virtual void select_transformer(st_select_lex *select_lex);
bool assigned() { return value_assigned; }
void assigned(bool a) { value_assigned= a; }
enum Type type() const;
@@ -70,11 +78,11 @@ public:
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
virtual void fix_length_and_dec();
table_map used_tables() const;
+ bool check_loop(uint id);
friend class select_subselect;
};
-
/* single value subselect */
class Item_singleval_subselect :public Item_subselect
@@ -116,6 +124,7 @@ public:
Item *new_item() { return new Item_singleval_subselect(this); }
enum Item_result result_type() const { return res_type; }
void fix_length_and_dec();
+
friend class select_singleval_subselect;
};
@@ -133,6 +142,8 @@ public:
{
value= item->value;
}
+ Item_exists_subselect(): Item_subselect() {}
+
virtual void assign_null()
{
value= 0;
@@ -147,6 +158,35 @@ public:
friend class select_exists_subselect;
};
+/* IN subselect */
+
+class Item_in_subselect :public Item_exists_subselect
+{
+protected:
+ Item * left_expr;
+
+public:
+ Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
+ Item_in_subselect(Item_in_subselect *item);
+ Item_in_subselect(): Item_exists_subselect() {}
+ virtual void select_transformer(st_select_lex *select_lex);
+ void single_value_transformer(st_select_lex *select_lex,
+ Item *left_expr, compare_func_creator func);
+};
+
+/* ALL/ANY/SOME subselect */
+class Item_allany_subselect :public Item_in_subselect
+{
+protected:
+ compare_func_creator func;
+
+public:
+ Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f,
+ st_select_lex *select_lex);
+ Item_allany_subselect(Item_allany_subselect *item);
+ virtual void select_transformer(st_select_lex *select_lex);
+};
+
class subselect_engine
{
protected:
@@ -175,6 +215,8 @@ public:
virtual uint cols()= 0; /* return number of columnss in select */
virtual bool depended()= 0; /* depended from outer select */
enum Item_result type() { return res_type; }
+ virtual bool check_loop(uint id)= 0;
+ virtual void exclude()= 0;
};
class subselect_single_select_engine: public subselect_engine
@@ -188,11 +230,13 @@ public:
subselect_single_select_engine(THD *thd, st_select_lex *select,
select_subselect *result,
Item_subselect *item);
- virtual int prepare();
- virtual void fix_length_and_dec();
- virtual int exec();
- virtual uint cols();
- virtual bool depended();
+ int prepare();
+ void fix_length_and_dec();
+ int exec();
+ uint cols();
+ bool depended();
+ bool check_loop(uint id);
+ void exclude();
};
class subselect_union_engine: public subselect_engine
@@ -203,9 +247,11 @@ public:
st_select_lex_unit *u,
select_subselect *result,
Item_subselect *item);
- virtual int prepare();
- virtual void fix_length_and_dec();
- virtual int exec();
- virtual uint cols();
- virtual bool depended();
+ int prepare();
+ void fix_length_and_dec();
+ int exec();
+ uint cols();
+ bool depended();
+ bool check_loop(uint id);
+ void exclude();
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 22b5e47fab5..4a2d716c953 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -22,8 +22,7 @@
#endif
#include "mysql_priv.h"
-
-
+#include "assert.h"
Item_sum::Item_sum(List<Item> &list)
{
arg_count=list.elements;
@@ -38,10 +37,15 @@ Item_sum::Item_sum(List<Item> &list)
args[i++]= item;
}
}
- with_sum_func=1;
+ mark_as_sum_func();
list.empty(); // Fields are used
}
+void Item_sum::mark_as_sum_func()
+{
+ current_thd->lex.current_select->with_sum_func=1;
+ with_sum_func= 1;
+}
void Item_sum::make_field(Send_field *tmp_field)
{
@@ -93,7 +97,7 @@ Item_sum_num::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -104,9 +108,7 @@ Item_sum_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- char buff[21];
- uint length= (uint) (longlong10_to_str(nr,buff,-10)-buff);
- str->copy(buff,length);
+ str->set(nr,thd_charset());
return str;
}
@@ -124,7 +126,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
maybe_null=0;
for (uint i=0 ; i < arg_count ; i++)
{
- if (args[i]->fix_fields(thd, tables, args + i))
+ if (args[i]->check_cols(1) || args[i]->fix_fields(thd, tables, args + i))
return 1;
if (decimals < args[i]->decimals)
decimals=args[i]->decimals;
@@ -135,6 +137,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
+ fixed= 1;
return 0;
}
@@ -149,7 +152,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 1;
}
thd->allow_sum_func=0; // No included group funcs
- if (item->fix_fields(thd, tables, args))
+ if (item->check_cols(1) || item->fix_fields(thd, tables, args))
return 1;
hybrid_type=item->result_type();
if (hybrid_type == INT_RESULT)
@@ -165,6 +168,7 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
+ fixed= 1;
return 0;
}
@@ -329,13 +333,17 @@ double Item_sum_hybrid::val()
switch (hybrid_type) {
case STRING_RESULT:
String *res; res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(),res->ptr(),res->length(),(char**)0) : 0.0;
case INT_RESULT:
if (unsigned_flag)
return ulonglong2double(sum_int);
return (double) sum_int;
case REAL_RESULT:
return sum;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
return 0; // Keep compiler happy
}
@@ -359,13 +367,17 @@ Item_sum_hybrid::val_str(String *str)
case STRING_RESULT:
return &value;
case REAL_RESULT:
- str->set(sum,decimals,my_thd_charset);
+ str->set(sum,decimals,thd_charset());
break;
case INT_RESULT:
if (unsigned_flag)
- str->set((ulonglong) sum_int,my_thd_charset);
+ str->set((ulonglong) sum_int,thd_charset());
else
- str->set((longlong) sum_int,my_thd_charset);
+ str->set((longlong) sum_int,thd_charset());
+ break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
break;
}
return str; // Keep compiler happy
@@ -409,6 +421,10 @@ bool Item_sum_min::add()
}
}
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
return 0;
}
@@ -452,6 +468,11 @@ bool Item_sum_max::add()
}
}
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
+
}
return 0;
}
@@ -810,7 +831,7 @@ String *Item_avg_field::val_str(String *str)
double nr=Item_avg_field::val();
if (null_value)
return 0;
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -847,7 +868,7 @@ String *Item_std_field::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -969,9 +990,9 @@ bool Item_sum_count_distinct::setup(THD *thd)
tmp_table_param->cleanup();
}
if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
- 0, 0,
+ 0,
select_lex->options | thd->options,
- select_lex->master_unit())))
+ HA_POS_ERROR)))
return 1;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
@@ -1069,7 +1090,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
int Item_sum_count_distinct::tree_to_myisam()
{
- if (create_myisam_from_heap(table, tmp_table_param,
+ if (create_myisam_from_heap(current_thd, table, tmp_table_param,
HA_ERR_RECORD_FILE_FULL, 1) ||
tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
left_root_right))
@@ -1115,7 +1136,8 @@ bool Item_sum_count_distinct::add()
if (tree_to_myisam())
return 1;
}
- else if (!tree_insert(&tree, table->record[0] + rec_offset, 0, tree.custom_arg))
+ else if (!tree_insert(&tree, table->record[0] + rec_offset, 0,
+ tree.custom_arg))
return 1;
}
else if ((error=table->file->write_row(table->record[0])))
@@ -1123,13 +1145,15 @@ bool Item_sum_count_distinct::add()
if (error != HA_ERR_FOUND_DUPP_KEY &&
error != HA_ERR_FOUND_DUPP_UNIQUE)
{
- if (create_myisam_from_heap(table, tmp_table_param, error,1))
+ if (create_myisam_from_heap(current_thd, table, tmp_table_param, error,
+ 1))
return 1; // Not a table_is_full error
}
}
return 0;
}
+
longlong Item_sum_count_distinct::val_int()
{
if (!table) // Empty query
@@ -1177,7 +1201,7 @@ String *Item_sum_udf_float::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals,my_thd_charset);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -1196,7 +1220,7 @@ String *Item_sum_udf_int::val_str(String *str)
if (null_value)
return 0;
else
- str->set(nr,my_thd_charset);
+ str->set(nr,thd_charset());
return str;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 3e67f1e3624..23b8482d41a 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -34,23 +34,28 @@ public:
uint arg_count;
bool quick_group; /* If incremental update of fields */
- Item_sum() : arg_count(0),quick_group(1) { with_sum_func=1; }
+ void mark_as_sum_func();
+ Item_sum() : arg_count(0),quick_group(1)
+ {
+ mark_as_sum_func();
+ }
Item_sum(Item *a) :quick_group(1)
{
arg_count=1;
args=tmp_args;
args[0]=a;
- with_sum_func = 1;
+ mark_as_sum_func();
}
Item_sum( Item *a, Item *b ) :quick_group(1)
{
arg_count=2;
args=tmp_args;
args[0]=a; args[1]=b;
- with_sum_func=1;
+ mark_as_sum_func();
}
Item_sum(List<Item> &list);
~Item_sum() { result_field=0; }
+
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
virtual void reset()=0;
@@ -384,6 +389,7 @@ public:
const char *func_name() const { return udf.name(); }
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ fixed= 1;
return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
@@ -436,12 +442,12 @@ public:
double val()
{
String *res; res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(),res->ptr(),res->length(),(char**) 0) : 0.0;
}
longlong val_int()
{
String *res; res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),(char**) 0,10) : (longlong) 0;
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index b42b78c9c91..7e2e8f7cfbd 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -31,28 +31,28 @@
static String month_names[] =
{
- String("January", default_charset_info),
- String("February", default_charset_info),
- String("March", default_charset_info),
- String("April", default_charset_info),
- String("May", default_charset_info),
- String("June", default_charset_info),
- String("July", default_charset_info),
- String("August", default_charset_info),
- String("September", default_charset_info),
- String("October", default_charset_info),
- String("November", default_charset_info),
- String("December", default_charset_info)
+ String("January", my_charset_latin1),
+ String("February", my_charset_latin1),
+ String("March", my_charset_latin1),
+ String("April", my_charset_latin1),
+ String("May", my_charset_latin1),
+ String("June", my_charset_latin1),
+ String("July", my_charset_latin1),
+ String("August", my_charset_latin1),
+ String("September", my_charset_latin1),
+ String("October", my_charset_latin1),
+ String("November", my_charset_latin1),
+ String("December", my_charset_latin1)
};
static String day_names[] =
{
- String("Monday", default_charset_info),
- String("Tuesday", default_charset_info),
- String("Wednesday", default_charset_info),
- String("Thursday", default_charset_info),
- String("Friday", default_charset_info),
- String("Saturday", default_charset_info),
- String("Sunday", default_charset_info)
+ String("Monday", my_charset_latin1),
+ String("Tuesday", my_charset_latin1),
+ String("Wednesday", my_charset_latin1),
+ String("Thursday", my_charset_latin1),
+ String("Friday", my_charset_latin1),
+ String("Saturday", my_charset_latin1),
+ String("Sunday", my_charset_latin1)
};
/*
@@ -153,14 +153,17 @@ longlong Item_func_month::val_int()
String* Item_func_monthname::val_str(String* str)
{
- uint month=(uint) Item_func_month::val_int();
+ uint month=(uint) Item_func_month::val_int();
if (!month) // This is also true for NULL
{
null_value=1;
return (String*) 0;
}
null_value=0;
- return &month_names[month-1];
+
+ String *m=&month_names[month-1];
+ str->copy(m->ptr(), m->length(), m->charset(), thd_charset());
+ return str;
}
// Returns the quarter of the year
@@ -195,15 +198,28 @@ longlong Item_func_second::val_int()
}
-// Returns the week of year in the range of 0 - 53
+/*
+ Returns the week of year.
+
+ The bits in week_format has the following meaning:
+ 0 If not set: USA format: Sunday is first day of week
+ If set: ISO format: Monday is first day of week
+ 1 If not set: Week is in range 0-53
+ If set Week is in range 1-53.
+*/
longlong Item_func_week::val_int()
{
uint year;
+ uint week_format;
TIME ltime;
if (get_arg0_date(&ltime,0))
return 0;
- return (longlong) calc_week(&ltime, 0, args[1]->val_int() == 0, &year);
+ week_format= (uint) args[1]->val_int();
+ return (longlong) calc_week(&ltime,
+ (week_format & 2) != 0,
+ (week_format & 1) == 0,
+ &year);
}
@@ -213,7 +229,7 @@ longlong Item_func_yearweek::val_int()
TIME ltime;
if (get_arg0_date(&ltime,0))
return 0;
- week=calc_week(&ltime, 1, args[1]->val_int() == 0, &year);
+ week=calc_week(&ltime, 1, (args[1]->val_int() & 1) == 0, &year);
return week+year*100;
}
@@ -234,7 +250,10 @@ String* Item_func_dayname::val_str(String* str)
uint weekday=(uint) val_int(); // Always Item_func_daynr()
if (null_value)
return (String*) 0;
- return &day_names[weekday];
+
+ String *d=&day_names[weekday];
+ str->copy(d->ptr(), d->length(), d->charset(), thd_charset());
+ return str;
}
@@ -396,21 +415,21 @@ String *Item_date::val_str(String *str)
return (String*) 0;
if (!value) // zero daynr
{
- str->copy("0000-00-00",10);
+ str->copy("0000-00-00",10,my_charset_latin1,thd_charset());
return str;
}
- if (str->alloc(11))
- return &empty_string; /* purecov: inspected */
- sprintf((char*) str->ptr(),"%04d-%02d-%02d",
+
+ char tmpbuff[11];
+ sprintf(tmpbuff,"%04d-%02d-%02d",
(int) (value/10000L) % 10000,
(int) (value/100)%100,
(int) (value%100));
- str->length(10);
+ str->copy(tmpbuff,10,my_charset_latin1,thd_charset());
return str;
}
-int Item_date::save_in_field(Field *field)
+int Item_date::save_in_field(Field *field, bool no_conversions)
{
TIME ltime;
timestamp_type t_type=TIMESTAMP_FULL;
@@ -442,7 +461,10 @@ void Item_func_curdate::fix_length_and_dec()
{
struct tm tm_tmp,*start;
time_t query_start=current_thd->query_start();
- decimals=0; max_length=10;
+
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=10*thd_charset()->mbmaxlen;
localtime_r(&query_start,&tm_tmp);
start=&tm_tmp;
value=(longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
@@ -467,27 +489,48 @@ bool Item_func_curdate::get_date(TIME *res,
return 0;
}
+String *Item_func_curtime::val_str(String *str)
+{
+ str_value.set(buff,buff_length,thd_charset());
+ return &str_value;
+}
+
void Item_func_curtime::fix_length_and_dec()
{
struct tm tm_tmp,*start;
time_t query_start=current_thd->query_start();
- decimals=0; max_length=8;
+ CHARSET_INFO *cs=thd_charset();
+
+ decimals=0;
+ max_length=8*cs->mbmaxlen;
localtime_r(&query_start,&tm_tmp);
start=&tm_tmp;
+ set_charset(cs);
value=(longlong) ((ulong) ((uint) start->tm_hour)*10000L+
(ulong) (((uint) start->tm_min)*100L+
(uint) start->tm_sec));
- buff_length= my_sprintf(buff, (buff,"%02d:%02d:%02d",
+
+ buff_length=cs->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d",
(int) start->tm_hour,
(int) start->tm_min,
- (int) start->tm_sec));
+ (int) start->tm_sec);
+}
+
+String *Item_func_now::val_str(String *str)
+{
+ str_value.set(buff,buff_length,thd_charset());
+ return &str_value;
}
void Item_func_now::fix_length_and_dec()
{
struct tm tm_tmp,*start;
time_t query_start=current_thd->query_start();
- decimals=0; max_length=19;
+ CHARSET_INFO *cs=thd_charset();
+
+ decimals=0;
+ max_length=19*cs->mbmaxlen;
+ set_charset(cs);
localtime_r(&query_start,&tm_tmp);
start=&tm_tmp;
value=((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
@@ -496,13 +539,14 @@ void Item_func_now::fix_length_and_dec()
(longlong) ((ulong) ((uint) start->tm_hour)*10000L+
(ulong) (((uint) start->tm_min)*100L+
(uint) start->tm_sec)));
- buff_length= (uint) my_sprintf(buff, (buff,"%04d-%02d-%02d %02d:%02d:%02d",
+
+ buff_length= (uint) cs->snprintf(cs,buff, sizeof(buff),"%04d-%02d-%02d %02d:%02d:%02d",
((int) (start->tm_year+1900)) % 10000,
(int) start->tm_mon+1,
(int) start->tm_mday,
(int) start->tm_hour,
(int) start->tm_min,
- (int) start->tm_sec));
+ (int) start->tm_sec);
/* For getdate */
ltime.year= start->tm_year+1900;
ltime.month= start->tm_mon+1;
@@ -523,7 +567,7 @@ bool Item_func_now::get_date(TIME *res,
}
-int Item_func_now::save_in_field(Field *to)
+int Item_func_now::save_in_field(Field *to, bool no_conversions)
{
to->set_notnull();
to->store_time(&ltime,TIMESTAMP_FULL);
@@ -533,7 +577,7 @@ int Item_func_now::save_in_field(Field *to)
String *Item_func_sec_to_time::val_str(String *str)
{
- char buff[23];
+ char buff[23*2];
const char *sign="";
longlong seconds=(longlong) args[0]->val_int();
ulong length;
@@ -547,7 +591,7 @@ String *Item_func_sec_to_time::val_str(String *str)
uint sec= (uint) ((ulonglong) seconds % 3600);
length= my_sprintf(buff,(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600),
sec/60, sec % 60));
- str->copy(buff, length);
+ str->copy(buff, length, my_charset_latin1, thd_charset());
return str;
}
@@ -891,20 +935,26 @@ String *Item_func_from_unixtime::val_str(String *str)
{
struct tm tm_tmp,*start;
time_t tmp=(time_t) args[0]->val_int();
+ uint32 l;
+ CHARSET_INFO *cs=thd_charset();
+
if ((null_value=args[0]->null_value))
return 0;
localtime_r(&tmp,&tm_tmp);
start=&tm_tmp;
- if (str->alloc(20))
+
+ l=20*cs->mbmaxlen+32;
+ if (str->alloc(l))
return str; /* purecov: inspected */
- sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d",
+ l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d",
(int) start->tm_year+1900,
(int) start->tm_mon+1,
(int) start->tm_mday,
(int) start->tm_hour,
(int) start->tm_min,
(int) start->tm_sec);
- str->length(19);
+ str->length(l);
+ str->set_charset(cs);
return str;
}
@@ -1035,26 +1085,31 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date)
String *Item_date_add_interval::val_str(String *str)
{
TIME ltime;
+ CHARSET_INFO *cs=thd_charset();
+ uint32 l;
if (Item_date_add_interval::get_date(&ltime,0))
return 0;
if (ltime.time_type == TIMESTAMP_DATE)
{
- if (str->alloc(11))
+ l=11*cs->mbmaxlen+32;
+ if (str->alloc(l))
goto null_date;
- sprintf((char*) str->ptr(),"%04d-%02d-%02d",
+ l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d",
ltime.year,ltime.month,ltime.day);
- str->length(10);
+ str->length(l);
}
else
{
- if (str->alloc(20))
+ l=20*cs->mbmaxlen+32;
+ if (str->alloc(l))
goto null_date;
- sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d",
+ l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d",
ltime.year,ltime.month,ltime.day,
ltime.hour,ltime.minute,ltime.second);
- str->length(19);
+ str->length(l);
}
+ str->set_charset(cs);
return str;
null_date:
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index fab8ea9fa9c..40397351c18 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -27,7 +27,10 @@ public:
Item_func_period_add(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "period_add"; }
- void fix_length_and_dec() { max_length=6; }
+ void fix_length_and_dec()
+ {
+ max_length=6*thd_charset()->mbmaxlen;
+ }
};
@@ -37,7 +40,11 @@ public:
Item_func_period_diff(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "period_diff"; }
- void fix_length_and_dec() { decimals=0; max_length=6; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=6*thd_charset()->mbmaxlen;
+ }
};
@@ -47,7 +54,12 @@ public:
Item_func_to_days(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "to_days"; }
- void fix_length_and_dec() { decimals=0; max_length=6; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=6*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -57,7 +69,12 @@ public:
Item_func_dayofmonth(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "dayofmonth"; }
- void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=2*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -69,12 +86,18 @@ public:
double val() { return (double) Item_func_month::val_int(); }
String *val_str(String *str)
{
- str->set(val_int(), my_thd_charset);
+ str->set(val_int(), thd_charset());
return null_value ? 0 : str;
}
const char *func_name() const { return "month"; }
enum Item_result result_type () const { return INT_RESULT; }
- void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=2*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -85,7 +108,13 @@ public:
const char *func_name() const { return "monthname"; }
String *val_str(String *str);
enum Item_result result_type () const { return STRING_RESULT; }
- void fix_length_and_dec() { decimals=0; max_length=10; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=10*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -95,7 +124,12 @@ public:
Item_func_dayofyear(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "dayofyear"; }
- void fix_length_and_dec() { decimals=0; max_length=3; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=3*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -105,7 +139,12 @@ public:
Item_func_hour(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "hour"; }
- void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=2*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -115,7 +154,12 @@ public:
Item_func_minute(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "minute"; }
- void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=2*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -125,7 +169,12 @@ public:
Item_func_quarter(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "quarter"; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=1*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -135,7 +184,12 @@ public:
Item_func_second(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "second"; }
- void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=2*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -145,7 +199,12 @@ public:
Item_func_week(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "week"; }
- void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=2*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
class Item_func_yearweek :public Item_int_func
@@ -154,7 +213,12 @@ public:
Item_func_yearweek(Item *a,Item *b) :Item_int_func(a,b) {}
longlong val_int();
const char *func_name() const { return "yearweek"; }
- void fix_length_and_dec() { decimals=0; max_length=6; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=6*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -164,7 +228,12 @@ public:
Item_func_year(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "year"; }
- void fix_length_and_dec() { decimals=0; max_length=4; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ decimals=0;
+ max_length=4*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -176,13 +245,20 @@ public:
:Item_func(a), odbc_type(type_arg) {}
longlong val_int();
double val() { return (double) val_int(); }
- String *val_str(String *str) {
- str->set(val_int(), my_thd_charset);
+ String *val_str(String *str)
+ {
+ str->set(val_int(), thd_charset());
return null_value ? 0 : str;
}
const char *func_name() const { return "weekday"; }
enum Item_result result_type () const { return INT_RESULT; }
- void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=1*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
class Item_func_dayname :public Item_func_weekday
@@ -192,7 +268,13 @@ class Item_func_dayname :public Item_func_weekday
const char *func_name() const { return "dayname"; }
String *val_str(String *str);
enum Item_result result_type () const { return STRING_RESULT; }
- void fix_length_and_dec() { decimals=0; max_length=9; maybe_null=1; }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=9*thd_charset()->mbmaxlen;
+ maybe_null=1;
+ }
};
@@ -206,7 +288,8 @@ public:
const char *func_name() const { return "timestamp"; }
void fix_length_and_dec()
{
- decimals=0; max_length=10;
+ decimals=0;
+ max_length=10*thd_charset()->mbmaxlen;
}
};
@@ -219,7 +302,8 @@ public:
const char *func_name() const { return "time_to_sec"; }
void fix_length_and_dec()
{
- decimals=0; max_length=10;
+ decimals=0;
+ max_length=10*thd_charset()->mbmaxlen;
}
};
@@ -235,15 +319,20 @@ public:
String *val_str(String *str);
double val() { return (double) val_int(); }
const char *func_name() const { return "date"; }
- void fix_length_and_dec() { decimals=0; max_length=10; }
- int save_in_field(Field *to);
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=10*thd_charset()->mbmaxlen;
+ }
+ int save_in_field(Field *to, bool no_conversions);
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_DATE);
}
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, my_thd_charset);
+ return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset());
}
};
@@ -261,7 +350,7 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
- t_arg, my_thd_charset);
+ t_arg, thd_charset());
}
};
@@ -269,7 +358,7 @@ public:
class Item_func_curtime :public Item_func
{
longlong value;
- char buff[9];
+ char buff[9*2+32];
uint buff_length;
public:
Item_func_curtime() :Item_func() {}
@@ -277,8 +366,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
double val() { return (double) value; }
longlong val_int() { return value; }
- String *val_str(String *str)
- { str_value.set(buff,buff_length,default_charset_info); return &str_value; }
+ String *val_str(String *str);
const char *func_name() const { return "curtime"; }
void fix_length_and_dec();
void make_field(Send_field *tmp_field)
@@ -288,7 +376,7 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
- new Field_time(maybe_null, name, t_arg, my_thd_charset);
+ new Field_time(maybe_null, name, t_arg, thd_charset());
}
};
@@ -309,7 +397,7 @@ public:
class Item_func_now :public Item_date_func
{
longlong value;
- char buff[20];
+ char buff[20*2+32]; // +32 to make my_snprintf_{8bit|ucs2} happy
uint buff_length;
TIME ltime;
public:
@@ -318,9 +406,8 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
double val() { return (double) value; }
longlong val_int() { return value; }
- int save_in_field(Field *to);
- String *val_str(String *str)
- { str_value.set(buff,buff_length,default_charset_info); return &str_value; }
+ int save_in_field(Field *to, bool no_conversions);
+ String *val_str(String *str);
const char *func_name() const { return "now"; }
void fix_length_and_dec();
bool get_date(TIME *res,bool fuzzy_date);
@@ -359,7 +446,12 @@ class Item_func_from_unixtime :public Item_date_func
longlong val_int();
String *val_str(String *str);
const char *func_name() const { return "from_unixtime"; }
- void fix_length_and_dec() { decimals=0; max_length=19; }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ decimals=0;
+ max_length=19*thd_charset()->mbmaxlen;
+ }
// enum Item_result result_type () const { return STRING_RESULT; }
bool get_date(TIME *res,bool fuzzy_date);
};
@@ -372,7 +464,12 @@ public:
double val() { return (double) Item_func_sec_to_time::val_int(); }
longlong val_int();
String *val_str(String *);
- void fix_length_and_dec() { maybe_null=1; max_length=13; }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ maybe_null=1;
+ max_length=13*thd_charset()->mbmaxlen;
+ }
const char *func_name() const { return "sec_to_time"; }
void make_field(Send_field *tmp_field)
{
@@ -381,7 +478,7 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
- new Field_time(maybe_null, name, t_arg, my_thd_charset);
+ new Field_time(maybe_null, name, t_arg, thd_charset());
}
};
@@ -404,12 +501,19 @@ public:
:Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
String *val_str(String *);
const char *func_name() const { return "date_add_interval"; }
- void fix_length_and_dec() { maybe_null=1; max_length=19; value.alloc(32);}
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ maybe_null=1;
+ max_length=19*thd_charset()->mbmaxlen;
+ value.alloc(32);
+ }
double val() { return (double) val_int(); }
longlong val_int();
bool get_date(TIME *res,bool fuzzy_date);
};
+
class Item_extract :public Item_int_func
{
const interval_type int_type;
@@ -423,17 +527,40 @@ class Item_extract :public Item_int_func
void fix_length_and_dec();
};
+
class Item_typecast :public Item_str_func
{
public:
Item_typecast(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "char"; }
String *val_str(String *a)
- { a=args[0]->val_str(a); null_value=args[0]->null_value; return a; }
- void fix_length_and_dec() { max_length=args[0]->max_length; }
+ {
+ String *tmp=args[0]->val_str(a);
+ null_value=args[0]->null_value;
+ tmp->set_charset(charset());
+ return tmp;
+ }
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ max_length=args[0]->max_length;
+ }
void print(String *str);
};
+class Item_char_typecast :public Item_typecast
+{
+public:
+ Item_char_typecast(Item *a) :Item_typecast(a) {}
+ void fix_length_and_dec()
+ {
+ set_charset(thd_charset());
+ max_length=args[0]->max_length;
+ }
+};
+
+
class Item_date_typecast :public Item_typecast
{
public:
@@ -446,10 +573,11 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
- new Field_date(maybe_null, name, t_arg, my_thd_charset);
+ new Field_date(maybe_null, name, t_arg, thd_charset());
}
};
+
class Item_time_typecast :public Item_typecast
{
public:
@@ -462,10 +590,11 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
- new Field_time(maybe_null, name, t_arg, my_thd_charset);
+ new Field_time(maybe_null, name, t_arg, thd_charset());
}
};
+
class Item_datetime_typecast :public Item_typecast
{
public:
@@ -478,6 +607,6 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
- t_arg, my_thd_charset);
+ t_arg, thd_charset());
}
};
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index f0d1d353cfb..2004be63de2 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -43,5 +43,9 @@ public:
bool add() { return 0; }
void reset_field() {}
void update_field(int offset) {}
- bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { return 0;}
+ bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
+ {
+ fixed= 1;
+ return 0;
+ }
};
diff --git a/sql/lex.h b/sql/lex.h
index 4b56eb4b5d8..eb03c0b36ec 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -56,6 +56,7 @@ static SYMBOL symbols[] = {
{ "AGAINST", SYM(AGAINST),0,0},
{ "ANALYZE", SYM(ANALYZE_SYM),0,0},
{ "AND", SYM(AND),0,0},
+ { "ANY", SYM(ANY_SYM),0,0},
{ "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0},
{ "AVG", SYM(AVG_SYM),0,0},
@@ -76,6 +77,7 @@ static SYMBOL symbols[] = {
{ "BOTH", SYM(BOTH),0,0},
{ "BTREE", SYM(BTREE_SYM),0,0},
{ "BY", SYM(BY),0,0},
+ { "BYTE", SYM(BYTE_SYM), 0, 0},
{ "CACHE", SYM(CACHE_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
{ "CASE", SYM(CASE_SYM),0,0},
@@ -126,11 +128,14 @@ static SYMBOL symbols[] = {
{ "DISABLE", SYM(DISABLE_SYM),0,0},
{ "DISTINCT", SYM(DISTINCT),0,0},
{ "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */
+ { "DIV", SYM(DIV_SYM),0,0},
{ "DO", SYM(DO_SYM),0,0},
{ "DOUBLE", SYM(DOUBLE_SYM),0,0},
+ { "DUAL", SYM(DUAL_SYM),0,0},
{ "DROP", SYM(DROP),0,0},
{ "DUMPFILE", SYM(DUMPFILE),0,0},
{ "DYNAMIC", SYM(DYNAMIC_SYM),0,0},
+ { "DUPLICATE", SYM(DUPLICATE),0,0},
{ "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0},
@@ -153,6 +158,7 @@ static SYMBOL symbols[] = {
{ "FLOAT4", SYM(FLOAT_SYM),0,0},
{ "FLOAT8", SYM(DOUBLE_SYM),0,0},
{ "FLUSH", SYM(FLUSH_SYM),0,0},
+ { "FALSE", SYM(FALSE_SYM),0,0},
{ "FOREIGN", SYM(FOREIGN),0,0},
{ "RAID_TYPE", SYM(RAID_TYPE),0,0},
{ "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0},
@@ -217,6 +223,8 @@ static SYMBOL symbols[] = {
{ "LIMIT", SYM(LIMIT),0,0},
{ "LOAD", SYM(LOAD),0,0},
{ "LOCAL", SYM(LOCAL_SYM),0,0},
+ { "LOCALTIME", SYM(NOW_SYM),0,0},
+ { "LOCALTIMESTAMP", SYM(NOW_SYM),0,0},
{ "LOCK", SYM(LOCK_SYM),0,0},
{ "LOCKS", SYM(LOCKS_SYM),0,0},
{ "LOGS", SYM(LOGS_SYM),0,0},
@@ -247,6 +255,7 @@ static SYMBOL symbols[] = {
{ "MIN_ROWS", SYM(MIN_ROWS),0,0},
{ "MINUTE", SYM(MINUTE_SYM),0,0},
{ "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM),0,0},
+ { "MOD", SYM(MOD_SYM),0,0},
{ "MODE", SYM(MODE_SYM),0,0},
{ "MODIFY", SYM(MODIFY_SYM),0,0},
{ "MONTH", SYM(MONTH_SYM),0,0},
@@ -262,6 +271,7 @@ static SYMBOL symbols[] = {
{ "NOT", SYM(NOT),0,0},
{ "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
+ { "OFFSET", SYM(OFFSET_SYM),0,0},
{ "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
@@ -313,6 +323,7 @@ static SYMBOL symbols[] = {
{ "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
+ { "SERIAL", SYM(SERIAL_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
{ "SESSION", SYM(SESSION_SYM),0,0},
{ "SET", SYM(SET),0,0},
@@ -323,6 +334,7 @@ static SYMBOL symbols[] = {
{ "SHUTDOWN", SYM(SHUTDOWN),0,0},
{ "SLAVE", SYM(SLAVE),0,0},
{ "SMALLINT", SYM(SMALLINT),0,0},
+ { "SOME", SYM(ANY_SYM),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
@@ -331,7 +343,7 @@ static SYMBOL symbols[] = {
{ "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
{ "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0},
- { "SQL_THREAD", SYM(SQL_THREAD),0,0},
+ { "SQL_THREAD", SYM(SQL_THREAD),0,0},
{ "SSL", SYM(SSL_SYM),0,0},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0},
{ "START", SYM(START_SYM),0,0},
@@ -356,6 +368,7 @@ static SYMBOL symbols[] = {
{ "TRAILING", SYM(TRAILING),0,0},
{ "TRANSACTION", SYM(TRANSACTION_SYM),0,0},
{ "TRUNCATE", SYM(TRUNCATE_SYM),0,0},
+ { "TRUE", SYM(TRUE_SYM),0,0},
{ "TO", SYM(TO_SYM),0,0},
{ "TYPE", SYM(TYPE_SYM),0,0},
{ "TYPES", SYM(TYPES_SYM),0,0},
@@ -369,8 +382,10 @@ static SYMBOL symbols[] = {
{ "USING", SYM(USING),0,0},
{ "UPDATE", SYM(UPDATE_SYM),0,0},
{ "USAGE", SYM(USAGE),0,0},
+ { "VALUE", SYM(VALUE_SYM),0,0},
{ "VALUES", SYM(VALUES),0,0},
{ "VARCHAR", SYM(VARCHAR),0,0},
+ { "VARCHARACTER", SYM(VARCHAR),0,0},
{ "VARIABLES", SYM(VARIABLES),0,0},
{ "VARYING", SYM(VARYING),0,0},
{ "VARBINARY", SYM(VARBINARY),0,0},
@@ -407,7 +422,9 @@ static SYMBOL sql_functions[] = {
{ "BIT_OR", SYM(BIT_OR),0,0},
{ "BIT_AND", SYM(BIT_AND),0,0},
{ "CAST", SYM(CAST_SYM),0,0},
+ { "CEIL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
+ { "CURRENT_USER", SYM(USER),0,0},
{ "BIT_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_length)},
{ "CENTROID", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_centroid)},
{ "CHAR_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
@@ -499,7 +516,6 @@ static SYMBOL sql_functions[] = {
{ "MD5", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_md5)},
{ "MID", SYM(SUBSTRING),0,0}, /* unireg function */
{ "MIN", SYM(MIN_SYM),0,0},
- { "MOD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_mod)},
{ "MLINEFROMTEXT", SYM(MLINEFROMTEXT),0,0},
{ "MPOINTFROMTEXT", SYM(MPOINTFROMTEXT),0,0},
{ "MPOLYFROMTEXT", SYM(MPOLYFROMTEXT),0,0},
@@ -514,6 +530,7 @@ 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 3b2444c8e9d..74d1109b203 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -80,7 +80,7 @@ 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(TABLE **table,uint count);
+static int lock_external(THD *thd, TABLE **table,uint count);
static int unlock_external(THD *thd, TABLE **table,uint count);
static void print_lock_error(int error);
@@ -116,14 +116,14 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
}
thd->proc_info="System lock";
- if (lock_external(tables,count))
+ if (lock_external(thd, tables, count))
{
my_free((gptr) sql_lock,MYF(0));
sql_lock=0;
thd->proc_info=0;
break;
}
- thd->proc_info=0;
+ thd->proc_info="Table lock";
thd->locked=1;
if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count))
{
@@ -142,6 +142,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
thd->locked=0;
break;
}
+ thd->proc_info=0;
/* some table was altered or deleted. reopen tables marked deleted */
mysql_unlock_tables(thd,sql_lock);
@@ -151,6 +152,7 @@ retry:
if (wait_for_tables(thd))
break; // Couldn't open tables
}
+ thd->proc_info=0;
if (thd->killed)
{
my_error(ER_SERVER_SHUTDOWN,MYF(0));
@@ -166,15 +168,15 @@ retry:
}
-static int lock_external(TABLE **tables,uint count)
+static int lock_external(THD *thd, TABLE **tables, uint count)
{
reg1 uint i;
int lock_type,error;
- THD *thd=current_thd;
DBUG_ENTER("lock_external");
for (i=1 ; i <= count ; i++, tables++)
{
+ DBUG_ASSERT((*tables)->reginfo.lock_type >= TL_READ);
lock_type=F_WRLCK; /* Lock exclusive */
if ((*tables)->db_stat & HA_READ_ONLY ||
((*tables)->reginfo.lock_type >= TL_READ &&
diff --git a/sql/log.cc b/sql/log.cc
index 286dba3f79b..dc7b5789efb 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1026,9 +1026,13 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
bool MYSQL_LOG::write(Log_event* event_info)
{
bool error=0;
+ DBUG_ENTER("MYSQL_LOG::write(event)");
if (!inited) // Can't use mutex if not init
- return 0;
+ {
+ DBUG_PRINT("error",("not initied"));
+ DBUG_RETURN(0);
+ }
pthread_mutex_lock(&LOCK_log);
/* In most cases this is only called if 'is_open()' is true */
@@ -1036,7 +1040,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
{
bool should_rotate = 0;
THD *thd=event_info->thd;
- const char* db = event_info->get_db();
+ const char *local_db = event_info->get_db();
#ifdef USING_TRANSACTIONS
IO_CACHE *file = ((event_info->get_cache_stmt()) ?
&thd->transaction.trans_log :
@@ -1046,10 +1050,11 @@ bool MYSQL_LOG::write(Log_event* event_info)
#endif
if ((thd && !(thd->options & OPTION_BIN_LOG) &&
(thd->master_access & SUPER_ACL)) ||
- (db && !db_ok(db, binlog_do_db, binlog_ignore_db)))
+ (local_db && !db_ok(local_db, binlog_do_db, binlog_ignore_db)))
{
VOID(pthread_mutex_unlock(&LOCK_log));
- return 0;
+ DBUG_PRINT("error",("!db_ok"));
+ DBUG_RETURN(0);
}
error=1;
@@ -1057,40 +1062,44 @@ bool MYSQL_LOG::write(Log_event* event_info)
No check for auto events flag here - this write method should
never be called if auto-events are enabled
*/
- if (thd && thd->last_insert_id_used)
- {
- Intvar_log_event e(thd,(uchar)LAST_INSERT_ID_EVENT,thd->last_insert_id);
- e.set_log_pos(this);
- if (thd->server_id)
- e.server_id = thd->server_id;
- if (e.write(file))
- goto err;
- }
- if (thd && thd->insert_id_used)
- {
- Intvar_log_event e(thd,(uchar)INSERT_ID_EVENT,thd->last_insert_id);
- e.set_log_pos(this);
- if (thd->server_id)
- e.server_id = thd->server_id;
- if (e.write(file))
- goto err;
- }
- if (thd && thd->rand_used)
+ if (thd)
{
- Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
- e.set_log_pos(this);
- if (e.write(file))
- goto err;
- }
- if (thd && thd->variables.convert_set)
- {
- char buf[1024] = "SET CHARACTER SET ";
- char* p = strend(buf);
- p = strmov(p, thd->variables.convert_set->name);
- Query_log_event e(thd, buf, (ulong)(p - buf));
- e.set_log_pos(this);
- if (e.write(file))
- goto err;
+ if (thd->last_insert_id_used)
+ {
+ Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
+ thd->last_insert_id);
+ e.set_log_pos(this);
+ if (thd->server_id)
+ e.server_id = thd->server_id;
+ if (e.write(file))
+ goto err;
+ }
+ if (thd->insert_id_used)
+ {
+ Intvar_log_event e(thd,(uchar) INSERT_ID_EVENT,thd->last_insert_id);
+ e.set_log_pos(this);
+ if (thd->server_id)
+ e.server_id = thd->server_id;
+ if (e.write(file))
+ goto err;
+ }
+ if (thd->rand_used)
+ {
+ Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
+ if (thd->variables.convert_set)
+ {
+ char buf[256], *p;
+ p= strmov(strmov(buf, "SET CHARACTER SET "),
+ thd->variables.convert_set->name);
+ Query_log_event e(thd, buf, (ulong) (p - buf), 0);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
}
event_info->set_log_pos(this);
if (event_info->write(file) ||
@@ -1135,7 +1144,7 @@ err:
}
pthread_mutex_unlock(&LOCK_log);
- return error;
+ DBUG_RETURN(error);
}
@@ -1165,6 +1174,7 @@ uint MYSQL_LOG::next_file_id()
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
{
VOID(pthread_mutex_lock(&LOCK_log));
+ DBUG_ENTER("MYSQL_LOG::write(cache");
if (is_open()) // Should always be true
{
@@ -1223,7 +1233,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
signal_update();
}
VOID(pthread_mutex_unlock(&LOCK_log));
- return 0;
+ DBUG_RETURN(0);
err:
if (!write_error)
@@ -1232,7 +1242,7 @@ err:
sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
}
VOID(pthread_mutex_unlock(&LOCK_log));
- return 1;
+ DBUG_RETURN(1);
}
@@ -1242,7 +1252,7 @@ err:
*/
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
- time_t query_start)
+ time_t query_start_arg)
{
bool error=0;
if (is_open())
@@ -1260,7 +1270,7 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
VOID(pthread_mutex_unlock(&LOCK_log));
return 0;
}
- if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start)
+ if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg)
{
current_time=time(NULL);
if (current_time != last_time)
@@ -1288,13 +1298,13 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
thd->ip ? thd->ip : "") == (uint) -1)
tmp_errno=errno;
}
- if (query_start)
+ if (query_start_arg)
{
/* For slow query log */
if (my_b_printf(&log_file,
"# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n",
- (ulong) (current_time - query_start),
- (ulong) (thd->time_after_lock - query_start),
+ (ulong) (current_time - query_start_arg),
+ (ulong) (thd->time_after_lock - query_start_arg),
(ulong) thd->sent_row_count,
(ulong) thd->examined_row_count) == (uint) -1)
tmp_errno=errno;
@@ -1321,11 +1331,11 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
}
if (thd->query_start_used)
{
- if (query_start != thd->query_start())
+ if (query_start_arg != thd->query_start())
{
- query_start=thd->query_start();
+ query_start_arg=thd->query_start();
end=strmov(end,",timestamp=");
- end=int10_to_str((long) query_start,end,10);
+ end=int10_to_str((long) query_start_arg,end,10);
}
}
if (end != buff)
diff --git a/sql/log_event.cc b/sql/log_event.cc
index c168c951c8f..5050bba9965 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -235,22 +235,25 @@ const char* Log_event::get_type_str()
****************************************************************************/
#ifndef MYSQL_CLIENT
-Log_event::Log_event(THD* thd_arg, uint16 flags_arg)
- :exec_time(0), flags(flags_arg), cached_event_len(0),
- temp_buf(0), thd(thd_arg)
+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)
{
- if (thd)
- {
- server_id = thd->server_id;
- when = thd->start_time;
- log_pos = thd->log_pos;
- }
- else
- {
- server_id = ::server_id;
- when = time(NULL);
- log_pos =0;
- }
+ 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)));
+}
+
+
+Log_event::Log_event()
+ :temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0),
+ thd(0)
+{
+ server_id= ::server_id;
+ when= time(NULL);
+ log_pos= 0;
}
#endif // !MYSQL_CLIENT
@@ -260,7 +263,7 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg)
****************************************************************************/
Log_event::Log_event(const char* buf, bool old_format)
- :cached_event_len(0), temp_buf(0)
+ :temp_buf(0), cached_event_len(0), cache_stmt(0)
{
when = uint4korr(buf);
server_id = uint4korr(buf + SERVER_ID_OFFSET);
@@ -330,11 +333,11 @@ void Log_event::init_show_field_list(List<Item>* field_list)
Only called by SHOW BINLOG EVENTS
****************************************************************************/
-int Log_event::net_send(THD* thd, const char* log_name, my_off_t pos)
+int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos)
{
- String* packet = &thd->packet;
- const char* p = strrchr(log_name, FN_LIBCHAR);
- const char* event_type;
+ String* packet = &thd_arg->packet;
+ const char *p= strrchr(log_name, FN_LIBCHAR);
+ const char *event_type;
if (p)
log_name = p + 1;
@@ -346,7 +349,7 @@ int Log_event::net_send(THD* thd, const char* log_name, my_off_t pos)
net_store_data(packet, server_id);
net_store_data(packet, (longlong) log_pos);
pack_info(packet);
- return my_net_write(&thd->net, (char*) packet->ptr(), packet->length());
+ return my_net_write(&thd_arg->net, (char*) packet->ptr(), packet->length());
}
#endif // !MYSQL_CLIENT
@@ -725,12 +728,10 @@ int Query_log_event::write_data(IO_CACHE* file)
#ifndef MYSQL_CLIENT
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans)
- :Log_event(thd_arg), data_buf(0), query(query_arg), db(thd_arg->db),
- q_len((uint32) query_length),
+ :Log_event(thd_arg, 0, using_trans), data_buf(0), query(query_arg),
+ db(thd_arg->db), q_len((uint32) query_length),
error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
- thread_id(thd_arg->thread_id),
- cache_stmt(using_trans &&
- (thd_arg->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ thread_id(thd_arg->thread_id)
{
time_t end_time;
time(&end_time);
@@ -1155,18 +1156,19 @@ int Load_log_event::write_data_body(IO_CACHE* file)
****************************************************************************/
#ifndef MYSQL_CLIENT
-Load_log_event::Load_log_event(THD* thd, sql_exchange* ex,
- const char* db_arg, const char* table_name_arg,
- List<Item>& fields_arg,
- enum enum_duplicates handle_dup)
- :Log_event(thd),thread_id(thd->thread_id), num_fields(0),fields(0),
- field_lens(0),field_block_len(0),
- table_name(table_name_arg ? table_name_arg : ""),
- db(db_arg), fname(ex->file_name)
+Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
+ const char *db_arg, const char *table_name_arg,
+ List<Item> &fields_arg,
+ enum enum_duplicates handle_dup,
+ bool using_trans)
+ :Log_event(thd_arg, 0, using_trans), thread_id(thd_arg->thread_id),
+ num_fields(0), fields(0), field_lens(0),field_block_len(0),
+ table_name(table_name_arg ? table_name_arg : ""),
+ db(db_arg), fname(ex->file_name)
{
time_t end_time;
time(&end_time);
- exec_time = (ulong) (end_time - thd->start_time);
+ exec_time = (ulong) (end_time - thd_arg->start_time);
/* db can never be a zero pointer in 4.0 */
db_len = (uint32) strlen(db);
table_name_len = (uint32) strlen(table_name);
@@ -1192,9 +1194,15 @@ Load_log_event::Load_log_event(THD* thd, sql_exchange* ex,
sql_ex.empty_flags = 0;
switch (handle_dup) {
- case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break;
- case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break;
- case DUP_ERROR: break;
+ case DUP_IGNORE:
+ sql_ex.opt_flags |= IGNORE_FLAG;
+ break;
+ case DUP_REPLACE:
+ sql_ex.opt_flags |= REPLACE_FLAG;
+ break;
+ case DUP_UPDATE: // Impossible here
+ case DUP_ERROR:
+ break;
}
if (!ex->field_term->length())
@@ -1236,11 +1244,11 @@ Load_log_event::Load_log_event(THD* thd, sql_exchange* ex,
constructed event.
****************************************************************************/
-Load_log_event::Load_log_event(const char* buf, int event_len,
- bool old_format):
- Log_event(buf, old_format),num_fields(0),fields(0),
- field_lens(0),field_block_len(0),
- table_name(0),db(0),fname(0)
+Load_log_event::Load_log_event(const char *buf, int event_len,
+ bool old_format)
+ :Log_event(buf, old_format),num_fields(0),fields(0),
+ field_lens(0),field_block_len(0),
+ table_name(0),db(0),fname(0)
{
if (!event_len) // derived class, will call copy_log_event() itself
return;
@@ -1390,14 +1398,14 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
****************************************************************************/
#ifndef MYSQL_CLIENT
-void Load_log_event::set_fields(List<Item> &fields)
+void Load_log_event::set_fields(List<Item> &field_list)
{
uint i;
- const char* field = this->fields;
- for (i = 0; i < num_fields; i++)
+ const char* field = fields;
+ for (i= 0; i < num_fields; i++)
{
- fields.push_back(new Item_field(db, table_name, field));
- field += field_lens[i] + 1;
+ field_list.push_back(new Item_field(db, table_name, field));
+ field+= field_lens[i] + 1;
}
}
#endif // !MYSQL_CLIENT
@@ -1458,8 +1466,8 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
ex.field_term->length(0);
ex.skip_lines = skip_lines;
- List<Item> fields;
- set_fields(fields);
+ List<Item> field_list;
+ set_fields(field_list);
thd->slave_proxy_id = thd->thread_id;
if (net)
{
@@ -1470,7 +1478,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
*/
thd->net.pkt_nr = net->pkt_nr;
}
- if (mysql_load(thd, &ex, &tables, fields, handle_dup, net != 0,
+ if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0,
TL_WRITE))
thd->query_error = 1;
if (thd->cuted_fields)
@@ -1795,14 +1803,12 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
#ifndef MYSQL_CLIENT
void Rand_log_event::pack_info(String* packet)
{
- char buf1[256], buf[22];
- String tmp(buf1, sizeof(buf1), system_charset_info);
- tmp.length(0);
- tmp.append("randseed1=");
- tmp.append(llstr(seed1, buf));
- tmp.append(",randseed2=");
- tmp.append(llstr(seed2, buf));
- net_store_data(packet, tmp.ptr(), tmp.length());
+ char buf1[256], *pos;
+ pos= strmov(buf1,"rand_seed1=");
+ pos= int10_to_str((long) seed1, pos, 10);
+ pos= strmov(pos, ",rand_seed2=");
+ pos= int10_to_str((long) seed2, pos, 10);
+ net_store_data(packet, buf1, (uint) (pos-buf1));
}
#endif // !MYSQL_CLIENT
@@ -1846,8 +1852,8 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
print_header(file);
fprintf(file, "\tRand\n");
}
- fprintf(file, "SET RAND SEED1=%s;\n", llstr(seed1, llbuff));
- fprintf(file, "SET RAND SEED2=%s;\n", llstr(seed2, llbuff));
+ fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
+ llstr(seed1, llbuff),llstr(seed2, llbuff));
fflush(file);
}
#endif // MYSQL_CLIENT
@@ -1860,8 +1866,8 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
#ifndef MYSQL_CLIENT
int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
- thd->rand.seed1 = seed1;
- thd->rand.seed2 = seed2;
+ thd->rand.seed1= (ulong) seed1;
+ thd->rand.seed2= (ulong) seed2;
rli->inc_pending(get_event_len());
return 0;
}
@@ -1907,8 +1913,8 @@ void Slave_log_event::pack_info(String* packet)
****************************************************************************/
#ifndef MYSQL_CLIENT
Slave_log_event::Slave_log_event(THD* thd_arg,
- struct st_relay_log_info* rli):
- Log_event(thd_arg),mem_pool(0),master_host(0)
+ struct st_relay_log_info* rli)
+ :Log_event(thd_arg, 0, 0), mem_pool(0), master_host(0)
{
DBUG_ENTER("Slave_log_event");
if (!rli->inited) // QQ When can this happen ?
@@ -2120,11 +2126,13 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
****************************************************************************/
#ifndef MYSQL_CLIENT
-Create_file_log_event::Create_file_log_event(THD* thd_arg, sql_exchange* ex,
- const char* db_arg, const char* table_name_arg,
- List<Item>& fields_arg, enum enum_duplicates handle_dup,
- char* block_arg, uint block_len_arg)
- :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup),
+Create_file_log_event::
+Create_file_log_event(THD* thd_arg, sql_exchange* ex,
+ const char* db_arg, const char* table_name_arg,
+ List<Item>& fields_arg, enum enum_duplicates handle_dup,
+ char* block_arg, uint block_len_arg, bool using_trans)
+ :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup,
+ using_trans),
fake_base(0),block(block_arg),block_len(block_len_arg),
file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
{
@@ -2327,9 +2335,10 @@ err:
****************************************************************************/
#ifndef MYSQL_CLIENT
Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
- uint block_len_arg)
- :Log_event(thd_arg), block(block_arg),block_len(block_len_arg),
- file_id(thd_arg->file_id)
+ 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)
{
}
#endif // !MYSQL_CLIENT
@@ -2447,8 +2456,8 @@ err:
****************************************************************************/
#ifndef MYSQL_CLIENT
-Delete_file_log_event::Delete_file_log_event(THD* thd_arg)
- :Log_event(thd_arg),file_id(thd_arg->file_id)
+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)
{
}
#endif // !MYSQL_CLIENT
@@ -2545,8 +2554,8 @@ 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)
- :Log_event(thd_arg),file_id(thd_arg->file_id)
+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)
{
}
#endif // !MYSQL_CLIENT
@@ -2556,8 +2565,8 @@ Execute_load_log_event::Execute_load_log_event(THD* thd_arg)
Execute_load_log_event ctor
****************************************************************************/
-Execute_load_log_event::Execute_load_log_event(const char* buf,int len)
- :Log_event(buf, 0),file_id(0)
+Execute_load_log_event::Execute_load_log_event(const char* buf, int len)
+ :Log_event(buf, 0), file_id(0)
{
if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
return;
diff --git a/sql/log_event.h b/sql/log_event.h
index bf04c480729..20a134ab3cc 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -247,18 +247,19 @@ struct st_relay_log_info;
class Log_event
{
public:
+ my_off_t log_pos;
+ char *temp_buf;
time_t when;
ulong exec_time;
uint32 server_id;
- my_off_t log_pos;
+ uint cached_event_len;
uint16 flags;
- int cached_event_len;
- char* temp_buf;
-
+ bool cache_stmt;
#ifndef MYSQL_CLIENT
THD* thd;
- Log_event(THD* thd_arg, uint16 flags_arg = 0);
+ Log_event(THD* thd_arg, uint16 flags_arg, bool cache_stmt);
+ Log_event();
// if mutex is 0, the read will proceed without mutex
static Log_event* read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
@@ -301,7 +302,7 @@ public:
{ return 0; }
virtual Log_event_type get_type_code() = 0;
virtual bool is_valid() = 0;
- virtual bool get_cache_stmt() { return 0; }
+ inline bool get_cache_stmt() { return cache_stmt; }
Log_event(const char* buf, bool old_format);
virtual ~Log_event() { free_temp_buf();}
void register_temp_buf(char* buf) { temp_buf = buf; }
@@ -350,14 +351,12 @@ public:
uint16 error_code;
ulong thread_id;
#ifndef MYSQL_CLIENT
- bool cache_stmt;
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
- bool using_trans=0);
+ bool using_trans);
const char* get_db() { return db; }
void pack_info(String* packet);
int exec_event(struct st_relay_log_info* rli);
- bool get_cache_stmt() { return cache_stmt; }
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -445,14 +444,15 @@ public:
const char* fname;
uint32 skip_lines;
sql_ex_info sql_ex;
-
+
#ifndef MYSQL_CLIENT
String field_lens_buf;
String fields_buf;
Load_log_event(THD* thd, sql_exchange* ex, const char* db_arg,
const char* table_name_arg,
- List<Item>& fields_arg, enum enum_duplicates handle_dup);
+ List<Item>& fields_arg, enum enum_duplicates handle_dup,
+ bool using_trans);
void set_fields(List<Item> &fields_arg);
void pack_info(String* packet);
const char* get_db() { return db; }
@@ -468,8 +468,10 @@ public:
Load_log_event(const char* buf, int event_len, bool old_format);
~Load_log_event()
{}
- Log_event_type get_type_code() { return sql_ex.new_format() ?
- NEW_LOAD_EVENT: LOAD_EVENT; }
+ Log_event_type get_type_code()
+ {
+ return sql_ex.new_format() ? NEW_LOAD_EVENT: LOAD_EVENT;
+ }
int write_data_header(IO_CACHE* file);
int write_data_body(IO_CACHE* file);
bool is_valid() { return table_name != 0; }
@@ -500,7 +502,7 @@ public:
char server_version[ST_SERVER_VER_LEN];
#ifndef MYSQL_CLIENT
- Start_log_event() :Log_event((THD*)0),binlog_version(BINLOG_VERSION)
+ Start_log_event() :Log_event(), binlog_version(BINLOG_VERSION)
{
created = (uint32) when;
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
@@ -538,7 +540,7 @@ public:
#ifndef MYSQL_CLIENT
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
- :Log_event(thd_arg),val(val_arg),type(type_arg)
+ :Log_event(),val(val_arg),type(type_arg)
{}
void pack_info(String* packet);
int exec_event(struct st_relay_log_info* rli);
@@ -570,7 +572,7 @@ class Rand_log_event: public Log_event
#ifndef MYSQL_CLIENT
Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg)
- :Log_event(thd_arg),seed1(seed1_arg),seed2(seed2_arg)
+ :Log_event(thd_arg,0,0),seed1(seed1_arg),seed2(seed2_arg)
{}
void pack_info(String* packet);
int exec_event(struct st_relay_log_info* rli);
@@ -596,7 +598,7 @@ class Stop_log_event: public Log_event
{
public:
#ifndef MYSQL_CLIENT
- Stop_log_event() :Log_event((THD*)0)
+ Stop_log_event() :Log_event()
{}
int exec_event(struct st_relay_log_info* rli);
#else
@@ -628,8 +630,9 @@ public:
bool alloced;
#ifndef MYSQL_CLIENT
Rotate_log_event(THD* thd_arg, const char* new_log_ident_arg,
- uint ident_len_arg = 0,ulonglong pos_arg = 4)
- : Log_event(thd_arg), new_log_ident(new_log_ident_arg),
+ uint ident_len_arg = 0,
+ ulonglong pos_arg = LOG_EVENT_OFFSET)
+ :Log_event(thd_arg,0,0), new_log_ident(new_log_ident_arg),
pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
(uint) strlen(new_log_ident_arg)), alloced(0)
{}
@@ -678,7 +681,8 @@ public:
const char* table_name_arg,
List<Item>& fields_arg,
enum enum_duplicates handle_dup,
- char* block_arg, uint block_len_arg);
+ char* block_arg, uint block_len_arg,
+ bool using_trans);
void pack_info(String* packet);
int exec_event(struct st_relay_log_info* rli);
#else
@@ -728,7 +732,7 @@ public:
#ifndef MYSQL_CLIENT
Append_block_log_event(THD* thd, char* block_arg,
- uint block_len_arg);
+ uint block_len_arg, bool using_trans);
int exec_event(struct st_relay_log_info* rli);
void pack_info(String* packet);
#else
@@ -754,7 +758,7 @@ public:
uint file_id;
#ifndef MYSQL_CLIENT
- Delete_file_log_event(THD* thd);
+ Delete_file_log_event(THD* thd, bool using_trans);
void pack_info(String* packet);
int exec_event(struct st_relay_log_info* rli);
#else
@@ -780,7 +784,7 @@ public:
uint file_id;
#ifndef MYSQL_CLIENT
- Execute_load_log_event(THD* thd);
+ Execute_load_log_event(THD* thd, bool using_trans);
void pack_info(String* packet);
int exec_event(struct st_relay_log_info* rli);
#else
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
index aa84a52eb0b..83f68a28228 100644
--- a/sql/mini_client.cc
+++ b/sql/mini_client.cc
@@ -87,7 +87,9 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
-#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
+ CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION)
+
#if defined(MSDOS) || defined(__WIN__)
#define perror(A)
@@ -295,11 +297,11 @@ static int mc_sock_connect(my_socket s, const struct sockaddr *name,
FD_SET(s, &sfds);
tv.tv_sec = (long) to;
tv.tv_usec = 0;
-#ifdef HPUX
+#ifdef HPUX10
res = select(s+1, NULL, (int*) &sfds, NULL, &tv);
#else
res = select(s+1, NULL, &sfds, NULL, &tv);
-#endif
+#endif /* HPUX10 */
if (res <= 0) /* Never became writable */
return(-1);
@@ -326,7 +328,7 @@ static int mc_sock_connect(my_socket s, const struct sockaddr *name,
** or packet is an error message
*****************************************************************************/
-ulong
+ulong
mc_net_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
@@ -431,7 +433,7 @@ my_bool mc_mysql_reconnect(MYSQL *mysql)
-int
+int
mc_simple_command(MYSQL *mysql,enum enum_server_command command,
const char *arg, uint length, my_bool skipp_check)
{
@@ -481,13 +483,14 @@ mc_simple_command(MYSQL *mysql,enum enum_server_command command,
}
-MYSQL *
+MYSQL *
mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag,
uint net_read_timeout)
{
char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info;
+ char password_hash[SCRAMBLE41_LENGTH];
my_socket sock;
ulong ip_addr;
struct sockaddr_in sock_addr;
@@ -510,7 +513,6 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
user ? user : "(Null)",
net_read_timeout,
(uint) slave_net_timeout));
-
net->vio = 0; /* If something goes wrong */
mysql->charset=default_charset_info; /* Set character set */
if (!port)
@@ -660,7 +662,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
vio_poll_read(net->vio, mysql->options.connect_timeout))
{
net->last_errno= CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ strmov(net->last_error,ER(net->last_errno));
goto error;
}
if ((pkt_length=mc_net_safe_read(mysql)) == packet_error)
@@ -775,7 +777,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Do the SSL layering. */
@@ -799,22 +801,103 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
}
DBUG_PRINT("info",("user: %s",buff+5));
- end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
- (my_bool) (mysql->protocol_version == 9));
- if (db)
+
+ /*
+ We always start with old type handshake the only difference is message sent
+ If server handles secure connection type we'll not send the real scramble
+ */
+ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+ {
+ if (passwd[0])
+ {
+ /* Prepare false scramble */
+ end=strend(buff+5)+1;
+ bfill(end, SCRAMBLE_LENGTH, 'x');
+ end+=SCRAMBLE_LENGTH;
+ *end=0;
+ }
+ else /* For empty password*/
+ {
+ end=strend(buff+5)+1;
+ *end=0; /* Store zero length scramble */
+ }
+ }
+ else
+ /*
+ Real scramble is only sent to old servers. This can be blocked
+ by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
+ */
+ end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+
+ /* Add database if needed */
+ if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME));
db=0;
}
+ /* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ strmov(net->last_error,ER(net->last_errno));
goto error;
}
- if (mc_net_safe_read(mysql) == packet_error)
+
+ /* We shall only query sever if it expect us to do so */
+
+ if ( (pkt_length=mc_net_safe_read(mysql)) == packet_error)
goto error;
+
+ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+ {
+ /* This should always happen with new server unless empty password */
+ if (pkt_length==24 && net->read_pos[0])
+ /* OK/Error message has zero as the first character */
+ {
+ /* Old passwords will have zero at the first byte of hash */
+ if (net->read_pos[0] != '*')
+ {
+ /* Build full password hash as it is required to decode scramble */
+ password_hash_stage1(buff, passwd);
+ /* Store copy as we'll need it later */
+ memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
+ /* Finally hash complete password using hash we got from server */
+ password_hash_stage2(password_hash,(char*)net->read_pos);
+ /* Decypt and store scramble 4 = hash for stage2 */
+ password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,
+ SCRAMBLE41_LENGTH);
+ mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
+ /* Encode scramble with password. Recycle buffer */
+ password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
+ }
+ else
+ {
+ /* Create password to decode scramble */
+ create_key_from_old_password(passwd,password_hash);
+ /* Decypt and store scramble 4 = hash for stage2 */
+ password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,
+ SCRAMBLE41_LENGTH);
+ mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
+ /* Finally scramble decoded scramble with password */
+ scramble(buff, mysql->scramble_buff, passwd,0);
+ }
+ /* Write second package of authentication */
+ if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
+ {
+ net->last_errno= CR_SERVER_LOST;
+ strmov(net->last_error,ER(net->last_errno));
+ goto error;
+ }
+ /* Read What server thinks about out new auth message report */
+ if (mc_net_safe_read(mysql) == packet_error)
+ goto error;
+ }
+ }
+
+ /* End of authentication part of handshake */
+
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1;
DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
@@ -841,7 +924,7 @@ error:
** NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************
*/
-int
+int
mysql_ssl_clear(MYSQL *mysql)
{
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
@@ -866,7 +949,7 @@ mysql_ssl_clear(MYSQL *mysql)
** If handle is alloced by mysql connect free it.
*************************************************************************/
-void
+void
mc_mysql_close(MYSQL *mysql)
{
DBUG_ENTER("mysql_close");
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 7788056138c..771d105a1c7 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -68,7 +68,9 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
****************************************************************************/
#define ACL_CACHE_SIZE 256
-#define HASH_PASSWORD_LENGTH 16
+/* 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 HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32
@@ -85,6 +87,7 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
*/
#define MIN_FILE_LENGTH_TO_USE_ROW_CACHE (16L*1024*1024)
#define MIN_ROWS_TO_USE_TABLE_CACHE 100
+#define MIN_ROWS_TO_USE_BULK_INSERT 100
/*
The following is used to decide if MySQL should use table scanning
@@ -201,6 +204,11 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define MODE_SERIALIZABLE 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 RAID_BLOCK_SIZE 1024
@@ -243,6 +251,20 @@ typedef struct st_sql_list {
uint elements;
byte *first;
byte **next;
+
+ inline void empty()
+ {
+ elements=0;
+ first=0;
+ next= &first;
+ }
+ inline void link_in_list(byte *element,byte **next_ptr)
+ {
+ elements++;
+ (*next)=element;
+ next= next_ptr;
+ *next=0;
+ }
} SQL_LIST;
@@ -263,6 +285,7 @@ inline THD *_current_thd(void)
#include "field.h" /* Field definitions */
#include "sql_udf.h"
#include "item.h"
+typedef compare_func_creator (*chooser_compare_func_creator)(bool invert);
#include "sql_class.h"
#include "opt_range.h"
@@ -314,16 +337,14 @@ void free_items(Item *item);
bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
void mysql_init_query(THD *thd);
-void mysql_reset_errors(THD *thd);
bool mysql_new_select(LEX *lex, bool move_down);
void create_select_for_variable(const char *var_name);
void mysql_init_multi_delete(LEX *lex);
void init_max_user_conn(void);
void init_update_queries(void);
void free_max_user_conn(void);
-pthread_handler_decl(handle_one_connection,arg);
-pthread_handler_decl(handle_bootstrap,arg);
-sig_handler end_thread_signal(int sig);
+extern "C" pthread_handler_decl(handle_one_connection,arg);
+extern "C" pthread_handler_decl(handle_bootstrap,arg);
void end_thread(THD *thd,bool put_in_cache);
void flush_thread_cache();
void mysql_execute_command(THD *thd);
@@ -399,8 +420,7 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
int mysql_union(THD *thd, LEX *lex,select_result *result);
-int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t,
- bool tables_is_opened);
+int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group,bool modify_item);
@@ -424,7 +444,7 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
- bool simple_alter=0);
+ bool simple_alter=0);
bool mysql_rename_table(enum db_type base,
const char *old_db,
const char * old_name,
@@ -435,16 +455,20 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &values,COND *conds,
+ List<Item> &values,COND *conds,
ORDER *order, ha_rows limit,
- enum enum_duplicates handle_duplicates,
- thr_lock_type lock_type);
+ enum enum_duplicates handle_duplicates);
+int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
+ List<Item> *fields, List<Item> *values,
+ COND *conds, ulong options,
+ enum enum_duplicates handle_duplicates,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
- List<List_item> &values, enum_duplicates flag,
- thr_lock_type lock_type);
+ List<List_item> &values, List<Item> &update_fields,
+ List<Item> &update_values, enum_duplicates flag);
void kill_delayed_threads(void);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
- ha_rows rows, thr_lock_type lock_type, ulong options);
+ ha_rows rows, ulong options);
int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok=0);
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update);
TABLE *open_table(THD *thd,const char *db,const char *table,const char *alias,
@@ -461,14 +485,14 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock);
bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
extern const Field *not_found_field;
-Field *find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
+Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
bool report_error);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
#ifdef HAVE_OPENSSL
-struct st_des_keyblock
-{
- des_cblock key1, key2, key3;
+struct st_des_keyblock
+{
+ des_cblock key1, key2, key3;
};
struct st_des_keyschedule
{
@@ -496,7 +520,7 @@ int mysqld_show_logs(THD *thd);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1);
int mysqld_show_create(THD *thd, TABLE_LIST *table_list);
-int mysqld_show_create_db(THD *thd, const char *dbname);
+int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create);
void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
@@ -510,11 +534,11 @@ int mysqld_show_column_types(THD *thd);
int mysqld_help (THD *thd, const char *text);
/* sql_prepare.cc */
-int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used);
+int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key);
void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used);
bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
void mysql_stmt_execute(THD *thd, char *packet);
-void mysql_stm_close(THD *thd, char *packet);
+void mysql_stmt_free(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);
@@ -522,6 +546,8 @@ int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
/* sql_error.cc */
void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
const char *msg);
+void store_warning(THD *thd, uint errcode, ...);
+void mysql_reset_errors(THD *thd);
my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
/* sql_handler.cc */
@@ -532,16 +558,16 @@ int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
/* sql_base.cc */
void set_item_name(Item *item,char *pos,uint length);
-bool add_field_to_list(char *field_name, enum enum_field_types type,
+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,
char *change, TYPELIB *interval,CHARSET_INFO *cs);
void store_position_for_column(const char *name);
-bool add_to_list(SQL_LIST &list,Item *group,bool asc=0);
+bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
-bool add_proc_to_list(Item *item);
+bool add_proc_to_list(THD *thd, Item *item);
TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
@@ -549,9 +575,9 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS};
extern const Item **not_found_item;
-Item ** find_item_in_list(Item *item, List<Item> &items,
+Item ** find_item_in_list(Item *item, List<Item> &items,
find_item_error_report_type report_error);
-bool insert_fields(THD *thd,TABLE_LIST *tables,
+bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
List_iterator<Item> *it);
bool setup_tables(TABLE_LIST *tables);
@@ -575,6 +601,11 @@ bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_thread_tables(THD *thd,bool locked=0);
bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd);
+TABLE_LIST * find_table_in_list(TABLE_LIST *table,
+ const char *db_name, const char *table_name);
+TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1);
@@ -605,7 +636,7 @@ int write_record(TABLE *table,COPY_INFO *info);
extern ulong volatile manager_status;
extern bool volatile manager_thread_in_use, mqh_used;
extern pthread_t manager_thread;
-pthread_handler_decl(handle_manager, arg);
+extern "C" pthread_handler_decl(handle_manager, arg);
/* sql_test.cc */
#ifndef DBUG_OFF
@@ -633,6 +664,8 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
const char *index_file_name,
enum_log_type type, bool read_append = 0,
bool no_auto_events = 0);
+/* mysqld.cc */
+void clear_error_message(THD *thd);
/*
External variables
@@ -653,6 +686,7 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
extern char pidfile_name[FN_REFLEN], time_zone[30], *opt_init_file;
extern char blob_newline;
extern double log_10[32];
+extern ulonglong keybuff_size;
extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables;
extern ulong created_tmp_tables, created_tmp_disk_tables;
extern ulong aborted_threads,aborted_connects;
@@ -671,8 +705,7 @@ extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count;
extern ulong ha_read_key_count, ha_read_next_count, ha_read_prev_count;
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;
-extern ulong keybuff_size,table_cache_size;
+extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong max_insert_delayed_threads, max_user_connections;
extern ulong long_query_count, what_to_log,flush_time,opt_sql_mode;
@@ -721,6 +754,7 @@ extern SHOW_COMP_OPTION have_innodb;
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;
/* optional things, have_* variables */
@@ -758,7 +792,7 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
/* old unireg functions */
void unireg_init(ulong options);
-void unireg_end(int signal);
+void unireg_end(void);
int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info,
List<create_field> &create_field,
uint key_count,KEY *key_info);
@@ -787,7 +821,7 @@ timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(byte *,uint,char,char);
-void unireg_abort(int exit_code);
+extern "C" void unireg_abort(int exit_code);
void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
SQL_SELECT *select,
int use_record_cache, bool print_errors);
@@ -818,10 +852,6 @@ bool check_column_name(const char *name);
bool check_table_name(const char *name, uint length);
char *get_field(MEM_ROOT *mem,TABLE *table,uint fieldnr);
int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
-int wild_compare(const char *str,const char *str_end,
- const char *wildstr,const char *wildend,char escape);
-int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *str_end,
- const char *wildstr,const char *wildend,char escape);
/* from hostname.cc */
struct in_addr;
@@ -845,25 +875,37 @@ Item *get_system_var(enum_var_type var_type, const char *var_name, uint length,
/* Some inline functions for more speed */
-inline bool add_item_to_list(Item *item)
+inline bool add_item_to_list(THD *thd, Item *item)
{
- return current_lex->current_select->add_item_to_list(item);
+ return thd->lex.current_select->add_item_to_list(thd, item);
}
-inline bool add_value_to_list(Item *value)
+
+inline bool add_value_to_list(THD *thd, Item *value)
{
- return current_lex->value_list.push_back(value);
+ return thd->lex.value_list.push_back(value);
}
-inline bool add_order_to_list(Item *item, bool asc)
+
+inline bool add_order_to_list(THD *thd, Item *item, bool asc)
{
- return current_lex->current_select->add_order_to_list(item, asc);
+ return thd->lex.current_select->add_order_to_list(thd, item, asc);
}
-inline bool add_group_to_list(Item *item, bool asc)
+
+inline bool add_group_to_list(THD *thd, Item *item, bool asc)
{
- return current_lex->current_select->add_group_to_list(item, asc);
+ return thd->lex.current_select->add_group_to_list(thd, item, asc);
}
+
inline void mark_as_null_row(TABLE *table)
{
table->null_row=1;
table->status|=STATUS_NULL_ROW;
bfill(table->null_flags,table->null_bytes,255);
}
+
+compare_func_creator comp_eq_creator(bool invert);
+compare_func_creator comp_ge_creator(bool invert);
+compare_func_creator comp_gt_creator(bool invert);
+compare_func_creator comp_le_creator(bool invert);
+compare_func_creator comp_lt_creator(bool invert);
+compare_func_creator comp_ne_creator(bool invert);
+
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c57e0fc38d1..811713bec15 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -32,6 +32,7 @@
#include <nisam.h>
#include <thr_alarm.h>
#include <ft_global.h>
+#include <assert.h>
#ifndef DBUG_OFF
#define ONE_THREAD
@@ -56,7 +57,7 @@ char pstack_file_name[80];
#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ)
#define HAVE_CLOSE_SERVER_SOCK 1
-#endif
+#endif
extern "C" { // Because of SCO 3.2V4.2
#include <errno.h>
@@ -179,10 +180,13 @@ static char szPipeName [ 257 ];
static SECURITY_ATTRIBUTES saPipeSecurity;
static SECURITY_DESCRIPTOR sdPipeDescriptor;
static HANDLE hPipe = INVALID_HANDLE_VALUE;
-static pthread_cond_t COND_handler_count;
static uint handler_count;
+static bool opt_enable_named_pipe = 0;
#endif
#ifdef __WIN__
+static bool opt_console=0,start_mode=0;
+static pthread_cond_t COND_handler_count;
+static uint handler_count;
static bool opt_console=0, start_mode=0, use_opt_args;
static int opt_argc;
static char **opt_argv;
@@ -253,7 +257,7 @@ my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted
If set, some standard measures to enforce slave data integrity will not
be performed
*/
-my_bool opt_reckless_slave = 0;
+my_bool opt_reckless_slave = 0;
ulong back_log, connect_timeout, concurrency;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30];
@@ -276,9 +280,9 @@ static char* pidfile_name_ptr= pidfile_name;
static pthread_t select_thread;
static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
-my_bool opt_safe_show_db=0, lower_case_table_names, opt_old_rpl_compat;
+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;
+my_bool opt_log_slave_updates= 0, opt_old_passwords=0;
volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
@@ -319,7 +323,8 @@ ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL |
uint protocol_version=PROTOCOL_VERSION;
struct system_variables global_system_variables;
struct system_variables max_system_variables;
-ulong keybuff_size,table_cache_size,
+ulonglong keybuff_size;
+ulong table_cache_size,
thread_stack,
thread_stack_min,what_to_log= ~ (1L << (uint) COM_TIME),
query_buff_size,
@@ -334,6 +339,15 @@ ulong query_cache_size=0;
ulong query_cache_limit=0;
Query_cache query_cache;
#endif
+arg_cmp_func Arg_comparator::comparator_matrix[4][2] =
+{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
+ {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
+ {&Arg_comparator::compare_int, &Arg_comparator::compare_e_int},
+ {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}};
+#ifdef HAVE_SMEM
+static char *shared_memory_base_name=default_shared_memory_base_name;
+static bool opt_enable_shared_memory = 0;
+#endif
volatile ulong cached_thread_count=0;
@@ -341,9 +355,9 @@ volatile ulong cached_thread_count=0;
my_string master_user = (char*) "test", master_password = 0, master_host=0,
master_info_file = (char*) "master.info",
relay_log_info_file = (char*) "relay-log.info",
- master_ssl_key=0, master_ssl_cert=0;
+ master_ssl_key=0, master_ssl_cert=0, master_ssl_capath=0, master_ssl_cipher=0;
my_string report_user = 0, report_password = 0, report_host=0;
-
+
const char *localhost=LOCAL_HOST;
const char *delayed_user="DELAYED";
uint master_port = MYSQL_PORT, master_connect_retry = 60;
@@ -372,7 +386,7 @@ ulong max_connections,max_insert_delayed_threads,max_used_connections,
max_connect_errors, max_user_connections = 0;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0;
-
+
char mysql_real_data_home[FN_REFLEN],
language[LIBLEN],reg_ext[FN_EXTLEN],
mysql_charsets_dir[FN_REFLEN], *charsets_list,
@@ -406,8 +420,12 @@ time_t start_time;
ulong opt_sql_mode = 0L;
const char *sql_mode_names[] =
-{ "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
- "SERIALIZE","ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",NullS };
+{
+ "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE",
+ "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
+ "POSTGRESQL", "ORACLE", "MSSQL", "SAPDB",
+ NullS
+};
TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"",
sql_mode_names};
@@ -435,7 +453,7 @@ pthread_attr_t connection_attrib;
#include <process.h>
#if !defined(EMBEDDED_LIBRARY)
HANDLE hEventShutdown;
-static char *event_name;
+static char shutdown_event_name[40];
#include "nt_servc.h"
static NTService Service; // Service object for WinNT
#endif
@@ -446,20 +464,23 @@ pthread_cond_t eventShutdown;
#endif
static void start_signal_handler(void);
-static void *signal_hand(void *arg);
+extern "C" pthread_handler_decl(signal_hand, arg);
static void set_options(void);
static void get_options(int argc,char **argv);
static char *get_relative_path(const char *path);
static void fix_paths(void);
-static pthread_handler_decl(handle_connections_sockets,arg);
-static pthread_handler_decl(kill_server_thread,arg);
+extern "C" pthread_handler_decl(handle_connections_sockets,arg);
+extern "C" pthread_handler_decl(kill_server_thread,arg);
static int bootstrap(FILE *file);
static void close_server_sock();
static bool read_init_file(char *file_name);
#ifdef __NT__
-static pthread_handler_decl(handle_connections_namedpipes,arg);
+extern "C" pthread_handler_decl(handle_connections_namedpipes,arg);
#endif
-extern pthread_handler_decl(handle_slave,arg);
+#ifdef HAVE_SMEM
+static pthread_handler_decl(handle_connections_shared_memory,arg);
+#endif
+extern "C" pthread_handler_decl(handle_slave,arg);
#ifdef SET_RLIMIT_NOFILE
static uint set_maximum_open_files(uint max_file_limit);
#endif
@@ -538,7 +559,7 @@ static void close_connections(void)
{
HANDLE temp;
DBUG_PRINT( "quit", ("Closing named pipes") );
-
+
/* Create connection to the handle named pipe handler to break the loop */
if ((temp = CreateFile(szPipeName,
GENERIC_READ | GENERIC_WRITE,
@@ -657,7 +678,7 @@ static void close_server_sock()
The following code is disabled as it causes MySQL to hang on
AIX 4.3 during shutdown
*/
- DBUG_PRINT("info",("calling closesocket on TCP/IP socket"));
+ DBUG_PRINT("info",("calling closesocket on TCP/IP socket"));
VOID(closesocket(tmp_sock));
#endif
}
@@ -689,7 +710,7 @@ void kill_mysql(void)
#ifdef SIGNALS_DONT_BREAK_READ
abort_loop=1; // Break connection loops
close_server_sock(); // Force accept to wake up
-#endif
+#endif
#if defined(__WIN__)
#if !defined(EMBEDDED_LIBRARY)
@@ -727,7 +748,7 @@ void kill_mysql(void)
(void*) 0))
sql_print_error("Error: Can't create thread to kill server");
}
-#endif
+#endif
DBUG_VOID_RETURN;
}
@@ -766,14 +787,14 @@ static void __cdecl kill_server(int sig_ptr)
if (sig != MYSQL_KILL_SIGNAL && sig != 0)
unireg_abort(1); /* purecov: inspected */
else
- unireg_end(0);
+ unireg_end();
pthread_exit(0); /* purecov: deadcode */
RETURN_FROM_KILL_SERVER;
}
#ifdef USE_ONE_SIGNAL_HAND
-static pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
+extern "C" pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
{
SHUTDOWN_THD;
my_thread_init(); // Initialize new thread
@@ -788,7 +809,7 @@ static pthread_handler_decl(kill_server_thread,arg __attribute__((unused)))
#define sigset signal
#endif
-static sig_handler print_signal_warning(int sig)
+extern "C" sig_handler print_signal_warning(int sig)
{
if (!DBUG_IN_USE)
{
@@ -805,16 +826,33 @@ static sig_handler print_signal_warning(int sig)
#endif
}
+/*
+ cleanup all memory and end program nicely
+
+ SYNOPSIS
+ unireg_end()
+
+ NOTES
+ This function never returns.
+
+ If SIGNALS_DONT_BREAK_READ is defined, this function is called
+ by the main thread. To get MySQL to shut down nicely in this case
+ (Mac OS X) we have to call exit() instead if pthread_exit().
+*/
-void unireg_end(int signal_number __attribute__((unused)))
+void unireg_end(void)
{
clean_up();
my_thread_end();
+#ifdef SIGNALS_DONT_BREAK_READ
+ exit(0);
+#else
pthread_exit(0); // Exit is in main thread
+#endif
}
-void unireg_abort(int exit_code)
+extern "C" void unireg_abort(int exit_code)
{
DBUG_ENTER("unireg_abort");
if (exit_code)
@@ -860,6 +898,9 @@ void clean_up(bool print_message)
bitmap_free(&temp_pool);
free_max_user_conn();
end_slave_list();
+#ifdef USE_REGEX
+ regex_end();
+#endif
#if !defined(__WIN__) && !defined(EMBEDDED_LIBRARY)
if (!opt_bootstrap)
@@ -980,6 +1021,7 @@ static void set_root(const char *path)
sql_perror("chroot");
unireg_abort(1);
}
+ my_setwd("/", MYF(0));
#endif
}
@@ -1161,7 +1203,7 @@ void close_connection(NET *net,uint errcode,bool lock)
/* Called when a thread is aborted */
/* ARGSUSED */
-sig_handler end_thread_signal(int sig __attribute__((unused)))
+extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
{
THD *thd=current_thd;
DBUG_ENTER("end_thread_signal");
@@ -1252,7 +1294,7 @@ void flush_thread_cache()
*/
#ifdef THREAD_SPECIFIC_SIGPIPE
-static sig_handler abort_thread(int sig __attribute__((unused)))
+extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
{
THD *thd=current_thd;
DBUG_ENTER("abort_thread");
@@ -1326,7 +1368,7 @@ static void start_signal_handler(void)
#define UNSAFE_DEFAULT_LINUX_THREADS 200
#endif
-static sig_handler handle_segfault(int sig)
+extern "C" sig_handler handle_segfault(int sig)
{
THD *thd=current_thd;
/*
@@ -1340,7 +1382,7 @@ static sig_handler handle_segfault(int sig)
fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
exit(1);
}
-
+
segfaulted = 1;
fprintf(stderr,"\
mysqld got signal %d;\n\
@@ -1352,7 +1394,7 @@ or misconfigured. This error can also be caused by malfunctioning hardware.\n",
We will try our best to scrape up some info that will hopefully help diagnose\n\
the problem, but since we have already crashed, something is definitely wrong\n\
and this may fail.\n\n");
- fprintf(stderr, "key_buffer_size=%ld\n", keybuff_size);
+ fprintf(stderr, "key_buffer_size=%lu\n", (ulong) keybuff_size);
fprintf(stderr, "read_buffer_size=%ld\n", global_system_variables.read_buff_size);
fprintf(stderr, "sort_buffer_size=%ld\n", thd->variables.sortbuff_size);
fprintf(stderr, "max_used_connections=%ld\n", max_used_connections);
@@ -1360,11 +1402,12 @@ and this may fail.\n\n");
fprintf(stderr, "threads_connected=%d\n", thread_count);
fprintf(stderr, "It is possible that mysqld could use up to \n\
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = %ld K\n\
-bytes of memory\n", (keybuff_size + (global_system_variables.read_buff_size +
- thd->variables.sortbuff_size) *
+bytes of memory\n", ((ulong) keybuff_size +
+ (global_system_variables.read_buff_size +
+ thd->variables.sortbuff_size) *
max_connections)/ 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
-
+
#if defined(HAVE_LINUXTHREADS)
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
@@ -1403,7 +1446,11 @@ information that should help you find out what is causing the crash.\n");
#endif /* HAVE_STACKTRACE */
if (test_flags & TEST_CORE_ON_SIGNAL)
+ {
+ fprintf(stderr, "Writing a core file\n");
+ fflush(stderr);
write_core(sig);
+ }
exit(1);
}
@@ -1511,7 +1558,7 @@ static void start_signal_handler(void)
/* This threads handles all signals and alarms */
/* ARGSUSED */
-static void *signal_hand(void *arg __attribute__((unused)))
+extern "C" void *signal_hand(void *arg __attribute__((unused)))
{
sigset_t set;
int sig;
@@ -1639,8 +1686,8 @@ static void *signal_hand(void *arg __attribute__((unused)))
/* ARGSUSED */
-static int my_message_sql(uint error, const char *str,
- myf MyFlags __attribute__((unused)))
+extern "C" int my_message_sql(uint error, const char *str,
+ myf MyFlags __attribute__((unused)))
{
THD *thd;
DBUG_ENTER("my_message_sql");
@@ -1660,6 +1707,17 @@ static int my_message_sql(uint error, const char *str,
DBUG_RETURN(0);
}
+
+/*
+ Forget last error message (if we got one)
+*/
+
+void clear_error_message(THD *thd)
+{
+ thd->net.last_error[0]= 0;
+}
+
+
#ifdef __WIN__
struct utsname
@@ -1675,7 +1733,7 @@ int uname(struct utsname *a)
#ifdef __WIN__
-pthread_handler_decl(handle_shutdown,arg)
+extern "C" pthread_handler_decl(handle_shutdown,arg)
{
MSG msg;
SHUTDOWN_THD;
@@ -1703,7 +1761,7 @@ int __stdcall handle_kill(ulong ctrl_type)
#endif
#ifdef OS2
-pthread_handler_decl(handle_shutdown,arg)
+extern "C" pthread_handler_decl(handle_shutdown,arg)
{
SHUTDOWN_THD;
my_thread_init();
@@ -1887,8 +1945,6 @@ int main(int argc, char **argv)
if (!ssl_acceptor_fd)
opt_use_ssl = 0;
}
- if (des_key_file)
- load_des_key_file(des_key_file);
#endif /* HAVE_OPENSSL */
#ifdef HAVE_LIBWRAP
@@ -1961,6 +2017,10 @@ int main(int argc, char **argv)
reset_floating_point_exceptions();
init_thr_lock();
init_slave_list();
+#ifdef HAVE_OPENSSL
+ if (des_key_file)
+ load_des_key_file(des_key_file);
+#endif /* HAVE_OPENSSL */
/* Setup log files */
if (opt_log)
@@ -1972,7 +2032,7 @@ int main(int argc, char **argv)
NullS, LOG_NEW);
using_update_log=1;
}
-
+
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
NullS, LOG_NORMAL);
@@ -1987,6 +2047,8 @@ int main(int argc, char **argv)
if (ha_init())
{
sql_print_error("Can't init databases");
+ if (unix_sock != INVALID_SOCKET)
+ unlink(mysql_unix_port);
exit(1);
}
ha_key_cache();
@@ -2022,10 +2084,12 @@ int main(int argc, char **argv)
pthread_key_create(&THR_MALLOC,NULL))
{
sql_print_error("Can't create thread-keys");
+ if (unix_sock != INVALID_SOCKET)
+ unlink(mysql_unix_port);
exit(1);
}
start_signal_handler(); // Creates pidfile
- if (acl_init(opt_noacl))
+ if (acl_init((THD*) 0, opt_noacl))
{
abort_loop=1;
select_thread_in_use=0;
@@ -2034,12 +2098,15 @@ int main(int argc, char **argv)
if (!opt_bootstrap)
(void) my_delete(pidfile_name,MYF(MY_WME)); // Not needed anymore
#endif
+ if (unix_sock != INVALID_SOCKET)
+ unlink(mysql_unix_port);
exit(1);
}
if (!opt_noacl)
- (void) grant_init();
+ (void) grant_init((THD*) 0);
init_max_user_conn();
init_update_queries();
+ DBUG_ASSERT(current_thd == 0);
#ifdef HAVE_DLOPEN
if (!opt_noacl)
@@ -2047,7 +2114,8 @@ int main(int argc, char **argv)
#endif
/* init_slave() must be called after the thread keys are created */
init_slave();
-
+
+ DBUG_ASSERT(current_thd == 0);
if (opt_bin_log && !server_id)
{
server_id= !master_host ? 1 : 2;
@@ -2123,21 +2191,24 @@ The server will not act as a slave.");
printf(ER(ER_READY),my_progname,server_version,"");
fflush(stdout);
-
+#if defined(__NT__) || defined(HAVE_SMEM)
#ifdef __NT__
if (hPipe == INVALID_HANDLE_VALUE &&
- (!have_tcpip || opt_disable_networking))
+ (!have_tcpip || opt_disable_networking) &&
+ !opt_enable_shared_memory)
{
- sql_print_error("TCP/IP or --enable-named-pipe should be configured on NT OS");
+ sql_print_error("TCP/IP,--shared-memory or --named-pipe should be configured on NT OS");
unireg_abort(1);
}
else
+#endif
{
pthread_mutex_lock(&LOCK_thread_count);
(void) pthread_cond_init(&COND_handler_count,NULL);
{
pthread_t hThread;
handler_count=0;
+#ifdef __NT__
if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
{
handler_count++;
@@ -2148,18 +2219,33 @@ The server will not act as a slave.");
handler_count--;
}
}
+#endif
+#ifdef HAVE_SMEM
+ if (opt_enable_shared_memory)
+ {
+ handler_count++;
+ if (pthread_create(&hThread,&connection_attrib,
+ handle_connections_shared_memory, 0))
+ {
+ sql_print_error("Warning: Can't create thread to handle shared memory");
+ handler_count--;
+ }
+ }
+#endif
if (have_tcpip && !opt_disable_networking)
{
handler_count++;
if (pthread_create(&hThread,&connection_attrib,
handle_connections_sockets, 0))
{
- sql_print_error("Warning: Can't create thread to handle named pipes");
+ sql_print_error("Warning: Can't create thread to handle tcp/ip");
handler_count--;
}
}
while (handler_count > 0)
+ {
pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
+ }
}
pthread_mutex_unlock(&LOCK_thread_count);
}
@@ -2230,7 +2316,7 @@ int mysql_service(void *p)
SYNOPSIS
default_service_handling()
- argv Pointer to argument list
+ argv Pointer to argument list
servicename Internal name of service
displayname Display name of service (in taskbar ?)
file_path Path to this program
@@ -2266,6 +2352,14 @@ bool default_service_handling(char **argv,
int main(int argc, char **argv)
{
+
+ /* When several instances are running on the same machine, we
+ need to have an unique named hEventShudown through the
+ application PID e.g.: MySQLShutdown1890; MySQLShutdown2342
+ */
+ int2str((int) GetCurrentProcessId(),strmov(shutdown_event_name,
+ "MySQLShutdown"), 10);
+
if (Service.GetOS()) /* true NT family */
{
char file_path[FN_REFLEN];
@@ -2273,17 +2367,16 @@ int main(int argc, char **argv)
fn_format(file_path,argv[0],file_path,"",1+4+16); /* Force full path */
if (argc == 2)
- {
+ {
if (!default_service_handling(argv,MYSQL_SERVICENAME, MYSQL_SERVICENAME,
file_path))
return 0;
if (Service.IsService(argv[1]))
{
/* start an optional service */
- event_name= argv[1];
- load_default_groups[0]= argv[1];
+ load_default_groups[0]= argv[1];
start_mode= 1;
- Service.Init(event_name, mysql_service);
+ Service.Init(argv[1], mysql_service);
return 0;
}
}
@@ -2302,9 +2395,8 @@ int main(int argc, char **argv)
use_opt_args=1;
opt_argc=argc;
opt_argv=argv;
- event_name= argv[2];
start_mode= 1;
- Service.Init(event_name, mysql_service);
+ Service.Init(argv[2], mysql_service);
return 0;
}
}
@@ -2324,7 +2416,6 @@ int main(int argc, char **argv)
{
/* start the default service */
start_mode= 1;
- event_name= "MySqlShutdown";
Service.Init(MYSQL_SERVICENAME, mysql_service);
return 0;
}
@@ -2361,7 +2452,7 @@ static int bootstrap(FILE *file)
if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
(void*) thd))
{
- sql_print_error("Warning: Can't create thread to handle bootstrap");
+ sql_print_error("Warning: Can't create thread to handle bootstrap");
DBUG_RETURN(-1);
}
/* Wait for thread to die */
@@ -2416,6 +2507,9 @@ static void create_new_thread(THD *thd)
for (uint i=0; i < 8 ; i++) // Generate password teststring
thd->scramble[i]= (char) (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
@@ -2488,7 +2582,7 @@ inline void kill_broken_server()
/* Handle new connections and spawn new process to handle them */
-pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
+extern "C" pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
{
my_socket sock,new_sock;
uint error_count=0;
@@ -2524,7 +2618,7 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
while (!abort_loop)
{
readFDs=clientFDs;
-#ifdef HPUX
+#ifdef HPUX10
if (select(max_used_connection,(int*) &readFDs,0,0,0) < 0)
continue;
#else
@@ -2538,7 +2632,7 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
MAYBE_BROKEN_SYSCALL
continue;
}
-#endif /* HPUX */
+#endif /* HPUX10 */
if (abort_loop)
{
MAYBE_BROKEN_SYSCALL;
@@ -2695,7 +2789,7 @@ pthread_handler_decl(handle_connections_sockets,arg __attribute__((unused)))
#ifdef __NT__
-pthread_handler_decl(handle_connections_namedpipes,arg)
+extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
{
HANDLE hConnectedPipe;
BOOL fConnected;
@@ -2777,58 +2871,272 @@ pthread_handler_decl(handle_connections_namedpipes,arg)
}
#endif /* __NT__ */
+/*
+ Thread of shared memory's service
+
+ SYNOPSIS
+ pthread_handler_decl()
+ handle_connections_shared_memory Thread handle
+ arg Arguments of thread
+*/
+#ifdef HAVE_SMEM
+pthread_handler_decl(handle_connections_shared_memory,arg)
+{
+/*
+ event_connect_request is event object for start connection actions
+ event_connect_answer is event object for confirm, that server put data
+ handle_connect_file_map is file-mapping object, use for create shared memory
+ handle_connect_map is pointer on shared memory
+ handle_map is pointer on shared memory for client
+ event_server_wrote,
+ event_server_read,
+ event_client_wrote,
+ event_client_read are events for transfer data between server and client
+ handle_file_map is file-mapping object, use for create shared memory
+*/
+ HANDLE handle_connect_file_map = NULL;
+ char *handle_connect_map = NULL;
+ HANDLE event_connect_request = NULL;
+ HANDLE event_connect_answer = NULL;
+ ulong smem_buffer_length = shared_memory_buffer_length + 4;
+ ulong connect_number = 1;
+ my_bool error_allow;
+ THD *thd;
+ char tmp[63];
+ char *suffix_pos;
+ char connect_number_char[22], *p;
+
+ my_thread_init();
+ DBUG_ENTER("handle_connections_shared_memorys");
+ DBUG_PRINT("general",("Waiting for allocated shared memory."));
+
+
+/*
+ The name of event and file-mapping events create agree next rule:
+ shared_memory_base_name+unique_part
+ Where:
+ shared_memory_base_name is unique value for each server
+ unique_part is unique value for each object (events and file-mapping)
+*/
+ suffix_pos = strxmov(tmp,shared_memory_base_name,"_",NullS);
+ strmov(suffix_pos, "CONNECT_REQUEST");
+ if ((event_connect_request = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0)
+ {
+ sql_perror("Can't create shared memory service ! The request event don't create.");
+ goto error;
+ }
+ strmov(suffix_pos, "CONNECT_ANSWER");
+ if ((event_connect_answer = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0)
+ {
+ sql_perror("Can't create shared memory service ! The answer event don't create.");
+ goto error;
+ }
+ strmov(suffix_pos, "CONNECT_DATA");
+ if ((handle_connect_file_map = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,
+ 0,sizeof(connect_number),tmp)) == 0)
+ {
+ sql_perror("Can't create shared memory service ! File mapping don't create.");
+ goto error;
+ }
+ if ((handle_connect_map = (char *)MapViewOfFile(handle_connect_file_map,FILE_MAP_WRITE,0,0,
+ sizeof(DWORD))) == 0)
+ {
+ sql_perror("Can't create shared memory service ! Map of memory don't create.");
+ goto error;
+ }
+
+
+ while (!abort_loop)
+ {
+/*
+ Wait a request from client
+*/
+ WaitForSingleObject(event_connect_request,INFINITE);
+ error_allow = FALSE;
+
+ HANDLE handle_client_file_map = NULL;
+ char *handle_client_map = NULL;
+ HANDLE event_client_wrote = NULL;
+ HANDLE event_client_read = NULL;
+ HANDLE event_server_wrote = NULL;
+ HANDLE event_server_read = NULL;
+
+ p = int2str(connect_number, connect_number_char, 10);
+/*
+ The name of event and file-mapping events create agree next rule:
+ shared_memory_base_name+unique_part+number_of_connection
+ Where:
+ shared_memory_base_name is uniquel value for each server
+ unique_part is unique value for each object (events and file-mapping)
+ number_of_connection is number of connection between server and client
+*/
+ suffix_pos = strxmov(tmp,shared_memory_base_name,"_",connect_number_char,"_",NullS);
+ strmov(suffix_pos, "DATA");
+ if ((handle_client_file_map = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,
+ PAGE_READWRITE,0,smem_buffer_length,tmp)) == 0)
+ {
+ sql_perror("Can't create connection with client in shared memory service ! File mapping don't create.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+ if ((handle_client_map = (char*)MapViewOfFile(handle_client_file_map,FILE_MAP_WRITE,0,0,smem_buffer_length)) == 0)
+ {
+ sql_perror("Can't create connection with client in shared memory service ! Map of memory don't create.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+ strmov(suffix_pos, "CLIENT_WROTE");
+ if ((event_client_wrote = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0)
+ {
+ sql_perror("Can't create connection with client in shared memory service ! CW event don't create.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+ strmov(suffix_pos, "CLIENT_READ");
+ if ((event_client_read = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0)
+ {
+ sql_perror("Can't create connection with client in shared memory service ! CR event don't create.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+ strmov(suffix_pos, "SERVER_READ");
+ if ((event_server_read = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0)
+ {
+ sql_perror("Can't create connection with client in shared memory service ! SR event don't create.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+ strmov(suffix_pos, "SERVER_WROTE");
+ if ((event_server_wrote = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0)
+ {
+ sql_perror("Can't create connection with client in shared memory service ! SW event don't create.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+ if (abort_loop) break;
+ if ( !(thd = new THD))
+ {
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+/*
+Send number of connection to client
+*/
+ int4store(handle_connect_map, connect_number);
+
+/*
+ Send number of connection to client
+*/
+ if (!SetEvent(event_connect_answer))
+ {
+ sql_perror("Can't create connection with client in shared memory service ! Can't send answer event.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+
+/*
+ Set event that client should receive data
+*/
+ if (!SetEvent(event_client_read))
+ {
+ sql_perror("Can't create connection with client in shared memory service ! Can't set client to read's mode.");
+ error_allow = TRUE;
+ goto errorconn;
+ }
+ if (!(thd->net.vio = vio_new_win32shared_memory(&thd->net,handle_client_file_map,handle_client_map,event_client_wrote,
+ event_client_read,event_server_wrote,event_server_read)) ||
+ my_net_init(&thd->net, thd->net.vio))
+ {
+ close_connection(&thd->net,ER_OUT_OF_RESOURCES);
+ delete thd;
+ error_allow = TRUE;
+ }
+ /* host name is unknown */
+errorconn:
+ if (error_allow)
+ {
+ if (!handle_client_map) UnmapViewOfFile(handle_client_map);
+ if (!handle_client_file_map) CloseHandle(handle_client_file_map);
+ if (!event_server_wrote) CloseHandle(event_server_wrote);
+ if (!event_server_read) CloseHandle(event_server_read);
+ if (!event_client_wrote) CloseHandle(event_client_wrote);
+ if (!event_client_read) CloseHandle(event_client_read);
+ continue;
+ }
+ thd->host = my_strdup(localhost,MYF(0)); /* Host is unknown */
+ create_new_thread(thd);
+ uint4korr(connect_number++);
+ }
+error:
+ if (!handle_connect_map) UnmapViewOfFile(handle_connect_map);
+ if (!handle_connect_file_map) CloseHandle(handle_connect_file_map);
+ if (!event_connect_answer) CloseHandle(event_connect_answer);
+ if (!event_connect_request) CloseHandle(event_connect_request);
+ pthread_mutex_lock(&LOCK_thread_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_RETURN(0);
+}
+#endif /* HAVE_SMEM */
+
/******************************************************************************
** handle start options
******************************************************************************/
enum options {
- OPT_ISAM_LOG=256, OPT_SKIP_NEW,
- OPT_SKIP_GRANT, OPT_SKIP_LOCK,
+ OPT_ISAM_LOG=256, OPT_SKIP_NEW,
+ OPT_SKIP_GRANT, OPT_SKIP_LOCK,
OPT_ENABLE_LOCK, OPT_USE_LOCKING,
- OPT_SOCKET, OPT_UPDATE_LOG,
- OPT_BIN_LOG, OPT_SKIP_RESOLVE,
+ OPT_SOCKET, OPT_UPDATE_LOG,
+ OPT_BIN_LOG, OPT_SKIP_RESOLVE,
OPT_SKIP_NETWORKING, OPT_BIN_LOG_INDEX,
OPT_BIND_ADDRESS, OPT_PID_FILE,
- OPT_SKIP_PRIOR, OPT_BIG_TABLES,
+ OPT_SKIP_PRIOR, OPT_BIG_TABLES,
OPT_STANDALONE, OPT_ONE_THREAD,
OPT_CONSOLE, OPT_LOW_PRIORITY_UPDATES,
- OPT_SKIP_HOST_CACHE, OPT_LONG_FORMAT,
- OPT_FLUSH, OPT_SAFE,
+ OPT_SKIP_HOST_CACHE, OPT_LONG_FORMAT,
+ OPT_FLUSH, OPT_SAFE,
OPT_BOOTSTRAP, OPT_SKIP_SHOW_DB,
- OPT_TABLE_TYPE, OPT_INIT_FILE,
- OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
+ OPT_TABLE_TYPE, OPT_INIT_FILE,
+ OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
- OPT_BDB_HOME, OPT_BDB_LOG,
+ OPT_BDB_HOME, OPT_BDB_LOG,
OPT_BDB_TMP, OPT_BDB_NOSYNC,
- OPT_BDB_LOCK, OPT_BDB_SKIP,
+ OPT_BDB_LOCK, OPT_BDB_SKIP,
OPT_BDB_NO_RECOVER, OPT_BDB_SHARED,
OPT_MASTER_HOST, OPT_MASTER_USER,
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
OPT_MASTER_RETRY_COUNT,
- OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
- OPT_MASTER_SSL_CERT,
- OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
+ OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
+ OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH,
+ OPT_MASTER_SSL_CIPHER,
+ 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,
OPT_WANT_CORE, OPT_CONCURRENT_INSERT,
OPT_MEMLOCK, OPT_MYISAM_RECOVER,
- OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
+ OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
OPT_SKIP_SLAVE_START, OPT_SKIP_INNOBASE,
- OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
- OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
- OPT_REPLICATE_WILD_IGNORE_TABLE,
- OPT_DISCONNECT_SLAVE_EVENT_COUNT,
+ OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
+ OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
+ OPT_REPLICATE_WILD_IGNORE_TABLE,
+ OPT_DISCONNECT_SLAVE_EVENT_COUNT,
OPT_ABORT_SLAVE_EVENT_COUNT,
OPT_INNODB_DATA_HOME_DIR,
OPT_INNODB_DATA_FILE_PATH,
- OPT_INNODB_LOG_GROUP_HOME_DIR,
- OPT_INNODB_LOG_ARCH_DIR,
- OPT_INNODB_LOG_ARCHIVE,
- OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
- OPT_INNODB_FLUSH_METHOD,
- OPT_INNODB_FAST_SHUTDOWN,
+ OPT_INNODB_LOG_GROUP_HOME_DIR,
+ OPT_INNODB_LOG_ARCH_DIR,
+ OPT_INNODB_LOG_ARCHIVE,
+ OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
+ OPT_INNODB_FLUSH_METHOD,
+ OPT_INNODB_FAST_SHUTDOWN,
OPT_SAFE_SHOW_DB,
OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
@@ -2865,7 +3173,7 @@ enum options {
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
- OPT_OPEN_FILES_LIMIT,
+ OPT_OPEN_FILES_LIMIT,
OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_SIZE,
OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT,
@@ -2886,7 +3194,10 @@ enum options {
OPT_INNODB_FORCE_RECOVERY,
OPT_BDB_CACHE_SIZE,
OPT_BDB_LOG_BUFFER_SIZE,
- OPT_BDB_MAX_LOCK
+ OPT_BDB_MAX_LOCK,
+ OPT_ENABLE_SHARED_MEMORY,
+ OPT_SHARED_MEMORY_BASE_NAME,
+ OPT_OLD_PASSWORDS
};
@@ -2965,7 +3276,7 @@ struct my_option my_long_options[] =
#endif
#endif
#ifdef HAVE_OPENSSL
- {"des-key-file", OPT_DES_KEY_FILE,
+ {"des-key-file", OPT_DES_KEY_FILE,
"Load keys for des_encrypt() and des_encrypt from given file",
(gptr*) &des_key_file, (gptr*) &des_key_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
@@ -2993,6 +3304,11 @@ struct my_option my_long_options[] =
{"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure",
(gptr*) &opt_do_pstack, (gptr*) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0,
0, 0, 0, 0},
+#ifdef HAVE_SMEM
+ {"shared-memory", OPT_ENABLE_SHARED_MEMORY,
+ "Enable the shared memory.",(gptr*) &opt_enable_shared_memory, (gptr*) &opt_enable_shared_memory,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"flush", OPT_FLUSH, "Flush tables to disk between SQL commands", 0, 0, 0,
@@ -3010,7 +3326,7 @@ struct my_option my_long_options[] =
(gptr*) &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"innodb_log_group_home_dir", OPT_INNODB_LOG_GROUP_HOME_DIR,
- "Path to innodb log files.", (gptr*) &innobase_log_group_home_dir,
+ "Path to innodb log files.", (gptr*) &innobase_log_group_home_dir,
(gptr*) &innobase_log_group_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
0, 0},
{"innodb_log_arch_dir", OPT_INNODB_LOG_ARCH_DIR,
@@ -3070,7 +3386,7 @@ struct my_option my_long_options[] =
{"log-long-format", OPT_LONG_FORMAT,
"Log some extra information to update log", 0, 0, 0, GET_NO_ARG, NO_ARG,
0, 0, 0, 0, 0, 0},
- {"log-slave-updates", OPT_LOG_SLAVE_UPDATES,
+ {"log-slave-updates", OPT_LOG_SLAVE_UPDATES,
"Tells the slave to log the updates from the slave thread to the binary log. You will need to turn it on if you plan to daisy-chain the slaves.",
(gptr*) &opt_log_slave_updates, (gptr*) &opt_log_slave_updates, 0, GET_BOOL,
NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -3079,7 +3395,7 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.low_priority_updates,
(gptr*) &max_system_variables.low_priority_updates,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"master-host", OPT_MASTER_HOST,
+ {"master-host", OPT_MASTER_HOST,
"Master hostname or IP address for replication. If not set, the slave thread will not be started. Note that the setting of master-host will be ignored if there exists a valid master.info file.",
(gptr*) &master_host, (gptr*) &master_host, 0, GET_STR, REQUIRED_ARG, 0, 0,
0, 0, 0, 0},
@@ -3118,6 +3434,14 @@ struct my_option my_long_options[] =
"Master SSL certificate file name. Only applies if you have enabled master-ssl.",
(gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 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.",
+ (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.",
+ (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.",
(gptr*) &myisam_recover_options_str, (gptr*) &myisam_recover_options_str, 0,
@@ -3207,7 +3531,7 @@ struct my_option my_long_options[] =
(gptr*) &report_port, (gptr*) &report_port, 0, GET_UINT, REQUIRED_ARG,
MYSQL_PORT, 0, 0, 0, 0, 0},
{"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented",
- (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_UINT,
+ (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"relay-log", OPT_RELAY_LOG, "Undocumented",
(gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0,
@@ -3217,11 +3541,12 @@ struct my_option my_long_options[] =
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 old 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...",
- (gptr*) &opt_safe_show_db, (gptr*) &opt_safe_show_db, 0, GET_BOOL, NO_ARG,
- 0, 0, 0, 0, 0, 0},
+ 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"safe-user-create", OPT_SAFE_USER_CREATE,
"Don't allow new user creation by the user who has no write privileges to the mysql.user table",
@@ -3234,6 +3559,11 @@ struct my_option my_long_options[] =
{"set-variable", 'O',
"Change the value of a variable. Please note that this option is deprecated;you can set variables directly with --variable-name=value.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef HAVE_SMEM
+ {"shared_memory_base_name",OPT_SHARED_MEMORY_BASE_NAME,
+ "Base name of shared memory", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name,
+ 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO,
"Show user and password in SHOW SLAVE STATUS",
(gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0,
@@ -3362,7 +3692,7 @@ struct my_option my_long_options[] =
"The size of the cache to hold the SQL statements for the binary log during a transaction. If you often use big, multi-statement transactions you can increase this to get more performance.",
(gptr*) &binlog_cache_size, (gptr*) &binlog_cache_size, 0, GET_ULONG,
REQUIRED_ARG, 32*1024L, IO_SIZE, ~0L, 0, IO_SIZE, 0},
- {"connect_timeout", OPT_CONNECT_TIMEOUT,
+ {"connect_timeout", OPT_CONNECT_TIMEOUT,
"The number of seconds the mysqld server is waiting for a connect packet before responding with Bad handshake",
(gptr*) &connect_timeout, (gptr*) &connect_timeout,
0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 },
@@ -3396,7 +3726,7 @@ struct my_option my_long_options[] =
HA_FT_MAXLEN, 0, 1, 0},
#ifdef HAVE_INNOBASE_DB
{"innodb_mirrored_log_groups", OPT_INNODB_MIRRORED_LOG_GROUPS,
- "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
+ "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
(gptr*) &innobase_mirrored_log_groups,
(gptr*) &innobase_mirrored_log_groups, 0, GET_LONG, REQUIRED_ARG, 1, 1, 10,
0, 1, 0},
@@ -3451,8 +3781,9 @@ struct my_option my_long_options[] =
IO_SIZE, 0},
{"key_buffer_size", OPT_KEY_BUFFER_SIZE,
"The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.",
- (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULONG, REQUIRED_ARG,
- KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, IO_SIZE, 0},
+ (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULL,
+ REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD,
+ IO_SIZE, 0},
{"long_query_time", OPT_LONG_QUERY_TIME,
"Log all queries that have taken more than long_query_time seconds to execute to file.",
(gptr*) &global_system_variables.long_query_time,
@@ -3554,7 +3885,7 @@ struct my_option my_long_options[] =
(gptr*) &max_system_variables.myisam_sort_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
- "Buffer length for TCP/IP and socket communication.",
+ "Buffer length for TCP/IP and socket communication.",
(gptr*) &global_system_variables.net_buffer_length,
(gptr*) &max_system_variables.net_buffer_length, 0, GET_ULONG,
REQUIRED_ARG, 16384, 1024, 1024*1024L, 0, 1024, 0},
@@ -3671,6 +4002,7 @@ struct show_var_st status_vars[]= {
{"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_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},
@@ -3684,6 +4016,7 @@ struct show_var_st status_vars[]= {
{"Com_create_table", (char*) (com_stat+(uint) SQLCOM_CREATE_TABLE),SHOW_LONG},
{"Com_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
{"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),SHOW_LONG},
+ {"Com_do", (char*) (com_stat+(uint) SQLCOM_DO),SHOW_LONG},
{"Com_drop_db", (char*) (com_stat+(uint) SQLCOM_DROP_DB),SHOW_LONG},
{"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG},
{"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
@@ -3693,11 +4026,12 @@ struct show_var_st status_vars[]= {
{"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
{"Com_ha_open", (char*) (com_stat+(uint) SQLCOM_HA_OPEN),SHOW_LONG},
{"Com_ha_read", (char*) (com_stat+(uint) SQLCOM_HA_READ),SHOW_LONG},
+ {"Com_help", (char*) (com_stat+(uint) SQLCOM_HELP),SHOW_LONG},
{"Com_insert", (char*) (com_stat+(uint) SQLCOM_INSERT),SHOW_LONG},
{"Com_insert_select", (char*) (com_stat+(uint) SQLCOM_INSERT_SELECT),SHOW_LONG},
{"Com_kill", (char*) (com_stat+(uint) SQLCOM_KILL),SHOW_LONG},
{"Com_load", (char*) (com_stat+(uint) SQLCOM_LOAD),SHOW_LONG},
- {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
+ {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
{"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},
@@ -3714,8 +4048,12 @@ struct show_var_st status_vars[]= {
{"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_create", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
+ {"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),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},
{"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG},
+ {"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_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
@@ -3723,18 +4061,22 @@ struct show_var_st status_vars[]= {
{"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
{"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG},
{"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG},
+ {"Com_show_privileges", (char*) (com_stat+(uint) SQLCOM_SHOW_PRIVILEGES),SHOW_LONG},
{"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
{"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},
+ {"Com_show_warnings", (char*) (com_stat+(uint) SQLCOM_SHOW_WARNS),SHOW_LONG},
{"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
{"Com_slave_stop", (char*) (com_stat+(uint) SQLCOM_SLAVE_STOP),SHOW_LONG},
{"Com_truncate", (char*) (com_stat+(uint) SQLCOM_TRUNCATE),SHOW_LONG},
{"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
{"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
+ {"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
{"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
{"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG},
@@ -3771,8 +4113,9 @@ struct show_var_st status_vars[]= {
{"Qcache_queries_in_cache", (char*) &query_cache.queries_in_cache, SHOW_LONG_CONST},
{"Qcache_inserts", (char*) &query_cache.inserts, SHOW_LONG},
{"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
+ {"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG},
{"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG},
- {"Qcache_free_memory", (char*) &query_cache.free_memory,
+ {"Qcache_free_memory", (char*) &query_cache.free_memory,
SHOW_LONG_CONST},
{"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
SHOW_LONG_CONST},
@@ -3891,11 +4234,11 @@ static void set_options(void)
/* Set default values for some variables */
global_system_variables.table_type=DB_TYPE_MYISAM;
- global_system_variables.tx_isolation=ISO_READ_COMMITTED;
- global_system_variables.select_limit= (ulong) HA_POS_ERROR;
+ global_system_variables.tx_isolation=ISO_REPEATABLE_READ;
+ global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
max_system_variables.select_limit= (ulong) HA_POS_ERROR;
- global_system_variables.max_join_size= (ulong) HA_POS_ERROR;
- max_system_variables.max_join_size= (ulong) HA_POS_ERROR;
+ global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
+ max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
#ifdef __WIN__
/* Allow Win32 users to move MySQL anywhere */
@@ -3918,7 +4261,7 @@ static void set_options(void)
}
-static my_bool
+extern "C" my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument)
{
@@ -3931,8 +4274,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case 'a':
opt_sql_mode = (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT |
- MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE
- | MODE_ONLY_FULL_GROUP_BY);
+ MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE |
+ MODE_ONLY_FULL_GROUP_BY);
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
break;
case 'b':
@@ -3943,6 +4286,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
case 'h':
strmake(mysql_real_data_home,argument, sizeof(mysql_real_data_home)-1);
+ /* Correct pointer set by my_getopt (for embedded library) */
+ mysql_data_home= mysql_real_data_home;
break;
case 'L':
strmake(language, argument, sizeof(language)-1);
@@ -3957,9 +4302,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
init_slave_skip_errors(argument);
break;
case OPT_SAFEMALLOC_MEM_LIMIT:
-#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
+#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
safemalloc_mem_limit = atoi(argument);
-#endif
+#endif
break;
#ifdef EMBEDDED_LIBRARY
case OPT_MAX_ALLOWED_PACKET:
@@ -4021,7 +4366,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int)OPT_REPLICATE_REWRITE_DB:
{
char* key = argument,*p, *val;
-
+
if (!(p= strstr(argument, "->")))
{
fprintf(stderr,
@@ -4188,7 +4533,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
else
{
struct hostent *ent;
- if (!argument || !argument[0])
+ if (argument || argument[0])
ent=gethostbyname(argument);
else
{
@@ -4292,7 +4637,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
berkeley_lock_type=berkeley_lock_types[type-1];
else
{
- if (test_if_int(argument,(uint) strlen(argument)))
+ if (test_if_int(argument,(uint) strlen(argument), my_charset_latin1))
berkeley_lock_scan_time=atoi(argument);
else
{
@@ -4363,7 +4708,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
global_system_variables.tx_isolation= ((opt_sql_mode & MODE_SERIALIZABLE) ?
ISO_SERIALIZABLE :
- ISO_READ_COMMITTED);
+ ISO_REPEATABLE_READ);
break;
}
case OPT_MASTER_PASSWORD:
@@ -4377,7 +4722,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
return 0;
}
-
/* Initiates DEBUG - but no debugging here ! */
static void get_options(int argc,char **argv)
@@ -4414,7 +4758,7 @@ static void get_options(int argc,char **argv)
myisam_max_temp_length=
(my_off_t) min(global_system_variables.myisam_max_sort_file_size,
(ulonglong) MAX_FILE_SIZE);
- myisam_max_extra_temp_length=
+ myisam_max_extra_temp_length=
(my_off_t) min(global_system_variables.myisam_max_extra_sort_file_size,
(ulonglong) MAX_FILE_SIZE);
@@ -4461,9 +4805,17 @@ fn_format_relative_to_data_home(my_string to, const char *name,
static void fix_paths(void)
{
- char buff[FN_REFLEN];
- (void) fn_format(mysql_home,mysql_home,"","",16); // Remove symlinks
+ char buff[FN_REFLEN],*pos;
convert_dirname(mysql_home,mysql_home,NullS);
+ /* Resolve symlinks to allow 'mysql_home' to be a relative symlink */
+ my_realpath(mysql_home,mysql_home,MYF(0));
+ /* Ensure that mysql_home ends in FN_LIBCHAR */
+ pos=strend(mysql_home);
+ if (pos[-1] != FN_LIBCHAR)
+ {
+ pos[0]= FN_LIBCHAR;
+ pos[1]= 0;
+ }
convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS);
convert_dirname(language,language,NullS);
(void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir
@@ -4587,7 +4939,7 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
j=pos;
while (j != end)
{
- if (my_toupper(system_charset_info,*i++) !=
+ if (my_toupper(system_charset_info,*i++) !=
my_toupper(system_charset_info,*j++))
goto skipp;
}
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index 2d0eae125d6..b917c91ce15 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -568,31 +568,3 @@ BOOL NTService::is_super_user()
FreeSid(psidAdministrators);
return ret_value;
}
-/* ------------------------------------------------------------------------
- -------------------------------------------------------------------------- */
-BOOL NTService::IsService(LPCSTR ServiceName)
-{
- BOOL ret_value=FALSE;
- SC_HANDLE service, scm;
-
- if (scm = OpenSCManager(0, 0,SC_MANAGER_ENUMERATE_SERVICE))
- {
- if ((service = OpenService(scm,ServiceName, SERVICE_ALL_ACCESS )))
- {
- ret_value=TRUE;
- CloseServiceHandle(service);
- }
- CloseServiceHandle(scm);
- }
- return ret_value;
-}
-/* ------------------------------------------------------------------------
- -------------------------------------------------------------------------- */
-BOOL NTService::got_service_option(char **argv, char *service_option)
-{
- char *option;
- for (option= argv[1]; *option; option++)
- if (!strcmp(option, service_option))
- return TRUE;
- return FALSE;
-}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 39e6b83221d..d76737e8e31 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -299,9 +299,6 @@ static SEL_TREE * get_mm_parts(PARAM *param,Field *field,
Item_result cmp_type);
static SEL_ARG *get_mm_leaf(PARAM *param,Field *field,KEY_PART *key_part,
Item_func::Functype type,Item *value);
-static bool like_range(const char *ptr,uint length,char wild_prefix,
- uint field_length, char *min_str,char *max_str,
- char max_sort_char,uint *min_length,uint *max_length);
static SEL_TREE *get_mm_tree(PARAM *param,COND *cond);
static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree);
static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
@@ -935,13 +932,16 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
String tmp(buff1,sizeof(buff1),default_charset_info),*res;
uint length,offset,min_length,max_length;
- if (!field->optimize_range((uint) key_part->key))
+ if (!field->optimize_range(param->real_keynr[key_part->key]))
DBUG_RETURN(0); // Can't optimize this
if (!(res= value->val_str(&tmp)))
DBUG_RETURN(&null_element);
- // Check if this was a function. This should have be optimized away
- // in the sql_select.cc
+ /*
+ TODO:
+ Check if this was a function. This should have be optimized away
+ in the sql_select.cc
+ */
if (res != &tmp)
{
tmp.copy(*res); // Get own copy
@@ -970,27 +970,14 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
max_str=min_str+length;
if (maybe_null)
max_str[0]= min_str[0]=0;
- if (field->binary())
- like_error=like_range(res->ptr(),res->length(),wild_prefix,field_length,
- min_str+offset,max_str+offset,(char) 255,
- &min_length,&max_length);
- else
- {
- CHARSET_INFO *charset=((Field_str*)(field))->charset();
-#ifdef USE_STRCOLL
- if (use_strnxfrm(charset))
- like_error= my_like_range(charset,
- res->ptr(),res->length(),wild_prefix,
- field_length, min_str+maybe_null,
- max_str+maybe_null,&min_length,&max_length);
- else
-#endif
- like_error=like_range(res->ptr(),res->length(),wild_prefix,
- field_length,
- min_str+offset,max_str+offset,
- charset->max_sort_char,
- &min_length,&max_length);
- }
+
+ like_error= my_like_range(field->charset(),
+ res->ptr(),res->length(),
+ wild_prefix,wild_one,wild_many,
+ field_length,
+ min_str+offset, max_str+offset,
+ &min_length,&max_length);
+
if (like_error) // Can't optimize with LIKE
DBUG_RETURN(0);
if (offset != maybe_null) // Blob
@@ -1018,32 +1005,35 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(tree);
}
- if (!field->optimize_range((uint) key_part->key) &&
+ if (!field->optimize_range(param->real_keynr[key_part->key]) &&
type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC)
DBUG_RETURN(0); // Can't optimize this
- /* 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 */
+ /*
+ 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
+ */
if (field->result_type() == STRING_RESULT &&
value->result_type() != STRING_RESULT &&
field->cmp_type() != value->result_type())
DBUG_RETURN(0);
- if (value->save_in_field(field) > 0)
+ if (value->save_in_field(field, 1) > 0)
{
+ /* This happens when we try to insert a NULL field in a not null column */
// TODO; Check if we can we remove the following block.
if (type == Item_func::EQUAL_FUNC)
{
/* convert column_name <=> NULL -> column_name IS NULL */
// Get local copy of key
char *str= (char*) alloc_root(param->mem_root,1);
- if (!*str)
+ if (!str)
DBUG_RETURN(0);
- *str = 1;
+ *str= 1;
DBUG_RETURN(new SEL_ARG(field,str,str));
}
- DBUG_RETURN(&null_element); // NULL is never true
+ DBUG_RETURN(&null_element); // cmp with NULL is never true
}
// Get local copy of key
char *str= (char*) alloc_root(param->mem_root,
@@ -1051,7 +1041,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
if (!str)
DBUG_RETURN(0);
if (maybe_null)
- *str=0; // Not NULL
+ *str= (char) field->is_real_null(); // Set to 1 if null
field->get_key_image(str+maybe_null,key_part->part_length, key_part->image_type);
if (!(tree=new SEL_ARG(field,str,str)))
DBUG_RETURN(0);
@@ -1119,69 +1109,6 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
}
-/*
-** Calculate min_str and max_str that ranges a LIKE string.
-** Arguments:
-** ptr Pointer to LIKE string.
-** ptr_length Length of LIKE string.
-** escape Escape character in LIKE. (Normally '\').
-** All escape characters should be removed from min_str and max_str
-** res_length Length of min_str and max_str.
-** min_str Smallest case sensitive string that ranges LIKE.
-** Should be space padded to res_length.
-** max_str Largest case sensitive string that ranges LIKE.
-** Normally padded with the biggest character sort value.
-**
-** The function should return 0 if ok and 1 if the LIKE string can't be
-** optimized !
-*/
-
-static bool like_range(const char *ptr,uint ptr_length,char escape,
- uint res_length, char *min_str,char *max_str,
- char max_sort_chr, uint *min_length, uint *max_length)
-{
- const char *end=ptr+ptr_length;
- char *min_org=min_str;
- char *min_end=min_str+res_length;
-
- for (; ptr != end && min_str != min_end ; ptr++)
- {
- if (*ptr == escape && ptr+1 != end)
- {
- ptr++; // Skip escape
- *min_str++= *max_str++ = *ptr;
- continue;
- }
- if (*ptr == wild_one) // '_' in SQL
- {
- *min_str++='\0'; // This should be min char
- *max_str++=max_sort_chr;
- continue;
- }
- if (*ptr == wild_many) // '%' in SQL
- {
- *min_length= (uint) (min_str - min_org);
- *max_length=res_length;
- do {
- *min_str++ = ' '; // Because if key compression
- *max_str++ = max_sort_chr;
- } while (min_str != min_end);
- return 0;
- }
- *min_str++= *max_str++ = *ptr;
- }
- *min_length= *max_length = (uint) (min_str - min_org);
-
- /* Temporary fix for handling wild_one at end of string (key compression) */
- for (char *tmp= min_str ; tmp > min_org && tmp[-1] == '\0';)
- *--tmp=' ';
-
- while (min_str != min_end)
- *min_str++ = *max_str++ = ' '; // Because if key compression
- return 0;
-}
-
-
/******************************************************************************
** Tree manipulation functions
** If tree is 0 it means that the condition can't be tested. It refers
@@ -2542,9 +2469,9 @@ int QUICK_SELECT::get_next()
if (range->flag & NO_MIN_RANGE) // Read first record
{
- int error;
- if ((error=file->index_first(record)))
- DBUG_RETURN(error); // Empty table
+ int local_error;
+ if ((local_error=file->index_first(record)))
+ DBUG_RETURN(local_error); // Empty table
if (cmp_next(range) == 0)
DBUG_RETURN(0);
range=0; // No matching records; go to next range
@@ -2578,13 +2505,13 @@ int QUICK_SELECT::get_next()
/* compare if found key is over max-value */
/* Returns 0 if key <= range->max_key */
-int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
+int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg)
{
- if (range->flag & NO_MAX_RANGE)
- return (0); /* key can't be to large */
+ if (range_arg->flag & NO_MAX_RANGE)
+ return 0; /* key can't be to large */
KEY_PART *key_part=key_parts;
- for (char *key=range->max_key, *end=key+range->max_length;
+ for (char *key=range_arg->max_key, *end=key+range_arg->max_length;
key < end;
key+= key_part++->part_length)
{
@@ -2605,7 +2532,7 @@ int QUICK_SELECT::cmp_next(QUICK_RANGE *range)
if (cmp > 0)
return 1;
}
- return (range->flag & NEAR_MAX) ? 1 : 0; // Exact match
+ return (range_arg->flag & NEAR_MAX) ? 1 : 0; // Exact match
}
@@ -2689,9 +2616,9 @@ int QUICK_SELECT_DESC::get_next()
if (range->flag & NO_MAX_RANGE) // Read last record
{
- int error;
- if ((error=file->index_last(record)))
- DBUG_RETURN(error); // Empty table
+ int local_error;
+ if ((local_error=file->index_last(record)))
+ DBUG_RETURN(local_error); // Empty table
if (cmp_prev(range) == 0)
DBUG_RETURN(0);
range=0; // No matching records; go to next range
@@ -2745,16 +2672,18 @@ int QUICK_SELECT_DESC::get_next()
}
}
+
/*
- * Returns 0 if found key is inside range (found key >= range->min_key).
- */
-int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
+ Returns 0 if found key is inside range (found key >= range->min_key).
+*/
+
+int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range_arg)
{
- if (range->flag & NO_MIN_RANGE)
- return (0); /* key can't be to small */
+ if (range_arg->flag & NO_MIN_RANGE)
+ return 0; /* key can't be to small */
KEY_PART *key_part = key_parts;
- for (char *key = range->min_key, *end = key + range->min_length;
+ for (char *key = range_arg->min_key, *end = key + range_arg->min_length;
key < end;
key += key_part++->part_length)
{
@@ -2778,42 +2707,45 @@ int QUICK_SELECT_DESC::cmp_prev(QUICK_RANGE *range)
if (cmp < 0)
return 1;
}
- return (range->flag & NEAR_MIN) ? 1 : 0; // Exact match
+ return (range_arg->flag & NEAR_MIN) ? 1 : 0; // Exact match
}
+
/*
* True if this range will require using HA_READ_AFTER_KEY
See comment in get_next() about this
*/
-bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range)
+bool QUICK_SELECT_DESC::range_reads_after_key(QUICK_RANGE *range_arg)
{
- return ((range->flag & (NO_MAX_RANGE | NEAR_MAX)) ||
- !(range->flag & EQ_RANGE) ||
- head->key_info[index].key_length != range->max_length) ? 1 : 0;
+ return ((range_arg->flag & (NO_MAX_RANGE | NEAR_MAX)) ||
+ !(range_arg->flag & EQ_RANGE) ||
+ head->key_info[index].key_length != range_arg->max_length) ? 1 : 0;
}
+
/* True if we are reading over a key that may have a NULL value */
-bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range,
+bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range_arg,
uint used_key_parts)
{
uint offset,end;
KEY_PART *key_part = key_parts,
*key_part_end= key_part+used_key_parts;
- for (offset= 0, end = min(range->min_length, range->max_length) ;
+ for (offset= 0, end = min(range_arg->min_length, range_arg->max_length) ;
offset < end && key_part != key_part_end ;
offset += key_part++->part_length)
{
uint null_length=test(key_part->null_bit);
- if (!memcmp((char*) range->min_key+offset, (char*) range->max_key+offset,
+ if (!memcmp((char*) range_arg->min_key+offset,
+ (char*) range_arg->max_key+offset,
key_part->part_length + null_length))
{
offset+=null_length;
continue;
}
- if (null_length && range->min_key[offset])
+ if (null_length && range_arg->min_key[offset])
return 1; // min_key is null and max_key isn't
// Range doesn't cover NULL. This is ok if there is no more null parts
break;
@@ -2826,7 +2758,7 @@ bool QUICK_SELECT_DESC::test_if_null_range(QUICK_RANGE *range,
*/
if (key_part != key_part_end && key_part->null_bit)
{
- if (offset >= range->min_length || range->min_key[offset])
+ if (offset >= range_arg->min_length || range_arg->min_key[offset])
return 1; // Could be null
key_part++;
}
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 38365dbb546..1477d46e756 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -37,6 +37,19 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
bool recalc_const_item=0;
table_map removed_tables=0;
Item *item;
+ COND *org_conds= conds;
+
+ /* Add all ON conditions to WHERE condition */
+ for (TABLE_LIST *tl=tables; tl ; tl= tl->next)
+ {
+ if (tl->on_expr)
+ conds= and_expressions(conds, tl->on_expr, &org_conds);
+ }
+
+ /*
+ Iterate through item is select part and replace COUNT(), MIN() and MAX()
+ with constants (if possible)
+ */
while ((item= it++))
{
diff --git a/sql/password.c b/sql/password.c
index 48181ea18e6..9fd3757106d 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -32,18 +32,59 @@
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
+
+
+ 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.
+
+ 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.
+
+ New Password handling functions by Peter Zaitsev
+
+
*****************************************************************************/
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
+#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 */
+
+
+/*
+ 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.# */
#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;
@@ -51,6 +92,19 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
rand_st->seed2=seed2%rand_st->max_value;
}
+
+/*
+ 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;
@@ -59,6 +113,18 @@ static void old_randominit(struct rand_struct *rand_st,ulong seed1)
rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
}
+
+/*
+ Generate Random number
+
+ SYNOPSIS
+ rnd()
+ rand_st INOUT Structure used for number generation
+
+ RETURN
+ Generated pseudo random number
+*/
+
double rnd(struct rand_struct *rand_st)
{
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
@@ -66,6 +132,70 @@ double rnd(struct rand_struct *rand_st)
return (((double) rand_st->seed1)/rand_st->max_value_dbl);
}
+
+/*
+ Generate String of printable random characters of requested length
+ String will not be zero terminated.
+
+ SYNOPSIS
+ create_random_string()
+ length IN Lenght of
+ rand_st INOUT Structure used for number generation
+ target OUT Buffer for generation
+
+ RETURN
+ none
+*/
+
+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. */
+ while (target<end)
+ {
+ *target=rnd(rand_st)*94+33;
+ target++;
+ }
+}
+
+
+/*
+ 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)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
@@ -84,13 +214,230 @@ void hash_password(ulong *result, const char *password)
return;
}
-void make_scrambled_password(char *to,const char *password)
+
+/*
+ Stage one password hashing.
+ Used in MySQL 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
+*/
+
+void password_hash_stage1(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,(int8*)&password[0],1);
+ }
+ sha1_result(&context,(uint8*)to);
+}
+
+
+/*
+ Stage two password hashing.
+ Used in MySQL 4.1 password handling
+
+ 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
+*/
+
+void password_hash_stage2(char *to,const char *salt)
+{
+ SHA1_CONTEXT context;
+ sha1_reset(&context);
+ sha1_input(&context,(uint8*)salt,4);
+ sha1_input(&context,to,SHA1_HASH_SIZE);
+ sha1_result(&context,(uint8*)to);
+}
+
+
+/*
+ Create password to be stored in user database from raw string
+ Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords
+
+ 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
+*/
+
+void make_scrambled_password(char *to,const char *password,
+ my_bool force_old_scramble,
+ struct rand_struct *rand_st)
{
- ulong hash_res[2];
- hash_password(hash_res,password);
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+ 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 */
+ {
+ to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
+ /* Random returns number from 0 to 1 so this would be good salt generation.*/
+ salt=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(digest,password);
+ /* Second stage is done with salt */
+ password_hash_stage2(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]);
+ }
}
+
+/*
+ Convert password from binary string form to salt form
+ Used for MySQL 4.1 password handling
+
+ 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
+*/
+
+void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt)
+{
+ unsigned char* password_end=password+SCRAMBLE41_LENGTH;
+ *res=salt;
+ res++;
+
+ /* Process password of known length*/
+ while (password<password_end)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 4 ; i++)
+ val=(val << 8)+(*password++);
+ *res++=val;
+ }
+}
+
+
+/*
+ Validate password for MySQL 4.1 password handling.
+
+ 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
+*/
+
+my_bool validate_password(const char* password, const char* message,
+ 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,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;
+}
+
+
+/*
+ Get length of password string which is stored in mysql.user table
+
+ SYNOPSIS
+ get_password_length()
+ force_old_scramble IN If we wish to use pre 4.1 scramble format
+
+ RETURN
+ password length >0
+*/
+
+int get_password_length(my_bool force_old_scramble)
+{
+ return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1;
+}
+
+
+/*
+ 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
+*/
+
+char get_password_version(const char* password)
+{
+ if (password==NULL) return 0;
+ if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
+ return 0;
+}
+
+
+/*
+ Get integer value of Hex character
+
+ SYNOPSIS
+ char_val()
+ X IN Character to find value for
+
+ RETURN
+ Appropriate integer value
+*/
+
+
+
inline uint char_val(char X)
{
return (uint) (X >= '0' && X <= '9' ? X-'0' :
@@ -98,16 +445,44 @@ inline uint char_val(char X)
X-'a'+10);
}
+
/*
-** This code assumes that len(password) is divideable with 8 and that
-** res is big enough (2 in mysql)
+ Get Binary salt from password as in mysql.user format
+
+ 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)
{
- res[0]=res[1]=0;
- if (password)
+ if (password) /* zero salt corresponds to empty password */
{
+ 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;
@@ -120,33 +495,166 @@ void get_salt_from_password(ulong *res,const char *password)
return;
}
-void make_password_from_salt(char *to, ulong *hash_res)
+
+/*
+ Get string version as stored in mysql.user from salt form
+
+ 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
+*/
+
+void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version)
{
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+ 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';
}
/*
- * Genererate a new message based on message and password
- * The same thing is done in client and server and the results are checked.
- */
+ Convert password in salted form to binary string password and hash-salt
+ For old password this involes one more hashing
+
+ 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
+*/
+
+void get_hash_and_password(ulong* salt, uint8 pversion, char* hash, unsigned char* bin_password)
+{
+ int t;
+ ulong* salt_end;
+ ulong val;
+ SHA1_CONTEXT context;
+ unsigned char* bp; /* Binary password loop pointer */
+
+ if (pversion) /* New password version assumed */
+ {
+ salt_end=salt+5;
+ sprintf(hash,"%04x",(unsigned short)salt[0]);
+ while (salt<salt_end) /* Iterate over these elements*/
+ {
+ val=*(++salt);
+ for (t=3; t>=0; t--)
+ {
+ bin_password[t]=val & 255;
+ val>>=8; /* Scroll 8 bits to get next part*/
+ }
+ bin_password+=4; /* Get to next 4 chars*/
+ }
+ }
+ else
+ {
+ /* Use zero starting hash as an indication of old password */
+ hash[0]=0;
+ salt_end=salt+2;
+ bp=bin_password;
+ /* 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]=val%256;
+
+ 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);
+ }
+}
+
+
+/*
+ Create key from old password to decode scramble
+ Used in 4.1 authentication with passwords stored old way
+
+ SYNOPSIS
+ create_key_from_old_password()
+ passwd IN Password used for key generation
+ key OUT Created 20 bytes key
+
+ RETURN
+ None
+*/
+
+
+void create_key_from_old_password(const char* passwd, char* key)
+{
+ 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);
+}
+
+
+/*
+ Scramble string with password
+ Used at pre 4.1 authentication phase.
+
+ 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
+*/
char *scramble(char *to,const char *message,const char *password,
my_bool old_ver)
{
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);
+ 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 (*message++)
+ while (*msg++)
*to++= (char) (floor(rnd(&rand_st)*31)+64);
if (!old_ver)
{ /* Make it harder to break */
@@ -160,15 +668,45 @@ char *scramble(char *to,const char *message,const char *password,
}
+/*
+ Check scrambled message
+ Used for pre 4.1 password handling
+
+ 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
+*/
+
my_bool check_scramble(const char *scrambled, const char *message,
ulong *hash_pass, my_bool old_ver)
{
struct rand_struct rand_st;
ulong hash_message[2];
- char buff[16],*to,extra; /* Big enough for check */
+ 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);
+ hash_password(hash_message,message_buffer);
if (old_ver)
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
else
diff --git a/sql/procedure.h b/sql/procedure.h
index 3792d823b12..b72c5cb559f 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -35,10 +35,10 @@ public:
}
enum Type type() const { return Item::PROC_ITEM; }
virtual void set(double nr)=0;
- virtual void set(const char *str,uint length)=0;
+ virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
virtual void set(longlong nr)=0;
virtual enum_field_types field_type() const=0;
- void set(const char *str) { set(str,(uint) strlen(str)); }
+ void set(const char *str) { set(str,(uint) strlen(str), thd_charset()); }
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,field_type());
@@ -58,11 +58,11 @@ public:
enum_field_types field_type() const { return FIELD_TYPE_DOUBLE; }
void set(double nr) { value=nr; }
void set(longlong nr) { value=(double) nr; }
- void set(const char *str,uint length __attribute__((unused)))
- { value=atof(str); }
+ void set(const char *str,uint length,CHARSET_INFO *cs)
+ { value=my_strntod(cs,str,length,(char**)0); }
double val() { return value; }
longlong val_int() { return (longlong) value; }
- String *val_str(String *s) { s->set(value,decimals,my_thd_charset); return s; }
+ String *val_str(String *s) { s->set(value,decimals,thd_charset()); return s; }
unsigned int size_of() { return sizeof(*this);}
};
@@ -76,11 +76,11 @@ public:
enum_field_types field_type() const { return FIELD_TYPE_LONG; }
void set(double nr) { value=(longlong) nr; }
void set(longlong nr) { value=nr; }
- void set(const char *str,uint length __attribute__((unused)))
- { value=strtoll(str,NULL,10); }
+ void set(const char *str,uint length, CHARSET_INFO *cs)
+ { value=my_strntoll(cs,str,length,NULL,10); }
double val() { return (double) value; }
longlong val_int() { return value; }
- String *val_str(String *s) { s->set(value, my_thd_charset); return s; }
+ String *val_str(String *s) { s->set(value, thd_charset()); return s; }
unsigned int size_of() { return sizeof(*this);}
};
@@ -92,11 +92,20 @@ public:
{ this->max_length=length; }
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return FIELD_TYPE_STRING; }
- void set(double nr) { str_value.set(nr, 2, my_thd_charset); }
- void set(longlong nr) { str_value.set(nr, my_thd_charset); }
- void set(const char *str, uint length) { str_value.copy(str,length); }
- double val() { return atof(str_value.ptr()); }
- longlong val_int() { return strtoll(str_value.ptr(),NULL,10); }
+ void set(double nr) { str_value.set(nr, 2, thd_charset()); }
+ void set(longlong nr) { str_value.set(nr, thd_charset()); }
+ void set(const char *str, uint length, CHARSET_INFO *cs)
+ { str_value.copy(str,length,cs); }
+ double val()
+ {
+ CHARSET_INFO *cs=str_value.charset();
+ return my_strntod(cs, str_value.ptr(), str_value.length(),(char**)0);
+ }
+ longlong val_int()
+ {
+ CHARSET_INFO *cs=str_value.charset();
+ return my_strntoll(cs,str_value.ptr(),str_value.length(),NULL,10);
+ }
String *val_str(String*)
{
return null_value ? (String*) 0 : (String*) &str_value;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 4295a16c547..785a253b1ac 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -188,14 +188,15 @@ err2:
return 1;
}
-static uint32* slave_list_key(SLAVE_INFO* si, uint* len,
- my_bool not_used __attribute__((unused)))
+extern "C" uint32
+*slave_list_key(SLAVE_INFO* si, uint* len,
+ my_bool not_used __attribute__((unused)))
{
*len = 4;
return &si->server_id;
}
-static void slave_info_free(void *s)
+extern "C" void slave_info_free(void *s)
{
my_free((gptr) s, MYF(MY_WME));
}
@@ -203,7 +204,7 @@ static void slave_info_free(void *s)
void init_slave_list()
{
hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
- (hash_get_key) slave_list_key, slave_info_free, 0);
+ (hash_get_key) slave_list_key, (hash_free_key) slave_info_free, 0);
pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 72579664a3e..691add191b2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -122,7 +122,7 @@ sys_var_thd_ulong sys_interactive_timeout("interactive_timeout",
&SV::net_interactive_timeout);
sys_var_thd_ulong sys_join_buffer_size("join_buffer_size",
&SV::join_buff_size);
-sys_var_long_ptr sys_key_buffer_size("key_buffer_size",
+sys_var_ulonglong_ptr sys_key_buffer_size("key_buffer_size",
&keybuff_size,
fix_key_buffer_size);
sys_var_bool_ptr sys_local_infile("local_infile",
@@ -154,11 +154,11 @@ sys_var_thd_ulong sys_max_error_count("max_error_count",
&SV::max_error_count);
sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size",
&SV::max_heap_table_size);
-sys_var_thd_ulong sys_max_join_size("max_join_size",
+sys_var_thd_ulonglong sys_max_join_size("max_join_size",
&SV::max_join_size,
fix_max_join_size);
#ifndef TO_BE_DELETED /* Alias for max_join_size */
-sys_var_thd_ulong sys_sql_max_join_size("sql_max_join_size",
+sys_var_thd_ulonglong sys_sql_max_join_size("sql_max_join_size",
&SV::max_join_size,
fix_max_join_size);
#endif
@@ -202,8 +202,6 @@ 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_safe_show_db("safe_show_database",
- &opt_safe_show_db);
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);
@@ -282,7 +280,7 @@ static sys_var_thd_bit sys_unique_checks("unique_checks",
/* Local state variables */
-static sys_var_thd_ulong sys_select_limit("sql_select_limit",
+static sys_var_thd_ulonglong sys_select_limit("sql_select_limit",
&SV::select_limit);
static sys_var_timestamp sys_timestamp("timestamp");
static sys_var_last_insert_id sys_last_insert_id("last_insert_id");
@@ -299,6 +297,8 @@ static sys_var_readonly sys_warning_count("warning_count",
/* alias for last_insert_id() to be compatible with Sybase */
static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter");
+static sys_var_rand_seed1 sys_rand_seed1("rand_seed1");
+static sys_var_rand_seed2 sys_rand_seed2("rand_seed2");
/*
@@ -370,10 +370,11 @@ sys_var *sys_variables[]=
&sys_query_cache_type,
#endif /* HAVE_QUERY_CACHE */
&sys_quote_show_create,
+ &sys_rand_seed1,
+ &sys_rand_seed2,
&sys_read_buff_size,
&sys_read_rnd_buff_size,
&sys_rpl_recovery_rank,
- &sys_safe_show_db,
&sys_safe_updates,
&sys_select_limit,
&sys_server_id,
@@ -448,7 +449,7 @@ struct show_var_st init_vars[]= {
{"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
{"innodb_force_recovery", (char*) &innobase_force_recovery, SHOW_LONG },
{"innodb_thread_concurrency", (char*) &innobase_thread_concurrency, SHOW_LONG },
- {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_LONG},
+ {"innodb_flush_log_at_trx_commit", (char*) &innobase_flush_log_at_trx_commit, SHOW_INT},
{"innodb_fast_shutdown", (char*) &innobase_fast_shutdown, SHOW_MY_BOOL},
{"innodb_flush_method", (char*) &innobase_unix_file_flush_method, SHOW_CHAR_PTR},
{"innodb_lock_wait_timeout", (char*) &innobase_lock_wait_timeout, SHOW_LONG },
@@ -519,14 +520,19 @@ struct show_var_st init_vars[]= {
{sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS},
{sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS},
#endif /* HAVE_QUERY_CACHE */
- {sys_safe_show_db.name, (char*) &sys_safe_show_db, 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},
+#endif
{sys_server_id.name, (char*) &sys_server_id, SHOW_SYS},
{sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
{"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL},
{"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL},
{"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
{sys_slow_launch_time.name, (char*) &sys_slow_launch_time, SHOW_SYS},
+#ifdef HAVE_SYS_UN_H
{"socket", (char*) &mysql_unix_port, SHOW_CHAR_PTR},
+#endif
{sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS},
{"sql_mode", (char*) &opt_sql_mode, SHOW_LONG},
{"table_cache", (char*) &table_cache_size, SHOW_LONG},
@@ -594,7 +600,7 @@ static void fix_max_join_size(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
{
- if (thd->variables.max_join_size == (ulong) HA_POS_ERROR)
+ if (thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
thd->options|= OPTION_BIG_SELECTS;
else
thd->options&= ~OPTION_BIG_SELECTS;
@@ -687,6 +693,23 @@ 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();
+ if (option_limits)
+ *value= (ulonglong) getopt_ull_limit_value(tmp, option_limits);
+ else
+ *value= (ulonglong) tmp;
+ return 0;
+}
+
+
+void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type)
+{
+ *value= (ulonglong) option_limits->def_value;
+}
+
+
bool sys_var_bool_ptr::update(THD *thd, set_var *var)
{
*value= (my_bool) var->save_result.ulong_value;
@@ -769,7 +792,7 @@ bool sys_var_thd_ulonglong::update(THD *thd, set_var *var)
void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
- global_system_variables.*offset= (ulong) option_limits->def_value;
+ global_system_variables.*offset= (ulonglong) option_limits->def_value;
else
thd->variables.*offset= global_system_variables.*offset;
}
@@ -1069,6 +1092,19 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
}
+bool sys_var_rand_seed1::update(THD *thd, set_var *var)
+{
+ thd->rand.seed1= (ulong) var->value->val_int();
+ return 0;
+}
+
+bool sys_var_rand_seed2::update(THD *thd, set_var *var)
+{
+ thd->rand.seed2= (ulong) var->value->val_int();
+ return 0;
+}
+
+
/*
Functions to update thd->options bits
*/
@@ -1325,7 +1361,7 @@ int set_var::check(THD *thd)
return 0;
}
- if (value->fix_fields(thd, 0, &value))
+ if (value->check_cols(1) || value->fix_fields(thd, 0, &value))
return -1;
if (var->check_update_type(value->result_type()))
{
diff --git a/sql/set_var.h b/sql/set_var.h
index 31154d1e1d7..39a5995e30f 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -86,6 +86,22 @@ public:
};
+class sys_var_ulonglong_ptr :public sys_var
+{
+public:
+ ulonglong *value;
+ sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr)
+ :sys_var(name_arg),value(value_ptr) {}
+ sys_var_ulonglong_ptr(const char *name_arg, ulonglong *value_ptr,
+ sys_after_update_func func)
+ :sys_var(name_arg,func), value(value_ptr) {}
+ bool update(THD *thd, set_var *var);
+ void set_default(THD *thd, enum_var_type type);
+ SHOW_TYPE type() { return SHOW_LONGLONG; }
+ byte *value_ptr(THD *thd, enum_var_type type) { return (byte*) value; }
+};
+
+
class sys_var_bool_ptr :public sys_var
{
public:
@@ -203,6 +219,10 @@ public:
sys_var_thd_ulonglong(const char *name_arg, ulonglong SV::*offset_arg)
:sys_var_thd(name_arg), offset(offset_arg)
{}
+ sys_var_thd_ulonglong(const char *name_arg, ulonglong SV::*offset_arg,
+ sys_after_update_func func)
+ :sys_var_thd(name_arg,func), offset(offset_arg)
+ {}
bool update(THD *thd, set_var *var);
void set_default(THD *thd, enum_var_type type);
SHOW_TYPE type() { return SHOW_LONGLONG; }
@@ -333,6 +353,23 @@ public:
};
+class sys_var_rand_seed1 :public sys_var
+{
+public:
+ sys_var_rand_seed1(const char *name_arg) :sys_var(name_arg) {}
+ bool update(THD *thd, set_var *var);
+ bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
+};
+
+class sys_var_rand_seed2 :public sys_var
+{
+public:
+ sys_var_rand_seed2(const char *name_arg) :sys_var(name_arg) {}
+ bool update(THD *thd, set_var *var);
+ bool check_type(enum_var_type type) { return type == OPT_GLOBAL; }
+};
+
+
class sys_var_thd_conv_charset :public sys_var_thd
{
public:
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index c8ac594f00b..6c1a6db674b 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 -A
ISO LATIN-8852-2
Dal-B¹í verze Jan Pazdziora, adelton@fi.muni.cz-A
@@ -103,7 +103,7 @@
"Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE",
"Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe",
"Z-Báznamù: %ld Zdvojených: %ld Varování: %ld",
-"INSERT TABLE '%-.64s' nen-Bí dovoleno v seznamu tabulek FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Nezn-Bámá identifikace threadu: %lu",
"Nejste vlastn-Bíkem threadu %lu",
"Nejsou pou-B¾ity ¾ádné tabulky",
@@ -188,7 +188,7 @@
"Update tabulky bez WHERE s kl-Bíèem není v módu bezpeèných update dovoleno",
"Kl-Bíè '%-.64s' v tabulce '%-.64s' neexistuje",
"Nemohu otev-Bøít tabulku",
-"Handler tabulky nepodporuje check/repair",
+"Handler tabulky nepodporuje %s",
"Proveden-Bí tohoto pøíkazu není v transakci dovoleno",
"Chyba %d p-Bøi COMMIT",
"Chyba %d p-Bøi ROLLBACK",
@@ -249,7 +249,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 5638260277e..2067f13d593 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -97,7 +97,7 @@
"Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet.",
"Kan ikke udføre DROP '%-.64s'. Undersøg om feltet/nøglen eksisterer.",
"Poster: %ld Ens: %ld Advarsler: %ld",
-"INSERT TABLE '%-.64s' er ikke tilladt i FROM tabel liste",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ukendt tråd id: %lu",
"Du er ikke ejer af tråden %lu",
"Ingen tabeller i brug",
@@ -182,7 +182,7 @@
"Du bruger sikker opdaterings modus ('safe update mode') og du forsøgte at opdatere en tabel uden en WHERE klausul, der gør brug af et KEY felt",
"Nøglen '%-.64s' eksisterer ikke i tabellen '%-.64s'",
"Kan ikke åbne tabellen",
-"Denne tabeltype understøtter ikke CHECK/REPAIR",
+"Denne tabeltype understøtter ikke %s",
"Du må ikke bruge denne kommando i en transaktion",
"Modtog fejl %d mens kommandoen COMMIT blev udført",
"Modtog fejl %d mens kommandoen ROLLBACK blev udført",
@@ -243,7 +243,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index acbda2829d0..0c8d652653f 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -105,7 +105,7 @@
"Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!",
"Kan '%-.64s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat.",
"Records: %ld Dubbel: %ld Waarschuwing: %ld",
-"INSERT TABLE '%-.64s' is niet toegestaan in de FROM tabel-lijst",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Onbekend thread id: %lu",
"U bent geen bezitter van thread %lu",
"Geen tabellen gebruikt.",
@@ -190,7 +190,7 @@
"U gebruikt 'safe update mode' en u probeerde een tabel te updaten zonder een WHERE met een KEY kolom",
"Zoeksleutel '%-.64s' bestaat niet in tabel '%-.64s'",
"Kan tabel niet openen",
-"De 'handler' voor de tabel ondersteund geen check/repair",
+"De 'handler' voor de tabel ondersteund geen %s",
"Het is u niet toegestaan dit commando uit te voeren binnen een transactie",
"Kreeg fout %d tijdens COMMIT",
"Kreeg fout %d tijdens ROLLBACK",
@@ -251,7 +251,13 @@
"Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 36d8831fd39..68e4f07f246 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -94,7 +94,7 @@
"You can't delete all columns with ALTER TABLE. Use DROP TABLE instead",
"Can't DROP '%-.64s'. Check that column/key exists",
"Records: %ld Duplicates: %ld Warnings: %ld",
-"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Unknown thread id: %lu",
"You are not owner of thread %lu",
"No tables used",
@@ -179,7 +179,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -240,7 +240,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias",
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 96bd758cc6a..13663cca8e2 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -99,7 +99,7 @@
"ALTER TABLE kasutades ei saa kustutada kõiki tulpasid. Kustuta tabel DROP TABLE abil",
"Ei suuda kustutada '%-.64s'. Kontrolli kas tulp/võti eksisteerib",
"Kirjeid: %ld Kattuvaid: %ld Hoiatusi: %ld",
-"INSERT TABLE '%-.64s' ei ole lubatud FROM tabelite nimekirjas",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Tundmatu lõim: %lu",
"Ei ole lõime %lu omanik",
"Ühtegi tabelit pole kasutusel",
@@ -184,7 +184,7 @@
"Katse muuta tabelit turvalises rezhiimis ilma WHERE klauslita",
"Võti '%-.64s' ei eksisteeri tabelis '%-.64s'",
"Ei suuda avada tabelit",
-"Antud tabelitüüp ei toeta CHECK/REPAIR käske",
+"Antud tabelitüüp ei toeta %s käske",
"Seda käsku ei saa kasutada transaktsiooni sees",
"Viga %d käsu COMMIT täitmisel",
"Viga %d käsu ROLLBACK täitmisel",
@@ -245,7 +245,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 932182a2c94..ac1764aa7eb 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -94,7 +94,7 @@
"Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE",
"Ne peut effacer (DROP) '%-.64s'. Vérifiez s'il existe",
"Enregistrements: %ld Doublons: %ld Avertissements: %ld",
-"INSERT TABLE '%-.64s' n'est pas permis dans FROM liste des tables",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Numéro de tâche inconnu: %lu",
"Vous n'êtes pas propriétaire de la tâche no: %lu",
"Aucune table utilisée",
@@ -179,7 +179,7 @@
"Vous êtes en mode 'safe update' et vous essayez de faire un UPDATE sans clause WHERE utilisant un index",
"L'index '%-.64s' n'existe pas sur la table '%-.64s'",
"Impossible d'ouvrir la table",
-"Ce type de table ne supporte pas les check/repair",
+"Ce type de table ne supporte pas les %s",
"Vous n'êtes pas autorisé à exécute cette commande dans une transaction",
"Erreur %d lors du COMMIT",
"Erreur %d lors du ROLLBACK",
@@ -240,7 +240,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index febd723df89..6b19034ae59 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -97,7 +97,7 @@
"Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Verwende DROP TABLE stattdessen.",
"Kann '%-.64s' nicht löschen (DROP). Existiert das Feld/der Schlüssel?",
"Datensätze: %ld Duplikate: %ld Warnungen: %ld",
-"INSERT TABLE '%-.64s' nicht erlaubt im FROM Abschnitt.",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Unbekannte Thread-ID: %lu",
"Nicht Besitzer des Threads %lu.",
"Keine Tabellen in Verwendung.",
@@ -182,7 +182,7 @@
"Unter Verwendung des Sicheren Updatemodes wurde versucht eine Tabelle zu updaten ohne eine KEY-Spalte in der WHERE-Klausel",
"Schlüssel '%-.64s' existiert nicht in der Tabelle '%-.64s'",
"Kann Tabelle nicht öffnen",
-"Der Tabellen-Handler für diese Tabelle unterstützt kein check/repair",
+"Der Tabellen-Handler für diese Tabelle unterstützt kein %s",
"Keine Berechtigung dieses Kommando in einer Transaktion auszuführen",
"Fehler %d wärend COMMIT",
"Fehler %d wärend ROLLBACK",
@@ -243,7 +243,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect return more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect return more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 9d9aa07af8d..7e680216b3e 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -94,7 +94,7 @@
"Äåí åßíáé äõíáôÞ ç äéáãñáöÞ üëùí ôùí ðåäßùí ìå ALTER TABLE. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå DROP TABLE",
"Áäýíáôç ç äéáãñáöÞ (DROP) '%-.64s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé",
"ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld ÐñïåéäïðïéÞóåéò: %ld",
-"INSERT TABLE '%-.64s' äåí åðéôñÝðåôáé óôï FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Áãíùóôï thread id: %lu",
"Äåí åßóèå owner ôïõ thread %lu",
"Äåí ÷ñçóéìïðïéÞèçêáí ðßíáêåò",
@@ -179,7 +179,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -240,7 +240,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index d596c8f3433..747d2be5a3b 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -96,7 +96,7 @@
"Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette",
"A DROP '%-.64s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e",
"Rekordok: %ld Duplikalva: %ld Warnings: %ld",
-"INSERT TABLE '%-.64s' nem engedelyezett a FROM table listabol",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ervenytelen szal (thread) id: %lu",
"A %lu thread-nek mas a tulajdonosa",
"Nincs hasznalt tabla",
@@ -181,7 +181,7 @@
"On a biztonsagos update modot hasznalja, es WHERE that uses a KEY column",
"A '%-.64s' kulcs nem letezik a '%-.64s' tablaban",
"Nem tudom megnyitni a tablat",
-"A tabla kezeloje (handler) nem tamogatja az ellenorzest/helyreallitast",
+"A tabla kezeloje (handler) nem tamogatja az %s",
"Az On szamara nem engedelyezett a parancs vegrehajtasa a tranzakcioban",
"%d hiba a COMMIT vegrehajtasa soran",
"%d hiba a ROLLBACK vegrehajtasa soran",
@@ -242,7 +242,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index d9ccf54d7ea..ef7efa925af 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -94,7 +94,7 @@
"Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE",
"Impossibile cancellare '%-.64s'. Controllare che il campo chiave esista",
"Records: %ld Duplicati: %ld Avvertimenti: %ld",
-"INSERT TABLE '%-.64s' non e` permesso nella FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Thread id: %lu sconosciuto",
"Utente non proprietario del thread %lu",
"Nessuna tabella usata",
@@ -179,7 +179,7 @@
"In modalita` 'safe update' si e` cercato di aggiornare una tabella senza clausola WHERE su una chiave",
"La chiave '%-.64s' non esiste nella tabella '%-.64s'",
"Impossibile aprire la tabella",
-"Il gestore per la tabella non supporta il controllo/riparazione",
+"Il gestore per la tabella non supporta il %s",
"Non puoi eseguire questo comando in una transazione",
"Rilevato l'errore %d durante il COMMIT",
"Rilevato l'errore %d durante il ROLLBACK",
@@ -240,7 +240,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 22a53801efd..61b69000473 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -96,7 +96,7 @@
"ALTER TABLE ¤ÇÁ´¤Æ¤Î column ¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó. DROP TABLE ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤",
"'%-.64s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿. Check that column/key exists",
"¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£¿ô: %ld Warnings: %ld",
-"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"thread id: %lu ¤Ï¤¢¤ê¤Þ¤»¤ó",
"thread %lu ¤Î¥ª¡¼¥Ê¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó",
"No tables used",
@@ -181,7 +181,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -242,7 +242,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 27a8fdde027..9c367c43551 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -94,7 +94,7 @@
"ALTER TABLE ¸í·ÉÀ¸·Î´Â ¸ðµç Ä®·³À» Áö¿ï ¼ö ¾ø½À´Ï´Ù. DROP TABLE ¸í·ÉÀ» ÀÌ¿ëÇϼ¼¿ä.",
"'%-.64s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª Å°°¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä.",
"·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³ °æ°í: %ld°³",
-"INSERT TABLE '%-.64s' ´Â FROM Å×À̺í list¿¡¼­ Çã°¡µÇÁö ¾Ê¾Ò½À´Ï´Ù.",
+"You can't specify target table '%-.64s' for update in FROM clause",
"¾Ë¼ö ¾ø´Â ¾²·¹µå id: %lu",
"¾²·¹µå(Thread) %luÀÇ ¼ÒÀ¯ÀÚ°¡ ¾Æ´Õ´Ï´Ù.",
"¾î¶² Å×ÀÌºíµµ »ç¿ëµÇÁö ¾Ê¾Ò½À´Ï´Ù.",
@@ -179,7 +179,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -240,7 +240,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 8e8b5aa7e61..a3fed98e81a 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -96,7 +96,7 @@
"Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor.",
"Kan ikkje DROP '%-.64s'. Undersøk om felt/nøkkel eksisterar.",
"Postar: %ld Like: %ld Åtvaringar: %ld",
-"INSERT TABLE '%-.64s' er ikkje tillate i FROM tabell liste",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ukjent tråd id: %lu",
"Du er ikkje eigar av tråd %lu",
"Ingen tabellar i bruk",
@@ -181,7 +181,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -242,7 +242,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 0f4650c186c..26eabe3b91f 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -96,7 +96,7 @@
"En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden.",
"Kan ikke DROP '%-.64s'. Undersøk om felt/nøkkel eksisterer.",
"Poster: %ld Like: %ld Advarsler: %ld",
-"INSERT TABLE '%-.64s' er ikke tillatt i FROM tabell liste",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ukjent tråd id: %lu",
"Du er ikke eier av tråden %lu",
"Ingen tabeller i bruk",
@@ -181,7 +181,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -242,7 +242,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 758e96e5ca3..616a5d4919b 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -98,7 +98,7 @@
"Nie mo¿na usun?æ wszystkich pól wykorzystuj?c ALTER TABLE. W zamian u¿yj DROP TABLE",
"Nie mo¿na wykonaæ operacji DROP '%-.64s'. Sprawd¥, czy to pole/klucz istnieje",
"Rekordów: %ld Duplikatów: %ld Ostrze¿eñ: %ld",
-"Operacja INSERT TABLE '%-.64s' nie jest dozwolona w li?cie tabel w FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Nieznany identyfikator w?tku: %lu",
"Nie jeste? w³a?cicielem w?tku %lu",
"Nie ma ¿adej u¿ytej tabeli",
@@ -183,7 +183,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -244,7 +244,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 21ebe5c39dc..04a9afaa808 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -94,7 +94,7 @@
"Você não pode deletar todas as colunas com ALTER TABLE. Use DROP TABLE em seu lugar",
"Não se pode fazer DROP '%-.64s'. Confira se esta coluna/chave existe",
"Registros: %ld - Duplicados: %ld - Avisos: %ld",
-"INSERT TABLE '%-.64s' não é permitido na lista de tabelas contidas em FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"'Id' de 'thread' %lu desconhecido",
"Você não é proprietário da 'thread' %lu",
"Nenhuma tabela usada",
@@ -179,7 +179,7 @@
"Você está usando modo de atualização seguro e tentou atualizar uma tabela sem uma cláusula WHERE que use uma coluna chave",
"Chave '%-.64s' não existe na tabela '%-.64s'",
"Não pode abrir a tabela",
-"O manipulador de tabela não suporta checagem/reparação (check/repair)",
+"O manipulador de tabela não suporta %s",
"Não lhe é permitido executar este comando em uma transação",
"Obteve erro %d durante COMMIT",
"Obteve erro %d durante ROLLBACK",
@@ -240,7 +240,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index c84049d6192..0ae6fc8e51a 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -98,7 +98,7 @@
"Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb",
"Nu pot sa DROP '%-.64s'. Verifica daca coloana/cheia exista",
"Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld",
-"INSERT TABLE '%-.64s' nu este permis in lista FROM de tabele",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Id-ul: %lu thread-ului este necunoscut",
"Nu sinteti proprietarul threadului %lu",
"Nici o tabela folosita",
@@ -183,7 +183,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -244,7 +244,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 0ee79ce5811..343178b3118 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -97,7 +97,7 @@
"îÅÌØÚÑ ÕÄÁÌÉÔØ ×ÓÅ ÐÏÌÑ ÞÅÒÅÚ ALTER TABLE. ÷ÏÓÐÏÌØÚÕÊÔÅÓØ DROP TABLE",
"îÅ ÍÏÇÕ ÓÂÒÏÓÉÔØ '%-.64s'. ðÒÏ×ÅÒØÔÅ, ÞÔÏ ÜÔÏ ÐÏÌÅ/ËÌÀÞ ÓÕÝÅÓÔ×ÕÀÔ",
"úÁÐÉÓÅÊ: %ld äÕÂÌÅÊ: %ld ðÒÅÄÕÐÒÅÖÄÅÎÉÊ: %ld",
-"INSERT TABLE '%-.64s' ÎÅ ÒÁÚÒÅÛÅÎÏ × ÓÐÉÓËÅ FROM TABLE",
+"÷Ù ÎÅ ÍÏÖÅÔÅ ÕËÁÚÁÔØ ÉÚÍÅÎÅÑÍÕÀ ÔÁÂÌÉÃÕ '%-.64s' × ÓÐÉÓËÅ ÔÁÂÌÉÃ FROM",
"îÅÉÚ×ÅÓÔÎÁÑ ÎÉÔØ: %lu",
"÷Ù ÎÅ ×ÌÁÄÅÌÅà ÎÉÔÉ %lu",
"ôÁÂÌÉÃÙ ÎÅ ÉÓÐÏÌØÚÏ×ÁÎÙ",
@@ -182,7 +182,7 @@
"MySQL ÒÁÂÏÔÁÅÔ × ÒÅÖÉÍÅ ÚÁÝÉÔÙ ÏÔ ÄÕÒÁËÏ× (safe_mode) - ÎÅ ÍÏÇÕ UPDATE ÂÅÚ WHERE Ó ËÁËÉÍ-ÎÅÂÕÄØ KEY",
"éÎÄÅËÓ '%-.64s' ÎÅ ÎÁÊÄÅÎ × ÔÁÂÌÉÃÅ '%-.64s'",
"îÅ ÍÏÇÕ ÏÔËÒÙÔØ ÔÁÂÌÉÃÕ",
-"äÁÎÎÙÊ ÔÉÐ ÔÁÂÌÉà ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ check/repair",
+"äÁÎÎÙÊ ÔÉÐ ÔÁÂÌÉà ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ËÏÍÁÎÄÕ %s",
"üÔÁ ËÏÍÁÎÄÁ ×ÎÕÔÒÉ ÔÒÁÎÚÁËÃÉÉ ÚÁÐÒÅÝÅÎÁ",
"ïÛÉÂËÁ %d ×Ï ×ÒÅÍÑ COMMIT",
"ïÛÉÂËÁ %d ×Ï ×ÒÅÍÑ ROLLBACK",
@@ -243,7 +243,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÇÏ ÐÏÌÑ",
+"ïÛÉÂËÁ ÍÏÝØÎÏÓÔÉ ÍÎÏÖÅÓÔ×Á (ÂÏÌØÛÅ/ÍÅÎØÛÅ %d ËÏÌÏÎÏË)",
"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ",
+"ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÐÏÌÑ '%s' ÉÚ %s × %s",
+"óÓÙÌËÁ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ (%s)",
+"Every derived table must have it's own alias"
+"Select %u ÂÙÌ ÕÐÒÁÚÄÎÅÎ × ÐÒÏÃÅÓÓÅ ÏÐÔÉÍÉÚÁÃÉÉ",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index d120630b636..b04b94b82e8 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -100,7 +100,7 @@
"Ne možete da izbrišete sve kolone pomoæu komande 'ALTER TABLE'. Upotrebite komandu 'DROP TABLE' ako želite to da uradite",
"Ne mogu da izvršim komandu drop 'DROP' na '%-.64s'. Proverite da li ta kolona (odnosno kljuè) postoji",
"Slogova: %ld Duplikata: %ld Upozorenja: %ld",
-"Komanda 'INSERT TABLE' na '%-.64s' nije dozvoljena u listi 'FROM' tabela",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Nepoznat thread identifikator: %lu",
"Vi niste vlasnik thread-a %lu",
"Nema upotrebljenih tabela",
@@ -236,7 +236,13 @@
"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index eb9e2a240a0..f8f52f86b6a 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -102,7 +102,7 @@
"One nemô¾em zmaza» all fields with ALTER TABLE. Use DROP TABLE instead",
"Nemô¾em zru¹i» (DROP) '%-.64s'. Skontrolujte, èi neexistujú záznamy/kµúèe",
"Záznamov: %ld Opakovaných: %ld Varovania: %ld",
-"INSERT TABLE '%-.64s' nie je dovolené v zozname tabuliek FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Neznáma identifikácia vlákna: %lu",
"Nie ste vlastníkom vlákna %lu",
"Nie je pou¾itá ¾iadna tabuµka",
@@ -187,7 +187,7 @@
"You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column",
"Key '%-.64s' doesn't exist in table '%-.64s'",
"Can't open table",
-"The handler for the table doesn't support check/repair",
+"The handler for the table doesn't support %s",
"You are not allowed to execute this command in a transaction",
"Got error %d during COMMIT",
"Got error %d during ROLLBACK",
@@ -248,7 +248,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 0b7de283481..674d36e9d8c 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -95,7 +95,7 @@
"No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo",
"No puedo ELIMINAR '%-.64s'. compuebe que el campo/clave existe",
"Registros: %ld Duplicados: %ld Peligros: %ld",
-"INSERT TABLE '%-.64s' no esta permitido en FROM tabla lista",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Identificador del thread: %lu desconocido",
"Tu no eres el propietario del thread%lu",
"No ha tablas usadas",
@@ -180,7 +180,7 @@
"Tu estás usando modo de actualización segura y tentado actualizar una tabla sin un WHERE que usa una KEY columna",
"Clave '%-.64s' no existe en la tabla '%-.64s'",
"No puedo abrir tabla",
-"El manipulador de la tabla no permite soporte para check/repair",
+"El manipulador de la tabla no permite soporte para %s",
"No tienes el permiso para ejecutar este comando en una transición",
"Obtenido error %d durante COMMIT",
"Obtenido error %d durante ROLLBACK",
@@ -241,7 +241,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
+"Cardinality error (more/less than %d columns)",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 052cd1506d3..052568ac30d 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -94,7 +94,7 @@
"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället",
"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns",
"Rader: %ld Dubletter: %ld Varningar: %ld",
-"INSERT table '%-.64s' får inte finnas i FROM tabell-listan",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Finns inget thread med id %lu",
"Du är inte ägare till thread %lu",
"Inga tabeller angivna",
@@ -179,7 +179,7 @@
"Du använder 'säker uppdaterings mod' och försökte uppdatera en table utan en WHERE sats som använder sig av en nyckel",
"Nyckel '%-.64s' finns inte in tabell '%-.64s'",
"Kan inte öppna tabellen",
-"Tabellhanteraren för denna tabell kan inte göra check/repair",
+"Tabellhanteraren för denna tabell kan inte göra %s",
"Du får inte utföra detta kommando i en transaktion",
"Fick fel %d vid COMMIT",
"Fick fel %d vid ROLLBACK",
@@ -229,18 +229,24 @@
"Option '%s' användes två gånger",
"Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)",
"Du har inte privlegiet '%-.128s' som behövs för denna 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",
-"Wrong foreign key definition for '%-.64s': %s",
-"Key reference and table reference doesn't match",
-"Subselect returns more than 1 field",
-"Subselect returns more than 1 record",
-"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Variable '%-.64s' är en LOCAL variabel och kan inte ändrad med SET GLOBAL",
+"Variable '%-.64s' är en GLOBAL variabel och bör sättas med SET GLOBAL",
+"Variable '%-.64s' har inte ett DEFAULT värde",
+"Variable '%-.64s' kan inte be satt till '%-.64s'",
+"Fel typ av argument till variabel '%-.64s'",
+"Variabeln '%-.64s' kan endast sättas, inte läsas",
+"Fel använding/placering av '%s'",
+"Denna version av MySQL kan inte utföra '%s'",
+"Fick fatalt fel %d: '%-.128s' från master vid läsning av binär loggen",
+"Felaktig FOREIGN KEY definition för '%-.64s': %s",
+"Nyckel referensen och table referensen stämmer inte överens",
+"Cardinality error (more/less than %d columns)",
+"Subselect returnerade mer än 1 rad",
+"Okänd PREPARED STATEMENT id (%ld) var given till %s",
+"Hjälp databasen finns inte eller är skadad",
+"Syklisk referens i subselect",
+"Konvertar kolumn '%s' från %s till %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 5cfad494a32..122506f17cf 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -99,7 +99,7 @@
"îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ×Ó¦ ÓÔÏ×Âæ ÚÁ ÄÏÐÏÍÏÇÏÀ ALTER TABLE. äÌÑ ÃØÏÇÏ ÓËÏÒÉÓÔÁÊÔÅÓÑ DROP TABLE",
"îÅ ÍÏÖÕ DROP '%-.64s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤",
"úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld úÁÓÔÅÒÅÖÅÎØ: %ld",
-"INSERT TABLE '%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ Õ ÐÅÒÅ̦ËÕ FROM TABLE",
+"ôÁÂÌÉÃÑ '%-.64s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM",
"îÅצÄÏÍÉÊ ¦ÄÅÎÔÉƦËÁÔÏÒ Ç¦ÌËÉ: %lu",
"÷É ÎÅ ×ÏÌÏÄÁÒ Ç¦ÌËÉ %lu",
"îÅ ×ÉËÏÒÉÓÔÁÎÏ ÔÁÂÌÉÃØ",
@@ -184,7 +184,7 @@
"÷É Õ ÒÅÖÉͦ ÂÅÚÐÅÞÎÏÇÏ ÏÎÏ×ÌÅÎÎÑ ÔÁ ÎÁÍÁÇÁ¤ÔÅÓØ ÏÎÏ×ÉÔÉ ÔÁÂÌÉÃÀ ÂÅÚ ÏÐÅÒÁÔÏÒÁ WHERE, ÝÏ ×ÉËÏÒÉÓÔÏ×Õ¤ KEY ÓÔÏ×ÂÅÃØ",
"ëÌÀÞ '%-.64s' ÎÅ ¦ÓÎÕ¤ × ÔÁÂÌÉæ '%-.64s'",
"îÅ ÍÏÖÕ ×¦ÄËÒÉÔÉ ÔÁÂÌÉÃÀ",
-"÷ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕÅ ÐÅÒÅצÒËÕ/צÄÎÏ×ÌÅÎÎÑ",
+"÷ËÁÚ¦×ÎÉË ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕÅ %s",
"÷ÁÍ ÎÅ ÄÏÚ×ÏÌÅÎÏ ×ÉËÏÎÕ×ÁÔÉ ÃÀ ËÏÍÁÎÄÕ × ÔÒÁÎÚÁËæ§",
"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ COMMIT",
"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ %d Ð¦Ä ÞÁÓ ROLLBACK",
@@ -245,7 +245,13 @@
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
-"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÓÔÏ×ÂÅÃØ",
-"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÚÁÐÉÓ",
+"Cardinality error (¦ÌØÛÅ/ÍÅÎØÛÅ Î¦Ö %d ÓÔÏ×Âæ×)",
+"ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ",
"Unknown prepared statement handler (%ld) given to %s",
-"Help database is corrupt or does not exist", \ No newline at end of file
+"Help database is corrupt or does not exist",
+"ãÉË̦ÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ЦÄÚÁÐÉÔ",
+"ðÅÒÅÔ×ÏÒÅÎÎÑ ÓÔÏ×ÂÃÁ '%s' Ú %s Õ %s",
+"ðÏÓÉÌÁÎÎÑ '%-.64s' ÎÅ ÐiÄÔÒÉÍÕÅÔÓÑ (%s)",
+"Every derived table must have it's own alias"
+"Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
diff --git a/sql/slave.cc b/sql/slave.cc
index a07fd7ac7d1..f8acc592afa 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -608,7 +608,7 @@ void init_table_rule_hash(HASH* h, bool* h_inited)
{
hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
(hash_get_key) get_table_key,
- (void (*)(void*)) free_table_ent, 0);
+ (hash_free_key) free_table_ent, 0);
*h_inited = 1;
}
@@ -638,9 +638,10 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
TABLE_RULE_ENT* e ;
get_dynamic(a, (gptr)&e, i);
- if (!wild_case_compare(system_charset_info, key, key_end,
+ if (!my_wildcmp(system_charset_info, key, key_end,
(const char*)e->db,
- (const char*)(e->db + e->key_len),'\\'))
+ (const char*)(e->db + e->key_len),
+ '\\',wild_one,wild_many))
return e;
}
@@ -1636,7 +1637,7 @@ bool flush_master_info(MASTER_INFO* mi)
DBUG_PRINT("enter",("master_pos: %ld", (long) mi->master_log_pos));
my_b_seek(file, 0L);
- my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n",
+ 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),
mi->host, mi->user,
mi->password, mi->port, mi->connect_retry
@@ -1944,7 +1945,7 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
"Slave: query '%s' partially completed on the master \
and was aborted. There is a chance that your master is inconsistent at this \
point. If you are sure that your master is ok, run this query manually on the\
- slave and then restart the slave with SET SQL_SLAVE_SKIP_COUNTER=1;\
+ slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;\
SLAVE START;", thd->query);
rli->last_slave_errno = expected_error;
sql_print_error("%s",rli->last_slave_error);
@@ -2024,11 +2025,10 @@ This may also be a network problem, or just a bug in the master or slave code.\
}
/*****************************************************************************
-
Slave I/O Thread entry point
-
*****************************************************************************/
-pthread_handler_decl(handle_slave_io,arg)
+
+extern "C" pthread_handler_decl(handle_slave_io,arg)
{
THD *thd; // needs to be first for thread_stack
MYSQL *mysql;
@@ -2297,11 +2297,10 @@ err:
}
/*****************************************************************************
-
Slave SQL Thread entry point
-
*****************************************************************************/
-pthread_handler_decl(handle_slave_sql,arg)
+
+extern "C" pthread_handler_decl(handle_slave_sql,arg)
{
THD *thd; /* needs to be first for thread_stack */
char llbuff[22],llbuff1[22];
@@ -2477,7 +2476,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);
+ Append_block_log_event aev(thd,0,0,0);
for (;;)
{
@@ -2490,7 +2489,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);
+ Execute_load_log_event xev(thd,0);
xev.log_pos = mi->master_log_pos;
if (unlikely(mi->rli.relay_log.append(&xev)))
{
diff --git a/sql/slave.h b/sql/slave.h
index 74c89f9d755..2c750e415bc 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -436,8 +436,8 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos,
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
const char** errmsg);
-pthread_handler_decl(handle_slave_io,arg);
-pthread_handler_decl(handle_slave_sql,arg);
+extern "C" pthread_handler_decl(handle_slave_io,arg);
+extern "C" pthread_handler_decl(handle_slave_sql,arg);
extern bool volatile abort_loop;
extern MASTER_INFO main_mi, *active_mi; /* active_mi for multi-master */
extern volatile int active_mi_in_use;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 5f8cf42c2bf..cde6ace1470 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -32,50 +32,6 @@
#include <assert.h>
#include <stdarg.h>
-struct acl_host_and_ip
-{
- char *hostname;
- long ip,ip_mask; // Used with masked ip:s
-};
-
-
-class ACL_ACCESS {
-public:
- ulong sort;
- ulong access;
-};
-
-
-/* ACL_HOST is used if no host is specified */
-
-class ACL_HOST :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *db;
-};
-
-
-class ACL_USER :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- uint hostname_length;
- USER_RESOURCES user_resource;
- char *user,*password;
- ulong salt[2];
- enum SSL_type ssl_type;
- const char *ssl_cipher, *x509_issuer, *x509_subject;
-};
-
-
-class ACL_DB :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *user,*db;
-};
-
class acl_entry :public hash_filo_element
{
@@ -103,6 +59,7 @@ static HASH acl_check_hosts, hash_tables;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
static uint grant_version=0;
+static uint priv_version=0; /* Version of priv tables. incremented by acl_init */
static ulong get_access(TABLE *form,uint fieldnr);
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
@@ -119,6 +76,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
SYNOPSIS
acl_init()
+ thd Thread handler
dont_read_acl_tables Set to 1 if run with --skip-grant
RETURN VALUES
@@ -127,9 +85,9 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
*/
-my_bool acl_init(bool dont_read_acl_tables)
+my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
- THD *thd, *org_thd;
+ THD *thd;
TABLE_LIST tables[3];
TABLE *table;
READ_RECORD read_record_info;
@@ -140,14 +98,17 @@ my_bool acl_init(bool dont_read_acl_tables)
if (!acl_cache)
acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0,
(hash_get_key) acl_entry_get_key,
- (void (*)(void*)) free);
+ (hash_free_key) free);
if (dont_read_acl_tables)
+ {
DBUG_RETURN(0); /* purecov: tested */
+ }
+
+ priv_version++; /* Priveleges updated */
/*
To be able to run this from boot, we allocate a temporary THD
*/
- org_thd=current_thd; // Save for restore
if (!(thd=new THD))
DBUG_RETURN(1); /* purecov: inspected */
thd->store_globals();
@@ -231,13 +192,18 @@ my_bool acl_init(bool dont_read_acl_tables)
"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 if (length % 8) // This holds true for passwords
+ else /* non emptpy and not short passwords */
{
- 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 */
+ user.pversion=get_password_version(user.password);
+ /* Only passwords of specific lengths depending on version are allowed */
+ if ( (!user.pversion && length % 8) || (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 */
+ }
}
get_salt_from_password(user.salt,user.password);
user.access=get_access(table,3) & GLOBAL_ACLS;
@@ -339,6 +305,11 @@ end:
delete thd;
if (org_thd)
org_thd->store_globals(); /* purecov: inspected */
+ else
+ {
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ }
DBUG_RETURN(return_val);
}
@@ -385,7 +356,7 @@ void acl_reload(THD *thd)
delete_dynamic(&acl_wild_hosts);
hash_free(&acl_check_hosts);
- if (acl_init(0))
+ if (acl_init(thd, 0))
{ // Error. Revert to old list
acl_free(); /* purecov: inspected */
acl_hosts=old_acl_hosts;
@@ -417,7 +388,7 @@ static ulong get_access(TABLE *form, uint fieldnr)
{
ulong access_bits=0,bit;
char buff[2];
- String res(buff,sizeof(buff),default_charset_info);
+ String res(buff,sizeof(buff),my_charset_latin1);
Field **pos;
for (pos=form->field+fieldnr, bit=1;
@@ -426,7 +397,7 @@ static ulong get_access(TABLE *form, uint fieldnr)
pos++ , bit<<=1)
{
(*pos)->val_str(&res,&res);
- if (my_toupper(system_charset_info, res[0]) == 'Y')
+ if (my_toupper(my_charset_latin1, res[0]) == 'Y')
access_bits|= bit;
}
return access_bits;
@@ -477,18 +448,51 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
return 0;
}
+/*
+ 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
+
+ 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;
+
*/
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
- bool old_ver, USER_RESOURCES *mqh)
+ bool old_ver, USER_RESOURCES *mqh,char* prepared_scramble,
+ uint *cur_priv_version,ACL_USER** hint_user)
{
ulong user_access=NO_ACCESS;
- *priv_user=(char*) user;
+ *priv_user= (char*) user;
+ bool password_correct= 0;
+ int stage= (*hint_user != NULL); /* NULL passed as first stage */
+ ACL_USER *acl_user= NULL;
+
DBUG_ENTER("acl_getroot");
bzero(mqh,sizeof(USER_RESOURCES));
@@ -499,126 +503,175 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
}
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.
*/
- for (uint i=0 ; i < acl_users.elements ; i++)
+
+ if (stage && (*cur_priv_version==priv_version))
+ acl_user=*hint_user;
+ else
+ for (uint i=0 ; i < acl_users.elements ; i++)
+ {
+ 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_search->host,host,ip))
+ {
+ /* Found mathing user */
+ acl_user=acl_user_search;
+ /* Store it as a cache */
+ *hint_user=acl_user;
+ *cur_priv_version=priv_version;
+ break;
+ }
+ }
+ }
+
+
+ /* Now we have acl_user found and may start our checks */
+
+ if (acl_user)
{
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user->user || !strcmp(user,acl_user->user))
+ /* Password should present for both or absend for both */
+ if (!acl_user->password && !*password ||
+ (acl_user->password && *password))
{
- if (compare_hostname(&acl_user->host,host,ip))
+ /* Quick check and accept for empty passwords*/
+ if (!acl_user->password && !*password)
+ password_correct=1;
+ else /* Normal password presents */
{
- if (!acl_user->password && !*password ||
- (acl_user->password && *password &&
- !check_scramble(password,message,acl_user->salt,
- (my_bool) old_ver)))
- {
+ /* 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 /* Password incorrect */
+ /* At the first stage - prepare scramble */
+ if (!stage)
+ 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 */
+
#ifdef HAVE_OPENSSL
- Vio *vio=thd->net.vio;
- /*
- In this point we know that user is allowed to connect
- from given host by given username/password pair. Now
- we check if SSL is required, if user is using SSL and
- if X509 certificate attributes are OK
- */
- 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;
- break;
- case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
- if (vio_type(vio) == VIO_TYPE_SSL)
- 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.
- */
- if (SSL_get_peer_certificate(vio->ssl_))
- user_access=acl_user->access;
- break;
- case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
- /*
- We do not check for absence of SSL because without SSL it does
- not pass all checks here anyway.
- If cipher name is specified, we compare it to actual cipher in
- use.
- */
- 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;
- else
- {
- user_access=NO_ACCESS;
- break;
- }
- }
- /* Prepare certificate (if exists) */
- DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(vio->ssl_);
- DBUG_PRINT("info",("checkpoint 2"));
- /* If X509 issuer is speified, we check it... */
- if (acl_user->x509_issuer)
- {
- 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))
- {
- user_access=NO_ACCESS;
- 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))
- user_access=NO_ACCESS;
- else
- user_access=acl_user->access;
- free(ptr);
- }
- break;
- }
-#else /* HAVE_OPENSSL */
+ {
+ Vio *vio=thd->net.vio;
+ /*
+ In this point we know that user is allowed to connect
+ from given host by given username/password pair. Now
+ we check if SSL is required, if user is using SSL and
+ if X509 certificate attributes are OK
+ */
+ 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;
+ break;
+ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ if (vio_type(vio) == VIO_TYPE_SSL)
+ 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.
+ */
+ if (SSL_get_peer_certificate(vio->ssl_))
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ /*
+ We do not check for absence of SSL because without SSL it does
+ not pass all checks here anyway.
+ If cipher name is specified, we compare it to actual cipher in
+ use.
+ */
+ 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;
-#endif /* HAVE_OPENSSL */
- *mqh=acl_user->user_resource;
- if (!acl_user->user)
- *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+ else
+ {
+ user_access=NO_ACCESS;
break;
}
-#ifndef ALLOW_DOWNGRADE_OF_USERS
- break; // Wrong password breaks loop /* purecov: inspected */
-#endif
}
+ /* Prepare certificate (if exists) */
+ DBUG_PRINT("info",("checkpoint 1"));
+ X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ DBUG_PRINT("info",("checkpoint 2"));
+ /* If X509 issuer is speified, we check it... */
+ if (acl_user->x509_issuer)
+ {
+ 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))
+ {
+ user_access=NO_ACCESS;
+ 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))
+ user_access=NO_ACCESS;
+ else
+ user_access=acl_user->access;
+ free(ptr);
+ }
+ break;
}
}
+#else /* HAVE_OPENSSL */
+ user_access=acl_user->access;
+#endif /* HAVE_OPENSSL */
+ *mqh=acl_user->user_resource;
+ if (!acl_user->user)
+ *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+
+unlock_and_exit:
VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(user_access);
}
-/*
-** Functions to add and change user and database privileges when one
-** changes things with GRANT
-*/
-
static byte* check_get_key(ACL_USER *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -627,12 +680,12 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
}
static void acl_update_user(const char *user, const char *host,
- const char *password,
+ const char *password,
enum SSL_type ssl_type,
const char *ssl_cipher,
const char *x509_issuer,
const char *x509_subject,
- USER_RESOURCES *mqh,
+ USER_RESOURCES *mqh,
ulong privileges)
{
for (uint i=0 ; i < acl_users.elements ; i++)
@@ -644,7 +697,7 @@ static void acl_update_user(const char *user, const char *host,
{
if (!acl_user->host.hostname && !host[0] ||
acl_user->host.hostname &&
- !my_strcasecmp(system_charset_info, host, acl_user->host.hostname))
+ !my_strcasecmp(my_charset_latin1, host, acl_user->host.hostname))
{
acl_user->access=privileges;
if (mqh->bits & 1)
@@ -665,12 +718,16 @@ static void acl_update_user(const char *user, const char *host,
}
if (password)
{
- if (!password[0])
+ 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);
}
}
break;
@@ -681,7 +738,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,
enum SSL_type ssl_type,
const char *ssl_cipher,
const char *x509_issuer,
@@ -706,6 +763,7 @@ static void acl_insert_user(const char *user, const char *host,
{
acl_user.password=(char*) ""; // Just point at something
get_salt_from_password(acl_user.salt,password);
+ acl_user.pversion=get_password_version(password);
}
VOID(push_dynamic(&acl_users,(gptr) &acl_user));
@@ -734,7 +792,7 @@ static void acl_update_db(const char *user, const char *host, const char *db,
{
if (!acl_db->host.hostname && !host[0] ||
acl_db->host.hostname &&
- !my_strcasecmp(system_charset_info, host, acl_db->host.hostname))
+ !my_strcasecmp(my_charset_latin1, host, acl_db->host.hostname))
{
if (!acl_db->db && !db[0] ||
acl_db->db && !strcmp(db,acl_db->db))
@@ -798,7 +856,7 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip,
end=strmov((tmp_db=strmov(key+sizeof(struct in_addr),user)+1),db);
if (lower_case_table_names)
{
- my_casedn_str(system_charset_info, tmp_db);
+ my_casedn_str(my_charset_latin1, tmp_db);
db=tmp_db;
}
key_length=(uint) (end-key);
@@ -873,7 +931,7 @@ int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
{
if (*wildstr == wild_prefix && wildstr[1])
wildstr++;
- if (my_toupper(cs, *wildstr++) !=
+ if (my_toupper(cs, *wildstr++) !=
my_toupper(cs, *str++)) DBUG_RETURN(1);
}
if (! *wildstr ) DBUG_RETURN (*str != 0);
@@ -916,7 +974,7 @@ static void init_check_host(void)
DBUG_ENTER("init_check_host");
VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
acl_users.elements,1));
- VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
+ VOID(hash_init(&acl_check_hosts,my_charset_latin1,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,HASH_CASE_INSENSITIVE));
if (!allow_all_hosts)
{
@@ -932,7 +990,7 @@ static void init_check_host(void)
{ // Check if host already exists
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
acl_host_and_ip *);
- if (!my_strcasecmp(system_charset_info,
+ if (!my_strcasecmp(my_charset_latin1,
acl_user->host.hostname, acl->hostname))
break; // already stored
}
@@ -1011,7 +1069,7 @@ bool check_change_password(THD *thd, const char *host, const char *user)
}
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
- my_strcasecmp(system_charset_info, host, thd->host_or_ip)))
+ my_strcasecmp(my_charset_latin1, host, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
return(1);
@@ -1038,7 +1096,7 @@ bool check_change_password(THD *thd, const char *host, const char *user)
RETURN VALUES
0 ok
1 ERROR; In this case the error is sent to the client.
-*/
+*/
bool change_password(THD *thd, const char *host, const char *user,
char *new_password)
@@ -1052,9 +1110,11 @@ 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 or 16 chars; simple hack to avoid cracking */
+ /* password should always be 0,16 or 45 chars; simple hack to avoid cracking */
length=(uint) strlen(new_password);
- new_password[length & 16]=0;
+
+ if (length!=45)
+ new_password[length & 16]=0;
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
@@ -1074,14 +1134,16 @@ bool change_password(THD *thd, const char *host, const char *user,
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));
- char buff[460];
+ char buff[512]; /* Extend with extended password length*/
ulong query_length=
my_sprintf(buff,
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
@@ -1089,7 +1151,7 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
mysql_update_log.write(thd, buff, query_length);
- Query_log_event qinfo(thd, buff, query_length);
+ Query_log_event qinfo(thd, buff, query_length, 0);
mysql_bin_log.write(&qinfo);
DBUG_RETURN(0);
}
@@ -1171,7 +1233,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
return (tmp & host->ip_mask) == host->ip;
}
return (!host->hostname ||
- (hostname && !wild_case_compare(system_charset_info,
+ (hostname && !wild_case_compare(my_charset_latin1,
hostname,host->hostname)) ||
(ip && !wild_compare(ip,host->hostname)));
}
@@ -1195,8 +1257,8 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
tables.db=(char*) "mysql";
if (!(table=open_ltable(thd,&tables,TL_WRITE)))
DBUG_RETURN(1); /* purecov: deadcode */
- table->field[0]->store(host,(uint) strlen(host), system_charset_info);
- table->field[1]->store(user,(uint) strlen(user), system_charset_info);
+ table->field[0]->store(host,(uint) strlen(host), my_charset_latin1);
+ table->field[1]->store(user,(uint) strlen(user), my_charset_latin1);
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,0,
@@ -1206,7 +1268,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
DBUG_RETURN(1); /* purecov: deadcode */
}
store_record(table,1);
- table->field[2]->store(new_password,(uint) strlen(new_password), system_charset_info);
+ table->field[2]->store(new_password,(uint) strlen(new_password), my_charset_latin1);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1264,7 +1326,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (combo.password.str && combo.password.str[0])
{
- if (combo.password.length != HASH_PASSWORD_LENGTH)
+ if ((combo.password.length != HASH_PASSWORD_LENGTH)
+ && combo.password.length != HASH_OLD_PASSWORD_LENGTH)
{
my_error(ER_PASSWORD_NO_MATCH,MYF(0));
DBUG_RETURN(-1);
@@ -1272,8 +1335,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
password=combo.password.str;
}
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
+ 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->file->index_init(0);
if (table->file->index_read(table->record[0],
(byte*) table->field[0]->ptr,0,
@@ -1294,16 +1357,16 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
}
old_row_exists = 0;
restore_record(table,2); // cp empty row from record[2]
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
- table->field[2]->store(password,(uint) strlen(password), system_charset_info);
+ 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);
}
else
{
old_row_exists = 1;
store_record(table,1); // Save copy for update
if (combo.password.str) // If password given
- table->field[2]->store(password,(uint) strlen(password), system_charset_info);
+ table->field[2]->store(password,(uint) strlen(password), my_charset_latin1);
}
/* Update table columns with new privileges */
@@ -1316,7 +1379,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
tmp_field++, priv <<= 1)
{
if (priv & rights) // set requested privileges
- (*tmp_field)->store(&what, 1, system_charset_info);
+ (*tmp_field)->store(&what, 1, my_charset_latin1);
}
rights=get_access(table,3);
DBUG_PRINT("info",("table->fields: %d",table->fields));
@@ -1325,35 +1388,40 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
/* We write down SSL related ACL stuff */
switch (thd->lex.ssl_type) {
case SSL_TYPE_ANY:
- table->field[24]->store("ANY",3, system_charset_info);
- table->field[25]->store("", 0, system_charset_info);
- table->field[26]->store("", 0, system_charset_info);
- table->field[27]->store("", 0, system_charset_info);
+ table->field[24]->store("ANY",3, my_charset_latin1);
+ table->field[25]->store("", 0, my_charset_latin1);
+ table->field[26]->store("", 0, my_charset_latin1);
+ table->field[27]->store("", 0, my_charset_latin1);
break;
case SSL_TYPE_X509:
- table->field[24]->store("X509",4, system_charset_info);
- table->field[25]->store("", 0, system_charset_info);
- table->field[26]->store("", 0, system_charset_info);
- table->field[27]->store("", 0, system_charset_info);
+ table->field[24]->store("X509",4, my_charset_latin1);
+ table->field[25]->store("", 0, my_charset_latin1);
+ table->field[26]->store("", 0, my_charset_latin1);
+ table->field[27]->store("", 0, my_charset_latin1);
break;
case SSL_TYPE_SPECIFIED:
- table->field[24]->store("SPECIFIED",9, system_charset_info);
- table->field[25]->store("", 0, system_charset_info);
- table->field[26]->store("", 0, system_charset_info);
- table->field[27]->store("", 0, system_charset_info);
+ table->field[24]->store("SPECIFIED",9, my_charset_latin1);
+ table->field[25]->store("", 0, my_charset_latin1);
+ table->field[26]->store("", 0, my_charset_latin1);
+ table->field[27]->store("", 0, my_charset_latin1);
if (thd->lex.ssl_cipher)
table->field[25]->store(thd->lex.ssl_cipher,
- strlen(thd->lex.ssl_cipher), system_charset_info);
+ strlen(thd->lex.ssl_cipher), my_charset_latin1);
if (thd->lex.x509_issuer)
table->field[26]->store(thd->lex.x509_issuer,
- strlen(thd->lex.x509_issuer), system_charset_info);
+ strlen(thd->lex.x509_issuer), my_charset_latin1);
if (thd->lex.x509_subject)
table->field[27]->store(thd->lex.x509_subject,
- strlen(thd->lex.x509_subject), system_charset_info);
+ strlen(thd->lex.x509_subject), my_charset_latin1);
break;
case SSL_TYPE_NOT_SPECIFIED:
- case SSL_TYPE_NONE: // Impossible
- break; // Nothing to do
+ break;
+ case SSL_TYPE_NONE:
+ table->field[24]->store("", 0, my_charset_latin1);
+ table->field[25]->store("", 0, my_charset_latin1);
+ table->field[26]->store("", 0, my_charset_latin1);
+ table->field[27]->store("", 0, my_charset_latin1);
+ break;
}
USER_RESOURCES mqh = thd->lex.mqh;
@@ -1441,9 +1509,9 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(-1);
}
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length, my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, my_charset_latin1);
table->file->index_init(0);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
HA_READ_KEY_EXACT))
@@ -1456,9 +1524,9 @@ static int replace_db_table(TABLE *table, const char *db,
}
old_row_exists = 0;
restore_record(table,2); // cp empty row from record[2]
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length, my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, my_charset_latin1);
}
else
{
@@ -1470,7 +1538,7 @@ static int replace_db_table(TABLE *table, const char *db,
for (i= 3, priv= 1; i < table->fields; i++, priv <<= 1)
{
if (priv & store_rights) // do it if priv is chosen
- table->field [i]->store(&what,1, system_charset_info);// set requested privileges
+ table->field [i]->store(&what,1, my_charset_latin1);// set requested privileges
}
rights=get_access(table,3);
rights=fix_rights_for_db(rights);
@@ -1551,13 +1619,13 @@ public:
tname= strdup_root(&memex,t);
if (lower_case_table_names)
{
- my_casedn_str(system_charset_info, db);
- my_casedn_str(system_charset_info, tname);
+ my_casedn_str(my_charset_latin1, db);
+ my_casedn_str(my_charset_latin1, tname);
}
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
- (void) hash_init(&hash_columns,system_charset_info,
+ (void) hash_init(&hash_columns,my_charset_latin1,
0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
}
@@ -1580,8 +1648,8 @@ public:
}
if (lower_case_table_names)
{
- my_casedn_str(system_charset_info, db);
- my_casedn_str(system_charset_info, tname);
+ my_casedn_str(my_charset_latin1, db);
+ my_casedn_str(my_charset_latin1, tname);
}
key_length = ((uint) strlen(db) + (uint) strlen(user) +
(uint) strlen(tname) + 3);
@@ -1592,22 +1660,22 @@ public:
privs = fix_rights_for_table(privs);
cols = fix_rights_for_column(cols);
- (void) hash_init(&hash_columns,system_charset_info,
+ (void) hash_init(&hash_columns,my_charset_latin1,
0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
if (cols)
{
int key_len;
- col_privs->field[0]->store(host,(uint) strlen(host), system_charset_info);
- col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
- col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
- col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info);
+ col_privs->field[0]->store(host,(uint) strlen(host), my_charset_latin1);
+ col_privs->field[1]->store(db,(uint) strlen(db), my_charset_latin1);
+ col_privs->field[2]->store(user,(uint) strlen(user), my_charset_latin1);
+ col_privs->field[3]->store(tname,(uint) strlen(tname), my_charset_latin1);
key_len=(col_privs->field[0]->pack_length()+
col_privs->field[1]->pack_length()+
col_privs->field[2]->pack_length()+
col_privs->field[3]->pack_length());
key_copy(key,col_privs,0,key_len);
- col_privs->field[4]->store("",0, system_charset_info);
+ col_privs->field[4]->store("",0, my_charset_latin1);
col_privs->file->index_init(0);
if (col_privs->file->index_read(col_privs->record[0],
(byte*) col_privs->field[0]->ptr,
@@ -1673,15 +1741,15 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
if (exact)
{
if ((host &&
- !my_strcasecmp(system_charset_info, host, grant_table->host)) ||
+ !my_strcasecmp(my_charset_latin1, host, grant_table->host)) ||
(ip && !strcmp(ip,grant_table->host)))
return grant_table;
}
else
{
- if ((host && !wild_case_compare(system_charset_info,
+ if ((host && !wild_case_compare(my_charset_latin1,
host,grant_table->host)) ||
- (ip && !wild_case_compare(system_charset_info,
+ (ip && !wild_case_compare(my_charset_latin1,
ip,grant_table->host)))
found=grant_table; // Host ok
}
@@ -1709,10 +1777,10 @@ static int replace_column_table(GRANT_TABLE *g_t,
byte key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_column_table");
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
- table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length, my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, my_charset_latin1);
+ table->field[3]->store(table_name,(uint) strlen(table_name), my_charset_latin1);
key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
table->field[2]->pack_length()+ table->field[3]->pack_length());
key_copy(key,table,0,key_length);
@@ -1729,7 +1797,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
ulong privileges = xx->rights;
bool old_row_exists=0;
key_restore(table,key,0,key_length);
- table->field[4]->store(xx->column.ptr(),xx->column.length(),system_charset_info);
+ table->field[4]->store(xx->column.ptr(),xx->column.length(),my_charset_latin1);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
@@ -1745,7 +1813,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
old_row_exists = 0;
restore_record(table,2); // Get empty record
key_restore(table,key,0,key_length);
- table->field[4]->store(xx->column.ptr(),xx->column.length(), system_charset_info);
+ table->field[4]->store(xx->column.ptr(),xx->column.length(), my_charset_latin1);
}
else
{
@@ -1817,7 +1885,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
GRANT_COLUMN *grant_column = NULL;
char colum_name_buf[HOSTNAME_LENGTH+1];
- String column_name(colum_name_buf,sizeof(colum_name_buf),system_charset_info);
+ String column_name(colum_name_buf,sizeof(colum_name_buf),my_charset_latin1);
privileges&= ~rights;
table->field[6]->store((longlong)
@@ -1887,10 +1955,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
restore_record(table,2); // Get empty record
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
- table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length, my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, my_charset_latin1);
+ table->field[3]->store(table_name,(uint) strlen(table_name), my_charset_latin1);
store_record(table,1); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
@@ -1935,7 +2003,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
}
- table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
+ table->field[4]->store(grantor,(uint) strlen(grantor), my_charset_latin1);
table->field[6]->store((longlong) store_table_rights);
table->field[7]->store((longlong) store_col_rights);
rights=fix_rights_for_table(store_table_rights);
@@ -2186,7 +2254,6 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
bool create_new_users=0;
TABLE_LIST tables[2];
DBUG_ENTER("mysql_grant");
-
if (!initialized)
{
send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: tested */
@@ -2196,7 +2263,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
if (lower_case_table_names && db)
{
strmov(tmp_db,db);
- my_casedn_str(system_charset_info, tmp_db);
+ my_casedn_str(my_charset_latin1, tmp_db);
db=tmp_db;
}
@@ -2275,9 +2342,9 @@ void grant_free(void)
/* Init grant array if possible */
-my_bool grant_init(void)
+my_bool grant_init(THD *org_thd)
{
- THD *thd, *org_thd;
+ THD *thd;
TABLE_LIST tables[2];
MYSQL_LOCK *lock;
my_bool return_val= 1;
@@ -2285,7 +2352,7 @@ my_bool grant_init(void)
DBUG_ENTER("grant_init");
grant_option = FALSE;
- (void) hash_init(&hash_tables,system_charset_info,
+ (void) hash_init(&hash_tables,my_charset_latin1,
0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
init_sql_alloc(&memex,1024,0);
@@ -2294,7 +2361,6 @@ my_bool grant_init(void)
if (!initialized)
DBUG_RETURN(0); /* purecov: tested */
- org_thd=current_thd;
if (!(thd=new THD))
DBUG_RETURN(1); /* purecov: deadcode */
thd->store_globals();
@@ -2352,13 +2418,18 @@ end:
delete thd;
if (org_thd)
org_thd->store_globals();
+ else
+ {
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
+ }
DBUG_RETURN(return_val);
}
/* Reload grant array if possible */
-void grant_reload(void)
+void grant_reload(THD *thd)
{
HASH old_hash_tables;bool old_grant_option;
MEM_ROOT old_mem;
@@ -2372,7 +2443,7 @@ void grant_reload(void)
old_grant_option = grant_option;
old_mem = memex;
- if (grant_init())
+ if (grant_init(thd))
{ // Error. Revert to old hash
grant_free(); /* purecov: deadcode */
hash_tables=old_hash_tables; /* purecov: deadcode */
@@ -2610,9 +2681,9 @@ bool check_grant_db(THD *thd,const char *db)
GRANT_TABLE *grant_table = (GRANT_TABLE*) hash_element(&hash_tables,idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
- (thd->host && !wild_case_compare(system_charset_info,
+ (thd->host && !wild_case_compare(my_charset_latin1,
thd->host,grant_table->host) ||
- (thd->ip && !wild_case_compare(system_charset_info,
+ (thd->ip && !wild_case_compare(my_charset_latin1,
thd->ip,grant_table->host))))
{
error=0; // Found match
@@ -2698,7 +2769,7 @@ static uint command_lengths[]=
};
-int mysql_show_grants(THD *thd,LEX_USER *lex_user)
+int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
ulong want_access;
uint counter,index;
@@ -2734,17 +2805,17 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!(host=acl_user->host.hostname))
host="%";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ !my_strcasecmp(my_charset_latin1, lex_user->host.str, host))
break;
}
- if (counter == acl_users.elements)
+ if (counter == acl_users.elements)
{
my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
MYF(0),lex_user->user.str,lex_user->host.str);
DBUG_RETURN(-1);
}
- Item_string *field=new Item_string("",0,system_charset_info);
+ Item_string *field=new Item_string("",0,my_charset_latin1);
List<Item> field_list;
field->name=buff;
field->max_length=1024;
@@ -2762,7 +2833,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
acl_user->ssl_type != SSL_TYPE_NONE)
{
want_access=acl_user->access;
- String global(buff,sizeof(buff),system_charset_info);
+ String global(buff,sizeof(buff),my_charset_latin1);
global.length(0);
global.append("GRANT ",6);
@@ -2770,13 +2841,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append("ALL PRIVILEGES",14);
else if (!(want_access & ~GRANT_ACL))
global.append("USAGE",5);
- else
+ else
{
bool found=0;
ulong j,test_access= want_access & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
{
- if (test_access & j)
+ if (test_access & j)
{
if (found)
global.append(", ",2);
@@ -2786,14 +2857,14 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
global.append (" ON *.* TO '",12);
- global.append(lex_user->user.str,lex_user->user.length);
+ global.append(lex_user->user.str,lex_user->user.length);
global.append ("'@'",3);
global.append(lex_user->host.str,lex_user->host.length);
global.append ('\'');
if (acl_user->password)
{
char passd_buff[HASH_PASSWORD_LENGTH+1];
- make_password_from_salt(passd_buff,acl_user->salt);
+ make_password_from_salt(passd_buff,acl_user->salt,acl_user->pversion);
global.append(" IDENTIFIED BY PASSWORD '",25);
global.append(passd_buff);
global.append('\'');
@@ -2835,9 +2906,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
(acl_user->user_resource.questions | acl_user->user_resource.updates |
acl_user->user_resource.connections))
{
- global.append(" WITH",5);
+ global.append(" WITH",5);
if (want_access & GRANT_ACL)
- global.append(" GRANT OPTION",13);
+ global.append(" GRANT OPTION",13);
if (acl_user->user_resource.questions)
{
char buff[22], *p; // just as in int2str
@@ -2881,12 +2952,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
host="";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ !my_strcasecmp(my_charset_latin1, lex_user->host.str, host))
{
want_access=acl_db->access;
- if (want_access)
+ if (want_access)
{
- String db(buff,sizeof(buff),system_charset_info);
+ String db(buff,sizeof(buff),my_charset_latin1);
db.length(0);
db.append("GRANT ",6);
@@ -2910,10 +2981,10 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
db.append (" ON `",5);
db.append(acl_db->db);
db.append ("`.* TO '",8);
- db.append(lex_user->user.str,lex_user->user.length);
+ db.append(lex_user->user.str,lex_user->user.length);
db.append ("'@'",3);
db.append(lex_user->host.str, lex_user->host.length);
- db.append ('\'');
+ db.append ('\'');
if (want_access & GRANT_ACL)
db.append(" WITH GRANT OPTION",18);
thd->packet.length(0);
@@ -2932,7 +3003,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
for (index=0 ; index < hash_tables.records ; index++)
{
const char *user,*host;
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index);
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index);
if (!(user=grant_table->user))
user="";
@@ -2940,32 +3011,32 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
host="";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+ !my_strcasecmp(my_charset_latin1, lex_user->host.str, host))
{
want_access=grant_table->privs;
if ((want_access | grant_table->cols) != 0)
{
- String global(buff,sizeof(buff),system_charset_info);
+ String global(buff,sizeof(buff),my_charset_latin1);
global.length(0);
global.append("GRANT ",6);
if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14);
- else
+ else
{
int found=0;
ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1)
{
- if (test_access & j)
+ if (test_access & j)
{
if (found)
global.append(", ",2);
found = 1;
global.append(command_array[counter],command_lengths[counter]);
- if (grant_table->cols)
+ if (grant_table->cols)
{
uint found_col=0;
for (uint col_index=0 ;
@@ -2974,9 +3045,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
hash_element(&grant_table->hash_columns,col_index);
- if (grant_column->rights & j)
+ if (grant_column->rights & j)
{
- if (!found_col)
+ if (!found_col)
{
global.append(" (",2);
found_col=1;
@@ -2998,12 +3069,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(".",1);
global.append(grant_table->tname);
global.append(" TO '",5);
- global.append(lex_user->user.str,lex_user->user.length);
+ global.append(lex_user->user.str,lex_user->user.length);
global.append("'@'",3);
- global.append(lex_user->host.str,lex_user->host.length);
+ global.append(lex_user->host.str,lex_user->host.length);
global.append('\'');
if (want_access & GRANT_ACL)
- global.append(" WITH GRANT OPTION",18);
+ global.append(" WITH GRANT OPTION",18);
thd->packet.length(0);
net_store_data(&thd->packet,global.ptr(),global.length());
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 326a55ddd0c..ceb866d809f 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -79,16 +79,66 @@
#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7))
#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7))
+/* Classes */
+
+struct acl_host_and_ip
+{
+ char *hostname;
+ long ip,ip_mask; // Used with masked ip:s
+};
+
+
+class ACL_ACCESS {
+public:
+ ulong sort;
+ ulong access;
+};
+
+
+/* ACL_HOST is used if no host is specified */
+
+class ACL_HOST :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *db;
+};
+
+
+class ACL_USER :public ACL_ACCESS
+{
+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
+ enum SSL_type ssl_type;
+ const char *ssl_cipher, *x509_issuer, *x509_subject;
+};
+
+
+class ACL_DB :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *user,*db;
+};
+
+
+
/* prototypes */
-my_bool acl_init(bool dont_read_acl_tables);
+my_bool acl_init(THD *thd, bool dont_read_acl_tables);
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);
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user,
- bool old_ver, USER_RESOURCES *max);
+ bool old_ver, USER_RESOURCES *max,char* prepared_scramble,
+ uint *cur_priv_version, ACL_USER **cached_user);
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,
@@ -98,9 +148,9 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
List <LEX_COLUMN> &column_list, ulong rights,
bool revoke);
-my_bool grant_init(void);
+my_bool grant_init(THD *thd);
void grant_free(void);
-void grant_reload(void);
+void grant_reload(THD *thd);
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_command=0, bool dont_print_error=0);
bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length,
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index d1ecdd029d5..ecd9f635060 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -89,21 +89,21 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
- net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
pc->max_tree_elements = (uint) (*param->item)->val_int();
param = param->next;
if (param->next) // no third parameter possible
{
- net_printf(thd, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMCOUNT_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
// second parameter
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
- net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
pc->max_treemem = (uint) (*param->item)->val_int();
@@ -111,7 +111,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
else if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
- net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
// if only one parameter was given, it will be the value of max_tree_elements
@@ -593,23 +593,23 @@ bool analyse::end_of_records()
{
func_items[1]->null_value = 0;
res = (*f)->get_min_arg(&s_min);
- func_items[1]->set(res->ptr(), res->length());
+ func_items[1]->set(res->ptr(), res->length(), res->charset());
func_items[2]->null_value = 0;
res = (*f)->get_max_arg(&s_max);
- func_items[2]->set(res->ptr(), res->length());
+ func_items[2]->set(res->ptr(), res->length(), res->charset());
}
func_items[3]->set((longlong) (*f)->min_length);
func_items[4]->set((longlong) (*f)->max_length);
func_items[5]->set((longlong) (*f)->empty);
func_items[6]->set((longlong) (*f)->nulls);
res = (*f)->avg(&s_max, rows);
- func_items[7]->set(res->ptr(), res->length());
+ func_items[7]->set(res->ptr(), res->length(), res->charset());
func_items[8]->null_value = 0;
res = (*f)->std(&s_max, rows);
if (!res)
func_items[8]->null_value = 1;
else
- func_items[8]->set(res->ptr(), res->length());
+ func_items[8]->set(res->ptr(), res->length(), res->charset());
// count the dots, quotas, etc. in (ENUM("a","b","c"...))
// if tree has been removed, don't suggest ENUM.
// treemem is used to measure the size of tree for strings,
@@ -640,7 +640,7 @@ bool analyse::end_of_records()
if (!(*f)->nulls)
tmp_str.append(" NOT NULL");
output_str_length = tmp_str.length();
- func_items[9]->set(tmp_str.ptr(), tmp_str.length());
+ func_items[9]->set(tmp_str.ptr(), tmp_str.length(), tmp_str.charset());
if (result->send_data(result_fields))
return -1;
continue;
@@ -677,7 +677,7 @@ bool analyse::end_of_records()
case FIELD_TYPE_DECIMAL:
ans.append("DECIMAL", 7);
// if item is FIELD_ITEM, it _must_be_ Field_num in this case
- if (((Field_num*) (*f)->item)->zerofill)
+ if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill)
ans.append(" ZEROFILL");
break;
default:
@@ -687,7 +687,7 @@ bool analyse::end_of_records()
}
if (!(*f)->nulls)
ans.append(" NOT NULL");
- func_items[9]->set(ans.ptr(), ans.length());
+ func_items[9]->set(ans.ptr(), ans.length(), ans.charset());
if (result->send_data(result_fields))
return -1;
}
@@ -896,14 +896,14 @@ int collect_real(double *element, element_count count __attribute__((unused)),
TREE_INFO *info)
{
char buff[MAX_FIELD_WIDTH];
- String s(buff, sizeof(buff),default_charset_info);
+ String s(buff, sizeof(buff),current_thd->thd_charset);
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
- s.set(*element, info->item->decimals, my_thd_charset);
+ s.set(*element, info->item->decimals, current_thd->thd_charset);
info->str->append(s);
info->str->append('\'');
return 0;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 77253d49ed0..e2b36106fb0 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -39,8 +39,8 @@ static key_map get_key_map_from_key_list(TABLE *table,
List<String> *index_list);
-static byte *cache_key(const byte *record,uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" byte *table_cache_key(const byte *record,uint *length,
+ my_bool not_used __attribute__((unused)))
{
TABLE *entry=(TABLE*) record;
*length=entry->key_length;
@@ -50,8 +50,8 @@ static byte *cache_key(const byte *record,uint *length,
void table_cache_init(void)
{
VOID(hash_init(&open_cache,system_charset_info,
- table_cache_size+16,0,0,cache_key,
- (void (*)(void*)) free_cache_entry,0));
+ table_cache_size+16,0,0,table_cache_key,
+ (hash_free_key) free_cache_entry,0));
mysql_rm_tmp_tables();
}
@@ -536,14 +536,14 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
if (!found)
if_wait_for_refresh=0; // Nothing to wait for
}
+ if (!tables)
+ kill_delayed_threads();
if (if_wait_for_refresh)
{
/*
If there is any table that has a lower refresh_version, wait until
this is closed (or this thread is killed) before returning
*/
- if (!tables)
- kill_delayed_threads();
thd->mysys_var->current_mutex= &LOCK_open;
thd->mysys_var->current_cond= &COND_refresh;
thd->proc_info="Flushing tables";
@@ -699,26 +699,20 @@ void close_temporary_tables(THD *thd)
{
TABLE *table,*next;
char *query, *end;
- const uint init_query_buf_size = 11; // "drop table "
uint query_buf_size;
bool found_user_tables = 0;
+ if (!thd->temporary_tables)
+ return;
+
LINT_INIT(end);
- query_buf_size = init_query_buf_size;
+ query_buf_size= 50; // Enough for DROP ... TABLE
for (table=thd->temporary_tables ; table ; table=table->next)
- {
query_buf_size += table->key_length;
- }
-
- if (query_buf_size == init_query_buf_size)
- return; // no tables to close
if ((query = alloc_root(&thd->mem_root, query_buf_size)))
- {
- memcpy(query, "drop table ", init_query_buf_size);
- end = query + init_query_buf_size;
- }
+ end=strmov(query, "DROP /*!40005 TEMPORARY */ TABLE ");
for (table=thd->temporary_tables ; table ; table=next)
{
@@ -727,12 +721,14 @@ void close_temporary_tables(THD *thd)
// skip temporary tables not created directly by the user
if (table->real_name[0] != '#')
{
- end = strxmov(end,table->table_cache_key,".",
- table->real_name,",", NullS);
- // here we assume table_cache_key always starts
- // with \0 terminated db name
+ /*
+ Here we assume table_cache_key always starts
+ with \0 terminated db name
+ */
found_user_tables = 1;
}
+ end = strxmov(end,table->table_cache_key,".",
+ table->real_name,",", NullS);
}
next=table->next;
close_temporary(table);
@@ -740,13 +736,61 @@ void close_temporary_tables(THD *thd)
if (query && found_user_tables && mysql_bin_log.is_open())
{
/* The -1 is to remove last ',' */
- Query_log_event qinfo(thd, query, (ulong)(end-query)-1);
+ Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0);
qinfo.error_code=0;
mysql_bin_log.write(&qinfo);
}
thd->temporary_tables=0;
}
+/*
+ Find first suitable table by alias in given list.
+
+ SYNOPSIS
+ find_table_in_list()
+ table - pointer to table list
+ db_name - data base name or 0 for any
+ table_name - table name or 0 for any
+
+ RETURN VALUES
+ NULL Table not found
+ # Pointer to found table.
+*/
+
+TABLE_LIST * find_table_in_list(TABLE_LIST *table,
+ const char *db_name, const char *table_name)
+{
+ for (; table; table= table->next)
+ if ((!db_name || !strcmp(table->db, db_name)) &&
+ (!table_name || !strcmp(table->alias, table_name)))
+ break;
+ return table;
+}
+
+/*
+ Find real table in given list.
+
+ SYNOPSIS
+ find_table_in_list()
+ table - pointer to table list
+ db_name - data base name
+ table_name - table name
+
+ RETURN VALUES
+ NULL Table not found
+ # Pointer to found table.
+*/
+
+TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name)
+{
+ for (; table; table= table->next)
+ if (!strcmp(table->db, db_name) &&
+ !strcmp(table->real_name, table_name))
+ break;
+ return table;
+}
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
{
@@ -1435,7 +1479,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
int error;
DBUG_ENTER("open_unireg_entry");
- (void) sprintf(path,"%s/%s/%s",mysql_data_home,db,name);
+ strxmov(path, mysql_data_home, "/", db, "/", name, NullS);
if (openfrm(path,alias,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY),
@@ -1564,6 +1608,61 @@ int open_tables(THD *thd,TABLE_LIST *start)
}
+/*
+ Check that lock is ok for tables; Call start stmt if ok
+
+ SYNOPSIS
+ check_lock_and_start_stmt()
+ thd Thread handle
+ table_list Table to check
+ lock_type Lock used for table
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
+static bool check_lock_and_start_stmt(THD *thd, TABLE *table,
+ thr_lock_type lock_type)
+{
+ int error;
+ DBUG_ENTER("check_lock_and_start_stmt");
+
+ if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
+ (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
+ {
+ my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
+ ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
+ MYF(0),table->table_name);
+ DBUG_RETURN(1);
+ }
+ if ((error=table->file->start_stmt(thd)))
+ {
+ table->file->print_error(error,MYF(0));
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Open and lock one table
+
+ SYNOPSIS
+ open_ltable()
+ thd Thread handler
+ table_list Table to open is first table in this list
+ lock_type Lock to use for open
+
+ RETURN VALUES
+ table Opened table
+ 0 Error
+
+ If ok, the following are also set:
+ table_list->lock_type lock_type
+ table_list->table table
+*/
+
TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{
TABLE *table;
@@ -1574,10 +1673,9 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
while (!(table=open_table(thd,table_list->db,
table_list->real_name,table_list->alias,
&refresh)) && refresh) ;
+
if (table)
{
- int error;
-
#if defined( __WIN__) || defined(OS2)
/* Win32 can't drop a file that is open */
if (lock_type == TL_WRITE_ALLOW_READ)
@@ -1585,39 +1683,29 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
lock_type= TL_WRITE;
}
#endif /* __WIN__ || OS2 */
-
- table_list->table=table;
+ table_list->lock_type= lock_type;
+ table_list->table= table;
table->grant= table_list->grant;
if (thd->locked_tables)
{
- thd->proc_info=0;
- if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ &&
- (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ)
- {
- my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
- ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
- MYF(0),table_list->alias);
- table=0;
- }
- else if ((error=table->file->start_stmt(thd)))
- {
- table->file->print_error(error,MYF(0));
- table=0;
- }
- thd->proc_info=0;
- DBUG_RETURN(table);
+ if (check_lock_and_start_stmt(thd, table, lock_type))
+ table= 0;
+ }
+ else
+ {
+ if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
+ if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
+ table= 0;
}
- if ((table->reginfo.lock_type=lock_type) != TL_UNLOCK)
- if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
- DBUG_RETURN(0);
}
thd->proc_info=0;
DBUG_RETURN(table);
}
+
/*
-** Open all tables in list and locks them for read.
-** The lock will automaticly be freed by the close_thread_tables
+ Open all tables in list and locks them for read.
+ The lock will automaticly be freed by close_thread_tables()
*/
int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
@@ -1627,10 +1715,27 @@ int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
return 0;
}
+
+/*
+ Lock all tables in list
+
+ SYNOPSIS
+ lock_tables()
+ thd Thread handler
+ tables Tables to lock
+
+ RETURN VALUES
+ 0 ok
+ -1 Error
+*/
+
int lock_tables(THD *thd,TABLE_LIST *tables)
{
TABLE_LIST *table;
- if (tables && !thd->locked_tables)
+ if (!tables)
+ return 0;
+
+ if (!thd->locked_tables)
{
uint count=0;
for (table = tables ; table ; table=table->next)
@@ -1647,10 +1752,9 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
{
for (table = tables ; table ; table=table->next)
{
- int error;
- if ((error=table->table->file->start_stmt(thd)))
+ if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
- table->table->file->print_error(error,MYF(0));
+ ha_rollback_stmt(thd);
return -1;
}
}
@@ -1658,10 +1762,11 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
return 0;
}
+
/*
-** Open a single table without table caching and don't set it in open_list
-** Used by alter_table to open a temporary table and when creating
-** a temporary table with CREATE TEMPORARY ...
+ Open a single table without table caching and don't set it in open_list
+ Used by alter_table to open a temporary table and when creating
+ a temporary table with CREATE TEMPORARY ...
*/
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
@@ -1670,11 +1775,13 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
TABLE *tmp_table;
DBUG_ENTER("open_temporary_table");
- // the extra size in my_malloc() is for table_cache_key
- // 4 bytes for master thread id if we are in the slave
- // 1 byte to terminate db
- // 1 byte to terminate table_name
- // total of 6 extra bytes in my_malloc in addition to table/db stuff
+ /*
+ The extra size in my_malloc() is for table_cache_key
+ 4 bytes for master thread id if we are in the slave
+ 1 byte to terminate db
+ 1 byte to terminate table_name
+ total of 6 extra bytes in my_malloc in addition to table/db stuff
+ */
if (!(tmp_table=(TABLE*) my_malloc(sizeof(*tmp_table)+(uint) strlen(db)+
(uint) strlen(table_name)+6,
MYF(MY_WME))))
@@ -1748,7 +1855,9 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
}
else
{
- Field **ptr=table->field;
+ Field **ptr;
+ if (!(ptr=table->field))
+ return (Field *)0;
while ((field = *ptr++))
{
if (!my_strcasecmp(system_charset_info, field->field_name, name))
@@ -1801,7 +1910,7 @@ const Field *not_found_field= (Field*) 0x1;
*/
Field *
-find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
+find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
bool report_error)
{
Field *found=0;
@@ -1810,13 +1919,13 @@ find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
const char *name=item->field_name;
uint length=(uint) strlen(name);
- if (table_name)
+ if (table_name && table_name[0])
{ /* Qualified field */
bool found_table=0;
for (; tables ; tables=tables->next)
{
if (!strcmp(tables->alias,table_name) &&
- (!db || !strcmp(db,tables->db)))
+ (!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db)))
{
found_table=1;
Field *find=find_field_in_table(thd,tables->table,name,length,
@@ -1848,8 +1957,14 @@ find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
table_name=buff;
}
if (report_error)
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- table_name, thd->where);
+ {
+ if (thd->lex.current_select->get_master()->order_list.elements)
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, ER(ER_TABLENAME_NOT_ALLOWED_HERE),
+ MYF(0), table_name, thd->where);
+ else
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ table_name, thd->where);
+ }
else
return (Field*) not_found_field;
}
@@ -1998,12 +2113,12 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
while ((item=it++))
{
- if (item->type() == Item::FIELD_ITEM &&
+ if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*')
{
- uint elem=fields.elements;
+ uint elem= fields.elements;
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
- ((Item_field*) item)->table_name,&it))
+ ((Item_field*) item)->table_name, &it))
DBUG_RETURN(-1); /* purecov: inspected */
if (sum_func_list)
{
@@ -2017,15 +2132,17 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
else
{
- if (item->fix_fields(thd, tables, it.ref()))
+ if (item->check_cols(1) ||
+ item->fix_fields(thd, tables, it.ref()))
DBUG_RETURN(-1); /* purecov: inspected */
+ item= *(it.ref()); //Item can be chenged in fix fields
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
sum_func_list)
item->split_sum_func(*sum_func_list);
thd->used_tables|=item->used_tables();
}
}
- DBUG_RETURN(test(thd->fatal_error));
+ DBUG_RETURN(test(thd->fatal_error || thd->net.report_error));
}
@@ -2069,6 +2186,7 @@ bool setup_tables(TABLE_LIST *tables)
DBUG_RETURN(1);
table->keys_in_use_for_query &= ~map;
}
+ table->used_keys &= table->keys_in_use_for_query;
if (table_list->shared)
{
/* Clear query_id that may have been set by previous select */
@@ -2106,8 +2224,8 @@ static key_map get_key_map_from_key_list(TABLE *table,
}
/****************************************************************************
-** This just drops in all fields instead of current '*' field
-** Returns pointer to last inserted field if ok
+ This just drops in all fields instead of current '*' field
+ Returns pointer to last inserted field if ok
****************************************************************************/
bool
@@ -2121,21 +2239,26 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
for (; tables ; tables=tables->next)
{
TABLE *table=tables->table;
- if (grant_option && !thd->master_access &&
- check_grant_all_columns(thd,SELECT_ACL,table) )
- DBUG_RETURN(-1);
if (!table_name || (!strcmp(table_name,tables->alias) &&
(!db_name || !strcmp(tables->db,db_name))))
{
+ /* Ensure that we have access right to all columns */
+ if (grant_option && !thd->master_access &&
+ check_grant_all_columns(thd,SELECT_ACL,table) )
+ DBUG_RETURN(-1);
Field **ptr=table->field,*field;
thd->used_tables|=table->map;
while ((field = *ptr++))
{
Item_field *item= new Item_field(field);
if (!found++)
- (void) it->replace(item);
+ (void) it->replace(item); // Replace '*'
else
it->after(item);
+ /*
+ Mark if field used before in this select.
+ Used by 'insert' to verify if a field name is used twice
+ */
if (field->query_id == thd->query_id)
thd->dupp_field=field;
field->query_id=thd->query_id;
@@ -2164,12 +2287,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
- thd->cond_count=0;
- thd->allow_sum_func=0;
+
+ thd->cond_count= 0;
if (*conds)
{
thd->where="where clause";
- if ((*conds)->fix_fields(thd, tables, conds))
+ if ((*conds)->check_cols(1) || (*conds)->fix_fields(thd, tables, conds))
DBUG_RETURN(1);
}
@@ -2180,7 +2303,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
/* Make a join an a expression */
thd->where="on clause";
- if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
+ if (table->on_expr->check_cols(1) ||
+ table->on_expr->fix_fields(thd, tables, &table->on_expr))
DBUG_RETURN(1);
thd->cond_count++;
@@ -2200,6 +2324,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
Item_cond_and *cond_and=new Item_cond_and();
if (!cond_and) // If not out of memory
DBUG_RETURN(1);
+ cond_and->top_level_item();
uint i,j;
for (i=0 ; i < t1->fields ; i++)
@@ -2237,7 +2362,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
table->on_expr=and_conds(table->on_expr,cond_and);
}
}
- DBUG_RETURN(test(thd->fatal_error));
+ DBUG_RETURN(test(thd->fatal_error || thd->net.report_error));
}
@@ -2257,7 +2382,7 @@ fill_record(List<Item> &fields,List<Item> &values)
while ((field=(Item_field*) f++))
{
value=v++;
- if (value->save_in_field(field->field) > 0)
+ if (value->save_in_field(field->field, 0) > 0)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2275,7 +2400,7 @@ fill_record(Field **ptr,List<Item> &values)
while ((field = *ptr++))
{
value=v++;
- if (value->save_in_field(field) == 1)
+ if (value->save_in_field(field, 0) == 1)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 5b3582c12da..8bc74942bc0 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -289,7 +289,7 @@ TODO list:
if (thd->temp_tables || global_merge_table_count)
- - Another option would be to set thd->safe_to_cache_query to 0
+ - Another option would be to set thd->lex.safe_to_cache_query to 0
in 'get_lock_data' if any of the tables was a tmp table or a
MRG_ISAM table.
(This could be done with almost no speed penalty)
@@ -473,33 +473,6 @@ byte *query_cache_table_get_key(const byte *record, uint *length,
Query_cache_query methods
*****************************************************************************/
-void Query_cache_query::init_n_lock()
-{
- DBUG_ENTER("Query_cache_query::init_n_lock");
- res=0; wri = 0; len = 0;
- my_rwlock_init(&lock, NULL);
- lock_writing();
- DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
- ((byte*) this)-ALIGN_SIZE(sizeof(Query_cache_block))));
- DBUG_VOID_RETURN;
-}
-
-
-void Query_cache_query::unlock_n_destroy()
-{
- DBUG_ENTER("Query_cache_query::unlock_n_destroy");
- DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
- ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block))));
- /*
- The following call is not needed on system where one can destroy an
- active semaphore
- */
- this->unlock_writing();
- rwlock_destroy(&lock);
- DBUG_VOID_RETURN;
-}
-
-
/*
Following methods work for block read/write locking only in this
particular case and in interaction with structure_guard_mutex.
@@ -551,6 +524,34 @@ inline void Query_cache_query::unlock_reading()
RW_UNLOCK(&lock);
}
+
+void Query_cache_query::init_n_lock()
+{
+ DBUG_ENTER("Query_cache_query::init_n_lock");
+ res=0; wri = 0; len = 0;
+ my_rwlock_init(&lock, NULL);
+ lock_writing();
+ DBUG_PRINT("qcache", ("inited & locked query for block 0x%lx",
+ ((byte*) this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ DBUG_VOID_RETURN;
+}
+
+
+void Query_cache_query::unlock_n_destroy()
+{
+ DBUG_ENTER("Query_cache_query::unlock_n_destroy");
+ DBUG_PRINT("qcache", ("destroyed & unlocked query for block 0x%lx",
+ ((byte*)this)-ALIGN_SIZE(sizeof(Query_cache_block))));
+ /*
+ The following call is not needed on system where one can destroy an
+ active semaphore
+ */
+ this->unlock_writing();
+ rwlock_destroy(&lock);
+ DBUG_VOID_RETURN;
+}
+
+
extern "C"
{
byte *query_cache_query_get_key(const byte *record, uint *length,
@@ -714,19 +715,19 @@ void query_cache_invalidate_by_MyISAM_filename(const char *filename)
Query_cache methods
*****************************************************************************/
-Query_cache::Query_cache(ulong query_cache_limit,
- ulong min_allocation_unit,
- ulong min_result_data_size,
- uint def_query_hash_size ,
- uint def_table_hash_size)
+Query_cache::Query_cache(ulong query_cache_limit_arg,
+ ulong min_allocation_unit_arg,
+ ulong min_result_data_size_arg,
+ uint def_query_hash_size_arg,
+ uint def_table_hash_size_arg)
:query_cache_size(0),
- query_cache_limit(query_cache_limit),
+ query_cache_limit(query_cache_limit_arg),
queries_in_cache(0), hits(0), inserts(0), refused(0),
- total_blocks(0),
- min_allocation_unit(ALIGN_SIZE(min_allocation_unit)),
- min_result_data_size(ALIGN_SIZE(min_result_data_size)),
- def_query_hash_size(ALIGN_SIZE(def_query_hash_size)),
- def_table_hash_size(ALIGN_SIZE(def_table_hash_size)),
+ total_blocks(0), lowmem_prunes(0),
+ min_allocation_unit(ALIGN_SIZE(min_allocation_unit_arg)),
+ min_result_data_size(ALIGN_SIZE(min_result_data_size_arg)),
+ def_query_hash_size(ALIGN_SIZE(def_query_hash_size_arg)),
+ def_table_hash_size(ALIGN_SIZE(def_table_hash_size_arg)),
initialized(0)
{
ulong min_needed= (ALIGN_SIZE(sizeof(Query_cache_block)) +
@@ -751,14 +752,13 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
{
- TABLE_COUNTER_TYPE tables;
+ TABLE_COUNTER_TYPE local_tables;
ulong tot_length;
DBUG_ENTER("Query_cache::store_query");
if (query_cache_size == 0)
DBUG_VOID_RETURN;
- uint8 tables_type= 0;
- if ((tables = is_cacheable(thd, thd->query_length,
+ if ((local_tables = is_cacheable(thd, thd->query_length,
thd->query, &thd->lex, tables_used,
&tables_type)))
{
@@ -805,7 +805,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
Query_cache_block *query_block;
query_block= write_block_data(tot_length, (gptr) thd->query,
ALIGN_SIZE(sizeof(Query_cache_query)),
- Query_cache_block::QUERY, tables, 1);
+ Query_cache_block::QUERY, local_tables, 1);
if (query_block != 0)
{
DBUG_PRINT("qcache", ("query block 0x%lx allocated, %lu",
@@ -822,7 +822,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
STRUCT_UNLOCK(&structure_guard_mutex);
goto end;
}
- if (!register_all_tables(query_block, tables_used, tables))
+ if (!register_all_tables(query_block, tables_used, local_tables))
{
refused++;
DBUG_PRINT("warning", ("tables list including failed"));
@@ -897,7 +897,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/* Check that we haven't forgot to reset the query cache variables */
DBUG_ASSERT(thd->net.query_cache_query == 0);
- if (!thd->safe_to_cache_query)
+ if (!thd->lex.safe_to_cache_query)
{
DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
goto err;
@@ -992,7 +992,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
table_list.db, table_list.alias));
refused++; // This is actually a hit
STRUCT_UNLOCK(&structure_guard_mutex);
- thd->safe_to_cache_query=0; // Don't try to cache this
+ thd->lex.safe_to_cache_query=0; // Don't try to cache this
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(-1); // Privilege error
}
@@ -1001,7 +1001,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
- thd->safe_to_cache_query=0; // Don't try to cache this
+ thd->lex.safe_to_cache_query=0; // Don't try to cache this
goto err_unlock; // Parse query
}
if (check_tables && !handler::caching_allowed(thd, table->db(),
@@ -1541,6 +1541,7 @@ my_bool Query_cache::free_old_query()
if (query_block != 0)
{
free_query(query_block);
+ lowmem_prunes++;
DBUG_RETURN(0);
}
}
@@ -1810,7 +1811,7 @@ inline ulong Query_cache::get_min_append_result_data_size()
my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
ulong data_len,
Query_cache_block *query_block,
- my_bool first_block)
+ my_bool first_block_arg)
{
ulong all_headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
ALIGN_SIZE(sizeof(Query_cache_result)));
@@ -1820,7 +1821,7 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
DBUG_PRINT("qcache", ("data_len %lu, all_headers_len %lu",
data_len, all_headers_len));
- ulong min_size = (first_block ?
+ ulong min_size = (first_block_arg ?
get_min_first_result_data_size():
get_min_append_result_data_size());
*result_block = allocate_block(max(min_size, align_len),
@@ -1847,7 +1848,7 @@ my_bool Query_cache::allocate_data_chain(Query_cache_block **result_block,
Query_cache_block *next_block;
if ((success = allocate_data_chain(&next_block,
len - new_block->length,
- query_block, first_block)))
+ query_block, first_block_arg)))
double_linked_list_join(new_block, next_block);
}
if (success)
@@ -1916,14 +1917,23 @@ void Query_cache::invalidate_table(Query_cache_block *table_block)
}
}
+/*
+ Store all used tables
+
+ SYNOPSIS
+ register_all_tables()
+ block Store tables in this block
+ tables_used List if used tables
+ tables_arg Not used ?
+*/
my_bool Query_cache::register_all_tables(Query_cache_block *block,
TABLE_LIST *tables_used,
- TABLE_COUNTER_TYPE tables)
+ TABLE_COUNTER_TYPE tables_arg)
{
TABLE_COUNTER_TYPE n;
DBUG_PRINT("qcache", ("register tables block 0x%lx, n %d, header %x",
- (ulong) block, (int) tables,
+ (ulong) block, (int) tables_arg,
(int) ALIGN_SIZE(sizeof(Query_cache_block))));
Query_cache_block_table *block_table = block->table(0);
@@ -2219,28 +2229,28 @@ void Query_cache::split_block(Query_cache_block *block, ulong len)
Query_cache_block *
-Query_cache::join_free_blocks(Query_cache_block *first_block,
+Query_cache::join_free_blocks(Query_cache_block *first_block_arg,
Query_cache_block *block_in_list)
{
Query_cache_block *second_block;
DBUG_ENTER("Query_cache::join_free_blocks");
DBUG_PRINT("qcache",
("join first 0x%lx, pnext 0x%lx, in list 0x%lx",
- (ulong) first_block, (ulong) first_block->pnext,
+ (ulong) first_block_arg, (ulong) first_block_arg->pnext,
(ulong) block_in_list));
exclude_from_free_memory_list(block_in_list);
- second_block = first_block->pnext;
+ second_block = first_block_arg->pnext;
// May be was not free block
second_block->used=0;
second_block->destroy();
total_blocks--;
- first_block->length += second_block->length;
- first_block->pnext = second_block->pnext;
- second_block->pnext->pprev = first_block;
+ first_block_arg->length += second_block->length;
+ first_block_arg->pnext = second_block->pnext;
+ second_block->pnext->pprev = first_block_arg;
- DBUG_RETURN(first_block);
+ DBUG_RETURN(first_block_arg);
}
@@ -2459,14 +2469,14 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
TABLE_LIST *tables_used,
uint8 *tables_type)
{
- TABLE_COUNTER_TYPE tables = 0;
+ TABLE_COUNTER_TYPE table_count = 0;
DBUG_ENTER("Query_cache::is_cacheable");
if (lex->sql_command == SQLCOM_SELECT &&
(thd->variables.query_cache_type == 1 ||
(thd->variables.query_cache_type == 2 && (lex->select_lex.options &
OPTION_TO_QUERY_CACHE))) &&
- thd->safe_to_cache_query)
+ lex->safe_to_cache_query)
{
DBUG_PRINT("qcache", ("options %lx %lx, type %u",
OPTION_TO_QUERY_CACHE,
@@ -2475,7 +2485,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
for (; tables_used; tables_used= tables_used->next)
{
- tables++;
+ table_count++;
DBUG_PRINT("qcache", ("table %s, db %s, type %u",
tables_used->real_name,
tables_used->db, tables_used->table->db_type));
@@ -2498,7 +2508,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
{
ha_myisammrg *handler = (ha_myisammrg *)tables_used->table->file;
MYRG_INFO *file = handler->myrg_info();
- tables+= (file->end_table - file->open_tables);
+ table_count+= (file->end_table - file->open_tables);
}
}
@@ -2508,8 +2518,8 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
DBUG_PRINT("qcache", ("not in autocommin mode"));
DBUG_RETURN(0);
}
- DBUG_PRINT("qcache", ("select is using %d tables", tables));
- DBUG_RETURN(tables);
+ DBUG_PRINT("qcache", ("select is using %d tables", table_count));
+ DBUG_RETURN(table_count);
}
DBUG_PRINT("qcache",
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 7726fc3aef1..9cf8977ee79 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -187,7 +187,7 @@ extern "C"
my_bool not_used);
}
void query_cache_insert(NET *thd, const char *packet, ulong length);
-void query_cache_invalidate_by_MyISAM_filename(const char* filename);
+extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
struct Query_cache_memory_bin
@@ -228,7 +228,7 @@ public:
ulong query_cache_size, query_cache_limit;
/* statistics */
ulong free_memory, queries_in_cache, hits, inserts, refused,
- free_memory_blocks, total_blocks;
+ free_memory_blocks, total_blocks, lowmem_prunes;
protected:
/*
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 887ee262777..ebd1d9d2b3c 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -37,7 +37,6 @@
#include <mysys_err.h>
#include <assert.h>
-extern struct rand_struct sql_rand;
/*****************************************************************************
** Instansiate templates
@@ -59,14 +58,14 @@ template class List_iterator<Alter_column>;
** User variables
****************************************************************************/
-static byte* get_var_key(user_var_entry *entry, uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" byte *get_var_key(user_var_entry *entry, uint *length,
+ my_bool not_used __attribute__((unused)))
{
*length=(uint) entry->name.length;
return (byte*) entry->name.str;
}
-static void free_var(user_var_entry *entry)
+extern "C" void free_user_var(user_var_entry *entry)
{
char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry));
if (entry->value && entry->value != pos)
@@ -87,10 +86,7 @@ THD::THD():user_time(0), fatal_error(0),
host=user=priv_user=db=query=ip=0;
host_or_ip="unknown ip";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
- query_start_used=safe_to_cache_query=prepare_command=0;
- pthread_mutex_lock(&LOCK_global_system_variables);
- variables= global_system_variables;
- pthread_mutex_unlock(&LOCK_global_system_variables);
+ query_start_used=prepare_command=0;
db_length=query_length=col_access=0;
query_error=0;
next_insert_id=last_insert_id=0;
@@ -107,6 +103,7 @@ THD::THD():user_time(0), fatal_error(0),
slave_proxy_id = 0;
file_id = 0;
cond_count=0;
+ warn_id= 0;
db_charset=default_charset_info;
thd_charset=default_charset_info;
mysys_var=0;
@@ -132,31 +129,22 @@ THD::THD():user_time(0), fatal_error(0),
server_id = ::server_id;
slave_net = 0;
log_pos = 0;
- server_status= SERVER_STATUS_AUTOCOMMIT;
- update_lock_default= (variables.low_priority_updates ?
- TL_WRITE_LOW_PRIORITY :
- TL_WRITE);
- options= thd_startup_options;
- sql_mode=(uint) opt_sql_mode;
- open_options=ha_open_options;
- session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
command=COM_CONNECT;
set_query_id=1;
db_access=NO_ACCESS;
version=refresh_version; // For boot
+ init();
/* Initialize sub structures */
bzero((char*) &mem_root,sizeof(mem_root));
bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
bzero((char*) &con_root,sizeof(con_root));
bzero((char*) &warn_root,sizeof(warn_root));
init_alloc_root(&warn_root, 1024, 0);
- bzero((char*) warn_count, sizeof(warn_count));
- warn_list.empty();
user_connect=(USER_CONN *)0;
hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
- (void (*)(void*)) free_var,0);
+ (hash_free_key) free_user_var,0);
/* Prepared statements */
last_prepared_stmt= 0;
@@ -183,18 +171,63 @@ THD::THD():user_time(0), fatal_error(0),
{
pthread_mutex_lock(&LOCK_thread_count);
ulong tmp=(ulong) (rnd(&sql_rand) * 3000000);
- randominit(&rand, tmp + (ulong) start_time,
- tmp + (ulong) thread_id);
pthread_mutex_unlock(&LOCK_thread_count);
+ randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id);
}
}
+
+/*
+ Init common variables that has to be reset on start and on change_user
+*/
+
+void THD::init(void)
+{
+ pthread_mutex_lock(&LOCK_global_system_variables);
+ variables= global_system_variables;
+ pthread_mutex_unlock(&LOCK_global_system_variables);
+ server_status= SERVER_STATUS_AUTOCOMMIT;
+ options= thd_startup_options;
+ sql_mode=(uint) opt_sql_mode;
+ open_options=ha_open_options;
+ update_lock_default= (variables.low_priority_updates ?
+ TL_WRITE_LOW_PRIORITY :
+ TL_WRITE);
+ session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
+ warn_list.empty();
+ bzero((char*) warn_count, sizeof(warn_count));
+ total_warn_count= 0;
+}
+
+/*
+ Do what's needed when one invokes change user
+
+ SYNOPSIS
+ change_user()
+
+ IMPLEMENTATION
+ Reset all resources that are connection specific
+*/
+
+
+void THD::change_user(void)
+{
+ cleanup();
+ cleanup_done= 0;
+ init();
+ hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
+ (hash_get_key) get_var_key,
+ (hash_free_key) free_user_var, 0);
+}
+
+
/* Do operations that may take a long time */
void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
ha_rollback(this);
+ delete_tree(&prepared_statements);
if (locked_tables)
{
lock=locked_tables; locked_tables=0;
@@ -206,17 +239,21 @@ void THD::cleanup(void)
close_thread_tables(this);
}
close_temporary_tables(this);
-#ifdef USING_TRANSACTIONS
- if (opt_using_transactions)
+ hash_free(&user_vars);
+ if (global_read_lock)
+ unlock_global_read_lock(this);
+ if (ull)
{
- close_cached_file(&transaction.trans_log);
- ha_close_connection(this);
+ pthread_mutex_lock(&LOCK_user_locks);
+ item_user_lock_release(ull);
+ pthread_mutex_unlock(&LOCK_user_locks);
+ ull= 0;
}
-#endif
cleanup_done=1;
DBUG_VOID_RETURN;
}
+
THD::~THD()
{
THD_CHECK_SENTRY(this);
@@ -233,15 +270,13 @@ THD::~THD()
}
if (!cleanup_done)
cleanup();
- if (global_read_lock)
- unlock_global_read_lock(this);
- if (ull)
+#ifdef USING_TRANSACTIONS
+ if (opt_using_transactions)
{
- pthread_mutex_lock(&LOCK_user_locks);
- item_user_lock_release(ull);
- pthread_mutex_unlock(&LOCK_user_locks);
+ close_cached_file(&transaction.trans_log);
+ ha_close_connection(this);
}
- hash_free(&user_vars);
+#endif
DBUG_PRINT("info", ("freeing host"));
if (host != localhost) // If not pointer to constant
@@ -254,7 +289,6 @@ THD::~THD()
free_root(&con_root,MYF(0));
free_root(&warn_root,MYF(0));
free_root(&transaction.mem_root,MYF(0));
- delete_tree(&prepared_statements);
mysys_var=0; // Safety (shouldn't be needed)
pthread_mutex_destroy(&LOCK_delete);
#ifndef DBUG_OFF
@@ -337,20 +371,21 @@ void THD::add_changed_table(TABLE *table)
DBUG_VOID_RETURN;
}
+
void THD::add_changed_table(const char *key, long key_length)
{
DBUG_ENTER("THD::add_changed_table(key)");
- CHANGED_TABLE_LIST** prev = &transaction.changed_tables;
- CHANGED_TABLE_LIST* curr = transaction.changed_tables;
+ CHANGED_TABLE_LIST **prev_changed = &transaction.changed_tables;
+ CHANGED_TABLE_LIST *curr = transaction.changed_tables;
- for (; curr; prev = &(curr->next), curr = curr->next)
+ for (; curr; prev_changed = &(curr->next), curr = curr->next)
{
int cmp = (long)curr->key_length - (long)key_length;
if (cmp < 0)
{
- list_include(prev, curr, changed_table_dup(key, key_length));
+ list_include(prev_changed, curr, changed_table_dup(key, key_length));
DBUG_PRINT("info",
- ("key_length %u %u", key_length, (*prev)->key_length));
+ ("key_length %u %u", key_length, (*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
else if (cmp == 0)
@@ -358,10 +393,10 @@ void THD::add_changed_table(const char *key, long key_length)
cmp = memcmp(curr->key, key, curr->key_length);
if (cmp < 0)
{
- list_include(prev, curr, changed_table_dup(key, key_length));
+ list_include(prev_changed, curr, changed_table_dup(key, key_length));
DBUG_PRINT("info",
("key_length %u %u", key_length,
- (*prev)->key_length));
+ (*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
else if (cmp == 0)
@@ -371,9 +406,9 @@ void THD::add_changed_table(const char *key, long key_length)
}
}
}
- *prev = changed_table_dup(key, key_length);
+ *prev_changed = changed_table_dup(key, key_length);
DBUG_PRINT("info", ("key_length %u %u", key_length,
- (*prev)->key_length));
+ (*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
@@ -434,6 +469,15 @@ void THD::close_active_vio()
}
#endif
+void THD::add_possible_loop (Item *item)
+{
+ if (!possible_loops)
+ {
+ possible_loops= new List<Item>;
+ }
+ possible_loops->push_back(item);
+}
+
/*****************************************************************************
** Functions to provide a interface to select results
*****************************************************************************/
@@ -872,9 +916,9 @@ bool select_singleval_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_singleval_subselect::send_data");
Item_singleval_subselect *it= (Item_singleval_subselect *)item;
- if (it->assigned()){
- thd->fatal_error= 1;
- my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
+ if (it->assigned())
+ {
+ my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
DBUG_RETURN(1);
}
if (unit->offset_limit_cnt)
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 71f1625309f..ca56d2dcdf5 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -29,12 +29,12 @@ class Slave_log_event;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
-enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE };
+enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE, DUP_UPDATE };
enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL };
-// log info errors
+// log info errors
#define LOG_INFO_EOF -1
#define LOG_INFO_IO -2
#define LOG_INFO_INVALID -3
@@ -188,6 +188,9 @@ typedef struct st_copy_info {
ha_rows error_count;
enum enum_duplicates handle_duplicates;
int escape_char, last_errno;
+/* for INSERT ... UPDATE */
+ List<Item> *update_fields;
+ List<Item> *update_values;
} COPY_INFO;
@@ -318,7 +321,7 @@ public:
typedef struct st_prep_stmt
{
THD *thd;
- Item_param *param;
+ Item_param **param;
Item *free_list;
MEM_ROOT mem_root;
ulong stmt_id;
@@ -341,13 +344,14 @@ struct system_variables
{
ulonglong myisam_max_extra_sort_file_size;
ulonglong myisam_max_sort_file_size;
+ ulonglong select_limit;
+ ulonglong max_join_size;
ulong bulk_insert_buff_size;
ulong join_buff_size;
ulong long_query_time;
ulong max_allowed_packet;
ulong max_error_count;
ulong max_heap_table_size;
- ulong max_join_size;
ulong max_prep_stmt_count;
ulong max_sort_length;
ulong max_tmp_tables;
@@ -361,7 +365,6 @@ struct system_variables
ulong query_cache_type;
ulong read_buff_size;
ulong read_rnd_buff_size;
- ulong select_limit;
ulong sortbuff_size;
ulong table_type;
ulong tmp_table_size;
@@ -482,11 +485,13 @@ public:
USER_CONN *user_connect;
CHARSET_INFO *db_charset;
CHARSET_INFO *thd_charset;
+ List<Item> *possible_loops; // Items that may cause loops in subselects
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count, old_total_warn_count;
- ulong query_id, version, options, thread_id, col_access;
+ ulong query_id, warn_id, version, options, thread_id, col_access;
ulong current_stmt_id;
+ ulong rand_saved_seed1, rand_saved_seed2;
long dbug_thread_id;
pthread_t real_id;
uint current_tablenr,tmp_table,cond_count;
@@ -494,21 +499,22 @@ public:
uint32 query_length;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
+ uint check_loops_counter; //last id used to check loops
/* variables.transaction_isolation is reset to this after each commit */
enum_tx_isolation session_tx_isolation;
- char scramble[9];
+ // 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
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
bool no_errors, allow_sum_func, password, fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
- ulonglong rand_saved_seed1, rand_saved_seed2;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
- bool safe_to_cache_query;
bool volatile killed;
bool prepare_command;
- Item_param *params; // Pointer to array of params
/*
If we do a purge of binary logs, log index info of the threads
@@ -532,6 +538,8 @@ public:
THD();
~THD();
+ void init(void);
+ void change_user(void);
void cleanup(void);
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -631,6 +639,7 @@ public:
net.last_errno= 0;
net.report_error= 0;
}
+ void add_possible_loop(Item *);
};
/*
@@ -673,7 +682,7 @@ public:
}
virtual bool send_fields(List<Item> &list,uint flag)=0;
virtual bool send_data(List<Item> &items)=0;
- virtual void initialize_tables (JOIN *join=0) {}
+ virtual bool initialize_tables (JOIN *join=0) { return 0; }
virtual void send_error(uint errcode,const char *err)
{
my_message(errcode, err, MYF(0));
@@ -737,10 +746,10 @@ class select_insert :public select_result {
List<Item> *fields;
ulonglong last_insert_id;
COPY_INFO info;
- uint save_time_stamp;
select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic)
- :table(table_par),fields(fields_par), last_insert_id(0), save_time_stamp(0) {
+ :table(table_par),fields(fields_par), last_insert_id(0)
+ {
bzero((char*) &info,sizeof(info));
info.handle_duplicates=duplic;
}
@@ -784,8 +793,8 @@ class select_union :public select_result {
public:
TABLE *table;
COPY_INFO info;
- uint save_time_stamp;
TMP_TABLE_PARAM *tmp_table_param;
+ bool not_describe;
select_union(TABLE *table_par);
~select_union();
@@ -917,61 +926,61 @@ public:
friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique);
};
- class multi_delete : public select_result {
- TABLE_LIST *delete_tables, *table_being_deleted;
+class multi_delete : public select_result
+{
+ TABLE_LIST *delete_tables, *table_being_deleted;
#ifdef SINISAS_STRIP
- IO_CACHE **tempfiles;
- byte *memory_lane;
+ IO_CACHE **tempfiles;
+ byte *memory_lane;
#else
- Unique **tempfiles;
+ Unique **tempfiles;
#endif
- THD *thd;
- ha_rows deleted;
- uint num_of_tables;
- int error;
- thr_lock_type lock_option;
- bool do_delete, not_trans_safe;
- public:
- multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
- uint num_of_tables);
- ~multi_delete();
- int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- bool send_fields(List<Item> &list,
- uint flag) { return 0; }
- bool send_data(List<Item> &items);
- void initialize_tables (JOIN *join);
- void send_error(uint errcode,const char *err);
- int do_deletes (bool from_send_error);
- bool send_eof();
- };
-
- class multi_update : public select_result {
- TABLE_LIST *update_tables, *table_being_updated;
- COPY_INFO *infos;
- TABLE **tmp_tables;
- THD *thd;
- ha_rows updated, found;
- List<Item> fields;
- List <Item> **fields_by_tables;
- thr_lock_type lock_option;
- enum enum_duplicates dupl;
- uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
- int error;
- bool do_update, not_trans_safe;
- public:
- multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
- enum enum_duplicates handle_duplicates,
- thr_lock_type lock_option_arg, uint num);
- ~multi_update();
- int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- bool send_fields(List<Item> &list,
+ THD *thd;
+ ha_rows deleted;
+ uint num_of_tables;
+ int error;
+ bool do_delete, transactional_tables, log_delayed, normal_tables;
+public:
+ multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
+ ~multi_delete();
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+ bool send_fields(List<Item> &list,
uint flag) { return 0; }
- bool send_data(List<Item> &items);
- void initialize_tables (JOIN *join);
- void send_error(uint errcode,const char *err);
- int do_updates (bool from_send_error);
- bool send_eof();
- };
+ bool send_data(List<Item> &items);
+ bool initialize_tables (JOIN *join);
+ void send_error(uint errcode,const char *err);
+ int do_deletes (bool from_send_error);
+ bool send_eof();
+};
+
+
+class multi_update : public select_result
+{
+ TABLE_LIST *all_tables, *update_tables, *table_being_updated;
+ THD *thd;
+ TABLE **tmp_tables, *main_table;
+ TMP_TABLE_PARAM *tmp_table_param;
+ ha_rows updated, found;
+ List <Item> *fields, *values;
+ List <Item> **fields_for_table, **values_for_table;
+ uint table_count;
+ Copy_field *copy_field;
+ enum enum_duplicates handle_duplicates;
+ bool do_update, trans_safe, transactional_tables, log_delayed;
+
+public:
+ multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields,
+ List<Item> *values, enum_duplicates handle_duplicates);
+ ~multi_update();
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+ bool send_fields(List<Item> &list, uint flag) { return 0; }
+ bool send_data(List<Item> &items);
+ bool initialize_tables (JOIN *join);
+ void send_error(uint errcode,const char *err);
+ int do_updates (bool from_send_error);
+ bool send_eof();
+};
+
class select_dumpvar :public select_result {
ha_rows row_count;
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 25a69f7e51b..85dfb38fa48 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -220,7 +220,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
if (!thd->query) // Only in replication
{
query= path;
- query_length= (uint) (strxmov(path,"create database ", db, NullS) -
+ query_length= (uint) (strxmov(path,"create database `", db, "`", NullS) -
path);
}
else
@@ -231,7 +231,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
mysql_update_log.write(thd, query, query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, query, query_length);
+ Query_log_event qinfo(thd, query, query_length, 0);
mysql_bin_log.write(&qinfo);
}
send_ok(thd, result);
@@ -282,7 +282,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
send_ok(thd, result);
@@ -331,8 +331,12 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
error= -1;
my_error(ER_DB_DROP_EXISTS,MYF(0),db);
}
- else if (!silent)
- send_ok(thd,0);
+ else
+ {
+ store_warning(thd,ER_DB_DROP_EXISTS,db);
+ if (!silent)
+ send_ok(thd,0);
+ }
goto exit;
}
pthread_mutex_lock(&LOCK_open);
@@ -346,22 +350,25 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
query_cache_invalidate1(db);
if (!silent)
{
+ const char *query;
+ ulong query_length;
if (!thd->query)
{
- thd->query = path;
- thd->query_length = (uint) (strxmov(path,"drop database ", db, NullS)-
- path);
+ /* The client used the old obsolete mysql_drop_db() call */
+ query= path;
+ query_length = (uint) (strxmov(path,"drop database `", db, "`",
+ NullS)- path);
}
- mysql_update_log.write(thd, thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
+ else
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
- mysql_bin_log.write(&qinfo);
+ query=thd->query;
+ query_length=thd->query_length;
}
- if (thd->query == path)
+ mysql_update_log.write(thd, query, query_length);
+ if (mysql_bin_log.is_open())
{
- thd->query = 0; // just in case
- thd->query_length = 0;
+ Query_log_event qinfo(thd, query, query_length, 0);
+ mysql_bin_log.write(&qinfo);
}
send_ok(thd,(ulong) deleted);
}
@@ -597,7 +604,7 @@ bool mysql_change_db(THD *thd, const char *name)
}
-int mysqld_show_create_db(THD *thd, const char *dbname)
+int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_info)
{
int length;
char path[FN_REFLEN], *to;
@@ -605,6 +612,8 @@ int mysqld_show_create_db(THD *thd, const char *dbname)
bool found_libchar;
HA_CREATE_INFO create;
CONVERT *convert=thd->variables.convert_set;
+ uint create_options = create_info ? create_info->options : 0;
+
DBUG_ENTER("mysql_show_create_db");
if (check_db_name(dbname))
@@ -660,12 +669,17 @@ int mysqld_show_create_db(THD *thd, const char *dbname)
String *packet = &thd->packet;
packet->length(0);
net_store_data(packet, convert, dbname);
- to= strxmov(path, "CREATE DATABASE `", dbname, "`", NullS);
+ to= strxmov(path, "CREATE DATABASE ", NullS);
+ if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ to= strxmov(to,"/*!32312 IF NOT EXISTS*/ ", NullS);
+ to=strxmov(to,"`",dbname,"`", NullS);
+
if (create.table_charset)
- to= strxmov(to," DEFAULT CHARACTER SET ", create.table_charset->name,
- NullS);
+ to= strxmov(to," /*!40100 DEFAULT CHARACTER SET ",
+ create.table_charset->name,"*/",NullS);
+
net_store_data(packet, convert, path, (uint) (to-path));
-
+
if (my_net_write(&thd->net,(char*) packet->ptr(), packet->length()))
DBUG_RETURN(1);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 64945fa2d4d..88da3e2505c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -28,36 +28,46 @@
#include "sql_select.h"
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
- ha_rows limit, thr_lock_type lock_type, ulong options)
+ ha_rows limit, ulong options)
{
int error;
TABLE *table;
SQL_SELECT *select=0;
READ_RECORD info;
bool using_limit=limit != HA_POS_ERROR;
- bool using_transactions;
+ bool transactional_table, log_delayed, safe_update, const_cond;
ha_rows deleted;
+ TABLE_LIST *delete_table_list= (TABLE_LIST*)
+ thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_delete");
- if (!table_list->db)
- table_list->db=thd->db;
- if ((thd->options & OPTION_SAFE_UPDATES) && !conds)
- {
- send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- DBUG_RETURN(1);
- }
-
- if (!(table = open_ltable(thd,table_list, lock_type)))
+ if ((open_and_lock_tables(thd, table_list)))
DBUG_RETURN(-1);
+ fix_tables_pointers(thd->lex.all_selects_list);
+ table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
table->map=1;
- if (setup_conds(thd,table_list,&conds) ||
+ if (setup_conds(thd, delete_table_list, &conds) ||
setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(-1);
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
+ DBUG_RETURN(-1);
+ }
+
+ const_cond= (!conds || conds->const_item());
+ safe_update=test(thd->options & OPTION_SAFE_UPDATES);
+ if (safe_update && const_cond)
+ {
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
/* Test if the user wants to delete all rows */
- if (!using_limit && (!conds || conds->const_item()) &&
+ if (!using_limit && const_cond &&
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
{
deleted= table->file->records;
@@ -79,9 +89,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
select=make_select(table,0,0,conds,&error);
if (error)
DBUG_RETURN(-1);
- if ((select && select->check_quick(test(thd->options & OPTION_SAFE_UPDATES),
- limit)) ||
- !limit)
+ if ((select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
send_ok(thd,0L);
@@ -92,7 +100,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
if (!table->quick_keys)
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
- if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR)
+ if (safe_update && !using_limit)
{
delete select;
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
@@ -132,9 +140,11 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
deleted=0L;
init_ftfuncs(thd, &thd->lex.select_lex, 1);
thd->proc_info="updating";
- while (!(error=info.read_record(&info)) && !thd->killed)
+ while (!(error=info.read_record(&info)) && !thd->killed &&
+ !thd->net.report_error)
{
- if (!(select && select->skipp_record()))
+ // thd->net.report_error is tested to disallow delete row on error
+ if (!(select && select->skipp_record())&& !thd->net.report_error )
{
if (!(error=table->file->delete_row(table->record[0])))
{
@@ -162,22 +172,31 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
(void) table->file->extra(HA_EXTRA_NORMAL);
cleanup:
- using_transactions=table->file->has_transactions();
- if (deleted && (error <= 0 || !using_transactions))
+ transactional_table= table->file->has_transactions();
+ log_delayed= (transactional_table || table->tmp_table);
+ if (deleted && (error <= 0 || !transactional_table))
{
mysql_update_log.write(thd,thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
- using_transactions);
- if (mysql_bin_log.write(&qinfo) && using_transactions)
+ log_delayed);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
- if (!using_transactions)
+ if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
- if (using_transactions && ha_autocommit_or_rollback(thd,error >= 0))
- error=1;
+ if (transactional_table)
+ {
+ if (ha_autocommit_or_rollback(thd,error >= 0))
+ error=1;
+ }
+
+ /*
+ Store table for future invalidation or invalidate it in
+ the query cache if something changed
+ */
if (deleted)
{
query_cache_invalidate3(thd, table_list, 1);
@@ -188,7 +207,7 @@ cleanup:
thd->lock=0;
}
delete select;
- if (error >= 0) // Fatal error
+ if (error >= 0 || thd->net.report_error)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
else
{
@@ -205,19 +224,18 @@ cleanup:
#define MEM_STRIP_BUF_SIZE current_thd->variables.sortbuff_size
-int refposcmp2(void* arg, const void *a,const void *b)
+extern "C" int refposcmp2(void* arg, const void *a,const void *b)
{
+ /* arg is a pointer to file->ref_length */
return memcmp(a,b, *(int*) arg);
}
multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
- thr_lock_type lock_option_arg,
uint num_of_tables_arg)
- : delete_tables (dt), thd(thd_arg), deleted(0),
- num_of_tables(num_of_tables_arg), error(0), lock_option(lock_option_arg),
- do_delete(false)
+ : delete_tables(dt), thd(thd_arg), deleted(0),
+ num_of_tables(num_of_tables_arg), error(0),
+ do_delete(0), transactional_tables(0), log_delayed(0), normal_tables(0)
{
- not_trans_safe=false;
tempfiles = (Unique **) sql_calloc(sizeof(Unique *) * (num_of_tables-1));
}
@@ -227,31 +245,22 @@ multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("multi_delete::prepare");
unit= u;
- do_delete = true;
+ do_delete= 1;
thd->proc_info="deleting from main table";
-
- if (thd->options & OPTION_SAFE_UPDATES)
- {
- TABLE_LIST *table_ref;
- for (table_ref=delete_tables; table_ref; table_ref=table_ref->next)
- {
- TABLE *table=table_ref->table;
- if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
- {
- my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
- DBUG_RETURN(1);
- }
- }
- }
DBUG_RETURN(0);
}
-void
+bool
multi_delete::initialize_tables(JOIN *join)
{
- int counter=0;
TABLE_LIST *walk;
+ Unique **tempfiles_ptr;
+ DBUG_ENTER("initialize_tables");
+
+ if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
+ DBUG_RETURN(1);
+
table_map tables_to_delete_from=0;
for (walk= delete_tables ; walk ; walk=walk->next)
tables_to_delete_from|= walk->table->map;
@@ -265,27 +274,30 @@ multi_delete::initialize_tables(JOIN *join)
{
/* We are going to delete from this table */
TABLE *tbl=walk->table=tab->table;
+ walk=walk->next;
/* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1;
- walk=walk->next;
- if (!not_trans_safe && !tbl->file->has_transactions())
- not_trans_safe=true;
+ tbl->used_keys= 0;
+ if (tbl->file->has_transactions())
+ log_delayed= transactional_tables= 1;
+ else if (tbl->tmp_table != NO_TMP_TABLE)
+ log_delayed= 1;
+ else
+ normal_tables= 1;
}
}
walk= delete_tables;
- walk->table->used_keys=0;
- for (walk=walk->next ; walk ; walk=walk->next, counter++)
+ tempfiles_ptr= tempfiles;
+ for (walk=walk->next ; walk ; walk=walk->next)
{
- tables_to_delete_from|= walk->table->map;
TABLE *table=walk->table;
- /* Don't use key read with MULTI-TABLE-DELETE */
- table->used_keys=0;
- tempfiles[counter] = new Unique (refposcmp2,
- (void *) &table->file->ref_length,
- table->file->ref_length,
- MEM_STRIP_BUF_SIZE);
+ *tempfiles_ptr++= new Unique (refposcmp2,
+ (void *) &table->file->ref_length,
+ table->file->ref_length,
+ MEM_STRIP_BUF_SIZE);
}
init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
+ DBUG_RETURN(thd->fatal_error != 0);
}
@@ -300,7 +312,7 @@ multi_delete::~multi_delete()
t->no_keyread=0;
}
- for (uint counter = 0; counter < num_of_tables-1; counter++)
+ for (uint counter= 0; counter < num_of_tables-1; counter++)
{
if (tempfiles[counter])
delete tempfiles[counter];
@@ -375,7 +387,7 @@ void multi_delete::send_error(uint errcode,const char *err)
In all other cases do attempt deletes ...
*/
if ((table_being_deleted->table->file->has_transactions() &&
- table_being_deleted == delete_tables) || !not_trans_safe)
+ table_being_deleted == delete_tables) || !normal_tables)
ha_rollback_stmt(thd);
else if (do_delete)
{
@@ -394,7 +406,7 @@ void multi_delete::send_error(uint errcode,const char *err)
int multi_delete::do_deletes(bool from_send_error)
{
- int error = 0, counter = 0;
+ int local_error= 0, counter= 0;
if (from_send_error)
{
@@ -407,7 +419,7 @@ int multi_delete::do_deletes(bool from_send_error)
else
table_being_deleted = delete_tables;
- do_delete = false;
+ do_delete= 0;
for (table_being_deleted=table_being_deleted->next;
table_being_deleted ;
table_being_deleted=table_being_deleted->next, counter++)
@@ -415,27 +427,26 @@ int multi_delete::do_deletes(bool from_send_error)
TABLE *table = table_being_deleted->table;
if (tempfiles[counter]->get(table))
{
- error=1;
+ local_error=1;
break;
}
READ_RECORD info;
init_read_record(&info,thd,table,NULL,0,0);
- while (!(error=info.read_record(&info)) &&
- (!thd->killed || from_send_error || not_trans_safe))
+ while (!(local_error=info.read_record(&info)) && !thd->killed)
{
- if ((error=table->file->delete_row(table->record[0])))
+ if ((local_error=table->file->delete_row(table->record[0])))
{
- table->file->print_error(error,MYF(0));
+ table->file->print_error(local_error,MYF(0));
break;
}
deleted++;
}
end_read_record(&info);
- if (error == -1) // End of file
- error = 0;
+ if (local_error == -1) // End of file
+ local_error = 0;
}
- return error;
+ return local_error;
}
@@ -451,15 +462,11 @@ bool multi_delete::send_eof()
thd->proc_info="deleting from reference tables";
/* Does deletes for the last n - 1 tables, returns 0 if ok */
- int error = do_deletes(0); // returns 0 if success
+ int local_error= do_deletes(0); // returns 0 if success
/* reset used flags */
thd->proc_info="end";
- if (error)
- {
- ::send_error(thd);
- return 1;
- }
+
/*
Write the SQL statement to the binlog if we deleted
@@ -467,24 +474,31 @@ bool multi_delete::send_eof()
was a non-transaction-safe table involved, since
modifications in it cannot be rolled back.
*/
- if (deleted || not_trans_safe)
+ if (deleted && (error <= 0 || normal_tables))
{
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
- if (mysql_bin_log.write(&qinfo) &&
- !not_trans_safe)
- error=1; // Log write failed: roll back the SQL statement
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ log_delayed);
+ if (mysql_bin_log.write(&qinfo) && !normal_tables)
+ local_error=1; // Log write failed: roll back the SQL statement
}
- /* Commit or rollback the current SQL statement */
- VOID(ha_autocommit_or_rollback(thd,error > 0));
+ if (!log_delayed)
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
+ /* Commit or rollback the current SQL statement */
+ if (transactional_tables)
+ if (ha_autocommit_or_rollback(thd,local_error > 0))
+ local_error=1;
+
if (deleted)
- {
query_cache_invalidate3(thd, delete_tables, 1);
- }
- ::send_ok(thd,deleted);
+
+ if (local_error)
+ ::send_error(thd);
+ else
+ ::send_ok(thd, deleted);
return 0;
}
@@ -557,8 +571,9 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
if (!ha_supports_generate(table_type))
{
/* Probably InnoDB table */
- DBUG_RETURN(mysql_delete(thd,table_list, (COND*) 0, (ORDER*) 0,
- HA_POS_ERROR, TL_WRITE, 0));
+ table_list->lock_type= TL_WRITE;
+ DBUG_RETURN(mysql_delete(thd, table_list, (COND*) 0, (ORDER*) 0,
+ HA_POS_ERROR, 0));
}
if (lock_and_wait_for_table_name(thd, table_list))
DBUG_RETURN(-1);
@@ -570,6 +585,7 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
*fn_ext(path)=0; // Remove the .frm extension
error= ha_create_table(path,&create_info,1) ? -1 : 0;
query_cache_invalidate3(thd, table_list, 0);
+
end:
if (!dont_send_ok)
{
@@ -578,7 +594,8 @@ end:
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ thd->tmp_table);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); // This should return record count
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 1335618b90d..f0df6811133 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -28,8 +28,7 @@
static const char *any_db="*any*"; // Special symbol for check_access
-int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
- bool tables_is_opened)
+int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
{
/*
TODO: make derived tables with union inside (now only 1 SELECT may be
@@ -51,24 +50,13 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
if (res)
DBUG_RETURN(-1);
- for (TABLE_LIST *cursor= (TABLE_LIST *)tables;
- cursor;
- cursor=cursor->next)
- {
- if (cursor->derived)
- {
- res= mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived,
- cursor, 0);
- if (res) DBUG_RETURN(res);
- }
- }
Item *item;
List_iterator<Item> it(sl->item_list);
while ((item= it++))
item_list.push_back(item);
- if (tables_is_opened || !(res=open_and_lock_tables(thd,tables)))
+ if (!(res=open_and_lock_tables(thd,tables)))
{
if (setup_fields(thd,tables,item_list,0,0,1))
{
@@ -78,10 +66,10 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
- (ORDER*) 0, 0, 1, 0,
+ (ORDER*) 0, 0, 1,
(sl->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
- unit)))
+ HA_POS_ERROR)))
{
res=-1;
goto exit;
@@ -89,19 +77,24 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
if ((derived_result=new select_union(table)))
{
+ derived_result->tmp_table_param=&tmp_table_param;
unit->offset_limit_cnt= sl->offset_limit;
unit->select_limit_cnt= sl->select_limit+sl->offset_limit;
if (unit->select_limit_cnt < sl->select_limit)
unit->select_limit_cnt= HA_POS_ERROR;
if (unit->select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
-
+
+ SELECT_LEX_NODE *save_current_select= lex->current_select;
+ lex->current_select= sl;
res= mysql_select(thd, tables, sl->item_list,
sl->where, (ORDER *) sl->order_list.first,
(ORDER*) sl->group_list.first,
sl->having, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK,
derived_result, unit, sl, 0);
+ lex->current_select= save_current_select;
+
if (!res)
{
// Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables
@@ -112,9 +105,17 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
t->real_name=table->real_name;
t->table=table;
table->derived_select_number= sl->select_number;
- sl->exclude();
- t->db= (tables && tables->db && tables->db[0]) ? t->db : thd->db;
+ table->tmp_table=TMP_TABLE;
+ if (lex->describe)
+ {
+ if (tables)
+ tables->table_list->table=tables->table; // to fix a problem in EXPLAIN
+ }
+ else
+ sl->exclude();
+ t->db=(char *)"";
t->derived=(SELECT_LEX *)0; // just in case ...
+ table->file->info(HA_STATUS_VARIABLE);
}
}
delete derived_result;
@@ -123,8 +124,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t,
free_tmp_table(thd,table);
exit:
close_thread_tables(thd);
- if (res > 0)
- send_error(thd, ER_UNKNOWN_COM_ERROR); // temporary only ...
}
DBUG_RETURN(res);
}
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 3d6a0fa24aa..bba49cf818b 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -51,13 +51,22 @@ This file contains the implementation of error and warnings related
SYNOPSIS
mysql_reset_errors()
thd Thread handle
+
+ IMPLEMENTATION
+ Don't reset warnings if this has already been called for this query.
+ This may happen if one gets a warning during the parsing stage,
+ in which case push_warnings() has already called this function.
*/
void mysql_reset_errors(THD *thd)
{
- free_root(&thd->warn_root,MYF(0));
- bzero((char*) thd->warn_count, sizeof(thd->warn_count));
- thd->warn_list.empty();
+ if (thd->query_id != thd->warn_id)
+ {
+ thd->warn_id= thd->query_id;
+ free_root(&thd->warn_root,MYF(0));
+ bzero((char*) thd->warn_count, sizeof(thd->warn_count));
+ thd->warn_list.empty();
+ }
}
@@ -75,6 +84,9 @@ void mysql_reset_errors(THD *thd)
void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
const char *msg)
{
+ if (thd->query_id != thd->warn_id)
+ mysql_reset_errors(thd);
+
if (thd->warn_list.elements < thd->variables.max_error_count)
{
/*
@@ -92,6 +104,34 @@ void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
thd->total_warn_count++;
}
+/*
+ Store warning to the list
+*/
+
+void store_warning(THD *thd, uint errcode, ...)
+{
+#if TESTS_TO_BE_FIXED
+ va_list args;
+ const char *format;
+ char warning[ERRMSGSIZE+20];
+ DBUG_ENTER("store_warning");
+ DBUG_PRINT("enter",("warning: %u",errcode));
+
+ va_start(args,errcode);
+ if (errcode)
+ format= ER(errcode);
+ else
+ {
+ format=va_arg(args,char*);
+ errcode= ER_UNKNOWN_ERROR;
+ }
+ (void) vsprintf (warning,format,args);
+ va_end(args);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, errcode, warning);
+ DBUG_VOID_RETURN;
+#endif
+}
+
/*
Send all notes, errors or warnings to the client in a result set
@@ -115,7 +155,7 @@ static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
{
List<Item> field_list;
- DBUG_ENTER("mysqld_show_errors");
+ DBUG_ENTER("mysqld_show_warnings");
field_list.push_back(new Item_empty_string("Level", 7));
field_list.push_back(new Item_int("Code",0,4));
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index c43869d9d55..6ea319a72e4 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -106,7 +106,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- if (cond && cond->fix_fields(thd, tables, &cond))
+ if (cond && (cond->check_cols(1) || cond->fix_fields(thd, tables, &cond)))
return -1;
if (keyname)
@@ -180,10 +180,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
- (void) item->save_in_field(key_part->field);
+ (void) item->save_in_field(key_part->field, 1);
key_len+=key_part->store_length;
}
- if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
+ if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
{
send_error(thd,ER_OUTOFMEMORY);
goto err;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 0a1b4435fff..f45e09cf0bf 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -25,7 +25,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list);
static int write_delayed(THD *thd,TABLE *table, enum_duplicates dup,
char *query, uint query_length, bool log_on);
static void end_delayed_insert(THD *thd);
-static pthread_handler_decl(handle_delayed_insert,arg);
+extern "C" pthread_handler_decl(handle_delayed_insert,arg);
static void unlink_blobs(register TABLE *table);
/* Define to force use of my_malloc() if the allocated memory block is big */
@@ -41,7 +41,8 @@ static void unlink_blobs(register TABLE *table);
/*
Check if insert fields are correct
- Resets form->time_stamp if a timestamp value is set
+ Updates table->time_stamp to point to timestamp field or 0, depending on
+ if timestamp should be updated or not.
*/
int
@@ -87,26 +88,29 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
return -1;
}
+ table->time_stamp=0;
if (table->timestamp_field && // Don't set timestamp if used
- table->timestamp_field->query_id == thd->query_id)
- table->time_stamp=0; // This should be saved
+ table->timestamp_field->query_id != thd->query_id)
+ table->time_stamp= table->timestamp_field->offset()+1;
}
- // For the values we need select_priv
+ // For the values we need select_priv
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
return 0;
}
-int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
- List<List_item> &values_list,enum_duplicates duplic,
- thr_lock_type lock_type)
+int mysql_insert(THD *thd,TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<List_item> &values_list,
+ List<Item> &update_fields,
+ List<Item> &update_values,
+ enum_duplicates duplic)
{
int error;
bool log_on= ((thd->options & OPTION_UPDATE_LOG) ||
!(thd->master_access & SUPER_ACL));
- bool using_transactions, bulk_insert=0;
+ bool transactional_table, log_delayed, bulk_insert=0;
uint value_count;
- uint save_time_stamp;
ulong counter = 1;
ulonglong id;
COPY_INFO info;
@@ -114,6 +118,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
List_iterator_fast<List_item> its(values_list);
List_item *values;
char *query=thd->query;
+ thr_lock_type lock_type = table_list->lock_type;
+ TABLE_LIST *insert_table_list= (TABLE_LIST*)
+ thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_insert");
/*
@@ -124,9 +131,12 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if ((lock_type == TL_WRITE_DELAYED &&
((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
thd->slave_thread)) ||
- (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE))
+ (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) ||
+ (duplic == DUP_UPDATE))
lock_type=TL_WRITE;
+ table_list->lock_type= lock_type;
+ int res;
if (lock_type == TL_WRITE_DELAYED)
{
if (thd->locked_tables)
@@ -141,25 +151,40 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
DBUG_RETURN(-1);
}
}
- if (!(table = delayed_get_table(thd,table_list)) && !thd->fatal_error)
- table = open_ltable(thd,table_list,lock_type=thd->update_lock_default);
+ if ((table= delayed_get_table(thd,table_list)) && !thd->fatal_error)
+ if (table_list->next && table)
+ res= open_and_lock_tables(thd, table_list->next);
+ else
+ res= (table == 0);
+ else
+ res= open_and_lock_tables(thd, table_list);
}
else
- table = open_ltable(thd,table_list,lock_type);
- if (!table)
+ res= open_and_lock_tables(thd, table_list);
+ if (res)
DBUG_RETURN(-1);
+ fix_tables_pointers(thd->lex.all_selects_list);
+
+ table= table_list->table;
thd->proc_info="init";
thd->used_tables=0;
- save_time_stamp=table->time_stamp;
values= its++;
if (check_insert_fields(thd,table,fields,*values,1) ||
- setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0))
+ setup_tables(insert_table_list) ||
+ setup_fields(thd, insert_table_list, *values, 0, 0, 0) ||
+ (duplic == DUP_UPDATE &&
+ (setup_fields(thd, insert_table_list, update_fields, 0, 0, 0) ||
+ setup_fields(thd, insert_table_list, update_values, 0, 0, 0))))
+ goto abort;
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
{
- table->time_stamp=save_time_stamp;
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
goto abort;
}
+
value_count= values->elements;
- while ((values = its++))
+ while ((values= its++))
{
counter++;
if (values->elements != value_count)
@@ -167,14 +192,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
MYF(0),counter);
- table->time_stamp=save_time_stamp;
goto abort;
}
- if (setup_fields(thd,table_list,*values,0,0,0))
- {
- table->time_stamp=save_time_stamp;
+ if (setup_fields(thd,insert_table_list,*values,0,0,0))
goto abort;
- }
}
its.rewind ();
/*
@@ -183,6 +204,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
info.records=info.deleted=info.copied=0;
info.handle_duplicates=duplic;
+ info.update_fields=&update_fields;
+ info.update_values=&update_values;
// Don't count warnings for simple inserts
if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS))
thd->count_cuted_fields = 1;
@@ -192,16 +215,21 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
error=0;
id=0;
thd->proc_info="update";
- if (duplic == DUP_IGNORE || duplic == DUP_REPLACE)
+ if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- if ((bulk_insert= (values_list.elements > 1 &&
+ if ((bulk_insert= (values_list.elements >= MIN_ROWS_TO_USE_BULK_INSERT &&
lock_type != TL_WRITE_DELAYED &&
!(specialflag & SPECIAL_SAFE_MODE))))
{
table->file->extra_opt(HA_EXTRA_WRITE_CACHE,
- thd->variables.read_buff_size);
- table->file->extra_opt(HA_EXTRA_BULK_INSERT_BEGIN,
- thd->variables.bulk_insert_buff_size);
+ min(thd->variables.read_buff_size,
+ table->avg_row_length*values_list.elements));
+ if (thd->variables.bulk_insert_buff_size)
+ table->file->extra_opt(HA_EXTRA_BULK_INSERT_BEGIN,
+ min(thd->variables.bulk_insert_buff_size,
+ (table->total_key_length +
+ table->keys * TREE_ELEMENT_EXTRA_SIZE)*
+ values_list.elements));
table->bulk_insert= 1;
}
@@ -210,9 +238,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if (fields.elements || !value_count)
{
restore_record(table,2); // Get empty record
- if (fill_record(fields,*values) || check_null_fields(thd,table))
+ if (fill_record(fields,*values)|| thd->net.report_error ||
+ check_null_fields(thd,table))
{
- if (values_list.elements != 1)
+ if (values_list.elements != 1 && !thd->net.report_error)
{
info.records++;
continue;
@@ -227,9 +256,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
restore_record(table,2); // Get empty record
else
table->record[0][0]=table->record[2][0]; // Fix delete marker
- if (fill_record(table->field,*values))
+ if (fill_record(table->field,*values) || thd->net.report_error)
{
- if (values_list.elements != 1)
+ if (values_list.elements != 1 && ! thd->net.report_error)
{
info.records++;
continue;
@@ -266,10 +295,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
info.copied=values_list.elements;
end_delayed_insert(thd);
}
- if (info.copied || info.deleted)
- {
- query_cache_invalidate3(thd, table_list, 1);
- }
+ query_cache_invalidate3(thd, table_list, 1);
}
else
{
@@ -297,22 +323,29 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
thd->insert_id(id); // For update log
else if (table->next_number_field)
id=table->next_number_field->val_int(); // Return auto_increment value
- using_transactions=table->file->has_transactions();
- if ((info.copied || info.deleted) && (error <= 0 || !using_transactions))
+
+ transactional_table= table->file->has_transactions();
+ log_delayed= (transactional_table || table->tmp_table);
+ if ((info.copied || info.deleted) && (error <= 0 || !transactional_table))
{
mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
- using_transactions);
- if (mysql_bin_log.write(&qinfo) && using_transactions)
+ log_delayed);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
- if (!using_transactions)
+ if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
- if (using_transactions)
+ if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
+
+ /*
+ Store table for future invalidation or invalidate it in
+ the query cache if something changed
+ */
if (info.copied || info.deleted)
{
query_cache_invalidate3(thd, table_list, 1);
@@ -324,11 +357,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
}
}
thd->proc_info="end";
- table->time_stamp=save_time_stamp; // Restore auto timestamp ptr
table->next_number_field=0;
thd->count_cuted_fields=0;
thd->next_insert_id=0; // Reset this if wrongly used
- if (duplic == DUP_IGNORE || duplic == DUP_REPLACE)
+ if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (error)
goto abort;
@@ -380,7 +412,8 @@ int write_record(TABLE *table,COPY_INFO *info)
char *key=0;
info->records++;
- if (info->handle_duplicates == DUP_REPLACE)
+ if (info->handle_duplicates == DUP_REPLACE ||
+ info->handle_duplicates == DUP_UPDATE)
{
while ((error=table->file->write_row(table->record[0])))
{
@@ -397,7 +430,9 @@ int write_record(TABLE *table,COPY_INFO *info)
was used. This ensures that we don't get a problem when the
whole range of the key has been used.
*/
- if (table->next_number_field && key_nr == table->next_number_index &&
+ if (info->handle_duplicates == DUP_REPLACE &&
+ table->next_number_field &&
+ key_nr == table->next_number_index &&
table->file->auto_increment_column_changed)
goto err;
if (table->file->table_flags() & HA_DUPP_POS)
@@ -429,16 +464,33 @@ int write_record(TABLE *table,COPY_INFO *info)
HA_READ_KEY_EXACT))))
goto err;
}
- if (last_uniq_key(table,key_nr))
+ if (info->handle_duplicates == DUP_UPDATE)
{
- if ((error=table->file->update_row(table->record[1],table->record[0])))
- goto err;
- info->deleted++;
- break; /* Update logfile and count */
+ /* we don't check for other UNIQUE keys - the first row
+ that matches, is updated. If update causes a conflict again,
+ an error is returned
+ */
+ restore_record(table,1);
+ if (fill_record(*info->update_fields,*info->update_values))
+ goto err;
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto err;
+ info->deleted++;
+ break;
+ }
+ else /* DUP_REPLACE */
+ {
+ if (last_uniq_key(table,key_nr))
+ {
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto err;
+ info->deleted++;
+ break; /* Update logfile and count */
+ }
+ else if ((error=table->file->delete_row(table->record[1])))
+ goto err;
+ info->deleted++;
}
- else if ((error=table->file->delete_row(table->record[1])))
- goto err;
- info->deleted++;
}
info->copied++;
}
@@ -913,7 +965,7 @@ void kill_delayed_threads(void)
* Create a new delayed insert thread
*/
-static pthread_handler_decl(handle_delayed_insert,arg)
+extern "C" pthread_handler_decl(handle_delayed_insert,arg)
{
delayed_insert *di=(delayed_insert*) arg;
THD *thd= &di->thd;
@@ -1197,7 +1249,7 @@ bool delayed_insert::handle_inserts(void)
mysql_update_log.write(&thd,row->query, row->query_length);
if (using_bin_log)
{
- Query_log_event qinfo(&thd, row->query, row->query_length);
+ Query_log_event qinfo(&thd, row->query, row->query_length,0);
mysql_bin_log.write(&qinfo);
}
}
@@ -1279,7 +1331,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
DBUG_ENTER("select_insert::prepare");
unit= u;
- save_time_stamp=table->time_stamp;
if (check_insert_fields(thd,table,*fields,values,1))
DBUG_RETURN(1);
@@ -1300,8 +1351,6 @@ select_insert::~select_insert()
{
if (table)
{
- if (save_time_stamp)
- table->time_stamp=save_time_stamp;
table->next_number_field=0;
table->file->extra(HA_EXTRA_RESET);
}
@@ -1320,7 +1369,7 @@ bool select_insert::send_data(List<Item> &values)
fill_record(*fields,values);
else
fill_record(table->field,values);
- if (write_record(table,&info))
+ if (thd->net.report_error || write_record(table,&info))
return 1;
if (table->next_number_field) // Clear for next record
{
@@ -1407,7 +1456,6 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
/* First field to copy */
field=table->field+table->fields - values.elements;
- save_time_stamp=table->time_stamp;
if (table->timestamp_field) // Don't set timestamp if used
{
table->timestamp_field->set_time();
@@ -1434,7 +1482,7 @@ bool select_create::send_data(List<Item> &values)
return 0;
}
fill_record(field,values);
- if (write_record(table,&info))
+ if (thd->net.report_error ||write_record(table,&info))
return 1;
if (table->next_number_field) // Clear for next record
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 5327801bf9c..833f36dbe9f 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -76,7 +76,7 @@ inline int lex_casecmp(const char *s, const char *t, uint len)
#include "lex_hash.h"
-static uchar state_map[256];
+static uchar state_map[256], ident_map[256];
void lex_init(void)
@@ -91,7 +91,7 @@ void lex_init(void)
VOID(pthread_key_create(&THR_LEX,NULL));
/* Fill state_map with states to get a faster parser */
- for (i=0; i < 256 ; i++)
+ for (i=0; i < sizeof(state_map) ; i++)
{
if (my_isalpha(system_charset_info,i))
state_map[i]=(uchar) STATE_IDENT;
@@ -126,6 +126,20 @@ void lex_init(void)
{
state_map[(uchar) '"'] = STATE_USER_VARIABLE_DELIMITER;
}
+
+ /*
+ Create a second map to make it faster to find identifiers
+ */
+ for (i=0; i < sizeof(ident_map) ; i++)
+ {
+ ident_map[i]= (uchar) (state_map[i] == STATE_IDENT ||
+ state_map[i] == STATE_NUMBER_IDENT);
+ }
+
+ /* Special handling of hex and binary strings */
+ state_map[(uchar)'x']= state_map[(uchar)'X']= (uchar) STATE_IDENT_OR_HEX;
+ state_map[(uchar)'b']= state_map[(uchar)'b']= (uchar) STATE_IDENT_OR_BIN;
+
DBUG_VOID_RETURN;
}
@@ -149,11 +163,13 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->select_lex.expr_list.empty();
lex->select_lex.ftfunc_list_alloc.empty();
lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
+ lex->current_select= &lex->select_lex;
lex->convert_set= (lex->thd= thd)->variables.convert_set;
lex->yacc_yyss=lex->yacc_yyvs=0;
lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE);
lex->slave_thd_opt=0;
lex->sql_command=SQLCOM_END;
+ lex->safe_to_cache_query= 1;
bzero(&lex->mi,sizeof(lex->mi));
return lex;
}
@@ -182,7 +198,7 @@ static int find_keyword(LEX *lex, uint len, bool function)
udf_func *udf;
if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
{
- lex->thd->safe_to_cache_query=0;
+ lex->safe_to_cache_query=0;
lex->yylval->udf=udf;
switch (udf->returns) {
case STRING_RESULT:
@@ -191,6 +207,10 @@ static int find_keyword(LEX *lex, uint len, bool function)
return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
case INT_RESULT:
return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
}
#endif
@@ -422,13 +442,13 @@ inline static uint int_token(const char *str,uint length)
// STATE_OPERATOR_OR_IDENT ; last state was an ident, text or number
// (which can't be followed by a signed number)
-int yylex(void *arg)
+int yylex(void *arg, void *yythd)
{
reg1 uchar c;
int tokval;
uint length;
enum lex_states state,prev_state;
- LEX *lex=current_lex;
+ LEX *lex= &(((THD *)yythd)->lex);
YYSTYPE *yylval=(YYSTYPE*) arg;
lex->yylval=yylval; // The global state
@@ -438,7 +458,7 @@ int yylex(void *arg)
LINT_INIT(c);
for (;;)
{
- switch(state) {
+ switch (state) {
case STATE_OPERATOR_OR_IDENT: // Next is operator or keyword
case STATE_START: // Start of token
// Skip startspace
@@ -459,7 +479,7 @@ int yylex(void *arg)
}
case STATE_CHAR: // Unknown or single char token
case STATE_SKIP: // This should not happen
- yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first char
+ yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first chr
yylval->lex_str.length=1;
c=yyGet();
if (c != ')')
@@ -468,12 +488,15 @@ int yylex(void *arg)
lex->tok_start=lex->ptr; // Let tok_start point at next item
return((int) c);
- case STATE_IDENT: // Incomplete keyword or ident
- if ((c == 'x' || c == 'X') && yyPeek() == '\'')
+ case STATE_IDENT_OR_HEX:
+ if (yyPeek() == '\'')
{ // Found x'hex-number'
- state=STATE_HEX_NUMBER;
+ state= STATE_HEX_NUMBER;
break;
}
+ /* Fall through */
+ case STATE_IDENT_OR_BIN: // TODO: Add binary string handling
+ case STATE_IDENT:
#if defined(USE_MB) && defined(USE_MB_IDENT)
if (use_mb(system_charset_info))
{
@@ -488,8 +511,7 @@ int yylex(void *arg)
}
lex->ptr += l - 1;
}
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT)
+ while (ident_map[c=yyGet()])
{
if (my_ismbhead(system_charset_info, c))
{
@@ -504,15 +526,13 @@ int yylex(void *arg)
}
else
#endif
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT) ;
+ while (ident_map[c=yyGet()]) ;
length= (uint) (lex->ptr - lex->tok_start)-1;
if (lex->ignore_space)
{
for (; state_map[c] == STATE_SKIP ; c= yyGet());
}
- if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
- state_map[yyPeek()] == STATE_NUMBER_IDENT))
+ if (c == '.' && ident_map[yyPeek()])
lex->next_state=STATE_IDENT_SEP;
else
{ // '(' must follow directly if function
@@ -550,7 +570,7 @@ int yylex(void *arg)
case STATE_NUMBER_IDENT: // number or ident which num-start
while (my_isdigit(system_charset_info,(c = yyGet()))) ;
- if (state_map[c] != STATE_IDENT)
+ if (!ident_map[c])
{ // Can't be identifier
state=STATE_INT_OR_REAL;
break;
@@ -575,7 +595,7 @@ int yylex(void *arg)
lex->tok_start[0] == '0' )
{ // Varbinary
while (my_isxdigit(system_charset_info,(c = yyGet()))) ;
- if ((lex->ptr - lex->tok_start) >= 4 && state_map[c] != STATE_IDENT)
+ if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
{
yylval->lex_str=get_token(lex,yyLength());
yylval->lex_str.str+=2; // Skip 0x
@@ -602,8 +622,7 @@ int yylex(void *arg)
}
lex->ptr += l - 1;
}
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT)
+ while (ident_map[c=yyGet()])
{
if (my_ismbhead(system_charset_info, c))
{
@@ -618,11 +637,9 @@ int yylex(void *arg)
}
else
#endif
- while (state_map[c = yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT) ;
+ while (ident_map[c = yyGet()]) ;
- if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
- state_map[yyPeek()] == STATE_NUMBER_IDENT))
+ if (c == '.' && ident_map[yyPeek()])
lex->next_state=STATE_IDENT_SEP;// Next is '.'
// fall through
@@ -855,9 +872,8 @@ int yylex(void *arg)
case STATE_END:
lex->next_state=STATE_END;
return(0); // We found end of input last time
-
- // Actually real shouldn't start
- // with . but allow them anyhow
+
+ /* Actually real shouldn't start with . but allow them anyhow */
case STATE_REAL_OR_POINT:
if (my_isdigit(system_charset_info,yyPeek()))
state = STATE_REAL; // Real
@@ -884,7 +900,8 @@ int yylex(void *arg)
return((int) '@');
case STATE_HOSTNAME: // end '@' of user@hostname
for (c=yyGet() ;
- my_isalnum(system_charset_info,c) || c == '.' || c == '_' || c == '$';
+ my_isalnum(system_charset_info,c) || c == '.' || c == '_' ||
+ c == '$';
c= yyGet()) ;
yylval->lex_str=get_token(lex,yyLength());
return(LEX_HOSTNAME);
@@ -901,8 +918,7 @@ int yylex(void *arg)
[(global | local | session) .]variable_name
*/
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT) ;
+ while (ident_map[c=yyGet()]) ;
if (c == '.')
lex->next_state=STATE_IDENT_SEP;
length= (uint) (lex->ptr - lex->tok_start)-1;
@@ -927,6 +943,7 @@ void st_select_lex_node::init_query()
{
next= master= slave= link_next= 0;
prev= link_prev= 0;
+ dependent= 0;
}
void st_select_lex_node::init_select()
@@ -936,7 +953,8 @@ void st_select_lex_node::init_select()
order_list.next= (byte**) &order_list.first;
select_limit= HA_POS_ERROR;
offset_limit= 0;
- create_refs= dependent= 0;
+ with_sum_func= 0;
+ create_refs= 0;
}
void st_select_lex_unit::init_query()
@@ -959,6 +977,8 @@ void st_select_lex::init_query()
table_list.next= (byte**) &table_list.first;
item_list.empty();
join= 0;
+ olap= UNSPECIFIED_OLAP_TYPE;
+ having_fix_field= 0;
}
void st_select_lex::init_select()
@@ -976,7 +996,6 @@ void st_select_lex::init_select()
ftfunc_list_alloc.empty();
ftfunc_list= &ftfunc_list_alloc;
linkage= UNSPECIFIED_TYPE;
- having_fix_field= 0;
}
/*
@@ -1044,6 +1063,34 @@ void st_select_lex_node::exclude()
*/
}
+void st_select_lex_unit::exclude_level()
+{
+ SELECT_LEX_UNIT *units= 0, **units_last= &units;
+ for(SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->link_prev && (*sl->link_prev= sl->link_next))
+ sl->link_next->link_prev= sl->link_prev;
+ SELECT_LEX_UNIT **last= 0;
+ for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
+ {
+ u->master= master;
+ last= (SELECT_LEX_UNIT**)&(u->next);
+ }
+ if (last)
+ {
+ (*units_last)= sl->first_inner_unit();
+ units_last= last;
+ }
+ }
+ if (units)
+ {
+ (*prev)= units;
+ (*units_last)= (SELECT_LEX_UNIT*)next;
+ }
+ else
+ (*prev)= next;
+}
+
st_select_lex* st_select_lex_node::select_lex()
{
DBUG_ENTER("st_select_lex_node::select_lex (never should be called)");
@@ -1051,19 +1098,19 @@ st_select_lex* st_select_lex_node::select_lex()
DBUG_RETURN(0);
}
-bool st_select_lex_node::add_item_to_list(Item *item)
+bool st_select_lex_node::add_item_to_list(THD *thd, Item *item)
{
return 1;
}
-bool st_select_lex_node::add_group_to_list(Item *item, bool asc)
+bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc)
{
return 1;
}
-bool st_select_lex_node::add_order_to_list(Item *item, bool asc)
+bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc)
{
- return add_to_list(order_list,item,asc);
+ return add_to_list(thd, order_list,item,asc);
}
bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func)
@@ -1119,7 +1166,7 @@ TABLE_LIST* st_select_lex_node::get_table_list() { return 0; }
List<Item>* st_select_lex_node::get_item_list() { return 0; }
List<String>* st_select_lex_node::get_use_index() { return 0; }
List<String>* st_select_lex_node::get_ignore_index() { return 0; }
-TABLE_LIST *st_select_lex_node::add_table_to_list(Table_ident *table,
+TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
bool updating,
thr_lock_type flags,
@@ -1159,6 +1206,8 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY");
return 1;
}
+ if (sl->linkage == DERIVED_TABLE_TYPE)
+ continue;
for (SELECT_LEX_UNIT *inner= sl->first_inner_unit();
inner;
inner= inner->next_unit())
@@ -1180,7 +1229,6 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
if (!cursor)
{
/* Add not used table to the total table list */
- aux->lock_type= lex->lock_option;
if (!(cursor= (TABLE_LIST *) thd->memdup((char*) aux,
sizeof(*aux))))
{
@@ -1221,14 +1269,14 @@ st_select_lex* st_select_lex::select_lex()
return this;
}
-bool st_select_lex::add_item_to_list(Item *item)
+bool st_select_lex::add_item_to_list(THD *thd, Item *item)
{
return item_list.push_back(item);
}
-bool st_select_lex::add_group_to_list(Item *item, bool asc)
+bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc)
{
- return add_to_list(group_list, item, asc);
+ return add_to_list(thd, group_list, item, asc);
}
bool st_select_lex::add_ftfunc_to_list(Item_func_match *func)
@@ -1283,4 +1331,7 @@ List<String>* st_select_lex::get_ignore_index()
return ignore_index_ptr;
}
-// There are st_select_lex::add_table_to_list in sql_parse.cc
+/*
+ There are st_select_lex::add_table_to_list &
+ st_select_lex::set_lock_for_tables in sql_parse.cc
+*/
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index ea944ef34c8..0c761baffa3 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -37,6 +37,11 @@ class LEX_COLUMN;
#define LEX_YYSTYPE YYSTYPE *
#endif
+/*
+ When a command is added here, be sure it's also added in mysqld.cc
+ in "struct show_var_st status_vars[]= {" ...
+*/
+
enum enum_sql_command {
SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE,
SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT,
@@ -50,9 +55,9 @@ enum enum_sql_command {
SQLCOM_SHOW_CREATE_DB,
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
- SQLCOM_GRANT,
+ SQLCOM_GRANT,
SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB,
- SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
+ SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
@@ -62,11 +67,14 @@ enum enum_sql_command {
SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS,
SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
- SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
+ SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI,
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_END, SQLCOM_HELP
+ SQLCOM_HELP,
+
+ /* This should be the last !!! */
+ SQLCOM_END
};
enum lex_states
@@ -78,7 +86,7 @@ enum lex_states
STATE_REAL_OR_POINT, STATE_BOOL, STATE_EOL, STATE_ESCAPE, STATE_LONG_COMMENT,
STATE_END_LONG_COMMENT, STATE_COLON, STATE_SET_VAR, STATE_USER_END,
STATE_HOSTNAME, STATE_SKIP, STATE_USER_VARIABLE_DELIMITER, STATE_SYSTEM_VAR,
- STATE_IDENT_OR_KEYWORD
+ STATE_IDENT_OR_KEYWORD, STATE_IDENT_OR_HEX, STATE_IDENT_OR_BIN
};
@@ -200,6 +208,7 @@ public:
List<List_item> expr_list;
List<List_item> when_list; /* WHEN clause (expression) */
ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
+ bool with_sum_func;
bool create_refs;
bool dependent; /* dependent from outer select subselect */
@@ -218,9 +227,9 @@ public:
void exclude();
virtual st_select_lex* select_lex();
- virtual bool add_item_to_list(Item *item);
- bool add_order_to_list(Item *item, bool asc);
- virtual bool add_group_to_list(Item *item, bool asc);
+ virtual bool add_item_to_list(THD *thd, Item *item);
+ bool add_order_to_list(THD *thd, Item *item, bool asc);
+ virtual bool add_group_to_list(THD *thd, Item *item, bool asc);
virtual bool add_ftfunc_to_list(Item_func_match *func);
virtual st_select_lex_unit* master_unit()= 0;
@@ -233,14 +242,16 @@ public:
virtual List<Item>* get_item_list();
virtual List<String>* get_use_index();
virtual List<String>* get_ignore_index();
- virtual TABLE_LIST *add_table_to_list(Table_ident *table,
+ virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
bool updating,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0);
-
+ virtual void set_lock_for_tables(thr_lock_type lock_type) {}
void mark_as_dependent(st_select_lex *last);
+
+ friend class st_select_lex_unit;
private:
void fast_exclude();
};
@@ -287,6 +298,7 @@ public:
st_select_lex* outer_select();
st_select_lex* first_select() { return (st_select_lex*) slave; }
st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; }
+ void st_select_lex_unit::exclude_level();
/* UNION methods */
int prepare(THD *thd, select_result *result);
@@ -294,6 +306,7 @@ public:
int cleanup();
friend void mysql_init_query(THD *thd);
+ friend int subselect_union_engine::exec();
private:
bool create_total_list_n_last_return(THD *thd, st_lex *lex,
TABLE_LIST ***result);
@@ -336,7 +349,7 @@ public:
}
st_select_lex* outer_select();
st_select_lex* next_select() { return (st_select_lex*) next; }
- st_select_lex* next_select_in_list()
+ st_select_lex* next_select_in_list()
{
return (st_select_lex*) link_next;
}
@@ -350,20 +363,21 @@ public:
uint get_in_sum_expr();
st_select_lex* select_lex();
- bool add_item_to_list(Item *item);
- bool add_group_to_list(Item *item, bool asc);
+ bool add_item_to_list(THD *thd, Item *item);
+ bool add_group_to_list(THD *thd, Item *item, bool asc);
bool add_ftfunc_to_list(Item_func_match *func);
TABLE_LIST* get_table_list();
List<Item>* get_item_list();
List<String>* get_use_index();
List<String>* get_ignore_index();
- TABLE_LIST* add_table_to_list(Table_ident *table,
+ TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table,
LEX_STRING *alias,
bool updating,
thr_lock_type flags= TL_UNLOCK,
List<String> *use_index= 0,
List<String> *ignore_index= 0);
+ void set_lock_for_tables(thr_lock_type lock_type);
inline void init_order()
{
order_list.elements= 0;
@@ -386,6 +400,8 @@ typedef struct st_lex
SELECT_LEX select_lex; /* first SELECT_LEX */
/* current SELECT_LEX in parsing */
SELECT_LEX_NODE *current_select;
+ /* list of all SELECT_LEX */
+ SELECT_LEX *all_selects_list;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */
@@ -436,9 +452,10 @@ typedef struct st_lex
uint grant, grant_tot_col, which_columns;
uint fk_delete_opt, fk_update_opt, fk_match_option;
uint param_count;
- bool drop_primary, drop_if_exists, local_file, olap;
+ bool drop_primary, drop_if_exists, drop_temporary, local_file;
bool in_comment, ignore_space, verbose, simple_alter;
- bool derived_tables, describe;
+ bool derived_tables, describe, olap;
+ bool safe_to_cache_query;
uint slave_thd_opt;
CHARSET_INFO *charset;
char *help_arg;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 52d1f3adf48..00450a3b86c 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -90,7 +90,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
bool is_fifo=0;
LOAD_FILE_INFO lf_info;
char * db = table_list->db ? table_list->db : thd->db;
- bool using_transactions;
+ bool transactional_table, log_delayed;
DBUG_ENTER("mysql_load");
#ifdef EMBEDDED_LIBRARY
@@ -105,6 +105,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
if (!(table = open_ltable(thd,table_list,lock_type)))
DBUG_RETURN(-1);
+ transactional_table= table->file->has_transactions();
+ log_delayed= (transactional_table || table->tmp_table);
+
if (!fields.elements)
{
Field **field;
@@ -224,6 +227,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
lf_info.handle_dup = handle_duplicates;
lf_info.wrote_create_file = 0;
lf_info.last_pos_in_file = HA_POS_ERROR;
+ lf_info.log_delayed= log_delayed;
read_info.set_io_cache_arg((void*) &lf_info);
}
restore_record(table,2);
@@ -275,16 +279,16 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
free_blobs(table); /* if pack_blob was used */
table->copy_blobs=0;
thd->count_cuted_fields=0; /* Don`t calc cuted fields */
- using_transactions = table->file->has_transactions();
+
if (error)
{
- if (using_transactions)
+ if (transactional_table)
ha_autocommit_or_rollback(thd,error);
if (!opt_old_rpl_compat && mysql_bin_log.is_open())
{
if (lf_info.wrote_create_file)
{
- Delete_file_log_event d(thd);
+ Delete_file_log_event d(thd, log_delayed);
mysql_bin_log.write(&d);
}
}
@@ -297,27 +301,30 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (!thd->slave_thread)
mysql_update_log.write(thd,thd->query,thd->query_length);
- if (!using_transactions)
+ if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
if (mysql_bin_log.is_open())
{
- if (opt_old_rpl_compat && !read_file_from_client)
+ if (opt_old_rpl_compat)
{
- Load_log_event qinfo(thd, ex, db, table->table_name, fields,
- handle_duplicates);
- mysql_bin_log.write(&qinfo);
+ if (!read_file_from_client)
+ {
+ Load_log_event qinfo(thd, ex, db, table->table_name, fields,
+ handle_duplicates, log_delayed);
+ mysql_bin_log.write(&qinfo);
+ }
}
- if (!opt_old_rpl_compat)
+ else
{
read_info.end_io_cache(); // make sure last block gets logged
if (lf_info.wrote_create_file)
{
- Execute_load_log_event e(thd);
+ Execute_load_log_event e(thd, log_delayed);
mysql_bin_log.write(&e);
}
}
}
- if (using_transactions)
+ if (transactional_table)
error=ha_autocommit_or_rollback(thd,error);
DBUG_RETURN(error);
}
diff --git a/sql/sql_manager.cc b/sql/sql_manager.cc
index 13cac83fc3f..0af6a80d4c2 100644
--- a/sql/sql_manager.cc
+++ b/sql/sql_manager.cc
@@ -32,7 +32,7 @@ pthread_t manager_thread;
pthread_mutex_t LOCK_manager;
pthread_cond_t COND_manager;
-pthread_handler_decl(handle_manager,arg __attribute__((unused)))
+extern "C" pthread_handler_decl(handle_manager,arg __attribute__((unused)))
{
int error = 0;
ulong status;
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 930e052ab90..6eb4fbcaaf6 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -75,7 +75,7 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new
!strcmp(((Item_field*)new_item)->table_name,iif->table_name) &&
!strcmp(((Item_field*)new_item)->field_name,iif->field_name))
{
- not_found=false;
+ not_found= 0;
((Item_field*)new_item)->db_name=iif->db_name;
Item_field *new_one=new Item_field(iif->db_name, iif->table_name, iif->field_name);
privlist.push_back(new_one);
@@ -151,7 +151,7 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
if (cursor->do_redirect)
{
cursor->table= ((TABLE_LIST*) cursor->table)->table;
- cursor->do_redirect=false;
+ cursor->do_redirect= 0;
}
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 10b05a0550d..90568bfcc5e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -44,14 +44,13 @@
#else
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
-#define SCRAMBLE_LENGTH 8
#define MEM_ROOT_BLOCK_SIZE 8192
#define MEM_ROOT_PREALLOC 8192
#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
#define TRANS_MEM_ROOT_PREALLOC 4096
-extern int yyparse(void);
+extern int yyparse(void *thd);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
@@ -61,7 +60,6 @@ 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);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
-static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, char **filename_ptr,
@@ -74,7 +72,7 @@ const char *command_name[]={
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
- "Prepare", "Prepare Execute", "Long Data"
+ "Prepare", "Prepare Execute", "Long Data", "Close stmt"
};
static char empty_c_string[1]= {0}; // Used for not defined 'db'
@@ -98,7 +96,17 @@ static void init_signals(void)
}
#endif
-inline bool end_active_trans(THD *thd)
+static void unlock_locked_tables(THD *thd)
+{
+ if (thd->locked_tables)
+ {
+ thd->lock=thd->locked_tables;
+ thd->locked_tables=0; // Will be automaticly closed
+ close_thread_tables(thd); // Free tables
+ }
+}
+
+static bool end_active_trans(THD *thd)
{
int error=0;
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN |
@@ -118,7 +126,7 @@ extern pthread_mutex_t LOCK_user_conn;
static int get_or_create_user_conn(THD *thd, const char *user,
const char *host,
- USER_RESOURCES *mqh)
+ USER_RESOURCES *mqh)
{
int return_val=0;
uint temp_len, user_len, host_len;
@@ -152,7 +160,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
uc->connections = 1;
uc->questions=uc->updates=uc->conn_per_hour=0;
uc->user_resources=*mqh;
- if (max_user_connections && mqh->connections > max_user_connections)
+ 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))
@@ -167,7 +175,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
end:
(void) pthread_mutex_unlock(&LOCK_user_conn);
return return_val;
-
+
}
@@ -177,14 +185,18 @@ end:
thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
*/
-static bool check_user(THD *thd,enum_server_command command, const char *user,
- const char *passwd, const char *db, bool check_count)
+static int check_user(THD *thd,enum_server_command command, const char *user,
+ const char *passwd, const char *db, bool check_count,
+ bool do_send_error, char* crypted_scramble,
+ bool had_password,uint *cur_priv_version,
+ ACL_USER** hint_user)
{
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
- if (!(thd->user = my_strdup(user, MYF(0))))
+ /* We shall avoid dupplicate user allocations here */
+ if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
{
send_error(thd,ER_OUT_OF_RESOURCES);
return 1;
@@ -193,25 +205,35 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
- CLIENT_LONG_PASSWORD),&ur);
+ CLIENT_LONG_PASSWORD),&ur,crypted_scramble,
+ cur_priv_version,hint_user);
+
DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length,
thd->host_or_ip, thd->priv_user,
- passwd[0] ? "yes": "no",
+ had_password ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*"));
+
+ /* in case we're going to retry we should not send error message at this point */
if (thd->master_access & NO_ACCESS)
{
- net_printf(thd, ER_ACCESS_DENIED_ERROR,
- thd->user,
+ if (do_send_error)
+ {
+ net_printf(thd, ER_ACCESS_DENIED_ERROR,
+ thd->user,
thd->host_or_ip,
- passwd[0] ? ER(ER_YES) : ER(ER_NO));
- mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
+ 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,
- passwd[0] ? ER(ER_YES) : ER(ER_NO));
- return(1); // Error already given
+ had_password ? ER(ER_YES) : ER(ER_NO));
+ return(1); // Error already given
+ }
+ else
+ return(-1); // do not report error in special handshake
}
+
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -236,9 +258,10 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
if ((ur.questions || ur.updates || ur.connections) &&
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
return -1;
- if (thd->user_connect && thd->user_connect->user_resources.connections &&
+ if (thd->user_connect && thd->user_connect->user_resources.connections &&
check_for_max_user_connections(thd, thd->user_connect))
return -1;
+
if (db && db[0])
{
bool error=test(mysql_change_db(thd,db));
@@ -257,23 +280,23 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
started with corresponding variable that is greater then 0.
*/
-static byte* get_key_conn(user_conn *buff, uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" byte *get_key_conn(user_conn *buff, uint *length,
+ my_bool not_used __attribute__((unused)))
{
*length=buff->len;
return (byte*) buff->user;
}
-static void free_user(struct user_conn *uc)
+extern "C" void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
}
-void init_max_user_conn(void)
+void init_max_user_conn(void)
{
(void) hash_init(&hash_user_connections,system_charset_info,max_connections,
0,0,
- (hash_get_key) get_key_conn, (void (*)(void*)) free_user,
+ (hash_get_key) get_key_conn, (hash_free_key) free_user,
0);
}
@@ -282,7 +305,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
int error=0;
DBUG_ENTER("check_for_max_user_connections");
-
+
if (max_user_connections &&
(max_user_connections <= (uint) uc->connections))
{
@@ -290,7 +313,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
error=1;
goto end;
}
- uc->connections++;
+ uc->connections++;
if (uc->user_resources.connections &&
uc->conn_per_hour++ >= uc->user_resources.connections)
{
@@ -352,7 +375,7 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
uc_update_queries[SQLCOM_DELETE_MULTI]=1;
uc_update_queries[SQLCOM_DROP_INDEX]=1;
- uc_update_queries[SQLCOM_MULTI_UPDATE]=1;
+ uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
}
@@ -410,11 +433,11 @@ end:
}
-static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them=false)
+static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
{
(void) pthread_mutex_lock(&LOCK_user_conn);
- if (lu) // for GRANT
+ if (lu) // for GRANT
{
USER_CONN *uc;
uint temp_len=lu->user.length+lu->host.length+2;
@@ -503,8 +526,10 @@ check_connections(THD *thd)
ulong pkt_len=0;
{
/* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
- int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41;
+ char buff[SERVER_VERSION_LENGTH +
+ SCRAMBLE_LENGTH+64],*end;
+ int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
@@ -526,6 +551,8 @@ check_connections(THD *thd)
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,
(uint) (end-buff)) ||
(pkt_len= my_net_read(net)) == packet_error ||
@@ -552,7 +579,13 @@ check_connections(THD *thd)
{
/* Do the SSL layering. */
DBUG_PRINT("info", ("IO layer change in progress..."));
- sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout);
+ if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
+ {
+ DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
+ pkt_len));
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len=my_net_read(net)) == packet_error ||
pkt_len < NORMAL_HANDSHAKE_SIZE)
@@ -578,19 +611,77 @@ check_connections(THD *thd)
char *user= (char*) net->read_pos+5;
char *passwd= strend(user)+1;
char *db=0;
- if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
- return ER_HANDSHAKE_ERROR;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
- db=strend(passwd)+1;
+ db=strend(passwd)+1;
+
+ /* We can get only old hash at this point */
+ if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
+ return ER_HANDSHAKE_ERROR;
+
if (thd->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
+ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
- opt_using_transactions)
- thd->net.return_status= &thd->server_status;
+ opt_using_transactions)
+ thd->net.return_status= &thd->server_status;
net->read_timeout=(uint) thd->variables.net_read_timeout;
- if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
- return (-1);
- thd->password=test(passwd[0]);
+
+ char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble and hash */
+
+ ACL_USER* cached_user=NULL; /* Initialise to NULL as first stage indication */
+ uint cur_priv_version;
+
+ /* Simple connect only for old clients. New clients always use secure auth */
+ bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
+
+ /* Store information if we used password. passwd will be dammaged */
+ bool using_password=test(passwd[0]);
+ /* Check user permissions. If password failure we'll get scramble back */
+ if (check_user(thd,COM_CONNECT, user, passwd, db, 1, simple_connect,
+ prepared_scramble,using_password,&cur_priv_version,&cached_user)<0)
+ {
+ /* If The client is old we just have to return error */
+ if (simple_connect)
+ return -1;
+
+ /* Store current used and database as they are erased with next packet */
+
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+
+ tmp_user[0]=0;
+ if (user)
+ strmake(tmp_user,user,USERNAME_LENGTH);
+
+ tmp_db[0]=0;
+ 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))
+ {
+ 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, 1,prepared_scramble,using_password,&cur_priv_version,
+ &cached_user))
+ return -1;
+ }
+ thd->password=using_password;
return 0;
}
@@ -660,7 +751,7 @@ pthread_handler_decl(handle_one_connection,arg)
goto end_thread;
}
- if ((ulong) thd->variables.max_join_size == (ulong) HA_POS_ERROR)
+ if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
if (thd->client_capabilities & CLIENT_COMPRESS)
net->compress=1; // Use compression
@@ -690,9 +781,9 @@ pthread_handler_decl(handle_one_connection,arg)
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
send_error(thd,net->last_errno,NullS);
- thread_safe_increment(aborted_threads,&LOCK_status);
+ statistic_increment(aborted_threads,&LOCK_status);
}
-
+
end_thread:
close_connection(net);
end_thread(thd,1);
@@ -711,7 +802,7 @@ end_thread:
Used when creating the initial grant tables
*/
-pthread_handler_decl(handle_bootstrap,arg)
+extern "C" pthread_handler_decl(handle_bootstrap,arg)
{
THD *thd=(THD*) arg;
FILE *file=bootstrap_file;
@@ -736,7 +827,7 @@ pthread_handler_decl(handle_bootstrap,arg)
#endif
- if ((ulong) thd->variables.max_join_size == (ulong) HA_POS_ERROR)
+ if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR)
thd->options |= OPTION_BIG_SELECTS;
thd->proc_info=0;
@@ -750,7 +841,7 @@ pthread_handler_decl(handle_bootstrap,arg)
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
- while (length && (my_isspace(system_charset_info, buff[length-1]) ||
+ while (length && (my_isspace(system_charset_info, buff[length-1]) ||
buff[length-1] == ';'))
length--;
buff[length]=0;
@@ -903,7 +994,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex.select_lex.options=0; // We store status here
switch (command) {
case COM_INIT_DB:
- thread_safe_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
@@ -915,7 +1006,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_TABLE_DUMP:
{
- thread_safe_increment(com_other, &LOCK_status);
+ statistic_increment(com_other, &LOCK_status);
slow_command = TRUE;
uint db_len = *(uchar*)packet;
uint tbl_len = *(uchar*)(packet + db_len + 1);
@@ -932,7 +1023,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_CHANGE_USER:
{
- thread_safe_increment(com_other,&LOCK_status);
+ thd->change_user();
+ clear_error_message(thd); // If errors from rollback
+
+ statistic_increment(com_other,&LOCK_status);
char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
@@ -942,34 +1036,108 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
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;
+ USER_CONN *save_uc= thd->user_connect;
+ bool simple_connect;
+ bool using_password;
+
+ ulong pkt_len=0; /* Length of reply packet */
+
+ /* Small check for incomming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
- { // Check if protocol is ok
- send_error(thd, ER_UNKNOWN_COM_ERROR);
- break;
- }
- if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
- { // Restore old user
- x_free(thd->user);
- x_free(thd->db);
- 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;
- break;
+ 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;
+
+ char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
+ ACL_USER* cached_user ; /* Cached user */
+ cached_user= NULL;
+ uint cur_priv_version; /* Cached grant version */
+
+ /* 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]);
+
+ if (simple_connect) /* Restore scramble for old clients */
+ memcpy(thd->scramble,thd->old_scramble,9);
+
+ /*
+ Check user permissions. If password failure we'll get scramble back
+ Do not retry if we already have sent error (result>0)
+ */
+ if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect,
+ prepared_scramble,using_password,&cur_priv_version,&cached_user)<0)
+ {
+ /* 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 */
+
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+
+ tmp_user[0]=0;
+ if (user)
+ strmake(tmp_user,user,USERNAME_LENGTH);
+
+ tmp_db[0]=0;
+ 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, 1,prepared_scramble,using_password,&cur_priv_version,
+ &cached_user))
+ 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=test(passwd[0]);
+ thd->password=using_password;
+ break;
+
+ /* Bad luck we shall restore old user */
+ restore_user_err:
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+
+ restore_user:
+ x_free(thd->user);
+ x_free(thd->db);
+ 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;
break;
}
+
case COM_EXECUTE:
{
mysql_stmt_execute(thd, packet);
@@ -985,6 +1153,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
mysql_stmt_prepare(thd, packet, packet_length);
break;
}
+ case COM_CLOSE_STMT:
+ {
+ mysql_stmt_free(thd, packet);
+ break;
+ }
case COM_QUERY:
{
if (alloc_query(thd, packet, packet_length))
@@ -1005,7 +1178,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *fields;
TABLE_LIST table_list;
- thread_safe_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
@@ -1040,7 +1213,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_CREATE_DB: // QQ: To be removed
{
- thread_safe_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
@@ -1058,7 +1231,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DROP_DB: // QQ: To be removed
{
- thread_safe_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
char *db=thd->strdup(packet);
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
@@ -1079,7 +1252,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_BINLOG_DUMP:
{
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
slow_command = TRUE;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -1103,7 +1276,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_REFRESH:
{
- thread_safe_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
ulong options= (ulong) (uchar) packet[0];
if (check_global_access(thd,RELOAD_ACL))
break;
@@ -1115,7 +1288,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_SHUTDOWN:
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
DBUG_PRINT("quit",("Got shutdown command"));
@@ -1138,7 +1311,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
- thread_safe_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
char buff[200];
ulong uptime = (ulong) (thd->start_time - start_time);
sprintf((char*) buff,
@@ -1157,11 +1330,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_PING:
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- thread_safe_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
mysql_log.write(thd,command,NullS);
@@ -1170,13 +1343,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
- thread_safe_increment(com_stat[SQLCOM_KILL],&LOCK_status);
+ statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id);
break;
}
case COM_DEBUG:
- thread_safe_increment(com_other,&LOCK_status);
+ statistic_increment(com_other,&LOCK_status);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
mysql_print_status(thd);
@@ -1255,7 +1428,7 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length)
packet_length--;
}
char *pos=packet+packet_length; // Point at end null
- while (packet_length > 0 &&
+ while (packet_length > 0 &&
(pos[-1] == ';' || my_isspace(system_charset_info,pos[-1])))
{
pos--;
@@ -1297,7 +1470,7 @@ mysql_execute_command(THD *thd)
that is not a SHOW command or a select that only access local
variables, but for now this is probably good enough.
*/
- if (tables)
+ if (tables || &lex->select_lex != lex->all_selects_list)
mysql_reset_errors(thd);
/*
Save old warning count to be able to send to client how many warnings we
@@ -1305,10 +1478,9 @@ mysql_execute_command(THD *thd)
*/
thd->old_total_warn_count= thd->total_warn_count;
- thd->net.report_error= 0;
if (thd->slave_thread)
{
- /*
+ /*
Skip if we are in the slave thread, some table rules have been
given and the table list says the query should not be replicated
*/
@@ -1327,82 +1499,36 @@ mysql_execute_command(THD *thd)
}
#endif
}
-
- select_result *explain_result= 0;
+
/*
TODO: make derived tables processing 'inside' SELECT processing.
TODO: solve problem with depended derived tables in subselects
*/
- if (lex->sql_command == SQLCOM_SELECT &&
- lex->describe && lex->derived_tables)
- {
- if (!(explain_result= new select_send()))
- {
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_VOID_RETURN;
- }
- //check rights
- for (cursor= tables;
- cursor;
- cursor= cursor->next)
- if (cursor->derived)
- {
- TABLE_LIST *tables=
- (TABLE_LIST *)((SELECT_LEX_UNIT *)
- cursor->derived)->first_select()->table_list.first;
- int res;
- if (tables)
- res= check_table_access(thd,SELECT_ACL, tables);
- else
- res= check_access(thd, SELECT_ACL, any_db);
- if (res)
- DBUG_VOID_RETURN;
- }
- thd->send_explain_fields(explain_result);
- // EXPLAIN derived tables
- for (cursor= tables;
- cursor;
- cursor= cursor->next)
- if (cursor->derived)
- {
- SELECT_LEX *select_lex= ((SELECT_LEX_UNIT *)
- cursor->derived)->first_select();
- if (!open_and_lock_tables(thd,
- (TABLE_LIST*) select_lex->table_list.first))
+ if (lex->derived_tables)
+ {
+ for (SELECT_LEX *sl= lex->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ for (TABLE_LIST *cursor= sl->get_table_list();
+ cursor;
+ cursor= cursor->next)
+ if (cursor->derived && (res=mysql_derived(thd, lex,
+ (SELECT_LEX_UNIT *)
+ cursor->derived,
+ cursor)))
{
- mysql_explain_select(thd, select_lex,
- "DERIVED", explain_result);
- // execute derived table SELECT to provide table for other SELECTs
- if (mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived,
- cursor, 1))
- DBUG_VOID_RETURN;
- }
- else
+ if (res < 0 || thd->net.report_error)
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
DBUG_VOID_RETURN;
- }
-
- }
- else if (lex->derived_tables)
- {
- for (TABLE_LIST *cursor= tables;
- cursor;
- cursor= cursor->next)
- if (cursor->derived && (res=mysql_derived(thd, lex,
- (SELECT_LEX_UNIT *)cursor->derived,
- cursor, 0)))
- {
- if (res < 0)
- send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
- DBUG_VOID_RETURN;
- }
+ }
}
- if ((lex->select_lex.next_select_in_list() &&
+ if ((&lex->select_lex != lex->all_selects_list &&
lex->unit.create_total_list(thd, lex, &tables)) ||
(table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables)))
DBUG_VOID_RETURN;
- thread_safe_increment(com_stat[lex->sql_command],&LOCK_status);
+ statistic_increment(com_stat[lex->sql_command],&LOCK_status);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
@@ -1423,10 +1549,11 @@ mysql_execute_command(THD *thd)
break; // Error message is given
}
- unit->offset_limit_cnt= unit->global_parameters->offset_limit;
- unit->select_limit_cnt= unit->global_parameters->select_limit+
- unit->global_parameters->offset_limit;
- if (unit->select_limit_cnt < unit->global_parameters->select_limit)
+ 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)
select_lex->options&= ~OPTION_FOUND_ROWS;
@@ -1435,37 +1562,25 @@ mysql_execute_command(THD *thd)
{
if (lex->describe)
{
- if (!explain_result)
- if (!(explain_result= new select_send()))
- {
- send_error(thd, ER_OUT_OF_RESOURCES);
- DBUG_VOID_RETURN;
- }
- else
- thd->send_explain_fields(explain_result);
- fix_tables_pointers(select_lex);
- res= mysql_explain_union(thd, &thd->lex.unit, explain_result);
+ if (!(result= new select_send()))
+ {
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
+ }
+ else
+ thd->send_explain_fields(result);
+ fix_tables_pointers(lex->all_selects_list);
+ res= mysql_explain_union(thd, &thd->lex.unit, result);
MYSQL_LOCK *save_lock= thd->lock;
thd->lock= (MYSQL_LOCK *)0;
- explain_result->send_eof();
+ result->send_eof();
thd->lock= save_lock;
}
else
{
if (!result)
{
- if ((result=new select_send()))
- {
- /*
- Normal select:
- Change lock if we are using SELECT HIGH PRIORITY,
- FOR UPDATE or IN SHARE MODE
- */
- TABLE_LIST *table;
- for (table = tables ; table ; table=table->next)
- table->lock_type= lex->lock_option;
- }
- else
+ if (!(result=new select_send()))
{
res= -1;
#ifdef DELETE_ITEMS
@@ -1583,7 +1698,7 @@ mysql_execute_command(THD *thd)
res = show_binlog_info(thd);
break;
}
-
+
case SQLCOM_LOAD_MASTER_DATA: // sync with master
if (check_global_access(thd, SUPER_ACL))
goto error;
@@ -1592,7 +1707,7 @@ mysql_execute_command(THD *thd)
else
res = load_master_data(thd);
break;
-
+
#ifdef HAVE_INNOBASE_DB
case SQLCOM_SHOW_INNODB_STATUS:
{
@@ -1679,9 +1794,9 @@ mysql_execute_command(THD *thd)
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- check_dup(tables->db, tables->real_name, tables->next))
+ find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
- net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
if (tables->next)
@@ -1689,8 +1804,6 @@ mysql_execute_command(THD *thd)
TABLE_LIST *table;
if (check_table_access(thd, SELECT_ACL, tables->next))
goto error; // Error message is given
- for (table = tables->next ; table ; table=table->next)
- table->lock_type= lex->lock_option;
}
unit->offset_limit_cnt= select_lex->offset_limit;
unit->select_limit_cnt= select_lex->select_limit+
@@ -1758,7 +1871,7 @@ mysql_execute_command(THD *thd)
#else
{
ulong priv=0;
- if (lex->name && strlen(lex->name) > NAME_LEN)
+ if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
res=0;
@@ -1770,7 +1883,7 @@ mysql_execute_command(THD *thd)
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) ||
- check_merge_table_access(thd, tables->db,
+ check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
@@ -1852,7 +1965,7 @@ mysql_execute_command(THD *thd)
res = show_binlogs(thd);
break;
}
-#endif
+#endif
case SQLCOM_SHOW_CREATE:
#ifdef DONT_ALLOW_SHOW_COMMANDS
send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
@@ -1930,102 +2043,69 @@ mysql_execute_command(THD *thd)
send_error(thd,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
- if (select_lex->table_list.elements == 1)
+ res= mysql_update(thd,tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates);
+ if (thd->net.report_error)
+ res= -1;
+ break;
+ case SQLCOM_UPDATE_MULTI:
+ if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
+ goto error;
+ if (grant_option && check_grant(thd,UPDATE_ACL,tables))
+ goto error;
+ if (select_lex->item_list.elements != lex->value_list.elements)
{
- res = mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates,
- lex->lock_option);
-
-#ifdef DELETE_ITEMS
- delete select_lex->where;
-#endif
+ send_error(thd,ER_WRONG_VALUE_COUNT);
+ DBUG_VOID_RETURN;
}
- else
{
- multi_update *result;
- uint table_count;
- TABLE_LIST *auxi;
- const char *msg=0;
-
- lex->sql_command=SQLCOM_MULTI_UPDATE;
- for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
- {
- table_count++;
- auxi->lock_type=TL_WRITE;
- }
-
+ const char *msg= 0;
if (select_lex->order_list.elements)
- msg="ORDER BY";
+ msg= "ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit !=
HA_POS_ERROR)
- msg="LIMIT";
+ msg= "LIMIT";
if (msg)
{
net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
res= 1;
break;
}
-
- tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
- if ((res=open_and_lock_tables(thd,tables)))
- break;
- unit->select_limit_cnt= HA_POS_ERROR;
- if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
- !setup_fields(thd,tables,lex->value_list,0,0,0) &&
- !thd->fatal_error &&
- (result=new multi_update(thd,tables,select_lex->item_list,
- lex->duplicates, lex->lock_option,
- table_count)))
- {
- List <Item> total_list;
- List_iterator <Item> field_list(select_lex->item_list);
- List_iterator <Item> value_list(lex->value_list);
- Item *item;
- while ((item=field_list++))
- total_list.push_back(item);
- while ((item=value_list++))
- total_list.push_back(item);
-
- res= mysql_select(thd, tables, total_list,
- select_lex->where,
- (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
- (ORDER *)NULL,
- select_lex->options | thd->options |
- SELECT_NO_JOIN_CACHE,
- result, unit, select_lex, 0);
- delete result;
- }
- else
- res= -1; // Error is not sent
- close_thread_tables(thd);
+ res= mysql_multi_update(thd,tables,
+ &select_lex->item_list,
+ &lex->value_list,
+ select_lex->where,
+ select_lex->options,
+ lex->duplicates, unit, select_lex);
}
- break;
- case SQLCOM_INSERT:
- if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INSERT_ACL,tables))
- goto error;
- res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- lex->duplicates,
- lex->lock_option);
break;
case SQLCOM_REPLACE:
- if (check_access(thd,INSERT_ACL | DELETE_ACL,
- tables->db,&tables->grant.privilege))
+ case SQLCOM_INSERT:
+ {
+ my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
+ if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INSERT_ACL | DELETE_ACL,
- tables))
-
+ if (grant_option && check_grant(thd,privilege,tables))
goto error;
+ if (select_lex->item_list.elements != lex->value_list.elements)
+ {
+ send_error(thd,ER_WRONG_VALUE_COUNT);
+ DBUG_VOID_RETURN;
+ }
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- DUP_REPLACE,
- lex->lock_option);
+ select_lex->item_list, lex->value_list,
+ (update ? DUP_UPDATE : lex->duplicates));
+ if (thd->net.report_error)
+ res= -1;
break;
+ }
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
@@ -2035,8 +2115,8 @@ mysql_execute_command(THD *thd)
select privileges for the rest
*/
{
- ulong privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
- INSERT_ACL : INSERT_ACL | DELETE_ACL);
+ 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,
@@ -2054,17 +2134,11 @@ mysql_execute_command(THD *thd)
if (unit->select_limit_cnt < select_lex->select_limit)
unit->select_limit_cnt= HA_POS_ERROR; // No limit
- if (check_dup(tables->db, tables->real_name, tables->next))
+ if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
- net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
- tables->lock_type=TL_WRITE; // update first table
- {
- TABLE_LIST *table;
- for (table = tables->next ; table ; table=table->next)
- table->lock_type= lex->lock_option;
- }
/* Skip first table, which is the table we are inserting in */
lex->select_lex.table_list.first=
@@ -2074,6 +2148,8 @@ mysql_execute_command(THD *thd)
if ((result=new select_insert(tables->table,&lex->field_list,
lex->duplicates)))
res=handle_select(thd,lex,result);
+ if (thd->net.report_error)
+ res= -1;
}
else
res= -1;
@@ -2103,8 +2179,9 @@ mysql_execute_command(THD *thd)
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
res = mysql_delete(thd,tables, select_lex->where,
(ORDER*) select_lex->order_list.first,
- select_lex->select_limit, lex->lock_option,
- select_lex->options);
+ select_lex->select_limit, select_lex->options);
+ if (thd->net.report_error)
+ res= -1;
break;
}
case SQLCOM_DELETE_MULTI:
@@ -2116,11 +2193,11 @@ 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,SELECT_ACL, tables) ||
check_table_access(thd,DELETE_ACL, aux_tables))
goto error;
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
- {
+ {
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
goto error;
}
@@ -2140,10 +2217,10 @@ mysql_execute_command(THD *thd)
net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
goto error;
}
- auxi->lock_type=walk->lock_type=TL_WRITE;
+ walk->lock_type= auxi->lock_type;
auxi->table_list= walk; // Remember corresponding table
}
- if (add_item_to_list(new Item_null()))
+ if (add_item_to_list(thd, new Item_null()))
{
res= -1;
break;
@@ -2154,17 +2231,31 @@ mysql_execute_command(THD *thd)
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
auxi->table= auxi->table_list->table;
+ if (&lex->select_lex != lex->all_selects_list)
+ for (TABLE_LIST *t= select_lex->get_table_list();
+ t; t= t->next)
+ {
+ if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
+ res= -1;
+ break;
+ }
+ }
+ fix_tables_pointers(lex->all_selects_list);
if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
- lex->lock_option,
table_count)))
{
- res= mysql_select(thd,tables,select_lex->item_list,
+ res= mysql_select(thd,select_lex->get_table_list(),
+ select_lex->item_list,
select_lex->where,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result, unit, select_lex, 0);
+ if (thd->net.report_error)
+ res= -1;
delete result;
}
else
@@ -2333,7 +2424,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_LOAD:
{
uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
if (!lex->local_file)
{
@@ -2361,11 +2452,7 @@ mysql_execute_command(THD *thd)
send_ok(thd);
break;
case SQLCOM_UNLOCK_TABLES:
- if (thd->locked_tables)
- {
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
- }
+ unlock_locked_tables(thd);
if (thd->options & OPTION_TABLE_LOCK)
{
end_active_trans(thd);
@@ -2376,12 +2463,7 @@ mysql_execute_command(THD *thd)
send_ok(thd);
break;
case SQLCOM_LOCK_TABLES:
- if (thd->locked_tables)
- {
- thd->lock=thd->locked_tables;
- thd->locked_tables=0; // Will be automaticly closed
- close_thread_tables(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))
@@ -2462,7 +2544,7 @@ mysql_execute_command(THD *thd)
send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
goto error;
}
- res=mysqld_show_create_db(thd,lex->name);
+ res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
break;
}
case SQLCOM_CREATE_FUNCTION:
@@ -2508,7 +2590,7 @@ mysql_execute_command(THD *thd)
if (user->password.str &&
(strcmp(thd->user,user->user.str) ||
user->host.str &&
- my_strcasecmp(system_charset_info,
+ my_strcasecmp(system_charset_info,
user->host.str, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
@@ -2531,7 +2613,7 @@ mysql_execute_command(THD *thd)
mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
}
@@ -2551,7 +2633,7 @@ mysql_execute_command(THD *thd)
mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
if (mqh_used && lex->sql_command == SQLCOM_GRANT)
@@ -2768,6 +2850,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
TABLE_LIST *org_tables=tables;
for (; tables ; tables=tables->next)
{
+ if (tables->derived || (tables->table && (int)tables->table->tmp_table))
+ continue;
if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) &&
thd->db)
tables->grant.privilege= want_access;
@@ -2784,7 +2868,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
found=1;
}
}
- else if (tables->db && check_access(thd,want_access,tables->db,&tables->grant.privilege,
+ else if (check_access(thd,want_access,tables->db,&tables->grant.privilege,
0, no_errors))
return TRUE;
}
@@ -2901,26 +2985,28 @@ void
mysql_init_query(THD *thd)
{
DBUG_ENTER("mysql_init_query");
- thd->lex.unit.init_query();
- thd->lex.unit.init_select();
- thd->lex.select_lex.init_query();
- thd->lex.unit.slave= &thd->lex.select_lex;
- thd->lex.unit.global_parameters= &thd->lex.select_lex; //Global limit & order
- thd->lex.select_lex.master= &thd->lex.unit;
- thd->lex.select_lex.prev= &thd->lex.unit.slave;
- thd->select_number= thd->lex.select_lex.select_number= 1;
- thd->lex.value_list.empty();
+ LEX *lex=&thd->lex;
+ lex->unit.init_query();
+ lex->unit.init_select();
+ lex->select_lex.init_query();
+ lex->value_list.empty();
+ lex->param_list.empty();
+ lex->unit.global_parameters= lex->unit.slave= lex->current_select=
+ lex->all_selects_list= &lex->select_lex;
+ lex->select_lex.master= &lex->unit;
+ lex->select_lex.prev= &lex->unit.slave;
+ lex->select_lex.link_next= 0;
+ lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
+ lex->olap=lex->describe=0;
+ lex->derived_tables= false;
+ thd->check_loops_counter= thd->select_number=
+ lex->select_lex.select_number= 1;
thd->free_list= 0;
- thd->lex.current_select= &thd->lex.select_lex;
- thd->lex.olap=thd->lex.describe=0;
- thd->lex.select_lex.olap= UNSPECIFIED_OLAP_TYPE;
- thd->fatal_error= 0; // Safety
thd->total_warn_count=0; // Warnings for this query
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
thd->sent_row_count= thd->examined_row_count= 0;
- thd->rand_used=0;
- thd->safe_to_cache_query= 1;
- thd->lex.param_list.empty();
+ thd->fatal_error= thd->rand_used= 0;
+ thd->possible_loops= 0;
DBUG_VOID_RETURN;
}
@@ -2930,12 +3016,14 @@ mysql_init_select(LEX *lex)
SELECT_LEX *select_lex= lex->current_select->select_lex();
DBUG_ASSERT(select_lex->linkage != GLOBAL_OPTIONS_TYPE);
select_lex->init_select();
- select_lex->master_unit()->select_limit= select_lex->select_limit=
+ select_lex->master_unit()->select_limit= select_lex->select_limit=
lex->thd->variables.select_limit;
- select_lex->olap= UNSPECIFIED_OLAP_TYPE;
- lex->exchange= 0;
- lex->result= 0;
- lex->proc_list.first= 0;
+ if (select_lex == &lex->select_lex)
+ {
+ lex->exchange= 0;
+ lex->result= 0;
+ lex->proc_list.first= 0;
+ }
}
@@ -2961,11 +3049,10 @@ mysql_new_select(LEX *lex, bool move_down)
}
else
select_lex->include_neighbour(lex->current_select);
-
+
select_lex->master_unit()->global_parameters= select_lex;
DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
- select_lex->include_global(lex->current_select->select_lex()->
- next_select_in_list_addr());
+ select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
lex->current_select= select_lex;
return 0;
}
@@ -2993,7 +3080,7 @@ void create_select_for_variable(const char *var_name)
lex->sql_command= SQLCOM_SELECT;
tmp.str= (char*) var_name;
tmp.length=strlen(var_name);
- add_item_to_list(get_system_var(OPT_SESSION, tmp));
+ add_item_to_list(lex->thd, get_system_var(OPT_SESSION, tmp));
DBUG_VOID_RETURN;
}
@@ -3016,21 +3103,27 @@ mysql_parse(THD *thd, char *inBuf, uint length)
mysql_init_query(thd);
thd->query_length = length;
- thd->lex.derived_tables= false;
+ thd->net.report_error= 0;
+
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
+ if (!yyparse((void *)thd) && ! thd->fatal_error)
{
if (mqh_used && thd->user_connect &&
- check_mqh(thd, thd->lex.sql_command))
+ check_mqh(thd, lex->sql_command))
{
thd->net.error = 0;
}
else
{
- mysql_execute_command(thd);
- query_cache_end_of_result(&thd->net);
+ if (thd->net.report_error)
+ send_error(thd, 0, NullS);
+ else
+ {
+ mysql_execute_command(thd);
+ query_cache_end_of_result(&thd->net);
+ }
}
}
else
@@ -3047,31 +3140,21 @@ mysql_parse(THD *thd, char *inBuf, uint length)
}
-inline static void
-link_in_list(SQL_LIST *list,byte *element,byte **next)
-{
- list->elements++;
- (*list->next)=element;
- list->next=next;
- *next=0;
-}
-
-
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
******************************************************************************/
-bool add_field_to_list(char *field_name, enum_field_types type,
+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,
char *change, TYPELIB *interval, CHARSET_INFO *cs)
{
register create_field *new_field;
- THD *thd=current_thd;
LEX *lex= &thd->lex;
uint allowed_type_modifier=0;
+ char warn_buff[MYSQL_ERRMSG_SIZE];
DBUG_ENTER("add_field_to_list");
if (strlen(field_name) > NAME_LEN)
@@ -3163,8 +3246,6 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if (!length) new_field->length=20;
allowed_type_modifier= AUTO_INCREMENT_FLAG;
break;
- case FIELD_TYPE_STRING:
- case FIELD_TYPE_VAR_STRING:
case FIELD_TYPE_NULL:
case FIELD_TYPE_GEOMETRY:
break;
@@ -3175,10 +3256,35 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if (new_field->decimals)
new_field->length++;
break;
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_VAR_STRING:
+ if (new_field->length < MAX_FIELD_WIDTH || default_value)
+ break;
+ /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
+ new_field->sql_type= FIELD_TYPE_BLOB;
+ sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR",
+ (cs == my_charset_bin) ? "BLOB" : "TEXT");
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT,
+ warn_buff);
+ /* fall through */
case FIELD_TYPE_BLOB:
case FIELD_TYPE_TINY_BLOB:
case FIELD_TYPE_LONG_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
+ if (new_field->length)
+ {
+ /* The user has given a length to the blob column */
+ if (new_field->length < 256)
+ type= FIELD_TYPE_TINY_BLOB;
+ if (new_field->length < 65536)
+ type= FIELD_TYPE_BLOB;
+ else if (new_field->length < 256L*256L*256L)
+ type= FIELD_TYPE_MEDIUM_BLOB;
+ else
+ type= FIELD_TYPE_LONG_BLOB;
+ new_field->length= 0;
+ }
+ new_field->sql_type= type;
if (default_value) // Allow empty as default value
{
String str,*res;
@@ -3345,18 +3451,18 @@ void store_position_for_column(const char *name)
}
bool
-add_proc_to_list(Item *item)
+add_proc_to_list(THD* thd, Item *item)
{
ORDER *order;
Item **item_ptr;
- if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
return 1;
item_ptr = (Item**) (order+1);
*item_ptr= item;
order->item=item_ptr;
order->free_me=0;
- link_in_list(&current_lex->proc_list,(byte*) order,(byte**) &order->next);
+ thd->lex.proc_list.link_in_list((byte*) order,(byte**) &order->next);
return 0;
}
@@ -3397,12 +3503,12 @@ static void remove_escape(char *name)
****************************************************************************/
-bool add_to_list(SQL_LIST &list,Item *item,bool asc)
+bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
{
ORDER *order;
Item **item_ptr;
DBUG_ENTER("add_to_list");
- if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
DBUG_RETURN(1);
item_ptr = (Item**) (order+1);
*item_ptr=item;
@@ -3410,12 +3516,13 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc)
order->asc = asc;
order->free_me=0;
order->used=0;
- link_in_list(&list,(byte*) order,(byte**) &order->next);
+ list.link_in_list((byte*) order,(byte**) &order->next);
DBUG_RETURN(0);
}
-TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
+TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
+ Table_ident *table,
LEX_STRING *alias,
bool updating,
thr_lock_type flags,
@@ -3423,7 +3530,6 @@ TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
List<String> *ignore_index)
{
register TABLE_LIST *ptr;
- THD *thd=current_thd;
char *alias_str;
DBUG_ENTER("add_table_to_list");
@@ -3431,7 +3537,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
DBUG_RETURN(0); // End of memory
alias_str= alias ? alias->str : table->table.str;
if (table->table.length > NAME_LEN ||
- (table->table.length && check_table_name(table->table.str,table->table.length)) ||
+ (table->table.length &&
+ check_table_name(table->table.str,table->table.length)) ||
table->db.str && check_db_name(table->db.str))
{
net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
@@ -3439,12 +3546,18 @@ TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
}
if (!alias) /* Alias is case sensitive */
+ {
+ if (table->sel)
+ {
+ net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
+ DBUG_RETURN(0);
+ }
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
-
+ }
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
- if (table->db.str)
+ if (table->db.str)
{
ptr->db= table->db.str;
ptr->db_length= table->db.length;
@@ -3460,7 +3573,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
ptr->db= empty_c_string;
ptr->db_length= 0;
}
-
+
ptr->alias= alias_str;
if (lower_case_table_names)
{
@@ -3493,36 +3606,61 @@ TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
}
}
}
- link_in_list(&table_list, (byte*) ptr, (byte**) &ptr->next);
+ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
DBUG_RETURN(ptr);
}
-void add_join_on(TABLE_LIST *b,Item *expr)
+/*
+ Set lock for all tables in current select level
+
+ SYNOPSIS:
+ set_lock_for_tables()
+ lock_type Lock to set for tables
+
+ NOTE:
+ If lock is a write lock, then tables->updating is set 1
+ This is to get tables_ok to know that the table is updated by the
+ query
+*/
+
+void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
{
- if (!b->on_expr)
- b->on_expr=expr;
- else
+ bool for_update= lock_type >= TL_READ_NO_INSERT;
+ DBUG_ENTER("set_lock_for_tables");
+ DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
+ for_update));
+
+ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
+ tables ;
+ tables=tables->next)
{
- // This only happens if you have both a right and left join
- b->on_expr=new Item_cond_and(b->on_expr,expr);
+ tables->lock_type= lock_type;
+ tables->updating= for_update;
}
+ DBUG_VOID_RETURN;
}
-void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
+void add_join_on(TABLE_LIST *b,Item *expr)
{
- b->natural_join=a;
+ if (expr)
+ {
+ if (!b->on_expr)
+ b->on_expr=expr;
+ else
+ {
+ // This only happens if you have both a right and left join
+ b->on_expr=new Item_cond_and(b->on_expr,expr);
+ }
+ b->on_expr->top_level_item();
+ }
}
- /* Check if name is used in table list */
-static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
+void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
{
- for (; tables ; tables=tables->next)
- if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
- return 1;
- return 0;
+ b->natural_join=a;
}
bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
@@ -3533,7 +3671,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
if (options & REFRESH_GRANT)
{
acl_reload(thd);
- grant_reload();
+ grant_reload(thd);
if (mqh_used)
reset_mqh(thd,(LEX_USER *) NULL,true);
}
@@ -3706,3 +3844,33 @@ bool check_simple_select()
}
return 0;
}
+
+compare_func_creator comp_eq_creator(bool invert)
+{
+ return invert?&Item_bool_func2::ne_creator:&Item_bool_func2::eq_creator;
+}
+
+compare_func_creator comp_ge_creator(bool invert)
+{
+ return invert?&Item_bool_func2::lt_creator:&Item_bool_func2::ge_creator;
+}
+
+compare_func_creator comp_gt_creator(bool invert)
+{
+ return invert?&Item_bool_func2::le_creator:&Item_bool_func2::gt_creator;
+}
+
+compare_func_creator comp_le_creator(bool invert)
+{
+ return invert?&Item_bool_func2::gt_creator:&Item_bool_func2::le_creator;
+}
+
+compare_func_creator comp_lt_creator(bool invert)
+{
+ return invert?&Item_bool_func2::ge_creator:&Item_bool_func2::lt_creator;
+}
+
+compare_func_creator comp_ne_creator(bool invert)
+{
+ return invert?&Item_bool_func2::eq_creator:&Item_bool_func2::ne_creator;
+}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 2cf51f5d72e..9d6e6d75ade 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -20,31 +20,47 @@ This file contains the implementation of prepare and executes.
Prepare:
- - Server gets the query from client with command 'COM_PREPARE'
+ - Server gets the query from client with command 'COM_PREPARE';
+ in the following format:
+ [COM_PREPARE:1] [query]
- Parse the query and recognize any parameter markers '?' and
- store its information list lex->param_list
+ store its information list in lex->param_list
+ - Allocate a new statement for this prepare; and keep this in
+ 'thd->prepared_statements' pool.
- Without executing the query, return back to client the total
number of parameters along with result-set metadata information
- (if any)
+ (if any) in the following format:
+ [STMT_ID:4][Columns:2][Param_count:2][Columns meta info][Params meta info]
Prepare-execute:
- Server gets the command 'COM_EXECUTE' to execute the
- previously prepared query.
- - If there is are any parameters, then replace the markers with the
- data supplied by client with the following format:
- [types_specified(0/1)][type][length][data] .. [type][length]..
+ previously prepared query. If there is any param markers; then client
+ will send the data in the following format:
+ [COM_EXECUTE:1]
+ [STMT_ID:4]
+ [NULL_BITS:(param_count+7)/8)]
+ [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
+ [[length]data]
+ [[length]data] .. [[length]data].
+ (Note: Except for string/binary types; all other types will not be
+ supplied with length field)
+ - Replace the param items with this new data. If it is a first execute
+ or types altered by client; then setup the conversion routines.
- Execute the query without re-parsing and send back the results
to client
Long data handling:
+
- Server gets the long data in pieces with command type 'COM_LONG_DATA'.
- The packet recieved will have the format as:
- [COM_LONG_DATA:1][parameter_number:2][type:2][data]
+ [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][type:2][data]
- Checks if the type is specified by client, and if yes reads the type,
and stores the data in that format.
- It's up to the client to check for read data ended. The server doesn't
- care.
+ care; and also server doesn't notify to the client that it got the
+ data or not; if there is any error; then during execute; the error
+ will be returned
***********************************************************************/
@@ -53,33 +69,9 @@ Long data handling:
#include <assert.h> // for DEBUG_ASSERT()
#include <m_ctype.h> // for isspace()
-extern int yyparse(void);
-static ulong get_param_length(uchar **packet);
-static uint get_buffer_type(uchar **packet);
-static bool param_is_null(uchar **packet);
-static bool setup_param_fields(THD *thd,List<Item> &params);
-static uchar* setup_param_field(Item_param *item_param, uchar *pos,
- uint buffer_type);
-static void setup_longdata_field(Item_param *item_param, uchar *pos);
-static bool setup_longdata(THD *thd,List<Item> &params);
-static bool send_prepare_results(PREP_STMT *stmt);
-static bool parse_prepare_query(PREP_STMT *stmt, char *packet, uint length);
-static bool mysql_send_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
- List<Item> &fields,
- List<List_item> &values_list,
- thr_lock_type lock_type);
-static bool mysql_test_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
- List<Item> &fields,
- List<List_item> &values_list,
- thr_lock_type lock_type);
-static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
- List<Item> &fields, List<Item> &values,
- COND *conds,thr_lock_type lock_type);
-static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
- List<Item> &fields, List<Item> &values,
- COND *conds, ORDER *order, ORDER *group,
- Item *having,thr_lock_type lock_type);
+#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
+extern int yyparse(void *thd);
/*
Find prepared statement in thd
@@ -114,9 +106,9 @@ static PREP_STMT *find_prepared_statement(THD *thd, ulong stmt_id,
Compare two prepared statements; Used to find a prepared statement
*/
-int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used)
+int compare_prep_stmt(void *not_used, PREP_STMT *stmt, ulong *key)
{
- return (a->stmt_id < b->stmt_id) ? -1 : (a->stmt_id == b->stmt_id) ? 0 : 1;
+ return (stmt->stmt_id == *key) ? 0 : (stmt->stmt_id < *key) ? -1 : 1;
}
@@ -132,22 +124,23 @@ int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used)
*/
void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used)
-{
- free_root(&stmt->mem_root, MYF(0));
+{
free_items(stmt->free_list);
+ free_root(&stmt->mem_root, MYF(0));
}
/*
Send prepared stmt info to client after prepare
*/
-bool send_prep_stmt(PREP_STMT *stmt, uint columns)
+static bool send_prep_stmt(PREP_STMT *stmt, uint columns)
{
+ NET *net=&stmt->thd->net;
char buff[8];
int4store(buff, stmt->stmt_id);
int2store(buff+4, columns);
int2store(buff+6, stmt->param_count);
- return my_net_write(&stmt->thd->net, buff, sizeof(buff));
+ return (my_net_write(net, buff, sizeof(buff)) || net_flush(net));
}
/*
@@ -156,43 +149,15 @@ bool send_prep_stmt(PREP_STMT *stmt, uint columns)
TODO: Not yet ready
*/
-bool send_item_params(PREP_STMT *stmt)
+static bool send_item_params(PREP_STMT *stmt)
{
+#if 0
char buff[1];
buff[0]=0;
- return my_net_write(&stmt->thd->net, buff, sizeof(buff));
-}
-
-
-
-/*
- Read the buffer type, this happens only first time
-*/
-
-static uint get_buffer_type(uchar **packet)
-{
- reg1 uchar *pos= *packet;
- (*packet)+= 2;
- return (uint) uint2korr(pos);
-}
-
-
-/*
- Check for NULL param data
-
- RETURN VALUES
- 0 Value was not NULL
- 1 Value was NULL
-*/
-
-static bool param_is_null(uchar **packet)
-{
- reg1 uchar *pos= *packet;
- if (*pos == 251)
- {
- (*packet)++;
+ if (my_net_write(&stmt->thd->net, buff, sizeof(buff)))
return 1;
- }
+ send_eof(stmt->thd);
+#endif
return 0;
}
@@ -222,60 +187,103 @@ static ulong get_param_length(uchar **packet)
(*packet)+=9; // Must be 254 when here
return (ulong) uint4korr(pos+1);
}
+ /*
+ Setup param conversion routines
-/*
- Read and return the data for parameters supplied by client
+ setup_param_xx()
+ param Parameter Item
+ pos Input data buffer
+
+ All these functions reads the data from pos and sets up that data
+ through 'param' and advances the buffer position to predifined
+ length position.
+
+ Make a note that the NULL handling is examined at first execution
+ (i.e. when input types altered) and for all subsequent executions
+ we don't read any values for this.
+
+ RETURN VALUES
+
*/
-static uchar* setup_param_field(Item_param *item_param,
- uchar *pos, uint buffer_type)
+static void setup_param_tiny(Item_param *param, uchar **pos)
{
- if (param_is_null(&pos))
- {
- item_param->set_null();
- return(pos);
- }
- switch (buffer_type) {
+ param->set_int((longlong)(**pos));
+ *pos+= 1;
+}
+
+static void setup_param_short(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)sint2korr(*pos));
+ *pos+= 2;
+}
+
+static void setup_param_int32(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)sint4korr(*pos));
+ *pos+= 4;
+}
+
+static void setup_param_int64(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)sint8korr(*pos));
+ *pos+= 8;
+}
+
+static void setup_param_float(Item_param *param, uchar **pos)
+{
+ float data;
+ float4get(data,*pos);
+ param->set_double((double) data);
+ *pos+= 4;
+}
+
+static void setup_param_double(Item_param *param, uchar **pos)
+{
+ double data;
+ float8get(data,*pos);
+ param->set_double((double) data);
+ *pos+= 8;
+}
+
+static void setup_param_str(Item_param *param, uchar **pos)
+{
+ 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)
+{
+ switch (param_type) {
case FIELD_TYPE_TINY:
- item_param->set_int((longlong)(*pos));
- pos += 1;
+ param->setup_param_func= setup_param_tiny;
+ param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_SHORT:
- item_param->set_int((longlong)sint2korr(pos));
- pos += 2;
- break;
- case FIELD_TYPE_INT24:
- item_param->set_int((longlong)sint4korr(pos));
- pos += 3;
+ param->setup_param_func= setup_param_short;
+ param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_LONG:
- item_param->set_int((longlong)sint4korr(pos));
- pos += 4;
+ param->setup_param_func= setup_param_int32;
+ param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_LONGLONG:
- item_param->set_int((longlong)sint8korr(pos));
- pos += 8;
+ param->setup_param_func= setup_param_int64;
+ param->item_result_type = INT_RESULT;
break;
case FIELD_TYPE_FLOAT:
- float data;
- float4get(data,pos);
- item_param->set_double((double) data);
- pos += 4;
+ param->setup_param_func= setup_param_float;
+ param->item_result_type = REAL_RESULT;
break;
case FIELD_TYPE_DOUBLE:
- double j;
- float8get(j,pos)
- item_param->set_double(j);
- pos += 8;
+ param->setup_param_func= setup_param_double;
+ param->item_result_type = REAL_RESULT;
break;
default:
- {
- ulong len=get_param_length(&pos);
- item_param->set_value((const char*)pos,len);
- pos+=len;
- }
+ param->setup_param_func= setup_param_str;
+ param->item_result_type = STRING_RESULT;
}
- return(pos);
}
/*
@@ -283,46 +291,45 @@ static uchar* setup_param_field(Item_param *item_param,
from client ..
*/
-static bool setup_param_fields(THD *thd, PREP_STMT *stmt)
-{
- DBUG_ENTER("setup_param_fields");
-#ifdef READY_TO_BE_USED
- Item_param *item_param;
- ulong param_count=0;
- uchar *pos=(uchar*) thd->net.read_pos+1;// skip command type
+static bool setup_params_data(PREP_STMT *stmt)
+{
+ THD *thd= stmt->thd;
+ List<Item> &params= thd->lex.param_list;
+ List_iterator<Item> param_iterator(params);
+ Item_param *param;
+ DBUG_ENTER("setup_params_data");
-
- if (*pos++) // No types supplied, read only param data
- {
- while ((item_param=(Item_param *)it++) &&
- (param_count++ < stmt->param_count))
- {
- if (item_param->long_data_supplied)
- continue;
+ uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header
+ uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits
- if (!(pos=setup_param_field(item_param,pos,item_param->buffer_type)))
- DBUG_RETURN(1);
+ if (*read_pos++) //types supplied / first execute
+ {
+ /*
+ First execute or types altered by the client, setup the
+ conversion routines for all parameters (one time)
+ */
+ while ((param= (Item_param *)param_iterator++))
+ {
+ setup_param_functions(param,*read_pos);
+ read_pos+= 2;
}
- }
- else // Types supplied, read and store it along with param data
+ param_iterator.rewind();
+ }
+ ulong param_no= 0;
+ while ((param= (Item_param *)param_iterator++))
{
- while ((item_param=(Item_param *)it++) &&
- (param_count++ < thd->param_count))
+ if (!param->long_data_supplied)
{
- if (item_param->long_data_supplied)
- continue;
-
- if (!(pos=setup_param_field(item_param,pos,
- item_param->buffer_type=
- (enum_field_types) get_buffer_type(&pos))))
- DBUG_RETURN(1);
+ if (IS_PARAM_NULL(pos,param_no))
+ param->maybe_null=param->null_value=1;
+ else
+ param->setup_param_func(param,&read_pos);
}
+ param_no++;
}
-#endif
DBUG_RETURN(0);
}
-
/*
Validates insert fields
*/
@@ -379,8 +386,7 @@ static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields,
static bool mysql_test_insert_fields(PREP_STMT *stmt,
TABLE_LIST *table_list,
List<Item> &fields,
- List<List_item> &values_list,
- thr_lock_type lock_type)
+ List<List_item> &values_list)
{
THD *thd= stmt->thd;
TABLE *table;
@@ -388,7 +394,7 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
List_item *values;
DBUG_ENTER("mysql_test_insert_fields");
- if (!(table = open_ltable(thd,table_list,lock_type)))
+ if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(1);
if ((values= its++))
@@ -431,13 +437,13 @@ static bool mysql_test_insert_fields(PREP_STMT *stmt,
static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- COND *conds, thr_lock_type lock_type)
+ COND *conds)
{
THD *thd= stmt->thd;
TABLE *table;
DBUG_ENTER("mysql_test_upd_fields");
- if (!(table = open_ltable(thd,table_list,lock_type)))
+ if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(1);
if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) ||
@@ -469,7 +475,7 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
List<Item> &fields, List<Item> &values,
COND *conds, ORDER *order, ORDER *group,
- Item *having, thr_lock_type lock_type)
+ Item *having)
{
TABLE *table;
bool hidden_group_fields;
@@ -477,7 +483,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
List<Item> all_fields(fields);
DBUG_ENTER("mysql_test_select_fields");
- if (!(table = open_ltable(thd,tables,lock_type)))
+ if (!(table = open_ltable(thd,tables,TL_READ)))
DBUG_RETURN(1);
thd->used_tables=0; // Updated by setup_fields
@@ -492,7 +498,8 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
{
thd->where="having clause";
thd->allow_sum_func=1;
- if (having->fix_fields(thd, tables, &having) || thd->fatal_error)
+ if (having->check_cols(1) || having->fix_fields(thd, tables, &having)
+ || thd->fatal_error)
DBUG_RETURN(1);
if (having->with_sum_func)
having->split_sum_func(all_fields);
@@ -550,21 +557,19 @@ static bool send_prepare_results(PREP_STMT *stmt)
case SQLCOM_INSERT:
if (mysql_test_insert_fields(stmt, tables, lex->field_list,
- lex->many_values, lex->lock_option))
+ lex->many_values))
goto abort;
break;
case SQLCOM_UPDATE:
if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
- lex->value_list, select_lex->where,
- lex->lock_option))
+ lex->value_list, select_lex->where))
goto abort;
break;
case SQLCOM_DELETE:
if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
- lex->value_list, select_lex->where,
- lex->lock_option))
+ lex->value_list, select_lex->where))
goto abort;
break;
@@ -572,8 +577,7 @@ static bool send_prepare_results(PREP_STMT *stmt)
if (mysql_test_select_fields(stmt, tables, select_lex->item_list,
lex->value_list, select_lex->where,
(ORDER*) select_lex->order_list.first,
- (ORDER*) select_lex->group_list.first,
- select_lex->having, lex->lock_option))
+ (ORDER*) select_lex->group_list.first, select_lex->having))
goto abort;
break;
@@ -583,6 +587,8 @@ static bool send_prepare_results(PREP_STMT *stmt)
Rest fall through to default category, no parsing
for non-DML statements
*/
+ if (send_prep_stmt(stmt, 0))
+ goto abort;
}
}
DBUG_RETURN(0);
@@ -597,7 +603,7 @@ abort:
*/
static bool parse_prepare_query(PREP_STMT *stmt,
- char *packet, uint length)
+ char *packet, uint length)
{
bool error= 1;
THD *thd= stmt->thd;
@@ -606,15 +612,30 @@ static bool parse_prepare_query(PREP_STMT *stmt,
mysql_log.write(thd,COM_PREPARE,"%s",packet);
mysql_init_query(thd);
thd->prepare_command=true;
- thd->safe_to_cache_query= 0;
+ thd->lex.param_count= 0;
LEX *lex=lex_start(thd, (uchar*) packet, length);
- if (!yyparse() && !thd->fatal_error)
+ lex->safe_to_cache_query= 0;
+ if (!yyparse((void *)thd) && !thd->fatal_error)
error= send_prepare_results(stmt);
lex_end(lex);
DBUG_RETURN(error);
}
+/*
+ Initialize parameter items in statement
+*/
+static bool init_param_items(THD *thd, PREP_STMT *stmt)
+{
+ Item_param **to;
+ if (!(stmt->param= to= (Item_param **)
+ my_malloc(sizeof(Item_param *)*(stmt->param_count+1),
+ MYF(MY_WME))))
+ return 1;
+ List_iterator<Item> param_iterator(thd->lex.param_list);
+ while ((*(to++) = (Item_param *)param_iterator++));
+ return 0;
+}
/*
Parse the query and send the total number of parameters
@@ -648,9 +669,13 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
goto err;
if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),WAIT_PRIOR);
-
- stmt.mem_root= thd->mem_root;
+ my_pthread_setprio(pthread_self(),WAIT_PRIOR);
+
+ if (init_param_items(thd, &stmt))
+ goto err;
+
+ stmt.mem_root= 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);
@@ -685,15 +710,13 @@ void mysql_stmt_execute(THD *thd, char *packet)
/* Check if we got an error when sending long data */
if (stmt->error_in_prepare)
{
- send_error(thd);
+ send_error(thd, stmt->last_errno, stmt->last_error);
DBUG_VOID_RETURN;
}
- if (stmt->param_count && setup_param_fields(thd, stmt))
+ if (stmt->param_count && setup_params_data(stmt))
DBUG_VOID_RETURN;
- MEM_ROOT thd_root= thd->mem_root;
- thd->mem_root = thd->con_root;
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
@@ -703,12 +726,11 @@ void mysql_stmt_execute(THD *thd, char *packet)
mysql_delete(), mysql_update() and mysql_select() to not to
have re-check on setup_* and other things ..
*/
- mysql_execute_command(thd);
+ mysql_execute_command(stmt->thd);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- thd->mem_root= thd_root;
DBUG_VOID_RETURN;
}
@@ -739,8 +761,8 @@ void mysql_stmt_reset(THD *thd, char *packet)
DBUG_VOID_RETURN;
}
- stmt->error_in_prepare=0;
- Item_param *item= stmt->param, *end= item + stmt->param_count;
+ stmt->error_in_prepare= 0;
+ Item_param *item= *stmt->param, *end= item + stmt->param_count;
/* Free long data if used */
if (stmt->long_data_used)
@@ -757,19 +779,19 @@ void mysql_stmt_reset(THD *thd, char *packet)
Delete a prepared statement from memory
*/
-void mysql_stmt_close(THD *thd, char *packet)
+void mysql_stmt_free(THD *thd, char *packet)
{
ulong stmt_id= uint4korr(packet);
PREP_STMT *stmt;
- DBUG_ENTER("mysql_stmt_close");
+ DBUG_ENTER("mysql_stmt_free");
if (!(stmt=find_prepared_statement(thd, stmt_id, "close")))
{
- send_error(thd);
+ send_error(thd); // Not seen by the client
DBUG_VOID_RETURN;
}
- /* Will call free_prep_stmt() */
- tree_delete(&thd->prepared_statements, (void*) stmt, NULL);
+ my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR));
+ tree_delete(&thd->prepared_statements, (void*) &stmt, (void *)0);
thd->last_prepared_stmt=0;
DBUG_VOID_RETURN;
}
@@ -800,17 +822,15 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
DBUG_ENTER("mysql_stmt_get_longdata");
/* The following should never happen */
- if (packet_length < 9)
+ if (packet_length < MYSQL_LONG_DATA_HEADER+1)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata");
DBUG_VOID_RETURN;
}
- pos++; // skip command type at first position
ulong stmt_id= uint4korr(pos);
uint param_number= uint2korr(pos+4);
- uint param_type= uint2korr(pos+6);
- pos+=8; // Point to data
+ pos+= MYSQL_LONG_DATA_HEADER; // Point to data
if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
{
@@ -824,12 +844,15 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
if (param_number >= stmt->param_count)
{
- stmt->error_in_prepare=1;
- stmt->last_errno=ER_WRONG_ARGUMENTS;
+ /* Error will be sent in execute call */
+ stmt->error_in_prepare= 1;
+ stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
DBUG_VOID_RETURN;
}
- stmt->param[param_number].set_longdata(pos, packet_length-9);
+ Item_param *param= *(stmt->param+param_number);
+ param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
stmt->long_data_used= 1;
DBUG_VOID_RETURN;
}
+
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index a9ab1776e19..5b0ec2ec843 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -94,7 +94,7 @@ end:
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 93545d10268..23951cec29f 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -941,7 +941,7 @@ int show_binlog_events(THD* thd)
if (mysql_bin_log.is_open())
{
LEX_MASTER_INFO *lex_mi = &thd->lex.mi;
- uint event_count, limit_start, limit_end;
+ ha_rows event_count, limit_start, limit_end;
my_off_t pos = lex_mi->pos;
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
@@ -1133,7 +1133,8 @@ 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, buffer, block_len,
+ lf_info->log_delayed);
mysql_bin_log.write(&a);
}
else
@@ -1141,7 +1142,7 @@ int log_loaded_block(IO_CACHE* file)
Create_file_log_event c(lf_info->thd,lf_info->ex,lf_info->db,
lf_info->table_name, *lf_info->fields,
lf_info->handle_dup, buffer,
- block_len);
+ block_len, lf_info->log_delayed);
mysql_bin_log.write(&c);
lf_info->wrote_create_file = 1;
DBUG_SYNC_POINT("debug_lock.created_file_event",10);
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 197fd03ec7c..15435382b08 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -43,13 +43,13 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg);
typedef struct st_load_file_info
{
THD* thd;
+ my_off_t last_pos_in_file;
sql_exchange* ex;
List <Item> *fields;
enum enum_duplicates handle_dup;
char* db;
char* table_name;
- bool wrote_create_file;
- my_off_t last_pos_in_file;
+ bool wrote_create_file, log_delayed;
} LOAD_FILE_INFO;
int log_loaded_block(IO_CACHE* file);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 93d48e3e1e0..5b8e2085982 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -57,7 +57,7 @@ static store_key *get_store_key(THD *thd,
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
static void make_join_readinfo(JOIN *join,uint options);
-static void join_free(JOIN *join);
+static void join_free(JOIN *join, bool full);
static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables);
static void update_depend_map(JOIN *join);
static void update_depend_map(JOIN *join, ORDER *order);
@@ -132,7 +132,9 @@ static void read_cached_record(JOIN_TAB *tab);
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &all_fields,ORDER *new_order);
-static ORDER *create_distinct_group(ORDER *order, List<Item> &fields);
+static ORDER *create_distinct_group(THD *thd, ORDER *order,
+ List<Item> &fields,
+ bool *all_order_by_fields_used);
static bool test_if_subpart(ORDER *a,ORDER *b);
static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
@@ -158,7 +160,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
{
int res;
register SELECT_LEX *select_lex = &lex->select_lex;
- fix_tables_pointers(select_lex);
+ fix_tables_pointers(lex->all_selects_list);
if (select_lex->next_select())
res=mysql_union(thd,lex,result);
else
@@ -199,6 +201,26 @@ void fix_tables_pointers(SELECT_LEX *select_lex)
}
}
+/*
+ Inline function to setup clauses without sum functions
+*/
+inline int setup_without_group(THD *thd, TABLE_LIST *tables,
+ List<Item> &fields,
+ List<Item> &all_fields,
+ COND **conds,
+ ORDER *order,
+ ORDER *group, bool *hidden_group_fields)
+{
+ bool save_allow_sum_func= thd->allow_sum_func;
+ thd->allow_sum_func= 0;
+ int res= (setup_conds(thd,tables, conds) ||
+ setup_order(thd,tables, fields, all_fields, order) ||
+ setup_group(thd,tables, fields, all_fields, group,
+ hidden_group_fields));
+ thd->allow_sum_func= save_allow_sum_func;
+ return res;
+}
+
/*****************************************************************************
Check fields, find best join, do the select and output fields.
mysql_select assumes that all tables are already opened
@@ -228,15 +250,13 @@ JOIN::prepare(TABLE_LIST *tables_init,
if (!fake_select_lex)
select_lex->join= this;
union_part= (unit->first_select()->next_select() != 0);
-
+
/* Check that all tables, fields, conds and order are ok */
if (setup_tables(tables_list) ||
setup_fields(thd,tables_list,fields_list,1,&all_fields,1) ||
- setup_conds(thd,tables_list,&conds) ||
- setup_order(thd,tables_list,fields_list,all_fields,order) ||
- setup_group(thd,tables_list,fields_list,all_fields,group_list,
- &hidden_group_fields))
+ setup_without_group(thd, tables_list, fields_list, all_fields,
+ &conds, order, group_list, &hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */
if (having)
@@ -244,7 +264,8 @@ JOIN::prepare(TABLE_LIST *tables_init,
thd->where="having clause";
thd->allow_sum_func=1;
select_lex->having_fix_field= 1;
- bool having_fix_rc= having->fix_fields(thd, tables_list, &having);
+ bool having_fix_rc= (having->check_cols(1) ||
+ having->fix_fields(thd, tables_list, &having));
select_lex->having_fix_field= 0;
if (having_fix_rc || thd->net.report_error)
DBUG_RETURN(-1); /* purecov: inspected */
@@ -324,6 +345,11 @@ JOIN::prepare(TABLE_LIST *tables_init,
this->group= group_list != 0;
row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
unit->select_limit_cnt);
+ /* select_limit is used to decide if we are likely to scan the whole table */
+ select_limit= unit->select_limit_cnt;
+ if (having || (select_options & OPTION_FOUND_ROWS))
+ select_limit= HA_POS_ERROR;
+ do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
this->unit= unit;
#ifdef RESTRICTED_GROUP
@@ -366,20 +392,24 @@ JOIN::optimize()
{
conds->fix_fields(thd, tables_list, &conds);
conds->change_ref_to_fields(thd, tables_list);
+ conds->top_level_item();
having= 0;
}
}
#endif
- conds=optimize_cond(conds,&cond_value);
+ conds= optimize_cond(conds,&cond_value);
if (thd->fatal_error || thd->net.report_error)
{
+ // quick abort
delete procedure;
- error = 0;
- DBUG_RETURN(1);
+ error= thd->fatal_error ? -1 : 1;
+ DBUG_RETURN(error);
}
- if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt)
- { /* Impossible cond */
+
+ if (cond_value == Item::COND_FALSE ||
+ (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
+ { /* Impossible cond */
zero_result_cause= "Impossible WHERE";
DBUG_RETURN(0);
}
@@ -395,31 +425,22 @@ JOIN::optimize()
zero_result_cause= "No matching min/max row";
DBUG_RETURN(0);
}
- if (select_options & SELECT_DESCRIBE)
- {
- select_describe(this, false, false, false,
- "Select tables optimized away");
- delete procedure;
- DBUG_RETURN(1);
- }
- tables_list= 0; // All tables resolved
+ zero_result_cause= "Select tables optimized away";
+ tables_list= 0; // All tables resolved
}
}
if (!tables_list)
- {
- test_function_query= 1;
DBUG_RETURN(0);
- }
- error= -1;
+ error= -1; // Error is sent to client
sort_by_table= get_sort_by_table(order, group_list, tables_list);
/* Calculate how to do the join */
thd->proc_info= "statistics";
if (make_join_statistics(this, tables_list, conds, &keyuse) ||
thd->fatal_error)
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
if (select_lex->dependent)
{
@@ -432,11 +453,14 @@ JOIN::optimize()
found_const_table_map= 0;
}
thd->proc_info= "preparing";
- result->initialize_tables(this);
+ if (result->initialize_tables(this))
+ {
+ DBUG_RETURN(1); // error = -1
+ }
if (const_table_map != found_const_table_map &&
!(select_options & SELECT_DESCRIBE))
{
- zero_result_cause= "";
+ zero_result_cause= "no matching row in const table";
select_options= 0; //TODO why option in return_zero_rows was droped
DBUG_RETURN(0);
}
@@ -444,9 +468,9 @@ JOIN::optimize()
best_read > (double) thd->variables.max_join_size &&
!(select_options & SELECT_DESCRIBE))
{ /* purecov: inspected */
- result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
+ my_message(ER_TOO_BIG_SELECT, ER(ER_TOO_BIG_SELECT), MYF(0));
error= 1; /* purecov: inspected */
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK))
@@ -474,9 +498,9 @@ JOIN::optimize()
select=make_select(*table, const_table_map,
const_table_map, conds, &error);
if (error)
- { /* purecov: inspected */
- error= -1; /* purecov: inspected */
- DBUG_RETURN(-1);
+ { /* purecov: inspected */
+ error= -1; /* purecov: inspected */
+ DBUG_RETURN(1);
}
if (make_join_select(this, select, conds))
{
@@ -494,24 +518,49 @@ JOIN::optimize()
if (! hidden_group_fields)
select_distinct=0;
}
- else if (select_distinct && tables - const_tables == 1 &&
- (unit->select_limit_cnt == HA_POS_ERROR ||
- (select_options & OPTION_FOUND_ROWS) ||
- order &&
- !(skip_sort_order=
- test_if_skip_sort_order(&join_tab[const_tables],
- order,
- unit->select_limit_cnt,
- 1))))
+ else if (select_distinct && tables - const_tables == 1)
{
- if ((group_list= create_distinct_group(order, fields_list)))
- {
- select_distinct= 0;
- no_order= !order;
- group= 1; // For end_write_group
+ /*
+ We are only using one table. In this case we change DISTINCT to a
+ GROUP BY query if:
+ - The GROUP BY can be done through indexes (no sort) and the ORDER
+ BY only uses selected fields.
+ (In this case we can later optimize away GROUP BY and ORDER BY)
+ - We are scanning the whole table without LIMIT
+ This can happen if:
+ - We are using CALC_FOUND_ROWS
+ - We are using an ORDER BY that can't be optimized away.
+
+ We don't want to use this optimization when we are using LIMIT
+ because in this case we can just create a temporary table that
+ holds LIMIT rows and stop when this table is full.
+ */
+ JOIN_TAB *tab= &join_tab[const_tables];
+ bool all_order_fields_used;
+ if (order)
+ skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
+ if ((group_list=create_distinct_group(thd, order, fields_list,
+ &all_order_fields_used)))
+ {
+ bool skip_group= (skip_sort_order &&
+ test_if_skip_sort_order(tab, group_list, select_limit,
+ 1) != 0);
+ if ((skip_group && all_order_fields_used) ||
+ select_limit == HA_POS_ERROR ||
+ (order && !skip_sort_order))
+ {
+ /* Change DISTINCT to GROUP BY */
+ select_distinct= 0;
+ no_order= !order;
+ if (all_order_fields_used)
+ order=0;
+ group=1; // For end_write_group
+ }
+ else
+ group_list= 0;
}
else if (thd->fatal_error) // End of memory
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
group_list= remove_const(this, group_list, conds, &simple_group);
if (!group_list && group)
@@ -595,7 +644,7 @@ JOIN::optimize()
(order && simple_order || group_list && simple_group))
{
if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
- DBUG_RETURN(-1);
+ DBUG_RETURN(1);
}
if (!(select_options & SELECT_BIG_RESULT) &&
@@ -659,23 +708,24 @@ JOIN::exec()
DBUG_ENTER("JOIN::exec");
- if (test_function_query)
+ if (!tables_list)
{ // Only test of functions
error=0;
if (select_options & SELECT_DESCRIBE)
- select_describe(this, false, false, false, "No tables used");
+ select_describe(this, false, false, false,
+ (zero_result_cause?zero_result_cause:"No tables used"));
else
{
result->send_fields(fields_list,1);
if (!having || having->val_int())
{
if (do_send_rows && result->send_data(fields_list))
- {
- result->send_error(0,NullS); /* purecov: inspected */
error= 1;
- }
else
+ {
error= (int) result->send_eof();
+ send_records=1;
+ }
}
else
error=(int) result->send_eof();
@@ -707,11 +757,9 @@ JOIN::exec()
order=group_list;
if (order &&
(const_tables == tables ||
- (simple_order &&
+ ((simple_order || skip_sort_order) &&
test_if_skip_sort_order(&join_tab[const_tables], order,
- (select_options & OPTION_FOUND_ROWS) ?
- HA_POS_ERROR : unit->select_limit_cnt,
- 0))))
+ select_limit, 0))))
order=0;
select_describe(this, need_tmp,
order != 0 && !skip_sort_order,
@@ -738,9 +786,9 @@ JOIN::exec()
group_list : (ORDER*) 0),
group_list ? 0 : select_distinct,
group_list && simple_group,
- (order == 0 || skip_sort_order) &&
- !(select_options & OPTION_FOUND_ROWS),
- select_options, unit)))
+ select_options,
+ (order == 0 || skip_sort_order) ? select_limit :
+ HA_POS_ERROR)))
DBUG_VOID_RETURN;
if (having_list &&
@@ -793,9 +841,10 @@ JOIN::exec()
/* Optimize "select distinct b from t1 order by key_part_1 limit #" */
if (order && skip_sort_order)
{
- (void) test_if_skip_sort_order(&this->join_tab[const_tables],
- order, unit->select_limit_cnt, 0);
- order=0;
+ /* Should always succeed */
+ if (test_if_skip_sort_order(&this->join_tab[const_tables],
+ order, unit->select_limit_cnt, 0))
+ order=0;
}
}
@@ -851,7 +900,7 @@ JOIN::exec()
DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */
- join_free(this);
+ join_free(this, 0);
if (make_simple_join(this, exec_tmp_table))
DBUG_VOID_RETURN;
calc_group_buffer(this, group_list);
@@ -864,9 +913,8 @@ JOIN::exec()
if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields,
(ORDER*) 0,
select_distinct && !group_list,
- 1, 0,
- select_options, unit)))
- DBUG_VOID_RETURN;
+ 1, select_options, HA_POS_ERROR)))
+ DBUG_VOID_RETURN;
if (group_list)
{
thd->proc_info="Creating sort index";
@@ -903,7 +951,7 @@ JOIN::exec()
if (exec_tmp_table->distinct)
select_distinct=0; /* Each row is unique */
- join_free(this); /* Free quick selects */
+ join_free(this, 0); /* Free quick selects */
if (select_distinct && ! group_list)
{
thd->proc_info="Removing duplicates";
@@ -960,6 +1008,7 @@ JOIN::exec()
sort_table_cond)))
DBUG_VOID_RETURN;
table->select_cond=table->select->cond;
+ table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(table->select->cond,
"select and having"););
having_list= make_cond_for_table(having_list, ~ (table_map) 0,
@@ -968,8 +1017,7 @@ JOIN::exec()
}
}
{
- ha_rows select_limit= unit->select_limit_cnt;
- if (having || group || (select_options & OPTION_FOUND_ROWS))
+ if (group)
select_limit= HA_POS_ERROR;
else
{
@@ -981,7 +1029,13 @@ JOIN::exec()
JOIN_TAB *end_table= &join_tab[tables];
for (; table < end_table ; table++)
{
- if (table->select_cond)
+ /*
+ table->keyuse is set in the case there was an original WHERE clause
+ on the table that was optimized away.
+ table->on_expr tells us that it was a LEFT JOIN and there will be
+ at least one row generated from the table.
+ */
+ if (table->select_cond || (table->keyuse && !table->on_expr))
{
/* We have to sort all rows */
select_limit= HA_POS_ERROR;
@@ -997,7 +1051,8 @@ JOIN::exec()
}
having=having_list; // Actually a parameter
thd->proc_info="Sending data";
- error=do_select(this, &fields_list, NULL, procedure);
+ error= thd->net.report_error ||
+ do_select(this, &fields_list, NULL, procedure);
DBUG_VOID_RETURN;
}
@@ -1011,7 +1066,7 @@ JOIN::cleanup(THD *thd)
DBUG_ENTER("JOIN::cleanup");
lock=0; // It's faster to unlock later
- join_free(this);
+ join_free(this, 1);
if (exec_tmp_table)
free_tmp_table(thd, exec_tmp_table);
delete select;
@@ -1037,6 +1092,24 @@ JOIN::cleanup(THD *thd)
DBUG_RETURN(error);
}
+bool JOIN::check_loop(uint id)
+{
+ DBUG_ENTER("JOIN::check_loop");
+ Item *item;
+ List_iterator<Item> it(all_fields);
+ DBUG_PRINT("info", ("all_fields:"));
+ while ((item= it++))
+ if (item->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("where:"));
+ if (select_lex->where && select_lex->where->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_PRINT("info", ("having:"));
+ if (select_lex->having && select_lex->having->check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
int
mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
ORDER *order, ORDER *group,Item *having, ORDER *proc_param,
@@ -1044,9 +1117,10 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
bool fake_select_lex)
{
+ int err;
+ bool free_join= 1;
DBUG_ENTER("mysql_select");
- bool free_join= 1;
JOIN *join;
if (!fake_select_lex && select_lex->join != 0)
{
@@ -1071,17 +1145,34 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
{
DBUG_RETURN(-1);
}
+ if (thd->possible_loops)
+ {
+ Item *item;
+ while(thd->possible_loops->elements)
+ {
+ item= thd->possible_loops->pop();
+ if (item->check_loop(thd->check_loops_counter++))
+ {
+ delete thd->possible_loops;
+ thd->possible_loops= 0;
+ my_message(ER_CYCLIC_REFERENCE, ER(ER_CYCLIC_REFERENCE), MYF(0));
+ return 1;
+ }
+ }
+ delete thd->possible_loops;
+ thd->possible_loops= 0;
+ }
}
- switch (join->optimize())
+ if ((err= join->optimize()))
{
- case 1:
- DBUG_RETURN(join->error);
- case -1:
- goto err;
- }
+ if (err == -1)
+ DBUG_RETURN(join->error);
+ DBUG_ASSERT(err == 1);
+ goto err; // 1
+ }
- if (free_join && join->global_optimize())
+ if (thd->net.report_error || (free_join && join->global_optimize()))
goto err;
join->exec();
@@ -1092,12 +1183,13 @@ err:
thd->limit_found_rows = join->send_records;
thd->examined_row_count = join->examined_rows;
thd->proc_info="end";
- int error= (fake_select_lex?0:join->cleanup(thd)) || thd->net.report_error;
+ err= (fake_select_lex ? join->error : join->cleanup(thd));
+ if (thd->net.report_error)
+ err= -1;
delete join;
- DBUG_RETURN(error);
+ DBUG_RETURN(err);
}
- else
- DBUG_RETURN(0);
+ DBUG_RETURN(join->error);
}
/*****************************************************************************
@@ -1128,13 +1220,21 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
}
+/*
+ Calculate the best possible join and initialize the join structure
+
+ RETURN VALUES
+ 0 ok
+ 1 Fatal error
+*/
+
static bool
make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse_array)
{
int error;
uint i,table_count,const_count,found_ref,refs,key,const_ref,eq_part;
- table_map const_table_map,found_const_table_map,all_table_map;
+ table_map found_const_table_map,all_table_map;
TABLE **table_vector;
JOIN_TAB *stat,*stat_end,*s,**stat_ref;
SQL_SELECT *select;
@@ -1154,7 +1254,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->best_ref=stat_vector;
stat_end=stat+table_count;
- const_table_map=found_const_table_map=all_table_map=0;
+ found_const_table_map=all_table_map=0;
const_count=0;
for (s=stat,i=0 ; tables ; s++,tables=tables->next,i++)
@@ -1245,7 +1345,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DBUG_RETURN(1);
/* Read tables with 0 or 1 rows (system tables) */
- join->const_table_map=const_table_map;
+ join->const_table_map= 0;
for (POSITION *p_pos=join->positions, *p_end=p_pos+const_count;
p_pos < p_end ;
@@ -1282,16 +1382,16 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->dependent) // If dependent on some table
{
// All dep. must be constants
- if (s->dependent & ~(join->const_table_map))
+ if (s->dependent & ~(found_const_table_map))
continue;
if (table->file->records <= 1L &&
!(table->file->table_flags() & HA_NOT_EXACT_COUNT))
{ // system table
- int tmp;
+ int tmp= 0;
s->type=JT_SYSTEM;
join->const_table_map|=table->map;
set_position(join,const_count++,s,(KEYUSE*) 0);
- if ((tmp=join_read_const_table(s,join->positions+const_count-1)))
+ if ((tmp= join_read_const_table(s,join->positions+const_count-1)))
{
if (tmp > 0)
DBUG_RETURN(1); // Fatal error
@@ -1316,7 +1416,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
if (keyuse->val->type() != Item::NULL_ITEM)
{
- if (!((~join->const_table_map) & keyuse->used_tables))
+ if (!((~found_const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
else
refs|=keyuse->used_tables;
@@ -1337,7 +1437,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
join->const_table_map|=table->map;
set_position(join,const_count++,s,start_keyuse);
if (create_ref_for_key(join, s, start_keyuse,
- join->const_table_map))
+ found_const_table_map))
DBUG_RETURN(1);
if ((tmp=join_read_const_table(s,
join->positions+const_count-1)))
@@ -1385,8 +1485,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
ha_rows records;
if (!select)
- select=make_select(s->table, join->const_table_map,
- join->const_table_map,
+ select=make_select(s->table, found_const_table_map,
+ found_const_table_map,
and_conds(conds,s->on_expr),&error);
records=get_quick_record_count(select,s->table, s->const_keys,
join->row_limit);
@@ -1395,7 +1495,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
select->quick=0;
if (records != HA_POS_ERROR)
{
- s->found_records=records;
+ s->records=s->found_records=records;
s->read_time= (ha_rows) (s->quick ? s->quick->read_time : 0.0);
}
}
@@ -1928,7 +2028,7 @@ static void
find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
double read_time)
{
- ulong rec;
+ ha_rows rec;
double tmp;
THD *thd= join->thd;
@@ -2121,7 +2221,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
records
This gives the formula:
records= (x * (b-a) + a*c-b)/(c-1)
-
+
b = records matched by whole key
a = records matched by first key part (10% of all records?)
c = number of key parts in key
@@ -2190,7 +2290,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{ // Check full join
if (s->on_expr)
{
- tmp=s->found_records; // Can't use read cache
+ tmp=rows2double(s->found_records); // Can't use read cache
}
else
{
@@ -2209,11 +2309,11 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
will ensure that this will be used
*/
best=tmp;
- records=s->found_records;
+ records= rows2double(s->found_records);
best_key=0;
}
}
- join->positions[idx].records_read=(double) records;
+ join->positions[idx].records_read= records;
join->positions[idx].key=best_key;
join->positions[idx].table= s;
if (!best_key && idx == join->const_tables &&
@@ -2549,12 +2649,13 @@ get_store_key(THD *thd, KEYUSE *keyuse, table_map used_tables,
bool
store_val_in_field(Field *field,Item *item)
{
+ bool error;
THD *thd=current_thd;
- ulong cuted_fields=thd->cuted_fields;
+ ha_rows cuted_fields=thd->cuted_fields;
thd->count_cuted_fields=1;
- (void) item->save_in_field(field);
+ error= item->save_in_field(field, 1);
thd->count_cuted_fields=0;
- return cuted_fields != thd->cuted_fields;
+ return error || cuted_fields != thd->cuted_fields;
}
@@ -2579,8 +2680,8 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join->sum_funcs=0;
join->send_records=(ha_rows) 0;
join->group=0;
- join->do_send_rows = 1;
join->row_limit=join->unit->select_limit_cnt;
+ join->do_send_rows = (join->row_limit) ? 1 : 0;
join_tab->cache.buff=0; /* No cacheing */
join_tab->table=tmp_table;
@@ -2638,7 +2739,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
use_quick_range=1;
tab->use_quick=1;
tab->ref.key_parts=0; // Don't use ref key.
- join->best_positions[i].records_read=tab->quick->records;
+ join->best_positions[i].records_read= rows2double(tab->quick->records);
}
COND *tmp=make_cond_for_table(cond,used_tables,current_map);
@@ -2899,8 +3000,40 @@ make_join_readinfo(JOIN *join, uint options)
}
+/*
+ Give error if we some tables are done with a full join
+
+ SYNOPSIS
+ error_if_full_join()
+ join Join condition
+
+ USAGE
+ This is used by multi_table_update and multi_table_delete when running
+ in safe mode
+
+ RETURN VALUES
+ 0 ok
+ 1 Error (full join used)
+*/
+
+bool error_if_full_join(JOIN *join)
+{
+ for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
+ tab < end;
+ tab++)
+ {
+ if (tab->type == JT_ALL && (!tab->select || !tab->select->quick))
+ {
+ my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
+ return(1);
+ }
+ }
+ return(0);
+}
+
+
static void
-join_free(JOIN *join)
+join_free(JOIN *join, bool full)
{
JOIN_TAB *tab,*end;
DBUG_ENTER("join_free");
@@ -2913,27 +3046,43 @@ join_free(JOIN *join)
*/
if (join->tables > join->const_tables) // Test for not-const tables
free_io_cache(join->table[join->const_tables]);
- for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ if (join->select_lex->dependent && !full)
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ {
+ if (tab->table)
+ {
+ if (tab->table->key_read)
+ {
+ tab->table->key_read= 0;
+ tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ /* Don't free index if we are using read_record */
+ if (!tab->read_record.table)
+ tab->table->file->index_end();
+ }
+ }
+ else
{
- delete tab->select;
- delete tab->quick;
- x_free(tab->cache.buff);
- if (tab->table)
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
{
- if (tab->table->key_read)
+ delete tab->select;
+ delete tab->quick;
+ x_free(tab->cache.buff);
+ if (tab->table)
{
- tab->table->key_read=0;
- tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ if (tab->table->key_read)
+ {
+ tab->table->key_read= 0;
+ tab->table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ /* Don't free index if we are using read_record */
+ if (!tab->read_record.table)
+ tab->table->file->index_end();
}
- /* Don't free index if we are using read_record */
- if (!tab->read_record.table)
- tab->table->file->index_end();
+ end_read_record(&tab->read_record);
}
- end_read_record(&tab->read_record);
+ join->table= 0;
}
- //TODO: is enough join_free at the end of mysql_select?
- if (!join->select_lex->dependent)
- join->table=0;
}
/*
We are not using tables anymore
@@ -2947,9 +3096,7 @@ join_free(JOIN *join)
}
join->group_fields.delete_elements();
join->tmp_table_param.copy_funcs.delete_elements();
- if (join->tmp_table_param.copy_field) // Because of bug in ecc
- delete [] join->tmp_table_param.copy_field;
- join->tmp_table_param.copy_field=0;
+ join->tmp_table_param.cleanup();
DBUG_VOID_RETURN;
}
@@ -3267,8 +3414,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
if ((tmp2=new COND_CMP(and_father,func)))
save_list->push_back(tmp2);
}
- func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
- func->arguments()[1]->result_type()));
+ func->set_cmp_func();
}
}
else if (left_item->eq(field,0) && right_item != value)
@@ -3288,8 +3434,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
if ((tmp2=new COND_CMP(and_father,func)))
save_list->push_back(tmp2);
}
- func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
- func->arguments()[1]->result_type()));
+ func->set_cmp_func();
}
}
}
@@ -3583,12 +3728,34 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
/****************************************************************************
- Create a temp table according to a field list.
- Set distinct if duplicates could be removed
- Given fields field pointers are changed to point at tmp_table
- for send_fields
+ Create internal temporary table
****************************************************************************/
+/*
+ Create field for temporary table
+
+ SYNOPSIS
+ create_tmp_field()
+ thd Thread handler
+ table Temporary table
+ item Item to create a field for
+ type Type of item (normally item->type)
+ copy_func If set and item is a function, store copy of item
+ in this array
+ group 1 if we are going to do a relative group by on result
+ modify_item 1 if item->result_field should point to new item.
+ This is relevent for how fill_record() is going to
+ work:
+ If modify_item is 1 then fill_record() will update
+ the record in the original table.
+ If modify_item is 0 then fill_record() will update
+ the temporary table
+
+ RETURN
+ 0 on error
+ new_created field
+*/
+
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group, bool modify_item)
@@ -3629,6 +3796,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
item->name,table,item->charset());
return new Field_string(item_sum->max_length,maybe_null,
item->name,table,item->charset());
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
}
thd->fatal_error=1;
@@ -3685,6 +3856,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
new_field= new Field_string(item->max_length,maybe_null,
item->name,table,item->str_value.charset());
break;
+ case ROW_RESULT:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
if (copy_func)
*((*copy_func)++) = (Item_result_field*) item; // Save for copy_funcs
@@ -3698,11 +3873,17 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
}
+/*
+ Create a temp table according to a field list.
+ Set distinct if duplicates could be removed
+ Given fields field pointers are changed to point at tmp_table
+ for send_fields
+*/
+
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, ulong select_options,
- SELECT_LEX_UNIT *unit)
+ ulong select_options, ha_rows rows_limit)
{
TABLE *table;
uint i,field_count,reclength,null_count,null_pack_length,
@@ -3722,9 +3903,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
uint temp_pool_slot=MY_BIT_NONE;
DBUG_ENTER("create_tmp_table");
- DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d allow_distinct_limit: %d group: %d",
+ DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
(int) distinct, (int) save_sum_fields,
- (int) allow_distinct_limit,test(group)));
+ (ulong) rows_limit,test(group)));
statistic_increment(created_tmp_tables, &LOCK_status);
@@ -3773,13 +3954,13 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
NullS))
{
bitmap_clear_bit(&temp_pool, temp_pool_slot);
- DBUG_RETURN(NULL); /* purecov: inspected */
+ DBUG_RETURN(NULL); /* purecov: inspected */
}
if (!(param->copy_field=copy=new Copy_field[field_count]))
{
bitmap_clear_bit(&temp_pool, temp_pool_slot);
- my_free((gptr) table,MYF(0)); /* purecov: inspected */
- DBUG_RETURN(NULL); /* purecov: inspected */
+ my_free((gptr) table,MYF(0)); /* purecov: inspected */
+ DBUG_RETURN(NULL); /* purecov: inspected */
}
param->funcs=copy_func;
strmov(tmpname,path);
@@ -3860,9 +4041,19 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
}
else
{
+ /*
+ The last parameter to create_tmp_field() is a bit tricky:
+
+ We need to set it to 0 in union, to get fill_record() to modify the
+ temporary table.
+ We need to set it to 1 on multi-table-update and in select to
+ write rows to the temporary table.
+ We here distinguish between UNION and multi-table-updates by the fact
+ that in the later case group is set to the row pointer.
+ */
Field *new_field=create_tmp_field(thd, table, item,type, &copy_func,
tmp_from_field, group != 0,
- not_all_columns);
+ not_all_columns || group !=0);
if (!new_field)
{
if (thd->fatal_error)
@@ -3895,7 +4086,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
*blob_field= 0; // End marker
/* If result table is small; use a heap */
- if (blob_count || using_unique_constraint || group_null_items ||
+ if (blob_count || using_unique_constraint ||
(select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES)
{
@@ -4035,6 +4226,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->usable_key_parts=keyinfo->key_parts= param->group_parts;
keyinfo->key_length=0;
keyinfo->rec_per_key=0;
+ keyinfo->algorithm= HA_KEY_ALG_UNDEF;
for (; group ; group=group->next,key_part_info++)
{
Field *field=(*group->item)->tmp_table_field();
@@ -4089,13 +4281,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_pack_length-=hidden_null_pack_length;
keyinfo->key_parts= ((field_count-param->hidden_field_count)+
test(null_pack_length));
- if (allow_distinct_limit)
- {
- set_if_smaller(table->max_rows, unit->select_limit_cnt);
- param->end_write_records= unit->select_limit_cnt;
- }
- else
- param->end_write_records= HA_POS_ERROR;
+ set_if_smaller(table->max_rows, rows_limit);
+ param->end_write_records= rows_limit;
table->distinct=1;
table->keys=1;
if (blob_count)
@@ -4111,6 +4298,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
keyinfo->key_length=(uint16) reclength;
keyinfo->name=(char*) "tmp";
+ keyinfo->algorithm= HA_KEY_ALG_UNDEF;
if (null_pack_length)
{
key_part_info->null_bit=0;
@@ -4176,7 +4364,6 @@ static bool open_tmp_table(TABLE *table)
table->db_stat=0;
return(1);
}
- /* VOID(ha_lock(table,F_WRLCK)); */ /* Single thread table */
(void) table->file->extra(HA_EXTRA_QUICK); /* Faster */
return(0);
}
@@ -4231,9 +4418,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
{
Field *field=keyinfo->key_part[i].field;
seg->flag= 0;
- seg->language= field->binary() ? MY_CHARSET_CURRENT :
- ((Field_str*)field)->charset()->number;
-
+ seg->language= field->charset()->number;
seg->length= keyinfo->key_part[i].length;
seg->start= keyinfo->key_part[i].offset;
if (field->flags & BLOB_FLAG)
@@ -4331,12 +4516,11 @@ free_tmp_table(THD *thd, TABLE *entry)
* If a HEAP table gets full, create a MyISAM table and copy all rows to this
*/
-bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
- bool ignore_last_dupp_key_error)
+bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+ int error, bool ignore_last_dupp_key_error)
{
TABLE new_table;
const char *save_proc_info;
- THD *thd=current_thd;
int write_err;
DBUG_ENTER("create_myisam_from_heap");
@@ -4494,7 +4678,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
error=0;
if (!table) // If sending data to client
{
- join_free(join); // Unlock all cursors
+ join_free(join, 0); // Unlock all cursors
if (join->result->send_eof())
error= 1; // Don't send error
}
@@ -4516,7 +4700,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
if (error == -1)
table->file->print_error(my_errno,MYF(0));
}
- DBUG_RETURN(error);
+ DBUG_RETURN(error || join->thd->net.report_error);
}
@@ -5312,7 +5496,8 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (error == HA_ERR_FOUND_DUPP_KEY ||
error == HA_ERR_FOUND_DUPP_UNIQUE)
goto end;
- if (create_myisam_from_heap(table, &join->tmp_table_param, error,1))
+ if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
+ error,1))
DBUG_RETURN(-1); // Not a table_is_full error
table->uniques=0; // To ensure rows are the same
}
@@ -5389,7 +5574,8 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_funcs(join->tmp_table_param.funcs);
if ((error=table->file->write_row(table->record[0])))
{
- if (create_myisam_from_heap(table, &join->tmp_table_param, error, 0))
+ if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
+ error, 0))
DBUG_RETURN(-1); // Not a table_is_full error
/* Change method to update rows */
table->file->index_init(0);
@@ -5483,7 +5669,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if ((error=table->file->write_row(table->record[0])))
{
- if (create_myisam_from_heap(table, &join->tmp_table_param,
+ if (create_myisam_from_heap(join->thd, table,
+ &join->tmp_table_param,
error, 0))
DBUG_RETURN(-1); // Not a table_is_full error
}
@@ -5496,6 +5683,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
else
{
+ if (end_of_records)
+ DBUG_RETURN(0);
join->first_record=1;
VOID(test_if_group_changed(join->group_fields));
}
@@ -5565,6 +5754,7 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
{
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
{
+ /* Create new top level AND item */
Item_cond_and *new_cond=new Item_cond_and;
if (!new_cond)
return (COND*) 0; // OOM /* purecov: inspected */
@@ -5602,6 +5792,7 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
new_cond->argument_list()->push_back(fix);
}
new_cond->used_tables_cache=((Item_cond_or*) cond)->used_tables_cache;
+ new_cond->top_level_item();
return new_cond;
}
}
@@ -5641,6 +5832,9 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
static Item *
part_of_refkey(TABLE *table,Field *field)
{
+ if (!table->reginfo.join_tab)
+ return (Item*) 0; // field from outer non-select (UPDATE,...)
+
uint ref_parts=table->reginfo.join_tab->ref.key_parts;
if (ref_parts)
{
@@ -5856,12 +6050,32 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
-/*****************************************************************************
+/*
If not selecting by given key, create an index how records should be read
- return: 0 ok
- -1 some fatal error
- 1 no records
-*****************************************************************************/
+
+ SYNOPSIS
+ create_sort_index()
+ thd Thread handler
+ tab Table to sort (in join structure)
+ order How table should be sorted
+ filesort_limit Max number of rows that needs to be sorted
+ select_limit Max number of rows in final output
+ Used to decide if we should use index or not
+
+
+ IMPLEMENTATION
+ - If there is an index that can be used, 'tab' is modified to use
+ this index.
+ - If no index, create with filesort() an index file that can be used to
+ retrieve rows in order (should be done with 'read_record').
+ The sorted data is stored in tab->table and will be freed when calling
+ free_io_cache(tab->table).
+
+ RETURN VALUES
+ 0 ok
+ -1 Some fatal error
+ 1 No records
+*/
static int
create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
@@ -5953,6 +6167,7 @@ static bool fix_having(JOIN *join, Item **having)
sort_table_cond)))
return 1;
table->select_cond=table->select->cond;
+ table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(table->select_cond,
"select and having"););
*having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
@@ -6566,7 +6781,9 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
return 0;
}
order->in_field_list=0;
- if ((*order->item)->fix_fields(thd, tables, order->item) || thd->fatal_error)
+ Item *it= *order->item;
+ if (it->check_cols(1) || it->fix_fields(thd, tables, order->item) ||
+ thd->fatal_error)
return 1; // Wrong field
all_fields.push_front(*order->item); // Add new field to field list
order->item=(Item**) all_fields.head_ref();
@@ -6679,12 +6896,14 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
*/
static ORDER *
-create_distinct_group(ORDER *order_list,List<Item> &fields)
+create_distinct_group(THD *thd, ORDER *order_list, List<Item> &fields,
+ bool *all_order_by_fields_used)
{
List_iterator<Item> li(fields);
Item *item;
ORDER *order,*group,**prev;
+ *all_order_by_fields_used= 1;
while ((item=li++))
item->marker=0; /* Marker that field is not used */
@@ -6693,13 +6912,15 @@ create_distinct_group(ORDER *order_list,List<Item> &fields)
{
if (order->in_field_list)
{
- ORDER *ord=(ORDER*) sql_memdup(order,sizeof(ORDER));
+ ORDER *ord=(ORDER*) thd->memdup((char*) order,sizeof(ORDER));
if (!ord)
return 0;
*prev=ord;
prev= &ord->next;
(*ord->item)->marker=1;
}
+ else
+ *all_order_by_fields_used= 0;
}
li.rewind();
@@ -6709,7 +6930,7 @@ create_distinct_group(ORDER *order_list,List<Item> &fields)
continue;
if (!item->marker)
{
- ORDER *ord=(ORDER*) sql_calloc(sizeof(ORDER));
+ ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER));
if (!ord)
return 0;
ord->item=li.ref();
@@ -7161,7 +7382,7 @@ copy_sum_funcs(Item_sum **func_ptr)
{
Item_sum *func;
for (; (func = *func_ptr) ; func_ptr++)
- (void) func->save_in_field(func->result_field);
+ (void) func->save_in_field(func->result_field, 1);
return;
}
@@ -7192,7 +7413,7 @@ copy_funcs(Item_result_field **func_ptr)
{
Item_result_field *func;
for (; (func = *func_ptr) ; func_ptr++)
- (void) func->save_in_field(func->result_field);
+ (void) func->save_in_field(func->result_field, 1);
return;
}
@@ -7381,56 +7602,32 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
if (tab->use_quick == 2)
{
- sprintf(buff_ptr,"range checked for each record (index map: %u)",
+ sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
tab->keys);
buff_ptr=strend(buff_ptr);
}
else
- buff_ptr=strmov(buff_ptr,"where used");
+ buff_ptr=strmov(buff_ptr,"; Using where");
}
if (key_read)
- {
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Using index");
- }
+ buff_ptr= strmov(buff_ptr,"; Using index");
if (table->reginfo.not_exists_optimize)
- {
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Not exists");
- }
+ buff_ptr= strmov(buff_ptr,"; Not exists");
if (need_tmp_table)
{
need_tmp_table=0;
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Using temporary");
+ buff_ptr= strmov(buff_ptr,"; Using temporary");
}
if (need_order)
{
need_order=0;
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Using filesort");
+ buff_ptr= strmov(buff_ptr,"; Using filesort");
}
if (distinct & test_all_bits(used_tables,thd->used_tables))
- {
- if (buff != buff_ptr)
- {
- buff_ptr[0]=';' ; buff_ptr[1]=' '; buff_ptr+=2;
- }
- buff_ptr=strmov(buff_ptr,"Distinct");
- }
- item_list.push_back(new Item_string(buff,(uint) (buff_ptr - buff),
+ buff_ptr= strmov(buff_ptr,"; Distinct");
+ if (buff_ptr == buff)
+ buff_ptr+= 2; // Skip inital "; "
+ item_list.push_back(new Item_string(buff+2,(uint) (buff_ptr - buff)-2,
default_charset_info));
// For next iteration
used_tables|=table->map;
@@ -7459,11 +7656,13 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
{
res= mysql_explain_select(thd, sl,
(((&thd->lex.select_lex)==sl)?
- ((sl->next_select_in_list())?"PRIMARY":
+ ((thd->lex.all_selects_list != sl)?"PRIMARY":
"SIMPLE"):
((sl == first)?
+ ((sl->linkage == DERIVED_TABLE_TYPE) ?
+ "DERIVED":
((sl->dependent)?"DEPENDENT SUBSELECT":
- "SUBSELECT"):
+ "SUBSELECT")):
((sl->dependent)?"DEPENDENT UNION":
"UNION"))),
result);
@@ -7471,8 +7670,8 @@ int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
break;
}
- if (res > 0)
- res= -res; // mysql_explain_select do not report error
+ if (res > 0 || thd->net.report_error)
+ res= -1; // mysql_explain_select do not report error
DBUG_RETURN(res);
}
diff --git a/sql/sql_select.h b/sql/sql_select.h
index c5b5357be50..1fbe2052831 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -115,7 +115,8 @@ typedef struct st_position { /* Used in find_best */
/* Param to create temporary tables when doing SELECT:s */
-class TMP_TABLE_PARAM {
+class TMP_TABLE_PARAM :public Sql_alloc
+{
public:
List<Item> copy_funcs;
List_iterator_fast<Item> copy_funcs_it;
@@ -159,7 +160,7 @@ class JOIN :public Sql_alloc
bool sort_and_group,first_record,full_join,group, no_field_update;
bool do_send_rows;
table_map const_table_map,found_const_table_map,outer_join;
- ha_rows send_records,found_records,examined_rows,row_limit;
+ ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read;
List<Item> *fields;
@@ -195,7 +196,6 @@ class JOIN :public Sql_alloc
SQL_SELECT *select; //created in optimisation phase
TABLE *exec_tmp_table; //used in 'exec' to hold temporary
- my_bool test_function_query; // need to return select items 1 row
const char *zero_result_cause; // not 0 if exec must return zero result
my_bool union_part; // this subselect is part of union
@@ -227,7 +227,6 @@ class JOIN :public Sql_alloc
error(0),
select(0),
exec_tmp_table(0),
- test_function_query(0),
zero_result_cause(0)
{
fields_list = fields;
@@ -244,7 +243,8 @@ class JOIN :public Sql_alloc
int global_optimize();
int reinit();
void exec();
- int cleanup(THD *thd);
+ int cleanup(THD *thd);
+ bool check_loop(uint id);
};
@@ -259,16 +259,15 @@ void TEST_join(JOIN *join);
bool store_val_in_field(Field *field,Item *val);
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, ulong select_options,
- SELECT_LEX_UNIT *unit);
+ ulong select_options, ha_rows rows_limit);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item_result_field **func_ptr);
-bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
- bool ignore_last_dupp_error);
+bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+ int error, bool ignore_last_dupp_error);
/* functions from opt_sum.cc */
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
@@ -320,12 +319,12 @@ class store_key_field: public store_key
copy_field.set(to_field,from_field,0);
}
}
- bool copy()
- {
- copy_field.do_copy(&copy_field);
- return err != 0;
- }
- const char *name() const { return field_name; }
+ bool copy()
+ {
+ copy_field.do_copy(&copy_field);
+ return err != 0;
+ }
+ const char *name() const { return field_name; }
};
@@ -342,8 +341,7 @@ public:
{}
bool copy()
{
- (void) item->save_in_field(to_field);
- return err != 0;
+ return item->save_in_field(to_field, 1) || err != 0;
}
const char *name() const { return "func"; }
};
@@ -366,7 +364,8 @@ public:
if (!inited)
{
inited=1;
- (void)item->save_in_field(to_field);
+ if (item->save_in_field(to_field, 1))
+ err= 1;
}
return err != 0;
}
@@ -374,3 +373,4 @@ public:
};
bool cp_buffer_from_ref(TABLE_REF *ref);
+bool error_if_full_join(JOIN *join);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index d6fe2f3772a..ebf5b210d6c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -889,7 +889,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
field_list.push_back(new Item_empty_string("Column_name",NAME_LEN));
field_list.push_back(item=new Item_empty_string("Collation",1));
item->maybe_null=1;
- field_list.push_back(item=new Item_int("Cardinality",0,11));
+ field_list.push_back(item=new Item_int("Cardinality",0,21));
item->maybe_null=1;
field_list.push_back(item=new Item_int("Sub_part",0,3));
item->maybe_null=1;
@@ -930,8 +930,8 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
KEY *key=table->key_info+i;
if (key->rec_per_key[j])
{
- ulong records=(table->file->records / key->rec_per_key[j]);
- end=int10_to_str((long) records, buff, 10);
+ ha_rows records=(table->file->records / key->rec_per_key[j]);
+ end=longlong10_to_str((longlong) records, buff, 10);
net_store_data(packet,convert,buff,(uint) (end-buff));
}
else
@@ -1140,6 +1140,10 @@ store_create_info(THD *thd, TABLE *table, String *packet)
if (!found_primary)
append_identifier(thd,packet,key_info->name);
+ if (table->db_type == DB_TYPE_HEAP &&
+ key_info->algorithm == HA_KEY_ALG_BTREE)
+ packet->append(" USING BTREE", 12);
+
// +BAR: send USING only in non-default case: non-spatial rtree
if((key_info->algorithm == HA_KEY_ALG_RTREE) &&
!(key_info->flags & HA_SPATIAL))
@@ -1424,7 +1428,7 @@ int mysqld_show_charsets(THD *thd, const char *wild)
net_store_data(&packet2,convert,cs[0]->name);
net_store_data(&packet2,(uint32) cs[0]->number);
net_store_data(&packet2,(uint32) cs[0]->strxfrm_multiply);
- net_store_data(&packet2,(uint32) (cs[0]->mbmaxlen ? cs[0]->mbmaxlen : 1));
+ net_store_data(&packet2,(uint32) (cs[0]->mbmaxlen));
if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
goto err;
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 1276020e3c3..51b2386ae62 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -93,18 +93,22 @@ bool String::realloc(uint32 alloc_length)
bool String::set(longlong num, CHARSET_INFO *cs)
{
- if (alloc(21))
+ uint l=20*cs->mbmaxlen+1;
+
+ if (alloc(l))
return TRUE;
- str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
+ str_length=(uint32) cs->ll10tostr(cs,Ptr,l,-10,num);
str_charset=cs;
return FALSE;
}
bool String::set(ulonglong num, CHARSET_INFO *cs)
{
- if (alloc(21))
+ uint l=20*cs->mbmaxlen+1;
+
+ if (alloc(l))
return TRUE;
- str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
+ str_length=(uint32) cs->ll10tostr(cs,Ptr,l,10,num);
str_charset=cs;
return FALSE;
}
@@ -117,14 +121,14 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs)
if (decimals >= NOT_FIXED_DEC)
{
sprintf(buff,"%.14g",num); // Enough for a DATETIME
- return copy(buff, (uint32) strlen(buff));
+ return copy(buff, (uint32) strlen(buff), my_charset_latin1, cs);
}
#ifdef HAVE_FCONVERT
int decpt,sign;
char *pos,*to;
VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1));
- if (!my_isdigit(system_charset_info, buff[1]))
+ if (!my_isdigit(my_charset_latin1, buff[1]))
{ // Nan or Inf
pos=buff+1;
if (sign)
@@ -132,7 +136,7 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs)
buff[0]='-';
pos=buff;
}
- return copy(pos,(uint32) strlen(pos));
+ return copy(pos,(uint32) strlen(pos), my_charset_latin1, cs);
}
if (alloc((uint32) ((uint32) decpt+3+decimals)))
return TRUE;
@@ -182,7 +186,7 @@ end:
#else
sprintf(buff,"%.*f",(int) decimals,num);
#endif
- return copy(buff,(uint32) strlen(buff));
+ return copy(buff,(uint32) strlen(buff), my_charset_latin1, cs);
#endif
}
@@ -208,13 +212,63 @@ bool String::copy(const String &str)
return FALSE;
}
-bool String::copy(const char *str,uint32 arg_length)
+bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs)
{
if (alloc(arg_length))
return TRUE;
if ((str_length=arg_length))
memcpy(Ptr,str,arg_length);
Ptr[arg_length]=0;
+ str_charset=cs;
+ return FALSE;
+}
+
+/* Copy with charset convertion */
+bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET_INFO *to)
+{
+ uint32 new_length=to->mbmaxlen*arg_length;
+ int cnvres;
+ my_wc_t wc;
+ const uchar *s=(const uchar *)str;
+ const uchar *se=s+arg_length;
+ uchar *d, *de;
+
+ if (alloc(new_length))
+ return TRUE;
+
+ d=(uchar *)Ptr;
+ de=d+new_length;
+
+ for (str_length=new_length ; s < se && d < de ; )
+ {
+ if ((cnvres=from->mb_wc(from,&wc,s,se)) > 0 )
+ {
+ s+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILSEQ)
+ {
+ s++;
+ wc='?';
+ }
+ else
+ break;
+
+outp:
+ if((cnvres=to->wc_mb(to,wc,d,de)) >0 )
+ {
+ d+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILUNI && wc!='?')
+ {
+ wc='?';
+ goto outp;
+ }
+ else
+ break;
+ }
+ Ptr[new_length]=0;
+ length((uint32) (d-(uchar *)Ptr));
+ str_charset=to;
return FALSE;
}
@@ -603,261 +657,5 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
return to;
}
-/* Make it easier to handle different charactersets */
-
-#ifdef USE_MB
-#define INC_PTR(cs,A,B) A+=((use_mb_flag && \
- my_ismbchar(cs,A,B)) ? my_ismbchar(cs,A,B) : 1)
-#else
-#define INC_PTR(cs,A,B) A++
-#endif
-
-/*
-** Compare string against string with wildcard
-** 0 if matched
-** -1 if not matched with wildcard
-** 1 if matched with wildcard
-*/
-
-#ifdef LIKE_CMP_TOUPPER
-#define likeconv(s,A) (uchar) my_toupper(s,A)
-#else
-#define likeconv(s,A) (uchar) (s)->sort_order[(uchar) (A)]
-#endif
-
-int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *str_end,
- const char *wildstr,const char *wildend,
- char escape)
-{
- int result= -1; // Not found, using wildcards
-#ifdef USE_MB
- bool use_mb_flag=use_mb(cs);
-#endif
- while (wildstr != wildend)
- {
- while (*wildstr != wild_many && *wildstr != wild_one)
- {
- if (*wildstr == escape && wildstr+1 != wildend)
- wildstr++;
-#ifdef USE_MB
- int l;
- if (use_mb_flag &&
- (l = my_ismbchar(cs, wildstr, wildend)))
- {
- if (str+l > str_end || memcmp(str, wildstr, l) != 0)
- return 1;
- str += l;
- wildstr += l;
- }
- else
-#endif
- if (str == str_end || likeconv(cs,*wildstr++) != likeconv(cs,*str++))
- return(1); // No match
- if (wildstr == wildend)
- return (str != str_end); // Match if both are at end
- result=1; // Found an anchor char
- }
- if (*wildstr == wild_one)
- {
- do
- {
- if (str == str_end) // Skip one char if possible
- return (result);
- INC_PTR(cs,str,str_end);
- } while (++wildstr < wildend && *wildstr == wild_one);
- if (wildstr == wildend)
- break;
- }
- if (*wildstr == wild_many)
- { // Found wild_many
- wildstr++;
- /* Remove any '%' and '_' from the wild search string */
- for (; wildstr != wildend ; wildstr++)
- {
- if (*wildstr == wild_many)
- continue;
- if (*wildstr == wild_one)
- {
- if (str == str_end)
- return (-1);
- INC_PTR(cs,str,str_end);
- continue;
- }
- break; // Not a wild character
- }
- if (wildstr == wildend)
- return(0); // Ok if wild_many is last
- if (str == str_end)
- return -1;
-
- uchar cmp;
- if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
- cmp= *++wildstr;
-#ifdef USE_MB
- const char* mb = wildstr;
- int mblen;
- LINT_INIT(mblen);
- if (use_mb_flag)
- mblen = my_ismbchar(cs, wildstr, wildend);
-#endif
- INC_PTR(cs,wildstr,wildend); // This is compared trough cmp
- cmp=likeconv(cs,cmp);
- do
- {
-#ifdef USE_MB
- if (use_mb_flag)
- {
- for (;;)
- {
- if (str >= str_end)
- return -1;
- if (mblen)
- {
- if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0)
- {
- str += mblen;
- break;
- }
- }
- else if (!my_ismbchar(cs, str, str_end) &&
- likeconv(cs,*str) == cmp)
- {
- str++;
- break;
- }
- INC_PTR(cs,str, str_end);
- }
- }
- else
- {
-#endif /* USE_MB */
- while (str != str_end && likeconv(cs,*str) != cmp)
- str++;
- if (str++ == str_end) return (-1);
-#ifdef USE_MB
- }
-#endif
- {
- int tmp=wild_case_compare(cs,str,str_end,wildstr,wildend,escape);
- if (tmp <= 0)
- return (tmp);
- }
- } while (str != str_end && wildstr[0] != wild_many);
- return(-1);
- }
- }
- return (str != str_end ? 1 : 0);
-}
-
-
-int wild_case_compare(String &match,String &wild, char escape)
-{
- DBUG_ENTER("wild_case_compare");
- DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
- ,match.ptr(),wild.ptr(),escape));
- DBUG_RETURN(wild_case_compare(match.str_charset,match.ptr(),match.ptr()+match.length(),
- wild.ptr(), wild.ptr()+wild.length(),escape));
-}
-
-/*
-** The following is used when using LIKE on binary strings
-*/
-
-int wild_compare(const char *str,const char *str_end,
- const char *wildstr,const char *wildend,char escape)
-{
- DBUG_ENTER("wild_compare");
- DBUG_PRINT("enter",("str='%s', str_end='%s', wildstr='%s', wildend='%s', escape='%c'"
- ,str,str_end,wildstr,wildend,escape));
- int result= -1; // Not found, using wildcards
- while (wildstr != wildend)
- {
- while (*wildstr != wild_many && *wildstr != wild_one)
- {
- if (*wildstr == escape && wildstr+1 != wildend)
- wildstr++;
- if (str == str_end || *wildstr++ != *str++)
- {
- DBUG_RETURN(1);
- }
- if (wildstr == wildend)
- {
- DBUG_RETURN(str != str_end); // Match if both are at end
- }
- result=1; // Found an anchor char
- }
- if (*wildstr == wild_one)
- {
- do
- {
- if (str == str_end) // Skip one char if possible
- DBUG_RETURN(result);
- str++;
- } while (*++wildstr == wild_one && wildstr != wildend);
- if (wildstr == wildend)
- break;
- }
- if (*wildstr == wild_many)
- { // Found wild_many
- wildstr++;
- /* Remove any '%' and '_' from the wild search string */
- for (; wildstr != wildend ; wildstr++)
- {
- if (*wildstr == wild_many)
- continue;
- if (*wildstr == wild_one)
- {
- if (str == str_end)
- {
- DBUG_RETURN(-1);
- }
- str++;
- continue;
- }
- break; // Not a wild character
- }
- if (wildstr == wildend)
- {
- DBUG_RETURN(0); // Ok if wild_many is last
- }
- if (str == str_end)
- {
- DBUG_RETURN(-1);
- }
- char cmp;
- if ((cmp= *wildstr) == escape && wildstr+1 != wildend)
- cmp= *++wildstr;
- wildstr++; // This is compared trough cmp
- do
- {
- while (str != str_end && *str != cmp)
- str++;
- if (str++ == str_end)
- {
- DBUG_RETURN(-1);
- }
- {
- int tmp=wild_compare(str,str_end,wildstr,wildend,escape);
- if (tmp <= 0)
- {
- DBUG_RETURN(tmp);
- }
- }
- } while (str != str_end && wildstr[0] != wild_many);
- DBUG_RETURN(-1);
- }
- }
- DBUG_RETURN(str != str_end ? 1 : 0);
-}
-
-
-int wild_compare(String &match,String &wild, char escape)
-{
- DBUG_ENTER("wild_compare");
- DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
- ,match.ptr(),wild.ptr(),escape));
- DBUG_RETURN(wild_compare(match.ptr(),match.ptr()+match.length(),
- wild.ptr(), wild.ptr()+wild.length(),escape));
-}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index c881cb22c5c..dde67b11d50 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -28,8 +28,6 @@ class String;
int sortcmp(const String *a,const String *b);
int stringcmp(const String *a,const String *b);
String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
-int wild_case_compare(String &match,String &wild,char escape);
-int wild_compare(String &match,String &wild,char escape);
class String
{
@@ -74,7 +72,7 @@ public:
{ sql_element_free(ptr_arg); }
~String() { free(); }
- inline void set_charset(CHARSET_INFO *charset) { str_charset=charset; }
+ inline void set_charset(CHARSET_INFO *charset) { str_charset= charset; }
inline CHARSET_INFO *charset() const { return str_charset; }
inline uint32 length() const { return str_length;}
inline uint32 alloced_length() const { return Alloced_length;}
@@ -178,7 +176,9 @@ public:
bool copy(); // Alloc string if not alloced
bool copy(const String &s); // Allocate new string
- bool copy(const char *s,uint32 arg_length); // Allocate new string
+ bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string
+ bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
+ CHARSET_INFO *csto);
bool append(const String &s);
bool append(const char *s,uint32 arg_length=0);
bool append(IO_CACHE* file, uint32 arg_length);
@@ -207,8 +207,6 @@ public:
friend int sortcmp(const String *a,const String *b);
friend int stringcmp(const String *a,const String *b);
friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
- friend int wild_case_compare(String &match,String &wild,char escape);
- friend int wild_compare(String &match,String &wild,char escape);
uint32 numchars();
int charpos(int i,uint32 offset=0);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5187351258e..d343ccd39f5 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -110,6 +110,17 @@ int mysql_rm_table_part2_with_lock(THD *thd,
return error;
}
+/*
+ TODO:
+ When logging to the binary log, we should log
+ tmp_tables and transactional tables as separate statements if we
+ are in a transaction; This is needed to get these tables into the
+ cached binary log that is only written on COMMIT.
+
+ The current code only writes DROP statements that only uses temporary
+ tables to the cache binary log. This should be ok on most cases, but
+ not all.
+*/
int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
bool dont_log_query)
@@ -119,7 +130,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
String wrong_tables;
db_type table_type;
int error;
- bool some_tables_deleted=0;
+ bool some_tables_deleted=0, tmp_table_deleted=0;
DBUG_ENTER("mysql_rm_table_part2");
for (table=tables ; table ; table=table->next)
@@ -127,7 +138,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
char *db=table->db ? table->db : thd->db;
if (!close_temporary_table(thd, db, table->real_name))
{
- some_tables_deleted=1; // Log query
+ tmp_table_deleted=1;
continue; // removed temporary table
}
@@ -143,8 +154,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
DBUG_RETURN(-1);
/* remove form file and isam files */
- (void) sprintf(path,"%s/%s/%s%s",mysql_data_home,db,table->real_name,
- reg_ext);
+ strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext,
+ NullS);
(void) unpack_filename(path,path);
error=0;
@@ -152,8 +163,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (access(path,F_OK))
{
- if (!if_exists)
- error=1;
+ if (if_exists)
+ store_warning(thd, ER_BAD_TABLE_ERROR, table->real_name);
+ else
+ error= 1;
}
else
{
@@ -177,7 +190,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
wrong_tables.append(String(table->real_name,default_charset_info));
}
}
- if (some_tables_deleted)
+ if (some_tables_deleted || tmp_table_deleted)
{
query_cache_invalidate3(thd, tables, 0);
if (!dont_log_query)
@@ -185,7 +198,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ tmp_table_deleted && !some_tables_deleted);
mysql_bin_log.write(&qinfo);
}
}
@@ -271,7 +285,8 @@ static int sort_keys(KEY *a, KEY *b)
create_info Create information (like MAX_ROWS)
fields List of fields to create
keys List of keys to create
- tmp_table Set to 1 if this is a temporary table
+ tmp_table Set to 1 if this is an internal temporary table
+ (From ALTER TABLE)
no_log Don't log the query to binary log.
DESCRIPTION
@@ -523,19 +538,19 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_iterator.rewind();
key_number=0;
- for (; (key=key_iterator++) ; key_info++, key_number++)
+ for (; (key=key_iterator++) ; key_number++)
{
uint key_length=0;
key_part_spec *column;
switch(key->type){
- case Key::MULTIPLE:
+ case Key::MULTIPLE:
key_info->flags = 0;
break;
- case Key::FULLTEXT:
+ case Key::FULLTEXT:
key_info->flags = HA_FULLTEXT;
break;
- case Key::SPATIAL:
+ case Key::SPATIAL:
key_info->flags = HA_SPATIAL;
break;
case Key::FOREIGN_KEY:
@@ -734,6 +749,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length);
DBUG_RETURN(-1);
}
+ key_info++;
}
if (!unique_key && !primary_key &&
(file->table_flags() & HA_REQUIRE_PRIMARY_KEY))
@@ -783,7 +799,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
thd->proc_info="creating table";
- create_info->create_statement = thd->query;
create_info->table_options=db_options;
if (rea_create_table(thd, path, create_info, fields, key_count,
key_info_buffer))
@@ -791,16 +806,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
/* my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,my_errno); */
goto end;
}
- if (!tmp_table && !no_log)
- {
- // Must be written before unlock
- mysql_update_log.write(thd,thd->query, thd->query_length);
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length);
- mysql_bin_log.write(&qinfo);
- }
- }
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
{
/* Open table and put in temporary table list */
@@ -810,6 +815,18 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
goto end;
}
}
+ if (!tmp_table && !no_log)
+ {
+ // Must be written before unlock
+ mysql_update_log.write(thd,thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ test(create_info->options &
+ HA_LEX_CREATE_TMP_TABLE));
+ mysql_bin_log.write(&qinfo);
+ }
+ }
error=0;
end:
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -1254,8 +1271,13 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
switch (result_code) {
case HA_ADMIN_NOT_IMPLEMENTED:
- net_store_data(packet, "error");
- net_store_data(packet, ER(ER_CHECK_NOT_IMPLEMENTED));
+ {
+ char buf[ERRMSGSIZE+20];
+ my_snprintf(buf, ERRMSGSIZE,
+ ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
+ net_store_data(packet, "error");
+ net_store_data(packet, buf);
+ }
break;
case HA_ADMIN_OK:
@@ -1510,7 +1532,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_update_log.write(thd, thd->query, thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
@@ -1865,8 +1887,14 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* We changed a temporary table */
if (error)
{
+ /*
+ * The following function call will also free a
+ * new_table pointer.
+ * Therefore, here new_table pointer is not free'd as it is
+ * free'd in close_temporary() which is called by by the
+ * close_temporary_table() function.
+ */
close_temporary_table(thd,new_db,tmp_name);
- my_free((gptr) new_table,MYF(0));
goto err;
}
/* Close lock if this is a transactional table */
@@ -1886,7 +1914,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
goto end_temporary;
@@ -2015,7 +2043,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
mysql_update_log.write(thd, thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
VOID(pthread_cond_broadcast(&COND_refresh));
@@ -2186,7 +2214,6 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (to->file->external_lock(thd,F_UNLCK))
error=1;
err:
- tmp_error = ha_recovery_logging(thd,TRUE);
free_io_cache(from);
*copied= found_count;
*deleted=delete_count;
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index b3bf47e7fd2..3fbeaa753db 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -41,6 +41,7 @@ static const char *lock_descriptions[] =
"High priority write lock",
"Highest priority write lock"
};
+extern HASH open_cache;
#ifndef DBUG_OFF
@@ -64,7 +65,6 @@ print_where(COND *cond,const char *info)
}
/* This is for debugging purposes */
-extern HASH open_cache;
extern TABLE *unused_tables;
void print_cached_tables(void)
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index f45eca0b65f..51d43b41833 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -98,8 +98,8 @@ static void init_syms(udf_func *tmp)
}
}
-static byte* get_hash_key(const byte *buff,uint *length,
- my_bool not_used __attribute__((unused)))
+extern "C" byte* get_hash_key(const byte *buff,uint *length,
+ my_bool not_used __attribute__((unused)))
{
udf_func *udf=(udf_func*) buff;
*length=(uint) udf->name_length;
@@ -203,6 +203,8 @@ void udf_init()
new_thd->version--; // Force close to free memory
close_thread_tables(new_thd);
delete new_thd;
+ /* Remember that we don't have a THD */
+ my_pthread_setspecific_ptr(THR_THD, 0);
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 53f89747ce7..6e8c2ebdb5c 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -41,7 +41,7 @@ int mysql_union(THD *thd, LEX *lex, select_result *result)
***************************************************************************/
select_union::select_union(TABLE *table_par)
- :table(table_par)
+ :table(table_par), not_describe(0)
{
bzero((char*) &info,sizeof(info));
/*
@@ -59,7 +59,7 @@ select_union::~select_union()
int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
unit= u;
- if (save_time_stamp && list.elements != table->fields)
+ if (not_describe && list.elements != table->fields)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
@@ -76,9 +76,16 @@ bool select_union::send_data(List<Item> &values)
return 0;
}
fill_record(table->field,values);
- if ((write_record(table,&info)))
+ if (thd->net.report_error || write_record(table,&info))
{
- if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0))
+ if (thd->net.last_errno == ER_RECORD_FILE_FULL)
+ {
+ thd->clear_error(); // do not report user about table overflow
+ if (create_myisam_from_heap(thd, table, tmp_table_param,
+ info.last_errno, 0))
+ return 1;
+ }
+ else
return 1;
}
return 0;
@@ -111,7 +118,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
prepared= 1;
union_result=0;
res= 0;
- found_rows_for_union= false;
+ found_rows_for_union= 0;
TMP_TABLE_PARAM tmp_table_param;
this->thd= thd;
this->result= result;
@@ -144,10 +151,9 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
tmp_table_param.field_count=item_list.elements;
if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
(ORDER*) 0, !union_option,
- 1, 0,
- (first_select()->options | thd->options |
- TMP_TABLE_ALL_COLUMNS),
- this)))
+ 1, (first_select()->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ HA_POS_ERROR)))
goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -159,7 +165,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
if (!(union_result=new select_union(table)))
goto err;
- union_result->save_time_stamp=1;
+ union_result->not_describe=1;
union_result->tmp_table_param=&tmp_table_param;
// prepare selects
@@ -208,7 +214,11 @@ int st_select_lex_unit::exec()
if (dependent || !item || !item->assigned())
{
if (optimized && item && item->assigned())
+ {
item->assigned(0); // We will reinit & rexecute unit
+ item->assign_null();
+ table->file->delete_all_rows();
+ }
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
thd->lex.current_select= sl;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index be69935a49c..de5cb9ef45b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -29,10 +29,12 @@ static bool compare_record(TABLE *table, ulong query_id)
{
if (!table->blob_fields)
return cmp_record(table,1);
+ /* Compare null bits */
if (memcmp(table->null_flags,
table->null_flags+table->rec_buff_length,
table->null_bytes))
return 1; // Diff in NULL value
+ /* Compare updated fields */
for (Field **ptr=table->field ; *ptr ; ptr++)
{
if ((*ptr)->query_id == query_id &&
@@ -50,25 +52,29 @@ int mysql_update(THD *thd,
COND *conds,
ORDER *order,
ha_rows limit,
- enum enum_duplicates handle_duplicates,
- thr_lock_type lock_type)
+ enum enum_duplicates handle_duplicates)
{
bool using_limit=limit != HA_POS_ERROR;
- bool used_key_is_modified, using_transactions;
+ bool safe_update= thd->options & OPTION_SAFE_UPDATES;
+ bool used_key_is_modified, transactional_table, log_delayed;
int error=0;
- uint save_time_stamp, used_index, want_privilege;
+ uint used_index, want_privilege;
ulong query_id=thd->query_id, timestamp_query_id;
key_map old_used_keys;
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
+ TABLE_LIST *update_table_list= (TABLE_LIST*)
+ thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_update");
LINT_INIT(used_index);
LINT_INIT(timestamp_query_id);
- if (!(table = open_ltable(thd,table_list,lock_type)))
- DBUG_RETURN(-1); /* purecov: inspected */
- save_time_stamp=table->time_stamp;
+ if ((open_and_lock_tables(thd, table_list)))
+ DBUG_RETURN(-1);
+ fix_tables_pointers(thd->lex.all_selects_list);
+ table= table_list->table;
+
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
@@ -77,9 +83,17 @@ int mysql_update(THD *thd,
table->quick_keys=0;
want_privilege=table->grant.want_privilege;
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
- if (setup_tables(table_list) || setup_conds(thd,table_list,&conds)
- || setup_ftfuncs(&thd->lex.select_lex))
+ if (setup_tables(update_table_list) ||
+ setup_conds(thd,update_table_list,&conds)
+ || setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(-1); /* purecov: inspected */
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
+ DBUG_RETURN(-1);
+ }
+
old_used_keys=table->used_keys; // Keys used in WHERE
/*
@@ -90,11 +104,12 @@ int mysql_update(THD *thd,
{
timestamp_query_id=table->timestamp_field->query_id;
table->timestamp_field->query_id=thd->query_id-1;
+ table->time_stamp= table->timestamp_field->offset() +1;
}
/* Check the fields we are going to modify */
table->grant.want_privilege=want_privilege;
- if (setup_fields(thd,table_list,fields,1,0,0))
+ if (setup_fields(thd,update_table_list,fields,1,0,0))
DBUG_RETURN(-1); /* purecov: inspected */
if (table->timestamp_field)
{
@@ -107,9 +122,8 @@ int mysql_update(THD *thd,
/* Check values */
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
- if (setup_fields(thd,table_list,values,0,0,0))
+ if (setup_fields(thd,update_table_list,values,0,0,0))
{
- table->time_stamp=save_time_stamp; // Restore timestamp pointer
DBUG_RETURN(-1); /* purecov: inspected */
}
@@ -117,12 +131,9 @@ int mysql_update(THD *thd,
table->used_keys=0;
select=make_select(table,0,0,conds,&error);
if (error ||
- (select && select->check_quick(test(thd->options & OPTION_SAFE_UPDATES),
- limit)) ||
- !limit)
+ (select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
- table->time_stamp=save_time_stamp; // Restore timestamp pointer
if (error)
{
DBUG_RETURN(-1); // Error in where
@@ -134,10 +145,9 @@ int mysql_update(THD *thd,
if (!table->quick_keys)
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
- if ((thd->options & OPTION_SAFE_UPDATES) && limit == HA_POS_ERROR)
+ if (safe_update && !using_limit)
{
delete select;
- table->time_stamp=save_time_stamp;
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
@@ -156,8 +166,8 @@ int mysql_update(THD *thd,
if (used_key_is_modified || order)
{
/*
- ** We can't update table directly; We must first search after all
- ** matching rows before updating the table!
+ We can't update table directly; We must first search after all
+ matching rows before updating the table!
*/
table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
IO_CACHE tempfile;
@@ -165,7 +175,6 @@ int mysql_update(THD *thd,
DISK_BUFFER_SIZE, MYF(MY_WME)))
{
delete select; /* purecov: inspected */
- table->time_stamp=save_time_stamp; // Restore timestamp pointer /* purecov: inspected */
DBUG_RETURN(-1);
}
if (old_used_keys & ((key_map) 1 << used_index))
@@ -196,7 +205,6 @@ int mysql_update(THD *thd,
== HA_POS_ERROR)
{
delete select;
- table->time_stamp=save_time_stamp; // Restore timestamp pointer
DBUG_RETURN(-1);
}
}
@@ -250,7 +258,6 @@ int mysql_update(THD *thd,
if (error >= 0)
{
delete select;
- table->time_stamp=save_time_stamp; // Restore timestamp pointer
DBUG_RETURN(-1);
}
}
@@ -270,7 +277,7 @@ int mysql_update(THD *thd,
if (!(select && select->skipp_record()))
{
store_record(table,1);
- if (fill_record(fields,values))
+ if (fill_record(fields,values) || thd->net.report_error)
break; /* purecov: inspected */
found++;
if (compare_record(table, query_id))
@@ -300,23 +307,31 @@ int mysql_update(THD *thd,
end_read_record(&info);
thd->proc_info="end";
VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY));
- table->time_stamp=save_time_stamp; // Restore auto timestamp pointer
- using_transactions=table->file->has_transactions();
- if (updated && (error <= 0 || !using_transactions))
+ transactional_table= table->file->has_transactions();
+ log_delayed= (transactional_table || table->tmp_table);
+ if (updated && (error <= 0 || !transactional_table))
{
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
- using_transactions);
- if (mysql_bin_log.write(&qinfo) && using_transactions)
- error=1;
+ log_delayed);
+ if (mysql_bin_log.write(&qinfo) && transactional_table)
+ error=1; // Rollback update
}
- if (!using_transactions)
+ if (!log_delayed)
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
- if (using_transactions && ha_autocommit_or_rollback(thd, error >= 0))
- error=1;
+ if (transactional_table)
+ {
+ if (ha_autocommit_or_rollback(thd, error >= 0))
+ error=1;
+ }
+
+ /*
+ Store table for future invalidation or invalidate it in
+ the query cache if something changed
+ */
if (updated)
{
query_cache_invalidate3(thd, table_list, 1);
@@ -345,329 +360,346 @@ int mysql_update(THD *thd,
DBUG_RETURN(0);
}
+
/***************************************************************************
Update multiple tables from join
***************************************************************************/
-multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
- enum enum_duplicates handle_duplicates, thr_lock_type lock_option_arg, uint num)
- : update_tables (ut), thd(thd_arg), updated(0), found(0), fields(fs), lock_option(lock_option_arg),
- dupl(handle_duplicates), num_of_tables(num), num_fields(0), num_updated(0) , error(0), do_update(false)
+/*
+ Setup multi-update handling and call SELECT to do the join
+*/
+
+int mysql_multi_update(THD *thd,
+ TABLE_LIST *table_list,
+ List<Item> *fields,
+ List<Item> *values,
+ COND *conds,
+ ulong options,
+ enum enum_duplicates handle_duplicates,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
- save_time_stamps = (uint *) sql_calloc (sizeof(uint) * num_of_tables);
- tmp_tables = (TABLE **)NULL;
- int counter=0;
- ulong timestamp_query_id;
- not_trans_safe=false;
- for (TABLE_LIST *dt=ut ; dt ; dt=dt->next,counter++)
+ int res;
+ multi_update *result;
+ TABLE_LIST *tl;
+ DBUG_ENTER("mysql_multi_update");
+
+ table_list->grant.want_privilege=(SELECT_ACL & ~table_list->grant.privilege);
+ if ((res=open_and_lock_tables(thd,table_list)))
+ DBUG_RETURN(res);
+
+ thd->select_limit=HA_POS_ERROR;
+ if (setup_fields(thd, table_list, *fields, 1, 0, 0))
+ DBUG_RETURN(-1);
+
+ /*
+ Count tables and setup timestamp handling
+ */
+ for (tl= (TABLE_LIST*) table_list ; tl ; tl=tl->next)
{
- TABLE *table=ut->table;
- // (void) ut->table->file->extra(HA_EXTRA_NO_KEYREAD);
- dt->table->used_keys=0;
+ TABLE *table= tl->table;
if (table->timestamp_field)
{
- // Don't set timestamp column if this is modified
- timestamp_query_id=table->timestamp_field->query_id;
- table->timestamp_field->query_id=thd->query_id-1;
- if (table->timestamp_field->query_id == thd->query_id)
- table->time_stamp=0;
- else
- table->timestamp_field->query_id=timestamp_query_id;
+ table->time_stamp=0;
+ // Only set timestamp column if this is not modified
+ if (table->timestamp_field->query_id != thd->query_id)
+ table->time_stamp= table->timestamp_field->offset() +1;
}
- save_time_stamps[counter]=table->time_stamp;
}
- error = 1; // In case we do not reach prepare we have to reset timestamps
+
+ if (!(result=new multi_update(thd, table_list, fields, values,
+ handle_duplicates)))
+ DBUG_RETURN(-1);
+
+ List<Item> total_list;
+ res= mysql_select(thd,table_list,total_list,
+ conds, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
+ (ORDER *)NULL,
+ options | SELECT_NO_JOIN_CACHE,
+ result, unit, select_lex, 0);
+
+end:
+ delete result;
+ DBUG_RETURN(res);
}
-int
-multi_update::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
+
+multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
+ List<Item> *field_list, List<Item> *value_list,
+ enum enum_duplicates handle_duplicates_arg)
+ :all_tables(table_list), update_tables(0), thd(thd_arg), tmp_tables(0),
+ updated(0), found(0), fields(field_list), values(value_list),
+ table_count(0), copy_field(0), handle_duplicates(handle_duplicates_arg),
+ do_update(1), trans_safe(0)
+{}
+
+
+/*
+ Connect fields with tables and create list of tables that are updated
+*/
+
+int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
{
+ TABLE_LIST *table_ref;
+ SQL_LIST update;
+ table_map tables_to_update= 0;
+ Item_field *item;
+ List_iterator_fast<Item> field_it(*fields);
+ List_iterator_fast<Item> value_it(*values);
+ uint i, max_fields;
DBUG_ENTER("multi_update::prepare");
- unit= u;
- do_update = true;
+
thd->count_cuted_fields=1;
thd->cuted_fields=0L;
- thd->proc_info="updating the main table";
- TABLE_LIST *table_ref;
+ thd->proc_info="updating main table";
- if (thd->options & OPTION_SAFE_UPDATES)
+ while ((item= (Item_field *) field_it++))
+ tables_to_update|= item->used_tables();
+
+ if (!tables_to_update)
{
- for (table_ref=update_tables; table_ref; table_ref=table_ref->next)
- {
- TABLE *table=table_ref->table;
- if ((thd->options & OPTION_SAFE_UPDATES) && !table->quick_keys)
- {
- my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE,MYF(0));
- DBUG_RETURN(1);
- }
- }
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "You didn't specify any tables to UPDATE");
+ DBUG_RETURN(1);
}
+
/*
- Here I have to connect fields with tables and only update tables that
- need to be updated.
- I calculate num_updated and fill-up table_sequence
- Set table_list->shared to true or false, depending on whether table is
- to be updated or not
+ We have to check values after setup_tables to get used_keys right in
+ reference tables
*/
- Item_field *item;
- List_iterator<Item> it(fields);
- num_fields=fields.elements;
- field_sequence = (uint *) sql_alloc(sizeof(uint)*num_fields);
- uint *int_ptr=field_sequence;
- while ((item= (Item_field *)it++))
- {
- unsigned int counter=0;
- for (table_ref=update_tables; table_ref;
- table_ref=table_ref->next, counter++)
- {
- if (table_ref->table == item->field->table)
- {
- if (!table_ref->shared)
- {
- TABLE *tbl=table_ref->table;
- num_updated++;
- table_ref->shared=1;
- if (!not_trans_safe && !table_ref->table->file->has_transactions())
- not_trans_safe=true;
- // to be moved if initialize_tables has to be used
- tbl->no_keyread=1;
- tbl->used_keys=0;
- }
- break;
- }
- }
- if (!table_ref)
- {
- net_printf(thd, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES");
- DBUG_RETURN(1);
- }
- else
- *int_ptr++=counter;
- }
- if (!num_updated--)
- {
- net_printf(thd, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE");
+ if (setup_fields(thd, all_tables, *values, 1,0,0))
DBUG_RETURN(1);
- }
/*
- Here, I have to allocate the array of temporary tables
- I have to treat a case of num_updated=1 differently in send_data() method.
+ Save tables beeing updated in update_tables
+ update_table->shared is position for table
+ Don't use key read on tables that are updated
*/
- if (num_updated)
+
+ update.empty();
+ for (table_ref= all_tables; table_ref; table_ref=table_ref->next)
{
- tmp_tables = (TABLE **) sql_calloc(sizeof(TABLE *) * num_updated);
- infos = (COPY_INFO *) sql_calloc(sizeof(COPY_INFO) * num_updated);
- fields_by_tables = (List_item **)sql_calloc(sizeof(List_item *) * (num_updated + 1));
- unsigned int counter;
- List<Item> *temp_fields;
- for (table_ref=update_tables, counter = 0; table_ref; table_ref=table_ref->next)
+ TABLE *table=table_ref->table;
+ if (tables_to_update & table->map)
{
- if (!table_ref->shared)
- continue;
- // Here we have to add row offset as an additional field ...
- if (!(temp_fields = (List_item *)sql_calloc(sizeof(List_item))))
- {
- error = 1; // A proper error message is due here
+ TABLE_LIST *tl= (TABLE_LIST*) thd->memdup((char*) table_ref,
+ sizeof(*tl));
+ if (!tl)
DBUG_RETURN(1);
- }
- temp_fields->empty();
- it.rewind(); int_ptr=field_sequence;
- while ((item= (Item_field *)it++))
- {
- if (*int_ptr++ == counter)
- temp_fields->push_back(item);
- }
- if (counter)
- {
- Field_string offset(table_ref->table->file->ref_length, false,
- "offset", table_ref->table, my_charset_bin);
- temp_fields->push_front(new Item_field(((Field *)&offset)));
-
- // Make a temporary table
- int cnt=counter-1;
- TMP_TABLE_PARAM tmp_table_param;
- bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
- tmp_table_param.field_count=temp_fields->elements;
- if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param,
- *temp_fields,
- (ORDER*) 0, 1, 0, 0,
- TMP_TABLE_ALL_COLUMNS,
- unit)))
- {
- error = 1; // A proper error message is due here
- DBUG_RETURN(1);
- }
- tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
- tmp_tables[cnt]->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- infos[cnt].handle_duplicates=DUP_IGNORE;
- temp_fields->pop(); // because we shall use those for values only ...
- }
- fields_by_tables[counter]=temp_fields;
- counter++;
+ update.link_in_list((byte*) tl, (byte**) &tl->next);
+ tl->shared= table_count++;
+ table->no_keyread=1;
+ table->used_keys=0;
+ table->pos_in_table_list= tl;
}
}
- init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
- error = 0; // Timestamps do not need to be restored, so far ...
- DBUG_RETURN(0);
+ table_count= update.elements;
+ update_tables= (TABLE_LIST*) update.first;
+
+ tmp_tables = (TABLE **) thd->calloc(sizeof(TABLE *) * table_count);
+ tmp_table_param = (TMP_TABLE_PARAM*) thd->calloc(sizeof(TMP_TABLE_PARAM) *
+ table_count);
+ fields_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
+ table_count);
+ values_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
+ table_count);
+ if (thd->fatal_error)
+ DBUG_RETURN(1);
+ for (i=0 ; i < table_count ; i++)
+ {
+ fields_for_table[i]= new List_item;
+ values_for_table[i]= new List_item;
+ }
+ if (thd->fatal_error)
+ DBUG_RETURN(1);
+
+ /* Split fields into fields_for_table[] and values_by_table[] */
+
+ field_it.rewind();
+ while ((item= (Item_field *) field_it++))
+ {
+ Item *value= value_it++;
+ uint offset= item->field->table->pos_in_table_list->shared;
+ fields_for_table[offset]->push_back(item);
+ values_for_table[offset]->push_back(value);
+ }
+ if (thd->fatal_error)
+ DBUG_RETURN(1);
+
+ /* Allocate copy fields */
+ max_fields=0;
+ for (i=0 ; i < table_count ; i++)
+ set_if_bigger(max_fields, fields_for_table[i]->elements);
+ copy_field= new Copy_field[max_fields];
+ DBUG_RETURN(thd->fatal_error != 0);
}
-void
+/*
+ Store first used table in main_table as this should be updated first
+ This is because we know that no row in this table will be read twice.
+
+ Create temporary tables to store changed values for all other tables
+ that are updated.
+*/
+
+bool
multi_update::initialize_tables(JOIN *join)
{
-#ifdef NOT_YET
- We skip it as it only makes a mess ...........
- TABLE_LIST *walk;
- table_map tables_to_update_from=0;
- for (walk= update_tables ; walk ; walk=walk->next)
- tables_to_update_from|= walk->table->map;
-
- walk= update_tables;
- for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
- tab < end;
- tab++)
+ TABLE_LIST *table_ref;
+ DBUG_ENTER("initialize_tables");
+
+ if ((thd->options & OPTION_SAFE_UPDATES) && error_if_full_join(join))
+ DBUG_RETURN(1);
+ main_table=join->join_tab->table;
+ trans_safe= transactional_tables= main_table->file->has_transactions();
+ log_delayed= trans_safe || main_table->tmp_table != NO_TMP_TABLE;
+
+ /* Create a temporary table for all tables after except main table */
+ for (table_ref= update_tables; table_ref; table_ref=table_ref->next)
{
- if (tab->table->map & tables_to_update_from)
+ TABLE *table=table_ref->table;
+ if (table != main_table)
{
-// We are going to update from this table
- TABLE *tbl=walk->table=tab->table;
- /* Don't use KEYREAD optimization on this table */
- tbl->no_keyread=1;
- walk=walk->next;
+ uint cnt= table_ref->shared;
+ ORDER group;
+ List<Item> temp_fields= *fields_for_table[cnt];
+ TMP_TABLE_PARAM *tmp_param= tmp_table_param+cnt;
+
+ /*
+ Create a temporary table to store all fields that are changed for this
+ table. The first field in the temporary table is a pointer to the
+ original row so that we can find and update it
+ */
+
+ /* 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))))
+ DBUG_RETURN(1);
+
+ /* Make an unique key over the first field to avoid duplicated updates */
+ bzero((char*) &group, sizeof(group));
+ group.asc= 1;
+ group.item= (Item**) temp_fields.head_ref();
+
+ tmp_param->quick_group=1;
+ tmp_param->field_count=temp_fields.elements;
+ tmp_param->group_parts=1;
+ tmp_param->group_length= table->file->ref_length;
+ if (!(tmp_tables[cnt]=create_tmp_table(thd,
+ tmp_param,
+ temp_fields,
+ (ORDER*) &group, 0, 0,
+ TMP_TABLE_ALL_COLUMNS,
+ HA_POS_ERROR)))
+ DBUG_RETURN(1);
+ tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
}
}
-#endif
+ DBUG_RETURN(0);
}
multi_update::~multi_update()
{
- int counter = 0;
- for (table_being_updated=update_tables ;
- table_being_updated ;
- counter++, table_being_updated=table_being_updated->next)
+ TABLE_LIST *table;
+ for (table= update_tables ; table; table= table->next)
+ table->table->no_keyread=0;
+
+ if (tmp_tables)
{
- TABLE *table=table_being_updated->table;
- table->no_keyread=0;
- if (error)
- table->time_stamp=save_time_stamps[counter];
+ for (uint cnt = 0; cnt < table_count; cnt++)
+ {
+ if (tmp_tables[cnt])
+ {
+ free_tmp_table(thd, tmp_tables[cnt]);
+ tmp_table_param[cnt].cleanup();
+ }
+ }
}
- if (tmp_tables)
- for (uint counter = 0; counter < num_updated; counter++)
- if (tmp_tables[counter])
- free_tmp_table(thd,tmp_tables[counter]);
+ if (copy_field)
+ delete [] copy_field;
+ thd->count_cuted_fields=0; // Restore this setting
+ if (!trans_safe)
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
}
-bool multi_update::send_data(List<Item> &values)
+bool multi_update::send_data(List<Item> &not_used_values)
{
- List<Item> real_values(values);
- for (uint counter = 0; counter < fields.elements; counter++)
- real_values.pop();
- // We have skipped fields ....
- if (!num_updated)
+ TABLE_LIST *cur_table;
+ DBUG_ENTER("multi_update::send_data");
+
+ found++;
+ for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
{
- for (table_being_updated=update_tables ;
- table_being_updated ;
- table_being_updated=table_being_updated->next)
+ TABLE *table= cur_table->table;
+ /* Check if we are using outer join and we didn't find the row */
+ if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
+ continue;
+
+ uint offset= cur_table->shared;
+ table->file->position(table->record[0]);
+ if (table == main_table)
{
- if (!table_being_updated->shared)
- continue;
- TABLE *table=table_being_updated->table;
- /* Check if we are using outer join and we didn't find the row */
- if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
- return 0;
- table->file->position(table->record[0]);
- // Only one table being updated receives a completely different treatment
table->status|= STATUS_UPDATED;
- store_record(table,1);
- if (fill_record(fields,real_values))
- return 1;
- found++;
- if (/* compare_record(table, query_id) && */
- !(error=table->file->update_row(table->record[1], table->record[0])))
- updated++;
- table->file->extra(HA_EXTRA_NO_CACHE);
- return error;
- }
- }
- else
- {
- int secure_counter= -1;
- for (table_being_updated=update_tables ;
- table_being_updated ;
- table_being_updated=table_being_updated->next, secure_counter++)
- {
- if (!table_being_updated->shared)
- continue;
-
- TABLE *table=table_being_updated->table;
- /* Check if we are using outer join and we didn't find the row */
- if (table->status & (STATUS_NULL_ROW | STATUS_UPDATED))
- continue;
- table->file->position(table->record[0]);
- Item *item;
- List_iterator<Item> it(real_values);
- List <Item> values_by_table;
- uint *int_ptr=field_sequence;
- while ((item= (Item *)it++))
- {
- if (*int_ptr++ == (uint) (secure_counter + 1))
- values_by_table.push_back(item);
- }
- // Here I am breaking values as per each table
- if (secure_counter < 0)
+ store_record(table,1);
+ if (fill_record(*fields_for_table[offset], *values_for_table[offset]))
+ DBUG_RETURN(1);
+ if (compare_record(table, thd->query_id))
{
- table->status|= STATUS_UPDATED;
- store_record(table,1);
- if (fill_record(*fields_by_tables[0],values_by_table))
- return 1;
- found++;
- if (/*compare_record(table, query_id) && */
- !(error=table->file->update_row(table->record[1], table->record[0])))
+ int error;
+ if (!updated++)
{
- updated++;
- table->file->extra(HA_EXTRA_NO_CACHE);
+ /*
+ Inform the main table that we are going to update the table even
+ while we may be scanning it. This will flush the read cache
+ if it's used.
+ */
+ main_table->file->extra(HA_EXTRA_PREPARE_FOR_UPDATE);
}
- else
+ if ((error=table->file->update_row(table->record[1],
+ table->record[0])))
{
table->file->print_error(error,MYF(0));
- if (!error) error=1;
- return 1;
+ updated--;
+ DBUG_RETURN(1);
}
}
- else
+ }
+ else
+ {
+ int error;
+ TABLE *tmp_table= tmp_tables[offset];
+ fill_record(tmp_table->field+1, *values_for_table[offset]);
+
+ /* Store pointer to row */
+ memcpy((char*) tmp_table->field[0]->ptr,
+ (char*) table->file->ref, table->file->ref_length);
+ /* Write row, ignoring duplicated updates to a row */
+ if ((error= tmp_table->file->write_row(tmp_table->record[0])) &&
+ (error != HA_ERR_FOUND_DUPP_KEY &&
+ error != HA_ERR_FOUND_DUPP_UNIQUE))
{
- // Here we insert into each temporary table
- values_by_table.push_front(new Item_string((char*) table->file->ref,
- table->file->ref_length,
- system_charset_info));
- fill_record(tmp_tables[secure_counter]->field,values_by_table);
- error= write_record(tmp_tables[secure_counter],
- &(infos[secure_counter]));
- if (error)
+ if (create_myisam_from_heap(thd, table, tmp_table_param + offset,
+ error, 1))
{
- error=-1;
- return 1;
+ do_update=0;
+ DBUG_RETURN(1); // Not a table_is_full error
}
}
}
}
- return 0;
+ DBUG_RETURN(0);
}
+
void multi_update::send_error(uint errcode,const char *err)
{
-
- //TODO error should be sent at the query processing end
/* First send error what ever it is ... */
::send_error(thd,errcode,err);
- /* reset used flags */
- // update_tables->table->no_keyread=0;
-
/* If nothing updated return */
if (!updated)
return;
@@ -675,96 +707,124 @@ void multi_update::send_error(uint errcode,const char *err)
/* Something already updated so we have to invalidate cache */
query_cache_invalidate3(thd, update_tables, 1);
- /* Below can happen when thread is killed early ... */
- if (!table_being_updated)
- table_being_updated=update_tables;
-
/*
- If rows from the first table only has been updated and it is transactional,
- just do rollback.
- The same if all tables are transactional, regardless of where we are.
- In all other cases do attempt updates ...
+ If all tables that has been updated are trans safe then just do rollback.
+ If not attempt to do remaining updates.
*/
- if ((table_being_updated->table->file->has_transactions() &&
- table_being_updated == update_tables) || !not_trans_safe)
+
+ if (trans_safe)
ha_rollback_stmt(thd);
- else if (do_update && num_updated)
- VOID(do_updates(true));
+ else if (do_update && table_count > 1)
+ {
+ /* Add warning here */
+ VOID(do_updates(0));
+ }
}
-int multi_update::do_updates (bool from_send_error)
+int multi_update::do_updates(bool from_send_error)
{
- int error = 0, counter = 0;
-
- if (from_send_error)
+ TABLE_LIST *cur_table;
+ int local_error;
+ ha_rows org_updated;
+ TABLE *table;
+ DBUG_ENTER("do_updates");
+
+ do_update= 0; // Don't retry this function
+ for (cur_table= update_tables; cur_table ; cur_table= cur_table->next)
{
- /* Found out table number for 'table_being_updated' */
- for (TABLE_LIST *aux=update_tables;
- aux != table_being_updated;
- aux=aux->next)
- counter++;
- }
- else
- table_being_updated = update_tables;
-
- do_update = false;
- for (table_being_updated=table_being_updated->next;
- table_being_updated ;
- table_being_updated=table_being_updated->next, counter++)
- {
- if (!table_being_updated->shared)
- continue;
+ table = cur_table->table;
+ if (table == main_table)
+ continue; // Already updated
- TABLE *table = table_being_updated->table;
- TABLE *tmp_table=tmp_tables[counter];
- if (tmp_table->file->extra(HA_EXTRA_NO_CACHE))
- {
- error=1;
- break;
- }
- List<Item> list;
- Field **ptr=tmp_table->field,*field;
- // This is supposed to be something like insert_fields
- thd->used_tables|=tmp_table->map;
- while ((field = *ptr++))
+ org_updated= updated;
+ byte *ref_pos;
+ TABLE *tmp_table= tmp_tables[cur_table->shared];
+ tmp_table->file->extra(HA_EXTRA_CACHE); // Change to read cache
+ table->file->extra(HA_EXTRA_NO_CACHE);
+
+ /*
+ Setup copy functions to copy fields from temporary table
+ */
+ List_iterator_fast<Item> field_it(*fields_for_table[cur_table->shared]);
+ Field **field= tmp_table->field+1; // Skip row pointer
+ Copy_field *copy_field_ptr= copy_field, *copy_field_end;
+ for ( ; *field ; field++)
{
- list.push_back((Item *)new Item_field(field));
- if (field->query_id == thd->query_id)
- thd->dupp_field=field;
- field->query_id=thd->query_id;
- tmp_table->used_keys&=field->part_of_key;
+ Item_field *item= (Item_field* ) field_it++;
+ (copy_field_ptr++)->set(item->field, *field, 0);
}
- tmp_table->used_fields=tmp_table->fields;
- error=0; list.pop(); // we get position some other way ...
- error = tmp_table->file->rnd_init(1);
- if (error)
- return error;
- while (!(error=tmp_table->file->rnd_next(tmp_table->record[0])) &&
- (!thd->killed || from_send_error || not_trans_safe))
+ copy_field_end=copy_field_ptr;
+
+ if ((local_error = tmp_table->file->rnd_init(1)))
+ goto err;
+
+ ref_pos= (byte*) tmp_table->field[0]->ptr;
+ for (;;)
{
- found++;
- error= table->file->rnd_pos(table->record[0],
- (byte*) (*(tmp_table->field))->ptr);
- if (error)
- return error;
+ if (thd->killed && trans_safe)
+ goto err;
+ if ((local_error=tmp_table->file->rnd_next(tmp_table->record[0])))
+ {
+ if (local_error == HA_ERR_END_OF_FILE)
+ break;
+ if (local_error == HA_ERR_RECORD_DELETED)
+ continue; // May happen on dup key
+ goto err;
+ }
+ found++;
+ if ((local_error= table->file->rnd_pos(table->record[0], ref_pos)))
+ goto err;
table->status|= STATUS_UPDATED;
- store_record(table,1);
- error= fill_record(*fields_by_tables[counter + 1],list) ||
- /* compare_record(table, query_id) || */
- table->file->update_row(table->record[1],table->record[0]);
- if (error)
+ store_record(table,1);
+
+ /* Copy data from temporary table to current table */
+ for (copy_field_ptr=copy_field;
+ copy_field_ptr != copy_field_end;
+ copy_field_ptr++)
+ (*copy_field_ptr->do_copy)(copy_field_ptr);
+
+ if (compare_record(table, thd->query_id))
{
- table->file->print_error(error,MYF(0));
- break;
+ if ((local_error=table->file->update_row(table->record[1],
+ table->record[0])))
+ {
+ if (local_error != HA_ERR_FOUND_DUPP_KEY ||
+ handle_duplicates != DUP_IGNORE)
+ goto err;
+ }
+ updated++;
+ if (table->tmp_table != NO_TMP_TABLE)
+ log_delayed= 1;
}
+ }
+
+ if (updated != org_updated)
+ {
+ if (table->tmp_table != NO_TMP_TABLE)
+ log_delayed= 1; // Tmp tables forces delay log
+ if (table->file->has_transactions())
+ log_delayed= transactional_tables= 1;
else
- updated++;
+ trans_safe= 0; // Can't do safe rollback
}
- if (error == HA_ERR_END_OF_FILE)
- error = 0;
}
- return error;
+ DBUG_RETURN(0);
+
+err:
+ if (!from_send_error)
+ table->file->print_error(local_error,MYF(0));
+
+ if (updated != org_updated)
+ {
+ if (table->tmp_table != NO_TMP_TABLE)
+ log_delayed= 1;
+ if (table->file->has_transactions())
+ log_delayed= transactional_tables= 1;
+ else
+ trans_safe= 0;
+ }
+ DBUG_RETURN(1);
}
@@ -772,61 +832,57 @@ int multi_update::do_updates (bool from_send_error)
bool multi_update::send_eof()
{
- thd->proc_info="updating the reference tables";
+ char buff[80];
+ thd->proc_info="updating reference tables";
/* Does updates for the last n - 1 tables, returns 0 if ok */
- int error = (num_updated) ? do_updates(false) : 0; /* do_updates returns 0 if success */
-
- /* reset used flags */
-#ifndef NOT_USED
- update_tables->table->no_keyread=0;
-#endif
- if (error == -1)
- error = 0;
- thd->proc_info="end";
- //TODO error should be sent at the query processing end
- if (error)
- send_error(error,"An error occured in multi-table update");
+ int local_error = (table_count) ? do_updates(0) : 0;
+ thd->proc_info= "end";
/*
Write the SQL statement to the binlog if we updated
- rows and we succeeded, or also in an error case when there
- was a non-transaction-safe table involved, since
- modifications in it cannot be rolled back.
+ rows and we succeeded or if we updated some non
+ transacational tables
*/
- if (updated || not_trans_safe)
+ if (updated && (local_error <= 0 || !trans_safe))
{
mysql_update_log.write(thd,thd->query,thd->query_length);
- Query_log_event qinfo(thd, thd->query, thd->query_length);
-
- /*
- mysql_bin_log is not open if binlogging or replication
- is not used
- */
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length,
+ log_delayed);
+ if (mysql_bin_log.write(&qinfo) && trans_safe)
+ local_error= 1; // Rollback update
+ }
+ if (!log_delayed)
+ thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ }
- if (mysql_bin_log.is_open() && mysql_bin_log.write(&qinfo) &&
- !not_trans_safe)
- error=1; /* Log write failed: roll back the SQL statement */
+ if (transactional_tables)
+ {
+ if (ha_autocommit_or_rollback(thd, local_error != 0))
+ local_error=1;
+ }
- /* Commit or rollback the current SQL statement */
- VOID(ha_autocommit_or_rollback(thd,error > 0));
+ if (local_error > 0) // if the above log write did not fail ...
+ {
+ /* Safety: If we haven't got an error before (should not happen) */
+ my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update",
+ MYF(0));
+ ::send_error(thd);
+ return 1;
}
- else
- error=0; // this can happen only if it is end of file error
- if (!error) // if the above log write did not fail ...
+
+
+ sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
+ (long) thd->cuted_fields);
+ if (updated)
{
- char buff[80];
- sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
- (long) thd->cuted_fields);
- if (updated)
- {
- query_cache_invalidate3(thd, update_tables, 1);
- }
- ::send_ok(thd,
- (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
- thd->insert_id_used ? thd->insert_id() : 0L,buff);
+ query_cache_invalidate3(thd, update_tables, 1);
}
- thd->count_cuted_fields=0;
+ ::send_ok(thd,
+ (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
+ thd->insert_id_used ? thd->insert_id() : 0L,buff);
return 0;
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b1cbe0ccf2b..ed8e8f0fb51 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -17,10 +17,18 @@
/* sql_yacc.yy */
%{
+/* thd is passed as an arg to yyparse(), and subsequently to yylex().
+** The type will be void*, so it must be cast to (THD*) when used.
+** Use the YYTHD macro for this.
+*/
+#define YYPARSE_PARAM yythd
+#define YYLEX_PARAM yythd
+#define YYTHD ((THD *)yythd)
+
#define MYSQL_YACC
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
-#define Lex current_lex
+#define Lex (&(YYTHD->lex))
#define Select Lex->current_select
#include "mysql_priv.h"
#include "slave.h"
@@ -31,13 +39,13 @@
#include <myisammrg.h>
extern void yyerror(const char*);
-int yylex(void *yylval);
+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; }
-inline Item *or_or_concat(Item* A, Item* B)
+inline Item *or_or_concat(THD *thd, Item* A, Item* B)
{
- return (current_thd->sql_mode & MODE_PIPES_AS_CONCAT ?
+ return (thd->sql_mode & MODE_PIPES_AS_CONCAT ?
(Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B));
}
@@ -69,7 +77,10 @@ inline Item *or_or_concat(Item* A, Item* B)
enum Item_cast cast_type;
enum Item_udftype udf_type;
CHARSET_INFO *charset;
+ thr_lock_type lock_type;
interval_type interval;
+ st_select_lex *select_lex;
+ chooser_compare_func_creator boolfunc2creator;
}
%{
@@ -86,6 +97,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NEXT_SYM
%token PREV_SYM
+%token DIV_SYM
%token EQ
%token EQUAL_SYM
%token GE
@@ -94,6 +106,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token LT
%token NE
%token IS
+%token MOD_SYM
%token SHIFT_LEFT
%token SHIFT_RIGHT
%token SET_VAR
@@ -103,6 +116,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token AFTER_SYM
%token ALTER
%token ANALYZE_SYM
+%token ANY_SYM
%token AVG_SYM
%token BEGIN_SYM
%token BINLOG_SYM
@@ -115,6 +129,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token CROSS
%token CUBE_SYM
%token DELETE_SYM
+%token DUAL_SYM
%token DO_SYM
%token DROP
%token EVENTS_SYM
@@ -167,13 +182,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BOTH
%token BTREE_SYM
%token BY
+%token BYTE_SYM
%token CACHE_SYM
%token CASCADE
%token CAST_SYM
%token CHARSET
%token CHECKSUM_SYM
%token CHECK_SYM
-%token CIPHER
%token COMMITTED_SYM
%token COLLATE_SYM
%token COLUMNS
@@ -191,6 +206,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token DES_KEY_FILE
%token DISABLE_SYM
%token DISTINCT
+%token DUPLICATE
%token DYNAMIC_SYM
%token ENABLE_SYM
%token ENCLOSED
@@ -199,6 +215,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ESCAPE_SYM
%token EXISTS
%token EXTENDED_SYM
+%token FALSE_SYM
%token FILE_SYM
%token FIRST_SYM
%token FIXED_SYM
@@ -229,7 +246,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token IN_SYM
%token ISOLATION
%token ISAM_SYM
-%token ISSUER
%token JOIN_SYM
%token KEYS
%token KEY_SYM
@@ -249,7 +265,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MASTER_USER_SYM
%token MASTER_LOG_FILE_SYM
%token MASTER_LOG_POS_SYM
-%token MASTER_LOG_SEQ_SYM
%token MASTER_PASSWORD_SYM
%token MASTER_PORT_SYM
%token MASTER_CONNECT_RETRY_SYM
@@ -270,10 +285,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NEW_SYM
%token NCHAR_SYM
%token NOT
-%token NO_FOREIGN_KEY_CHECKS
%token NO_SYM
%token NULL_SYM
%token NUM
+%token OFFSET_SYM
%token ON
%token OPEN_SYM
%token OPTION
@@ -300,7 +315,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token REAL_NUM
%token REFERENCES
%token REGEXP
-%token RELAXED_UNIQUE_CHECKS
%token RELOAD
%token RENAME
%token REPEATABLE_SYM
@@ -314,6 +328,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ROW_SYM
%token RTREE_SYM
%token SET
+%token SERIAL_SYM
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SIMPLE_SYM
@@ -332,6 +347,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token TO_SYM
%token TRAILING
%token TRANSACTION_SYM
+%token TRUE_SYM
%token TYPE_SYM
%token TYPES_SYM
%token FUNC_ARG0
@@ -349,6 +365,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token USE_FRM
%token USE_SYM
%token USING
+%token VALUE_SYM
%token VALUES
%token VARIABLES
%token WHERE
@@ -516,7 +533,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%left '&'
%left SHIFT_LEFT SHIFT_RIGHT
%left '-' '+'
-%left '*' '/' '%'
+%left '*' '/' '%' DIV_SYM MOD_SYM
%left NEG '~'
%left XOR
%left '^'
@@ -530,7 +547,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_str>
IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME
- ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET
+ ULONGLONG_NUM field_ident select_alias ident ident_or_text
+ UNDERSCORE_CHARSET
%type <lex_str_ptr>
opt_table_alias
@@ -539,17 +557,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
table_ident references
%type <simple_string>
- remember_name remember_end opt_len opt_ident opt_db text_or_password
+ remember_name remember_end opt_ident opt_db text_or_password
opt_escape
%type <string>
- text_string
+ text_string
%type <num>
type int_type real_type order_dir opt_field_spec lock_option
udf_type if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_var_type opt_var_ident_type
- delete_option
+ delete_option opt_temporary all_or_any
%type <ulong_num>
ULONG_NUM raid_types merge_insert_types
@@ -557,6 +575,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <ulonglong_number>
ulonglong_num
+%type <lock_type>
+ replace_lock_option opt_low_priority insert_lock_option load_data_lock
+
%type <item>
literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
@@ -605,22 +626,26 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_user> user grant_user
-%type <charset>
+%type <charset>
charset_name
charset_name_or_default
opt_db_default_character_set
%type <variable> internal_variable_name
+%type <select_lex> in_subselect in_subselect_init
+
+%type <boolfunc2creator> comp_op
+
%type <NONE>
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
show describe load alter optimize flush
reset purge begin commit rollback slave master_def master_defs
- repair restore backup analyze check
+ repair restore backup analyze check
field_list field_list_item field_spec kill
select_item_list select_item values_list no_braces
- limit_clause delete_limit_clause fields opt_values values
+ opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
when_list2 expr_list2 handler
opt_precision opt_ignore opt_column opt_restrict
@@ -628,36 +653,38 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
field_opt_list opt_binary table_lock_list table_lock varchar
ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use
opt_delete_options opt_delete_option
- opt_outer table_list table_name opt_option opt_place opt_low_priority
+ opt_outer table_list table_name opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id
opt_column_list grant_privileges opt_table user_list grant_option
grant_privilege grant_privilege_list
- flush_options flush_option insert_lock_option replace_lock_option
+ flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
- single_multi table_wild_list table_wild_one opt_wild union union_list
- precision union_option opt_on_delete_item subselect_start opt_and
- subselect_end select_var_list select_var_list_init help
+ single_multi table_wild_list table_wild_one opt_wild
+ union_clause union_list union_option
+ precision subselect_start opt_and
+ subselect_end select_var_list select_var_list_init help opt_len
END_OF_INPUT
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
- ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM THEN_SYM WHEN_SYM
+ ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM
+ THEN_SYM WHEN_SYM DIV_SYM MOD_SYM
%%
query:
END_OF_INPUT
{
- THD *thd=current_thd;
+ THD *thd= YYTHD;
if (!thd->bootstrap &&
(!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
{
- send_error(current_thd,ER_EMPTY_QUERY);
+ send_error(thd,ER_EMPTY_QUERY);
YYABORT;
- }
+ }
else
{
thd->lex.sql_command = SQLCOM_EMPTY_QUERY;
@@ -685,7 +712,7 @@ verb_clause:
| lock
| kill
| optimize
- | purge
+ | purge
| rename
| repair
| replace
@@ -703,10 +730,10 @@ verb_clause:
| update
| use
| help;
-
+
/* help */
-help:
+help:
HELP TEXT_STRING
{
LEX *lex= Lex;
@@ -721,8 +748,11 @@ change:
{
LEX *lex = Lex;
lex->sql_command = SQLCOM_CHANGE_MASTER;
- memset(&lex->mi, 0, sizeof(lex->mi));
- } master_defs;
+ bzero((char*) &lex->mi, sizeof(lex->mi));
+ }
+ master_defs
+ {}
+ ;
master_defs:
master_def
@@ -781,14 +811,17 @@ master_def:
create:
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
{
- THD *thd=current_thd;
+ THD *thd= YYTHD;
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_TABLE;
- if (!lex->select_lex.add_table_to_list($5,
- ($2 &
+ if (!lex->select_lex.add_table_to_list(thd,$5,
+ ($2 &
HA_LEX_CREATE_TMP_TABLE ?
&tmp_table_alias :
- (LEX_STRING*) 0),1))
+ (LEX_STRING*) 0),1,
+ ((using_update_log)?
+ TL_READ_NO_INSERT:
+ TL_READ)))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
@@ -800,19 +833,19 @@ create:
lex->create_info.table_charset=thd->db_charset?thd->db_charset:default_charset_info;
}
create2
-
+ {}
| CREATE opt_unique_or_fulltext INDEX ident key_alg ON table_ident
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_INDEX;
- if (!lex->current_select->add_table_to_list($7,NULL,1))
+ if (!lex->current_select->add_table_to_list(lex->thd, $7,NULL,1))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty();
lex->change=NullS;
}
- '(' key_list ')'
+ '(' key_list ')'
{
LEX *lex=Lex;
@@ -856,7 +889,7 @@ create3:
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(lex);
}
- select_options select_item_list opt_select_from union {}
+ select_options select_item_list opt_select_from union_clause {}
;
opt_as:
@@ -888,30 +921,26 @@ create_table_options_space_separated:
create_table_options:
create_table_option
- | create_table_option create_table_options;
+ | create_table_option create_table_options
| create_table_option ',' create_table_options;
-o_eq:
- /* empty */
- | EQ {};
-
create_table_option:
- TYPE_SYM o_eq table_types { Lex->create_info.db_type= $3; }
- | MAX_ROWS o_eq ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
- | MIN_ROWS o_eq ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
- | AVG_ROW_LENGTH o_eq ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
- | PASSWORD o_eq TEXT_STRING { Lex->create_info.password=$3.str; }
- | COMMENT_SYM o_eq TEXT_STRING { Lex->create_info.comment=$3.str; }
- | AUTO_INC o_eq ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
- | PACK_KEYS_SYM o_eq ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
- | PACK_KEYS_SYM o_eq DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
- | CHECKSUM_SYM o_eq ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; }
- | DELAY_KEY_WRITE_SYM o_eq ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; }
- | ROW_FORMAT_SYM o_eq row_types { Lex->create_info.row_type= $3; }
- | RAID_TYPE o_eq raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKS o_eq ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKSIZE o_eq ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | UNION_SYM o_eq '(' table_list ')'
+ TYPE_SYM opt_equal table_types { Lex->create_info.db_type= $3; }
+ | MAX_ROWS opt_equal ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
+ | MIN_ROWS opt_equal ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
+ | AVG_ROW_LENGTH opt_equal ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
+ | PASSWORD opt_equal TEXT_STRING { Lex->create_info.password=$3.str; }
+ | COMMENT_SYM opt_equal TEXT_STRING { Lex->create_info.comment=$3.str; }
+ | AUTO_INC opt_equal ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
+ | PACK_KEYS_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
+ | PACK_KEYS_SYM opt_equal DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
+ | CHECKSUM_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; }
+ | DELAY_KEY_WRITE_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; }
+ | ROW_FORMAT_SYM opt_equal row_types { Lex->create_info.row_type= $3; }
+ | RAID_TYPE opt_equal raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKS opt_equal ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKSIZE opt_equal ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | UNION_SYM opt_equal '(' table_list ')'
{
/* Move the union list to the merge_list */
LEX *lex=Lex;
@@ -924,19 +953,19 @@ create_table_option:
table_list->next=0;
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
- | opt_default CHARSET o_eq charset_name_or_default
- {
+ | opt_default CHARSET opt_equal charset_name_or_default
+ {
Lex->create_info.table_charset= $4;
Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET;
}
- | opt_default CHAR_SYM SET o_eq charset_name_or_default
- {
+ | opt_default CHAR_SYM SET opt_equal charset_name_or_default
+ {
Lex->create_info.table_charset= $5;
Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET;
}
- | INSERT_METHOD o_eq merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
- | DATA_SYM DIRECTORY_SYM o_eq TEXT_STRING { Lex->create_info.data_file_name= $4.str; }
- | INDEX DIRECTORY_SYM o_eq TEXT_STRING { Lex->create_info.index_file_name= $4.str; };
+ | INSERT_METHOD opt_equal merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
+ | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING { Lex->create_info.data_file_name= $4.str; }
+ | INDEX DIRECTORY_SYM opt_equal TEXT_STRING { Lex->create_info.index_file_name= $4.str; };
table_types:
ISAM_SYM { $$= DB_TYPE_ISAM; }
@@ -963,7 +992,7 @@ merge_insert_types:
| LAST_SYM { $$= MERGE_INSERT_TO_LAST; };
opt_select_from:
- /* empty */
+ opt_limit_clause {}
| select_from select_lock_type;
udf_func_type:
@@ -981,7 +1010,7 @@ field_list:
field_list_item:
- field_spec
+ field_spec check_constraint
| field_spec references
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
@@ -1003,10 +1032,16 @@ field_list_item:
lex->fk_match_option));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
- | opt_constraint CHECK_SYM '(' expr ')'
+ | opt_constraint check_constraint
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
- };
+ }
+ ;
+
+check_constraint:
+ /* empty */
+ | CHECK_SYM expr
+ ;
opt_constraint:
/* empty */
@@ -1023,7 +1058,7 @@ field_spec:
type opt_attribute
{
LEX *lex=Lex;
- if (add_field_to_list($1.str,
+ if (add_field_to_list(lex->thd, $1.str,
(enum enum_field_types) $3,
lex->length,lex->dec,lex->type,
lex->default_value, lex->comment,
@@ -1032,7 +1067,7 @@ field_spec:
};
type:
- int_type opt_len field_options { Lex->length=$2; $$=$1; }
+ int_type opt_len field_options { $$=$1; }
| real_type opt_precision field_options { $$=$1; }
| FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; }
| BIT_SYM opt_len { Lex->length=(char*) "1";
@@ -1043,7 +1078,7 @@ type:
$$=FIELD_TYPE_STRING; }
| char opt_binary { Lex->length=(char*) "1";
$$=FIELD_TYPE_STRING; }
- | BINARY '(' NUM ')' { Lex->length=$3.str;
+ | BINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=my_charset_bin;
$$=FIELD_TYPE_STRING; }
| varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
@@ -1051,16 +1086,22 @@ type:
| VARBINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=my_charset_bin;
$$=FIELD_TYPE_VAR_STRING; }
- | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; Lex->length=$2; }
+ | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; }
| DATE_SYM { $$=FIELD_TYPE_DATE; }
| TIME_SYM { $$=FIELD_TYPE_TIME; }
- | TIMESTAMP { $$=FIELD_TYPE_TIMESTAMP; }
+ | TIMESTAMP
+ {
+ if (YYTHD->sql_mode & MODE_SAPDB)
+ $$=FIELD_TYPE_DATETIME;
+ else
+ $$=FIELD_TYPE_TIMESTAMP;
+ }
| TIMESTAMP '(' NUM ')' { Lex->length=$3.str;
$$=FIELD_TYPE_TIMESTAMP; }
| DATETIME { $$=FIELD_TYPE_DATETIME; }
| TINYBLOB { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_TINY_BLOB; }
- | BLOB_SYM { Lex->charset=my_charset_bin;
+ | BLOB_SYM opt_len { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_BLOB; }
| GEOMETRY_SYM { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_GEOMETRY; }
@@ -1072,13 +1113,15 @@ type:
$$=FIELD_TYPE_MEDIUM_BLOB; }
| LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
| TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_BLOB; }
- | TEXT_SYM opt_binary { $$=FIELD_TYPE_BLOB; }
+ | TEXT_SYM opt_len opt_binary { $$=FIELD_TYPE_BLOB; }
| MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
| LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; }
| DECIMAL_SYM float_options field_options
{ $$=FIELD_TYPE_DECIMAL;}
| NUMERIC_SYM float_options field_options
{ $$=FIELD_TYPE_DECIMAL;}
+ | FIXED_SYM float_options field_options
+ { $$=FIELD_TYPE_DECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
{
LEX *lex=Lex;
@@ -1090,7 +1133,15 @@ type:
LEX *lex=Lex;
lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_SET;
- };
+ }
+ | LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
+ | SERIAL_SYM
+ {
+ $$=FIELD_TYPE_LONGLONG;
+ Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
+ UNIQUE_FLAG);
+ }
+ ;
char:
CHAR_SYM {}
@@ -1111,7 +1162,7 @@ int_type:
| BIGINT { $$=FIELD_TYPE_LONGLONG; };
real_type:
- REAL { $$= current_thd->sql_mode & MODE_REAL_AS_FLOAT ?
+ REAL { $$= YYTHD->sql_mode & MODE_REAL_AS_FLOAT ?
FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; }
| DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; }
| DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; };
@@ -1143,8 +1194,8 @@ field_option:
| ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; };
opt_len:
- /* empty */ { $$=(char*) 0; } /* use default length */
- | '(' NUM ')' { $$=$2.str; };
+ /* empty */ { Lex->length=(char*) 0; } /* use default length */
+ | '(' NUM ')' { Lex->length= $2.str; };
opt_precision:
/* empty */ {}
@@ -1163,25 +1214,28 @@ attribute:
| NOT NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
| DEFAULT literal { Lex->default_value=$2; }
| AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
- | PRIMARY_SYM KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; }
+ | SERIAL_SYM DEFAULT VALUE_SYM
+ { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG; }
+ | 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; };
+
charset_name:
BINARY
- {
+ {
if (!($$=get_charset_by_name("binary",MYF(0))))
{
- net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,"binary");
+ net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"binary");
YYABORT;
}
}
- | ident
- {
+ | ident
+ {
if (!($$=get_charset_by_name($1.str,MYF(0))))
{
- net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
YYABORT;
}
};
@@ -1201,13 +1255,20 @@ opt_db_default_character_set:
opt_binary:
/* empty */ { Lex->charset=NULL; }
+ | BYTE_SYM { Lex->charset=my_charset_bin; }
| BINARY { Lex->charset=my_charset_bin; }
| CHAR_SYM SET charset_name { Lex->charset=$3; } ;
+
+opt_primary:
+ /* empty */
+ | PRIMARY_SYM
+ ;
+
references:
REFERENCES table_ident
{
- LEX *lex=Lex;
+ LEX *lex=Lex;
lex->fk_delete_opt= lex->fk_update_opt= lex->fk_match_option= 0;
lex->ref_list.empty();
}
@@ -1215,7 +1276,7 @@ references:
{
$$=$2;
};
-
+
opt_ref_list:
/* empty */ opt_on_delete {}
| '(' ref_list ')' opt_on_delete {};
@@ -1303,11 +1364,11 @@ string_list:
alter:
ALTER opt_ignore TABLE_SYM table_ident
{
- THD *thd=current_thd;
+ THD *thd= YYTHD;
LEX *lex=&thd->lex;
lex->sql_command = SQLCOM_ALTER_TABLE;
lex->name=0;
- if (!lex->select_lex.add_table_to_list($4, NULL,1))
+ if (!lex->select_lex.add_table_to_list(thd, $4, NULL,1))
YYABORT;
lex->drop_primary=0;
lex->create_list.empty();
@@ -1317,15 +1378,15 @@ alter:
lex->alter_list.empty();
lex->select_lex.init_order();
lex->select_lex.db=lex->name=0;
- bzero((char*) &lex->create_info,sizeof(lex->create_info));
+ bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.db_type= DB_TYPE_DEFAULT;
lex->create_info.table_charset=thd->db_charset?thd->db_charset:default_charset_info;
lex->create_info.row_type= ROW_TYPE_NOT_USED;
lex->alter_keys_onoff=LEAVE_AS_IS;
lex->simple_alter=1;
}
- alter_list;
-
+ alter_list
+ {}
| ALTER DATABASE ident opt_db_default_character_set
{
LEX *lex=Lex;
@@ -1361,7 +1422,7 @@ alter_list_item:
type opt_attribute
{
LEX *lex=Lex;
- if (add_field_to_list($3.str,
+ if (add_field_to_list(lex->thd,$3.str,
(enum enum_field_types) $5,
lex->length,lex->dec,lex->type,
lex->default_value, lex->comment,
@@ -1403,7 +1464,7 @@ alter_list_item:
lex->simple_alter=0;
}
| RENAME opt_to table_ident
- {
+ {
LEX *lex=Lex;
lex->select_lex.db=$3->db.str;
lex->name= $3->table.str;
@@ -1435,31 +1496,35 @@ opt_to:
| EQ {}
| AS {};
+/*
+ The first two deprecate the last two--delete the last two for 4.1 release
+*/
+
slave:
START_SYM SLAVE slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_START;
- lex->type = 0;
- }
- |
- STOP_SYM SLAVE slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_STOP;
- lex->type = 0;
- };
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_START;
+ lex->type = 0;
+ }
+ | STOP_SYM SLAVE slave_thread_opts
+ {
+ LEX *lex=Lex;
+ lex->sql_command = SQLCOM_SLAVE_STOP;
+ lex->type = 0;
+ }
+ ;
slave_thread_opts:
slave_thread_opt
| slave_thread_opts ',' slave_thread_opt;
slave_thread_opt:
- /*empty*/ {}
+ /*empty*/ {}
| SQL_THREAD { Lex->slave_thd_opt|=SLAVE_SQL; }
| IO_THREAD { Lex->slave_thd_opt|=SLAVE_IO; }
;
-
+
restore:
RESTORE_SYM table_or_tables
{
@@ -1487,7 +1552,9 @@ repair:
lex->sql_command = SQLCOM_REPAIR;
lex->check_opt.init();
}
- table_list opt_mi_repair_type;
+ table_list opt_mi_repair_type
+ {}
+ ;
opt_mi_repair_type:
/* empty */ { Lex->check_opt.flags = T_MEDIUM; }
@@ -1509,7 +1576,9 @@ analyze:
lex->sql_command = SQLCOM_ANALYZE;
lex->check_opt.init();
}
- table_list opt_mi_check_type;
+ table_list opt_mi_check_type
+ {}
+ ;
check:
CHECK_SYM table_or_tables
@@ -1518,7 +1587,9 @@ check:
lex->sql_command = SQLCOM_CHECK;
lex->check_opt.init();
}
- table_list opt_mi_check_type;
+ table_list opt_mi_check_type
+ {}
+ ;
opt_mi_check_type:
/* empty */ { Lex->check_opt.flags = T_MEDIUM; }
@@ -1542,14 +1613,18 @@ optimize:
lex->sql_command = SQLCOM_OPTIMIZE;
lex->check_opt.init();
}
- table_list opt_mi_check_type;
+ table_list opt_mi_check_type
+ {}
+ ;
rename:
RENAME table_or_tables
{
Lex->sql_command=SQLCOM_RENAME_TABLE;
}
- table_to_table_list;
+ table_to_table_list
+ {}
+ ;
table_to_table_list:
table_to_table
@@ -1557,12 +1632,13 @@ table_to_table_list:
table_to_table:
table_ident TO_SYM table_ident
- {
- SELECT_LEX_NODE *sl= Lex->current_select;
- if (!sl->add_table_to_list($1,NULL,1,TL_IGNORE) ||
- !sl->add_table_to_list($3,NULL,1,TL_IGNORE))
+ {
+ LEX *lex=Lex;
+ SELECT_LEX_NODE *sl= lex->current_select;
+ if (!sl->add_table_to_list(lex->thd, $1,NULL,1,TL_IGNORE) ||
+ !sl->add_table_to_list(lex->thd, $3,NULL,1,TL_IGNORE))
YYABORT;
- };
+ };
/*
Select : retrieve data from table
@@ -1572,50 +1648,59 @@ table_to_table:
select:
select_init { Lex->sql_command=SQLCOM_SELECT; };
+/* Need select_init2 for subselects. */
select_init:
- SELECT_SYM select_part2
- {
- LEX *lex= Lex;
- if (lex->current_select->set_braces(false))
- {
- send_error(lex->thd, ER_SYNTAX_ERROR);
- YYABORT;
- }
- }
- union
+ SELECT_SYM select_init2
|
- '(' SELECT_SYM select_part2 ')'
- {
+ '(' SELECT_SYM select_part2 ')'
+ {
LEX *lex= Lex;
SELECT_LEX_NODE * sel= lex->current_select;
- if (sel->set_braces(true))
+ if (sel->set_braces(1))
{
send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT;
}
/* select in braces, can't contain global parameters */
sel->master_unit()->global_parameters=
- sel->master_unit();
+ sel->master_unit();
} union_opt;
+select_init2:
+ select_part2
+ {
+ LEX *lex= Lex;
+ if (lex->current_select->set_braces(0))
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ }
+ union_clause
+ ;
+
select_part2:
{
LEX *lex=Lex;
- lex->lock_option=TL_READ;
- mysql_init_select(lex);
+ if (lex->current_select == &lex->select_lex)
+ lex->lock_option= TL_READ; /* Only for global SELECT */
+ mysql_init_select(lex);
}
select_options select_item_list select_into select_lock_type;
select_into:
- limit_clause {}
+ opt_limit_clause {}
+ | FROM DUAL_SYM /* oracle compatibility: oracle always requires FROM
+ clause, and DUAL is system table without fields.
+ Is "SELECT 1 FROM DUAL" any better than
+ "SELECT 1" ? Hmmm :) */
+ | into
| select_from
- | opt_into
- | opt_into select_from
- | select_from opt_into;
+ | into select_from
+ | select_from into;
select_from:
- FROM join_table_list where_clause group_clause having_clause opt_order_clause limit_clause procedure_clause;
-
+ FROM join_table_list where_clause group_clause having_clause opt_order_clause opt_limit_clause procedure_clause;
select_options:
/* empty*/
@@ -1648,7 +1733,7 @@ select_option:
YYABORT;
Select->options|= OPTION_FOUND_ROWS;
}
- | SQL_NO_CACHE_SYM { current_thd->safe_to_cache_query=0; }
+ | SQL_NO_CACHE_SYM { Lex->safe_to_cache_query=0; }
| SQL_CACHE_SYM { Select->options|= OPTION_TO_QUERY_CACHE; }
| ALL {}
;
@@ -1658,18 +1743,15 @@ select_lock_type:
| FOR_SYM UPDATE_SYM
{
LEX *lex=Lex;
- if (check_simple_select())
- YYABORT;
- lex->lock_option= TL_WRITE;
- lex->thd->safe_to_cache_query=0;
+ lex->current_select->set_lock_for_tables(TL_WRITE);
+ lex->safe_to_cache_query=0;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
LEX *lex=Lex;
- if (check_simple_select())
- YYABORT;
- lex->lock_option= TL_READ_WITH_SHARED_LOCKS;
- lex->thd->safe_to_cache_query=0;
+ lex->current_select->
+ set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
+ lex->safe_to_cache_query=0;
}
;
@@ -1678,7 +1760,7 @@ select_item_list:
| select_item
| '*'
{
- if (add_item_to_list(new Item_field(NULL,NULL,"*")))
+ if (add_item_to_list(YYTHD, new Item_field(NULL,NULL,"*")))
YYABORT;
};
@@ -1686,7 +1768,7 @@ select_item_list:
select_item:
remember_name select_item2 remember_end select_alias
{
- if (add_item_to_list($2))
+ if (add_item_to_list(YYTHD, $2))
YYABORT;
if ($4.str)
$2->set_name($4.str);
@@ -1719,17 +1801,35 @@ optional_braces:
expr: expr_expr { $$= $1; }
| simple_expr { $$= $1; };
+comp_op: EQ { $$ = &comp_eq_creator; }
+ | GE { $$ = &comp_ge_creator; }
+ | GT_SYM { $$ = &comp_gt_creator; }
+ | LE { $$ = &comp_le_creator; }
+ | LT { $$ = &comp_lt_creator; }
+ | NE { $$ = &comp_ne_creator; }
+ ;
+
+all_or_any: ALL { $$ = 1; }
+ | ANY_SYM { $$ = 0; }
+ ;
+
/* expressions that begin with 'expr' */
expr_expr:
- expr IN_SYM '(' expr_list ')'
+ expr IN_SYM '(' expr_list ')'
{ $$= new Item_func_in($1,*$4); }
| expr NOT IN_SYM '(' expr_list ')'
{ $$= new Item_func_not(new Item_func_in($1,*$5)); }
+ | expr IN_SYM in_subselect
+ { $$= new Item_in_subselect(YYTHD, $1, $3); }
+ | expr NOT IN_SYM in_subselect
+ {
+ $$= new Item_func_not(new Item_in_subselect(YYTHD, $1, $4));
+ }
| expr BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_between($1,$3,$5); }
| expr NOT BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
| expr OR expr { $$= new Item_cond_or($1,$3); }
| expr XOR expr { $$= new Item_cond_xor($1,$3); }
| expr AND expr { $$= new Item_cond_and($1,$3); }
@@ -1739,21 +1839,27 @@ expr_expr:
| expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
| expr IS NULL_SYM { $$= new Item_func_isnull($1); }
| expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | expr EQ expr { $$= new Item_func_eq($1,$3); }
| expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | expr GE expr { $$= new Item_func_ge($1,$3); }
- | expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
- | expr LE expr { $$= new Item_func_le($1,$3); }
- | expr LT expr { $$= new Item_func_lt($1,$3); }
- | expr NE expr { $$= new Item_func_ne($1,$3); }
+ | expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); }
+ | expr comp_op all_or_any in_subselect %prec EQ
+ {
+ Item_allany_subselect *it=
+ new Item_allany_subselect(YYTHD, $1, (*$2)($3), $4);
+ if ($3)
+ $$ = new Item_func_not(it); /* ALL */
+ else
+ $$ = it; /* ANY/SOME */
+ }
| expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
| expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
| expr '+' expr { $$= new Item_func_plus($1,$3); }
| expr '-' expr { $$= new Item_func_minus($1,$3); }
| expr '*' expr { $$= new Item_func_mul($1,$3); }
| expr '/' expr { $$= new Item_func_div($1,$3); }
+ | expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
+ | expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
| expr '|' expr { $$= new Item_func_bit_or($1,$3); }
- | expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
+ | expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
| expr '&' expr { $$= new Item_func_bit_and($1,$3); }
| expr '%' expr { $$= new Item_func_mod($1,$3); }
| expr '+' INTERVAL_SYM expr interval
@@ -1769,7 +1875,7 @@ no_in_expr:
{ $$= new Item_func_between($1,$3,$5); }
| no_in_expr NOT BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
| no_in_expr OR expr { $$= new Item_cond_or($1,$3); }
| no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); }
| no_in_expr AND expr { $$= new Item_cond_and($1,$3); }
@@ -1779,23 +1885,29 @@ no_in_expr:
| no_in_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
| no_in_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
| no_in_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | no_in_expr EQ expr { $$= new Item_func_eq($1,$3); }
| no_in_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | no_in_expr GE expr { $$= new Item_func_ge($1,$3); }
- | no_in_expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
- | no_in_expr LE expr { $$= new Item_func_le($1,$3); }
- | no_in_expr LT expr { $$= new Item_func_lt($1,$3); }
- | no_in_expr NE expr { $$= new Item_func_ne($1,$3); }
+ | no_in_expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); }
+ | no_in_expr comp_op all_or_any in_subselect %prec EQ
+ {
+ Item_allany_subselect *it=
+ new Item_allany_subselect(YYTHD, $1, (*$2)($3), $4);
+ if ($3)
+ $$ = new Item_func_not(it); /* ALL */
+ else
+ $$ = it; /* ANY/SOME */
+ }
| no_in_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
| no_in_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
| no_in_expr '+' expr { $$= new Item_func_plus($1,$3); }
| no_in_expr '-' expr { $$= new Item_func_minus($1,$3); }
| no_in_expr '*' expr { $$= new Item_func_mul($1,$3); }
| no_in_expr '/' expr { $$= new Item_func_div($1,$3); }
+ | no_in_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
| no_in_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
| no_in_expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
| no_in_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
| no_in_expr '%' expr { $$= new Item_func_mod($1,$3); }
+ | no_in_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
| no_in_expr '+' INTERVAL_SYM expr interval
{ $$= new Item_date_add_interval($1,$4,$5,0); }
| no_in_expr '-' INTERVAL_SYM expr interval
@@ -1804,15 +1916,21 @@ no_in_expr:
/* expressions that begin with 'expr' that does NOT follow AND */
no_and_expr:
- no_and_expr IN_SYM '(' expr_list ')'
- { $$= new Item_func_in($1,*$4); }
+ no_and_expr IN_SYM '(' expr_list ')'
+ { $$= new Item_func_in($1,*$4); }
| no_and_expr NOT IN_SYM '(' expr_list ')'
{ $$= new Item_func_not(new Item_func_in($1,*$5)); }
+ | no_and_expr IN_SYM in_subselect
+ { $$= new Item_in_subselect(YYTHD, $1, $3); }
+ | no_and_expr NOT IN_SYM in_subselect
+ {
+ $$= new Item_func_not(new Item_in_subselect(YYTHD, $1, $4));
+ }
| no_and_expr BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_between($1,$3,$5); }
| no_and_expr NOT BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
| no_and_expr OR expr { $$= new Item_cond_or($1,$3); }
| no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); }
| no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
@@ -1821,23 +1939,29 @@ no_and_expr:
| no_and_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
| no_and_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
| no_and_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | no_and_expr EQ expr { $$= new Item_func_eq($1,$3); }
| no_and_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | no_and_expr GE expr { $$= new Item_func_ge($1,$3); }
- | no_and_expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
- | no_and_expr LE expr { $$= new Item_func_le($1,$3); }
- | no_and_expr LT expr { $$= new Item_func_lt($1,$3); }
- | no_and_expr NE expr { $$= new Item_func_ne($1,$3); }
+ | no_and_expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); }
+ | no_and_expr comp_op all_or_any in_subselect %prec EQ
+ {
+ Item_allany_subselect *it=
+ new Item_allany_subselect(YYTHD, $1, (*$2)($3), $4);
+ if ($3)
+ $$ = new Item_func_not(it); /* ALL */
+ else
+ $$ = it; /* ANY/SOME */
+ }
| no_and_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
| no_and_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
| no_and_expr '+' expr { $$= new Item_func_plus($1,$3); }
| no_and_expr '-' expr { $$= new Item_func_minus($1,$3); }
| no_and_expr '*' expr { $$= new Item_func_mul($1,$3); }
| no_and_expr '/' expr { $$= new Item_func_div($1,$3); }
+ | no_and_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
| no_and_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
| no_and_expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
| no_and_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
| no_and_expr '%' expr { $$= new Item_func_mod($1,$3); }
+ | no_and_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
| no_and_expr '+' INTERVAL_SYM expr interval
{ $$= new Item_date_add_interval($1,$4,$5,0); }
| no_and_expr '-' INTERVAL_SYM expr interval
@@ -1851,12 +1975,12 @@ simple_expr:
| '@' ident_or_text SET_VAR expr
{
$$= new Item_func_set_user_var($2,$4);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
- | '@' ident_or_text
+ | '@' ident_or_text
{
$$= new Item_func_get_user_var($2);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| '@' '@' opt_var_ident_type ident_or_text
{
@@ -1869,6 +1993,13 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; }
+ /* Note: In SQL-99 "ROW" is optional, but not having it mandatory
+ causes conflicts with the INTERVAL syntax. */
+ | ROW_SYM '(' expr ',' expr_list ')'
+ {
+ $5->push_front($3);
+ $$= new Item_row(*$5);
+ }
| EXISTS exists_subselect { $$= $2; }
| singleval_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
@@ -1910,22 +2041,22 @@ simple_expr:
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
| CURDATE optional_braces
- { $$= new Item_func_curdate(); current_thd->safe_to_cache_query=0; }
+ { $$= new Item_func_curdate(); Lex->safe_to_cache_query=0; }
| CURTIME optional_braces
- { $$= new Item_func_curtime(); current_thd->safe_to_cache_query=0; }
+ { $$= new Item_func_curtime(); Lex->safe_to_cache_query=0; }
| CURTIME '(' expr ')'
- {
- $$= new Item_func_curtime($3);
- current_thd->safe_to_cache_query=0;
+ {
+ $$= new Item_func_curtime($3);
+ Lex->safe_to_cache_query=0;
}
| DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,0); }
| DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
{ $$= new Item_date_add_interval($3,$6,$7,1); }
| DATABASE '(' ')'
- {
+ {
$$= new Item_func_database();
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| ELT_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_elt($3, *$5); }
@@ -1934,7 +2065,7 @@ simple_expr:
| ENCRYPT '(' expr ')'
{
$$= new Item_func_encrypt($3);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_encrypt($3,$5); }
| DECODE_SYM '(' expr ',' TEXT_STRING ')'
@@ -1955,6 +2086,8 @@ simple_expr:
{ $$= new Item_func_export_set($3, $5, $7, $9); }
| EXPORT_SET '(' expr ',' expr ',' expr ',' expr ',' expr ')'
{ $$= new Item_func_export_set($3, $5, $7, $9, $11); }
+ | FALSE_SYM
+ { $$= new Item_int((char*) "FALSE",0,1); }
| FORMAT_SYM '(' expr ',' NUM ')'
{ $$= new Item_func_format($3,atoi($5.str)); }
| FROM_UNIXTIME '(' expr ')'
@@ -1970,8 +2103,8 @@ simple_expr:
| GEOMFROMTEXT '(' expr ',' expr ')'
{ $$= new Item_func_geometry_from_text($3); }
| GEOMETRYCOLLECTION '(' expr_list ')'
- { $$= new Item_func_spatial_collection(* $3,
- Geometry::wkbGeometryCollection,
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbGeometryCollection,
Geometry::wkbPoint); }
| HOUR_SYM '(' expr ')'
{ $$= new Item_func_hour($3); }
@@ -1992,12 +2125,12 @@ simple_expr:
| LAST_INSERT_ID '(' expr ')'
{
$$= new Item_func_set_last_insert_id($3);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
| LINESTRING '(' expr_list ')'
- { $$= new Item_func_spatial_collection(* $3,
+ { $$= new Item_func_spatial_collection(* $3,
Geometry::wkbLineString, Geometry::wkbPoint); }
| LOCATE '(' expr ',' expr ')'
{ $$= new Item_func_locate($5,$3); }
@@ -2021,10 +2154,12 @@ simple_expr:
{ $$= new Item_func_geometry_from_text($3); }
| MINUTE_SYM '(' expr ')'
{ $$= new Item_func_minute($3); }
+ | MOD_SYM '(' expr ',' expr ')'
+ { $$ = new Item_func_mod( $3, $5); }
| MONTH_SYM '(' expr ')'
{ $$= new Item_func_month($3); }
| MULTILINESTRING '(' expr_list ')'
- { $$= new Item_func_spatial_collection(* $3,
+ { $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiLineString, Geometry::wkbLineString); }
| MLINEFROMTEXT '(' expr ')'
{ $$= new Item_func_geometry_from_text($3); }
@@ -2039,15 +2174,15 @@ simple_expr:
| MPOLYFROMTEXT '(' expr ',' expr ')'
{ $$= new Item_func_geometry_from_text($3); }
| MULTIPOINT '(' expr_list ')'
- { $$= new Item_func_spatial_collection(* $3,
+ { $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiPoint, Geometry::wkbPoint); }
| MULTIPOLYGON '(' expr_list ')'
- { $$= new Item_func_spatial_collection(* $3,
+ { $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiPolygon, Geometry::wkbPolygon ); }
| NOW_SYM optional_braces
- { $$= new Item_func_now(); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_now(); Lex->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
- { $$= new Item_func_now($3); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;}
| PASSWORD '(' expr ')'
{
$$= new Item_func_password($3);
@@ -2061,14 +2196,14 @@ simple_expr:
| POLYFROMTEXT '(' expr ',' expr ')'
{ $$= new Item_func_geometry_from_text($3); }
| POLYGON '(' expr_list ')'
- { $$= new Item_func_spatial_collection(* $3,
+ { $$= new Item_func_spatial_collection(* $3,
Geometry::wkbPolygon, Geometry::wkbLineString); }
| POSITION_SYM '(' no_in_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
| RAND '(' expr ')'
- { $$= new Item_func_rand($3); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_rand($3); Lex->safe_to_cache_query=0;}
| RAND '(' ')'
- { $$= new Item_func_rand(); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_rand(); Lex->safe_to_cache_query=0;}
| REPLACE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_replace($3,$5,$7); }
| RIGHT '(' expr ',' expr ')'
@@ -2100,6 +2235,8 @@ simple_expr:
{ $$= new Item_func_trim($5,$3); }
| TRUNCATE_SYM '(' expr ',' expr ')'
{ $$= new Item_func_round($3,$5,1); }
+ | TRUE_SYM
+ { $$= new Item_int((char*) "TRUE",1,1); }
| UDA_CHAR_SUM '(' udf_expr_list ')'
{
if ($3 != NULL)
@@ -2143,18 +2280,18 @@ simple_expr:
$$ = new Item_func_udf_int($1);
}
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
- {
+ {
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
}
| UNIX_TIMESTAMP '(' ')'
{
$$= new Item_func_unix_timestamp();
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); current_thd->safe_to_cache_query=0; }
+ { $$= new Item_func_user(); Lex->safe_to_cache_query=0; }
| WEEK_SYM '(' expr ')'
{ $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); }
| WEEK_SYM '(' expr ',' expr ')'
@@ -2166,9 +2303,9 @@ simple_expr:
| YEARWEEK '(' expr ',' expr ')'
{ $$= new Item_func_yearweek($3, $5); }
| BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
- {
+ {
$$=new Item_func_benchmark($3,$5);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new Item_extract( $3, $5); };
@@ -2207,7 +2344,7 @@ in_sum_expr:
if (lex->current_select->inc_in_sum_expr())
{
send_error(lex->thd, ER_SYNTAX_ERROR);
- YYABORT;
+ YYABORT;
}
}
expr
@@ -2218,13 +2355,15 @@ in_sum_expr:
cast_type:
BINARY { $$=ITEM_CAST_BINARY; }
+ | CHAR_SYM { $$=ITEM_CAST_CHAR; }
| SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; }
| SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
| UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; }
| UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; }
| DATE_SYM { $$=ITEM_CAST_DATE; }
| TIME_SYM { $$=ITEM_CAST_TIME; }
- | DATETIME { $$=ITEM_CAST_DATETIME; };
+ | DATETIME { $$=ITEM_CAST_DATETIME; }
+ ;
expr_list:
{ Select->expr_list.push_front(new List<Item>); }
@@ -2264,7 +2403,7 @@ when_list:
when_list2:
expr THEN_SYM expr
{
- SELECT_LEX_NODE *sel=Select;
+ SELECT_LEX_NODE *sel=Select;
sel->when_list.head()->push_back($1);
sel->when_list.head()->push_back($3);
}
@@ -2334,39 +2473,39 @@ join_table:
}
table_ident opt_table_alias opt_key_definition
{
- SELECT_LEX_NODE *sel=Select;
- if (!($$= sel->add_table_to_list($2, $3, 0, TL_UNLOCK,
+ LEX *lex= Lex;
+ SELECT_LEX_NODE *sel= lex->current_select;
+ if (!($$= sel->add_table_to_list(lex->thd, $2, $3, 0,
+ lex->lock_option,
sel->get_use_index(),
sel->get_ignore_index())))
YYABORT;
}
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
- | '(' SELECT_SYM select_part3 ')' opt_table_alias
+ | '(' SELECT_SYM select_derived ')' opt_table_alias
{
LEX *lex=Lex;
SELECT_LEX_UNIT *unit= lex->current_select->master_unit();
lex->current_select= unit->outer_select();
if (!($$= lex->current_select->
- add_table_to_list(new Table_ident(unit), $5, 0, TL_UNLOCK)))
+ add_table_to_list(lex->thd, new Table_ident(unit), $5, 0,
+ lex->lock_option)))
YYABORT;
};
-select_part3:
+select_derived:
{
LEX *lex= Lex;
- lex->derived_tables= true;
- if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
+ lex->derived_tables= 1;
+ if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE ||
mysql_new_select(lex, 1))
YYABORT;
mysql_init_select(lex);
lex->current_select->linkage= DERIVED_TABLE_TYPE;
}
- select_options select_item_list select_intoto;
-
-select_intoto:
- limit_clause {}
- | select_from;
+ select_options select_item_list opt_select_from
+ ;
opt_outer:
/* empty */ {}
@@ -2450,16 +2589,25 @@ opt_table_alias:
where_clause:
- /* empty */ { Select->select_lex()->where= 0; }
- | WHERE expr { Select->select_lex()->where= $2; };
+ /* empty */ { Select->select_lex()->where= 0; }
+ | WHERE expr
+ {
+ Select->select_lex()->where= $2;
+ if ($2)
+ $2->top_level_item();
+ }
+ ;
having_clause:
/* empty */
| HAVING { Select->select_lex()->create_refs= 1; } expr
- {
- SELECT_LEX *sel= Select->select_lex();
- sel->having= $3; sel->create_refs=0;
- };
+ {
+ SELECT_LEX *sel= Select->select_lex();
+ sel->having= $3; sel->create_refs=0;
+ if ($3)
+ $3->top_level_item();
+ }
+ ;
opt_escape:
ESCAPE_SYM TEXT_STRING { $$= $2.str; }
@@ -2476,16 +2624,16 @@ group_clause:
group_list:
group_list ',' order_ident order_dir
- { if (add_group_to_list($3,(bool) $4)) YYABORT; }
+ { if (add_group_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
| order_ident order_dir
- { if (add_group_to_list($1,(bool) $2)) YYABORT; };
+ { if (add_group_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
olap_opt:
/* empty */ {}
| WITH CUBE_SYM
{
LEX *lex=Lex;
- lex->olap = true;
+ lex->olap= 1;
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
net_printf(lex->thd, ER_WRONG_USAGE, "WITH CUBE",
@@ -2499,7 +2647,7 @@ olap_opt:
| WITH ROLLUP_SYM
{
LEX *lex= Lex;
- lex->olap= true;
+ lex->olap= 1;
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
net_printf(lex->thd, ER_WRONG_USAGE, "WITH ROLLUP",
@@ -2521,14 +2669,9 @@ opt_order_clause:
| order_clause;
order_clause:
- ORDER_SYM BY
- {
+ ORDER_SYM BY
+ {
LEX *lex=Lex;
- if (lex->sql_command == SQLCOM_MULTI_UPDATE)
- {
- net_printf(lex->thd, ER_WRONG_USAGE, "UPDATE", "ORDER BY");
- YYABORT;
- }
if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
lex->current_select->select_lex()->olap !=
UNSPECIFIED_OLAP_TYPE)
@@ -2542,9 +2685,9 @@ order_clause:
order_list:
order_list ',' order_ident order_dir
- { if (add_order_to_list($3,(bool) $4)) YYABORT; }
+ { if (add_order_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
| order_ident order_dir
- { if (add_order_to_list($1,(bool) $2)) YYABORT; };
+ { if (add_order_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
order_dir:
/* empty */ { $$ = 1; }
@@ -2552,9 +2695,13 @@ order_dir:
| DESC { $$ =0; };
-limit_clause:
+opt_limit_clause:
/* empty */ {}
- | LIMIT ULONG_NUM
+ | limit_clause {}
+ ;
+
+limit_clause:
+ LIMIT
{
LEX *lex= Lex;
if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
@@ -2565,35 +2712,37 @@ limit_clause:
"LIMIT");
YYABORT;
}
+ }
+ limit_options
+ {}
+ ;
+
+limit_options:
+ ULONG_NUM
+ {
+ SELECT_LEX_NODE *sel= Select;
+ sel->select_limit= $1;
+ sel->offset_limit= 0L;
+ }
+ | ULONG_NUM ',' ULONG_NUM
+ {
SELECT_LEX_NODE *sel= Select;
- sel->select_limit= $2;
- sel->offset_limit= 0L;
+ sel->select_limit= $3;
+ sel->offset_limit= $1;
}
- | LIMIT ULONG_NUM ',' ULONG_NUM
+ | ULONG_NUM OFFSET_SYM ULONG_NUM
{
- LEX *lex=Lex;
- if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
- lex->current_select->select_lex()->olap !=
- UNSPECIFIED_OLAP_TYPE)
- {
- net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP",
- "LIMIT");
- YYABORT;
- }
- SELECT_LEX_NODE *sel= lex->current_select;
- sel->select_limit= $4;
- sel->offset_limit= $2;
- };
+ SELECT_LEX_NODE *sel= Select;
+ sel->select_limit= $1;
+ sel->offset_limit= $3;
+ }
+ ;
+
delete_limit_clause:
/* empty */
{
LEX *lex=Lex;
- if (lex->sql_command == SQLCOM_MULTI_UPDATE)
- {
- net_printf(lex->thd, ER_WRONG_USAGE, "DELETE", "LIMIT");
- YYABORT;
- }
lex->current_select->select_limit= HA_POS_ERROR;
}
| LIMIT ulonglong_num
@@ -2617,12 +2766,19 @@ procedure_clause:
| PROCEDURE ident /* Procedure name */
{
LEX *lex=Lex;
+ if (&lex->select_lex != lex->current_select)
+ {
+ net_printf(lex->thd, ER_WRONG_USAGE,
+ "PROCEDURE",
+ "subquery");
+ YYABORT;
+ }
lex->proc_list.elements=0;
lex->proc_list.first=0;
lex->proc_list.next= (byte**) &lex->proc_list.first;
- if (add_proc_to_list(new Item_field(NULL,NULL,$2.str)))
+ if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str)))
YYABORT;
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
'(' procedure_list ')';
@@ -2638,10 +2794,11 @@ procedure_list2:
procedure_item:
remember_name expr
{
- if (add_proc_to_list($2))
+ LEX *lex= Lex;
+ if (add_proc_to_list(lex->thd, $2))
YYABORT;
if (!$2->name)
- $2->set_name($1,(uint) ((char*) Lex->tok_end - $1));
+ $2->set_name($1,(uint) ((char*) lex->tok_end - $1));
}
;
@@ -2652,7 +2809,8 @@ select_var_list_init:
if (!lex->describe && (!(lex->result= new select_dumpvar())))
YYABORT;
}
- select_var_list
+ select_var_list
+ {}
;
select_var_list:
@@ -2668,7 +2826,7 @@ select_var_ident: '@' ident_or_text
}
;
-opt_into:
+into:
INTO OUTFILE TEXT_STRING
{
LEX *lex=Lex;
@@ -2694,7 +2852,7 @@ opt_into:
}
| INTO select_var_list_init
{
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
;
@@ -2702,24 +2860,28 @@ opt_into:
DO statement
*/
-do: DO_SYM
+do: DO_SYM
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DO;
if (!(lex->insert_list = new List_item))
YYABORT;
}
- values;
+ values
+ {}
+ ;
+
/*
Drop : delete tables or index
*/
drop:
- DROP TABLE_SYM if_exists table_list opt_restrict
+ DROP opt_temporary TABLE_SYM if_exists table_list opt_restrict
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_TABLE;
- lex->drop_if_exists = $3;
+ lex->drop_temporary= $2;
+ lex->drop_if_exists= $4;
}
| DROP INDEX ident ON table_ident {}
{
@@ -2728,7 +2890,7 @@ drop:
lex->drop_list.empty();
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
- if (!lex->current_select->add_table_to_list($5,NULL, 1))
+ if (!lex->current_select->add_table_to_list(lex->thd, $5,NULL, 1))
YYABORT;
}
| DROP DATABASE if_exists ident
@@ -2752,37 +2914,63 @@ table_list:
table_name:
table_ident
- { if (!Select->add_table_to_list($1, NULL, 1)) YYABORT; };
+ { if (!Select->add_table_to_list(YYTHD, $1, NULL, 1)) YYABORT; };
if_exists:
- /* empty */ { $$=0; }
- | IF EXISTS { $$= 1; };
+ /* empty */ { $$= 0; }
+ | IF EXISTS { $$= 1; }
+ ;
+opt_temporary:
+ /* empty */ { $$= 0; }
+ | TEMPORARY { $$= 1; }
+ ;
/*
** Insert : add new data to table
*/
insert:
- INSERT { Lex->sql_command = SQLCOM_INSERT; } insert_lock_option opt_ignore insert2 insert_field_spec;
+ INSERT
+ {
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_INSERT;
+ /* for subselects */
+ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
+ } insert_lock_option
+ opt_ignore insert2
+ {
+ Select->set_lock_for_tables($3);
+ }
+ insert_field_spec opt_insert_update
+ {}
+ ;
replace:
REPLACE
{
- LEX *lex=Lex;
+ LEX *lex=Lex;
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
}
- replace_lock_option insert2 insert_field_spec;
+ replace_lock_option insert2
+ {
+ Select->set_lock_for_tables($3);
+ }
+ insert_field_spec
+ {}
+ {}
+ ;
insert_lock_option:
- /* empty */ { Lex->lock_option= TL_WRITE_CONCURRENT_INSERT; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; }
- | DELAYED_SYM { Lex->lock_option= TL_WRITE_DELAYED; }
- | HIGH_PRIORITY { Lex->lock_option= TL_WRITE; };
+ /* empty */ { $$= TL_WRITE_CONCURRENT_INSERT; }
+ | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
+ | DELAYED_SYM { $$= TL_WRITE_DELAYED; }
+ | HIGH_PRIORITY { $$= TL_WRITE; }
+ ;
replace_lock_option:
- opt_low_priority {}
- | DELAYED_SYM { Lex->lock_option= TL_WRITE_DELAYED; };
+ opt_low_priority { $$= $1; }
+ | DELAYED_SYM { $$= TL_WRITE_DELAYED; };
insert2:
INTO insert_table {}
@@ -2819,6 +3007,7 @@ fields:
insert_values:
VALUES values_list {}
+ | VALUE_SYM values_list {}
| SELECT_SYM
{
LEX *lex=Lex;
@@ -2827,8 +3016,9 @@ insert_values:
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(lex);
}
- select_options select_item_list select_from select_lock_type
- union {};
+ select_options select_item_list opt_select_from select_lock_type
+ union_clause {}
+ ;
values_list:
values_list ',' no_braces
@@ -2888,79 +3078,112 @@ values:
;
expr_or_default:
- expr { $$= $1;}
+ expr { $$= $1;}
| DEFAULT {$$= new Item_default(); }
;
+opt_insert_update:
+ /* empty */
+ | ON DUPLICATE
+ { /* for simplisity, let's forget about
+ INSERT ... SELECT ... UPDATE
+ for a moment */
+ if (Lex->sql_command != SQLCOM_INSERT)
+ {
+ send_error(Lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ }
+ KEY_SYM UPDATE_SYM update_list
+ ;
+
/* Update rows in a table */
update:
- UPDATE_SYM
- {
+ UPDATE_SYM
+ {
LEX *lex= Lex;
lex->sql_command= SQLCOM_UPDATE;
lex->select_lex.init_order();
}
- opt_low_priority opt_ignore join_table_list SET update_list where_clause opt_order_clause delete_limit_clause;
+ opt_low_priority opt_ignore join_table_list
+ SET update_list where_clause opt_order_clause delete_limit_clause
+ {
+ LEX *lex= Lex;
+ Select->set_lock_for_tables($3);
+ if (lex->select_lex.table_list.elements > 1)
+ lex->sql_command=SQLCOM_UPDATE_MULTI;
+ }
+ ;
update_list:
update_list ',' simple_ident equal expr
{
- if (add_item_to_list($3) || add_value_to_list($5))
+ if (add_item_to_list(YYTHD, $3) || add_value_to_list(YYTHD, $5))
YYABORT;
}
| simple_ident equal expr
{
- if (add_item_to_list($1) || add_value_to_list($3))
+ if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
YYABORT;
};
opt_low_priority:
- /* empty */ { Lex->lock_option= current_thd->update_lock_default; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; };
+ /* empty */ { $$= YYTHD->update_lock_default; }
+ | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
/* Delete rows from a table */
delete:
DELETE_SYM
- {
+ {
LEX *lex= Lex;
lex->sql_command= SQLCOM_DELETE;
lex->select_lex.options= 0;
lex->lock_option= lex->thd->update_lock_default;
lex->select_lex.init_order();
}
- opt_delete_options single_multi {};
+ opt_delete_options single_multi {}
+ ;
single_multi:
- FROM table_name where_clause opt_order_clause delete_limit_clause {}
+ FROM table_ident
+ {
+ if (!Select->add_table_to_list(YYTHD, $2, NULL, 1, Lex->lock_option))
+ YYABORT;
+ }
+ where_clause opt_order_clause
+ delete_limit_clause {}
| table_wild_list
{ mysql_init_multi_delete(Lex); }
- FROM join_table_list where_clause
+ FROM join_table_list where_clause
| FROM table_wild_list
{ mysql_init_multi_delete(Lex); }
- USING join_table_list where_clause;
+ USING join_table_list where_clause
+ {}
+ ;
table_wild_list:
table_wild_one {}
| table_wild_list ',' table_wild_one {};
table_wild_one:
- ident opt_wild
- {
- if (!Select->add_table_to_list(new Table_ident($1), NULL, 1,
- TL_WRITE))
- YYABORT;
- }
- | ident '.' ident opt_wild
- {
- if (!Select->add_table_to_list(new Table_ident($1, $3, 0), NULL,
- 1, TL_WRITE))
+ ident opt_wild
+ {
+ if (!Select->add_table_to_list(YYTHD, new Table_ident($1), NULL, 1,
+ Lex->lock_option))
+ YYABORT;
+ }
+ | ident '.' ident opt_wild
+ {
+ if (!Select->add_table_to_list(YYTHD, new Table_ident($1, $3, 0),
+ NULL, 1, Lex->lock_option))
YYABORT;
- };
+ }
+ ;
opt_wild:
- /* empty */ {}
+ /* empty */ {}
| '.' '*' {};
@@ -2979,15 +3202,24 @@ truncate:
lex->sql_command= SQLCOM_TRUNCATE;
lex->select_lex.options= 0;
lex->select_lex.init_order();
- lex->lock_option= lex->thd->update_lock_default; };
+ }
+ ;
opt_table_sym:
/* empty */
| TABLE_SYM;
-
+
/* Show things */
-show: SHOW { Lex->wild=0;} show_param;
+show: SHOW
+ {
+ LEX *lex=Lex;
+ lex->wild=0;
+ bzero((char*) &lex->create_info,sizeof(lex->create_info));
+ }
+ show_param
+ {}
+ ;
show_param:
DATABASES wild
@@ -3018,10 +3250,10 @@ show_param:
Lex->sql_command= SQLCOM_SHOW_FIELDS;
if ($5)
$4->change_db($5);
- if (!Select->add_table_to_list($4, NULL, 0))
+ if (!Select->add_table_to_list(YYTHD, $4, NULL, 0))
YYABORT;
}
- | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
+ | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
TEXT_STRING AND MASTER_LOG_POS_SYM EQ ulonglong_num
AND MASTER_SERVER_ID_SYM EQ
ULONG_NUM
@@ -3045,13 +3277,13 @@ show_param:
lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
lex->select_lex.select_limit= lex->thd->variables.select_limit;
lex->select_lex.offset_limit= 0L;
- } limit_clause
+ } opt_limit_clause
| keys_or_index FROM table_ident opt_db
{
Lex->sql_command= SQLCOM_SHOW_KEYS;
if ($4)
$3->change_db($4);
- if (!Select->add_table_to_list($3, NULL, 0))
+ if (!Select->add_table_to_list(YYTHD, $3, NULL, 0))
YYABORT;
}
| COLUMN_SYM TYPES_SYM
@@ -3069,14 +3301,14 @@ show_param:
LEX *lex=Lex;
lex->sql_command= SQLCOM_SHOW_PRIVILEGES;
}
- | COUNT_SYM '(' '*' ')' WARNINGS
+ | COUNT_SYM '(' '*' ')' WARNINGS
{ (void) create_select_for_variable("warning_count"); }
- | COUNT_SYM '(' '*' ')' ERRORS
+ | COUNT_SYM '(' '*' ')' ERRORS
{ (void) create_select_for_variable("error_count"); }
- | WARNINGS {Select->offset_limit=0L;} limit_clause
+ | WARNINGS {Select->offset_limit=0L;} opt_limit_clause
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
- | ERRORS {Select->offset_limit=0L;} limit_clause
- { Lex->sql_command = SQLCOM_SHOW_ERRORS;}
+ | ERRORS {Select->offset_limit=0L;} opt_limit_clause
+ { Lex->sql_command = SQLCOM_SHOW_ERRORS;}
| STATUS_SYM wild
{ Lex->sql_command= SQLCOM_SHOW_STATUS; }
| INNOBASE_SYM STATUS_SYM
@@ -3085,7 +3317,7 @@ show_param:
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
| opt_var_type VARIABLES wild
{
- THD *thd= current_thd;
+ THD *thd= YYTHD;
thd->lex.sql_command= SQLCOM_SHOW_VARIABLES;
thd->lex.option_type= (enum_var_type) $1;
}
@@ -3100,15 +3332,16 @@ show_param:
lex->grant_user=$3;
lex->grant_user->password.str=NullS;
}
- | CREATE DATABASE ident
+ | CREATE DATABASE opt_if_not_exists ident
{
Lex->sql_command=SQLCOM_SHOW_CREATE_DB;
- Lex->name=$3.str;
+ Lex->create_info.options=$3;
+ Lex->name=$4.str;
}
| CREATE TABLE_SYM table_ident
{
Lex->sql_command = SQLCOM_SHOW_CREATE;
- if(!Select->add_table_to_list($3, NULL,0))
+ if(!Select->add_table_to_list(YYTHD, $3, NULL,0))
YYABORT;
}
| MASTER_SYM STATUS_SYM
@@ -3153,17 +3386,16 @@ describe:
lex->wild=0;
lex->verbose=0;
lex->sql_command=SQLCOM_SHOW_FIELDS;
- if (!Select->add_table_to_list($2, NULL,0))
+ if (!Select->add_table_to_list(lex->thd, $2, NULL,0))
YYABORT;
}
- opt_describe_column
- | describe_command select
- {
+ opt_describe_column {}
+ | describe_command { Lex->describe=1; } select
+ {
LEX *lex=Lex;
- lex->select_lex.options|= SELECT_DESCRIBE;
- lex->describe=1;
- };
-
+ lex->select_lex.options|= SELECT_DESCRIBE;
+ }
+ ;
describe_command:
DESC
@@ -3184,14 +3416,16 @@ flush:
LEX *lex=Lex;
lex->sql_command= SQLCOM_FLUSH; lex->type=0;
}
- flush_options;
+ flush_options
+ {}
+ ;
flush_options:
flush_options ',' flush_option
| flush_option;
flush_option:
- table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list
+ table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list {}
| TABLES WITH READ_SYM LOCK_SYM { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; }
| QUERY_SYM CACHE_SYM { Lex->type|= REFRESH_QUERY_CACHE_FREE; }
| HOSTS_SYM { Lex->type|= REFRESH_HOSTS; }
@@ -3212,7 +3446,10 @@ reset:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_RESET; lex->type=0;
- } reset_options;
+ } reset_options
+ {}
+ ;
+
reset_options:
reset_options ',' reset_option
| reset_option;
@@ -3240,8 +3477,8 @@ kill:
KILL_SYM expr
{
LEX *lex=Lex;
- if ($2->fix_fields(lex->thd, 0, &$2))
- {
+ if ($2->check_cols(1) || $2->fix_fields(lex->thd, 0, &$2))
+ {
send_error(lex->thd, ER_SET_CONSTANTS_ONLY);
YYABORT;
}
@@ -3264,7 +3501,8 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_LOAD;
- lex->local_file= $4;
+ lex->lock_option= $3;
+ lex->local_file= $4;
if (!(lex->exchange= new sql_exchange($6.str,0)))
YYABORT;
lex->field_list.empty();
@@ -3272,14 +3510,14 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING
opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term
opt_ignore_lines opt_field_spec
{
- if (!Select->add_table_to_list($11, NULL, 1))
+ if (!Select->add_table_to_list(YYTHD, $11, NULL, 1))
YYABORT;
}
|
LOAD TABLE_SYM table_ident FROM MASTER_SYM
{
Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
- if (!Select->add_table_to_list($3, NULL, 1))
+ if (!Select->add_table_to_list(YYTHD, $3, NULL, 1))
YYABORT;
}
@@ -3294,9 +3532,9 @@ opt_local:
| LOCAL_SYM { $$=1;};
load_data_lock:
- /* empty */ { Lex->lock_option= current_thd->update_lock_default; }
- | CONCURRENT { Lex->lock_option= TL_WRITE_CONCURRENT_INSERT ; }
- | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; };
+ /* empty */ { $$= YYTHD->update_lock_default; }
+ | CONCURRENT { $$= TL_WRITE_CONCURRENT_INSERT ; }
+ | LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
opt_duplicate:
@@ -3343,28 +3581,28 @@ opt_ignore_lines:
/* Common definitions */
text_literal:
- TEXT_STRING { $$ = new Item_string($1.str,$1.length,current_thd->thd_charset); }
+ TEXT_STRING { $$ = new Item_string($1.str,$1.length,YYTHD->thd_charset); }
| UNDERSCORE_CHARSET TEXT_STRING { $$ = new Item_string($2.str,$2.length,Lex->charset); }
| text_literal TEXT_STRING
{ ((Item_string*) $1)->append($2.str,$2.length); };
text_string:
- TEXT_STRING { $$= new String($1.str,$1.length,current_thd->thd_charset); }
+ TEXT_STRING { $$= new String($1.str,$1.length,YYTHD->thd_charset); }
| HEX_NUM
{
Item *tmp = new Item_varbinary($1.str,$1.length);
$$= tmp ? tmp->val_str((String*) 0) : (String*) 0;
};
param_marker:
- '?'
+ '?'
{
LEX *lex=Lex;
- if (current_thd->prepare_command)
- {
- lex->param_list.push_back($$=new Item_param());
+ if (YYTHD->prepare_command)
+ {
+ lex->param_list.push_back($$=new Item_param());
lex->param_count++;
}
- else
+ else
{
yyerror("You have an error in your SQL syntax");
YYABORT;
@@ -3395,7 +3633,7 @@ insert_ident:
table_wild:
ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); }
| ident '.' ident '.' '*'
- { $$ = new Item_field((current_thd->client_capabilities &
+ { $$ = new Item_field((YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); };
order_ident:
@@ -3420,7 +3658,7 @@ simple_ident:
| ident '.' ident '.' ident
{
SELECT_LEX_NODE *sel=Select;
- $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
+ $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
};
@@ -3439,12 +3677,13 @@ ident:
IDENT { $$=$1; }
| keyword
{
- LEX *lex;
- $$.str=sql_strmake($1.str,$1.length);
+ LEX *lex= Lex;
+ $$.str= lex->thd->strmake($1.str,$1.length);
$$.length=$1.length;
- if ((lex=Lex)->next_state != STATE_END)
+ if (lex->next_state != STATE_END)
lex->next_state=STATE_OPERATOR_OR_IDENT;
- };
+ }
+ ;
ident_or_text:
ident { $$=$1;}
@@ -3454,13 +3693,15 @@ ident_or_text:
user:
ident_or_text
{
- if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user))))
+ THD *thd= YYTHD;
+ if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
$$->user = $1; $$->host.str=NullS;
}
| ident_or_text '@' ident_or_text
{
- if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user))))
+ THD *thd= YYTHD;
+ if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
$$->user = $1; $$->host=$3;
};
@@ -3472,6 +3713,7 @@ keyword:
| AFTER_SYM {}
| AGAINST {}
| AGGREGATE_SYM {}
+ | ANY_SYM {}
| AUTO_INC {}
| AVG_ROW_LENGTH {}
| AVG_SYM {}
@@ -3482,11 +3724,11 @@ keyword:
| BIT_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
+ | BYTE_SYM {}
| CACHE_SYM {}
| CHANGED {}
| CHARSET {}
| CHECKSUM_SYM {}
- | CHECK_SYM {}
| CIPHER_SYM {}
| CLIENT_SYM {}
| CLOSE_SYM {}
@@ -3505,6 +3747,7 @@ keyword:
| DIRECTORY_SYM {}
| DO_SYM {}
| DUMPFILE {}
+ | DUAL_SYM {}
| DYNAMIC_SYM {}
| END {}
| ENUM {}
@@ -3565,6 +3808,7 @@ keyword:
| NEW_SYM {}
| NO_SYM {}
| NONE_SYM {}
+ | OFFSET_SYM {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PARTIAL {}
@@ -3594,6 +3838,7 @@ keyword:
| ROW_FORMAT_SYM {}
| ROW_SYM {}
| SECOND_SYM {}
+ | SERIAL_SYM {}
| SERIALIZABLE_SYM {}
| SESSION_SYM {}
| SIGNED_SYM {}
@@ -3622,6 +3867,7 @@ keyword:
| UNCOMMITTED_SYM {}
| USE_FRM {}
| VARIABLES {}
+ | VALUE_SYM {}
| WORK_SYM {}
| YEAR_SYM {}
;
@@ -3636,7 +3882,9 @@ set:
lex->option_type=OPT_DEFAULT;
lex->var_list.empty();
}
- option_value_list;
+ option_value_list
+ {}
+ ;
opt_option:
/* empty */ {}
@@ -3698,9 +3946,9 @@ option_value:
}
| PASSWORD equal text_or_password
{
- THD *thd=current_thd;
+ THD *thd=YYTHD;
LEX_USER *user;
- if (!(user=(LEX_USER*) sql_alloc(sizeof(LEX_USER))))
+ if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
YYABORT;
user->host.str=0;
user->user.str=thd->priv_user;
@@ -3728,7 +3976,7 @@ isolation_types:
| REPEATABLE_SYM READ_SYM { $$= ISO_REPEATABLE_READ; }
| SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; }
;
-
+
text_or_password:
TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')'
@@ -3737,8 +3985,8 @@ text_or_password:
$$=$3.str;
else
{
- char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
- make_scrambled_password(buff,$3.str);
+ char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
+ make_scrambled_password(buff,$3.str,opt_old_passwords,&current_thd->rand);
$$=buff;
}
}
@@ -3760,7 +4008,9 @@ lock:
{
Lex->sql_command=SQLCOM_LOCK_TABLES;
}
- table_lock_list;
+ table_lock_list
+ {}
+ ;
table_or_tables:
TABLE_SYM
@@ -3773,14 +4023,14 @@ table_lock_list:
table_lock:
table_ident opt_table_alias lock_option
{
- if (!Select->add_table_to_list($1, $2, 0, (thr_lock_type) $3))
+ if (!Select->add_table_to_list(YYTHD, $1, $2, 0, (thr_lock_type) $3))
YYABORT;
}
;
lock_option:
READ_SYM { $$=TL_READ_NO_INSERT; }
- | WRITE_SYM { $$=current_thd->update_lock_default; }
+ | WRITE_SYM { $$=YYTHD->update_lock_default; }
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
| READ_SYM LOCAL_SYM { $$= TL_READ; }
;
@@ -3799,14 +4049,14 @@ handler:
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_HA_OPEN;
- if (!lex->current_select->add_table_to_list($2, $4, 0))
+ if (!lex->current_select->add_table_to_list(lex->thd, $2, $4, 0))
YYABORT;
}
| HANDLER_SYM table_ident CLOSE_SYM
{
LEX *lex= Lex;
lex->sql_command = SQLCOM_HA_CLOSE;
- if (!lex->current_select->add_table_to_list($2, 0, 0))
+ if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
YYABORT;
}
| HANDLER_SYM table_ident READ_SYM
@@ -3816,10 +4066,10 @@ handler:
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
lex->current_select->select_limit= 1;
lex->current_select->offset_limit= 0L;
- if (!lex->current_select->add_table_to_list($2, 0, 0))
+ if (!lex->current_select->add_table_to_list(lex->thd, $2, 0, 0))
YYABORT;
}
- handler_read_or_scan where_clause limit_clause { }
+ handler_read_or_scan where_clause opt_limit_clause { }
;
handler_read_or_scan:
@@ -3870,7 +4120,9 @@ revoke:
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero((char*) &lex->mqh, sizeof(lex->mqh));
}
- grant_privileges ON opt_table FROM user_list;
+ grant_privileges ON opt_table FROM user_list
+ {}
+ ;
grant:
GRANT
@@ -3886,7 +4138,9 @@ grant:
bzero(&(lex->mqh),sizeof(lex->mqh));
}
grant_privileges ON opt_table TO_SYM user_list
- require_clause grant_options;
+ require_clause grant_options
+ {}
+ ;
grant_privileges:
grant_privilege_list {}
@@ -3899,10 +4153,10 @@ grant_privilege_list:
| grant_privilege_list ',' grant_privilege;
grant_privilege:
- 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
+ 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 {}
| DELETE_SYM { Lex->grant |= DELETE_ACL;}
| USAGE {}
| INDEX { Lex->grant |= INDEX_ACL;}
@@ -3966,7 +4220,7 @@ require_list_element:
lex->ssl_cipher=$2.str;
}
;
-
+
opt_table:
'*'
{
@@ -4007,7 +4261,7 @@ opt_table:
| table_ident
{
LEX *lex=Lex;
- if (!lex->current_select->add_table_to_list($1,NULL,0))
+ if (!lex->current_select->add_table_to_list(lex->thd, $1,NULL,0))
YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
@@ -4031,10 +4285,10 @@ grant_user:
$$=$1; $1->password=$4;
if ($4.length)
{
- char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
+ char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
if (buff)
{
- make_scrambled_password(buff,$4.str);
+ make_scrambled_password(buff,$4.str,opt_old_passwords,&current_thd->rand);
$1->password.str=buff;
$1->password.length=HASH_PASSWORD_LENGTH;
}
@@ -4082,7 +4336,7 @@ column_list_id:
require_clause: /* empty */
- | REQUIRE_SYM require_list
+ | REQUIRE_SYM require_list
{
Lex->ssl_type=SSL_TYPE_SPECIFIED;
}
@@ -4129,7 +4383,8 @@ grant_option:
;
begin:
- BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work;
+ BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work {}
+ ;
opt_work:
/* empty */ {}
@@ -4148,9 +4403,10 @@ rollback:
*/
-union:
+union_clause:
/* empty */ {}
- | union_list;
+ | union_list
+ ;
union_list:
UNION_SYM union_option
@@ -4161,7 +4417,7 @@ union_list:
/* Only the last SELECT can have INTO...... */
net_printf(lex->thd, ER_WRONG_USAGE, "UNION", "INTO");
YYABORT;
- }
+ }
if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
send_error(lex->thd, ER_SYNTAX_ERROR);
@@ -4171,15 +4427,16 @@ union_list:
YYABORT;
lex->current_select->linkage=UNION_TYPE;
}
- select_init
+ select_init {}
;
union_opt:
- union {}
- | optional_order_or_limit {};
+ union_list {}
+ | optional_order_or_limit {}
+ ;
optional_order_or_limit:
- /* empty */ {}
+ /* Empty */ {}
|
{
LEX *lex=Lex;
@@ -4189,13 +4446,19 @@ optional_order_or_limit:
YYABORT;
}
SELECT_LEX *sel= lex->current_select->select_lex();
- sel->master_unit()->global_parameters=
+ sel->master_unit()->global_parameters=
sel->master_unit();
lex->current_select= sel->master_unit();
lex->current_select->select_limit=
lex->thd->variables.select_limit;
}
- opt_order_clause limit_clause
+ order_or_limit
+ ;
+
+order_or_limit:
+ order_clause opt_limit_clause
+ |
+ limit_clause
;
union_option:
@@ -4210,9 +4473,9 @@ singleval_subselect:
};
singleval_subselect_init:
- select_init
+ select_init2
{
- $$= new Item_singleval_subselect(current_thd,
+ $$= new Item_singleval_subselect(YYTHD,
Lex->current_select->master_unit()->
first_select());
};
@@ -4225,15 +4488,28 @@ exists_subselect:
};
exists_subselect_init:
- select_init
+ select_init2
{
- $$= new Item_exists_subselect(current_thd,
+ $$= new Item_exists_subselect(YYTHD,
Lex->current_select->master_unit()->
first_select());
};
+in_subselect:
+ subselect_start in_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+in_subselect_init:
+ select_init2
+ {
+ $$= Lex->current_select->master_unit()->first_select();
+ };
+
subselect_start:
- '('
+ '(' SELECT_SYM
{
if (mysql_new_select(Lex, 1))
YYABORT;
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index 1aba73dda33..f5c0a59b572 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -206,7 +206,7 @@ resolve it\n");
/* Produce a core for the thread */
-#ifdef HAVE_LINUXTHREADS
+#ifdef NOT_USED /* HAVE_LINUXTHREADS */
void write_core(int sig)
{
signal(sig, SIG_DFL);
diff --git a/sql/table.cc b/sql/table.cc
index 6e2df849700..84a072c886d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -95,15 +95,15 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (my_read(file,(byte*) head,64,MYF(MY_NABP))) goto err_not_open;
if (head[0] != (uchar) 254 || head[1] != 1 ||
- (head[2] < FRM_VER && head[2] > FRM_VER+2))
- goto err_not_open; /* purecov: inspected */
+ (head[2] != FRM_VER && head[2] > FRM_VER+2))
+ goto err_not_open; /* purecov: inspected */
new_field_pack_flag=head[27];
new_frm_ver= (head[2] - FRM_VER);
field_pack_length= new_frm_ver < 2 ? 11 : 15;
error=3;
if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
- goto err_not_open; /* purecov: inspected */
+ goto err_not_open; /* purecov: inspected */
*fn_ext(index_file)='\0'; // Remove .frm extension
outparam->db_type=ha_checktype((enum db_type) (uint) *(head+3));
@@ -145,7 +145,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
goto err_not_open; /* purecov: inspected */
bzero((char*) keyinfo,n_length);
outparam->key_info=keyinfo;
- outparam->max_key_length=0;
+ outparam->max_key_length= outparam->total_key_length= 0;
key_part= (KEY_PART_INFO*) (keyinfo+keys);
strpos=disk_buff+6;
@@ -203,11 +203,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
set_if_bigger(outparam->max_key_length,keyinfo->key_length+
keyinfo->key_parts);
+ outparam->total_key_length+= keyinfo->key_length;
if (keyinfo->flags & HA_NOSAME)
set_if_bigger(outparam->max_unique_length,keyinfo->key_length);
}
keynames=(char*) key_part;
strpos+= (strmov(keynames, (char *) strpos) - keynames)+1;
+
outparam->reclength = uint2korr((head+16));
if (*(head+26) == 1)
outparam->system=1; /* one-record-database */
@@ -391,9 +393,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(TYPELIB*) 0),
outparam->fieldnames.type_names[i],
outparam);
+ if (!reg_field) // Not supported field type
+ {
+ error= 4;
+ goto err_not_open; /* purecov: inspected */
+ }
reg_field->comment=comment;
- if (!reg_field->binary())
- ((Field_str*) reg_field)->set_charset(charset);
+ reg_field->set_charset(charset);
if (!(reg_field->flags & NOT_NULL_FLAG))
{
if ((null_bit<<=1) == 256)
diff --git a/sql/table.h b/sql/table.h
index d09194442c8..d24e4e1e422 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -58,6 +58,7 @@ struct st_table {
uint reclength; /* Recordlength */
uint rec_buff_length;
uint keys,key_parts,primary_key,max_key_length,max_unique_length;
+ uint total_key_length;
uint uniques;
uint null_fields; /* number of null fields */
uint blob_fields; /* number of blob fields */
@@ -117,21 +118,23 @@ struct st_table {
table_map map; /* ID bit of table (1,2,4,8,16...) */
ulong version,flush_version;
uchar *null_flags;
- IO_CACHE *io_cache; /* If sorted trough file*/
- byte *record_pointers; /* If sorted in memory */
- ha_rows found_records; /* How many records in sort */
+ IO_CACHE *io_cache; /* If sorted trough filebyte */
+ byte *record_pointers; /* If sorted in memory */
+ ha_rows found_records; /* How many records in sort */
ORDER *group;
ha_rows quick_rows[MAX_KEY];
uint quick_key_parts[MAX_KEY];
key_part_map const_key_parts[MAX_KEY];
ulong query_id;
- uint temp_pool_slot;
-
+ union /* Temporary variables */
+ {
+ uint temp_pool_slot; /* Used by intern temp tables */
+ struct st_table_list *pos_in_table_list;
+ };
/* number of select if it is derived table */
uint derived_select_number;
-
- THD *in_use; /* Which thread uses this */
+ THD *in_use; /* Which thread uses this */
struct st_table *next,*prev;
};
@@ -160,10 +163,10 @@ typedef struct st_table_list
GRANT_INFO grant;
thr_lock_type lock_type;
uint outer_join; /* Which join type */
+ uint shared; /* Used in union or in multi-upd */
uint32 db_length, real_name_length;
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
- bool shared; /* Used twice in union */
bool do_redirect; /* To get the struct in UNION's */
} TABLE_LIST;
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 81310c4a863..a171ba42ff3 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -590,7 +590,7 @@ static bool make_empty_rec(File file,enum db_type table_type,
if (field->def &&
(regfield->real_type() != FIELD_TYPE_YEAR ||
field->def->val_int() != 0))
- (void) field->def->save_in_field(regfield);
+ (void) field->def->save_in_field(regfield, 1);
else if (regfield->real_type() == FIELD_TYPE_ENUM &&
(field->flags & NOT_NULL_FLAG))
{