summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am13
-rw-r--r--sql/convert.cc12
-rw-r--r--sql/des_key_file.cc5
-rw-r--r--sql/field.cc884
-rw-r--r--sql/field.h299
-rw-r--r--sql/field_conv.cc19
-rw-r--r--sql/filesort.cc73
-rw-r--r--sql/gen_lex_hash.cc746
-rw-r--r--sql/gstream.cc137
-rw-r--r--sql/gstream.h69
-rw-r--r--sql/ha_berkeley.cc42
-rw-r--r--sql/ha_heap.cc220
-rw-r--r--sql/ha_heap.h5
-rw-r--r--sql/ha_innodb.cc22
-rw-r--r--sql/ha_myisam.cc30
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/handler.h20
-rw-r--r--sql/hash_filo.h4
-rw-r--r--sql/hostname.cc4
-rw-r--r--sql/init.cc11
-rw-r--r--sql/item.cc344
-rw-r--r--sql/item.h140
-rw-r--r--sql/item_buff.cc2
-rw-r--r--sql/item_cmpfunc.cc240
-rw-r--r--sql/item_cmpfunc.h137
-rw-r--r--sql/item_create.cc170
-rw-r--r--sql/item_create.h40
-rw-r--r--sql/item_func.cc395
-rw-r--r--sql/item_func.h185
-rw-r--r--sql/item_strfunc.cc665
-rw-r--r--sql/item_strfunc.h334
-rw-r--r--sql/item_subselect.cc380
-rw-r--r--sql/item_subselect.h216
-rw-r--r--sql/item_sum.cc67
-rw-r--r--sql/item_sum.h25
-rw-r--r--sql/item_timefunc.cc204
-rw-r--r--sql/item_timefunc.h202
-rw-r--r--sql/item_uniq.h5
-rw-r--r--sql/key.cc6
-rw-r--r--sql/lex.h69
-rw-r--r--sql/lock.cc11
-rw-r--r--sql/log.cc59
-rw-r--r--sql/log_event.cc2482
-rw-r--r--sql/log_event.h108
-rw-r--r--sql/mini_client.cc22
-rw-r--r--sql/mysql_priv.h137
-rw-r--r--sql/mysqld.cc379
-rw-r--r--sql/net_pkg.cc172
-rw-r--r--sql/net_serv.cc115
-rw-r--r--sql/opt_range.cc229
-rw-r--r--sql/opt_range.h9
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/procedure.cc3
-rw-r--r--sql/procedure.h10
-rw-r--r--sql/repl_failsafe.cc40
-rw-r--r--sql/set_var.cc84
-rw-r--r--sql/set_var.h33
-rw-r--r--sql/share/charsets/Index36
-rw-r--r--sql/share/charsets/armscii8.conf93
-rw-r--r--sql/share/charsets/cp1251.conf19
-rw-r--r--sql/share/charsets/cp1251bin.conf95
-rw-r--r--sql/share/charsets/cp1251cias.conf99
-rw-r--r--sql/share/charsets/cp1251csas.conf99
-rw-r--r--sql/share/charsets/cp1256.conf94
-rw-r--r--sql/share/charsets/cp1257.conf18
-rw-r--r--sql/share/charsets/cp1257bin.conf96
-rw-r--r--sql/share/charsets/cp1257ltlvciai.conf97
-rw-r--r--sql/share/charsets/cp1257ltlvcias.conf97
-rw-r--r--sql/share/charsets/cp1257ltlvcsas.conf97
-rw-r--r--sql/share/charsets/cp866.conf96
-rw-r--r--sql/share/charsets/croat.conf18
-rw-r--r--sql/share/charsets/danish.conf18
-rw-r--r--sql/share/charsets/dec8.conf18
-rw-r--r--sql/share/charsets/dos.conf21
-rw-r--r--sql/share/charsets/estonia.conf18
-rw-r--r--sql/share/charsets/german1.conf18
-rw-r--r--sql/share/charsets/greek.conf19
-rw-r--r--sql/share/charsets/hebrew.conf19
-rw-r--r--sql/share/charsets/hp8.conf19
-rw-r--r--sql/share/charsets/hungarian.conf18
-rw-r--r--sql/share/charsets/keybcs2.conf91
-rw-r--r--sql/share/charsets/koi8_ru.conf19
-rw-r--r--sql/share/charsets/koi8_ukr.conf18
-rw-r--r--sql/share/charsets/latin1.conf18
-rw-r--r--sql/share/charsets/latin1bin.conf96
-rw-r--r--sql/share/charsets/latin1cias.conf97
-rw-r--r--sql/share/charsets/latin1csas.conf97
-rw-r--r--sql/share/charsets/latin2.conf18
-rw-r--r--sql/share/charsets/latin5.conf18
-rw-r--r--sql/share/charsets/latvian.conf95
-rw-r--r--sql/share/charsets/latvian1.conf94
-rw-r--r--sql/share/charsets/macce.conf91
-rw-r--r--sql/share/charsets/maccebin.conf96
-rw-r--r--sql/share/charsets/macceciai.conf96
-rw-r--r--sql/share/charsets/maccecias.conf96
-rw-r--r--sql/share/charsets/maccecsas.conf96
-rw-r--r--sql/share/charsets/macroman.conf91
-rw-r--r--sql/share/charsets/macromanbin.conf96
-rw-r--r--sql/share/charsets/macromanciai.conf97
-rw-r--r--sql/share/charsets/macromancias.conf97
-rw-r--r--sql/share/charsets/macromancsas.conf97
-rw-r--r--sql/share/charsets/pclatin2.conf91
-rw-r--r--sql/share/charsets/swe7.conf18
-rw-r--r--sql/share/charsets/usa7.conf18
-rw-r--r--sql/share/charsets/win1250.conf18
-rw-r--r--sql/share/charsets/win1251.conf18
-rw-r--r--sql/share/charsets/win1251ukr.conf18
-rw-r--r--sql/share/czech/errmsg.txt10
-rw-r--r--sql/share/danish/errmsg.txt8
-rw-r--r--sql/share/dutch/errmsg.txt8
-rw-r--r--sql/share/english/errmsg.txt10
-rw-r--r--sql/share/estonian/errmsg.txt8
-rw-r--r--sql/share/french/errmsg.txt8
-rw-r--r--sql/share/german/errmsg.txt8
-rw-r--r--sql/share/greek/errmsg.txt10
-rw-r--r--sql/share/hungarian/errmsg.txt10
-rw-r--r--sql/share/italian/errmsg.txt8
-rw-r--r--sql/share/japanese/errmsg.txt10
-rw-r--r--sql/share/korean/errmsg.txt10
-rw-r--r--sql/share/norwegian-ny/errmsg.txt10
-rw-r--r--sql/share/norwegian/errmsg.txt10
-rw-r--r--sql/share/polish/errmsg.txt10
-rw-r--r--sql/share/portuguese/errmsg.txt8
-rw-r--r--sql/share/romanian/errmsg.txt10
-rw-r--r--sql/share/russian/errmsg.txt8
-rw-r--r--sql/share/serbian/errmsg.txt244
-rw-r--r--sql/share/slovak/errmsg.txt10
-rw-r--r--sql/share/spanish/errmsg.txt8
-rw-r--r--sql/share/swedish/errmsg.txt28
-rw-r--r--sql/share/ukrainian/errmsg.txt8
-rw-r--r--sql/slave.cc392
-rw-r--r--sql/slave.h92
-rw-r--r--sql/spatial.cc1442
-rw-r--r--sql/spatial.h497
-rw-r--r--sql/sql_acl.cc261
-rw-r--r--sql/sql_analyse.cc68
-rw-r--r--sql/sql_analyse.h55
-rw-r--r--sql/sql_base.cc401
-rw-r--r--sql/sql_cache.cc34
-rw-r--r--sql/sql_class.cc257
-rw-r--r--sql/sql_class.h217
-rw-r--r--sql/sql_db.cc390
-rw-r--r--sql/sql_delete.cc64
-rw-r--r--sql/sql_derived.cc134
-rw-r--r--sql/sql_do.cc2
-rw-r--r--sql/sql_error.cc165
-rw-r--r--sql/sql_handler.cc20
-rw-r--r--sql/sql_help.cc408
-rw-r--r--sql/sql_insert.cc32
-rw-r--r--sql/sql_lex.cc478
-rw-r--r--sql/sql_lex.h319
-rw-r--r--sql/sql_list.h6
-rw-r--r--sql/sql_load.cc6
-rw-r--r--sql/sql_parse.cc900
-rw-r--r--sql/sql_prepare.cc835
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_repl.cc57
-rw-r--r--sql/sql_select.cc1288
-rw-r--r--sql/sql_select.h86
-rw-r--r--sql/sql_show.cc424
-rw-r--r--sql/sql_string.cc439
-rw-r--r--sql/sql_string.h116
-rw-r--r--sql/sql_table.cc240
-rw-r--r--sql/sql_test.cc129
-rw-r--r--sql/sql_udf.cc27
-rw-r--r--sql/sql_union.cc407
-rw-r--r--sql/sql_update.cc44
-rw-r--r--sql/sql_yacc.yy1243
-rw-r--r--sql/structs.h5
-rw-r--r--sql/table.cc77
-rw-r--r--sql/table.h21
-rw-r--r--sql/time.cc92
-rw-r--r--sql/uniques.cc3
-rw-r--r--sql/unireg.cc74
-rw-r--r--sql/unireg.h2
175 files changed, 20410 insertions, 5658 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 28abf407f3f..09fedd393c2 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -46,7 +46,7 @@ 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 mysql_priv.h \
+ item_create.h item_subselect.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 \
@@ -56,17 +56,19 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
sql_select.h structs.h table.h sql_udf.h hash_filo.h\
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
log_event.h mini_client.h sql_repl.h slave.h \
- stacktrace.h sql_sort.h sql_cache.h set_var.h
+ stacktrace.h sql_sort.h sql_cache.h set_var.h \
+ spatial.h gstream.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 \
+ thr_malloc.cc item_create.cc item_subselect.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 \
mysqld.cc password.c hash_filo.cc hostname.cc \
convert.cc set_var.cc sql_parse.cc sql_yacc.yy \
sql_base.cc table.cc sql_select.cc sql_insert.cc \
+ sql_prepare.cc sql_error.cc \
sql_update.cc sql_delete.cc uniques.cc sql_do.cc \
procedure.cc item_uniq.cc sql_test.cc \
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
@@ -79,9 +81,10 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
- slave.cc sql_repl.cc sql_union.cc \
+ slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
mini_client.cc mini_client_errors.c \
- stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc
+ stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\
+ gstream.cc spatial.cc sql_help.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
diff --git a/sql/convert.cc b/sql/convert.cc
index e4ae13d1e07..13a6dfe0392 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -433,7 +433,17 @@ CONVERT *get_convert_set(const char *name)
{
for (CONVERT **ptr=convert_tables ; *ptr ; ptr++)
{
- if (!my_strcasecmp((*ptr)->name,name))
+ /*
+ 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))
return (*ptr);
}
return 0;
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index d9c924b5a3c..ca92e38279b 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -70,9 +70,10 @@ load_des_key_file(const char *file_name)
{
offset=(char) (offset - '0');
// Remove newline and possible other control characters
- for (start=buf+1 ; isspace(*start) ; start++) ;
+ for (start=buf+1 ; my_isspace(system_charset_info, *start) ; start++) ;
end=buf+length;
- for (end=strend(buf) ; end > start && !isgraph(end[-1]) ; end--) ;
+ for (end=strend(buf) ;
+ end > start && !my_isgraph(system_charset_info, end[-1]) ; end--) ;
if (start != end)
{
diff --git a/sql/field.cc b/sql/field.cc
index e631ade16b1..f2324a0a331 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -84,7 +84,8 @@ bool test_if_int(const char *str,int length)
{
const char *end=str+length;
- while (str != end && isspace(*str)) // Allow start space
+ // Allow start space
+ while (str != end && my_isspace(system_charset_info,*str))
str++; /* purecov: inspected */
if (str != end && (*str == '-' || *str == '+'))
str++;
@@ -92,7 +93,7 @@ bool test_if_int(const char *str,int length)
return 0; // Error: Empty string
for (; str != end ; str++)
{
- if (!isdigit(*str))
+ if (!my_isdigit(system_charset_info,*str))
{
if (*str == '.')
{ // Allow '.0000'
@@ -100,10 +101,10 @@ bool test_if_int(const char *str,int length)
if (str == end)
return 1;
}
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
return 0;
for (str++ ; str != end ; str++)
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
return 0;
return 1;
}
@@ -114,7 +115,7 @@ bool test_if_int(const char *str,int length)
static bool test_if_real(const char *str,int length)
{
- while (length && isspace(*str))
+ while (length && my_isspace(system_charset_info,*str))
{ // Allow start space
length--; str++;
}
@@ -123,10 +124,10 @@ static bool test_if_real(const char *str,int length)
if (*str == '+' || *str == '-')
{
length--; str++;
- if (!length || !(isdigit(*str) || *str == '.'))
+ if (!length || !(my_isdigit(system_charset_info,*str) || *str == '.'))
return 0;
}
- while (length && isdigit(*str))
+ while (length && my_isdigit(system_charset_info,*str))
{
length--; str++;
}
@@ -135,7 +136,7 @@ static bool test_if_real(const char *str,int length)
if (*str == '.')
{
length--; str++;
- while (length && isdigit(*str))
+ while (length && my_isdigit(system_charset_info,*str))
{
length--; str++;
}
@@ -144,18 +145,19 @@ static bool test_if_real(const char *str,int length)
return 1;
if (*str == 'E' || *str == 'e')
{
- if (length < 3 || (str[1] != '+' && str[1] != '-') || !isdigit(str[2]))
+ if (length < 3 || (str[1] != '+' && str[1] != '-') ||
+ !my_isdigit(system_charset_info,str[2]))
return 0;
length-=3;
str+=3;
- while (length && isdigit(*str))
+ while (length && my_isdigit(system_charset_info,*str))
{
length--; str++;
}
}
for (; length ; length--, str++)
{ // Allow end space
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
return 0;
}
return 1;
@@ -179,6 +181,8 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
field_length(length_arg),null_bit(null_bit_arg)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;
+ comment.str= (char*) "";
+ comment.length=0;
}
uint Field::offset()
@@ -203,7 +207,7 @@ bool Field::send(THD *thd, String *packet)
if (is_null())
return net_store_null(packet);
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),default_charset_info);
val_str(&tmp,&tmp);
CONVERT *convert;
if ((convert=thd->variables.convert_set))
@@ -223,8 +227,11 @@ void Field_num::add_zerofill_and_unsigned(String &res) const
void Field_num::make_field(Send_field *field)
{
+ /* table_cache_key is not set for temp tables */
+ field->db_name=table->table_cache_key ? table->table_cache_key : "";
+ field->org_table_name=table->real_name;
field->table_name=table_name;
- field->col_name=field_name;
+ field->col_name=field->org_col_name=field_name;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
@@ -234,8 +241,11 @@ void Field_num::make_field(Send_field *field)
void Field_str::make_field(Send_field *field)
{
+ /* table_cache_key is not set for temp tables */
+ field->db_name=table->table_cache_key ? table->table_cache_key : "";
+ field->org_table_name=table->real_name;
field->table_name=table_name;
- field->col_name=field_name;
+ field->col_name=field->org_col_name=field_name;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
@@ -266,7 +276,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy)
bool Field::get_date(TIME *ltime,bool fuzzydate)
{
char buff[40];
- String tmp(buff,sizeof(buff)),tmp2,*res;
+ String tmp(buff,sizeof(buff),default_charset_info),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
return 1;
@@ -276,7 +286,7 @@ bool Field::get_date(TIME *ltime,bool fuzzydate)
bool Field::get_time(TIME *ltime)
{
char buff[40];
- String tmp(buff,sizeof(buff)),tmp2,*res;
+ String tmp(buff,sizeof(buff),default_charset_info),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
str_to_time(res->ptr(),res->length(),ltime))
return 1;
@@ -290,24 +300,26 @@ void Field::store_time(TIME *ltime,timestamp_type type)
char buff[25];
switch (type) {
case TIMESTAMP_NONE:
- store("",0); // Probably an error
+ store("",0,default_charset_info); // Probably an error
break;
case TIMESTAMP_DATE:
sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
- store(buff,10);
+ store(buff,10,default_charset_info);
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);
+ store(buff,19,default_charset_info);
break;
case TIMESTAMP_TIME:
- sprintf(buff, "%02d:%02d:%02d",
- ltime->hour,ltime->minute,ltime->second);
- store(buff,(uint) strlen(buff));
+ {
+ ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d",
+ ltime->hour,ltime->minute,ltime->second));
+ store(buff,(uint) length, default_charset_info);
break;
}
+ }
}
@@ -324,7 +336,7 @@ bool Field::optimize_range(uint idx)
void
Field_decimal::reset(void)
{
- Field_decimal::store("0",1);
+ Field_decimal::store("0",1,default_charset_info);
}
void Field_decimal::overflow(bool negative)
@@ -366,7 +378,7 @@ void Field_decimal::overflow(bool negative)
}
-void Field_decimal::store(const char *from,uint len)
+int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs)
{
const char *end= from+len;
/* The pointer where the field value starts (i.e., "where to write") */
@@ -377,13 +389,13 @@ void Field_decimal::store(const char *from,uint len)
specified), '+' or '-'
*/
char sign_char=0;
- /* The pointers where prezeros start and stop */
+ /* The pointers where prezeros start and stop */
const char *pre_zeros_from, *pre_zeros_end;
- /* The pointers where digits at the left of '.' start and stop */
+ /* The pointers where digits at the left of '.' start and stop */
const char *int_digits_from, *int_digits_end;
- /* The pointers where digits at the right of '.' start and stop */
+ /* The pointers where digits at the right of '.' start and stop */
const char *frac_digits_from, *frac_digits_end;
- /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
+ /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0;
uint exponent=0; // value of the exponent
/*
@@ -393,21 +405,21 @@ void Field_decimal::store(const char *from,uint len)
const char *int_digits_tail_from;
/* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */
uint int_digits_added_zeros;
- /*
- Pointer used when digits move from the right of the '.' to the left
- of the '.'
- */
+ /*
+ Pointer used when digits move from the right of the '.' to the left
+ of the '.'
+ */
const char *frac_digits_head_end;
- /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
+ /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */
uint frac_digits_added_zeros;
char *pos,*tmp_left_pos,*tmp_right_pos;
/* Pointers that are used as limits (begin and end of the field buffer) */
char *left_wall,*right_wall;
char tmp_char;
- /*
- To remember if current_thd->cuted_fields has already been incremented,
- to do that only once
- */
+ /*
+ To remember if current_thd->cuted_fields has already been incremented,
+ to do that only once
+ */
bool is_cuted_fields_incr=0;
LINT_INIT(int_digits_tail_from);
@@ -417,16 +429,18 @@ void Field_decimal::store(const char *from,uint len)
/*
There are three steps in this function :
- - parse the input string
- - modify the position of digits around the decimal dot '.'
- according to the exponent value (if specified)
- - write the formatted number
+ - parse the input string
+ - modify the position of digits around the decimal dot '.'
+ according to the exponent value (if specified)
+ - write the formatted number
*/
if ((tmp_dec=dec))
tmp_dec++;
- for (; from !=end && isspace(*from); from++) ; // Read spaces
+ /* skip pre-space */
+ while (from != end && my_isspace(system_charset_info,*from))
+ from++;
if (from == end)
{
current_thd->cuted_fields++;
@@ -445,11 +459,11 @@ void Field_decimal::store(const char *from,uint len)
if (sign_char=='-')
{
Field_decimal::overflow(1);
- return;
+ return 1;
}
/*
- Defining this will not store "+" for unsigned decimal type even if
- it is passed in numeric string. This will make some tests to fail
+ Defining this will not store "+" for unsigned decimal type even if
+ it is passed in numeric string. This will make some tests to fail
*/
#ifdef DONT_ALLOW_UNSIGNED_PLUS
else
@@ -462,13 +476,13 @@ void Field_decimal::store(const char *from,uint len)
for (; from!=end && *from == '0'; from++) ; // Read prezeros
pre_zeros_end=int_digits_from=from;
/* Read non zero digits at the left of '.'*/
- for (; from!=end && isdigit(*from);from++) ;
+ for (; from != end && my_isdigit(system_charset_info, *from) ; from++) ;
int_digits_end=from;
if (from!=end && *from == '.') // Some '.' ?
from++;
frac_digits_from= from;
/* Read digits at the right of '.' */
- for (;from!=end && isdigit(*from); from++) ;
+ for (;from!=end && my_isdigit(system_charset_info, *from); from++) ;
frac_digits_end=from;
// Some exponentiation symbol ?
if (from != end && (*from == 'e' || *from == 'E'))
@@ -484,7 +498,7 @@ void Field_decimal::store(const char *from,uint len)
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 && isdigit(*from); from++)
+ for (;from!=end && my_isdigit(system_charset_info, *from); from++)
{
exponent=10*exponent+(*from-'0');
if (exponent>MAX_EXPONENT)
@@ -501,7 +515,8 @@ void Field_decimal::store(const char *from,uint len)
if (current_thd->count_cuted_fields)
{
- for (;from != end && isspace(*from); from++) ; // Read end spaces
+ // Skip end spaces
+ for (;from != end && my_isspace(system_charset_info, *from); from++) ;
if (from != end) // If still something left, warn
{
current_thd->cuted_fields++;
@@ -513,21 +528,21 @@ void Field_decimal::store(const char *from,uint len)
Now "move" digits around the decimal dot according to the exponent value,
and add necessary zeros.
Examples :
- - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3)
- - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed
- between '.' and '1'
+ - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3)
+ - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed
+ between '.' and '1'
- 1234.5E-3 : '234' moves at the right of '.'
- These moves are implemented with pointers which point at the begin
- and end of each moved segment. Examples :
+ These moves are implemented with pointers which point at the begin
+ and end of each moved segment. Examples :
- 1234.5E-3 : before the code below is executed, the int_digits part is
- from '1' to '4' and the frac_digits part from '5' to '5'. After the code
- below, the int_digits part is from '1' to '1', the frac_digits_head
- part is from '2' to '4', and the frac_digits part from '5' to '5'.
+ from '1' to '4' and the frac_digits part from '5' to '5'. After the code
+ below, the int_digits part is from '1' to '1', the frac_digits_head
+ part is from '2' to '4', and the frac_digits part from '5' to '5'.
- 1234.5E3 : before the code below is executed, the int_digits part is
- from '1' to '4' and the frac_digits part from '5' to '5'. After the code
- below, the int_digits part is from '1' to '4', the int_digits_tail
- part is from '5' to '5', the frac_digits part is empty, and
- int_digits_added_zeros=2 (to make 1234500).
+ from '1' to '4' and the frac_digits part from '5' to '5'. After the code
+ below, the int_digits part is from '1' to '4', the int_digits_tail
+ part is from '5' to '5', the frac_digits part is empty, and
+ int_digits_added_zeros=2 (to make 1234500).
*/
/*
@@ -589,7 +604,7 @@ void Field_decimal::store(const char *from,uint len)
{
// too big number, change to max or min number
Field_decimal::overflow(sign_char == '-');
- return;
+ return 1;
}
/*
@@ -670,7 +685,7 @@ void Field_decimal::store(const char *from,uint len)
{
if (current_thd->count_cuted_fields && !is_cuted_fields_incr)
break; // Go on below to see if we lose non zero digits
- return;
+ return 0;
}
*pos++='0';
}
@@ -683,7 +698,7 @@ void Field_decimal::store(const char *from,uint len)
{
if (!is_cuted_fields_incr)
current_thd->cuted_fields++;
- return;
+ return 0;
}
continue;
}
@@ -700,7 +715,7 @@ void Field_decimal::store(const char *from,uint len)
{
if (!is_cuted_fields_incr)
current_thd->cuted_fields++;
- return;
+ return 0;
}
continue;
}
@@ -709,26 +724,26 @@ void Field_decimal::store(const char *from,uint len)
while (pos != right_wall)
*pos++='0'; // Fill with zeros at right of '.'
-
+ return 0;
}
-void Field_decimal::store(double nr)
+int Field_decimal::store(double nr)
{
if (unsigned_flag && nr < 0)
{
overflow(1);
- return;
+ return 1;
}
#ifdef HAVE_FINITE
if (!finite(nr)) // Handle infinity as special case
{
overflow(nr < 0.0);
- return;
+ return 1;
}
#endif
-
+
reg4 uint i,length;
char fyllchar,*to;
char buff[320];
@@ -737,36 +752,43 @@ void Field_decimal::store(double nr)
#ifdef HAVE_SNPRINTF_
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr);
+ length=(uint) strlen(buff);
#else
- sprintf(buff,"%.*f",dec,nr);
+ length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr));
#endif
- length=(uint) strlen(buff);
if (length > field_length)
+ {
overflow(nr < 0.0);
+ return 1;
+ }
else
{
to=ptr;
for (i=field_length-length ; i-- > 0 ;)
*to++ = fyllchar;
memcpy(to,buff,length);
+ return 0;
}
}
-void Field_decimal::store(longlong nr)
+int Field_decimal::store(longlong nr)
{
if (unsigned_flag && nr < 0)
{
overflow(1);
- return;
+ return 1;
}
char buff[22];
uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff);
uint int_part=field_length- (dec ? dec+1 : 0);
if (length > int_part)
+ {
overflow(test(nr < 0L)); /* purecov: inspected */
+ return 1;
+ }
else
{
char fyllchar = zerofill ? (char) '0' : (char) ' ';
@@ -779,6 +801,7 @@ void Field_decimal::store(longlong nr)
to[length]='.';
bfill(to+length+1,dec,'0');
}
+ return 0;
}
}
@@ -812,7 +835,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
if (field_length < tmp_length) // Error in data
val_ptr->length(0);
else
- val_ptr->set((const char*) str,field_length-tmp_length);
+ val_ptr->set((const char*) str,field_length-tmp_length,default_charset_info);
return val_ptr;
}
@@ -829,8 +852,10 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
for (end=a_ptr+field_length;
a_ptr != end &&
(*a_ptr == *b_ptr ||
- ((isspace(*a_ptr) || *a_ptr == '+' || *a_ptr == '0') &&
- (isspace(*b_ptr) || *b_ptr == '+' || *b_ptr == '0')));
+ ((my_isspace(system_charset_info,*a_ptr) || *a_ptr == '+' ||
+ *a_ptr == '0') &&
+ (my_isspace(system_charset_info,*b_ptr) || *b_ptr == '+' ||
+ *b_ptr == '0')));
a_ptr++,b_ptr++)
{
if (*a_ptr == '-') // If both numbers are negative
@@ -857,8 +882,8 @@ void Field_decimal::sort_string(char *to,uint length)
char *str,*end;
for (str=ptr,end=ptr+length;
str != end &&
- ((isspace(*str) || *str == '+' || *str == '0')) ;
-
+ ((my_isspace(system_charset_info,*str) || *str == '+' ||
+ *str == '0')) ;
str++)
*to++=' ';
if (str == end)
@@ -869,7 +894,7 @@ void Field_decimal::sort_string(char *to,uint length)
*to++=1; // Smaller than any number
str++;
while (str != end)
- if (isdigit(*str))
+ if (my_isdigit(system_charset_info,*str))
*to++= (char) ('9' - *str++);
else
*to++= *str++;
@@ -877,6 +902,7 @@ void Field_decimal::sort_string(char *to,uint length)
else memcpy(to,str,(uint) (end-str));
}
+
void Field_decimal::sql_type(String &res) const
{
uint tmp=field_length;
@@ -893,10 +919,11 @@ void Field_decimal::sql_type(String &res) const
** tiny int
****************************************************************************/
-void Field_tiny::store(const char *from,uint len)
+int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
+ String tmp_str(from,len,default_charset_info);
long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int error= 0;
if (unsigned_flag)
{
@@ -904,14 +931,19 @@ void Field_tiny::store(const char *from,uint len)
{
tmp=0; /* purecov: inspected */
current_thd->cuted_fields++; /* purecov: inspected */
+ error= 1;
}
else if (tmp > 255)
{
tmp= 255;
current_thd->cuted_fields++;
+ error= 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
else
{
@@ -919,21 +951,28 @@ void Field_tiny::store(const char *from,uint len)
{
tmp= -128;
current_thd->cuted_fields++;
+ error= 1;
}
else if (tmp >= 128)
{
tmp= 127;
current_thd->cuted_fields++;
+ error= 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
ptr[0]= (char) tmp;
+ return error;
}
-void Field_tiny::store(double nr)
+int Field_tiny::store(double nr)
{
+ int error= 0;
nr=rint(nr);
if (unsigned_flag)
{
@@ -941,11 +980,13 @@ void Field_tiny::store(double nr)
{
*ptr=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > 255.0)
{
*ptr=(char) 255;
current_thd->cuted_fields++;
+ error= 1;
}
else
*ptr=(char) nr;
@@ -956,30 +997,36 @@ void Field_tiny::store(double nr)
{
*ptr= (char) -128;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > 127.0)
{
*ptr=127;
current_thd->cuted_fields++;
+ error= 1;
}
else
*ptr=(char) nr;
}
+ return error;
}
-void Field_tiny::store(longlong nr)
+int Field_tiny::store(longlong nr)
{
+ int error= 0;
if (unsigned_flag)
{
if (nr < 0L)
{
*ptr=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > 255L)
{
*ptr= (char) 255;
current_thd->cuted_fields++;
+ error= 1;
}
else
*ptr=(char) nr;
@@ -990,15 +1037,18 @@ void Field_tiny::store(longlong nr)
{
*ptr= (char) -128;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > 127L)
{
*ptr=127;
current_thd->cuted_fields++;
+ error= 1;
}
else
*ptr=(char) nr;
}
+ return error;
}
@@ -1064,24 +1114,30 @@ 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.
-void Field_short::store(const char *from,uint len)
+int Field_short::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
+ String tmp_str(from,len,default_charset_info);
long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int error= 0;
if (unsigned_flag)
{
if (tmp < 0)
{
tmp=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (tmp > (uint16) ~0)
{
tmp=(uint16) ~0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
else
{
@@ -1089,14 +1145,19 @@ void Field_short::store(const char *from,uint len)
{
tmp= INT_MIN16;
current_thd->cuted_fields++;
+ error= 1;
}
else if (tmp > INT_MAX16)
{
tmp=INT_MAX16;
current_thd->cuted_fields++;
+ error= 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1106,11 +1167,13 @@ void Field_short::store(const char *from,uint len)
else
#endif
shortstore(ptr,(short) tmp);
+ return error;
}
-void Field_short::store(double nr)
+int Field_short::store(double nr)
{
+ int error= 0;
int16 res;
nr=rint(nr);
if (unsigned_flag)
@@ -1119,11 +1182,13 @@ void Field_short::store(double nr)
{
res=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (double) (uint16) ~0)
{
res=(int16) (uint16) ~0;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int16) (uint16) nr;
@@ -1134,11 +1199,13 @@ void Field_short::store(double nr)
{
res=INT_MIN16;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (double) INT_MAX16)
{
res=INT_MAX16;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int16) nr;
@@ -1151,10 +1218,12 @@ void Field_short::store(double nr)
else
#endif
shortstore(ptr,res);
+ return error;
}
-void Field_short::store(longlong nr)
+int Field_short::store(longlong nr)
{
+ int error= 0;
int16 res;
if (unsigned_flag)
{
@@ -1162,11 +1231,13 @@ void Field_short::store(longlong nr)
{
res=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (longlong) (uint16) ~0)
{
res=(int16) (uint16) ~0;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int16) (uint16) nr;
@@ -1177,11 +1248,13 @@ void Field_short::store(longlong nr)
{
res=INT_MIN16;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > INT_MAX16)
{
res=INT_MAX16;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int16) nr;
@@ -1194,6 +1267,7 @@ void Field_short::store(longlong nr)
else
#endif
shortstore(ptr,res);
+ return error;
}
@@ -1304,10 +1378,11 @@ void Field_short::sql_type(String &res) const
// Note: Sometimes this should be fixed to use one strtol() to use
// len and check for garbage after number.
-void Field_medium::store(const char *from,uint len)
+int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
+ String tmp_str(from,len,default_charset_info);
long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int error= 0;
if (unsigned_flag)
{
@@ -1315,14 +1390,19 @@ void Field_medium::store(const char *from,uint len)
{
tmp=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (tmp >= (long) (1L << 24))
{
tmp=(long) (1L << 24)-1L;
current_thd->cuted_fields++;
+ error= 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
else
{
@@ -1330,22 +1410,29 @@ void Field_medium::store(const char *from,uint len)
{
tmp= INT_MIN24;
current_thd->cuted_fields++;
+ error= 1;
}
else if (tmp > INT_MAX24)
{
tmp=INT_MAX24;
current_thd->cuted_fields++;
+ error= 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
int3store(ptr,tmp);
+ return error;
}
-void Field_medium::store(double nr)
+int Field_medium::store(double nr)
{
+ int error= 0;
nr=rint(nr);
if (unsigned_flag)
{
@@ -1353,12 +1440,14 @@ void Field_medium::store(double nr)
{
int3store(ptr,0);
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr >= (double) (long) (1L << 24))
{
uint32 tmp=(uint32) (1L << 24)-1L;
int3store(ptr,tmp);
current_thd->cuted_fields++;
+ error= 1;
}
else
int3store(ptr,(uint32) nr);
@@ -1370,32 +1459,38 @@ void Field_medium::store(double nr)
long tmp=(long) INT_MIN24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (double) INT_MAX24)
{
long tmp=(long) INT_MAX24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
+ error= 1;
}
else
int3store(ptr,(long) nr);
}
+ return error;
}
-void Field_medium::store(longlong nr)
+int Field_medium::store(longlong nr)
{
+ int error= 0;
if (unsigned_flag)
{
if (nr < 0L)
{
int3store(ptr,0);
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr >= (longlong) (long) (1L << 24))
{
long tmp=(long) (1L << 24)-1L;;
int3store(ptr,tmp);
current_thd->cuted_fields++;
+ error= 1;
}
else
int3store(ptr,(uint32) nr);
@@ -1407,16 +1502,19 @@ void Field_medium::store(longlong nr)
long tmp=(long) INT_MIN24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (longlong) INT_MAX24)
{
long tmp=(long) INT_MAX24;
int3store(ptr,tmp);
current_thd->cuted_fields++;
+ error= 1;
}
else
int3store(ptr,(long) nr);
}
+ return error;
}
@@ -1489,14 +1587,15 @@ 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.
-void Field_long::store(const char *from,uint len)
+int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
{
- while (len && isspace(*from))
+ while (len && my_isspace(system_charset_info,*from))
{
len--; from++;
}
long tmp;
- String tmp_str(from,len);
+ int error= 0;
+ String tmp_str(from,len,default_charset_info);
errno=0;
if (unsigned_flag)
{
@@ -1504,6 +1603,7 @@ void Field_long::store(const char *from,uint len)
{
tmp=0; // Set negative to 0
errno=ERANGE;
+ error= 1;
}
else
tmp=(long) strtoul(tmp_str.c_ptr(),NULL,10);
@@ -1511,7 +1611,10 @@ void Field_long::store(const char *from,uint len)
else
tmp=strtol(tmp_str.c_ptr(),NULL,10);
if (errno || current_thd->count_cuted_fields && !test_if_int(from,len))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1520,11 +1623,13 @@ void Field_long::store(const char *from,uint len)
else
#endif
longstore(ptr,tmp);
+ return error;
}
-void Field_long::store(double nr)
+int Field_long::store(double nr)
{
+ int error= 0;
int32 res;
nr=rint(nr);
if (unsigned_flag)
@@ -1533,11 +1638,13 @@ void Field_long::store(double nr)
{
res=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (double) (ulong) ~0L)
{
res=(int32) (uint32) ~0L;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int32) (ulong) nr;
@@ -1548,11 +1655,13 @@ void Field_long::store(double nr)
{
res=(int32) INT_MIN32;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (double) INT_MAX32)
{
res=(int32) INT_MAX32;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int32) nr;
@@ -1565,11 +1674,13 @@ void Field_long::store(double nr)
else
#endif
longstore(ptr,res);
+ return error;
}
-void Field_long::store(longlong nr)
+int Field_long::store(longlong nr)
{
+ int error= 0;
int32 res;
if (unsigned_flag)
{
@@ -1577,11 +1688,13 @@ void Field_long::store(longlong nr)
{
res=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr >= (LL(1) << 32))
{
res=(int32) (uint32) ~0L;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int32) (uint32) nr;
@@ -1592,11 +1705,13 @@ void Field_long::store(longlong nr)
{
res=(int32) INT_MIN32;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > (longlong) INT_MAX32)
{
res=(int32) INT_MAX32;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(int32) nr;
@@ -1609,6 +1724,7 @@ void Field_long::store(longlong nr)
else
#endif
longstore(ptr,res);
+ return error;
}
@@ -1717,14 +1833,15 @@ void Field_long::sql_type(String &res) const
** longlong int
****************************************************************************/
-void Field_longlong::store(const char *from,uint len)
+int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
{
- while (len && isspace(*from))
+ while (len && my_isspace(system_charset_info,*from))
{ // For easy error check
len--; from++;
}
longlong tmp;
- String tmp_str(from,len);
+ String tmp_str(from,len,default_charset_info);
+ int error= 0;
errno=0;
if (unsigned_flag)
{
@@ -1732,6 +1849,7 @@ void Field_longlong::store(const char *from,uint len)
{
tmp=0; // Set negative to 0
errno=ERANGE;
+ error= 1;
}
else
tmp=(longlong) strtoull(tmp_str.c_ptr(),NULL,10);
@@ -1739,7 +1857,10 @@ void Field_longlong::store(const char *from,uint len)
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;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1748,11 +1869,13 @@ void Field_longlong::store(const char *from,uint len)
else
#endif
longlongstore(ptr,tmp);
+ return error;
}
-void Field_longlong::store(double nr)
+int Field_longlong::store(double nr)
{
+ int error= 0;
longlong res;
nr=rint(nr);
if (unsigned_flag)
@@ -1761,11 +1884,13 @@ void Field_longlong::store(double nr)
{
res=0;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr >= (double) ~ (ulonglong) 0)
{
res= ~(longlong) 0;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(longlong) (ulonglong) nr;
@@ -1776,11 +1901,13 @@ void Field_longlong::store(double nr)
{
res=(longlong) LONGLONG_MIN;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr >= (double) LONGLONG_MAX)
{
res=(longlong) LONGLONG_MAX;
current_thd->cuted_fields++;
+ error= 1;
}
else
res=(longlong) nr;
@@ -1793,10 +1920,11 @@ void Field_longlong::store(double nr)
else
#endif
longlongstore(ptr,res);
+ return error;
}
-void Field_longlong::store(longlong nr)
+int Field_longlong::store(longlong nr)
{
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1806,6 +1934,7 @@ void Field_longlong::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
+ return 0;
}
@@ -1924,35 +2053,43 @@ void Field_longlong::sql_type(String &res) const
** single precision float
****************************************************************************/
-void Field_float::store(const char *from,uint len)
+int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
+ 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))
+ {
current_thd->cuted_fields++;
+ return 1;
+ }
+ return (errno) ? 1 : 0;
}
-void Field_float::store(double nr)
+int Field_float::store(double nr)
{
float j;
+ int error= 0;
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
if (unsigned_flag && nr < 0)
{
current_thd->cuted_fields++;
nr=0;
+ error= 1;
}
if (nr < -FLT_MAX)
{
j= -FLT_MAX;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr > FLT_MAX)
{
j=FLT_MAX;
current_thd->cuted_fields++;
+ error= 1;
}
else
j= (float) nr;
@@ -1964,16 +2101,19 @@ void Field_float::store(double nr)
else
#endif
memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ return error;
}
-void Field_float::store(longlong nr)
+int Field_float::store(longlong nr)
{
+ int error= 0;
float j= (float) nr;
if (unsigned_flag && j < 0)
{
current_thd->cuted_fields++;
j=0;
+ error= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1983,6 +2123,7 @@ void Field_float::store(longlong nr)
else
#endif
memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ return error;
}
@@ -2082,10 +2223,10 @@ String *Field_float::val_str(String *val_buffer,
#ifdef HAVE_SNPRINTF
to[to_length-1]=0; // Safety
snprintf(to,to_length-1,"%.*f",dec,nr);
+ to=strend(to);
#else
- sprintf(to,"%.*f",dec,nr);
+ to+= my_sprintf(to,(to,"%.*f",dec,nr));
#endif
- to=strend(to);
#endif
}
#ifdef HAVE_FCONVERT
@@ -2174,17 +2315,22 @@ void Field_float::sql_type(String &res) const
** double precision floating point numbers
****************************************************************************/
-void Field_double::store(const char *from,uint len)
+int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
+ 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))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
if (unsigned_flag && j < 0)
{
current_thd->cuted_fields++;
j=0;
+ error= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2194,17 +2340,20 @@ void Field_double::store(const char *from,uint len)
else
#endif
doublestore(ptr,j);
+ return error;
}
-void Field_double::store(double nr)
+int Field_double::store(double nr)
{
+ int error= 0;
if (dec < NOT_FIXED_DEC)
nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point
if (unsigned_flag && nr < 0)
{
current_thd->cuted_fields++;
nr=0;
+ error= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2214,15 +2363,18 @@ void Field_double::store(double nr)
else
#endif
doublestore(ptr,nr);
+ return error;
}
-void Field_double::store(longlong nr)
+int Field_double::store(longlong nr)
{
double j= (double) nr;
+ int error= 0;
if (unsigned_flag && j < 0)
{
current_thd->cuted_fields++;
+ error= 1;
j=0;
}
#ifdef WORDS_BIGENDIAN
@@ -2233,6 +2385,7 @@ void Field_double::store(longlong nr)
else
#endif
doublestore(ptr,j);
+ return error;
}
@@ -2331,10 +2484,10 @@ String *Field_double::val_str(String *val_buffer,
#ifdef HAVE_SNPRINTF
to[to_length-1]=0; // Safety
snprintf(to,to_length-1,"%.*f",dec,nr);
+ to=strend(to);
#else
- sprintf(to,"%.*f",dec,nr);
+ to+= my_sprintf(to,(to,"%.*f",dec,nr));
#endif
- to=strend(to);
#endif
}
#ifdef HAVE_FCONVERT
@@ -2430,7 +2583,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
}
-void Field_timestamp::store(const char *from,uint len)
+int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs)
{
long tmp=(long) str_to_timestamp(from,len);
#ifdef WORDS_BIGENDIAN
@@ -2441,6 +2594,7 @@ void Field_timestamp::store(const char *from,uint len)
else
#endif
longstore(ptr,tmp);
+ return 0;
}
void Field_timestamp::fill_and_store(char *from,uint len)
@@ -2472,14 +2626,17 @@ void Field_timestamp::fill_and_store(char *from,uint len)
}
-void Field_timestamp::store(double nr)
+int Field_timestamp::store(double nr)
{
+ int error= 0;
if (nr < 0 || nr > 99991231235959.0)
{
- nr=0; // Avoid overflow on buff
+ nr= 0; // Avoid overflow on buff
current_thd->cuted_fields++;
+ error= 1;
}
- Field_timestamp::store((longlong) rint(nr));
+ error|= Field_timestamp::store((longlong) rint(nr));
+ return error;
}
@@ -2520,7 +2677,7 @@ static longlong fix_datetime(longlong nr)
}
-void Field_timestamp::store(longlong nr)
+int Field_timestamp::store(longlong nr)
{
TIME l_time;
time_t timestamp;
@@ -2548,6 +2705,7 @@ void Field_timestamp::store(longlong nr)
else
#endif
longstore(ptr,(uint32) timestamp);
+ return 0;
}
@@ -2744,8 +2902,10 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
void Field_timestamp::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"timestamp(%d)",(int) field_length);
- res.length((uint) strlen(res.ptr()));
+ ulong length= my_sprintf((char*) res.ptr(),
+ ((char*) res.ptr(),"timestamp(%d)",
+ (int) field_length));
+ res.length(length);
}
@@ -2769,12 +2929,16 @@ void Field_timestamp::set_time()
** Stored as a 3 byte unsigned int
****************************************************************************/
-void Field_time::store(const char *from,uint len)
+int Field_time::store(const char *from,uint len,CHARSET_INFO *cs)
{
TIME ltime;
long tmp;
+ int error= 0;
if (str_to_time(from,len,&ltime))
+ {
tmp=0L;
+ error= 1;
+ }
else
{
if (ltime.month)
@@ -2784,26 +2948,31 @@ void Field_time::store(const char *from,uint len)
{
tmp=8385959;
current_thd->cuted_fields++;
+ error= 1;
}
}
if (ltime.neg)
tmp= -tmp;
- Field_time::store((longlong) tmp);
+ error |= Field_time::store((longlong) tmp);
+ return error;
}
-void Field_time::store(double nr)
+int Field_time::store(double nr)
{
long tmp;
+ int error= 0;
if (nr > 8385959.0)
{
tmp=8385959L;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr < -8385959.0)
{
tmp= -8385959L;
current_thd->cuted_fields++;
+ error= 1;
}
else
{
@@ -2814,24 +2983,29 @@ void Field_time::store(double nr)
{
tmp=0;
current_thd->cuted_fields++;
+ error= 1;
}
}
int3store(ptr,tmp);
+ return error;
}
-void Field_time::store(longlong nr)
+int Field_time::store(longlong nr)
{
long tmp;
+ int error= 0;
if (nr > (longlong) 8385959L)
{
tmp=8385959L;
current_thd->cuted_fields++;
+ error= 1;
}
else if (nr < (longlong) -8385959L)
{
tmp= -8385959L;
current_thd->cuted_fields++;
+ error= 1;
}
else
{
@@ -2840,9 +3014,11 @@ void Field_time::store(longlong nr)
{
tmp=0;
current_thd->cuted_fields++;
+ error= 1;
}
}
int3store(ptr,tmp);
+ return error;
}
@@ -2868,10 +3044,11 @@ String *Field_time::val_str(String *val_buffer,
tmp= -tmp;
sign= "-";
}
- sprintf((char*) val_buffer->ptr(),"%s%02d:%02d:%02d",
- sign,(int) (tmp/10000), (int) (tmp/100 % 100),
- (int) (tmp % 100));
- val_buffer->length((uint) strlen(val_buffer->ptr()));
+ long length= my_sprintf((char*) val_buffer->ptr(),
+ ((char*) val_buffer->ptr(),"%s%02d:%02d:%02d",
+ sign,(int) (tmp/10000), (int) (tmp/100 % 100),
+ (int) (tmp % 100)));
+ val_buffer->length(length);
return val_buffer;
}
@@ -2909,7 +3086,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused)))
void Field_time::sql_type(String &res) const
{
- res.set("time",4);
+ res.set("time",4,default_charset_info);
}
/****************************************************************************
@@ -2918,16 +3095,16 @@ void Field_time::sql_type(String &res) const
** Can handle 2 byte or 4 byte years!
****************************************************************************/
-void Field_year::store(const char *from, uint len)
+int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
{
- String tmp_str(from,len);
+ String tmp_str(from,len,default_charset_info);
long nr= strtol(tmp_str.c_ptr(),NULL,10);
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr=0;
current_thd->cuted_fields++;
- return;
+ return 1;
}
else if (current_thd->count_cuted_fields && !test_if_int(from,len))
current_thd->cuted_fields++;
@@ -2939,23 +3116,27 @@ void Field_year::store(const char *from, uint len)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
+ return 0;
}
-void Field_year::store(double nr)
+int Field_year::store(double nr)
{
if (nr < 0.0 || nr >= 2155.0)
- Field_year::store((longlong) -1);
+ {
+ (void) Field_year::store((longlong) -1);
+ return 1;
+ }
else
- Field_year::store((longlong) nr);
+ return Field_year::store((longlong) nr);
}
-void Field_year::store(longlong nr)
+int Field_year::store(longlong nr)
{
if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
{
*ptr=0;
current_thd->cuted_fields++;
- return;
+ return 1;
}
if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000
{
@@ -2965,6 +3146,7 @@ void Field_year::store(longlong nr)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
+ return 0;
}
@@ -2995,8 +3177,9 @@ String *Field_year::val_str(String *val_buffer,
void Field_year::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"year(%d)",(int) field_length);
- res.length((uint) strlen(res.ptr()));
+ ulong length=my_sprintf((char*) res.ptr(),
+ ((char*) res.ptr(),"year(%d)",(int) field_length));
+ res.length(length);
}
@@ -3007,12 +3190,16 @@ void Field_year::sql_type(String &res) const
** Stored as a 4 byte unsigned int
****************************************************************************/
-void Field_date::store(const char *from, uint len)
+int Field_date::store(const char *from, uint len,CHARSET_INFO *cs)
{
TIME l_time;
uint32 tmp;
+ int error= 0;
if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
+ {
tmp=0;
+ error= 1;
+ }
else
tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day);
#ifdef WORDS_BIGENDIAN
@@ -3023,18 +3210,21 @@ void Field_date::store(const char *from, uint len)
else
#endif
longstore(ptr,tmp);
+ return error;
}
-void Field_date::store(double nr)
+int Field_date::store(double nr)
{
long tmp;
+ int error= 0;
if (nr >= 19000000000000.0 && nr <= 99991231235959.0)
nr=floor(nr/1000000.0); // Timestamp to date
if (nr < 0.0 || nr > 99991231.0)
{
tmp=0L;
current_thd->cuted_fields++;
+ error= 1;
}
else
tmp=(long) rint(nr);
@@ -3046,18 +3236,21 @@ void Field_date::store(double nr)
else
#endif
longstore(ptr,tmp);
+ return error;
}
-void Field_date::store(longlong nr)
+int Field_date::store(longlong nr)
{
long tmp;
+ int error= 0;
if (nr >= LL(19000000000000) && nr < LL(99991231235959))
nr=nr/LL(1000000); // Timestamp to date
if (nr < 0 || nr > LL(99991231))
{
tmp=0L;
current_thd->cuted_fields++;
+ error= 1;
}
else
tmp=(long) nr;
@@ -3069,6 +3262,7 @@ void Field_date::store(longlong nr)
else
#endif
longstore(ptr,tmp);
+ return error;
}
@@ -3155,7 +3349,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused)))
void Field_date::sql_type(String &res) const
{
- res.set("date",4);
+ res.set("date",4,default_charset_info);
}
/****************************************************************************
@@ -3164,35 +3358,45 @@ void Field_date::sql_type(String &res) const
** In number context: YYYYMMDD
****************************************************************************/
-void Field_newdate::store(const char *from,uint len)
+int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs)
{
TIME l_time;
long tmp;
+ int error= 0;
if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE)
+ {
tmp=0L;
+ error= 1;
+ }
else
tmp= l_time.day + l_time.month*32 + l_time.year*16*32;
int3store(ptr,tmp);
+ return error;
}
-void Field_newdate::store(double nr)
+int Field_newdate::store(double nr)
{
if (nr < 0.0 || nr > 99991231235959.0)
- Field_newdate::store((longlong) -1);
+ {
+ (void) Field_newdate::store((longlong) -1);
+ return 1;
+ }
else
- Field_newdate::store((longlong) rint(nr));
+ return Field_newdate::store((longlong) rint(nr));
}
-void Field_newdate::store(longlong nr)
+int Field_newdate::store(longlong nr)
{
int32 tmp;
+ int error= 0;
if (nr >= LL(100000000) && nr <= LL(99991231235959))
nr=nr/LL(1000000); // Timestamp to date
if (nr < 0L || nr > 99991231L)
{
tmp=0;
current_thd->cuted_fields++;
+ error= 1;
}
else
{
@@ -3210,11 +3414,13 @@ void Field_newdate::store(longlong nr)
{
tmp=0L; // Don't allow date to change
current_thd->cuted_fields++;
+ error= 1;
}
else
tmp= day + month*32 + (tmp/10000)*16*32;
}
int3store(ptr,(int32) tmp);
+ return error;
}
void Field_newdate::store_time(TIME *ltime,timestamp_type type)
@@ -3306,7 +3512,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused)))
void Field_newdate::sql_type(String &res) const
{
- res.set("date",4);
+ res.set("date",4,default_charset_info);
}
@@ -3317,7 +3523,7 @@ void Field_newdate::sql_type(String &res) const
** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int.
****************************************************************************/
-void Field_datetime::store(const char *from,uint len)
+int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs)
{
longlong tmp=str_to_datetime(from,len,1);
#ifdef WORDS_BIGENDIAN
@@ -3328,26 +3534,32 @@ void Field_datetime::store(const char *from,uint len)
else
#endif
longlongstore(ptr,tmp);
+ return 0;
}
-void Field_datetime::store(double nr)
+int Field_datetime::store(double nr)
{
+ int error= 0;
if (nr < 0.0 || nr > 99991231235959.0)
{
nr=0.0;
current_thd->cuted_fields++;
+ error= 1;
}
- Field_datetime::store((longlong) rint(nr));
+ error |= Field_datetime::store((longlong) rint(nr));
+ return error;
}
-void Field_datetime::store(longlong nr)
+int Field_datetime::store(longlong nr)
{
+ int error= 0;
if (nr < 0 || nr > LL(99991231235959))
{
nr=0;
current_thd->cuted_fields++;
+ error= 1;
}
else
nr=fix_datetime(nr);
@@ -3359,6 +3571,7 @@ void Field_datetime::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
+ return error;
}
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
@@ -3523,7 +3736,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused)))
void Field_datetime::sql_type(String &res) const
{
- res.set("datetime",8);
+ res.set("datetime",8,default_charset_info);
}
/****************************************************************************
@@ -3533,10 +3746,11 @@ void Field_datetime::sql_type(String &res) const
/* Copy a string and fill with space */
-void Field_string::store(const char *from,uint length)
+int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ int error= 0;
#ifdef USE_TIS620
- if (!binary_flag) {
+ if (!binary()) {
ThNormalize((uchar *)ptr, field_length, (uchar *)from, length);
if (length < field_length) {
bfill(ptr + length, field_length - length, ' ');
@@ -3557,33 +3771,35 @@ void Field_string::store(const char *from,uint length)
const char *end=from+length;
for (from+=field_length ; from != end ; from++)
{
- if (!isspace(*from))
+ if (!my_isspace(field_charset,*from))
{
current_thd->cuted_fields++;
+ error=1;
break;
}
}
}
}
#endif /* USE_TIS620 */
+ return error;
}
-void Field_string::store(double nr)
+int Field_string::store(double nr)
{
char buff[MAX_FIELD_WIDTH],*end;
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
end=strcend(buff,' ');
- Field_string::store(buff,(uint) (end - buff));
+ return Field_string::store(buff,(uint) (end - buff), default_charset_info);
}
-void Field_string::store(longlong nr)
+int Field_string::store(longlong nr)
{
char buff[22];
char *end=longlong10_to_str(nr,buff,-10);
- Field_string::store(buff,(uint) (end-buff));
+ return Field_string::store(buff,(uint) (end-buff), default_charset_info);
}
@@ -3618,51 +3834,57 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)),
#endif
while (end > ptr && end[-1] == ' ')
end--;
- val_ptr->set((const char*) ptr,(uint) (end - ptr));
+ val_ptr->set((const char*) ptr,(uint) (end - ptr),field_charset);
return val_ptr;
}
int Field_string::cmp(const char *a_ptr, const char *b_ptr)
{
- if (binary_flag)
- return memcmp(a_ptr,b_ptr,field_length);
- else
- return my_sortcmp(a_ptr,b_ptr,field_length);
+ return my_strnncoll(field_charset,
+ (const uchar*)a_ptr,field_length,
+ (const uchar*)b_ptr,field_length);
}
void Field_string::sort_string(char *to,uint length)
{
- if (binary_flag)
+ if (binary())
memcpy((byte*) to,(byte*) ptr,(size_t) length);
else
{
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info)) {
- uint tmp=my_strnxfrm(default_charset_info,
- (unsigned char *)to, (unsigned char *) ptr,
- length, field_length);
+ if (use_strnxfrm(field_charset)) {
+ uint tmp=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *) ptr, field_length);
if (tmp < length)
bzero(to + tmp, length - tmp);
}
else
#endif
for (char *from=ptr,*end=ptr+length ; from != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *from++];
+ *to++=(char) field_charset->sort_order[(uint) (uchar) *from++];
}
}
void Field_string::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"%s(%d)",
- field_length > 3 &&
- (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
- "varchar" : "char",
- (int) field_length);
- res.length((uint) strlen(res.ptr()));
- if (binary_flag)
+ ulong length= my_sprintf((char*) res.ptr(),
+ ((char*) res.ptr(), "%s(%d)",
+ (field_length > 3 &&
+ (table->db_options_in_use &
+ HA_OPTION_PACK_RECORD) ?
+ "varchar" : "char"),
+ (int) field_length));
+ res.length((uint) length);
+ if (binary())
res.append(" binary");
+ else
+ {
+ res.append(" character set ");
+ res.append(field_charset->name);
+ }
}
@@ -3692,12 +3914,14 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length)
uint a_length= (uint) (uchar) *a++;
uint b_length= (uint) (uchar) *b++;
- if (binary_flag)
+ if (binary())
{
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar*)a,a_length,
+ (const uchar*)b,b_length);
}
@@ -3709,12 +3933,14 @@ int Field_string::pack_cmp(const char *b, uint length)
end--;
uint a_length = (uint) (end - ptr);
- if (binary_flag)
+ if (binary())
{
int cmp= memcmp(ptr,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(ptr,a_length, b, b_length);
+ return my_strnncoll(field_charset,
+ (const uchar*)ptr,a_length,
+ (const uchar*)b, b_length);
}
@@ -3737,10 +3963,11 @@ uint Field_string::max_packed_col_length(uint max_length)
****************************************************************************/
-void Field_varstring::store(const char *from,uint length)
+int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ int error= 0;
#ifdef USE_TIS620
- if (!binary_flag)
+ if (!binary())
{
ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length);
}
@@ -3754,27 +3981,29 @@ void Field_varstring::store(const char *from,uint length)
length=field_length;
memcpy(ptr+2,from,field_length);
current_thd->cuted_fields++;
+ error= 1;
}
#endif /* USE_TIS620 */
int2store(ptr,length);
+ return error;
}
-void Field_varstring::store(double nr)
+int Field_varstring::store(double nr)
{
char buff[MAX_FIELD_WIDTH],*end;
int width=min(field_length,DBL_DIG+5);
sprintf(buff,"%-*.*g",width,max(width-5,0),nr);
end=strcend(buff,' ');
- Field_varstring::store(buff,(uint) (end - buff));
+ return Field_varstring::store(buff,(uint) (end - buff), default_charset_info);
}
-void Field_varstring::store(longlong nr)
+int Field_varstring::store(longlong nr)
{
char buff[22];
char *end=longlong10_to_str(nr,buff,-10);
- Field_varstring::store(buff,(uint) (end-buff));
+ return Field_varstring::store(buff,(uint) (end-buff), default_charset_info);
}
@@ -3806,7 +4035,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
uint length=uint2korr(ptr);
- val_ptr->set((const char*) ptr+2,length);
+ val_ptr->set((const char*) ptr+2,length,field_charset);
return val_ptr;
}
@@ -3816,25 +4045,24 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
uint a_length=uint2korr(a_ptr);
uint b_length=uint2korr(b_ptr);
int diff;
- if (binary_flag)
- diff=memcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
- else
- diff=my_sortcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
+ diff=my_strnncoll(field_charset,
+ (const uchar*)a_ptr+2,min(a_length,b_length),
+ (const uchar*)b_ptr+2,min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
void Field_varstring::sort_string(char *to,uint length)
{
uint tot_length=uint2korr(ptr);
- if (binary_flag)
+ if (binary())
memcpy((byte*) to,(byte*) ptr+2,(size_t) tot_length);
else
{
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- tot_length=my_strnxfrm(default_charset_info,
- (unsigned char *) to, (unsigned char *)ptr+2,
- length, tot_length);
+ if (use_strnxfrm(field_charset))
+ tot_length=my_strnxfrm(field_charset,
+ (unsigned char *) to, length,
+ (unsigned char *)ptr+2, tot_length);
else
{
#endif
@@ -3842,7 +4070,7 @@ void Field_varstring::sort_string(char *to,uint length)
if (tot_length > length)
tot_length=length;
for (char *from=ptr+2,*end=from+tot_length ; from != end ;)
- *tmp++=(char) my_sort_order[(uint) (uchar) *from++];
+ *tmp++=(char) field_charset->sort_order[(uint) (uchar) *from++];
#ifdef USE_STRCOLL
}
#endif
@@ -3854,10 +4082,17 @@ void Field_varstring::sort_string(char *to,uint length)
void Field_varstring::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"varchar(%d)",(int) field_length);
- res.length((uint) strlen(res.ptr()));
- if (binary_flag)
+ ulong length= my_sprintf((char*) res.ptr(),
+ ((char*) res.ptr(),"varchar(%u)",
+ field_length));
+ res.length((uint) length);
+ if (binary())
res.append(" binary");
+ else
+ {
+ res.append(" character set ");
+ res.append(field_charset->name);
+ }
}
char *Field_varstring::pack(char *to, const char *from, uint max_length)
@@ -3908,12 +4143,14 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
+ if (binary())
{
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
int Field_varstring::pack_cmp(const char *b, uint key_length)
@@ -3929,12 +4166,14 @@ int Field_varstring::pack_cmp(const char *b, uint key_length)
{
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
+ if (binary())
{
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
uint Field_varstring::packed_col_length(const char *data_ptr, uint length)
@@ -3959,15 +4198,13 @@ uint Field_varstring::max_packed_col_length(uint max_length)
Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
- bool binary_arg)
+ CHARSET_INFO *cs)
:Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
- table_arg),
- packlength(blob_pack_length),binary_flag(binary_arg)
+ table_arg, cs),
+ packlength(blob_pack_length), geom_flag(true)
{
flags|= BLOB_FLAG;
- if (binary_arg)
- flags|=BINARY_FLAG;
if (table)
table->blob_fields++;
}
@@ -4054,7 +4291,7 @@ uint32 Field_blob::get_length(const char *pos)
}
-void Field_blob::store(const char *from,uint len)
+int Field_blob::store(const char *from,uint len,CHARSET_INFO *cs)
{
if (!len)
{
@@ -4069,7 +4306,7 @@ void Field_blob::store(const char *from,uint len)
if (table->copy_blobs || len <= MAX_FIELD_WIDTH)
{ // Must make a copy
#ifdef USE_TIS620
- if (!binary_flag)
+ if (!binary())
{
/* If there isn't enough memory, use original string */
if ((th_ptr=(char * ) my_malloc(sizeof(char) * len,MYF(0))))
@@ -4079,7 +4316,7 @@ void Field_blob::store(const char *from,uint len)
}
}
#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));
@@ -4087,20 +4324,21 @@ void Field_blob::store(const char *from,uint len)
}
bmove(ptr+packlength,(char*) &from,sizeof(char*));
}
+ return 0;
}
-void Field_blob::store(double nr)
+int Field_blob::store(double nr)
{
- value.set(nr);
- Field_blob::store(value.ptr(),(uint) value.length());
+ value.set(nr,2,current_thd->thd_charset);
+ return Field_blob::store(value.ptr(),(uint) value.length(), value.charset());
}
-void Field_blob::store(longlong nr)
+int Field_blob::store(longlong nr)
{
- value.set(nr);
- Field_blob::store(value.ptr(), (uint) value.length());
+ value.set(nr,current_thd->thd_charset);
+ return Field_blob::store(value.ptr(), (uint) value.length(), value.charset());
}
@@ -4143,9 +4381,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
- val_ptr->set("",0); // A bit safer than ->length(0)
+ val_ptr->set("",0,field_charset); // A bit safer than ->length(0)
else
- val_ptr->set((const char*) blob,get_length(ptr));
+ val_ptr->set((const char*) blob,get_length(ptr),field_charset);
return val_ptr;
}
@@ -4153,11 +4391,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)),
int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
uint32 b_length)
{
- int diff;
- if (binary_flag)
- diff=memcmp(a,b,min(a_length,b_length));
- else
- diff=my_sortcmp(a,b,min(a_length,b_length));
+ int diff=my_strnncoll(field_charset,
+ (const uchar*)a,min(a_length,b_length),
+ (const uchar*)b,min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
@@ -4205,11 +4441,30 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff,uint length)
+void Field_blob::get_key_image(char *buff,uint length, imagetype type)
{
- length-=HA_KEY_BLOB_LENGTH;
- uint32 blob_length=get_length(ptr);
+ length-= HA_KEY_BLOB_LENGTH;
+ uint32 blob_length= get_length(ptr);
char *blob;
+
+ if (type == itMBR)
+ {
+ if (!blob_length)
+ return;
+ get_ptr(&blob);
+
+ MBR mbr;
+ Geometry gobj;
+ gobj.create_from_wkb(blob,blob_length);
+ gobj.get_mbr(&mbr);
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ return;
+ }
+
+ length-=HA_KEY_BLOB_LENGTH;
if ((uint32) length > blob_length)
{
#ifdef HAVE_purify
@@ -4225,9 +4480,34 @@ void Field_blob::get_key_image(char *buff,uint length)
void Field_blob::set_key_image(char *buff,uint length)
{
length=uint2korr(buff);
- Field_blob::store(buff+2,length);
+ (void) Field_blob::store(buff+2,length, default_charset_info);
+}
+
+
+void Field_geom::get_key_image(char *buff,uint length, imagetype type)
+{
+ length-=HA_KEY_BLOB_LENGTH;
+ ulong blob_length=get_length(ptr);
+ char *blob;
+ get_ptr(&blob);
+ memcpy(buff+2,blob,length);
+
+ MBR mbr;
+ Geometry gobj;
+ gobj.create_from_wkb(blob,blob_length);
+ gobj.get_mbr(&mbr);
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ return;
+}
+
+void Field_geom::set_key_image(char *buff,uint length)
+{
}
+
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
char *blob1;
@@ -4259,7 +4539,7 @@ void Field_blob::sort_string(char *to,uint length)
if (blob_length > length)
blob_length=length;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
- if (binary_flag)
+ if (binary())
{
memcpy(to,blob,blob_length);
to+=blob_length;
@@ -4267,11 +4547,11 @@ void Field_blob::sort_string(char *to,uint length)
else
{
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (use_strnxfrm(field_charset))
{
- blob_length=my_strnxfrm(default_charset_info,
- (unsigned char *)to,(unsigned char *)blob,
- length,blob_org_length);
+ blob_length=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *)blob, blob_org_length);
if (blob_length >= length)
return;
to+=blob_length;
@@ -4279,7 +4559,7 @@ void Field_blob::sort_string(char *to,uint length)
else
#endif
for (char *end=blob+blob_length ; blob != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *blob++];
+ *to++=(char) field_charset->sort_order[(uint) (uchar) *blob++];
}
bzero(to,length-blob_length);
}
@@ -4295,8 +4575,13 @@ void Field_blob::sql_type(String &res) const
case 3: str="medium"; break;
case 4: str="long"; break;
}
- res.set(str,(uint) strlen(str));
- res.append(binary_flag ? "blob" : "text");
+ res.set(str,(uint) strlen(str),default_charset_info);
+ res.append(binary() ? "blob" : "text");
+ if (!binary())
+ {
+ res.append(" character set ");
+ res.append(field_charset->name);
+ }
}
@@ -4352,12 +4637,14 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
a_length= (uint) (uchar) *a++;
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
+ if (binary())
{
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
@@ -4378,12 +4665,14 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
{
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
+ if (binary())
{
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_strnncoll(field_charset,
+ (const uchar *)a,a_length,
+ (const uchar *)b,b_length);
}
/* Create a packed key that will be used for storage from a MySQL row */
@@ -4494,14 +4783,16 @@ void Field_enum::store_type(ulonglong value)
uint find_enum(TYPELIB *lib,const char *x, uint length)
{
const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ while (end > x && my_isspace(system_charset_info,end[-1]))
end--;
const char *i;
const char *j;
for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++)
{
- for (i=x ; i != end && toupper(*i) == toupper(*j) ; i++, j++) ;
+ for (i=x ; i != end &&
+ my_toupper(system_charset_info,*i) ==
+ my_toupper(system_charset_info,*j) ; i++, j++) ;
if (i == end && ! *j)
return(pos+1);
}
@@ -4514,8 +4805,9 @@ uint find_enum(TYPELIB *lib,const char *x, uint length)
** (if there isn't a empty value in the enum)
*/
-void Field_enum::store(const char *from,uint length)
+int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ int error= 0;
uint tmp=find_enum(typelib,from,length);
if (!tmp)
{
@@ -4535,29 +4827,34 @@ void Field_enum::store(const char *from,uint length)
{
tmp=0;
current_thd->cuted_fields++;
+ error=1;
}
}
else
current_thd->cuted_fields++;
}
store_type((ulonglong) tmp);
+ return error;
}
-void Field_enum::store(double nr)
+int Field_enum::store(double nr)
{
- Field_enum::store((longlong) nr);
+ return Field_enum::store((longlong) nr);
}
-void Field_enum::store(longlong nr)
+int Field_enum::store(longlong nr)
{
+ int error= 0;
if ((uint) nr > typelib->count || nr == 0)
{
current_thd->cuted_fields++;
nr=0;
+ error=1;
}
store_type((ulonglong) (uint) nr);
+ return error;
}
@@ -4620,7 +4917,8 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)),
val_ptr->length(0);
else
val_ptr->set((const char*) typelib->type_names[tmp-1],
- (uint) strlen(typelib->type_names[tmp-1]));
+ (uint) strlen(typelib->type_names[tmp-1]),
+ field_charset);
return val_ptr;
}
@@ -4657,12 +4955,19 @@ void Field_enum::sql_type(String &res) const
{
if (flag)
res.append(',');
- res.append('\'');
- append_unescaped(&res,*pos);
- res.append('\'');
+ append_unescaped(&res, *pos, strlen(*pos));
flag=1;
}
res.append(')');
+ if (binary())
+ {
+ res.append(" binary");
+ }
+ else
+ {
+ res.append(" character set ");
+ res.append(field_charset->name);
+ }
}
@@ -4678,14 +4983,14 @@ void Field_enum::sql_type(String &res) const
ulonglong find_set(TYPELIB *lib,const char *x,uint length)
{
const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ while (end > x && my_isspace(system_charset_info, end[-1]))
end--;
ulonglong found=0;
if (x != end)
{
const char *start=x;
- bool error=0;
+ bool error= 0;
for (;;)
{
const char *pos=start;
@@ -4706,8 +5011,9 @@ ulonglong find_set(TYPELIB *lib,const char *x,uint length)
}
-void Field_set::store(const char *from,uint length)
+int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
{
+ int error= 0;
ulonglong tmp=find_set(typelib,from,length);
if (!tmp && length && length < 22)
{
@@ -4723,23 +5029,30 @@ void Field_set::store(const char *from,uint length)
tmp=strtoull(conv,&end,10);
if (my_errno || end != conv+length ||
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
+ {
tmp=0;
+ error=1;
+ }
else
current_thd->cuted_fields--; // Remove warning from find_set
}
store_type(tmp);
+ return error;
}
-void Field_set::store(longlong nr)
+int Field_set::store(longlong nr)
{
+ int error= 0;
if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) -
(longlong) 1))
{
nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1);
current_thd->cuted_fields++;
+ error=1;
}
store_type((ulonglong) nr);
+ return error;
}
@@ -4757,7 +5070,8 @@ String *Field_set::val_str(String *val_buffer,
if (val_buffer->length())
val_buffer->append(field_separator);
String str(typelib->type_names[bitnr],
- (uint) strlen(typelib->type_names[bitnr]));
+ (uint) strlen(typelib->type_names[bitnr]),
+ field_charset);
val_buffer->append(str);
}
tmp>>=1;
@@ -4777,12 +5091,19 @@ void Field_set::sql_type(String &res) const
{
if (flag)
res.append(',');
- res.append('\'');
- append_unescaped(&res,*pos);
- res.append('\'');
+ append_unescaped(&res, *pos, strlen(*pos));
flag=1;
}
res.append(')');
+ if (binary())
+ {
+ res.append(" binary");
+ }
+ else
+ {
+ res.append(" character set ");
+ res.append(field_charset->name);
+ }
}
/* returns 1 if the fields are equally defined */
@@ -4804,7 +5125,8 @@ bool Field_enum::eq_def(Field *field)
if (typelib->count < from_lib->count)
return 0;
for (uint i=0 ; i < from_lib->count ; i++)
- if (my_strcasecmp(typelib->type_names[i],from_lib->type_names[i]))
+ if (my_strcasecmp(field_charset,
+ typelib->type_names[i],from_lib->type_names[i]))
return 0;
return 1;
}
@@ -4880,6 +5202,7 @@ Field *make_field(char *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
uint pack_flag,
enum_field_types field_type,
+ CHARSET_INFO *field_charset,
Field::utype unireg_check,
TYPELIB *interval,
const char *field_name,
@@ -4894,8 +5217,7 @@ Field *make_field(char *ptr, uint32 field_length,
{
if (!f_is_packed(pack_flag))
return new Field_string(ptr,field_length,null_pos,null_bit,
- unireg_check, field_name, table,
- f_is_binary(pack_flag) != 0);
+ unireg_check, field_name, table, field_charset);
uint pack_length=calc_pack_length((enum_field_types)
f_packtype(pack_flag),
@@ -4904,20 +5226,22 @@ Field *make_field(char *ptr, uint32 field_length,
if (f_is_blob(pack_flag))
return new Field_blob(ptr,null_pos,null_bit,
unireg_check, field_name, table,
- pack_length,f_is_binary(pack_flag) != 0);
+ pack_length, field_charset);
if (f_is_geom(pack_flag))
- return 0;
+ return new Field_geom(ptr,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_length);
if (interval)
{
if (f_is_enum(pack_flag))
return new Field_enum(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
- pack_length, interval);
+ pack_length, interval, field_charset);
else
return new Field_set(ptr,field_length,null_pos,null_bit,
unireg_check, field_name, table,
- pack_length, interval);
+ pack_length, interval, field_charset);
}
}
@@ -4973,22 +5297,22 @@ Field *make_field(char *ptr, uint32 field_length,
unireg_check, field_name, table);
case FIELD_TYPE_DATE:
return new Field_date(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NEWDATE:
return new Field_newdate(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_TIME:
return new Field_time(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_DATETIME:
return new Field_datetime(ptr,null_pos,null_bit,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_NULL:
- return new Field_null(ptr,field_length,unireg_check,field_name,table);
+ return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset);
default: // Impossible (Wrong version)
break;
}
- return 0; // Impossible
+ return 0;
}
@@ -5003,6 +5327,8 @@ create_field::create_field(Field *old_field,Field *orig_field)
unireg_check=old_field->unireg_check;
pack_length=old_field->pack_length();
sql_type= old_field->real_type();
+ charset= old_field->charset(); // May be NULL ptr
+ comment= old_field->comment;
/* Fix if the original table had 4 byte pointer blobs */
if (flags & BLOB_FLAG)
@@ -5011,6 +5337,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
decimals= old_field->decimals();
if (sql_type == FIELD_TYPE_STRING)
{
+ /* Change CHAR -> VARCHAR if dynamic record length */
sql_type=old_field->type();
decimals=0;
}
@@ -5024,7 +5351,8 @@ create_field::create_field(Field *old_field,Field *orig_field)
orig_field)
{
char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff));
+ CHARSET_INFO *field_charset= charset ? charset : default_charset_info;
+ String tmp(buff,sizeof(buff),field_charset);
/* Get the value from record[2] (the default value row) */
my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2);
@@ -5036,7 +5364,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
{
pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1);
pos[tmp.length()]=0;
- def=new Item_string(pos,tmp.length());
+ def=new Item_string(pos,tmp.length(),field_charset);
}
}
}
diff --git a/sql/field.h b/sql/field.h
index ba28a6a872e..8c4c48968c4 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -41,12 +41,16 @@ public:
uchar *null_ptr; // Byte where null_bit is
struct st_table *table; // Pointer for table
const char *table_name,*field_name;
+ LEX_STRING comment;
ulong query_id; // For quick test of used fields
/* Field is part of the following keys */
key_map key_start,part_of_key,part_of_sortkey;
enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
+
+ enum imagetype { itRAW, itMBR};
+
utype unireg_check;
uint32 field_length; // Length of field
uint16 flags;
@@ -56,9 +60,9 @@ public:
utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg);
virtual ~Field() {}
- virtual void store(const char *to,uint length)=0;
- virtual void store(double nr)=0;
- virtual void store(longlong nr)=0;
+ virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0;
+ virtual int store(double nr)=0;
+ virtual int store(longlong nr)=0;
virtual void store_time(TIME *ltime,timestamp_type t_type);
virtual double val_real(void)=0;
virtual longlong val_int(void)=0;
@@ -125,7 +129,7 @@ public:
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 | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+ tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | ENUM_FLAG | SET_FLAG);
tmp->reset_fields();
}
return tmp;
@@ -145,17 +149,12 @@ public:
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff,uint length)
+ virtual void get_key_image(char *buff,uint length, imagetype type)
{ get_image(buff,length); }
virtual void set_key_image(char *buff,uint length)
{ set_image(buff,length); }
inline int cmp_image(char *buff,uint length)
- {
- if (binary())
- return memcmp(ptr,buff,length);
- else
- return my_casecmp(ptr,buff,length);
- }
+ { return memcmp(ptr,buff,length); }
inline longlong val_int_offset(uint row_offset)
{
ptr+=row_offset;
@@ -199,6 +198,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) 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);
@@ -246,19 +247,32 @@ public:
class Field_str :public Field {
+protected:
+ CHARSET_INFO *field_charset;
public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg,CHARSET_INFO *charset)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
- {}
+ { field_charset=charset; }
Item_result result_type () const { return STRING_RESULT; }
uint decimals() const { return NOT_FIXED_DEC; }
- friend class create_field;
void make_field(Send_field *);
uint size_of() const { return sizeof(*this); }
+ CHARSET_INFO *charset(void) const { return field_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)
+ {
+ if (binary())
+ return memcmp(ptr,buff,length);
+ else
+ return my_strncasecmp(field_charset,ptr,buff,length);
+ }
+ friend class create_field;
};
@@ -277,9 +291,9 @@ public:
enum ha_base_keytype key_type() const
{ return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
void reset(void);
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -306,9 +320,9 @@ public:
enum_field_types type() const { return FIELD_TYPE_TINY;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=0; }
double val_real(void);
longlong val_int(void);
@@ -335,9 +349,9 @@ public:
enum_field_types type() const { return FIELD_TYPE_SHORT;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;}
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=0; }
double val_real(void);
longlong val_int(void);
@@ -364,9 +378,9 @@ public:
enum_field_types type() const { return FIELD_TYPE_INT24;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
double val_real(void);
longlong val_int(void);
@@ -398,9 +412,9 @@ public:
enum_field_types type() const { return FIELD_TYPE_LONG;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; }
double val_real(void);
longlong val_int(void);
@@ -434,9 +448,9 @@ public:
enum_field_types type() const { return FIELD_TYPE_LONGLONG;}
enum ha_base_keytype key_type() const
{ return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; }
double val_real(void);
longlong val_int(void);
@@ -462,9 +476,9 @@ public:
{}
enum_field_types type() const { return FIELD_TYPE_FLOAT;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { bzero(ptr,sizeof(float)); }
double val_real(void);
longlong val_int(void);
@@ -494,9 +508,9 @@ public:
{}
enum_field_types type() const { return FIELD_TYPE_DOUBLE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { bzero(ptr,sizeof(double)); }
double val_real(void);
longlong val_int(void);
@@ -515,14 +529,14 @@ class Field_null :public Field_str {
public:
Field_null(char *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, len_arg, null, 1,
- unireg_check_arg, field_name_arg, table_arg)
+ unireg_check_arg, field_name_arg, table_arg, cs)
{}
enum_field_types type() const { return FIELD_TYPE_NULL;}
- void store(const char *to, uint length) { null[0]=1; }
- void store(double nr) { null[0]=1; }
- void store(longlong nr) { null[0]=1; }
+ int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; }
+ int store(double nr) { null[0]=1; return 0; }
+ int store(longlong nr) { null[0]=1; return 0; }
void reset(void) {}
double val_real(void) { return 0.0;}
longlong val_int(void) { return 0;}
@@ -531,7 +545,7 @@ public:
int cmp(const char *a, const char *b) { return 0;}
void sort_string(char *buff, uint length) {}
uint32 pack_length() const { return 0; }
- void sql_type(String &str) const { str.set("null",4); }
+ void sql_type(String &str) const { str.set("null",4,my_thd_charset); }
uint size_of() const { return sizeof(*this); }
};
@@ -544,9 +558,9 @@ public:
enum Item_result result_type () const { return field_length == 8 || field_length == 14 ? INT_RESULT : STRING_RESULT; }
enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; }
double val_real(void);
longlong val_int(void);
@@ -588,9 +602,9 @@ public:
unireg_check_arg, field_name_arg, table_arg, 1, 1)
{}
enum_field_types type() const { return FIELD_TYPE_YEAR;}
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -602,20 +616,20 @@ class Field_date :public Field_str {
public:
Field_date(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
+ unireg_check_arg, field_name_arg, table_arg, cs)
{}
Field_date(bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg) {}
+ NONE, field_name_arg, table_arg, cs) {}
enum_field_types type() const { return FIELD_TYPE_DATE;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; }
enum Item_result cmp_type () const { return INT_RESULT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; }
double val_real(void);
longlong val_int(void);
@@ -632,17 +646,17 @@ class Field_newdate :public Field_str {
public:
Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
+ unireg_check_arg, field_name_arg, table_arg, cs)
{}
enum_field_types type() const { return FIELD_TYPE_DATE;}
enum_field_types real_type() const { return FIELD_TYPE_NEWDATE; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void store_time(TIME *ltime,timestamp_type type);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
double val_real(void);
@@ -663,20 +677,20 @@ class Field_time :public Field_str {
public:
Field_time(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
+ unireg_check_arg, field_name_arg, table_arg, cs)
{}
Field_time(bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,8, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg) {}
+ NONE, field_name_arg, table_arg, cs) {}
enum_field_types type() const { return FIELD_TYPE_TIME;}
enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; }
enum Item_result cmp_type () const { return INT_RESULT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; }
double val_real(void);
longlong val_int(void);
@@ -695,22 +709,22 @@ class Field_datetime :public Field_str {
public:
Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg)
+ unireg_check_arg, field_name_arg, table_arg, cs)
{}
Field_datetime(bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,19, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg) {}
+ NONE, field_name_arg, table_arg, cs) {}
enum_field_types type() const { return FIELD_TYPE_DATETIME;}
#ifdef HAVE_LONG_LONG
enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; }
#endif
enum Item_result cmp_type () const { return INT_RESULT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void store_time(TIME *ltime,timestamp_type type);
void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; }
double val_real(void);
@@ -728,28 +742,17 @@ public:
class Field_string :public Field_str {
- bool binary_flag;
public:
Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg,bool binary_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
- binary_flag(binary_arg)
- {
- if (binary_arg)
- flags|=BINARY_FLAG;
- }
+ unireg_check_arg, field_name_arg, table_arg,cs) {};
Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, bool binary_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg),
- binary_flag(binary_arg)
- {
- if (binary_arg)
- flags|=BINARY_FLAG;
- }
+ NONE, field_name_arg, table_arg, cs) {};
enum_field_types type() const
{
@@ -758,13 +761,12 @@ public:
FIELD_TYPE_VAR_STRING : FIELD_TYPE_STRING);
}
enum ha_base_keytype key_type() const
- { return binary_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
+ { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; }
bool zero_pack() const { return 0; }
- bool binary() const { return binary_flag; }
void reset(void) { bfill(ptr,field_length,' '); }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -783,40 +785,28 @@ public:
class Field_varstring :public Field_str {
- bool binary_flag;
public:
Field_varstring(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg,
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg,bool binary_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
- binary_flag(binary_arg)
- {
- if (binary_arg)
- flags|=BINARY_FLAG;
- }
+ unireg_check_arg, field_name_arg, table_arg, cs) {};
Field_varstring(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, bool binary_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg),
- binary_flag(binary_arg)
- {
- if (binary_arg)
- flags|=BINARY_FLAG;
- }
+ NONE, field_name_arg, table_arg, cs) {};
enum_field_types type() const { return FIELD_TYPE_VAR_STRING; }
enum ha_base_keytype key_type() const
- { return binary_flag ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
+ { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
bool zero_pack() const { return 0; }
- bool binary() const { return binary_flag; }
void reset(void) { bzero(ptr,field_length+2); }
uint32 pack_length() const { return (uint32) field_length+2; }
uint32 key_length() const { return (uint32) field_length; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -837,28 +827,26 @@ public:
class Field_blob :public Field_str {
uint packlength;
String value; // For temporaries
- bool binary_flag;
+ bool geom_flag;
public:
Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint blob_pack_length,
- bool binary_arg);
+ CHARSET_INFO *cs);
Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
- struct st_table *table_arg, bool binary_arg)
+ struct st_table *table_arg, CHARSET_INFO *cs)
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
- NONE, field_name_arg, table_arg),
- packlength(3),binary_flag(binary_arg)
+ NONE, field_name_arg, table_arg, cs),
+ packlength(3), geom_flag(true)
{
flags|= BLOB_FLAG;
- if (binary_arg)
- flags|=BINARY_FLAG;
}
enum_field_types type() const { return FIELD_TYPE_BLOB;}
enum ha_base_keytype key_type() const
- { return binary_flag ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; }
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
@@ -879,7 +867,6 @@ public:
inline uint32 get_length(uint row_offset=0)
{ return get_length(ptr+row_offset); }
uint32 get_length(const char *ptr);
- bool binary() const { return binary_flag; }
inline void get_ptr(char **str)
{
memcpy_fixed(str,ptr+packlength,sizeof(char*));
@@ -894,13 +881,13 @@ public:
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- void get_key_image(char *buff,uint length);
+ void get_key_image(char *buff,uint length, imagetype type);
void set_key_image(char *buff,uint length);
void sql_type(String &str) const;
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;
@@ -923,6 +910,24 @@ public:
};
+class Field_geom :public Field_blob {
+public:
+ Field_geom(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg,uint blob_pack_length)
+ :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, table_arg, blob_pack_length,my_charset_bin) {}
+ Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg)
+ :Field_blob(len_arg, maybe_null_arg, field_name_arg,
+ table_arg, my_charset_bin) {}
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY; }
+
+ void get_key_image(char *buff,uint length, imagetype type);
+ void set_key_image(char *buff,uint length);
+};
+
+
class Field_enum :public Field_str {
protected:
uint packlength;
@@ -932,9 +937,10 @@ public:
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint packlength_arg,
- TYPELIB *typelib_arg)
+ TYPELIB *typelib_arg,
+ CHARSET_INFO *charset_arg)
:Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
- unireg_check_arg, field_name_arg, table_arg),
+ unireg_check_arg, field_name_arg, table_arg, charset_arg),
packlength(packlength_arg),typelib(typelib_arg)
{
flags|=ENUM_FLAG;
@@ -942,9 +948,9 @@ public:
enum_field_types type() const { return FIELD_TYPE_STRING; }
enum Item_result cmp_type () const { return INT_RESULT; }
enum ha_base_keytype key_type() const;
- void store(const char *to,uint length);
- void store(double nr);
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr);
+ int store(longlong nr);
void reset() { bzero(ptr,packlength); }
double val_real(void);
longlong val_int(void);
@@ -958,7 +964,6 @@ public:
enum_field_types real_type() const { return FIELD_TYPE_ENUM; }
virtual bool zero_pack() const { return 0; }
bool optimize_range(uint idx) { return 0; }
- bool binary() const { return 0; }
bool eq_def(Field *field);
};
@@ -969,17 +974,17 @@ public:
uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
struct st_table *table_arg,uint32 packlength_arg,
- TYPELIB *typelib_arg)
+ TYPELIB *typelib_arg, CHARSET_INFO *charset_arg)
:Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg,
table_arg, packlength_arg,
- typelib_arg)
+ typelib_arg,charset_arg)
{
flags=(flags & ~ENUM_FLAG) | SET_FLAG;
}
- void store(const char *to,uint length);
- void store(double nr) { Field_set::store((longlong) nr); }
- void store(longlong nr);
+ int store(const char *to,uint length,CHARSET_INFO *charset);
+ int store(double nr) { return Field_set::store((longlong) nr); }
+ int store(longlong nr);
virtual bool zero_pack() const { return 1; }
String *val_str(String*,String *);
void sql_type(String &str) const;
@@ -996,12 +1001,14 @@ public:
const char *field_name;
const char *change; // If done with alter table
const char *after; // Put column after this one
+ LEX_STRING comment; // Comment for field
Item *def; // Default value
enum enum_field_types sql_type;
uint32 length;
uint decimals,flags,pack_length;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
+ CHARSET_INFO *charset;
Field *field; // For alter table
uint8 row,col,sc_length,interval_id; // For rea_create_table
@@ -1017,7 +1024,9 @@ public:
class Send_field {
public:
- const char *table_name,*col_name;
+ const char *db_name;
+ const char *table_name,*org_table_name;
+ const char *col_name,*org_col_name;
uint length,flags,decimals;
enum_field_types type;
Send_field() {}
@@ -1050,8 +1059,8 @@ public:
Field *make_field(char *ptr, uint32 field_length,
uchar *null_pos, uchar null_bit,
- uint pack_flag,
- enum_field_types field_type,
+ uint pack_flag, enum_field_types field_type,
+ CHARSET_INFO *cs,
Field::utype unireg_check,
TYPELIB *interval, const char *field_name,
struct st_table *table);
@@ -1076,6 +1085,7 @@ bool test_if_int(const char *str,int length);
#define FIELDFLAG_BITFIELD 512 // mangled with dec!
#define FIELDFLAG_BLOB 1024 // mangled with dec!
#define FIELDFLAG_GEOM 2048
+
#define FIELDFLAG_LEFT_FULLSCREEN 8192
#define FIELDFLAG_RIGHT_FULLSCREEN 16384
#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
@@ -1098,7 +1108,6 @@ bool test_if_int(const char *str,int length);
#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15)
#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC))
#define f_is_alpha(x) (!f_is_num(x))
-#define f_is_binary(x) ((x) & FIELDFLAG_BINARY)
#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
#define f_is_bitfield(x) ((x) & FIELDFLAG_BITFIELD)
#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 53b26920c14..ab71f324732 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -245,7 +245,7 @@ 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());
+ copy->tmp.length(),default_charset_info);
}
/* Save blob in copy->tmp for GROUP BY */
@@ -253,20 +253,20 @@ static void do_conv_blob(Copy_field *copy)
static void do_save_blob(Copy_field *copy)
{
char buff[MAX_FIELD_WIDTH];
- String res(buff,sizeof(buff));
+ String res(buff,sizeof(buff),default_charset_info);
copy->from_field->val_str(&res,&res);
copy->tmp.copy(res);
((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
- copy->tmp.length());
+ copy->tmp.length(),default_charset_info);
}
static void do_field_string(Copy_field *copy)
{
char buff[MAX_FIELD_WIDTH];
- copy->tmp.set_quick(buff,sizeof(buff));
+ 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());
+ copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),default_charset_info);
}
@@ -293,7 +293,7 @@ static void do_cut_string(Copy_field *copy)
ptr != end ;
ptr++)
{
- if (!isspace(*ptr))
+ if (!my_isspace(system_charset_info, *ptr))
{
current_thd->cuted_fields++; // Give a warning
break;
@@ -525,7 +525,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());
+ blob->store(blob->value.ptr(),blob->value.length(),to->charset());
return;
}
if ((from->result_type() == STRING_RESULT &&
@@ -535,9 +535,10 @@ void field_conv(Field *to,Field *from)
to->type() == FIELD_TYPE_DECIMAL)
{
char buff[MAX_FIELD_WIDTH];
- String result(buff,sizeof(buff));
+ String result(buff,sizeof(buff),default_charset_info);
from->val_str(&result,&result);
- to->store(result.c_ptr_quick(),result.length());
+ 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)
to->store(from->val_real());
diff --git a/sql/filesort.cc b/sql/filesort.cc
index ad16c16db3e..fab666a1203 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -63,26 +63,31 @@ static uint sortlength(SORT_FIELD *sortorder,uint length);
table->record_pointers
*/
-ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
- SQL_SELECT *select, ha_rows special, ha_rows max_rows,
- ha_rows *examined_rows)
+ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
+ SQL_SELECT *select, ha_rows max_rows, ha_rows *examined_rows)
{
int error;
ulong memavl;
uint maxbuffer;
+ uint i;
BUFFPEK *buffpek;
ha_rows records;
uchar **sort_keys;
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
SORTPARAM param;
- THD *thd= current_thd;
-
+ CHARSET_INFO *charset=my_charset_bin;
DBUG_ENTER("filesort");
- DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length,special););
+ DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length););
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_PUSH(""); /* No DBUG here */
#endif
+ // BAR TODO: this is not absolutely correct, but OK for now
+ for(i=0;i<table->fields;i++)
+ if (!table->field[i]->binary())
+ charset=table->field[i]->charset();
+ // /BAR TODO
+
outfile= table->io_cache;
my_b_clear(&tempfile);
my_b_clear(&buffpek_pointers);
@@ -102,27 +107,15 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
{
statistic_increment(filesort_scan_count, &LOCK_status);
}
- if (select && my_b_inited(&select->file))
- {
- records=special=select->records; /* purecov: deadcode */
- selected_records_file= &select->file; /* purecov: deadcode */
- reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */
- }
- else if (special)
- {
- records=special; /* purecov: deadcode */
- selected_records_file= outfile; /* purecov: deadcode */
- reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */
- }
#ifdef CAN_TRUST_RANGE
- else if (select && select->quick && select->quick->records > 0L)
+ if (select && select->quick && select->quick->records > 0L)
{
records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2),
table->file->records)+EXTRA_RECORDS;
selected_records_file=0;
}
-#endif
else
+#endif
{
records=table->file->estimate_number_of_rows();
selected_records_file= 0;
@@ -131,7 +124,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
records=param.max_rows; /* purecov: inspected */
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info) &&
+ if (use_strnxfrm(charset) &&
!(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME))))
goto err;
#endif
@@ -208,7 +201,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
err:
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (param.tmp_buffer)
x_free(param.tmp_buffer);
#endif
x_free((gptr) sort_keys);
@@ -479,7 +472,7 @@ static void make_sortkey(register SORTPARAM *param,
if (item->maybe_null)
*to++=1;
/* All item->str() to use some extra byte for end null.. */
- String tmp((char*) to,sort_field->length+4);
+ String tmp((char*) to,sort_field->length+4,default_charset_info);
String *res=item->val_str(&tmp);
if (!res)
{
@@ -494,6 +487,7 @@ static void make_sortkey(register SORTPARAM *param,
break;
}
length=res->length();
+ CHARSET_INFO *cs=res->charset();
int diff=(int) (sort_field->length-length);
if (diff < 0)
{
@@ -501,9 +495,9 @@ static void make_sortkey(register SORTPARAM *param,
length=sort_field->length;
}
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if(use_strnxfrm(cs))
{
- if (item->binary)
+ if (item->binary())
{
if (res->ptr() != (char*) to)
memcpy(to,res->ptr(),length);
@@ -518,10 +512,8 @@ static void make_sortkey(register SORTPARAM *param,
memcpy(param->tmp_buffer,from,length);
from=param->tmp_buffer;
}
- uint tmp_length=my_strnxfrm(default_charset_info,
- to,(unsigned char *) from,
- sort_field->length,
- length);
+ uint tmp_length=my_strnxfrm(cs,to,sort_field->length,
+ (unsigned char *) from, length);
if (tmp_length < sort_field->length)
bzero((char*) to+tmp_length,sort_field->length-tmp_length);
}
@@ -532,8 +524,8 @@ static void make_sortkey(register SORTPARAM *param,
if (res->ptr() != (char*) to)
memcpy(to,res->ptr(),length);
bzero((char *)to+length,diff);
- if (!item->binary)
- case_sort((char*) to,length);
+ if (!item->binary())
+ my_tosort(cs, (char*) to,length);
#ifdef USE_STRCOLL
}
#endif
@@ -935,8 +927,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
{
sortorder->length=sortorder->field->pack_length();
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info) && !sortorder->field->binary())
- sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
+ if (!sortorder->field->binary())
+ {
+ CHARSET_INFO *cs=sortorder->field->charset();
+ if (use_strnxfrm(cs))
+ sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ }
#endif
}
if (sortorder->field->maybe_null())
@@ -944,12 +940,19 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
}
else
{
+#ifdef USE_STRCOLL
+
+#endif
switch ((sortorder->result_type=sortorder->item->result_type())) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info) && !sortorder->item->binary)
- sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
+ if (!sortorder->item->binary())
+ {
+ CHARSET_INFO *cs=sortorder->item->charset();
+ if (use_strnxfrm(cs))
+ sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ }
#endif
break;
case INT_RESULT:
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 8139cf4fdb0..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 8000 // 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);
}
-
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/gstream.cc b/sql/gstream.cc
new file mode 100644
index 00000000000..bd2345212c3
--- /dev/null
+++ b/sql/gstream.cc
@@ -0,0 +1,137 @@
+#include "mysql_priv.h"
+
+int GTextReadStream::get_next_toc_type() const
+{
+ const char *cur = m_cur;
+ while((*cur)&&(strchr(" \t\r\n",*cur)))
+ {
+ cur++;
+ }
+ if(!(*cur))
+ {
+ return eostream;
+ }
+
+ if(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_'))
+ {
+ return word;
+ }
+
+ if(((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || (*cur=='.'))
+ {
+ return numeric;
+ }
+
+ if(*cur == '(')
+ {
+ return l_bra;
+ }
+
+ if(*cur == ')')
+ {
+ return r_bra;
+ }
+
+ if(*cur == ',')
+ {
+ return comma;
+ }
+
+ return unknown;
+}
+
+const char *GTextReadStream::get_next_word(int *word_len)
+{
+ const char *cur = m_cur;
+ while((*cur)&&(strchr(" \t\r\n",*cur)))
+ {
+ cur++;
+ }
+ m_last_text_position = cur;
+
+ if(!(*cur))
+ {
+ return 0;
+ }
+
+ const char *wd_start = cur;
+
+ if(((*cur<'a') || (*cur>'z')) && ((*cur<'A') || (*cur>'Z')) && (*cur!='_'))
+ {
+ return NULL;
+ }
+
+ ++cur;
+
+ while(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_') ||
+ ((*cur>='0') && (*cur<='9')))
+ {
+ ++cur;
+ }
+
+ *word_len = cur - wd_start;
+
+ m_cur = cur;
+
+ return wd_start;
+}
+
+int GTextReadStream::get_next_number(double *d)
+{
+ const char *cur = m_cur;
+ while((*cur)&&(strchr(" \t\r\n",*cur)))
+ {
+ cur++;
+ }
+
+ m_last_text_position = cur;
+ if(!(*cur))
+ {
+ set_error_msg("Numeric constant expected");
+ return 1;
+ }
+
+ if(((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.'))
+ {
+ set_error_msg("Numeric constant expected");
+ return 1;
+ }
+
+ char *endptr;
+
+ *d = my_strtod(my_charset_latin1, cur, &endptr);
+
+ if(endptr)
+ {
+ m_cur = endptr;
+ }
+
+ return 0;
+}
+
+char GTextReadStream::get_next_symbol()
+{
+ const char *cur = m_cur;
+ while((*cur)&&(strchr(" \t\r\n",*cur)))
+ {
+ cur++;
+ }
+ if(!(*cur))
+ {
+ return 0;
+ }
+
+ m_cur = cur + 1;
+ m_last_text_position = cur;
+
+ return *cur;
+}
+
+void GTextReadStream::set_error_msg(const char *msg)
+{
+ size_t len = strlen(msg);
+ m_err_msg = (char *)my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR));
+ memcpy(m_err_msg, msg, len + 1);
+}
+
+
diff --git a/sql/gstream.h b/sql/gstream.h
new file mode 100644
index 00000000000..f26ef8899f8
--- /dev/null
+++ b/sql/gstream.h
@@ -0,0 +1,69 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ 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 GTextReadStream
+{
+public:
+ enum TokTypes
+ {
+ unknown,
+ eostream,
+ word,
+ numeric,
+ l_bra,
+ r_bra,
+ comma,
+ };
+
+ GTextReadStream(const char *buffer, int size)
+ :m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer),
+ m_err_msg(NULL)
+ {}
+ GTextReadStream(): m_cur(NULL), m_limit(NULL), m_err_msg(NULL)
+ {}
+
+ ~GTextReadStream()
+ {
+ my_free(m_err_msg, MYF(MY_ALLOW_ZERO_PTR));
+ }
+
+ int get_next_toc_type() const;
+ const char *get_next_word(int *word_len);
+ int get_next_number(double *d);
+ char get_next_symbol();
+
+ const char *get_last_text_position() const
+ {
+ return m_last_text_position;
+ }
+
+ void set_error_msg(const char *msg);
+
+ // caller should free this pointer
+ char *get_error_msg()
+ {
+ char *err_msg = m_err_msg;
+ m_err_msg = NULL;
+ return err_msg;
+ }
+
+protected:
+ const char *m_cur;
+ const char *m_limit;
+ const char *m_last_text_position;
+ char *m_err_msg;
+};
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 06acf4fa2e3..679642ca949 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -168,7 +168,7 @@ bool berkeley_init(void)
db_env=0; /* purecov: inspected */
}
- (void) hash_init(&bdb_open_tables,32,0,0,
+ (void) hash_init(&bdb_open_tables,system_charset_info,32,0,0,
(hash_get_key) bdb_get_key,0,0);
pthread_mutex_init(&bdb_mutex,MY_MUTEX_INIT_FAST);
DBUG_RETURN(db_env == 0);
@@ -194,12 +194,12 @@ bool berkeley_flush_logs()
int error;
bool result=0;
DBUG_ENTER("berkeley_flush_logs");
- if ((error=log_flush(db_env,0)))
+ if ((error=db_env->log_flush(db_env,0)))
{
my_error(ER_ERROR_DURING_FLUSH_LOGS,MYF(0),error); /* purecov: inspected */
result=1; /* purecov: inspected */
}
- if ((error=txn_checkpoint(db_env,0,0,0)))
+ if ((error=db_env->txn_checkpoint(db_env,0,0,0)))
{
my_error(ER_ERROR_DURING_CHECKPOINT,MYF(0),error); /* purecov: inspected */
result=1; /* purecov: inspected */
@@ -243,10 +243,8 @@ int berkeley_show_logs(THD *thd)
init_alloc_root(&show_logs_root, 1024, 1024);
my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root);
- if ((error= log_archive(db_env, &all_logs, DB_ARCH_ABS | DB_ARCH_LOG,
- (void* (*)(size_t)) sql_alloc)) ||
- (error= log_archive(db_env, &free_logs, DB_ARCH_ABS,
- (void* (*)(size_t)) sql_alloc)))
+ if ((error= db_env->log_archive(db_env, &all_logs, DB_ARCH_ABS | DB_ARCH_LOG))
+ || (error= db_env->log_archive(db_env, &free_logs, DB_ARCH_ABS)))
{
DBUG_PRINT("error", ("log_archive failed (error %d)", error));
db_env->err(db_env, error, "log_archive: DB_ARCH_ABS");
@@ -309,10 +307,10 @@ void berkeley_cleanup_log_files(void)
/* XXX: Probably this should be done somewhere else, and
* should be tunable by the user. */
- if ((error = txn_checkpoint(db_env, 0, 0, 0)))
+ if ((error = db_env->txn_checkpoint(db_env, 0, 0, 0)))
my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error); /* purecov: inspected */
- if ((error = log_archive(db_env, &names, DB_ARCH_ABS, NULL)) != 0)
+ if ((error = db_env->log_archive(db_env, &names, DB_ARCH_ABS)) != 0)
{
DBUG_PRINT("error", ("log_archive failed (error %d)", error)); /* purecov: inspected */
db_env->err(db_env, error, "log_archive: DB_ARCH_ABS"); /* purecov: inspected */
@@ -512,9 +510,11 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
berkeley_cmp_packed_key));
if (!hidden_primary_key)
file->app_private= (void*) (table->key_info+table->primary_key);
- if ((error=(file->open(file, fn_format(name_buff,name,"", ha_berkeley_ext,
- 2 | 4),
- "main", DB_BTREE, open_mode,0))))
+ if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
+ (error= (file->open(file, transaction,
+ fn_format(name_buff, name, "", ha_berkeley_ext, 2 | 4),
+ "main", DB_BTREE, open_mode, 0))) ||
+ (error= transaction->commit(transaction, 0)))
{
free_share(share,table, hidden_primary_key,1); /* purecov: inspected */
my_free((char*) rec_buff,MYF(0)); /* purecov: inspected */
@@ -545,8 +545,10 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked)
(*ptr)->app_private= (void*) (table->key_info+i);
if (!(table->key_info[i].flags & HA_NOSAME))
(*ptr)->set_flags(*ptr, DB_DUP);
- if ((error=((*ptr)->open(*ptr, name_buff, part, DB_BTREE,
- open_mode, 0))))
+ if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) ||
+ (error=((*ptr)->open(*ptr, transaction, name_buff, part, DB_BTREE,
+ open_mode, 0))) ||
+ (error= transaction->commit(transaction, 0)))
{
close(); /* purecov: inspected */
my_errno=error; /* purecov: inspected */
@@ -1836,7 +1838,7 @@ static int create_sub_table(const char *table_name, const char *sub_name,
if (!(error=db_create(&file, db_env, 0)))
{
file->set_flags(file, flags);
- error=(file->open(file, table_name, sub_name, type,
+ error=(file->open(file, NULL, table_name, sub_name, type,
DB_THREAD | DB_CREATE, my_umask));
if (error)
{
@@ -1892,7 +1894,7 @@ int ha_berkeley::create(const char *name, register TABLE *form,
DB *status_block;
if (!db_create(&status_block, db_env, 0))
{
- if (!status_block->open(status_block, name_buff,
+ if (!status_block->open(status_block, NULL, name_buff,
"status", DB_BTREE, DB_CREATE, 0))
{
char rec_buff[4+MAX_KEY*4];
@@ -2080,7 +2082,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
free(stat);
stat=0;
}
- if (key_file[i]->stat(key_file[i], (void*) &stat, 0, 0))
+ if (key_file[i]->stat(key_file[i], (void*) &stat, 0))
goto err; /* purecov: inspected */
share->rec_per_key[i]= (stat->bt_ndata /
(stat->bt_nkeys ? stat->bt_nkeys : 1));
@@ -2093,7 +2095,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
free(stat);
stat=0;
}
- if (file->stat(file, (void*) &stat, 0, 0))
+ if (file->stat(file, (void*) &stat, 0))
goto err; /* purecov: inspected */
}
pthread_mutex_lock(&share->mutex);
@@ -2296,7 +2298,7 @@ void ha_berkeley::get_status()
fn_format(name_buff, share->table_name,"", ha_berkeley_ext, 2 | 4);
if (!db_create(&share->status_block, db_env, 0))
{
- if (share->status_block->open(share->status_block, name_buff,
+ if (share->status_block->open(share->status_block, NULL, name_buff,
"status", DB_BTREE, open_mode, 0))
{
share->status_block->close(share->status_block, 0); /* purecov: inspected */
@@ -2372,7 +2374,7 @@ static void update_status(BDB_SHARE *share, TABLE *table)
if (db_create(&share->status_block, db_env, 0)) /* purecov: inspected */
goto end; /* purecov: inspected */
share->status_block->set_flags(share->status_block,0); /* purecov: inspected */
- if (share->status_block->open(share->status_block,
+ if (share->status_block->open(share->status_block, NULL,
fn_format(name_buff,share->table_name,"",
ha_berkeley_ext,2 | 4),
"status", DB_BTREE,
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 2edc3b1478e..4a3b9495f6f 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -33,69 +33,14 @@ const char **ha_heap::bas_ext() const
int ha_heap::open(const char *name, int mode, uint test_if_locked)
{
- uint key,parts,mem_per_row=0;
- ulong max_rows;
- HP_KEYDEF *keydef;
- HP_KEYSEG *seg;
- THD *thd= current_thd;
-
- for (key=parts=0 ; key < table->keys ; key++)
- parts+=table->key_info[key].key_parts;
-
- if (!(keydef=(HP_KEYDEF*) my_malloc(table->keys*sizeof(HP_KEYDEF)+
- parts*sizeof(HP_KEYSEG),MYF(MY_WME))))
- return my_errno;
- seg=my_reinterpret_cast(HP_KEYSEG*) (keydef+table->keys);
- for (key=0 ; key < table->keys ; key++)
+ if (!(file= heap_open(name, mode)) && my_errno == ENOENT)
{
- KEY *pos=table->key_info+key;
- KEY_PART_INFO *key_part= pos->key_part;
- KEY_PART_INFO *key_part_end= key_part+pos->key_parts;
-
- mem_per_row += (pos->key_length + (sizeof(char*) * 2));
-
- keydef[key].keysegs=(uint) pos->key_parts;
- keydef[key].flag = (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
- keydef[key].seg=seg;
-
- for (; key_part != key_part_end ; key_part++, seg++)
- {
- uint flag=key_part->key_type;
- Field *field=key_part->field;
- if (!f_is_packed(flag) &&
- f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
- !(flag & FIELDFLAG_BINARY))
- seg->type= (int) HA_KEYTYPE_TEXT;
- else
- seg->type= (int) HA_KEYTYPE_BINARY;
- seg->start=(uint) key_part->offset;
- seg->length=(uint) key_part->length;
- if (field->null_ptr)
- {
- seg->null_bit=field->null_bit;
- seg->null_pos= (uint) (field->null_ptr-
- (uchar*) table->record[0]);
- }
- else
- {
- seg->null_bit=0;
- seg->null_pos=0;
- }
- }
+ HA_CREATE_INFO create_info;
+ bzero(&create_info, sizeof(create_info));
+ if (!create(name, table, &create_info))
+ file= heap_open(name, mode);
}
- mem_per_row += MY_ALIGN(table->reclength+1, sizeof(char*));
- max_rows = (ulong) (thd->variables.max_heap_table_size / mem_per_row);
- file=heap_open(name,mode,
- table->keys,keydef,
- table->reclength,
- (ulong) ((table->max_rows < max_rows && table->max_rows) ?
- table->max_rows : max_rows),
- (ulong) table->min_rows);
- my_free((gptr) keydef,MYF(0));
- if (file)
- info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE);
- ref_length=sizeof(HEAP_PTR);
- return (!file ? errno : 0);
+ return (file ? 0 : 1);
}
int ha_heap::close(void)
@@ -108,6 +53,8 @@ int ha_heap::write_row(byte * buf)
statistic_increment(ha_write_count,&LOCK_status);
if (table->time_stamp)
update_timestamp(buf+table->time_stamp-1);
+ if (table->next_number_field && buf == table->record[0])
+ update_auto_increment();
return heap_write(file,buf);
}
@@ -125,25 +72,21 @@ int ha_heap::delete_row(const byte * buf)
return heap_delete(file,buf);
}
-int ha_heap::index_read(byte * buf, const byte * key,
- uint key_len __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
+int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
+ enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
- int error=heap_rkey(file,buf,active_index, key);
- table->status=error ? STATUS_NOT_FOUND: 0;
+ statistic_increment(ha_read_key_count, &LOCK_status);
+ int error = heap_rkey(file,buf,active_index, key, key_len, find_flag);
+ 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 __attribute__((unused)),
- enum ha_rkey_function find_flag
- __attribute__((unused)))
+ uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
- int error=heap_rkey(file, buf, index, key);
- table->status=error ? STATUS_NOT_FOUND: 0;
+ statistic_increment(ha_read_key_count, &LOCK_status);
+ int error = heap_rkey(file, buf, index, key, key_len, find_flag);
+ table->status = error ? STATUS_NOT_FOUND : 0;
return error;
}
@@ -167,7 +110,7 @@ int ha_heap::index_prev(byte * buf)
int ha_heap::index_first(byte * buf)
{
statistic_increment(ha_read_first_count,&LOCK_status);
- int error=heap_rfirst(file, buf);
+ int error=heap_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -175,7 +118,7 @@ int ha_heap::index_first(byte * buf)
int ha_heap::index_last(byte * buf)
{
statistic_increment(ha_read_last_count,&LOCK_status);
- int error=heap_rlast(file, buf);
+ int error=heap_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -222,6 +165,8 @@ void ha_heap::info(uint flag)
index_file_length=info.index_length;
max_data_file_length= info.max_records* info.reclength;
delete_length= info.deleted * info.reclength;
+ if (flag & HA_STATUS_AUTO)
+ auto_increment_value= info.auto_increment;
}
int ha_heap::extra(enum ha_extra_function operation)
@@ -255,7 +200,6 @@ THR_LOCK_DATA **ha_heap::store_lock(THD *thd,
return to;
}
-
/*
We have to ignore ENOENT entries as the HEAP table is created on open and
not when doing a CREATE on the table.
@@ -272,7 +216,6 @@ int ha_heap::rename_table(const char * from, const char * to)
return heap_rename(from,to);
}
-
ha_rows ha_heap::records_in_range(int inx,
const byte *start_key,uint start_key_len,
enum ha_rkey_function start_search_flag,
@@ -280,18 +223,121 @@ ha_rows ha_heap::records_in_range(int inx,
enum ha_rkey_function end_search_flag)
{
KEY *pos=table->key_info+inx;
- if (start_key_len != end_key_len ||
- start_key_len != pos->key_length ||
- start_search_flag != HA_READ_KEY_EXACT ||
- end_search_flag != HA_READ_AFTER_KEY)
- return HA_POS_ERROR; // Can't only use exact keys
- return 10; // Good guess
+ if (pos->algorithm == HA_KEY_ALG_BTREE)
+ {
+ return hp_rb_records_in_range(file, inx, start_key, start_key_len,
+ start_search_flag, end_key, end_key_len,
+ end_search_flag);
+ }
+ else
+ {
+ if (start_key_len != end_key_len ||
+ start_key_len != pos->key_length ||
+ start_search_flag != HA_READ_KEY_EXACT ||
+ end_search_flag != HA_READ_AFTER_KEY)
+ return HA_POS_ERROR; // Can't only use exact keys
+ return 10; // Good guess
+ }
}
+int ha_heap::create(const char *name, TABLE *table,
+ HA_CREATE_INFO *create_info)
+{
+ uint key, parts, mem_per_row= 0;
+ uint auto_key= 0, auto_key_type= 0;
+ ha_rows max_rows;
+ HP_KEYDEF *keydef;
+ HA_KEYSEG *seg;
+ char buff[FN_REFLEN];
+ int error;
+
+ for (key= parts= 0; key < table->keys; key++)
+ parts+= table->key_info[key].key_parts;
+
+ if (!(keydef= (HP_KEYDEF*) my_malloc(table->keys * sizeof(HP_KEYDEF) +
+ parts * sizeof(HA_KEYSEG),
+ MYF(MY_WME))))
+ return my_errno;
+ seg= my_reinterpret_cast(HA_KEYSEG*) (keydef + table->keys);
+ for (key= 0; key < table->keys; key++)
+ {
+ KEY *pos= table->key_info+key;
+ KEY_PART_INFO *key_part= pos->key_part;
+ KEY_PART_INFO *key_part_end= key_part + pos->key_parts;
-int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info)
+ mem_per_row+= (pos->key_length + (sizeof(char*) * 2));
+ keydef[key].keysegs= (uint) pos->key_parts;
+ keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL));
+ keydef[key].seg= seg;
+ keydef[key].algorithm= ((pos->algorithm == HA_KEY_ALG_UNDEF) ?
+ HA_KEY_ALG_HASH : pos->algorithm);
+
+ for (; key_part != key_part_end; key_part++, seg++)
+ {
+ uint flag= key_part->key_type;
+ Field *field= key_part->field;
+ if (pos->algorithm == HA_KEY_ALG_BTREE)
+ seg->type= field->key_type();
+ else
+ {
+ if (!f_is_packed(flag) &&
+ f_packtype(flag) == (int) FIELD_TYPE_DECIMAL &&
+ !(flag & FIELDFLAG_BINARY))
+ seg->type= (int) HA_KEYTYPE_TEXT;
+ else
+ seg->type= (int) HA_KEYTYPE_BINARY;
+ }
+ seg->start= (uint) key_part->offset;
+ seg->length= (uint) key_part->length;
+ seg->flag = 0;
+ seg->charset= field->charset();
+ if (field->null_ptr)
+ {
+ seg->null_bit= field->null_bit;
+ seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]);
+ }
+ else
+ {
+ seg->null_bit= 0;
+ seg->null_pos= 0;
+ }
+ if (field->flags & AUTO_INCREMENT_FLAG)
+ {
+ auto_key= key + 1;
+ auto_key_type= field->key_type();
+ }
+ }
+ }
+ mem_per_row+= MY_ALIGN(table->reclength + 1, sizeof(char*));
+ 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;
+ hp_create_info.auto_increment= (create_info->auto_increment_value ?
+ create_info->auto_increment_value - 1 : 0);
+ error= heap_create(fn_format(buff,name,"","",4+2),
+ table->keys,keydef, table->reclength,
+ (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);
+ ref_length= sizeof(HEAP_PTR);
+ return (error);
+}
+
+void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
{
- char buff[FN_REFLEN];
- return heap_create(fn_format(buff,name,"","",4+2));
+ table->file->info(HA_STATUS_AUTO);
+ if (!(create_info->used_fields & HA_CREATE_USED_AUTO))
+ create_info->auto_increment_value= auto_increment_value;
+}
+
+longlong ha_heap::get_auto_increment()
+{
+ ha_heap::info(HA_STATUS_AUTO);
+ return auto_increment_value;
}
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 504f5262bf3..f82a1a460d8 100644
--- a/sql/ha_heap.h
+++ b/sql/ha_heap.h
@@ -40,8 +40,7 @@ class ha_heap: public handler
ulong table_flags() const
{
return (HA_READ_RND_SAME | HA_NO_INDEX | HA_KEYPOS_TO_RNDPOS |
- HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ |
- HA_NO_AUTO_INCREMENT);
+ HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ);
}
ulong index_flags(uint inx) const
{
@@ -63,6 +62,7 @@ class ha_heap: public handler
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
+ longlong get_auto_increment();
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
@@ -87,6 +87,7 @@ class ha_heap: public handler
int delete_table(const char *from);
int rename_table(const char * from, const char * to);
int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+ void update_create_info(HA_CREATE_INFO *create_info);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 95bf8e8eb75..7787b543f34 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -765,9 +765,8 @@ innobase_init(void)
DBUG_RETURN(1);
}
-
- (void) hash_init(&innobase_open_tables,32,0,0,
- (hash_get_key) innobase_get_key,0,0);
+ (void) hash_init(&innobase_open_tables,system_charset_info,32,0,0,
+ (hash_get_key) innobase_get_key,0,0);
pthread_mutex_init(&innobase_mutex,MY_MUTEX_INIT_FAST);
/* If this is a replication slave and we needed to do a crash recovery,
@@ -1384,8 +1383,11 @@ innobase_mysql_cmp(
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
- ret = my_sortncmp((const char*) a, a_length,
- (const char*) b, b_length);
+ // BAR TODO: Discuss with heikki.tuuri@innodb.com
+ // so that he sends CHARSET_INFO for the field to this function.
+ ret = my_strnncoll(default_charset_info,
+ a, a_length,
+ b, b_length);
if (ret < 0) {
return(-1);
} else if (ret > 0) {
@@ -1421,7 +1423,7 @@ get_innobase_type_from_mysql_type(
DBUG_ASSERT((ulint)FIELD_TYPE_DECIMAL < 256);
switch (field->type()) {
- case FIELD_TYPE_VAR_STRING: if (field->flags & BINARY_FLAG) {
+ case FIELD_TYPE_VAR_STRING: if (field->binary()) {
return(DATA_BINARY);
} else if (strcmp(
@@ -1431,7 +1433,7 @@ get_innobase_type_from_mysql_type(
} else {
return(DATA_VARMYSQL);
}
- case FIELD_TYPE_STRING: if (field->flags & BINARY_FLAG) {
+ case FIELD_TYPE_STRING: if (field->binary()) {
return(DATA_FIXBINARY);
} else if (strcmp(
@@ -3210,8 +3212,8 @@ innobase_drop_database(
memcpy(namebuf, ptr, len);
namebuf[len] = '/';
namebuf[len + 1] = '\0';
-#ifdef __WIN__
- casedn_str(namebuf);
+#ifdef FN_NO_CASE_SENCE
+ my_casedn_str(system_charset_info, namebuf);
#endif
trx = trx_allocate_for_mysql();
@@ -3937,7 +3939,7 @@ innodb_show_status(
ut_free(buf);
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 0c472ea6a45..ae71e362875 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -28,6 +28,7 @@
#include "../srclib/myisam/myisamdef.h"
#else
#include "../myisam/myisamdef.h"
+#include "../myisam/rt_index.h"
#endif
ulong myisam_recover_options= HA_RECOVER_NONE;
@@ -86,6 +87,11 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
extern "C" {
+volatile bool *killed_ptr(MI_CHECK *param)
+{
+ return &(((THD *)(param->thd))->killed);
+}
+
void mi_check_print_error(MI_CHECK *param, const char *fmt,...)
{
param->error_printed|=1;
@@ -122,8 +128,12 @@ const char **ha_myisam::bas_ext() const
const char *ha_myisam::index_type(uint key_number)
{
- return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
+ return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
"FULLTEXT" :
+ (table->key_info[key_number].flags & HA_SPATIAL) ?
+ "SPATIAL" :
+ (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
+ "RTREE" :
"BTREE");
}
@@ -554,7 +564,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
param.tmpfile_createflag = O_RDWR | O_TRUNC;
param.using_global_keycache = 1;
param.thd=thd;
- param.tmpdir=mysql_tmpdir;
+ param.tmpdir=&mysql_tmpdir_list;
param.out_flag=0;
strmov(fixed_name,file->filename);
@@ -717,7 +727,7 @@ bool ha_myisam::activate_all_index(THD *thd)
T_CREATE_MISSING_KEYS);
param.myf_rw&= ~MY_WAIT_IF_FULL;
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
- param.tmpdir=mysql_tmpdir;
+ param.tmpdir=&mysql_tmpdir_list;
error=repair(thd,param,0) != HA_ADMIN_OK;
thd->proc_info=save_proc_info;
}
@@ -778,7 +788,7 @@ int ha_myisam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
statistic_increment(ha_read_key_count,&LOCK_status);
- int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
+ int error=mi_rkey(file,buf,active_index, key, key_len, (enum ha_rkey_function)find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -787,7 +797,7 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
statistic_increment(ha_read_key_count,&LOCK_status);
- int error=mi_rkey(file,buf,index, key, key_len, find_flag);
+ int error=mi_rkey(file,buf,index, key, key_len, (enum ha_rkey_function)find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -1019,7 +1029,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
KEY *pos;
MI_KEYDEF *keydef;
MI_COLUMNDEF *recinfo,*recinfo_pos;
- MI_KEYSEG *keyseg;
+ HA_KEYSEG *keyseg;
uint options=table_arg->db_options_in_use;
DBUG_ENTER("ha_myisam::create");
@@ -1028,14 +1038,16 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
&recinfo,(table_arg->fields*2+2)*sizeof(MI_COLUMNDEF),
&keydef, table_arg->keys*sizeof(MI_KEYDEF),
&keyseg,
- ((table_arg->key_parts + table_arg->keys) * sizeof(MI_KEYSEG)),
+ ((table_arg->key_parts + table_arg->keys) * sizeof(HA_KEYSEG)),
0)))
DBUG_RETURN(1);
pos=table_arg->key_info;
for (i=0; i < table_arg->keys ; i++, pos++)
{
- keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT));
+ keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
+ keydef[i].key_alg=pos->algorithm == HA_KEY_ALG_UNDEF ?
+ HA_KEY_ALG_BTREE : pos->algorithm;
keydef[i].seg=keyseg;
keydef[i].keysegs=pos->key_parts;
for (j=0 ; j < pos->key_parts ; j++)
@@ -1070,7 +1082,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
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=MY_CHARSET_CURRENT;
+ keydef[i].seg[j].language = field->charset()->number;
if (field->null_ptr)
{
diff --git a/sql/handler.cc b/sql/handler.cc
index f07e90d2eb9..b2cf86a6abc 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -689,7 +689,7 @@ void handler::print_error(int error, myf errflag)
{
/* Write the dupplicated key in the error message */
char key[MAX_KEY_LENGTH];
- String str(key,sizeof(key));
+ String str(key,sizeof(key),default_charset_info);
key_unpack(&str,table,(uint) key_nr);
uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_DUP_ENTRY));
if (str.length() >= max_length)
diff --git a/sql/handler.h b/sql/handler.h
index b9209d087a0..6cbd83af282 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -137,6 +137,7 @@ enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED,
#define HA_CREATE_USED_MAX_ROWS 32
#define HA_CREATE_USED_AVG_ROW_LENGTH 64
#define HA_CREATE_USED_PACK_KEYS 128
+#define HA_CREATE_USED_CHARSET 256
typedef struct st_thd_trans {
void *bdb_tid;
@@ -149,21 +150,22 @@ enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
typedef struct st_ha_create_information
{
- ulong table_options;
- enum db_type db_type;
- enum row_type row_type;
- ulong avg_row_length;
- ulonglong max_rows,min_rows;
- ulonglong auto_increment_value;
+ CHARSET_INFO *table_charset;
char *comment,*password;
char *data_file_name, *index_file_name;
- uint options; /* OR of HA_CREATE_ options */
- uint raid_type,raid_chunks;
+ ulonglong max_rows,min_rows;
+ ulonglong auto_increment_value;
+ ulong table_options;
+ ulong avg_row_length;
ulong raid_chunksize;
- bool if_not_exists;
ulong used_fields;
SQL_LIST merge_list;
+ enum db_type db_type;
+ enum row_type row_type;
+ uint options; /* OR of HA_CREATE_ options */
+ uint raid_type,raid_chunks;
uint merge_insert_method;
+ bool if_not_exists;
} HA_CREATE_INFO;
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index 34584b45d8c..f7384cc6e32 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -75,8 +75,8 @@ public:
if (!locked)
(void) pthread_mutex_lock(&lock);
(void) hash_free(&cache);
- (void) hash_init(&cache,size,key_offset, key_length, get_key, free_element,
- 0);
+ (void) hash_init(&cache,system_charset_info,size,key_offset,
+ key_length, get_key, free_element,0);
if (!locked)
(void) pthread_mutex_unlock(&lock);
first_link=last_link=0;
diff --git a/sql/hostname.cc b/sql/hostname.cc
index be035e52ac1..609532a67d6 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -221,10 +221,10 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors)
/* Don't accept hostnames that starts with digits because they may be
false ip:s */
- if (isdigit(name[0]))
+ if (my_isdigit(system_charset_info,name[0]))
{
char *pos;
- for (pos= name+1 ; isdigit(*pos); pos++) ;
+ for (pos= name+1 ; my_isdigit(system_charset_info,*pos); pos++) ;
if (*pos == '.')
{
DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
diff --git a/sql/init.cc b/sql/init.cc
index df06ddd41ef..8834fd3a89c 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -52,17 +52,6 @@ void unireg_init(ulong options)
}
specialflag|=options; /* Set options from argv */
- // The following is needed because of like optimization in select.cc
-
- uchar max_char=my_sort_order[(uchar) max_sort_char];
- for (i = 0; i < 256; i++)
- {
- if ((uchar) my_sort_order[i] > max_char)
- {
- max_char=(uchar) my_sort_order[i];
- max_sort_char= (char) i;
- }
- }
thread_stack_min=thread_stack - STACK_MIN_SIZE;
DBUG_VOID_RETURN;
}
diff --git a/sql/item.cc b/sql/item.cc
index b3b4e99e28a..48ec11d02c2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -37,20 +37,34 @@ void item_init(void)
Item::Item()
{
marker=0;
- binary=maybe_null=null_value=with_sum_func=unsigned_flag=0;
+ maybe_null=null_value=with_sum_func=unsigned_flag=0;
name=0;
decimals=0; max_length=0;
next=current_thd->free_list; // Put in free list
current_thd->free_list=this;
+ loop_id= 0;
}
-void Item::set_name(char *str,uint length)
+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);
+}
+
+void Item::set_name(const char *str,uint length)
{
if (!length)
- name=str; // Used by AS
+ name= (char*) str; // Used by AS
else
{
- while (length && !isgraph(*str))
+ while (length && !my_isgraph(system_charset_info,*str))
{ // Fix problem with yacc
length--;
str++;
@@ -66,7 +80,7 @@ void Item::set_name(char *str,uint length)
bool Item::eq(const Item *item, bool binary_cmp) const
{
return type() == item->type() && name && item->name &&
- !my_strcasecmp(name,item->name);
+ !my_strcasecmp(system_charset_info,name,item->name);
}
bool Item_string::eq(const Item *item, bool binary_cmp) const
@@ -89,7 +103,7 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
bool Item::get_date(TIME *ltime,bool fuzzydate)
{
char buff[40];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
if (!(res=val_str(&tmp)) ||
str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
{
@@ -107,7 +121,7 @@ bool Item::get_date(TIME *ltime,bool fuzzydate)
bool Item::get_time(TIME *ltime)
{
char buff[40];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
if (!(res=val_str(&tmp)) ||
str_to_time(res->ptr(),res->length(),ltime))
{
@@ -117,6 +131,11 @@ 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);
@@ -131,8 +150,8 @@ void Item_field::set_field(Field *field_par)
decimals= field->decimals();
table_name=field_par->table_name;
field_name=field_par->field_name;
- binary=field_par->binary();
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
+ set_charset(field_par->charset());
}
const char *Item_ident::full_name() const
@@ -234,7 +253,7 @@ table_map Item_field::used_tables() const
String *Item_int::val_str(String *str)
{
- str->set(value);
+ str->set(value, thd_charset());
return str;
}
@@ -242,7 +261,7 @@ void Item_int::print(String *str)
{
if (!name)
{
- str_value.set(value);
+ str_value.set(value, thd_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -250,7 +269,7 @@ void Item_int::print(String *str)
String *Item_uint::val_str(String *str)
{
- str->set((ulonglong) value);
+ str->set((ulonglong) value, thd_charset());
return str;
}
@@ -258,7 +277,7 @@ void Item_uint::print(String *str)
{
if (!name)
{
- str_value.set((ulonglong) value);
+ str_value.set((ulonglong) value, thd_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -267,7 +286,7 @@ void Item_uint::print(String *str)
String *Item_real::val_str(String *str)
{
- str->set(value,decimals);
+ str->set(value,decimals,thd_charset());
return str;
}
@@ -287,6 +306,113 @@ String *Item_null::val_str(String *str)
{ null_value=1; return 0;}
+/* Item_param related */
+void Item_param::set_null()
+{
+ maybe_null=null_value=1;
+}
+
+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, CHARSET_INFO *cs)
+{
+ str_value.set(str,length,cs);
+ item_result_type = STRING_RESULT;
+ item_type = STRING_ITEM;
+}
+
+
+void Item_param::set_longdata(const char *str, ulong length, CHARSET_INFO *cs)
+{
+ /* TODO: Fix this for binary handling by making use of
+ buffer_type..
+ */
+ str_value.append(str,length);
+}
+
+
+int Item_param::save_in_field(Field *field)
+{
+ if (null_value)
+ return (int) set_field_to_null(field);
+
+ field->set_notnull();
+ if (item_result_type == INT_RESULT)
+ {
+ longlong nr=val_int();
+ return (field->store(nr)) ? -1 : 0;
+ }
+ if (item_result_type == REAL_RESULT)
+ {
+ double nr=val();
+ return (field->store(nr)) ? -1 : 0;
+ }
+ String *result=val_str(&str_value);
+ return (field->store(result->ptr(),result->length(),field->charset())) ? -1 : 0;
+}
+
+
+void Item_param::make_field(Send_field *tmp_field)
+{
+ init_make_field(tmp_field,FIELD_TYPE_STRING);
+}
+
+
+double Item_param::val()
+{
+ switch (item_result_type) {
+ case STRING_RESULT:
+ return (double)atof(str_value.ptr());
+ case INT_RESULT:
+ return (double)int_value;
+ default:
+ return real_value;
+ }
+}
+
+
+longlong Item_param::val_int()
+{
+ switch (item_result_type) {
+ case STRING_RESULT:
+ return strtoll(str_value.ptr(),(char**) 0,10);
+ case REAL_RESULT:
+ return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5));
+ default:
+ return int_value;
+ }
+}
+
+
+String *Item_param::val_str(String* str)
+{
+ switch (item_result_type) {
+ case INT_RESULT:
+ str->set(int_value, thd_charset());
+ return str;
+ case REAL_RESULT:
+ str->set(real_value, 2, thd_charset());
+ return str;
+ default:
+ return (String*) &str_value;
+ }
+}
+/* End of Item_param related */
+
+
void Item_copy_string::copy()
{
String *res=item->val_str(&str_value);
@@ -304,23 +430,65 @@ String *Item_copy_string::val_str(String *str)
}
/*
-** Functions to convert item to field (for send_fields)
+ Functions to convert item to field (for send_fields)
*/
/* ARGSUSED */
bool Item::fix_fields(THD *thd,
- struct st_table_list *list)
+ struct st_table_list *list,
+ Item ** ref)
{
return 0;
}
-bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (!field) // If field is not checked
{
Field *tmp;
- if (!(tmp=find_field_in_tables(thd,this,tables)))
- return 1;
+ if ((tmp= find_field_in_tables(thd, this, tables, 0)) == 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).
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
+ mention of table name, but if we join tables in one list it will
+ cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
+ */
+ SELECT_LEX *last= 0;
+
+ // Prevent using outer fields in subselects, that is not supported now
+ if (thd->lex.current_select->linkage != DERIVED_TABLE_TYPE)
+ 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;
+ if (!tmp)
+ return -1;
+ else if (tmp == not_found_field)
+ {
+ // call to return error code
+ find_field_in_tables(thd, this, tables, 1);
+ return -1;
+ }
+ else
+ {
+ depended_from= last;
+ /*
+ Mark all selects from resolved to 1 before select where was
+ found table as depended (of select where was found table)
+ */
+ thd->lex.current_select->mark_as_dependent(last);
+ }
+ }
+ else if (!tmp)
+ return -1;
+
set_field(tmp);
}
else if (thd && thd->set_query_id && field->query_id != thd->query_id)
@@ -331,13 +499,24 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
table->used_fields++;
table->used_keys&=field->part_of_key;
}
+ if (depended_from != 0 && depended_from->having_fix_field)
+ {
+ *ref= new Item_ref((char *)db_name, (char *)table_name,
+ (char *)field_name);
+ if (!*ref)
+ return 1;
+ return (*ref)->fix_fields(thd, tables, ref);
+ }
return 0;
}
void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type)
-{
+{
+ tmp_field->db_name=(char*) "";
+ tmp_field->org_table_name=(char*) "";
+ tmp_field->org_col_name=(char*) "";
tmp_field->table_name=(char*) "";
tmp_field->col_name=name;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
@@ -429,7 +608,7 @@ void Item_field::save_org_in_field(Field *to)
}
}
-bool Item_field::save_in_field(Field *to)
+int Item_field::save_in_field(Field *to)
{
if (result_field->is_null())
{
@@ -445,6 +624,7 @@ bool Item_field::save_in_field(Field *to)
return 0;
}
+
/*
Store null in field
@@ -461,7 +641,7 @@ bool Item_field::save_in_field(Field *to)
1 Field doesn't support NULL values and can't handle 'field = NULL'
*/
-bool Item_null::save_in_field(Field *field)
+int Item_null::save_in_field(Field *field)
{
return set_field_to_null_with_conversions(field);
}
@@ -479,27 +659,29 @@ bool Item_null::save_in_field(Field *field)
1 Field doesn't support NULL values
*/
-bool Item_null::save_safe_in_field(Field *field)
+int Item_null::save_safe_in_field(Field *field)
{
return set_field_to_null(field);
}
-bool Item::save_in_field(Field *field)
+int Item::save_in_field(Field *field)
{
+ int error;
if (result_type() == STRING_RESULT ||
result_type() == REAL_RESULT &&
field->result_type() == STRING_RESULT)
{
String *result;
+ CHARSET_INFO *cs=field->charset();
char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
- str_value.set_quick(buff,sizeof(buff));
+ str_value.set_quick(buff,sizeof(buff),cs);
result=val_str(&str_value);
if (null_value)
return set_field_to_null_with_conversions(field);
field->set_notnull();
- field->store(result->ptr(),result->length());
- str_value.set_quick(0, 0);
+ error=field->store(result->ptr(),result->length(),cs);
+ str_value.set_quick(0, 0, cs);
}
else if (result_type() == REAL_RESULT)
{
@@ -507,7 +689,7 @@ bool Item::save_in_field(Field *field)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
+ error=field->store(nr);
}
else
{
@@ -515,41 +697,38 @@ bool Item::save_in_field(Field *field)
if (null_value)
return set_field_to_null_with_conversions(field);
field->set_notnull();
- field->store(nr);
+ error=field->store(nr);
}
- return 0;
+ return (error) ? -1 : 0;
}
-
-bool Item_string::save_in_field(Field *field)
+int Item_string::save_in_field(Field *field)
{
String *result;
+ CHARSET_INFO *cs=field->charset();
result=val_str(&str_value);
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(result->ptr(),result->length());
- return 0;
+ return (field->store(result->ptr(),result->length(),cs)) ? -1 : 0;
}
-bool Item_int::save_in_field(Field *field)
+int Item_int::save_in_field(Field *field)
{
longlong nr=val_int();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
- return 0;
+ return (field->store(nr)) ? -1 : 0;
}
-bool Item_real::save_in_field(Field *field)
+int Item_real::save_in_field(Field *field)
{
double nr=val();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
- return 0;
+ return (field->store(nr)) ? -1 : 0;
}
/****************************************************************************
@@ -572,7 +751,7 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
char *ptr=(char*) sql_alloc(max_length+1);
if (!ptr)
return;
- str_value.set(ptr,max_length);
+ str_value.set(ptr,max_length,my_charset_bin);
char *end=ptr+max_length;
if (max_length*2 != str_length)
*ptr++=char_val(*str++); // Not even, assume 0 prefix
@@ -582,7 +761,6 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
str+=2;
}
*ptr=0; // Keep purify happy
- binary=1; // Binary is default
}
longlong Item_varbinary::val_int()
@@ -597,19 +775,21 @@ longlong Item_varbinary::val_int()
}
-bool Item_varbinary::save_in_field(Field *field)
+int Item_varbinary::save_in_field(Field *field)
{
+ int error;
+ CHARSET_INFO *cs=field->charset();
field->set_notnull();
if (field->result_type() == STRING_RESULT)
{
- field->store(str_value.ptr(),str_value.length());
+ error=field->store(str_value.ptr(),str_value.length(),cs);
}
else
{
longlong nr=val_int();
- field->store(nr);
+ error=field->store(nr);
}
- return 0;
+ return (error) ? -1 : 0;
}
@@ -626,7 +806,7 @@ bool Item::send(THD *thd, String *packet)
{
char buff[MAX_FIELD_WIDTH];
CONVERT *convert;
- String s(buff,sizeof(buff)),*res;
+ String s(buff,sizeof(buff),packet->charset()),*res;
if (!(res=val_str(&s)))
return net_store_null(packet);
if ((convert=thd->variables.convert_set))
@@ -644,20 +824,78 @@ bool Item_null::send(THD *thd, String *packet)
Find field in select list having the same name
*/
-bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
if (!ref)
{
- if (!(ref=find_item_in_list(this,thd->lex.select->item_list)))
+ 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 &&
+ thd->lex.current_select->linkage !=
+ DERIVED_TABLE_TYPE) ?
+ REPORT_EXCEPT_NOT_FOUND :
+ REPORT_ALL_ERRORS))) ==
+ (Item **)not_found_item)
+ {
+ /*
+ We can't find table field in table list of current select,
+ consequently we have to find it in outer subselect(s).
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
+ mention of table name, but if we join tables in one list it will
+ cause error ER_NON_UNIQ_ERROR in find_item_in_list.
+ */
+ SELECT_LEX *last=0;
+ for ( ; sl ; sl= sl->outer_select())
+ if((ref= find_item_in_list(this, (last= sl)->item_list,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item)
+ break;
+
+ if (!ref)
+ {
+ return 1;
+ }
+ else if (ref == (Item **)not_found_item)
+ {
+ // Call to report error
+ find_item_in_list(this,
+ *(thd->lex.current_select->get_item_list()),
+ REPORT_ALL_ERRORS);
+ ref= 0;
+ return 1;
+ }
+ else
+ {
+ depended_from= last;
+ thd->lex.current_select->mark_as_dependent(last);
+ thd->add_possible_loop(this);
+ }
+ }
+ else if (!ref)
return 1;
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
- binary= (*ref)->binary;
}
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
@@ -685,7 +923,7 @@ Item *resolve_const_item(Item *item,Item *comp_item)
if (res_type == STRING_RESULT)
{
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff)),*result;
+ String tmp(buff,sizeof(buff),default_charset_info),*result;
result=item->val_str(&tmp);
if (item->null_value)
{
@@ -699,7 +937,7 @@ Item *resolve_const_item(Item *item,Item *comp_item)
#ifdef DELETE_ITEMS
delete item;
#endif
- return new Item_string(name,tmp_str,length);
+ return new Item_string(name,tmp_str,length,default_charset_info);
}
if (res_type == INT_RESULT)
{
@@ -740,8 +978,8 @@ bool field_is_equal_to_item(Field *field,Item *item)
{
char item_buff[MAX_FIELD_WIDTH];
char field_buff[MAX_FIELD_WIDTH];
- String item_tmp(item_buff,sizeof(item_buff)),*item_result;
- String field_tmp(field_buff,sizeof(field_buff));
+ String item_tmp(item_buff,sizeof(item_buff),default_charset_info),*item_result;
+ String field_tmp(field_buff,sizeof(field_buff),default_charset_info);
item_result=item->val_str(&item_tmp);
if (item->null_value)
return 1; // This must be true
diff --git a/sql/item.h b/sql/item.h
index 563db2291fb..5eeaa22a2a2 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); }
@@ -32,7 +33,8 @@ public:
enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM,
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};
+ PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM,
+ SUBSELECT_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
String str_value; /* used to store value */
@@ -42,21 +44,19 @@ public:
uint8 marker,decimals;
my_bool maybe_null; /* If item may be null */
my_bool null_value; /* if item is null */
- my_bool binary;
my_bool unsigned_flag;
my_bool with_sum_func;
-
// alloc & destruct is done as start of select using sql_alloc
Item();
virtual ~Item() { name=0; } /*lint -e1509 */
- void set_name(char* str,uint length=0);
+ 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 *);
- virtual bool save_in_field(Field *field);
+ virtual bool fix_fields(THD *, struct st_table_list *, Item **);
+ virtual int save_in_field(Field *field);
virtual void save_org_in_field(Field *field)
{ (void) save_in_field(field); }
- virtual bool save_safe_in_field(Field *field)
+ virtual int save_safe_in_field(Field *field)
{ return save_in_field(field); }
virtual bool send(THD *thd, String *str);
virtual bool eq(const Item *, bool binary_cmp) const;
@@ -71,6 +71,7 @@ public:
virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); }
virtual String *str_result(String* tmp) { return val_str(tmp); }
+ virtual bool is_null_result() { return is_null(); }
virtual table_map used_tables() const { return (table_map) 0L; }
virtual bool basic_const_item() const { return 0; }
virtual Item *new_item() { return 0; } /* Only for const items */
@@ -83,24 +84,30 @@ public:
virtual void split_sum_func(List<Item> &fields) {}
virtual bool get_date(TIME *ltime,bool fuzzydate);
virtual bool get_time(TIME *ltime);
- virtual bool is_null() { return 0; }
- virtual unsigned int size_of()= 0;
+ virtual bool is_null() { return 0; };
+ virtual CHARSET_INFO *thd_charset() const;
+ 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() {}
};
+class st_select_lex;
class Item_ident :public Item
{
public:
const char *db_name;
const char *table_name;
const char *field_name;
+ st_select_lex *depended_from;
Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par)
- :db_name(db_name_par),table_name(table_name_par),field_name(field_name_par)
+ :db_name(db_name_par),table_name(table_name_par),
+ field_name(field_name_par), depended_from(0)
{ name = (char*) field_name_par; }
const char *full_name() const;
- unsigned int size_of() { return sizeof(*this);}
};
@@ -124,13 +131,14 @@ public:
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
+ bool is_null_result() { return result_field->is_null(); }
bool send(THD *thd, String *str_arg)
{
return result_field->send(thd,str_arg);
}
void make_field(Send_field *field);
- bool fix_fields(THD *,struct st_table_list *);
- bool save_in_field(Field *field);
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ int save_in_field(Field *field);
void save_org_in_field(Field *field);
table_map used_tables() const;
enum Item_result result_type () const
@@ -141,7 +149,6 @@ public:
bool get_date(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -156,17 +163,52 @@ public:
longlong val_int();
String *val_str(String *str);
void make_field(Send_field *field);
- bool save_in_field(Field *field);
- bool save_safe_in_field(Field *field);
+ int save_in_field(Field *field);
+ int save_safe_in_field(Field *field);
enum Item_result result_type () const
{ return STRING_RESULT; }
bool send(THD *thd, String *str);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_null(name); }
bool is_null() { return 1; }
- unsigned int size_of() { return sizeof(*this);}
};
+class Item_param :public Item
+{
+public:
+ longlong int_value;
+ double real_value;
+ enum Item_result item_result_type;
+ enum Type item_type;
+ enum enum_field_types buffer_type;
+ my_bool long_data_supplied;
+
+ Item_param(char *name_par=0)
+ {
+ name= name_par ? name_par : (char*) "?";
+ long_data_supplied = false;
+ item_type = STRING_ITEM;
+ item_result_type = STRING_RESULT;
+ }
+ enum Type type() const { return item_type; }
+ double val();
+ longlong val_int();
+ String *val_str(String*);
+ void make_field(Send_field *field);
+ int save_in_field(Field *field);
+ void set_null();
+ void set_int(longlong i);
+ void set_double(double i);
+ void set_value(const char *str, uint length, CHARSET_INFO *cs);
+ void set_long_str(const char *str, ulong length, CHARSET_INFO *cs);
+ void set_long_binary(const char *str, ulong length, CHARSET_INFO *cs);
+ void set_longdata(const char *str, ulong length, CHARSET_INFO *cs);
+ void set_long_end();
+ void reset() {}
+ enum Item_result result_type () const
+ { return item_result_type; }
+ Item *new_item() { return new Item_param(name); }
+};
class Item_int :public Item
{
@@ -190,11 +232,10 @@ public:
double val() { return (double) value; }
String *val_str(String*);
void make_field(Send_field *field);
- bool save_in_field(Field *field);
+ int save_in_field(Field *field);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); }
void print(String *str);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -209,7 +250,6 @@ public:
void make_field(Send_field *field);
Item *new_item() { return new Item_uint(name,max_length); }
void print(String *str);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -232,7 +272,7 @@ public:
max_length=length;
}
Item_real(double value_par) :value(value_par) {}
- bool save_in_field(Field *field);
+ int save_in_field(Field *field);
enum Type type() const { return REAL_ITEM; }
double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));}
@@ -240,7 +280,6 @@ public:
void make_field(Send_field *field);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_real(name,value,decimals,max_length); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -252,22 +291,21 @@ public:
decimals=NOT_FIXED_DEC;
max_length=DBL_DIG+8;
}
- unsigned int size_of() { return sizeof(*this);}
};
class Item_string :public Item
{
public:
- Item_string(const char *str,uint length)
+ Item_string(const char *str,uint length,CHARSET_INFO *cs)
{
- str_value.set(str,length);
+ str_value.set(str,length,cs);
max_length=length;
name=(char*) str_value.ptr();
decimals=NOT_FIXED_DEC;
}
- Item_string(const char *name_par,const char *str,uint length)
+ Item_string(const char *name_par,const char *str,uint length,CHARSET_INFO *cs)
{
- str_value.set(str,length);
+ str_value.set(str,length,cs);
max_length=length;
name=(char*) name_par;
decimals=NOT_FIXED_DEC;
@@ -277,16 +315,15 @@ public:
double val() { return atof(str_value.ptr()); }
longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); }
String *val_str(String*) { return (String*) &str_value; }
- bool save_in_field(Field *field);
+ int save_in_field(Field *field);
void make_field(Send_field *field);
enum Item_result result_type () const { return STRING_RESULT; }
bool basic_const_item() const { return 1; }
bool eq(const Item *item, bool binary_cmp) const;
- Item *new_item() { return new Item_string(name,str_value.ptr(),max_length); }
+ Item *new_item() { return new Item_string(name,str_value.ptr(),max_length,default_charset_info); }
String *const_string() { return &str_value; }
inline void append(char *str,uint length) { str_value.append(str,length); }
void print(String *str);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -298,7 +335,7 @@ public:
Item_default() { name= (char*) "DEFAULT"; }
enum Type type() const { return DEFAULT_ITEM; }
void make_field(Send_field *field) {}
- bool save_in_field(Field *field)
+ int save_in_field(Field *field)
{
field->set_default();
return 0;
@@ -307,7 +344,6 @@ public:
virtual longlong val_int() { return 0; }
virtual String *val_str(String *str) { return 0; }
bool basic_const_item() const { return 1; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -316,18 +352,16 @@ public:
class Item_datetime :public Item_string
{
public:
- Item_datetime(const char *item_name): Item_string(item_name,"",0)
+ Item_datetime(const char *item_name): Item_string(item_name,"",0,default_charset_info)
{ max_length=19;}
void make_field(Send_field *field);
- unsigned int size_of() { return sizeof(*this);}
};
class Item_empty_string :public Item_string
{
public:
- Item_empty_string(const char *header,uint length) :Item_string("",0)
+ Item_empty_string(const char *header,uint length) :Item_string("",0,default_charset_info)
{ name=(char*) header; max_length=length;}
- unsigned int size_of() { return sizeof(*this);}
};
class Item_varbinary :public Item
@@ -339,10 +373,9 @@ public:
double val() { return (double) Item_varbinary::val_int(); }
longlong val_int();
String *val_str(String*) { return &str_value; }
- bool save_in_field(Field *field);
+ int save_in_field(Field *field);
void make_field(Send_field *field);
enum Item_result result_type () const { return INT_RESULT; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -355,7 +388,6 @@ public:
Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
table_map used_tables() const { return 1; }
virtual void fix_length_and_dec()=0;
- unsigned int size_of() { return sizeof(*this);}
};
@@ -374,25 +406,25 @@ public:
double val()
{
double tmp=(*ref)->val_result();
- null_value=(*ref)->null_value;
+ null_value=(*ref)->is_null_result();
return tmp;
}
longlong val_int()
{
longlong tmp=(*ref)->val_int_result();
- null_value=(*ref)->null_value;
+ null_value=(*ref)->is_null_result();
return tmp;
}
String *val_str(String* tmp)
{
tmp=(*ref)->str_result(tmp);
- null_value=(*ref)->null_value;
+ null_value=(*ref)->is_null_result();
return tmp;
}
bool is_null()
{
(void) (*ref)->val_int_result();
- return (*ref)->null_value;
+ return (*ref)->is_null_result();
}
bool get_date(TIME *ltime,bool fuzzydate)
{
@@ -400,12 +432,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 *);
- bool save_in_field(Field *field) { return (*ref)->save_in_field(field); }
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ int save_in_field(Field *field) { return (*ref)->save_in_field(field); }
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(); }
- unsigned int size_of() { return sizeof(*this);}
+ bool check_loop(uint id);
};
@@ -421,20 +453,22 @@ class Item_int_with_ref :public Item_int
public:
Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg)
{}
- bool save_in_field(Field *field)
+ int save_in_field(Field *field)
{
return ref->save_in_field(field);
}
- unsigned int size_of() { return sizeof(*this);}
};
+#include "gstream.h"
+#include "spatial.h"
#include "item_sum.h"
#include "item_func.h"
#include "item_cmpfunc.h"
#include "item_strfunc.h"
#include "item_timefunc.h"
#include "item_uniq.h"
+#include "item_subselect.h"
class Item_copy_string :public Item
{
@@ -460,7 +494,6 @@ public:
table_map used_tables() const { return (table_map) 1L; }
bool const_item() const { return 0; }
bool is_null() { return null_value; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -471,7 +504,6 @@ public:
Item_buff() :null_value(0) {}
virtual bool cmp(void)=0;
virtual ~Item_buff(); /*line -e1509 */
- unsigned int size_of() { return sizeof(*this);}
};
class Item_str_buff :public Item_buff
@@ -482,7 +514,6 @@ public:
Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {}
bool cmp(void);
~Item_str_buff(); // Deallocate String:s
- unsigned int size_of() { return sizeof(*this);}
};
@@ -493,7 +524,6 @@ class Item_real_buff :public Item_buff
public:
Item_real_buff(Item *item_par) :item(item_par),value(0.0) {}
bool cmp(void);
- unsigned int size_of() { return sizeof(*this);}
};
class Item_int_buff :public Item_buff
@@ -503,7 +533,6 @@ class Item_int_buff :public Item_buff
public:
Item_int_buff(Item *item_par) :item(item_par),value(0) {}
bool cmp(void);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -520,7 +549,6 @@ public:
buff= (char*) sql_calloc(length=field->pack_length());
}
bool cmp(void);
- unsigned int size_of() { return sizeof(*this);}
};
extern Item_buff *new_Item_buff(Item *item);
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index b55a4dc66a0..7b8976bb572 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -56,7 +56,7 @@ bool Item_str_buff::cmp(void)
}
else if (null_value)
return 0; // new and old value was null
- else if (!item->binary)
+ else if (!item->binary())
tmp= sortcmp(&value,res) != 0;
else
tmp= stringcmp(&value,res) != 0;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index ee587289168..1065c8cf023 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -24,6 +24,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
+
/*
Test functions
Most of these returns 0LL if false and 1LL if true and
@@ -42,14 +43,17 @@ longlong Item_func_not::val_int()
This is done when comparing DATE's of different formats and
also when comparing bigint to strings (in which case the string
is converted once to a bigint).
+
+ RESULT VALUES
+ 0 Can't convert item
+ 1 Item was replaced with an integer version of the item
*/
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) && !((*item)->null_value))
{
Item *tmp=new Item_int_with_ref(field->val_int(), *item);
if (tmp)
@@ -124,7 +128,7 @@ int Item_bool_func2::compare_string()
if ((res2=args[1]->val_str(&tmp_value2)))
{
null_value=0;
- return binary ? stringcmp(res1,res2) : sortcmp(res1,res2);
+ return binary() ? stringcmp(res1,res2) : sortcmp(res1,res2);
}
}
null_value=1;
@@ -195,7 +199,7 @@ longlong Item_func_equal::val_int()
res2=args[1]->val_str(&tmp_value2);
if (!res1 || !res2)
return test(res1 == res2);
- return (binary ? test(stringcmp(res1,res2) == 0) :
+ return (binary() ? test(stringcmp(res1,res2) == 0) :
test(sortcmp(res1,res2) == 0));
}
case REAL_RESULT:
@@ -262,7 +266,7 @@ longlong Item_func_strcmp::val_int()
null_value=1;
return 0;
}
- int value= binary ? stringcmp(a,b) : sortcmp(a,b);
+ int value= binary() ? stringcmp(a,b) : sortcmp(a,b);
null_value=0;
return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
}
@@ -340,6 +344,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;
@@ -353,7 +365,7 @@ void Item_func_between::fix_length_and_dec()
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)
+ if (args[0]->binary() | args[1]->binary() | args[2]->binary())
string_compare=stringcmp;
else
string_compare=sortcmp;
@@ -513,21 +525,22 @@ Item_func_if::fix_length_and_dec()
if (null1)
{
cached_result_type= arg2_type;
- binary= args[2]->binary;
+ set_charset(args[2]->charset());
}
else if (null2)
{
cached_result_type= arg1_type;
- binary= args[1]->binary;
+ set_charset(args[1]->charset());
}
else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT)
{
cached_result_type = STRING_RESULT;
- binary=args[1]->binary | args[2]->binary;
+ set_charset( (args[1]->binary() || args[2]->binary()) ?
+ my_charset_bin : args[1]->charset());
}
else
{
- binary=1; // Number
+ set_charset(my_charset_bin); // Number
if (arg1_type == REAL_RESULT || arg2_type == REAL_RESULT)
cached_result_type = REAL_RESULT;
else
@@ -665,7 +678,7 @@ Item *Item_func_case::find_item(String *str)
}
if ((tmp=args[i]->val_str(str))) // If not null
{
- if (first_expr->binary || args[i]->binary)
+ if (first_expr->binary() || args[i]->binary())
{
if (stringcmp(tmp,first_expr_str)==0)
return args[i+1];
@@ -722,7 +735,7 @@ String *Item_func_case::val_str(String *str)
longlong Item_func_case::val_int()
{
char buff[MAX_FIELD_WIDTH];
- String dummy_str(buff,sizeof(buff));
+ String dummy_str(buff,sizeof(buff),default_charset_info);
Item *item=find_item(&dummy_str);
longlong res;
@@ -739,7 +752,7 @@ longlong Item_func_case::val_int()
double Item_func_case::val()
{
char buff[MAX_FIELD_WIDTH];
- String dummy_str(buff,sizeof(buff));
+ String dummy_str(buff,sizeof(buff),default_charset_info);
Item *item=find_item(&dummy_str);
double res;
@@ -755,12 +768,12 @@ double Item_func_case::val()
bool
-Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables)
+Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- if (first_expr && first_expr->fix_fields(thd,tables) ||
- else_expr && else_expr->fix_fields(thd,tables))
+ if (first_expr && first_expr->fix_fields(thd, tables, &first_expr) ||
+ else_expr && else_expr->fix_fields(thd, tables, &else_expr))
return 1;
- if (Item_func::fix_fields(thd,tables))
+ if (Item_func::fix_fields(thd, tables, ref))
return 1;
if (first_expr)
{
@@ -777,6 +790,16 @@ Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables)
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();
@@ -911,7 +934,7 @@ int in_vector::find(Item *item)
in_string::in_string(uint elements,qsort_cmp cmp_func)
- :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff))
+ :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff),default_charset_info)
{}
in_string::~in_string()
@@ -926,6 +949,9 @@ void in_string::set(uint pos,Item *item)
String *res=item->val_str(str);
if (res && res != str)
*str= *res;
+ // BAR TODO: I'm not sure this is absolutely correct
+ if (!str->charset())
+ str->set_charset(default_charset_info);
}
byte *in_string::get_value(Item *item)
@@ -976,7 +1002,7 @@ void Item_func_in::fix_length_and_dec()
{
switch (item->result_type()) {
case STRING_RESULT:
- if (item->binary)
+ if (item->binary())
array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */
else
array=new in_string(arg_count,(qsort_cmp) sortcmp);
@@ -1002,7 +1028,7 @@ void Item_func_in::fix_length_and_dec()
{
switch (item->result_type()) {
case STRING_RESULT:
- if (item->binary)
+ if (item->binary())
in_item= new cmp_item_binary_string;
else
in_item= new cmp_item_sort_string;
@@ -1099,7 +1125,7 @@ longlong Item_func_bit_and::val_int()
bool
-Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
+Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
List_iterator<Item> li(list);
Item *item;
@@ -1123,7 +1149,7 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
}
if (abort_on_null)
item->top_level_item();
- if (item->fix_fields(thd,tables))
+ if (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;
@@ -1137,6 +1163,20 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
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)
{
@@ -1328,12 +1368,15 @@ longlong Item_func_like::val_int()
return 0;
}
null_value=0;
+ if ((res->charset()->state & MY_CS_BINSORT) ||
+ (res2->charset()->state & MY_CS_BINSORT))
+ 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;
}
@@ -1353,9 +1396,9 @@ Item_func::optimize_type Item_func_like::select_optimize() const
return OPTIMIZE_NONE;
}
-bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist)
+bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
{
- if (Item_bool_func2::fix_fields(thd, tlist))
+ if (Item_bool_func2::fix_fields(thd, tlist, ref))
return 1;
/*
@@ -1405,19 +1448,22 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist)
#ifdef USE_REGEX
bool
-Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
+Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
- if (args[0]->fix_fields(thd,tables) || args[1]->fix_fields(thd,tables))
+ if (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;
max_length=1; decimals=0;
- binary=args[0]->binary || args[1]->binary;
+ if (args[0]->binary() || args[1]->binary())
+ set_charset(my_charset_bin);
+
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
const_item_cache=args[0]->const_item() && args[1]->const_item();
if (!regex_compiled && args[1]->const_item())
{
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),default_charset_info);
String *res=args[1]->val_str(&tmp);
if (args[1]->null_value)
{ // Will always return NULL
@@ -1426,8 +1472,9 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
}
int error;
if ((error=regcomp(&preg,res->c_ptr(),
- binary ? REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE)))
+ binary() ? REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ res->charset())))
{
(void) regerror(error,&preg,buff,sizeof(buff));
my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff);
@@ -1444,7 +1491,7 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
longlong Item_func_regex::val_int()
{
char buff[MAX_FIELD_WIDTH];
- String *res, tmp(buff,sizeof(buff));
+ String *res, tmp(buff,sizeof(buff),default_charset_info);
res=args[0]->val_str(&tmp);
if (args[0]->null_value)
@@ -1455,7 +1502,7 @@ longlong Item_func_regex::val_int()
if (!regex_is_const)
{
char buff2[MAX_FIELD_WIDTH];
- String *res2, tmp2(buff2,sizeof(buff2));
+ String *res2, tmp2(buff2,sizeof(buff2),default_charset_info);
res2= args[1]->val_str(&tmp2);
if (args[1]->null_value)
@@ -1472,8 +1519,9 @@ longlong Item_func_regex::val_int()
regex_compiled=0;
}
if (regcomp(&preg,res2->c_ptr(),
- binary ? REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE))
+ binary() ? REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ res->charset()))
{
null_value=1;
@@ -1500,9 +1548,9 @@ Item_func_regex::~Item_func_regex()
#ifdef LIKE_CMP_TOUPPER
-#define likeconv(A) (uchar) toupper(A)
+#define likeconv(cs,A) (uchar) (cs)->toupper(A)
#else
-#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
+#define likeconv(cs,A) (uchar) (cs)->sort_order[(uchar) (A)]
#endif
@@ -1516,11 +1564,12 @@ void Item_func_like::turboBM_compute_suffixes(int* suff)
const int plm1 = pattern_len - 1;
int f = 0;
int g = plm1;
- int* const splm1 = suff + plm1;
+ int *const splm1 = suff + plm1;
+ CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed
*splm1 = pattern_len;
- if (binary)
+ if (binary())
{
int i;
for (i = pattern_len - 2; i >= 0; i--)
@@ -1552,7 +1601,8 @@ void Item_func_like::turboBM_compute_suffixes(int* suff)
if (i < g)
g = i; // g = min(i, g)
f = i;
- while (g >= 0 && likeconv(pattern[g]) == likeconv(pattern[g + plm1 - f]))
+ while (g >= 0 && likeconv(cs, pattern[g]) ==
+ likeconv(cs, pattern[g + plm1 - f]))
g--;
suff[i] = f - g;
}
@@ -1613,19 +1663,25 @@ void Item_func_like::turboBM_compute_good_suffix_shifts(int* suff)
void Item_func_like::turboBM_compute_bad_character_shifts()
{
- int* i;
- int* end = bmBc + alphabet_size;
+ int *i;
+ int *end = bmBc + alphabet_size;
+ int j;
+ const int plm1 = pattern_len - 1;
+ CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed
+
for (i = bmBc; i < end; i++)
*i = pattern_len;
- int j;
- const int plm1 = pattern_len - 1;
- if (binary)
+ if (binary())
+ {
for (j = 0; j < plm1; j++)
bmBc[pattern[j]] = plm1 - j;
+ }
else
+ {
for (j = 0; j < plm1; j++)
- bmBc[likeconv(pattern[j])] = plm1 - j;
+ bmBc[likeconv(cs,pattern[j])] = plm1 - j;
+ }
}
@@ -1641,12 +1697,13 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
int shift = pattern_len;
int j = 0;
int u = 0;
+ CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed
const int plm1 = pattern_len - 1;
const int tlmpl = text_len - pattern_len;
/* Searching */
- if (binary)
+ if (binary())
{
while (j <= tlmpl)
{
@@ -1682,7 +1739,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
while (j <= tlmpl)
{
register int i = plm1;
- while (i >= 0 && likeconv(pattern[i]) == likeconv(text[i + j]))
+ while (i >= 0 && likeconv(cs,pattern[i]) == likeconv(cs,text[i + j]))
{
i--;
if (i == plm1 - shift)
@@ -1693,7 +1750,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
register const int v = plm1 - i;
turboShift = u - v;
- bcShift = bmBc[likeconv(text[i + j])] - plm1 + i;
+ bcShift = bmBc[likeconv(cs, text[i + j])] - plm1 + i;
shift = max(turboShift, bcShift);
shift = max(shift, bmGs[i]);
if (shift == bmGs[i])
@@ -1748,3 +1805,82 @@ longlong Item_cond_xor::val_int()
}
return (longlong) result;
}
+
+/****************************************************************
+ Classes and functions for spatial relations
+*****************************************************************/
+
+longlong Item_func_spatial_rel::val_int()
+{
+ String *res1=args[0]->val_str(&tmp_value1);
+ String *res2=args[1]->val_str(&tmp_value2);
+ Geometry g1, g2;
+ MBR mbr1,mbr2;
+
+ if ((null_value=(args[0]->null_value ||
+ args[1]->null_value ||
+ g1.create_from_wkb(res1->ptr(),res1->length()) ||
+ g2.create_from_wkb(res2->ptr(),res2->length()) ||
+ g1.get_mbr(&mbr1) ||
+ g2.get_mbr(&mbr2))))
+ return 0;
+
+ switch (spatial_rel)
+ {
+ case SP_CONTAINS_FUNC:
+ return mbr1.contains(&mbr2);
+ case SP_WITHIN_FUNC:
+ return mbr1.within(&mbr2);
+ case SP_EQUALS_FUNC:
+ return mbr1.equals(&mbr2);
+ case SP_DISJOINT_FUNC:
+ return mbr1.disjoint(&mbr2);
+ case SP_INTERSECTS_FUNC:
+ return mbr1.intersects(&mbr2);
+ case SP_TOUCHES_FUNC:
+ return mbr1.touches(&mbr2);
+ case SP_OVERLAPS_FUNC:
+ return mbr1.overlaps(&mbr2);
+ case SP_CROSSES_FUNC:
+ return 0;
+ default:
+ break;
+ }
+
+ null_value=1;
+ return 0;
+}
+
+longlong Item_func_isempty::val_int()
+{
+ String tmp;
+ null_value=0;
+ return args[0]->null_value ? 1 : 0;
+}
+
+longlong Item_func_issimple::val_int()
+{
+ String tmp;
+ String *wkb=args[0]->val_str(&tmp);
+
+ if ((null_value= (!wkb || args[0]->null_value )))
+ return 0;
+ /* TODO: Ramil or Holyfoot, add real IsSimple calculation */
+ return 0;
+}
+
+longlong Item_func_isclosed::val_int()
+{
+ String tmp;
+ String *wkb=args[0]->val_str(&tmp);
+ Geometry geom;
+ int isclosed;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,is_closed) ||
+ geom.is_closed(&isclosed));
+
+ return (longlong) isclosed;
+}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index e163bc40a6e..a9dc6c87f95 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -28,7 +28,6 @@ public:
Item_bool_func(Item *a) :Item_int_func(a) {}
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
void fix_length_and_dec() { decimals=0; max_length=1; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_bool_func2 :public Item_int_func
@@ -48,7 +47,6 @@ public:
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()); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -82,7 +80,6 @@ public:
enum Functype rev_functype() const { return EQUAL_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "<=>"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -180,15 +177,16 @@ public:
Item_func_interval(Item *a,List<Item> &list)
:Item_int_func(list),item(a),intervals(0) {}
longlong val_int();
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref)
{
- return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ return (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();
- unsigned int size_of() { return sizeof(*this);}
+ bool check_loop(uint id);
};
@@ -203,7 +201,6 @@ public:
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -223,7 +220,6 @@ public:
}
void fix_length_and_dec();
const char *func_name() const { return "if"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -238,7 +234,6 @@ public:
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
const char *func_name() const { return "nullif"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -253,7 +248,6 @@ public:
void fix_length_and_dec();
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "coalesce"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_case :public Item_func
@@ -272,9 +266,9 @@ public:
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
void print(String *str);
- bool fix_fields(THD *thd,struct st_table_list *tlist);
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
Item *find_item(String *str);
- unsigned int size_of() { return sizeof(*this);}
+ bool check_loop(uint id);
};
@@ -355,7 +349,7 @@ class cmp_item_sort_string :public cmp_item {
char value_buff[80];
String value,*value_res;
public:
- cmp_item_sort_string() :value(value_buff,sizeof(value_buff)) {}
+ cmp_item_sort_string() :value(value_buff,sizeof(value_buff),default_charset_info) {}
void store_value(Item *item)
{
value_res=item->val_str(&value);
@@ -363,7 +357,7 @@ public:
int cmp(Item *arg)
{
char buff[80];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
if (!(res=arg->val_str(&tmp)))
return 1; /* Can't be right */
return sortcmp(value_res,res);
@@ -376,7 +370,7 @@ public:
int cmp(Item *arg)
{
char buff[80];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
if (!(res=arg->val_str(&tmp)))
return 1; /* Can't be right */
return stringcmp(value_res,res);
@@ -423,9 +417,10 @@ class Item_func_in :public Item_int_func
Item_func_in(Item *a,List<Item> &list)
:Item_int_func(list),item(a),array(0),in_item(0) {}
longlong val_int();
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref)
{
- return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ return (item->fix_fields(thd, tlist, &item) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
void fix_length_and_dec();
~Item_func_in() { delete item; delete array; delete in_item; }
@@ -436,7 +431,13 @@ 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();
- unsigned int size_of() { return sizeof(*this);}
+ 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));
+ }
};
@@ -474,7 +475,6 @@ public:
}
}
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_isnotnull :public Item_bool_func
@@ -489,7 +489,6 @@ public:
}
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_like :public Item_bool_func2
@@ -522,8 +521,7 @@ public:
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "like"; }
void fix_length_and_dec();
- bool fix_fields(THD *thd,struct st_table_list *tlist);
- unsigned int size_of() { return sizeof(*this);}
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
};
#ifdef USE_REGEX
@@ -541,9 +539,8 @@ public:
regex_compiled(0),regex_is_const(0) {}
~Item_func_regex();
longlong val_int();
- bool fix_fields(THD *thd,struct st_table_list *tlist);
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
const char *func_name() const { return "regex"; }
- unsigned int size_of() { return sizeof(*this);}
};
#else
@@ -573,7 +570,7 @@ public:
{ 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 *);
+ bool fix_fields(THD *, struct st_table_list *, Item **ref);
enum Type type() const { return COND_ITEM; }
List<Item>* argument_list() { return &list; }
@@ -582,7 +579,7 @@ public:
void print(String *str);
void split_sum_func(List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
- unsigned int size_of() { return sizeof(*this);}
+ bool check_loop(uint id);
void top_level_item() { abort_on_null=1; }
};
@@ -608,6 +605,17 @@ public:
};
+class Item_cond_xor :public Item_cond
+{
+public:
+ Item_cond_xor() :Item_cond() {}
+ Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) {}
+ enum Functype functype() const { return COND_XOR_FUNC; }
+ longlong val_int();
+ const char *func_name() const { return "xor"; }
+};
+
+
/* Some usefull inline functions */
inline Item *and_conds(Item *a,Item *b)
@@ -620,15 +628,80 @@ inline Item *and_conds(Item *a,Item *b)
return cond;
}
-class Item_cond_xor :public Item_cond
+Item *and_expressions(Item *a, Item *b, Item **org_item);
+
+/**************************************************************
+ Spatial relations
+***************************************************************/
+
+class Item_func_spatial_rel :public Item_bool_func2
{
+ enum Functype spatial_rel;
public:
- Item_cond_xor() :Item_cond() {}
- Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) {}
- enum Functype functype() const { return COND_XOR_FUNC; }
+ Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) :
+ Item_bool_func2(a,b) { spatial_rel = sp_rel; }
longlong val_int();
- const char *func_name() const { return "xor"; }
+ enum Functype functype() const
+ {
+ switch (spatial_rel) {
+ case SP_CONTAINS_FUNC:
+ return SP_WITHIN_FUNC;
+ case SP_WITHIN_FUNC:
+ return SP_CONTAINS_FUNC;
+ default:
+ return spatial_rel;
+ }
+ }
+ enum Functype rev_functype() const { return spatial_rel; }
+ const char *func_name() const
+ {
+ switch (spatial_rel) {
+ case SP_CONTAINS_FUNC:
+ return "contains";
+ case SP_WITHIN_FUNC:
+ return "within";
+ case SP_EQUALS_FUNC:
+ return "equals";
+ case SP_DISJOINT_FUNC:
+ return "disjoint";
+ case SP_INTERSECTS_FUNC:
+ return "intersects";
+ case SP_TOUCHES_FUNC:
+ return "touches";
+ case SP_CROSSES_FUNC:
+ return "crosses";
+ case SP_OVERLAPS_FUNC:
+ return "overlaps";
+ default:
+ return "sp_unknown";
+ }
+ }
};
-Item *and_expressions(Item *a, Item *b, Item **org_item);
+class Item_func_isempty :public Item_bool_func
+{
+public:
+ Item_func_isempty(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "isempty"; }
+};
+
+class Item_func_issimple :public Item_bool_func
+{
+public:
+ Item_func_issimple(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "issimple"; }
+};
+
+class Item_func_isclosed :public Item_bool_func
+{
+public:
+ Item_func_isclosed(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "isclosed"; }
+};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index f28e3248c61..e4c9a160686 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -96,6 +96,11 @@ Item *create_func_cot(Item* a)
new Item_func_tan(a));
}
+Item *create_func_crc32(Item* a)
+{
+ return new Item_func_crc32(a);
+}
+
Item *create_func_date_format(Item* a,Item *b)
{
return new Item_func_date_format(a,b,0);
@@ -242,7 +247,7 @@ Item *create_func_lpad(Item* a, Item *b, Item *c)
Item *create_func_ltrim(Item* a)
{
- return new Item_func_ltrim(a,new Item_string(" ",1));
+ return new Item_func_ltrim(a,new Item_string(" ",1,default_charset_info));
}
Item *create_func_md5(Item* a)
@@ -324,7 +329,7 @@ Item *create_func_rpad(Item* a, Item *b, Item *c)
Item *create_func_rtrim(Item* a)
{
- return new Item_func_rtrim(a,new Item_string(" ",1));
+ return new Item_func_rtrim(a,new Item_string(" ",1,default_charset_info));
}
Item *create_func_sec_to_time(Item* a)
@@ -349,7 +354,7 @@ Item *create_func_sha(Item* a)
Item *create_func_space(Item *a)
{
- return new Item_func_repeat(new Item_string(" ",1),a);
+ return new Item_func_repeat(new Item_string(" ",1,default_charset_info),a);
}
Item *create_func_soundex(Item* a)
@@ -394,7 +399,9 @@ Item *create_func_ucase(Item* a)
Item *create_func_version(void)
{
- return new Item_string(NullS,server_version, (uint) strlen(server_version));
+ return new Item_string(NullS,server_version,
+ (uint) strlen(server_version),
+ default_charset_info);
}
Item *create_func_weekday(Item* a)
@@ -444,3 +451,158 @@ Item *create_func_quote(Item* a)
{
return new Item_func_quote(a);
}
+
+Item *create_func_geometry_from_text(Item* a)
+{
+ return new Item_func_geometry_from_text(a);
+}
+
+Item *create_func_as_text(Item* a)
+{
+ return new Item_func_as_text(a);
+}
+
+Item *create_func_startpoint(Item* a)
+{
+ return new Item_func_spatial_decomp(a, Item_func::SP_STARTPOINT);
+}
+
+Item *create_func_endpoint(Item* a)
+{
+ return new Item_func_spatial_decomp(a, Item_func::SP_ENDPOINT);
+}
+
+Item *create_func_exteriorring(Item* a)
+{
+ return new Item_func_spatial_decomp(a, Item_func::SP_EXTERIORRING);
+}
+
+Item *create_func_pointn(Item* a, Item* b)
+{
+ return new Item_func_spatial_decomp_n(a,b,Item_func::SP_POINTN);
+}
+
+Item *create_func_interiorringn(Item* a, Item* b)
+{
+ return new Item_func_spatial_decomp_n(a,b,Item_func::SP_INTERIORRINGN);
+}
+
+Item *create_func_geometryn(Item* a, Item* b)
+{
+ return new Item_func_spatial_decomp_n(a,b,Item_func::SP_GEOMETRYN);
+}
+
+Item *create_func_centroid(Item* a)
+{
+ return new Item_func_centroid(a);
+}
+
+Item *create_func_envelope(Item* a)
+{
+ return new Item_func_envelope(a);
+}
+
+Item *create_func_equals(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_EQUALS_FUNC);
+}
+
+Item *create_func_disjoint(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_DISJOINT_FUNC);
+}
+
+Item *create_func_intersects(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_INTERSECTS_FUNC);
+}
+
+Item *create_func_touches(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_TOUCHES_FUNC);
+}
+
+Item *create_func_crosses(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_CROSSES_FUNC);
+}
+
+Item *create_func_within(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_WITHIN_FUNC);
+}
+
+Item *create_func_contains(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_CONTAINS_FUNC);
+}
+
+Item *create_func_overlaps(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_OVERLAPS_FUNC);
+}
+
+Item *create_func_isempty(Item* a)
+{
+ return new Item_func_isempty(a);
+}
+
+Item *create_func_issimple(Item* a)
+{
+ return new Item_func_issimple(a);
+}
+
+Item *create_func_isclosed(Item* a)
+{
+ return new Item_func_isclosed(a);
+}
+
+Item *create_func_geometry_type(Item* a)
+{
+ return new Item_func_geometry_type(a);
+}
+
+Item *create_func_dimension(Item* a)
+{
+ return new Item_func_dimension(a);
+}
+
+Item *create_func_x(Item* a)
+{
+ return new Item_func_x(a);
+}
+
+Item *create_func_y(Item* a)
+{
+ return new Item_func_y(a);
+}
+
+Item *create_func_numpoints(Item* a)
+{
+ return new Item_func_numpoints(a);
+}
+
+Item *create_func_numinteriorring(Item* a)
+{
+ return new Item_func_numinteriorring(a);
+}
+
+Item *create_func_numgeometries(Item* a)
+{
+ return new Item_func_numgeometries(a);
+}
+
+Item *create_func_area(Item* a)
+{
+ return new Item_func_area(a);
+}
+
+Item *create_func_glength(Item* a)
+{
+ return new Item_func_glength(a);
+}
+
+Item *create_func_point(Item* a, Item* b)
+{
+ return new Item_func_point(a,b);
+}
diff --git a/sql/item_create.h b/sql/item_create.h
index 28fbd61df8f..6d9cef04c13 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -27,10 +27,12 @@ Item *create_func_bit_count(Item* a);
Item *create_func_bit_length(Item* a);
Item *create_func_ceiling(Item* a);
Item *create_func_char_length(Item* a);
+Item *create_func_cast(Item *a, Item_cast cast_type);
Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
Item *create_func_cot(Item* a);
+Item *create_func_crc32(Item* a);
Item *create_func_date_format(Item* a,Item *b);
Item *create_func_dayname(Item* a);
Item *create_func_dayofmonth(Item* a);
@@ -94,3 +96,41 @@ Item *create_load_file(Item* a);
Item *create_wait_for_master_pos(Item* a, Item* b);
Item *create_func_is_free_lock(Item* a);
Item *create_func_quote(Item* a);
+
+Item *create_func_geometry_from_text(Item* a);
+Item *create_func_as_text(Item* a);
+Item *create_func_startpoint(Item* a);
+Item *create_func_endpoint(Item* a);
+Item *create_func_exteriorring(Item* a);
+Item *create_func_centroid(Item* a);
+Item *create_func_envelope(Item* a);
+Item *create_func_pointn(Item* a, Item* b);
+Item *create_func_interiorringn(Item* a, Item* b);
+Item *create_func_geometryn(Item* a, Item* b);
+
+Item *create_func_equals(Item* a, Item* b);
+Item *create_func_disjoint(Item* a, Item* b);
+Item *create_func_intersects(Item* a, Item* b);
+Item *create_func_touches(Item* a, Item* b);
+Item *create_func_crosses(Item* a, Item* b);
+Item *create_func_within(Item* a, Item* b);
+Item *create_func_contains(Item* a, Item* b);
+Item *create_func_overlaps(Item* a, Item* b);
+
+Item *create_func_isempty(Item* a);
+Item *create_func_issimple(Item* a);
+Item *create_func_isclosed(Item* a);
+
+Item *create_func_geometry_type(Item* a);
+Item *create_func_dimension(Item* a);
+Item *create_func_x(Item* a);
+Item *create_func_y(Item* a);
+Item *create_func_area(Item* a);
+Item *create_func_glength(Item* a);
+
+Item *create_func_numpoints(Item* a);
+Item *create_func_numinteriorring(Item* a);
+Item *create_func_numgeometries(Item* a);
+
+Item *create_func_point(Item* a,Item* b);
+
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 5721a2f5e8c..75260065be6 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -22,11 +22,13 @@
#endif
#include "mysql_priv.h"
+#include "slave.h" // for wait_for_master_pos
#include <m_ctype.h>
#include <hash.h>
#include <time.h>
#include <ft_global.h>
-#include "slave.h" // for wait_for_master_pos
+#include <zlib.h>
+#include <assert.h>
/* return TRUE if item is a constant */
@@ -55,12 +57,45 @@ Item_func::Item_func(List<Item> &list)
list.empty(); // Fields are used
}
+
+/*
+ Resolve references to table column for a function and it's argument
+
+ SYNOPSIS:
+ fix_fields()
+ thd Thread object
+ tables List of all open tables involved in the query
+ ref Pointer to where this object is used. This reference
+ is used if we want to replace this object with another
+ one (for example in the summary functions).
+
+ DESCRIPTION
+ Call fix_fields() for all arguments to the function. The main intention
+ is to allow all Item_field() objects to setup pointers to the table fields.
+
+ Sets as a side effect the following class variables:
+ maybe_null Set if any argument may return NULL
+ with_sum_func Set if any of the arguments contains a sum function
+ used_table_cache Set to union of the arguments used table
+
+ str_value.charset If this is a string function, set this to the
+ character set for the first argument.
+
+ If for any item any of the defaults are wrong, then this can
+ be fixed in the fix_length_and_dec() function that is called
+ after this one or by writing a specialized fix_fields() for the
+ item.
+
+ RETURN VALUES
+ 0 ok
+ 1 Got error. Stored with my_error().
+*/
+
bool
-Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
+Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
Item **arg,**arg_end;
char buff[STACK_BUFF_ALLOC]; // Max argument in function
- binary=0;
used_tables_cache=0;
const_item_cache=1;
@@ -68,14 +103,20 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
return 0; // Fatal error if flag is set!
if (arg_count)
{ // Print purify happy
+ /*
+ 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))
+ if ((*arg)->fix_fields(thd, tables, arg))
return 1; /* purecov: inspected */
if ((*arg)->maybe_null)
maybe_null=1;
- if ((*arg)->binary)
- binary=1;
+ if ((*arg)->binary())
+ set_charset(my_charset_bin);
with_sum_func= with_sum_func || (*arg)->with_sum_func;
used_tables_cache|=(*arg)->used_tables();
const_item_cache&= (*arg)->const_item();
@@ -85,6 +126,22 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
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)
{
@@ -187,9 +244,9 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
break;
case STRING_RESULT:
if (max_length > 255)
- res= new Field_blob(max_length, maybe_null, name, t_arg, binary);
+ res= new Field_blob(max_length, maybe_null, name, t_arg, charset());
else
- res= new Field_string(max_length, maybe_null, name, t_arg, binary);
+ res= new Field_string(max_length, maybe_null, name, t_arg, charset());
break;
}
return res;
@@ -202,7 +259,7 @@ String *Item_real_func::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -215,9 +272,9 @@ String *Item_num_func::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else if (!unsigned_flag)
- str->set(nr);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,thd_charset());
}
else
{
@@ -225,7 +282,7 @@ String *Item_num_func::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
}
return str;
}
@@ -245,9 +302,9 @@ String *Item_int_func::val_str(String *str)
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,thd_charset());
return str;
}
@@ -274,9 +331,9 @@ String *Item_num_op::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else if (!unsigned_flag)
- str->set(nr);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,thd_charset());
}
else
{
@@ -284,7 +341,7 @@ String *Item_num_op::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
}
return str;
}
@@ -398,6 +455,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);
@@ -748,7 +824,6 @@ void Item_func_min_max::fix_length_and_dec()
decimals=0;
max_length=0;
maybe_null=1;
- binary=0;
cmp_type=args[0]->result_type();
for (uint i=0 ; i < arg_count ; i++)
{
@@ -759,8 +834,8 @@ void Item_func_min_max::fix_length_and_dec()
if (!args[i]->maybe_null)
maybe_null=0;
cmp_type=item_cmp_type(cmp_type,args[i]->result_type());
- if (args[i]->binary)
- binary=1;
+ if (args[i]->binary())
+ set_charset(my_charset_bin);
}
}
@@ -774,9 +849,9 @@ String *Item_func_min_max::val_str(String *str)
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,thd_charset());
return str;
}
case REAL_RESULT:
@@ -785,7 +860,7 @@ String *Item_func_min_max::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
case STRING_RESULT:
@@ -806,7 +881,7 @@ String *Item_func_min_max::val_str(String *str)
res2= args[i]->val_str(res == str ? &tmp_value : str);
if (res2)
{
- int cmp=binary ? stringcmp(res,res2) : sortcmp(res,res2);
+ int cmp=binary() ? stringcmp(res,res2) : sortcmp(res,res2);
if ((cmp_sign < 0 ? cmp : -cmp) < 0)
res=res2;
}
@@ -862,6 +937,18 @@ longlong Item_func_min_max::val_int()
return value;
}
+longlong Item_func_crc32::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length());
+}
+
longlong Item_func_length::val_int()
{
@@ -884,7 +971,7 @@ longlong Item_func_char_length::val_int()
return 0; /* purecov: inspected */
}
null_value=0;
- return (longlong) (!args[0]->binary) ? res->numchars() : res->length();
+ return (longlong) (!args[0]->binary()) ? res->numchars() : res->length();
}
@@ -892,7 +979,7 @@ longlong Item_func_locate::val_int()
{
String *a=args[0]->val_str(&value1);
String *b=args[1]->val_str(&value2);
- bool binary_str = args[0]->binary || args[1]->binary;
+ bool binary_str = args[0]->binary() || args[1]->binary();
if (!a || !b)
{
null_value=1;
@@ -907,7 +994,7 @@ longlong Item_func_locate::val_int()
{
start=(uint) args[2]->val_int()-1;
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ if (use_mb(a->charset()))
{
start0=start;
if (!binary_str)
@@ -920,7 +1007,7 @@ longlong Item_func_locate::val_int()
if (!b->length()) // Found empty string at start
return (longlong) (start+1);
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary_str)
+ if (use_mb(a->charset()) && !binary_str)
{
const char *ptr=a->ptr()+start;
const char *search=b->ptr();
@@ -939,14 +1026,15 @@ longlong Item_func_locate::val_int()
return (longlong) start0+1;
}
skipp:
- if ((l=my_ismbchar(default_charset_info,ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(a->charset(),ptr,strend)))
+ ptr+=l;
else ++ptr;
++start0;
}
return 0;
}
#endif /* USE_MB */
- return (longlong) (binary ? a->strstr(*b,start) :
+ return (longlong) (binary() ? a->strstr(*b,start) :
(a->strstr_case(*b,start)))+1;
}
@@ -990,12 +1078,12 @@ longlong Item_func_ord::val_int()
null_value=0;
if (!res->length()) return 0;
#ifdef USE_MB
- if (use_mb(default_charset_info) && !args[0]->binary)
+ if (use_mb(res->charset()) && !args[0]->binary())
{
register const char *str=res->ptr();
- register uint32 n=0, l=my_ismbchar(default_charset_info,
- str,str+res->length());
- if (!l) return (longlong)((uchar) *str);
+ register uint32 n=0, l=my_ismbchar(res->charset(),str,str+res->length());
+ if (!l)
+ return (longlong)((uchar) *str);
while (l--)
n=(n<<8)|(uint32)((uchar) *str++);
return (longlong) n;
@@ -1055,6 +1143,7 @@ longlong Item_func_find_in_set::val_int()
null_value=0;
int diff;
+ CHARSET_INFO *charset= find->charset();
if ((diff=buffer->length() - find->length()) >= 0)
{
const char *f_pos=find->ptr();
@@ -1068,7 +1157,7 @@ longlong Item_func_find_in_set::val_int()
const char *pos= f_pos;
while (pos != f_end)
{
- if (toupper(*str) != toupper(*pos))
+ if (my_toupper(charset,*str) != my_toupper(charset,*pos))
goto not_found;
str++;
pos++;
@@ -1163,7 +1252,7 @@ udf_handler::~udf_handler()
bool
-udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func,
+udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
uint arg_count, Item **arguments)
{
char buff[STACK_BUFF_ALLOC]; // Max argument in function
@@ -1188,7 +1277,7 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func,
args=arguments;
/* Fix all arguments */
- func->binary=func->maybe_null=0;
+ func->maybe_null=0;
used_tables_cache=0;
const_item_cache=1;
@@ -1207,10 +1296,10 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
- if ((*arg)->fix_fields(thd,tables))
+ if ((*arg)->fix_fields(thd, tables, arg))
return 1;
- if ((*arg)->binary)
- func->binary=1;
+ if ((*arg)->binary())
+ func->set_charset(my_charset_bin);
if ((*arg)->maybe_null)
func->maybe_null=1;
func->with_sum_func= func->with_sum_func || (*arg)->with_sum_func;
@@ -1373,7 +1462,7 @@ String *udf_handler::val_str(String *str,String *save_str)
str->length(res_length);
return str;
}
- save_str->set(res, res_length);
+ save_str->set(res, res_length, default_charset_info);
return save_str;
}
@@ -1394,7 +1483,7 @@ String *Item_func_udf_float::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -1415,9 +1504,9 @@ String *Item_func_udf_int::val_str(String *str)
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr);
+ str->set(nr,thd_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,thd_charset());
return str;
}
@@ -1498,7 +1587,8 @@ char *ull_get_key(const ULL *ull,uint *length,
void item_user_lock_init(void)
{
pthread_mutex_init(&LOCK_user_locks,MY_MUTEX_INIT_SLOW);
- hash_init(&hash_user_locks,16,0,0,(hash_get_key) ull_get_key,NULL,0);
+ hash_init(&hash_user_locks,system_charset_info,
+ 16,0,0,(hash_get_key) ull_get_key,NULL,0);
}
void item_user_lock_free(void)
@@ -1512,9 +1602,9 @@ void item_user_lock_release(ULL *ull)
if (mysql_bin_log.is_open())
{
char buf[256];
- String tmp(buf,sizeof(buf));
- tmp.length(0);
- tmp.append("DO RELEASE_LOCK(\"");
+ const char *command="DO RELEASE_LOCK(\"";
+ String tmp(buf,sizeof(buf), system_charset_info);
+ 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(),1);
@@ -1772,7 +1862,7 @@ longlong Item_func_set_last_insert_id::val_int()
longlong Item_func_benchmark::val_int()
{
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff), default_charset_info);
THD *thd=current_thd;
for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
@@ -1827,11 +1917,12 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
}
-bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
+ Item **ref)
{
if (!thd)
thd=current_thd; // Should never happen
- if (Item_func::fix_fields(thd,tables) ||
+ if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return 1;
entry->update_query_id=thd->query_id;
@@ -1849,7 +1940,8 @@ Item_func_set_user_var::fix_length_and_dec()
}
void Item_func_set_user_var::update_hash(void *ptr, uint length,
- Item_result type)
+ Item_result type,
+ CHARSET_INFO *cs)
{
if ((null_value=args[0]->null_value))
{
@@ -1858,6 +1950,7 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length,
my_free(entry->value,MYF(0));
entry->value=0;
entry->length=0;
+ entry->var_charset=cs;
}
else
{
@@ -1888,6 +1981,7 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length,
memcpy(entry->value,ptr,length);
entry->length= length;
entry->type=type;
+ entry->var_charset=cs;
}
return;
@@ -1910,7 +2004,7 @@ Item_func_set_user_var::update()
break;
case STRING_RESULT:
char buffer[MAX_FIELD_WIDTH];
- String tmp(buffer,sizeof(buffer));
+ String tmp(buffer,sizeof(buffer),default_charset_info);
(void) val_str(&tmp);
break;
}
@@ -1922,7 +2016,7 @@ double
Item_func_set_user_var::val()
{
double value=args[0]->val();
- update_hash((void*) &value,sizeof(value), REAL_RESULT);
+ update_hash((void*) &value,sizeof(value), REAL_RESULT, default_charset_info);
return value;
}
@@ -1930,7 +2024,7 @@ longlong
Item_func_set_user_var::val_int()
{
longlong value=args[0]->val_int();
- update_hash((void*) &value,sizeof(longlong),INT_RESULT);
+ update_hash((void*) &value,sizeof(longlong),INT_RESULT, default_charset_info);
return value;
}
@@ -1939,9 +2033,9 @@ Item_func_set_user_var::val_str(String *str)
{
String *res=args[0]->val_str(str);
if (!res) // Null value
- update_hash((void*) 0,0,STRING_RESULT);
+ update_hash((void*) 0,0,STRING_RESULT, default_charset_info);
else
- update_hash(res->c_ptr(),res->length()+1,STRING_RESULT);
+ update_hash(res->c_ptr(),res->length()+1,STRING_RESULT,res->charset());
return res;
}
@@ -1976,13 +2070,13 @@ Item_func_get_user_var::val_str(String *str)
return NULL;
switch (entry->type) {
case REAL_RESULT:
- str->set(*(double*) entry->value,decimals);
+ str->set(*(double*) entry->value,decimals,thd_charset());
break;
case INT_RESULT:
- str->set(*(longlong*) entry->value);
+ 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;
@@ -2085,7 +2179,7 @@ longlong Item_func_inet_aton::val_int()
char c = '.'; // we mark c to indicate invalid IP in case length is 0
char buff[36];
- String *s,tmp(buff,sizeof(buff));
+ String *s,tmp(buff,sizeof(buff),default_charset_info);
if (!(s = args[0]->val_str(&tmp))) // If null value
goto err;
null_value=0;
@@ -2124,7 +2218,9 @@ void Item_func_match::init_search(bool no_order)
DBUG_VOID_RETURN;
if (key == NO_SUCH_KEY)
- concat= new Item_func_concat_ws(new Item_string(" ",1), fields);
+ concat=new Item_func_concat_ws(new Item_string(" ",1,
+ default_charset_info),
+ fields);
if (master)
{
@@ -2135,15 +2231,15 @@ void Item_func_match::init_search(bool no_order)
DBUG_VOID_RETURN;
}
- String *ft_tmp=0;
+ String *ft_tmp= 0;
char tmp1[FT_QUERY_MAXLEN];
- String tmp2(tmp1,sizeof(tmp1));
+ String tmp2(tmp1,sizeof(tmp1),default_charset_info);
// MATCH ... AGAINST (NULL) is meaningless, but possible
if (!(ft_tmp=key_item()->val_str(&tmp2)))
{
ft_tmp= &tmp2;
- tmp2.set("",0);
+ tmp2.set("",0,default_charset_info);
}
ft_handler=table->file->ft_init_ext(mode, key,
@@ -2158,7 +2254,7 @@ void Item_func_match::init_search(bool no_order)
}
-bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
+bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
List_iterator<Item> li(fields);
Item *item;
@@ -2172,7 +2268,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
modifications to find_best and auto_close as complement to auto_init code
above.
*/
- if (Item_func::fix_fields(thd,tlist) || !const_item())
+ if (Item_func::fix_fields(thd, tlist, ref) || !const_item())
{
my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST");
return 1;
@@ -2180,7 +2276,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
while ((item=li++))
{
- if (item->fix_fields(thd,tlist))
+ if (item->fix_fields(thd, tlist, li.ref()))
return 1;
if (item->type() == Item::REF_ITEM)
li.replace(item= *((Item_ref *)item)->ref);
@@ -2204,6 +2300,19 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
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()
{
@@ -2327,6 +2436,7 @@ double Item_func_match::val()
DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, record, 0));
}
+
longlong Item_func_bit_xor::val_int()
{
ulonglong arg1= (ulonglong) args[0]->val_int();
@@ -2343,18 +2453,19 @@ longlong Item_func_bit_xor::val_int()
Item *get_system_var(enum_var_type var_type, LEX_STRING name)
{
- if (!my_strcasecmp(name.str,"VERSION"))
- return new Item_string("@@VERSION",server_version,
- (uint) strlen(server_version));
+ if (!my_strcasecmp(system_charset_info, name.str, "VERSION"))
+ return new Item_string("@@VERSION", server_version,
+ (uint) strlen(server_version),
+ system_charset_info);
THD *thd=current_thd;
Item *item;
sys_var *var;
char buff[MAX_SYS_VAR_LENGTH+3+8], *pos;
- if (!(var= find_sys_var(name.str)))
+ if (!(var= find_sys_var(name.str, name.length)))
{
- net_printf(&thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, name.str);
+ net_printf(thd, ER_UNKNOWN_SYSTEM_VARIABLE, name.str);
return 0;
}
if (!(item=var->item(thd, var_type)))
@@ -2374,6 +2485,23 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name)
}
+Item *get_system_var(enum_var_type var_type, const char *var_name, uint length,
+ const char *item_name)
+{
+ THD *thd=current_thd;
+ Item *item;
+ sys_var *var;
+
+ var= find_sys_var(var_name, length);
+ DBUG_ASSERT(var != 0);
+ if (!(item=var->item(thd, var_type)))
+ return 0; // Impossible
+ thd->safe_to_cache_query=0;
+ item->set_name(item_name); // Will use original name
+ return item;
+}
+
+
/*
Check a user level lock.
@@ -2408,3 +2536,124 @@ longlong Item_func_is_free_lock::val_int()
return 1;
return 0;
}
+
+
+/**************************************************************************
+ Spatial functions
+***************************************************************************/
+
+longlong Item_func_dimension::val_int()
+{
+ uint32 dim;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ geom.dimension(&dim));
+
+ return (longlong) dim;
+}
+
+longlong Item_func_numinteriorring::val_int()
+{
+ uint32 num;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,num_interior_ring) ||
+ geom.num_interior_ring(&num));
+
+ return (longlong) num;
+}
+
+longlong Item_func_numgeometries::val_int()
+{
+ uint32 num=0;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,num_geometries) ||
+ geom.num_geometries(&num));
+
+ return (longlong) num;
+}
+
+longlong Item_func_numpoints::val_int()
+{
+ uint32 num=0;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,num_points) ||
+ geom.num_points(&num));
+
+ return (longlong) num;
+}
+
+
+double Item_func_x::val()
+{
+ double res=0;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,get_x) ||
+ geom.get_x(&res));
+
+ return res;
+}
+
+
+double Item_func_y::val()
+{
+ double res=0;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,get_y) ||
+ geom.get_y(&res));
+
+ return res;
+}
+
+
+double Item_func_area::val()
+{
+ double res=0;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,area) ||
+ geom.area(&res));
+
+ return res;
+}
+
+
+double Item_func_glength::val()
+{
+ double res=0;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,length) ||
+ geom.length(&res));
+ return res;
+}
diff --git a/sql/item_func.h b/sql/item_func.h
index 2e02d7cfd28..b659a6d69d2 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -39,7 +39,13 @@ public:
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC,
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
- COND_AND_FUNC,COND_OR_FUNC,COND_XOR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC};
+ COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC, BETWEEN, IN_FUNC,
+ INTERVAL_FUNC,
+ SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
+ SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
+ SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
+ SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
+ SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN};
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; }
@@ -94,7 +100,7 @@ public:
}
Item_func(List<Item> &list);
~Item_func() {} /* Nothing to do; Items are freed automaticly */
- bool fix_fields(THD *,struct st_table_list *);
+ bool fix_fields(THD *,struct st_table_list *, Item **ref);
void make_field(Send_field *field);
table_map used_tables() const;
void update_used_tables();
@@ -121,8 +127,8 @@ public:
}
bool is_null() { (void) val_int(); return null_value; }
friend class udf_handler;
- unsigned int size_of() { return sizeof(*this);}
Field *tmp_table_field(TABLE *t_arg);
+ bool check_loop(uint id);
};
@@ -137,7 +143,6 @@ public:
longlong val_int() { return (longlong) val(); }
enum Item_result result_type () const { return REAL_RESULT; }
void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -153,7 +158,6 @@ public:
enum Item_result result_type () const { return hybrid_type; }
void fix_length_and_dec() { fix_num_length_and_dec(); }
bool is_null() { (void) val(); return null_value; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -169,7 +173,6 @@ class Item_num_op :public Item_func
void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); }
void find_num_type(void);
bool is_null() { (void) val(); return null_value; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -251,6 +254,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:
@@ -459,7 +474,6 @@ public:
const char *func_name() const { return truncate ? "truncate" : "round"; }
double val();
void fix_length_and_dec();
- unsigned int size_of() { return sizeof(*this);}
};
@@ -495,7 +509,6 @@ class Item_func_units :public Item_real_func
double val();
const char *func_name() const { return name; }
void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -512,7 +525,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
enum Item_result result_type () const { return cmp_type; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_min :public Item_func_min_max
@@ -529,6 +541,16 @@ public:
const char *func_name() const { return "greatest"; }
};
+class Item_func_crc32 :public Item_int_func
+{
+ String value;
+public:
+ Item_func_crc32(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "crc32"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
class Item_func_length :public Item_int_func
{
@@ -538,7 +560,6 @@ public:
longlong val_int();
const char *func_name() const { return "length"; }
void fix_length_and_dec() { max_length=10; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_bit_length :public Item_func_length
@@ -557,7 +578,6 @@ public:
longlong val_int();
const char *func_name() const { return "char_length"; }
void fix_length_and_dec() { max_length=10; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_locate :public Item_int_func
@@ -569,7 +589,6 @@ public:
const char *func_name() const { return "locate"; }
longlong val_int();
void fix_length_and_dec() { maybe_null=0; max_length=11; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -581,9 +600,10 @@ public:
Item_func_field(Item *a,List<Item> &list) :Item_int_func(list),item(a) {}
~Item_func_field() { delete item; }
longlong val_int();
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
{
- return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ return (item->fix_fields(thd, tlist, &item) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
void update_used_tables()
{
@@ -599,7 +619,13 @@ public:
const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
}
- unsigned int size_of() { return sizeof(*this);}
+ 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));
+ }
};
@@ -611,7 +637,6 @@ public:
longlong val_int();
const char *func_name() const { return "ascii"; }
void fix_length_and_dec() { max_length=3; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_ord :public Item_int_func
@@ -621,7 +646,6 @@ public:
Item_func_ord(Item *a) :Item_int_func(a) {}
longlong val_int();
const char *func_name() const { return "ord"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_find_in_set :public Item_int_func
@@ -634,7 +658,6 @@ public:
longlong val_int();
const char *func_name() const { return "find_in_set"; }
void fix_length_and_dec();
- unsigned int size_of() { return sizeof(*this);}
};
@@ -710,7 +733,6 @@ class Item_func_benchmark :public Item_int_func
longlong val_int();
const char *func_name() const { return "benchmark"; }
void fix_length_and_dec() { max_length=1; maybe_null=0; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -727,15 +749,14 @@ public:
:Item_func(list), udf(udf_arg) {}
~Item_udf_func() {}
const char *func_name() const { return udf.name(); }
- bool fix_fields(THD *thd,struct st_table_list *tables)
+ bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref)
{
- 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;
+ 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;
return res;
}
Item_result result_type () const { return udf.result_type(); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -844,7 +865,6 @@ class Item_func_get_lock :public Item_int_func
longlong val_int();
const char *func_name() const { return "get_lock"; }
void fix_length_and_dec() { max_length=1; maybe_null=1;}
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_release_lock :public Item_int_func
@@ -855,7 +875,6 @@ class Item_func_release_lock :public Item_int_func
longlong val_int();
const char *func_name() const { return "release_lock"; }
void fix_length_and_dec() { max_length=1; maybe_null=1;}
- unsigned int size_of() { return sizeof(*this);}
};
/* replication functions */
@@ -868,7 +887,6 @@ class Item_master_pos_wait :public Item_int_func
longlong val_int();
const char *func_name() const { return "master_pos_wait"; }
void fix_length_and_dec() { max_length=1; maybe_null=1;}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -887,14 +905,13 @@ public:
double val();
longlong val_int();
String *val_str(String *str);
- void update_hash(void *ptr, uint length, enum Item_result type);
+ void update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs);
bool update();
enum Item_result result_type () const { return cached_result_type; }
- bool fix_fields(THD *thd,struct st_table_list *tables);
+ bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref);
void fix_length_and_dec();
void print(String *str);
const char *func_name() const { return "set_user_var"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -919,7 +936,6 @@ public:
table_map used_tables() const
{ return const_var_flag ? 0 : RAND_TABLE_BIT; }
bool eq(const Item *item, bool binary_cmp) const;
- unsigned int size_of() { return sizeof(*this);}
};
@@ -968,14 +984,98 @@ public:
}
enum Functype functype() const { return FT_FUNC; }
void update_used_tables() {}
- bool fix_fields(THD *thd,struct st_table_list *tlist);
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
bool eq(const Item *, bool binary_cmp) const;
longlong val_int() { return val()!=0.0; }
double val();
bool fix_index();
void init_search(bool no_order);
- unsigned int size_of() { return sizeof(*this);}
+ bool check_loop(uint id);
+};
+
+
+class Item_func_dimension :public Item_int_func
+{
+ String value;
+public:
+ Item_func_dimension(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "dimension"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+
+class Item_func_x :public Item_real_func
+{
+ String value;
+public:
+ Item_func_x(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "x"; }
+};
+
+
+class Item_func_y :public Item_real_func
+{
+ String value;
+public:
+ Item_func_y(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "y"; }
+};
+
+
+class Item_func_numgeometries :public Item_int_func
+{
+ String value;
+public:
+ Item_func_numgeometries(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "numgeometries"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+
+class Item_func_numinteriorring :public Item_int_func
+{
+ String value;
+public:
+ Item_func_numinteriorring(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "numinteriorring"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+
+class Item_func_numpoints :public Item_int_func
+{
+ String value;
+public:
+ Item_func_numpoints(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "numpoints"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+
+class Item_func_area :public Item_real_func
+{
+ String value;
+public:
+ Item_func_area(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "area"; }
+};
+
+
+class Item_func_glength :public Item_real_func
+{
+ String value;
+public:
+ Item_func_glength(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "glength"; }
};
@@ -998,16 +1098,6 @@ public:
const char *func_name() const { return "match_bool"; }
};
-/* For type casts */
-
-enum Item_cast
-{
- ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
- ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME
-};
-
-Item *create_func_cast(Item *a, Item_cast cast_type);
-
class Item_func_bit_xor : public Item_int_func
{
@@ -1026,5 +1116,12 @@ public:
longlong val_int();
const char *func_name() const { return "check_lock"; }
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
- unsigned int size_of() { return sizeof(*this);}
+};
+
+/* For type casts */
+
+enum Item_cast
+{
+ ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT,
+ ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index af533eefe9a..1a561c9eb34 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -37,14 +37,14 @@
#include "sha1.h"
#include "my_aes.h"
-String empty_string("");
+String empty_string("",default_charset_info);
uint nr_of_decimals(const char *str)
{
if ((str=strchr(str,'.')))
{
const char *start= ++str;
- for (; isdigit(*str) ; str++) ;
+ for (; my_isdigit(system_charset_info,*str) ; str++) ;
return (uint) (str-start);
}
return 0;
@@ -145,7 +145,7 @@ void Item_func_sha::fix_length_and_dec()
String *Item_func_aes_encrypt::val_str(String *str)
{
char key_buff[80];
- String tmp_key_value(key_buff, sizeof(key_buff));
+ String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
String *sptr= args[0]->val_str(str); // String to encrypt
String *key= args[1]->val_str(&tmp_key_value); // key
int aes_length;
@@ -180,7 +180,8 @@ void Item_func_aes_encrypt::fix_length_and_dec()
String *Item_func_aes_decrypt::val_str(String *str)
{
char key_buff[80];
- String tmp_key_value(key_buff, sizeof(key_buff)), *sptr, *key;
+ String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
+ String *sptr, *key;
DBUG_ENTER("Item_func_aes_decrypt::val_str");
sptr= args[0]->val_str(str); // String to decrypt
@@ -231,6 +232,8 @@ String *Item_func_concat::val_str(String *str)
use_as_buff= &tmp_value;
for (i=1 ; i < arg_count ; i++)
{
+ if (args[i]->binary())
+ set_charset(my_charset_bin);
if (res->length() == 0)
{
if (!(res=args[i]->val_str(str)))
@@ -259,6 +262,7 @@ String *Item_func_concat::val_str(String *str)
str->append(*res2);
}
res=str;
+ res->set_charset(charset());
}
else if (res == &tmp_value)
{
@@ -270,6 +274,7 @@ String *Item_func_concat::val_str(String *str)
if (tmp_value.replace(0,0,*res))
goto null;
res= &tmp_value;
+ res->set_charset(charset());
use_as_buff=str; // Put next arg here
}
else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() &&
@@ -288,6 +293,7 @@ String *Item_func_concat::val_str(String *str)
*res))
goto null;
res= &tmp_value;
+ res->set_charset(charset());
use_as_buff=str; // Put next arg here
}
else
@@ -297,6 +303,7 @@ String *Item_func_concat::val_str(String *str)
tmp_value.append(*res2))
goto null;
res= &tmp_value;
+ res->set_charset(charset());
use_as_buff=str;
}
}
@@ -486,7 +493,7 @@ error:
String *Item_func_concat_ws::val_str(String *str)
{
char tmp_str_buff[10];
- String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff)),
+ String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info),
*sep_str, *res, *res2,*use_as_buff;
uint i;
@@ -625,7 +632,7 @@ String *Item_func_reverse::val_str(String *str)
ptr = (char *) res->ptr();
end=ptr+res->length();
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
String tmpstr;
tmpstr.copy(*res);
@@ -633,7 +640,7 @@ String *Item_func_reverse::val_str(String *str)
register uint32 l;
while (ptr < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end)))
+ if ((l=my_ismbchar(res->charset(), ptr,end)))
tmp-=l, memcpy(tmp,ptr,l), ptr+=l;
else
*--tmp=*ptr++;
@@ -676,8 +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 = (args[0]->binary || args[1]->binary ||
- !use_mb(default_charset_info));
+ bool binary_str;
#endif
null_value=0;
@@ -688,6 +694,10 @@ String *Item_func_replace::val_str(String *str)
if (args[1]->null_value)
goto null;
+#ifdef USE_MB
+ binary_str = (args[0]->binary() || args[1]->binary() || !use_mb(res->charset()));
+#endif
+
if (res2->length() == 0)
return res;
#ifndef USE_MB
@@ -734,7 +744,7 @@ redo:
goto redo;
}
skipp:
- if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
else ++ptr;
}
}
@@ -793,7 +803,7 @@ String *Item_func_insert::val_str(String *str)
args[3]->null_value)
goto null; /* purecov: inspected */
#ifdef USE_MB
- if (use_mb(default_charset_info) && !args[0]->binary)
+ if (use_mb(res->charset()) && !args[0]->binary())
{
start=res->charpos(start);
length=res->charpos(length,start);
@@ -866,7 +876,7 @@ String *Item_func_left::val_str(String *str)
if (length <= 0)
return &empty_string;
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
length = res->charpos(length);
#endif
if (res->length() > (ulong) length)
@@ -874,6 +884,7 @@ String *Item_func_left::val_str(String *str)
if (!res->alloced_length())
{ // Don't change const str
str_value= *res; // Not malloced string
+ set_charset(res->charset());
res= &str_value;
}
res->length((uint) length);
@@ -914,7 +925,7 @@ String *Item_func_right::val_str(String *str)
if (res->length() <= (uint) length)
return res; /* purecov: inspected */
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
uint start=res->numchars()-(uint) length;
if (start<=0) return res;
@@ -947,7 +958,7 @@ String *Item_func_substr::val_str(String *str)
(arg_count == 3 && args[2]->null_value))))
return 0; /* purecov: inspected */
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
start=res->charpos(start);
length=res->charpos(length,start);
@@ -1007,7 +1018,7 @@ String *Item_func_substr_index::val_str(String *str)
return &empty_string; // Wrong parameters
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
const char *ptr=res->ptr();
const char *strend = ptr+res->length();
@@ -1032,7 +1043,7 @@ String *Item_func_substr_index::val_str(String *str)
continue;
}
skipp:
- if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
else ++ptr;
} /* either not found or got total number when count<0 */
if (pass == 0) /* count<0 */
@@ -1104,7 +1115,7 @@ String *Item_func_ltrim::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),res->charset());
String *remove_str=args[1]->val_str(&tmp);
uint remove_length;
LINT_INIT(remove_length);
@@ -1142,7 +1153,7 @@ String *Item_func_rtrim::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),res->charset());
String *remove_str=args[1]->val_str(&tmp);
uint remove_length;
LINT_INIT(remove_length);
@@ -1161,11 +1172,11 @@ String *Item_func_rtrim::val_str(String *str)
{
char chr=(*remove_str)[0];
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
while (ptr < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l,p=ptr;
+ if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l,p=ptr;
else ++ptr;
}
ptr=p;
@@ -1178,12 +1189,12 @@ String *Item_func_rtrim::val_str(String *str)
{
const char *r_ptr=remove_str->ptr();
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
loop:
while (ptr + remove_length < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l;
else ++ptr;
}
if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
@@ -1214,7 +1225,7 @@ String *Item_func_trim::val_str(String *str)
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),res->charset());
String *remove_str=args[1]->val_str(&tmp);
uint remove_length;
LINT_INIT(remove_length);
@@ -1229,14 +1240,14 @@ String *Item_func_trim::val_str(String *str)
while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
ptr+=remove_length;
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary())
{
char *p=ptr;
register uint32 l;
loop:
while (ptr + remove_length < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l;
else ++ptr;
}
if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
@@ -1269,7 +1280,7 @@ String *Item_func_password::val_str(String *str)
if (res->length() == 0)
return &empty_string;
make_scrambled_password(tmp_value,res->c_ptr());
- str->set(tmp_value,16);
+ str->set(tmp_value,16,res->charset());
return str;
}
@@ -1303,7 +1314,7 @@ String *Item_func_encrypt::val_str(String *str)
}
pthread_mutex_lock(&LOCK_crypt);
char *tmp=crypt(res->c_ptr(),salt_ptr);
- str->set(tmp,(uint) strlen(tmp));
+ str->set(tmp,(uint) strlen(tmp),res->charset());
str->copy();
pthread_mutex_unlock(&LOCK_crypt);
return str;
@@ -1355,17 +1366,25 @@ String *Item_func_database::val_str(String *str)
if (!current_thd->db)
str->length(0);
else
- str->set((const char*) current_thd->db,(uint) strlen(current_thd->db));
+ str->copy((const char*) current_thd->db,(uint) strlen(current_thd->db), system_charset_info, 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_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;
}
@@ -1386,9 +1405,9 @@ extern "C" {
extern const char *soundex_map; // In mysys/static.c
}
-static char get_scode(char *ptr)
+static char get_scode(CHARSET_INFO *cs,char *ptr)
{
- uchar ch=toupper(*ptr);
+ uchar ch=my_toupper(cs,*ptr);
if (ch < 'A' || ch > 'Z')
{
// Thread extended alfa (country spec)
@@ -1410,21 +1429,21 @@ String *Item_func_soundex::val_str(String *str)
char *to= (char *) tmp_value.ptr();
char *from= (char *) res->ptr(), *end=from+res->length();
- while (from != end && isspace(*from)) // Skip pre-space
+ while (from != end && my_isspace(str->charset(),*from)) // Skip pre-space
from++; /* purecov: inspected */
if (from == end)
return &empty_string; // No alpha characters.
- *to++ = toupper(*from); // Copy first letter
- last_ch = get_scode(from); // code of the first letter
+ *to++ = my_toupper(str->charset(),*from);// Copy first letter
+ last_ch = get_scode(str->charset(),from);// code of the first letter
// for the first 'double-letter check.
// Loop on input letters until
// end of input (null) or output
// letter code count = 3
for (from++ ; from < end ; from++)
{
- if (!isalpha(*from))
+ if (!my_isalpha(str->charset(),*from))
continue;
- ch=get_scode(from);
+ ch=get_scode(str->charset(),from);
if ((ch != '0') && (ch != last_ch)) // if not skipped or double
{
*to++ = ch; // letter, copy to output
@@ -1458,7 +1477,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);
+ str->set(nr,decimals,thd_charset());
str_length=str->length();
if (nr < 0)
str_length--; // Don't count sign
@@ -1626,7 +1645,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));
@@ -1888,12 +1907,232 @@ String *Item_func_conv::val_str(String *str)
else
dec= (longlong) strtoull(res->c_ptr(),&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;
}
+String *Item_func_conv_charset::val_str(String *str)
+{
+ my_wc_t wc;
+ int cnvres;
+ const uchar *s, *se;
+ uchar *d, *d0, *de;
+ 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+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);
+ if (cnvres>0)
+ {
+ s+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILSEQ)
+ {
+ s++;
+ wc='?';
+ }
+ else
+ break;
+
+outp:
+ cnvres=to->wc_mb(to,wc,d,de);
+ if (cnvres>0)
+ {
+ d+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILUNI && wc!='?')
+ {
+ wc='?';
+ goto outp;
+ }
+ else
+ break;
+ };
+
+ str->length((uint32) (d-d0));
+ str->set_charset(to);
+ return str;
+}
+
+void Item_func_conv_charset::fix_length_and_dec()
+{
+ max_length = args[0]->max_length*conv_charset->mbmaxlen;
+ set_charset(conv_charset);
+}
+
+
+
+String *Item_func_conv_charset3::val_str(String *str)
+{
+ my_wc_t wc;
+ int cnvres;
+ const uchar *s, *se;
+ uchar *d, *d0, *de;
+ uint32 dmaxlen;
+ String *arg= args[0]->val_str(str);
+ String *to_cs= args[1]->val_str(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 ||
+ !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))))
+ {
+ null_value=1;
+ return 0;
+ }
+
+ s=(const uchar*)arg->ptr();
+ se=s+arg->length();
+
+ 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);
+ if (cnvres>0)
+ {
+ s+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILSEQ)
+ {
+ s++;
+ wc='?';
+ }
+ else
+ break;
+
+outp:
+ cnvres=to_charset->wc_mb(to_charset,wc,d,de);
+ if (cnvres>0)
+ {
+ d+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILUNI && wc!='?')
+ {
+ wc='?';
+ goto outp;
+ }
+ else
+ break;
+ };
+
+ str->length((uint32) (d-d0));
+ str->set_charset(to_charset);
+ return str;
+}
+
+
+bool Item_func_conv_charset::fix_fields(THD *thd,struct st_table_list *tables, Item **ref)
+{
+ 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))
+ return 1;
+ maybe_null=args[0]->maybe_null;
+ const_item_cache=args[0]->const_item();
+ set_charset(conv_charset);
+ fix_length_and_dec();
+ return 0;
+}
+
+
+void Item_func_conv_charset3::fix_length_and_dec()
+{
+ max_length = args[0]->max_length;
+}
+
+String *Item_func_set_collation::val_str(String *str)
+{
+ str=args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ str->set_charset(set_collation);
+ return str;
+}
+
+bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables, Item **ref)
+{
+ 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))
+ return 1;
+ maybe_null=args[0]->maybe_null;
+ set_charset(set_collation);
+ with_sum_func= with_sum_func || args[0]->with_sum_func;
+ used_tables_cache=args[0]->used_tables();
+ const_item_cache=args[0]->const_item();
+ fix_length_and_dec();
+ return 0;
+}
+
+bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
+{
+ /* Assume we don't have rtti */
+ if (this == item)
+ return 1;
+ if (item->type() != FUNC_ITEM)
+ return 0;
+ Item_func *item_func=(Item_func*) item;
+ if (arg_count != item_func->arg_count ||
+ func_name() != item_func->func_name())
+ return 0;
+ Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item;
+ if (set_collation != item_func_sc->set_collation)
+ return 0;
+ for (uint i=0; i < arg_count ; i++)
+ if (!args[i]->eq(item_func_sc->args[i], binary_cmp))
+ return 0;
+ return 1;
+}
+
+String *Item_func_charset::val_str(String *str)
+{
+ String *res = args[0]->val_str(str);
+
+ if ((null_value=(args[0]->null_value || !res->charset())))
+ return 0;
+ str->copy(res->charset()->name,strlen(res->charset()->name),my_charset_latin1,thd_charset());
+ return str;
+}
+
+
String *Item_func_hex::val_str(String *str)
{
if (args[0]->result_type() != STRING_RESULT)
@@ -1904,7 +2143,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;
}
@@ -2013,7 +2252,7 @@ String* Item_func_export_set::val_str(String* str)
}
break;
case 3:
- sep_buf.set(",", 1);
+ sep_buf.set(",", 1, default_charset_info);
sep = &sep_buf;
}
null_value=0;
@@ -2077,6 +2316,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
return str;
}
+
/*
QUOTE() function returns argument string in single quotes suitable for
using in a SQL statement.
@@ -2167,3 +2407,338 @@ null:
null_value= 1;
return 0;
}
+
+
+/*******************************************************
+General functions for spatial objects
+********************************************************/
+
+String *Item_func_geometry_from_text::val_str(String *str)
+{
+ Geometry geom;
+ String *wkt = args[0]->val_str(str);
+ GTextReadStream trs(wkt->ptr(), wkt->length());
+
+ str->length(0);
+ if ((null_value=(args[0]->null_value || geom.create_from_wkt(&trs, str, 0))))
+ return 0;
+ return str;
+}
+
+
+void Item_func_geometry_from_text::fix_length_and_dec()
+{
+ max_length=MAX_BLOB_WIDTH;
+}
+
+
+String *Item_func_as_text::val_str(String *str)
+{
+ String *wkt = args[0]->val_str(str);
+ Geometry geom;
+
+ if ((null_value=(args[0]->null_value ||
+ geom.create_from_wkb(wkt->ptr(),wkt->length()))))
+ return 0;
+
+ str->length(0);
+
+ if ((null_value=geom.as_wkt(str)))
+ return 0;
+
+ return str;
+}
+
+void Item_func_as_text::fix_length_and_dec()
+{
+ max_length=MAX_BLOB_WIDTH;
+}
+
+String *Item_func_geometry_type::val_str(String *str)
+{
+ String *wkt = args[0]->val_str(str);
+ Geometry geom;
+
+ 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),
+ default_charset_info);
+ return str;
+}
+
+
+String *Item_func_envelope::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ Geometry geom;
+
+ null_value = args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ geom.envelope(str);
+
+ return null_value ? 0 : str;
+}
+
+
+String *Item_func_centroid::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ Geometry geom;
+
+ null_value = args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,centroid) ||
+ geom.centroid(str);
+
+ return null_value ? 0: str;
+}
+
+
+/***********************************************
+ Spatial decomposition functions
+***********************************************/
+
+String *Item_func_spatial_decomp::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ Geometry geom;
+
+ if ((null_value = (args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()))))
+ return 0;
+
+ null_value=1;
+ switch(decomp_func)
+ {
+ case SP_STARTPOINT:
+ if (!GEOM_METHOD_PRESENT(geom,start_point) || geom.start_point(str))
+ goto ret;
+ break;
+
+ case SP_ENDPOINT:
+ if (!GEOM_METHOD_PRESENT(geom,end_point) || geom.end_point(str))
+ goto ret;
+ break;
+
+ case SP_EXTERIORRING:
+ if (!GEOM_METHOD_PRESENT(geom,exterior_ring) || geom.exterior_ring(str))
+ goto ret;
+ break;
+
+ default:
+ goto ret;
+ }
+ null_value=0;
+
+ret:
+ return null_value ? 0 : str;
+}
+
+
+String *Item_func_spatial_decomp_n::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ long n = (long) args[1]->val_int();
+ Geometry geom;
+
+ if ((null_value = (args[0]->null_value ||
+ args[1]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) )))
+ return 0;
+
+ null_value=1;
+
+ switch(decomp_func_n)
+ {
+ case SP_POINTN:
+ 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) ||
+ geom.geometry_n(n,str))
+ goto ret;
+ break;
+
+ case SP_INTERIORRINGN:
+ if (!GEOM_METHOD_PRESENT(geom,interior_ring_n) ||
+ geom.interior_ring_n(n,str))
+ goto ret;
+ break;
+
+ default:
+ goto ret;
+ }
+ null_value=0;
+
+ret:
+ return null_value ? 0 : str;
+}
+
+
+
+/***********************************************
+Functions to concatinate various spatial objects
+************************************************/
+
+
+/*
+* Concatinate doubles into Point
+*/
+
+
+String *Item_func_point::val_str(String *str)
+{
+ if ( (null_value = (args[0]->null_value ||
+ args[1]->null_value ||
+ str->realloc(1+4+8+8))))
+ return 0;
+
+ str->length(0);
+ str->q_append((char)Geometry::wkbNDR);
+ str->q_append((uint32)Geometry::wkbPoint);
+ str->q_append((double)args[0]->val());
+ str->q_append((double)args[1]->val());
+ return str;
+}
+
+
+/*
+ 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,
+ we do not check wkb type of items, any is valid.
+*/
+
+String *Item_func_spatial_collection::val_str(String *str)
+{
+ uint i;
+
+ null_value=1;
+
+ str->length(0);
+ if(str->reserve(9,512))
+ return 0;
+
+ str->q_append((char)Geometry::wkbNDR);
+ str->q_append((uint32)coll_type);
+ str->q_append((uint32)arg_count);
+
+ for (i = 0; i < arg_count; ++i)
+ {
+ if (args[i]->null_value)
+ goto ret;
+
+ String *res = args[i]->val_str(str);
+
+ if ( coll_type == Geometry::wkbGeometryCollection )
+ {
+ /*
+ 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
+ {
+ enum Geometry::wkbType wkb_type;
+ uint32 len=res->length();
+ const char *data=res->ptr()+1;
+
+ /*
+ 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);
+ data+=4;
+ 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)
+ goto ret;
+
+ data+=WKB_HEADER_SIZE;
+ len-=WKB_HEADER_SIZE;
+ if (str->reserve(len,512))
+ goto ret;
+ str->q_append(data,len);
+ break;
+
+ case Geometry::wkbLineString:
+ if (str->reserve(POINT_DATA_SIZE,512))
+ goto ret;
+ str->q_append(data,POINT_DATA_SIZE);
+ break;
+
+ case Geometry::wkbPolygon:
+ {
+ uint32 n_points;
+ double x1, y1, x2, y2;
+
+ 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;
+ }
+ }
+ }
+
+ if (str->length() > current_thd->variables.max_allowed_packet)
+ goto ret;
+
+ null_value = 0;
+
+ret:
+ return null_value ? 0 : str;
+}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 181aa8fb6ba..2b308630b48 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -35,10 +35,8 @@ public:
double val();
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
- unsigned int size_of() { return sizeof(*this);}
};
-
class Item_func_md5 :public Item_str_func
{
String tmp_value;
@@ -47,7 +45,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "md5"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -88,7 +85,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "concat"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_concat_ws :public Item_str_func
@@ -103,13 +99,19 @@ public:
String *val_str(String *);
void fix_length_and_dec();
void update_used_tables();
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- return (separator->fix_fields(thd,tlist)
- || Item_func::fix_fields(thd,tlist));
+ return (separator->fix_fields(thd, tlist, &separator)
+ || Item_func::fix_fields(thd, tlist, ref));
}
const char *func_name() const { return "concat_ws"; }
- unsigned int size_of() { return sizeof(*this);}
+ 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
@@ -130,7 +132,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "replace"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -143,7 +144,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "insert"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -190,7 +190,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "right"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -203,7 +202,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "substr"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -215,7 +213,6 @@ public:
String *val_str(String *);
void fix_length_and_dec() { max_length= args[0]->max_length; }
const char *func_name() const { return "substr_index"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -227,7 +224,6 @@ public:
String *val_str(String *);
void fix_length_and_dec() { max_length= args[0]->max_length; }
const char *func_name() const { return "ltrim"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -239,7 +235,6 @@ public:
String *val_str(String *);
void fix_length_and_dec() { max_length= args[0]->max_length; }
const char *func_name() const { return "rtrim"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_trim :public Item_str_func
@@ -250,7 +245,6 @@ public:
String *val_str(String *);
void fix_length_and_dec() { max_length= args[0]->max_length; }
const char *func_name() const { return "trim"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -262,7 +256,6 @@ public:
String *val_str(String *);
void fix_length_and_dec() { max_length = 16; }
const char *func_name() const { return "password"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_des_encrypt :public Item_str_func
@@ -275,7 +268,6 @@ public:
void fix_length_and_dec()
{ maybe_null=1; max_length = args[0]->max_length+8; }
const char *func_name() const { return "des_encrypt"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_des_decrypt :public Item_str_func
@@ -287,7 +279,6 @@ public:
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; }
const char *func_name() const { return "des_decrypt"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_encrypt :public Item_str_func
@@ -298,7 +289,6 @@ public:
Item_func_encrypt(Item *a, Item *b): Item_str_func(a,b) {}
String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length = 13; }
- unsigned int size_of() { return sizeof(*this);}
};
#include "sql_crypt.h"
@@ -312,7 +302,6 @@ public:
Item_str_func(a),sql_crypt(seed) {}
String *val_str(String *);
void fix_length_and_dec();
- unsigned int size_of() { return sizeof(*this);}
};
class Item_func_decode :public Item_func_encode
@@ -328,7 +317,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"; }
};
@@ -337,7 +330,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"; }
};
@@ -350,7 +347,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "soundex"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -364,14 +360,21 @@ public:
double val();
longlong val_int();
String *val_str(String *str);
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ return (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"; }
- unsigned int size_of() { return sizeof(*this);}
+ 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));
+ }
};
@@ -384,14 +387,21 @@ public:
Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {}
~Item_func_make_set() { delete item; }
String *val_str(String *str);
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
- return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ return (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"; }
- unsigned int size_of() { return sizeof(*this);}
+ 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));
+ }
};
@@ -406,7 +416,6 @@ public:
max_length=args[0]->max_length+(args[0]->max_length-args[0]->decimals)/3;
}
const char *func_name() const { return "format"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -415,7 +424,7 @@ class Item_func_char :public Item_str_func
public:
Item_func_char(List<Item> &list) :Item_str_func(list) {}
String *val_str(String *);
- void fix_length_and_dec() { maybe_null=0; max_length=arg_count; binary=0;}
+ void fix_length_and_dec() { maybe_null=0; max_length=arg_count; }
const char *func_name() const { return "char"; }
};
@@ -428,7 +437,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "repeat"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -441,7 +449,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "rpad"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -454,7 +461,6 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "lpad"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -476,7 +482,6 @@ public:
const char *func_name() const { return "hex"; }
String *val_str(String *);
void fix_length_and_dec() { decimals=0; max_length=args[0]->max_length*2; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -491,7 +496,11 @@ public:
null_value=args[0]->null_value;
return tmp;
}
- void fix_length_and_dec() { binary=1; max_length=args[0]->max_length; }
+ void fix_length_and_dec()
+ {
+ set_charset(my_charset_bin);
+ max_length=args[0]->max_length;
+ }
void print(String *str) { print_op(str); }
};
@@ -504,8 +513,11 @@ public:
String *val_str(String *);
const char *func_name() const { return "load_file"; }
void fix_length_and_dec()
- { binary=1; maybe_null=1; max_length=MAX_BLOB_WIDTH;}
- unsigned int size_of() { return sizeof(*this);}
+ {
+ set_charset(my_charset_bin);
+ maybe_null=1;
+ max_length=MAX_BLOB_WIDTH;
+ }
};
@@ -520,7 +532,7 @@ class Item_func_export_set: public Item_str_func
const char *func_name() const { return "export_set"; }
};
- class Item_func_inet_ntoa : public Item_str_func
+class Item_func_inet_ntoa : public Item_str_func
{
public:
Item_func_inet_ntoa(Item *a) :Item_str_func(a)
@@ -539,3 +551,245 @@ public:
String *val_str(String *);
void fix_length_and_dec() { max_length= args[0]->max_length * 2 + 2; }
};
+
+class Item_func_conv_charset :public Item_str_func
+{
+ CHARSET_INFO *conv_charset;
+public:
+ Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
+ { conv_charset=cs; }
+ bool fix_fields(THD *thd,struct st_table_list *tables,Item **ref);
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "conv_charset"; }
+};
+
+class Item_func_set_collation :public Item_str_func
+{
+ CHARSET_INFO *set_collation;
+public:
+ Item_func_set_collation(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
+ { set_collation=cs; }
+ bool fix_fields(THD *thd,struct st_table_list *tables, Item **ref);
+ String *val_str(String *);
+ void fix_length_and_dec()
+ { max_length = args[0]->max_length; }
+ bool eq(const Item *item, bool binary_cmp) const;
+ const char *func_name() const { return "set_collation"; }
+};
+
+class Item_func_conv_charset3 :public Item_str_func
+{
+public:
+ Item_func_conv_charset3(Item *arg1,Item *arg2,Item *arg3)
+ :Item_str_func(arg1,arg2,arg3) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "conv_charset3"; }
+};
+
+class Item_func_charset :public Item_str_func
+{
+public:
+ Item_func_charset(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ const char *func_name() const { return "charset"; }
+ void fix_length_and_dec()
+ {
+ max_length=40; // should be enough
+ set_charset(thd_charset());
+ };
+};
+
+
+/*******************************************************
+Spatial functions
+********************************************************/
+
+class Item_func_geometry_from_text :public Item_str_func
+{
+public:
+ Item_func_geometry_from_text(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "geometryfromtext"; }
+ String *val_str(String *);
+ void fix_length_and_dec();
+};
+
+class Item_func_as_text :public Item_str_func
+{
+public:
+ Item_func_as_text(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "astext"; }
+ String *val_str(String *);
+ void fix_length_and_dec();
+};
+
+class Item_func_geometry_type :public Item_str_func
+{
+public:
+ Item_func_geometry_type(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ const char *func_name() const { return "geometrytype"; }
+ void fix_length_and_dec()
+ {
+ max_length=20; // "GeometryCollection" is the most long
+ };
+};
+
+class Item_func_centroid :public Item_str_func
+{
+public:
+ Item_func_centroid(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "centroid"; }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_envelope :public Item_str_func
+{
+public:
+ Item_func_envelope(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "envelope"; }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_point :public Item_str_func
+{
+public:
+ Item_func_point(Item *a,Item *b) :Item_str_func(a,b) {}
+ const char *func_name() const { return "point"; }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_spatial_decomp :public Item_str_func
+{
+ enum Functype decomp_func;
+public:
+ Item_func_spatial_decomp(Item *a, Item_func::Functype ft) :
+ Item_str_func(a) { decomp_func = ft; }
+ const char *func_name() const
+ {
+ switch (decomp_func)
+ {
+ case SP_STARTPOINT:
+ return "startpoint";
+ case SP_ENDPOINT:
+ return "endpoint";
+ case SP_EXTERIORRING:
+ return "exteriorring";
+ default:
+ return "spatial_decomp_unknown";
+ }
+ }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_spatial_decomp_n :public Item_str_func
+{
+ enum Functype decomp_func_n;
+public:
+ Item_func_spatial_decomp_n(Item *a, Item *b, Item_func::Functype ft) :
+ Item_str_func(a, b) { decomp_func_n = ft; }
+ const char *func_name() const
+ {
+ switch (decomp_func_n)
+ {
+ case SP_POINTN:
+ return "pointn";
+ case SP_GEOMETRYN:
+ return "geometryn";
+ case SP_INTERIORRINGN:
+ return "interiorringn";
+ default:
+ return "spatial_decomp_n_unknown";
+ }
+ }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+
+class Item_func_spatial_collection :public Item_str_func
+{
+ String tmp_value;
+ enum Geometry::wkbType coll_type;
+ enum Geometry::wkbType item_type;
+public:
+ Item_func_spatial_collection(
+ List<Item> &list, enum Geometry::wkbType ct, enum Geometry::wkbType it) :
+ Item_str_func(list)
+ {
+ coll_type=ct;
+ item_type=it;
+ }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multipoint"; }
+};
+
+
+/*
+class Item_func_multipoint :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_multipoint(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multipoint"; }
+};
+
+class Item_func_linestring :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_linestring(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "linestring"; }
+};
+
+class Item_func_multilinestring :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_multilinestring(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multilinestring"; }
+};
+
+class Item_func_polygon :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_polygon(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "polygon"; }
+};
+
+class Item_func_multipolygon :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_multipolygon(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multipolygon"; }
+};
+
+class Item_func_geometrycollection :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_geometrycollection(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "geometrycollection"; }
+};
+
+*/
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
new file mode 100644
index 00000000000..1f1944026ef
--- /dev/null
+++ b/sql/item_subselect.cc
@@ -0,0 +1,380 @@
+/* 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 */
+
+/*
+ subselect Item
+
+SUBSELECT TODO:
+ - add function from mysql_select that use JOIN* as parameter to JOIN methods
+ (sql_select.h/sql_select.cc)
+ - remove double 'having' & 'having_list' from JOIN
+ (sql_select.h/sql_select.cc)
+
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+
+Item_subselect::Item_subselect():
+ Item_result_field(), engine_owner(1), value_assigned(0)
+{
+ assign_null();
+ /*
+ item value is NULL if select_subselect not changed this value
+ (i.e. some rows will be found returned)
+ */
+ null_value= 1;
+}
+
+void Item_subselect::init(THD *thd, st_select_lex *select_lex,
+ select_subselect *result)
+{
+
+ DBUG_ENTER("Item_subselect::init");
+ DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
+
+ if (select_lex->next_select())
+ engine= new subselect_union_engine(thd, select_lex->master_unit(), result,
+ this);
+ else
+ engine= new subselect_single_select_engine(thd, select_lex, result,
+ this);
+ DBUG_VOID_RETURN;
+}
+
+Item_subselect::~Item_subselect()
+{
+ if (engine_owner)
+ delete engine;
+}
+
+void Item_subselect::make_field (Send_field *tmp_field)
+{
+ if (null_value)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_NULL);
+ tmp_field->length=4;
+ } else {
+ init_make_field(tmp_field, ((result_type() == STRING_RESULT) ?
+ FIELD_TYPE_VAR_STRING :
+ (result_type() == INT_RESULT) ?
+ FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE));
+ }
+}
+
+bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+{
+ 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));
+ return 1;
+ }
+ fix_length_and_dec();
+ }
+ 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();
+}
+
+inline table_map Item_subselect::used_tables() const
+{
+ return (table_map) engine->depended() ? 1L : 0L;
+}
+
+Item_singleval_subselect::Item_singleval_subselect(THD *thd,
+ st_select_lex *select_lex):
+ Item_subselect()
+{
+ init(thd, select_lex, new select_singleval_subselect(this));
+ max_columns= 1;
+ maybe_null= 1;
+}
+
+void Item_singleval_subselect::fix_length_and_dec()
+{
+ engine->fix_length_and_dec();
+ res_type= engine->type();
+}
+
+Item::Type Item_subselect::type() const
+{
+ return SUBSELECT_ITEM;
+}
+
+double Item_singleval_subselect::val ()
+{
+ if (engine->exec())
+ {
+ assign_null();
+ return 0;
+ }
+ return real_value;
+}
+
+longlong Item_singleval_subselect::val_int ()
+{
+ if (engine->exec())
+ {
+ assign_null();
+ return 0;
+ }
+ return int_value;
+}
+
+String *Item_singleval_subselect::val_str (String *str)
+{
+ if (engine->exec() || null_value)
+ {
+ assign_null();
+ return 0;
+ }
+ return &string_value;
+}
+
+Item_exists_subselect::Item_exists_subselect(THD *thd,
+ st_select_lex *select_lex):
+ Item_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
+}
+
+void Item_exists_subselect::fix_length_and_dec()
+{
+ max_length= 1;
+
+}
+
+double Item_exists_subselect::val ()
+{
+ if (engine->exec())
+ {
+ assign_null();
+ return 0;
+ }
+ return (double) value;
+}
+
+longlong Item_exists_subselect::val_int ()
+{
+ if (engine->exec())
+ {
+ assign_null();
+ return 0;
+ }
+ return value;
+}
+
+String *Item_exists_subselect::val_str(String *str)
+{
+ if (engine->exec())
+ {
+ assign_null();
+ return 0;
+ }
+ str->set(value,thd_charset());
+ return str;
+}
+
+
+subselect_single_select_engine::subselect_single_select_engine(THD *thd,
+ st_select_lex *select,
+ select_subselect *result,
+ Item_subselect *item):
+ subselect_engine(thd, item, result),
+ prepared(0), optimized(0), executed(0)
+{
+ select_lex= select;
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ 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->select_limit_cnt= HA_POS_ERROR; // no limit
+ if (unit->select_limit_cnt == HA_POS_ERROR)
+ select_lex->options&= ~OPTION_FOUND_ROWS;
+ join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
+ if (!join || !result)
+ {
+ //out of memory
+ 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;
+}
+
+subselect_union_engine::subselect_union_engine(THD *thd,
+ st_select_lex_unit *u,
+ select_subselect *result,
+ Item_subselect *item):
+ subselect_engine(thd, item, result)
+{
+ unit= u;
+ if( !result)
+ {
+ //out of memory
+ thd->fatal_error= 1;
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ }
+ unit->item= item;
+}
+
+int subselect_single_select_engine::prepare()
+{
+ if (prepared)
+ return 0;
+ prepared= 1;
+ SELECT_LEX_NODE *save_select= thd->lex.current_select;
+ thd->lex.current_select= select_lex;
+ if(join->prepare((TABLE_LIST*) select_lex->table_list.first,
+ select_lex->where,
+ (ORDER*) select_lex->order_list.first,
+ (ORDER*) select_lex->group_list.first,
+ select_lex->having,
+ (ORDER*) 0, select_lex,
+ select_lex->master_unit(), 0))
+ return 1;
+ thd->lex.current_select= save_select;
+ return 0;
+}
+
+int subselect_union_engine::prepare()
+{
+ return unit->prepare(thd, result);
+}
+
+void subselect_single_select_engine::fix_length_and_dec()
+{
+ List_iterator_fast<Item> li(select_lex->item_list);
+ Item *sel_item= li++;
+ item->max_length= sel_item->max_length;
+ res_type= sel_item->result_type();
+ item->decimals= sel_item->decimals;
+}
+
+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())
+ {
+ List_iterator_fast<Item> li(sl->item_list);
+ Item *s_item= li++;
+ if ((len= s_item->max_length))
+ mlen= len;
+ if (!sel_item)
+ sel_item= s_item;
+ }
+ item->max_length= mlen;
+ res_type= sel_item->result_type();
+ item->decimals= sel_item->decimals;
+}
+
+int subselect_single_select_engine::exec()
+{
+ DBUG_ENTER("subselect_single_select_engine::exec");
+ if (!optimized)
+ {
+ optimized=1;
+ if (join->optimize())
+ {
+ executed= 1;
+ DBUG_RETURN(join->error?join->error:1);
+ }
+ }
+ if (select_lex->dependent && executed)
+ {
+ if (join->reinit())
+ DBUG_RETURN(1);
+ item->assign_null();
+ item->assigned((executed= 0));
+ }
+ if (!executed)
+ {
+ SELECT_LEX_NODE *save_select= join->thd->lex.current_select;
+ join->thd->lex.current_select= select_lex;
+ join->exec();
+ join->thd->lex.current_select= save_select;
+ executed= 1;
+ DBUG_RETURN(join->error||thd->fatal_error);
+ }
+ DBUG_RETURN(0);
+}
+
+int subselect_union_engine::exec()
+{
+ return unit->exec();
+}
+
+uint subselect_single_select_engine::cols()
+{
+ return select_lex->item_list.elements;
+}
+
+uint subselect_union_engine::cols()
+{
+ return unit->first_select()->item_list.elements;
+}
+
+bool subselect_single_select_engine::depended()
+{
+ return select_lex->dependent;
+}
+
+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);
+}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
new file mode 100644
index 00000000000..3ad6c68a6ba
--- /dev/null
+++ b/sql/item_subselect.h
@@ -0,0 +1,216 @@
+/* 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 */
+
+/* subselect Item */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+class st_select_lex;
+class st_select_lex_unit;
+class JOIN;
+class select_subselect;
+class subselect_engine;
+
+/* base class for subselects */
+
+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:
+ /* engine that perform execution of subselect (single select or union) */
+ subselect_engine *engine;
+ /* allowed number of columns (1 for single value subqueries) */
+ uint max_columns;
+
+public:
+ Item_subselect();
+ Item_subselect(Item_subselect *item)
+ {
+ null_value= item->null_value;
+ decimals= item->decimals;
+ max_columns= item->max_columns;
+ engine= item->engine;
+ engine_owner= 0;
+ name= item->name;
+ }
+
+ /*
+ We need this method, because some compilers do not allow 'this'
+ 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);
+
+ ~Item_subselect();
+ virtual void assign_null()
+ {
+ null_value= 1;
+ }
+ bool assigned() { return value_assigned; }
+ void assigned(bool a) { value_assigned= a; }
+ enum Type type() const;
+ bool is_null() { return null_value; }
+ void make_field (Send_field *);
+ 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
+{
+protected:
+ longlong int_value; /* Here stored integer value of this item */
+ double real_value; /* Here stored real value of this item */
+ /*
+ Here stored string value of this item.
+ (str_value used only as temporary buffer, because it can be changed
+ by Item::save_field)
+ */
+ String string_value;
+ enum Item_result res_type; /* type of results */
+
+public:
+ Item_singleval_subselect(THD *thd, st_select_lex *select_lex);
+ Item_singleval_subselect(Item_singleval_subselect *item):
+ Item_subselect(item)
+ {
+ int_value= item->int_value;
+ real_value= item->real_value;
+ string_value.set(item->string_value, 0, item->string_value.length());
+ max_length= item->max_length;
+ decimals= item->decimals;
+ res_type= item->res_type;
+ }
+ virtual void assign_null()
+ {
+ null_value= 1;
+ int_value= 0;
+ real_value= 0;
+ max_length= 4;
+ res_type= STRING_RESULT;
+ }
+ double val ();
+ longlong val_int ();
+ String *val_str (String *);
+ 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;
+};
+
+/* exists subselect */
+
+class Item_exists_subselect :public Item_subselect
+{
+protected:
+ longlong value; /* value of this item (boolean: exists/not-exists) */
+
+public:
+ Item_exists_subselect(THD *thd, st_select_lex *select_lex);
+ Item_exists_subselect(Item_exists_subselect *item):
+ Item_subselect(item)
+ {
+ value= item->value;
+ }
+ virtual void assign_null()
+ {
+ value= 0;
+ }
+
+ Item *new_item() { return new Item_exists_subselect(this); }
+ enum Item_result result_type() const { return INT_RESULT;}
+ longlong val_int();
+ double val();
+ String *val_str(String*);
+ void fix_length_and_dec();
+ friend class select_exists_subselect;
+};
+
+class subselect_engine
+{
+protected:
+ select_subselect *result; /* results storage class */
+ THD *thd; /* pointer to current THD */
+ Item_subselect *item; /* item, that use this engine */
+ enum Item_result res_type; /* type of results */
+public:
+ static void *operator new(size_t size)
+ {
+ return (void*) sql_alloc((uint) size);
+ }
+ static void operator delete(void *ptr, size_t size) {}
+
+ subselect_engine(THD *thd, Item_subselect *si, select_subselect *res)
+ {
+ result= res;
+ item= si;
+ this->thd= thd;
+ res_type= STRING_RESULT;
+ }
+
+ virtual int prepare()= 0;
+ virtual void fix_length_and_dec()= 0;
+ virtual int exec()= 0;
+ 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;
+};
+
+class subselect_single_select_engine: public subselect_engine
+{
+ my_bool prepared; /* simple subselect is prepared */
+ my_bool optimized; /* simple subselect is optimized */
+ my_bool executed; /* simple subselect is executed */
+ st_select_lex *select_lex; /* corresponding select_lex */
+ JOIN * join; /* corresponding JOIN structure */
+public:
+ subselect_single_select_engine(THD *thd, st_select_lex *select,
+ select_subselect *result,
+ Item_subselect *item);
+ int prepare();
+ void fix_length_and_dec();
+ int exec();
+ uint cols();
+ bool depended();
+ bool check_loop(uint id);
+};
+
+class subselect_union_engine: public subselect_engine
+{
+ st_select_lex_unit *unit; /* corresponding unit structure */
+public:
+ subselect_union_engine(THD *thd,
+ st_select_lex_unit *u,
+ select_subselect *result,
+ Item_subselect *item);
+ int prepare();
+ void fix_length_and_dec();
+ int exec();
+ uint cols();
+ bool depended();
+ bool check_loop(uint id);
+};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index bdf48b3ac54..db4c45fc412 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -60,8 +60,9 @@ void Item_sum::make_field(Send_field *tmp_field)
result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
FIELD_TYPE_VAR_STRING);
}
- tmp_field->table_name=(char*)"";
- tmp_field->col_name=name;
+ tmp_field->db_name=(char*)"";
+ tmp_field->org_table_name=tmp_field->table_name=(char*)"";
+ tmp_field->org_col_name=tmp_field->col_name=name;
}
void Item_sum::print(String *str)
@@ -92,7 +93,7 @@ Item_sum_num::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -105,13 +106,13 @@ Item_sum_int::val_str(String *str)
return 0;
char buff[21];
uint length= (uint) (longlong10_to_str(nr,buff,-10)-buff);
- str->copy(buff,length);
+ str->copy(buff,length,thd_charset());
return str;
}
bool
-Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables)
+Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (!thd->allow_sum_func)
{
@@ -123,7 +124,7 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables)
maybe_null=0;
for (uint i=0 ; i < arg_count ; i++)
{
- if (args[i]->fix_fields(thd,tables))
+ if (args[i]->fix_fields(thd, tables, args + i))
return 1;
if (decimals < args[i]->decimals)
decimals=args[i]->decimals;
@@ -139,7 +140,7 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables)
bool
-Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
+Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
Item *item=args[0];
if (!thd->allow_sum_func)
@@ -148,7 +149,7 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
return 1;
}
thd->allow_sum_func=0; // No included group funcs
- if (item->fix_fields(thd,tables))
+ if (item->fix_fields(thd, tables, args))
return 1;
hybrid_type=item->result_type();
if (hybrid_type == INT_RESULT)
@@ -159,7 +160,6 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
max_length=item->max_length;
decimals=item->decimals;
maybe_null=item->maybe_null;
- binary=item->binary;
unsigned_flag=item->unsigned_flag;
result_field=0;
null_value=1;
@@ -359,13 +359,13 @@ Item_sum_hybrid::val_str(String *str)
case STRING_RESULT:
return &value;
case REAL_RESULT:
- str->set(sum,decimals);
+ str->set(sum,decimals,thd_charset());
break;
case INT_RESULT:
if (unsigned_flag)
- str->set((ulonglong) sum_int);
+ str->set((ulonglong) sum_int,thd_charset());
else
- str->set((longlong) sum_int);
+ str->set((longlong) sum_int,thd_charset());
break;
}
return str; // Keep compiler happy
@@ -379,7 +379,7 @@ bool Item_sum_min::add()
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
(null_value ||
- (binary ? stringcmp(&value,result) : sortcmp(&value,result)) > 0))
+ (binary() ? stringcmp(&value,result) : sortcmp(&value,result)) > 0))
{
value.copy(*result);
null_value=0;
@@ -422,7 +422,7 @@ bool Item_sum_max::add()
String *result=args[0]->val_str(&tmp_value);
if (!args[0]->null_value &&
(null_value ||
- (binary ? stringcmp(&value,result) : sortcmp(&value,result)) < 0))
+ (binary() & MY_CS_BINSORT ? stringcmp(&value,result) : sortcmp(&value,result)) < 0))
{
value.copy(*result);
null_value=0;
@@ -513,7 +513,7 @@ void Item_sum_hybrid::reset_field()
if (hybrid_type == STRING_RESULT)
{
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
res=args[0]->val_str(&tmp);
if (args[0]->null_value)
@@ -524,7 +524,7 @@ void Item_sum_hybrid::reset_field()
else
{
result_field->set_notnull();
- result_field->store(res->ptr(),res->length());
+ result_field->store(res->ptr(),res->length(),tmp.charset());
}
}
else if (hybrid_type == INT_RESULT)
@@ -692,9 +692,9 @@ Item_sum_hybrid::min_max_update_str_field(int offset)
result_field->ptr-=offset;
if (result_field->is_null() ||
- (cmp_sign * (binary ? stringcmp(res_str,&tmp_value) :
+ (cmp_sign * (binary() ? stringcmp(res_str,&tmp_value) :
sortcmp(res_str,&tmp_value)) < 0))
- result_field->store(res_str->ptr(),res_str->length());
+ result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
else
{ // Use old value
char *res=result_field->ptr;
@@ -810,7 +810,7 @@ String *Item_avg_field::val_str(String *str)
double nr=Item_avg_field::val();
if (null_value)
return 0;
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -847,7 +847,7 @@ String *Item_std_field::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -864,7 +864,10 @@ static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
static int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
- return my_sortcmp((char*) key1, (char*) key2, *(uint*) arg);
+ /* BAR TODO: remove default_charset_info */
+ return my_strnncoll(default_charset_info,
+ (const uchar*) key1, *(uint*) arg,
+ (const uchar*) key2, *(uint*) arg);
}
/*
@@ -928,9 +931,10 @@ Item_sum_count_distinct::~Item_sum_count_distinct()
}
-bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
+ Item **ref)
{
- if (Item_sum_num::fix_fields(thd,tables) ||
+ if (Item_sum_num::fix_fields(thd, tables, ref) ||
!(tmp_table_param= new TMP_TABLE_PARAM))
return 1;
return 0;
@@ -939,6 +943,10 @@ bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables)
bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
+ SELECT_LEX *select_lex= current_lex->current_select->select_lex();
+ if (select_lex->linkage == GLOBAL_OPTIONS_TYPE)
+ return 1;
+
/* Create a table with an unique key over all parameters */
for (uint i=0; i < arg_count ; i++)
{
@@ -960,9 +968,10 @@ bool Item_sum_count_distinct::setup(THD *thd)
free_tmp_table(thd, table);
tmp_table_param->cleanup();
}
- if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
- 0, 0,
- current_lex->select->options | thd->options)))
+ if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
+ 0, 0,
+ select_lex->options | thd->options,
+ select_lex->master_unit())))
return 1;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
@@ -1106,7 +1115,7 @@ bool Item_sum_count_distinct::add()
if (tree_to_myisam())
return 1;
}
- else if (!tree_insert(&tree, table->record[0] + rec_offset, 0))
+ 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])))
@@ -1168,7 +1177,7 @@ String *Item_sum_udf_float::val_str(String *str)
if (null_value)
return 0; /* purecov: inspected */
else
- str->set(nr,decimals);
+ str->set(nr,decimals,thd_charset());
return str;
}
@@ -1187,7 +1196,7 @@ String *Item_sum_udf_int::val_str(String *str)
if (null_value)
return 0;
else
- str->set(nr);
+ str->set(nr,thd_charset());
return str;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 2cf92343ebb..3e67f1e3624 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -70,7 +70,6 @@ public:
void print(String *str);
void fix_num_length_and_dec();
virtual bool setup(THD *thd) {return 0;}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -81,11 +80,10 @@ public:
Item_sum_num(Item *item_par) :Item_sum(item_par) {}
Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {}
Item_sum_num(List<Item> &list) :Item_sum(list) {}
- bool fix_fields(THD *,struct st_table_list *);
+ bool fix_fields(THD *, TABLE_LIST *, Item **);
longlong val_int() { return (longlong) val(); } /* Real as default */
String *val_str(String*str);
void reset_field();
- unsigned int size_of() { return sizeof(*this);}
};
@@ -100,7 +98,6 @@ public:
double val() { return (double) val_int(); }
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -118,7 +115,6 @@ class Item_sum_sum :public Item_sum_num
void reset_field();
void update_field(int offset);
const char *func_name() const { return "sum"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -141,7 +137,6 @@ class Item_sum_count :public Item_sum_int
void reset_field();
void update_field(int offset);
const char *func_name() const { return "count"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -151,7 +146,7 @@ class Item_sum_count_distinct :public Item_sum_int
{
TABLE *table;
table_map used_table_cache;
- bool fix_fields(THD *thd,TABLE_LIST *tables);
+ bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
uint32 *field_lengths;
TMP_TABLE_PARAM *tmp_table_param;
TREE tree;
@@ -193,7 +188,6 @@ class Item_sum_count_distinct :public Item_sum_int
void update_field(int offset) { return ; } // Never called
const char *func_name() const { return "count_distinct"; }
bool setup(THD *thd);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -213,7 +207,6 @@ public:
String *val_str(String*);
void make_field(Send_field *field);
void fix_length_and_dec() {}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -235,7 +228,6 @@ class Item_sum_avg :public Item_sum_num
Item *result_item(Field *field)
{ return new Item_avg_field(this); }
const char *func_name() const { return "avg"; }
- unsigned int size_of() { return sizeof(*this);}
};
class Item_sum_std;
@@ -252,7 +244,6 @@ public:
bool is_null() { (void) val_int(); return null_value; }
void make_field(Send_field *field);
void fix_length_and_dec() {}
- unsigned int size_of() { return sizeof(*this);}
};
class Item_sum_std :public Item_sum_num
@@ -273,7 +264,6 @@ class Item_sum_std :public Item_sum_num
Item *result_item(Field *field)
{ return new Item_std_field(this); }
const char *func_name() const { return "std"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -293,7 +283,7 @@ class Item_sum_hybrid :public Item_sum
Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par),cmp_sign(sign),
used_table_cache(~(table_map) 0)
{}
- bool fix_fields(THD *,struct st_table_list *);
+ bool fix_fields(THD *, TABLE_LIST *, Item **);
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
@@ -316,7 +306,6 @@ class Item_sum_hybrid :public Item_sum
void min_max_update_str_field(int offset);
void min_max_update_real_field(int offset);
void min_max_update_int_field(int offset);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -328,7 +317,6 @@ public:
bool add();
const char *func_name() const { return "min"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -340,7 +328,6 @@ public:
bool add();
const char *func_name() const { return "max"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -356,7 +343,6 @@ class Item_sum_bit :public Item_sum_int
void reset();
longlong val_int();
void reset_field();
- unsigned int size_of() { return sizeof(*this);}
};
@@ -367,7 +353,6 @@ class Item_sum_or :public Item_sum_bit
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_or"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -378,7 +363,6 @@ class Item_sum_and :public Item_sum_bit
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_and"; }
- unsigned int size_of() { return sizeof(*this);}
};
/*
@@ -398,7 +382,7 @@ public:
{ quick_group=0;}
~Item_udf_sum() {}
const char *func_name() const { return udf.name(); }
- bool fix_fields(THD *thd,struct st_table_list *tables)
+ bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
}
@@ -409,7 +393,6 @@ public:
bool add();
void reset_field() {};
void update_field(int offset_arg) {};
- unsigned int size_of() { return sizeof(*this);}
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index ccbba3777c4..7c085a1b25a 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -29,11 +29,31 @@
** Todo: Move month and days to language files
*/
-static String month_names[] = { "January", "February", "March", "April",
- "May", "June", "July", "August",
- "September", "October", "November", "December" };
-static String day_names[] = { "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday" ,"Sunday" };
+static String month_names[] =
+{
+ 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", 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)
+};
/*
** Get a array of positive numbers from a string object.
@@ -49,16 +69,16 @@ bool get_interval_info(const char *str,uint length,uint count,
{
const char *end=str+length;
uint i;
- while (str != end && !isdigit(*str))
+ while (str != end && !my_isdigit(system_charset_info,*str))
str++;
for (i=0 ; i < count ; i++)
{
long value;
- for (value=0; str != end && isdigit(*str) ; str++)
+ for (value=0; str != end && my_isdigit(system_charset_info,*str) ; str++)
value=value*10L + (long) (*str - '0');
values[i]= value;
- while (str != end && !isdigit(*str))
+ while (str != end && !my_isdigit(system_charset_info,*str))
str++;
if (str == end && i != count-1)
{
@@ -133,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
@@ -227,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;
}
@@ -302,7 +328,7 @@ static bool get_interval_value(Item *args,interval_type int_type,
/* record negative intervalls in t->neg */
str=res->ptr();
const char *end=str+res->length();
- while (str != end && isspace(*str))
+ while (str != end && my_isspace(system_charset_info,*str))
str++;
if (str != end && *str == '-')
{
@@ -389,21 +415,21 @@ String *Item_date::val_str(String *str)
return (String*) 0;
if (!value) // zero daynr
{
- str->copy("0000-00-00");
+ 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;
}
-bool Item_date::save_in_field(Field *field)
+int Item_date::save_in_field(Field *field)
{
TIME ltime;
timestamp_type t_type=TIMESTAMP_FULL;
@@ -435,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+
@@ -460,28 +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));
- sprintf(buff,"%02d:%02d:%02d",
- (int) start->tm_hour,
- (int) start->tm_min,
- (int) start->tm_sec);
- buff_length=(uint) strlen(buff);
+
+ buff_length=cs->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d",
+ (int) start->tm_hour,
+ (int) start->tm_min,
+ (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+
@@ -490,14 +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)));
- sprintf(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);
- buff_length=(uint) strlen(buff);
+
+ 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);
/* For getdate */
ltime.year= start->tm_year+1900;
ltime.month= start->tm_mon+1;
@@ -518,7 +567,7 @@ bool Item_func_now::get_date(TIME *res,
}
-bool Item_func_now::save_in_field(Field *to)
+int Item_func_now::save_in_field(Field *to)
{
to->set_notnull();
to->store_time(&ltime,TIMESTAMP_FULL);
@@ -528,9 +577,10 @@ bool 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;
if ((null_value=args[0]->null_value))
return (String*) 0;
if (seconds < 0)
@@ -539,9 +589,9 @@ String *Item_func_sec_to_time::val_str(String *str)
sign= "-";
}
uint sec= (uint) ((ulonglong) seconds % 3600);
- sprintf(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600),
- sec/60, sec % 60);
- str->copy(buff,(uint) strlen(buff));
+ length= my_sprintf(buff,(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600),
+ sec/60, sec % 60));
+ str->copy(buff, length, my_charset_latin1, thd_charset());
return str;
}
@@ -651,6 +701,7 @@ String *Item_func_date_format::val_str(String *str)
TIME l_time;
char intbuff[15];
uint size,weekday;
+ ulong length;
if (!date_or_time)
{
@@ -743,40 +794,39 @@ String *Item_func_date_format::val_str(String *str)
null_value=1;
return 0;
}
- sprintf(intbuff,"%d",l_time.day);
- str->append(intbuff);
+ length= my_sprintf(intbuff, (intbuff,"%d",l_time.day));
+ str->append(intbuff, length);
if (l_time.day >= 10 && l_time.day <= 19)
str->append("th");
else
{
- switch (l_time.day %10)
- {
+ switch (l_time.day %10) {
case 1:
- str->append("st");
+ str->append("st",2);
break;
case 2:
- str->append("nd");
+ str->append("nd",2);
break;
case 3:
- str->append("rd");
+ str->append("rd",2);
break;
default:
- str->append("th");
+ str->append("th",2);
break;
}
}
break;
case 'Y':
sprintf(intbuff,"%04d",l_time.year);
- str->append(intbuff);
+ str->append(intbuff,4);
break;
case 'y':
sprintf(intbuff,"%02d",l_time.year%100);
- str->append(intbuff);
+ str->append(intbuff,2);
break;
case 'm':
sprintf(intbuff,"%02d",l_time.month);
- str->append(intbuff);
+ str->append(intbuff,2);
break;
case 'c':
sprintf(intbuff,"%d",l_time.month);
@@ -784,7 +834,7 @@ String *Item_func_date_format::val_str(String *str)
break;
case 'd':
sprintf(intbuff,"%02d",l_time.day);
- str->append(intbuff);
+ str->append(intbuff,2);
break;
case 'e':
sprintf(intbuff,"%d",l_time.day);
@@ -792,16 +842,16 @@ String *Item_func_date_format::val_str(String *str)
break;
case 'H':
sprintf(intbuff,"%02d",l_time.hour);
- str->append(intbuff);
+ str->append(intbuff,2);
break;
case 'h':
case 'I':
sprintf(intbuff,"%02d", (l_time.hour+11)%12+1);
- str->append(intbuff);
+ str->append(intbuff,2);
break;
case 'i': /* minutes */
sprintf(intbuff,"%02d",l_time.minute);
- str->append(intbuff);
+ str->append(intbuff,2);
break;
case 'j':
if (date_or_time)
@@ -812,7 +862,7 @@ String *Item_func_date_format::val_str(String *str)
sprintf(intbuff,"%03d",
(int) (calc_daynr(l_time.year,l_time.month,l_time.day) -
calc_daynr(l_time.year,1,1)) + 1);
- str->append(intbuff);
+ str->append(intbuff,3);
break;
case 'k':
sprintf(intbuff,"%d",l_time.hour);
@@ -823,7 +873,7 @@ String *Item_func_date_format::val_str(String *str)
str->append(intbuff);
break;
case 'p':
- str->append(l_time.hour < 12 ? "AM" : "PM");
+ str->append(l_time.hour < 12 ? "AM" : "PM",2);
break;
case 'r':
sprintf(intbuff,(l_time.hour < 12) ? "%02d:%02d:%02d AM" :
@@ -837,7 +887,8 @@ String *Item_func_date_format::val_str(String *str)
str->append(intbuff);
break;
case 'T':
- sprintf(intbuff,"%02d:%02d:%02d",l_time.hour,l_time.minute,l_time.second);
+ sprintf(intbuff,"%02d:%02d:%02d", l_time.hour, l_time.minute,
+ l_time.second);
str->append(intbuff);
break;
case 'U':
@@ -845,7 +896,7 @@ String *Item_func_date_format::val_str(String *str)
{
uint year;
sprintf(intbuff,"%02d",calc_week(&l_time, 0, (*ptr) == 'U', &year));
- str->append(intbuff);
+ str->append(intbuff,2);
}
break;
case 'v':
@@ -853,7 +904,7 @@ String *Item_func_date_format::val_str(String *str)
{
uint year;
sprintf(intbuff,"%02d",calc_week(&l_time, 1, (*ptr) == 'V', &year));
- str->append(intbuff);
+ str->append(intbuff,2);
}
break;
case 'x':
@@ -862,13 +913,13 @@ String *Item_func_date_format::val_str(String *str)
uint year;
(void) calc_week(&l_time, 1, (*ptr) == 'X', &year);
sprintf(intbuff,"%04d",year);
- str->append(intbuff);
+ str->append(intbuff,4);
}
break;
case 'w':
weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1);
- sprintf(intbuff,"%01d",weekday);
- str->append(intbuff);
+ sprintf(intbuff,"%d",weekday);
+ str->append(intbuff,1);
break;
default:
str->append(*ptr);
@@ -884,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;
}
@@ -1028,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 0fe487b7983..07cdfde115b 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;
+ }
};
@@ -67,10 +84,20 @@ public:
Item_func_month(Item *a) :Item_func(a) {}
longlong val_int();
double val() { return (double) Item_func_month::val_int(); }
- String *val_str(String *str) { str->set(val_int()); return null_value ? 0 : str;}
+ String *val_str(String *str)
+ {
+ 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;
+ }
};
@@ -81,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;
+ }
};
@@ -91,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;
+ }
};
@@ -101,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;
+ }
};
@@ -111,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;
+ }
};
@@ -121,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;
+ }
};
@@ -131,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;
+ }
};
@@ -141,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
@@ -150,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;
+ }
};
@@ -160,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;
+ }
};
@@ -172,11 +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()); return null_value ? 0 : str;}
+ 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; }
- unsigned int size_of() { return sizeof(*this);}
+ 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
@@ -186,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;
+ }
};
@@ -200,9 +288,9 @@ 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;
}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -214,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;
}
};
@@ -230,17 +319,21 @@ 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; }
- bool 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);
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);
+ return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset());
}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -257,16 +350,15 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
- t_arg);
+ t_arg, thd_charset());
}
- unsigned int size_of() { return sizeof(*this);}
};
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() {}
@@ -274,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); 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)
@@ -284,9 +375,9 @@ public:
}
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg);
+ return (!t_arg) ? result_field :
+ new Field_time(maybe_null, name, t_arg, thd_charset());
}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -300,14 +391,13 @@ public:
const char *func_name() const { return "curdate"; }
void fix_length_and_dec(); /* Retrieves curtime */
bool get_date(TIME *res,bool fuzzy_date);
- unsigned int size_of() { return sizeof(*this);}
};
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:
@@ -316,13 +406,11 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
double val() { return (double) value; }
longlong val_int() { return value; }
- bool save_in_field(Field *to);
- String *val_str(String *str)
- { str_value.set(buff,buff_length); return &str_value; }
+ int save_in_field(Field *to);
+ 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);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -347,7 +435,6 @@ public:
const char *func_name() const { return "date_format"; }
void fix_length_and_dec();
uint format_length(const String *format);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -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)
{
@@ -380,7 +477,8 @@ public:
}
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg);
+ return (!t_arg) ? result_field :
+ new Field_time(maybe_null, name, t_arg, thd_charset());
}
};
@@ -403,11 +501,16 @@ 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);
- unsigned int size_of() { return sizeof(*this);}
};
class Item_extract :public Item_int_func
@@ -421,7 +524,6 @@ class Item_extract :public Item_int_func
longlong val_int();
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
- unsigned int size_of() { return sizeof(*this);}
};
class Item_typecast :public Item_str_func
@@ -446,7 +548,8 @@ public:
}
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg);
+ return (!t_arg) ? result_field :
+ new Field_date(maybe_null, name, t_arg, thd_charset());
}
};
@@ -461,7 +564,8 @@ public:
}
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg);
+ return (!t_arg) ? result_field :
+ new Field_time(maybe_null, name, t_arg, thd_charset());
}
};
@@ -477,6 +581,6 @@ public:
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
- t_arg);
+ t_arg, thd_charset());
}
};
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index cc087832f49..f0d1d353cfb 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -29,9 +29,9 @@ public:
:Item_real_func(list) {}
double val() { return 0.0; }
void fix_length_and_dec() { decimals=0; max_length=6; }
- unsigned int size_of() { return sizeof(*this);}
};
+
class Item_sum_unique_users :public Item_sum_num
{
public:
@@ -43,6 +43,5 @@ public:
bool add() { return 0; }
void reset_field() {}
void update_field(int offset) {}
- bool fix_fields(THD *thd,struct st_table_list *tlist) { return 0;}
- unsigned int size_of() { return sizeof(*this);}
+ bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { return 0;}
};
diff --git a/sql/key.cc b/sql/key.cc
index d103c07eb72..84669808b92 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -192,8 +192,10 @@ int key_cmp(TABLE *table,const byte *key,uint idx,uint key_length)
if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
FIELDFLAG_PACK)))
{
- if (my_sortcmp((char*) key,(char*) table->record[0]+key_part->offset,
- length))
+ /* BAR TODO: I'm not sure this should be system_charset_info */
+ if (my_strnncoll(system_charset_info,
+ (const uchar*) key, length,
+ (const uchar*) table->record[0]+key_part->offset,length))
return 1;
}
else if (memcmp(key,table->record[0]+key_part->offset,length))
diff --git a/sql/lex.h b/sql/lex.h
index 49b6a3811e5..0d0d60fe204 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2002 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
@@ -74,12 +74,15 @@ static SYMBOL symbols[] = {
{ "BOOL", SYM(BOOL_SYM),0,0},
{ "BOOLEAN", SYM(BOOLEAN_SYM),0,0},
{ "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},
{ "CHAR", SYM(CHAR_SYM),0,0},
{ "CHARACTER", SYM(CHAR_SYM),0,0},
+ { "CHARSET", SYM(CHARSET),0,0},
{ "CHANGE", SYM(CHANGE),0,0},
{ "CHANGED", SYM(CHANGED),0,0},
{ "CHECK", SYM(CHECK_SYM),0,0},
@@ -87,6 +90,7 @@ static SYMBOL symbols[] = {
{ "CIPHER", SYM(CIPHER_SYM),0,0},
{ "CLIENT", SYM(CLIENT_SYM),0,0},
{ "CLOSE", SYM(CLOSE_SYM),0,0},
+ { "COLLATE", SYM(COLLATE_SYM),0,0},
{ "COLUMN", SYM(COLUMN_SYM),0,0},
{ "COLUMNS", SYM(COLUMNS),0,0},
{ "COMMENT", SYM(COMMENT_SYM),0,0},
@@ -123,11 +127,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},
+ { "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
@@ -149,6 +156,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},
@@ -159,13 +167,16 @@ static SYMBOL symbols[] = {
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
{ "FUNCTION", SYM(UDF_SYM),0,0},
+ { "GEOMETRY", SYM(GEOMETRY_SYM),0,0},
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
{ "GRANT", SYM(GRANT),0,0},
{ "GRANTS", SYM(GRANTS),0,0},
{ "GROUP", SYM(GROUP),0,0},
{ "HAVING", SYM(HAVING),0,0},
{ "HANDLER", SYM(HANDLER_SYM),0,0},
+ { "HASH", SYM(HASH_SYM),0,0},
{ "HEAP", SYM(HEAP_SYM),0,0},
+ { "HELP", SYM(HELP),0,0},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
{ "HOUR", SYM(HOUR_SYM),0,0},
{ "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0},
@@ -240,6 +251,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},
@@ -304,18 +316,22 @@ static SYMBOL symbols[] = {
{ "ROLLUP", SYM(ROLLUP_SYM),0,0},
{ "ROW", SYM(ROW_SYM),0,0},
{ "ROWS", SYM(ROWS_SYM),0,0},
+ { "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},
{ "SIGNED", SYM(SIGNED_SYM),0,0},
+ { "SIMPLE", SYM(SIMPLE_SYM),0,0},
{ "SHARE", SYM(SHARE_SYM),0,0},
{ "SHOW", SYM(SHOW),0,0},
{ "SHUTDOWN", SYM(SHUTDOWN),0,0},
{ "SLAVE", SYM(SLAVE),0,0},
{ "SMALLINT", SYM(SMALLINT),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
+ { "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
@@ -347,8 +363,10 @@ 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},
{ "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0},
{ "UNION", SYM(UNION_SYM),0,0},
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
@@ -359,11 +377,14 @@ 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},
+ { "WARNINGS", SYM(WARNINGS),0,0},
{ "WITH", SYM(WITH),0,0},
{ "WORK", SYM(WORK_SYM),0,0},
{ "WRITE", SYM(WRITE_SYM),0,0},
@@ -384,8 +405,10 @@ static SYMBOL sql_functions[] = {
{ "ADDDATE", SYM(DATE_ADD_INTERVAL),0,0},
{ "AES_ENCRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_encrypt)},
{ "AES_DECRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_decrypt)},
+ { "AREA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_area)},
{ "ASCII", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ascii)},
{ "ASIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_asin)},
+ { "ASTEXT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_as_text)},
{ "ATAN", SYM(ATAN),0,0},
{ "ATAN2", SYM(ATAN),0,0},
{ "BENCHMARK", SYM(BENCHMARK_SYM),0,0},
@@ -396,17 +419,21 @@ static SYMBOL sql_functions[] = {
{ "CAST", SYM(CAST_SYM),0,0},
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
{ "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)},
{ "CHARACTER_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "COALESCE", SYM(COALESCE),0,0},
{ "CONCAT", SYM(CONCAT),0,0},
{ "CONCAT_WS", SYM(CONCAT_WS),0,0},
{ "CONNECTION_ID", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
+ { "CONTAINS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_contains)},
{ "CONV", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
{ "CONVERT", SYM(CONVERT_SYM),0,0},
{ "COUNT", SYM(COUNT_SYM),0,0},
{ "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
+ { "CRC32", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_crc32)},
+ { "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)},
{ "CURDATE", SYM(CURDATE),0,0},
{ "CURTIME", SYM(CURTIME),0,0},
{ "DATE_ADD", SYM(DATE_ADD_INTERVAL),0,0},
@@ -420,9 +447,15 @@ static SYMBOL sql_functions[] = {
{ "DEGREES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_degrees)},
{ "DES_ENCRYPT", SYM(DES_ENCRYPT_SYM),0,0},
{ "DES_DECRYPT", SYM(DES_DECRYPT_SYM),0,0},
+ { "DIMENSION", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dimension)},
+ { "DISJOINT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_disjoint)},
{ "ELT", SYM(ELT_FUNC),0,0},
{ "ENCODE", SYM(ENCODE_SYM),0,0},
{ "ENCRYPT", SYM(ENCRYPT),0,0},
+ { "ENDPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_endpoint)},
+ { "ENVELOPE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_envelope)},
+ { "EQUALS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_equals)},
+ { "EXTERIORRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exteriorring)},
{ "EXTRACT", SYM(EXTRACT_SYM),0,0},
{ "EXP", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exp)},
{ "EXPORT_SET", SYM(EXPORT_SET),0,0},
@@ -434,6 +467,12 @@ static SYMBOL sql_functions[] = {
{ "FROM_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_from_days)},
{ "FROM_UNIXTIME", SYM(FROM_UNIXTIME),0,0},
{ "GET_LOCK", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_get_lock)},
+ { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0},
+ { "GEOMETRYN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_geometryn)},
+ { "GEOMETRYTYPE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_geometry_type)},
+ { "GEOMCOLLFROMTEXT", SYM(GEOMCOLLFROMTEXT),0,0},
+ { "GEOMFROMTEXT", SYM(GEOMFROMTEXT),0,0},
+ { "GLENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_glength)},
{ "GREATEST", SYM(GREATEST_SYM),0,0},
{ "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0},
{ "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)},
@@ -441,13 +480,20 @@ static SYMBOL sql_functions[] = {
{ "INET_ATON", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_aton)},
{ "INET_NTOA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_ntoa)},
{ "INSTR", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_instr)},
+ { "INTERIORRINGN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_interiorringn)},
+ { "INTERSECTS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_intersects)},
+ { "ISCLOSED", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isclosed)},
+ { "ISEMPTY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isempty)},
{ "ISNULL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isnull)},
{ "IS_FREE_LOCK", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_is_free_lock)},
{ "LAST_INSERT_ID", SYM(LAST_INSERT_ID),0,0},
+ { "ISSIMPLE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_issimple)},
{ "LCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)},
{ "LEAST", SYM(LEAST_SYM),0,0},
{ "LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "LN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ln)},
+ { "LINEFROMTEXT", SYM(LINEFROMTEXT),0,0},
+ { "LINESTRING", SYM(LINESTRING),0,0},
{ "LOAD_FILE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_load_file)},
{ "LOCATE", SYM(LOCATE),0,0},
{ "LOG", SYM(LOG_SYM),0,0},
@@ -463,16 +509,30 @@ 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},
+ { "MULTILINESTRING", SYM(MULTILINESTRING),0,0},
+ { "MULTIPOINT", SYM(MULTIPOINT),0,0},
+ { "MULTIPOLYGON", SYM(MULTIPOLYGON),0,0},
{ "MONTHNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_monthname)},
{ "NOW", SYM(NOW_SYM),0,0},
{ "NULLIF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_nullif)},
+ { "NUMGEOMETRIES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numgeometries)},
+ { "NUMINTERIORRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numinteriorring)},
+ { "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)},
{ "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)},
{ "PERIOD_DIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_diff)},
{ "PI", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_pi)},
+ { "POINT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_point)},
+ { "POINTFROMTEXT", SYM(POINTFROMTEXT),0,0},
+ { "POINTN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pointn)},
+ { "POLYFROMTEXT", SYM(POLYFROMTEXT),0,0},
+ { "POLYGON", SYM(POLYGON),0,0},
{ "POSITION", SYM(POSITION_SYM),0,0},
{ "POW", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
{ "POWER", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
@@ -496,6 +556,7 @@ static SYMBOL sql_functions[] = {
{ "SOUNDEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_soundex)},
{ "SPACE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_space)},
{ "SQRT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sqrt)},
+ { "STARTPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_startpoint)},
{ "STD", SYM(STD_SYM),0,0},
{ "STDDEV", SYM(STD_SYM),0,0},
{ "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)},
@@ -508,6 +569,7 @@ static SYMBOL sql_functions[] = {
{ "TIME_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)},
{ "TIME_TO_SEC", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_time_to_sec)},
{ "TO_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_to_days)},
+ { "TOUCHES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_touches)},
{ "TRIM", SYM(TRIM),0,0},
{ "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
@@ -517,5 +579,8 @@ static SYMBOL sql_functions[] = {
{ "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
{ "WEEK", SYM(WEEK_SYM),0,0},
{ "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)},
+ { "WITHIN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_within)},
+ { "X", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_x)},
+ { "Y", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_y)},
{ "YEARWEEK", SYM(YEARWEEK),0,0}
};
diff --git a/sql/lock.cc b/sql/lock.cc
index 4c84bbb6e69..74d1109b203 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -69,6 +69,12 @@ TODO:
#include "mysql_priv.h"
#include <hash.h>
#include <assert.h>
+#include <ha_myisammrg.h>
+#ifndef MASTER
+#include "../srclib/myisammrg/myrg_def.h"
+#else
+#include "../myisammrg/myrg_def.h"
+#endif
extern HASH open_cache;
@@ -156,6 +162,7 @@ retry:
sql_lock=0;
}
}
+
thd->lock_time();
DBUG_RETURN (sql_lock);
}
@@ -412,8 +419,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
return 0;
}
}
+ THR_LOCK_DATA **org_locks = locks;
locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE :
lock_type);
+ if (locks)
+ for ( ; org_locks != locks ; org_locks++)
+ (*org_locks)->debug_print_param= (void *) table;
}
return sql_lock;
}
diff --git a/sql/log.cc b/sql/log.cc
index 597985e8796..0e1af8e5dae 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -45,16 +45,19 @@ static bool test_if_number(const char *str,
static int find_uniq_filename(char *name)
{
- long number;
- uint i,length;
- char buff[FN_REFLEN];
- struct st_my_dir *dir_info;
+ long number;
+ uint i;
+ char buff[FN_REFLEN];
+ struct st_my_dir *dir_info;
reg1 struct fileinfo *file_info;
- ulong max_found=0;
+ ulong max_found=0;
+
DBUG_ENTER("find_uniq_filename");
- length=dirname_part(buff,name);
- char *start=name+length,*end=strend(start);
+ uint length = dirname_part(buff,name);
+ char *start = name + length;
+ char *end = strend(start);
+
*end='.';
length= (uint) (end-start+1);
@@ -75,7 +78,7 @@ static int find_uniq_filename(char *name)
my_dirend(dir_info);
*end++='.';
- sprintf(end,"%03ld",max_found+1);
+ sprintf(end,"%06ld",max_found+1);
DBUG_RETURN(0);
}
@@ -213,15 +216,18 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
time_t skr=time(NULL);
struct tm tm_tmp;
localtime_r(&skr,&tm_tmp);
- sprintf(buff,"# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n",
- my_progname,server_version,
- tm_tmp.tm_year % 100,
- tm_tmp.tm_mon+1,
- tm_tmp.tm_mday,
- tm_tmp.tm_hour,
- tm_tmp.tm_min,
- tm_tmp.tm_sec);
- if (my_b_write(&log_file, (byte*) buff,(uint) strlen(buff)) ||
+ ulong length;
+ length= my_sprintf(buff,
+ (buff,
+ "# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n",
+ my_progname,server_version,
+ tm_tmp.tm_year % 100,
+ tm_tmp.tm_mon+1,
+ tm_tmp.tm_mday,
+ tm_tmp.tm_hour,
+ tm_tmp.tm_min,
+ tm_tmp.tm_sec));
+ if (my_b_write(&log_file, (byte*) buff, length) ||
flush_io_cache(&log_file))
goto err;
break;
@@ -935,7 +941,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
{
if (is_open() && (what_to_log & (1L << (uint) command)))
{
- int error=0;
+ uint length;
+ int error= 0;
VOID(pthread_mutex_lock(&LOCK_log));
/* Test if someone closed between the is_open test and lock */
@@ -984,8 +991,10 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
}
else if (my_b_write(&log_file, (byte*) "\t\t",2) < 0)
error=errno;
- sprintf(buff,"%7ld %-11.11s", id,command_name[(uint) command]);
- if (my_b_write(&log_file, (byte*) buff,strlen(buff)))
+ length=my_sprintf(buff,
+ (buff, "%7ld %-11.11s", id,
+ command_name[(uint) command]));
+ if (my_b_write(&log_file, (byte*) buff,length))
error=errno;
if (format)
{
@@ -1235,11 +1244,7 @@ err:
/*
Write update log in a format suitable for incremental backup
-
- NOTE
- - This code should be deleted in MySQL 5,0 as the binary log
- is a full replacement for the update log.
-
+ This is also used by the slow query log.
*/
bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
@@ -1474,7 +1479,7 @@ static bool test_if_number(register const char *str,
while (*str++ == ' ') ;
if (*--str == '-' || *str == '+')
str++;
- while (isdigit(*str) || (allow_wildcards &&
+ while (my_isdigit(system_charset_info,*str) || (allow_wildcards &&
(*str == wild_many || *str == wild_one)))
{
flag=1;
@@ -1483,7 +1488,7 @@ static bool test_if_number(register const char *str,
if (*str == '.')
{
for (str++ ;
- isdigit(*str) ||
+ my_isdigit(system_charset_info,*str) ||
(allow_wildcards && (*str == wild_many || *str == wild_one)) ;
str++, flag=1) ;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 373e50b84f7..3747af22922 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -26,6 +26,11 @@
#include <assert.h>
+/*****************************************************************************
+
+ my_b_safe_write()
+
+ ****************************************************************************/
inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
int len)
{
@@ -40,6 +45,11 @@ inline int my_b_safe_write(IO_CACHE* file, const byte *buf,
return my_b_write(file, buf,len);
}
+/*****************************************************************************
+
+ pretty_print_str()
+
+ ****************************************************************************/
#ifdef MYSQL_CLIENT
static void pretty_print_str(FILE* file, char* str, int len)
{
@@ -63,16 +73,26 @@ static void pretty_print_str(FILE* file, char* str, int len)
}
fputc('\'', file);
}
-#endif
+#endif // MYSQL_CLIENT
-#ifndef MYSQL_CLIENT
+/*****************************************************************************
+
+ ignored_error_code()
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
inline int ignored_error_code(int err_code)
{
return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+ pretty_print_str()
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
static void pretty_print_str(String* packet, char* str, int len)
{
char* end = str + len;
@@ -95,8 +115,14 @@ static void pretty_print_str(String* packet, char* str, int len)
}
packet->append('\'');
}
+#endif // !MYSQL_CLIENT
+/*****************************************************************************
+ slave_load_file_stem()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
static inline char* slave_load_file_stem(char*buf, uint file_id,
int event_server_id)
{
@@ -108,9 +134,81 @@ static inline char* slave_load_file_stem(char*buf, uint file_id,
*buf++ = '-';
return int10_to_str(file_id, buf, 10);
}
+#endif // !MYSQL_CLIENT
-#endif
+/*****************************************************************************
+
+ cleanup_load_tmpdir()
+
+ Delete all temporary files used for SQL_LOAD.
+
+ TODO
+ - When we get a 'server start' event, we should only remove
+ the files associated with the server id that just started.
+ Easily fixable by adding server_id as a prefix to the log files.
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+static void cleanup_load_tmpdir()
+{
+ MY_DIR *dirp;
+ FILEINFO *file;
+ uint i;
+ if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
+ return;
+
+ for (i=0 ; i < (uint)dirp->number_off_files; i++)
+ {
+ file=dirp->dir_entry+i;
+ if (is_prefix(file->name,"SQL_LOAD-"))
+ my_delete(file->name, MYF(0));
+ }
+
+ my_dirend(dirp);
+}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ write_str()
+
+ ****************************************************************************/
+static bool write_str(IO_CACHE *file, char *str, byte length)
+{
+ return (my_b_safe_write(file, &length, 1) ||
+ my_b_safe_write(file, (byte*) str, (int) length));
+}
+
+/*****************************************************************************
+
+ read_str()
+
+ ****************************************************************************/
+static inline int read_str(char * &buf, char *buf_end, char * &str,
+ uint8 &len)
+{
+ if (buf + (uint) (uchar) *buf >= buf_end)
+ return 1;
+ len = (uint8) *buf;
+ str= buf+1;
+ buf+= (uint) len+1;
+ return 0;
+}
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Log_event::get_type_str()
+ ****************************************************************************/
const char* Log_event::get_type_str()
{
switch(get_type_code()) {
@@ -126,20 +224,26 @@ const char* Log_event::get_type_str()
case APPEND_BLOCK_EVENT: return "Append_block";
case DELETE_FILE_EVENT: return "Delete_file";
case EXEC_LOAD_EVENT: return "Exec_load";
+ case RAND_EVENT: return "RAND";
default: /* impossible */ return "Unknown";
}
}
+/*****************************************************************************
+
+ Log_event::Log_event()
+
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
:temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg),
thd(thd_arg)
{
- 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)));
+ 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)));
}
@@ -147,40 +251,17 @@ 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;
+ server_id= ::server_id;
+ when= time(NULL);
+ log_pos= 0;
}
+#endif // !MYSQL_CLIENT
-/*
- Delete all temporary files used for SQL_LOAD.
-
- TODO
- - When we get a 'server start' event, we should only remove
- the files associated with the server id that just started.
- Easily fixable by adding server_id as a prefix to the log files.
-*/
-
-static void cleanup_load_tmpdir()
-{
- MY_DIR *dirp;
- FILEINFO *file;
- uint i;
- if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
- return;
-
- for (i=0 ; i < (uint)dirp->number_off_files; i++)
- {
- file=dirp->dir_entry+i;
- if (is_prefix(file->name,"SQL_LOAD-"))
- my_delete(file->name, MYF(0));
- }
-
- my_dirend(dirp);
-}
+/*****************************************************************************
-#endif
+ Log_event::Log_event()
+ ****************************************************************************/
Log_event::Log_event(const char* buf, bool old_format)
:temp_buf(0), cached_event_len(0), cache_stmt(0)
{
@@ -204,6 +285,11 @@ Log_event::Log_event(const char* buf, bool old_format)
#ifndef MYSQL_CLIENT
+/*****************************************************************************
+
+ Log_event::exec_event()
+
+ ****************************************************************************/
int Log_event::exec_event(struct st_relay_log_info* rli)
{
if (rli) // QQ When is this not true ?
@@ -215,170 +301,21 @@ int Log_event::exec_event(struct st_relay_log_info* rli)
return 0;
}
-void Log_event::pack_info(String* packet)
-{
- net_store_data(packet, "", 0);
-}
-
-void Query_log_event::pack_info(String* packet)
-{
- char buf[256];
- String tmp(buf, sizeof(buf));
- tmp.length(0);
- if (db && db_len)
- {
- tmp.append("use ");
- tmp.append(db, db_len);
- tmp.append("; ", 2);
- }
-
- if (query && q_len)
- tmp.append(query, q_len);
- net_store_data(packet, (char*)tmp.ptr(), tmp.length());
-}
-
-void Start_log_event::pack_info(String* packet)
-{
- char buf1[256];
- String tmp(buf1, sizeof(buf1));
- tmp.length(0);
- char buf[22];
-
- tmp.append("Server ver: ");
- tmp.append(server_version);
- tmp.append(", Binlog ver: ");
- tmp.append(llstr(binlog_version, buf));
- net_store_data(packet, tmp.ptr(), tmp.length());
-}
-
-void Load_log_event::pack_info(String* packet)
-{
- char buf[256];
- String tmp(buf, sizeof(buf));
- tmp.length(0);
- if (db && db_len)
- {
- tmp.append("use ");
- tmp.append(db, db_len);
- tmp.append("; ", 2);
- }
-
- tmp.append("LOAD DATA INFILE '");
- tmp.append(fname, fname_len);
- tmp.append("' ", 2);
- if (sql_ex.opt_flags && REPLACE_FLAG )
- tmp.append(" REPLACE ");
- else if (sql_ex.opt_flags && IGNORE_FLAG )
- tmp.append(" IGNORE ");
-
- tmp.append("INTO TABLE ");
- tmp.append(table_name);
- if (sql_ex.field_term_len)
- {
- tmp.append(" FIELDS TERMINATED BY ");
- pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len);
- }
-
- if (sql_ex.enclosed_len)
- {
- if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
- tmp.append(" OPTIONALLY ");
- tmp.append( " ENCLOSED BY ");
- pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len);
- }
-
- if (sql_ex.escaped_len)
- {
- tmp.append( " ESCAPED BY ");
- pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len);
- }
-
- if (sql_ex.line_term_len)
- {
- tmp.append(" LINES TERMINATED BY ");
- pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len);
- }
-
- if (sql_ex.line_start_len)
- {
- tmp.append(" LINES STARTING BY ");
- pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len);
- }
-
- if ((int)skip_lines > 0)
- tmp.append( " IGNORE %ld LINES ", (long) skip_lines);
-
- if (num_fields)
- {
- uint i;
- const char* field = fields;
- tmp.append(" (");
- for (i = 0; i < num_fields; i++)
- {
- if (i)
- tmp.append(" ,");
- tmp.append( field);
-
- field += field_lens[i] + 1;
- }
- tmp.append(')');
- }
-
- net_store_data(packet, tmp.ptr(), tmp.length());
-}
-
-void Rotate_log_event::pack_info(String* packet)
-{
- char buf1[256], buf[22];
- String tmp(buf1, sizeof(buf1));
- tmp.length(0);
- tmp.append(new_log_ident, ident_len);
- tmp.append(";pos=");
- tmp.append(llstr(pos,buf));
- if (flags & LOG_EVENT_FORCED_ROTATE_F)
- tmp.append("; forced by master");
- net_store_data(packet, tmp.ptr(), tmp.length());
-}
+/*****************************************************************************
-void Intvar_log_event::pack_info(String* packet)
-{
- char buf1[256], buf[22];
- String tmp(buf1, sizeof(buf1));
- tmp.length(0);
- tmp.append(get_var_type_name());
- tmp.append('=');
- tmp.append(llstr(val, buf));
- net_store_data(packet, tmp.ptr(), tmp.length());
-}
+ Log_event::pack_info()
-void Rand_log_event::pack_info(String* packet)
+ ****************************************************************************/
+void Log_event::pack_info(String* packet)
{
- 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));
+ net_store_data(packet, "", 0);
}
-void Slave_log_event::pack_info(String* packet)
-{
- char buf1[256], buf[22], *end;
- String tmp(buf1, sizeof(buf1));
- tmp.length(0);
- tmp.append("host=");
- tmp.append(master_host);
- tmp.append(",port=");
- end= int10_to_str((long) master_port, buf, 10);
- tmp.append(buf, (uint32) (end-buf));
- tmp.append(",log=");
- tmp.append(master_log);
- tmp.append(",pos=");
- tmp.append(llstr(master_pos,buf));
- net_store_data(packet, tmp.ptr(), tmp.length());
-}
+/*****************************************************************************
+ Log_event::init_show_field_list()
+ ****************************************************************************/
void Log_event::init_show_field_list(List<Item>* field_list)
{
field_list->push_back(new Item_empty_string("Log_name", 20));
@@ -389,14 +326,18 @@ void Log_event::init_show_field_list(List<Item>* field_list)
field_list->push_back(new Item_empty_string("Info", 20));
}
-/*
- * only called by SHOW BINLOG EVENTS
- */
+/*****************************************************************************
+
+ Log_event::net_send()
+
+ Only called by SHOW BINLOG EVENTS
+
+ ****************************************************************************/
int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos)
{
String* packet = &thd_arg->packet;
- const char* p = strrchr(log_name, FN_LIBCHAR);
- const char* event_type;
+ const char *p= strrchr(log_name, FN_LIBCHAR);
+ const char *event_type;
if (p)
log_name = p + 1;
@@ -410,22 +351,23 @@ int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos)
pack_info(packet);
return my_net_write(&thd_arg->net, (char*) packet->ptr(), packet->length());
}
+#endif // !MYSQL_CLIENT
-#endif /* MYSQL_CLIENT */
-
-
-int Query_log_event::write(IO_CACHE* file)
-{
- return query ? Log_event::write(file) : -1;
-}
+/*****************************************************************************
+ Log_event::write()
+ ****************************************************************************/
int Log_event::write(IO_CACHE* file)
{
return (write_header(file) || write_data(file)) ? -1 : 0;
}
+/*****************************************************************************
+ Log_event::write_header()
+
+ ****************************************************************************/
int Log_event::write_header(IO_CACHE* file)
{
char buf[LOG_EVENT_HEADER_LEN];
@@ -445,8 +387,13 @@ int Log_event::write_header(IO_CACHE* file)
return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf)));
}
-#ifndef MYSQL_CLIENT
+/*****************************************************************************
+
+ Log_event::read_log_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
int Log_event::read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock)
{
@@ -501,8 +448,7 @@ end:
pthread_mutex_unlock(log_lock);
DBUG_RETURN(result);
}
-
-#endif // MYSQL_CLIENT
+#endif // !MYSQL_CLIENT
#ifndef MYSQL_CLIENT
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
@@ -513,7 +459,13 @@ end:
#define LOCK_MUTEX
#endif
-// allocates memory - the caller is responsible for clean-up
+/*****************************************************************************
+
+ Log_event::read_log_event()
+
+ Allocates memory--the caller is responsible for clean-up
+
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
Log_event* Log_event::read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
@@ -576,7 +528,11 @@ data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]);
return res;
}
+/*****************************************************************************
+
+ Log_event::read_log_event()
+ ****************************************************************************/
Log_event* Log_event::read_log_event(const char* buf, int event_len,
const char **error, bool old_format)
{
@@ -642,8 +598,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
return ev;
}
-
#ifdef MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Log_event::print_header()
+
+ ****************************************************************************/
void Log_event::print_header(FILE* file)
{
char llbuff[22];
@@ -653,6 +614,11 @@ void Log_event::print_header(FILE* file)
llstr(log_pos,llbuff));
}
+/*****************************************************************************
+
+ Log_event::print_timestamp()
+
+ ****************************************************************************/
void Log_event::print_timestamp(FILE* file, time_t* ts)
{
struct tm *res;
@@ -674,113 +640,91 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
res->tm_sec);
}
+#endif // MYSQL_CLIENT
-void Start_log_event::print(FILE* file, bool short_form, char* last_db)
-{
- if (short_form)
- return;
+/*****************************************************************************
- print_header(file);
- fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
- server_version);
- print_timestamp(file, (time_t*)&created);
- fputc('\n', file);
- fflush(file);
-}
+ Log_event::set_log_pos()
-void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Log_event::set_log_pos(MYSQL_LOG* log)
{
- if (short_form)
- return;
-
- print_header(file);
- fprintf(file, "\tStop\n");
- fflush(file);
+ if (!log_pos)
+ log_pos = my_b_tell(&log->log_file);
}
+#endif // !MYSQL_CLIENT
-void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
-{
- char buf[22];
- if (short_form)
- return;
- print_header(file);
- fprintf(file, "\tRotate to ");
- if (new_log_ident)
- my_fwrite(file, (byte*) new_log_ident, (uint)ident_len,
- MYF(MY_NABP | MY_WME));
- fprintf(file, " pos: %s", llstr(pos, buf));
- if (flags & LOG_EVENT_FORCED_ROTATE_F)
- fprintf(file," forced by master");
- fputc('\n', file);
- fflush(file);
-}
-#endif /* #ifdef MYSQL_CLIENT */
+/*****************************************************************************
+ *****************************************************************************
+ Query_log_event methods
-Start_log_event::Start_log_event(const char* buf,
- bool old_format)
- :Log_event(buf, old_format)
-{
- buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET);
- memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
- ST_SERVER_VER_LEN);
- created = uint4korr(buf+ST_CREATED_OFFSET);
-}
+ *****************************************************************************
+ ****************************************************************************/
-int Start_log_event::write_data(IO_CACHE* file)
-{
- char buff[START_HEADER_LEN];
- int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
- memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
- int4store(buff + ST_CREATED_OFFSET,created);
- return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
-}
+#ifndef MYSQL_CLIENT
+/*****************************************************************************
+ Query_log_event::pack_info()
-Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
- bool old_format)
- :Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
+ ****************************************************************************/
+void Query_log_event::pack_info(String* packet)
{
- // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
- int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- uint ident_offset;
- if (event_len < header_size)
- return;
- buf += header_size;
- if (old_format)
- {
- ident_len = (uint)(event_len - OLD_HEADER_LEN);
- pos = 4;
- ident_offset = 0;
- }
- else
+ char buf[256];
+ String tmp(buf, sizeof(buf), system_charset_info);
+ tmp.length(0);
+ if (db && db_len)
{
- ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD);
- pos = uint8korr(buf + R_POS_OFFSET);
- ident_offset = ROTATE_HEADER_LEN;
+ tmp.append("use `", 5);
+ tmp.append(db, db_len);
+ tmp.append("`; ", 3);
}
- set_if_smaller(ident_len,FN_REFLEN-1);
- if (!(new_log_ident= my_strdup_with_length((byte*) buf +
- ident_offset,
- (uint) ident_len,
- MYF(MY_WME))))
- return;
- alloced = 1;
+
+ if (query && q_len)
+ tmp.append(query, q_len);
+ net_store_data(packet, (char*)tmp.ptr(), tmp.length());
}
+#endif // !MYSQL_CLIENT
+/*****************************************************************************
-int Rotate_log_event::write_data(IO_CACHE* file)
+ Query_log_event::write()
+
+ ****************************************************************************/
+int Query_log_event::write(IO_CACHE* file)
{
- char buf[ROTATE_HEADER_LEN];
- int8store(buf, pos + R_POS_OFFSET);
- return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
- my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
+ return query ? Log_event::write(file) : -1;
+}
+
+/*****************************************************************************
+
+ Query_log_event::write_data()
+
+ ****************************************************************************/
+int Query_log_event::write_data(IO_CACHE* file)
+{
+ if (!query)
+ return -1;
+
+ char buf[QUERY_HEADER_LEN];
+ int4store(buf + Q_THREAD_ID_OFFSET, thread_id);
+ int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
+ buf[Q_DB_LEN_OFFSET] = (char) db_len;
+ int2store(buf + Q_ERR_CODE_OFFSET, error_code);
+
+ return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
+ my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
+ my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0;
}
+/*****************************************************************************
+
+ Query_log_event::Query_log_event()
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans)
@@ -794,8 +738,13 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
exec_time = (ulong) (end_time - thd->start_time);
db_len = (db) ? (uint32) strlen(db) : 0;
}
-#endif
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Query_log_event::Query_log_event()
+ ****************************************************************************/
Query_log_event::Query_log_event(const char* buf, int event_len,
bool old_format)
:Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL)
@@ -831,9 +780,12 @@ Query_log_event::Query_log_event(const char* buf, int event_len,
*((char*)query+q_len) = 0;
}
+/*****************************************************************************
-#ifdef MYSQL_CLIENT
+ Query_log_event::print()
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
void Query_log_event::print(FILE* file, bool short_form, char* last_db)
{
char buff[40],*end; // Enough for SET TIMESTAMP
@@ -861,113 +813,311 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME));
fprintf(file, ";\n");
}
-#endif
-
+#endif // MYSQL_CLIENT
-int Query_log_event::write_data(IO_CACHE* file)
-{
- if (!query)
- return -1;
-
- char buf[QUERY_HEADER_LEN];
- int4store(buf + Q_THREAD_ID_OFFSET, thread_id);
- int4store(buf + Q_EXEC_TIME_OFFSET, exec_time);
- buf[Q_DB_LEN_OFFSET] = (char) db_len;
- int2store(buf + Q_ERR_CODE_OFFSET, error_code);
+/*****************************************************************************
- return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) ||
- my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) ||
- my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0;
-}
+ Query_log_event::exec_event()
-Intvar_log_event::Intvar_log_event(const char* buf, bool old_format)
- :Log_event(buf, old_format)
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Query_log_event::exec_event(struct st_relay_log_info* rli)
{
- buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- type = buf[I_TYPE_OFFSET];
- val = uint8korr(buf+I_VAL_OFFSET);
-}
+ int expected_error,actual_error = 0;
+ init_sql_alloc(&thd->mem_root, 8192,0);
+ thd->db = rewrite_db((char*)db);
-const char* Intvar_log_event::get_var_type_name()
-{
- switch(type) {
- case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID";
- case INSERT_ID_EVENT: return "INSERT_ID";
- default: /* impossible */ return "UNKNOWN";
+ /*
+ InnoDB internally stores the master log position it has processed so far;
+ position to store is really pos + pending + event_len
+ since we must store the pos of the END of the current log event
+ */
+ rli->event_len= get_event_len();
+
+ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+ {
+ thd->query = (char*)query;
+ thd->set_time((time_t)when);
+ thd->current_tablenr = 0;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id = query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->query_error= 0; // clear error
+ thd->clear_error();
+
+ thd->slave_proxy_id = thread_id; // for temp tables
+
+ /*
+ Sanity check to make sure the master did not get a really bad
+ error on the query.
+ */
+ if (ignored_error_code((expected_error = error_code)) ||
+ !check_expected_error(thd,rli,expected_error))
+ {
+ mysql_log.write(thd,COM_QUERY,"%s",thd->query);
+ DBUG_PRINT("query",("%s",thd->query));
+ mysql_parse(thd, thd->query, q_len);
+ DBUG_PRINT("info",("expected_error: %d last_errno: %d",
+ expected_error, thd->net.last_errno));
+ if ((expected_error != (actual_error= thd->net.last_errno)) &&
+ expected_error &&
+ !ignored_error_code(actual_error) &&
+ !ignored_error_code(expected_error))
+ {
+ const char* errmsg = "Slave: did not get the expected error\
+ running query from master - expected: '%s' (%d), got '%s' (%d)";
+ sql_print_error(errmsg, ER_SAFE(expected_error),
+ expected_error,
+ actual_error ? thd->net.last_error: "no error",
+ actual_error);
+ thd->query_error = 1;
+ }
+ else if (expected_error == actual_error ||
+ ignored_error_code(actual_error))
+ {
+ DBUG_PRINT("info",("error ignored"));
+ thd->query_error = 0;
+ *rli->last_slave_error = 0;
+ rli->last_slave_errno = 0;
+ }
+ }
+ else
+ {
+ // master could be inconsistent, abort and tell DBA to check/fix it
+ thd->db = thd->query = 0;
+ thd->variables.convert_set = 0;
+ close_thread_tables(thd);
+ free_root(&thd->mem_root,0);
+ return 1;
+ }
+ }
+ thd->db= 0; // prevent db from being freed
+ thd->query= 0; // just to be sure
+ // assume no convert for next query unless set explictly
+ thd->variables.convert_set = 0;
+ close_thread_tables(thd);
+
+ if (thd->query_error || thd->fatal_error)
+ {
+ slave_print_error(rli,actual_error, "error '%s' on query '%s'",
+ actual_error ? thd->net.last_error :
+ "unexpected success or fatal error", query);
+ free_root(&thd->mem_root,0);
+ return 1;
}
+ free_root(&thd->mem_root,0);
+ return Log_event::exec_event(rli);
}
+#endif // !MYSQL_CLIENT
-int Intvar_log_event::write_data(IO_CACHE* file)
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Start_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Start_log_event::pack_info()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Start_log_event::pack_info(String* packet)
{
- char buf[9];
- buf[I_TYPE_OFFSET] = type;
- int8store(buf + I_VAL_OFFSET, val);
- return my_b_safe_write(file, (byte*) buf, sizeof(buf));
+ char buf1[256];
+ String tmp(buf1, sizeof(buf1), system_charset_info);
+ tmp.length(0);
+ char buf[22];
+
+ tmp.append("Server ver: ");
+ tmp.append(server_version);
+ tmp.append(", Binlog ver: ");
+ tmp.append(llstr(binlog_version, buf));
+ net_store_data(packet, tmp.ptr(), tmp.length());
}
+#endif // !MYSQL_CLIENT
+/*****************************************************************************
+
+ Start_log_event::print()
+
+ ****************************************************************************/
#ifdef MYSQL_CLIENT
-void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
+void Start_log_event::print(FILE* file, bool short_form, char* last_db)
{
- char llbuff[22];
- const char *msg;
- LINT_INIT(msg);
-
- if (!short_form)
- {
- print_header(file);
- fprintf(file, "\tIntvar\n");
- }
+ if (short_form)
+ return;
- fprintf(file, "SET ");
- switch (type) {
- case LAST_INSERT_ID_EVENT:
- msg="LAST_INSERT_ID";
- break;
- case INSERT_ID_EVENT:
- msg="INSERT_ID";
- break;
- }
- fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff));
+ print_header(file);
+ fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
+ server_version);
+ print_timestamp(file, (time_t*)&created);
+ fputc('\n', file);
fflush(file);
}
-#endif
+#endif // MYSQL_CLIENT
/*****************************************************************************
- *
- * Rand log event
- *
+
+ Start_log_event::Start_log_event()
+
****************************************************************************/
-Rand_log_event::Rand_log_event(const char* buf, bool old_format)
+Start_log_event::Start_log_event(const char* buf,
+ bool old_format)
:Log_event(buf, old_format)
{
buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
- seed1 = uint8korr(buf+RAND_SEED1_OFFSET);
- seed2 = uint8korr(buf+RAND_SEED2_OFFSET);
+ binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET);
+ memcpy(server_version, buf+ST_SERVER_VER_OFFSET,
+ ST_SERVER_VER_LEN);
+ created = uint4korr(buf+ST_CREATED_OFFSET);
}
-int Rand_log_event::write_data(IO_CACHE* file)
+/*****************************************************************************
+
+ Start_log_event::write_data()
+
+ ****************************************************************************/
+int Start_log_event::write_data(IO_CACHE* file)
{
- char buf[16];
- int8store(buf + RAND_SEED1_OFFSET, seed1);
- int8store(buf + RAND_SEED2_OFFSET, seed2);
- return my_b_safe_write(file, (byte*) buf, sizeof(buf));
+ char buff[START_HEADER_LEN];
+ int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
+ memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
+ int4store(buff + ST_CREATED_OFFSET,created);
+ return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
}
-#ifdef MYSQL_CLIENT
-void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
+/*****************************************************************************
+
+ Start_log_event::exec_event()
+
+ The master started
+
+ IMPLEMENTATION
+ - To handle the case where the master died without a stop event,
+ we clean up all temporary tables + locks that we got.
+
+ TODO
+ - Remove all active user locks
+ - If we have an active transaction at this point, the master died
+ in the middle while writing the transaction to the binary log.
+ In this case we should stop the slave.
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Start_log_event::exec_event(struct st_relay_log_info* rli)
{
- char llbuff[22];
- if (!short_form)
+ /* All temporary tables was deleted on the master */
+ close_temporary_tables(thd);
+ /*
+ If we have old format, load_tmpdir is cleaned up by the I/O thread
+ */
+ if (!rli->mi->old_format)
+ cleanup_load_tmpdir();
+ return Log_event::exec_event(rli);
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Load_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Load_log_event::pack_info()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Load_log_event::pack_info(String* packet)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf), system_charset_info);
+ tmp.length(0);
+ if (db && db_len)
{
- print_header(file);
- fprintf(file, "\tRand\n");
+ tmp.append("use ");
+ tmp.append(db, db_len);
+ tmp.append("; ", 2);
}
- fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
- llstr(seed1, llbuff),llstr(seed2, llbuff));
- fflush(file);
+
+ tmp.append("LOAD DATA INFILE '");
+ tmp.append(fname, fname_len);
+ tmp.append("' ", 2);
+ if (sql_ex.opt_flags && REPLACE_FLAG )
+ tmp.append(" REPLACE ");
+ else if (sql_ex.opt_flags && IGNORE_FLAG )
+ tmp.append(" IGNORE ");
+
+ tmp.append("INTO TABLE ");
+ tmp.append(table_name);
+ if (sql_ex.field_term_len)
+ {
+ tmp.append(" FIELDS TERMINATED BY ");
+ pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len);
+ }
+
+ if (sql_ex.enclosed_len)
+ {
+ if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
+ tmp.append(" OPTIONALLY ");
+ tmp.append( " ENCLOSED BY ");
+ pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len);
+ }
+
+ if (sql_ex.escaped_len)
+ {
+ tmp.append( " ESCAPED BY ");
+ pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len);
+ }
+
+ if (sql_ex.line_term_len)
+ {
+ tmp.append(" LINES TERMINATED BY ");
+ pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len);
+ }
+
+ if (sql_ex.line_start_len)
+ {
+ tmp.append(" LINES STARTING BY ");
+ pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len);
+ }
+
+ if ((int)skip_lines > 0)
+ tmp.append( " IGNORE %ld LINES ", (long) skip_lines);
+
+ if (num_fields)
+ {
+ uint i;
+ const char* field = fields;
+ tmp.append(" (");
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ tmp.append(" ,");
+ tmp.append( field);
+
+ field += field_lens[i] + 1;
+ }
+ tmp.append(')');
+ }
+
+ net_store_data(packet, tmp.ptr(), tmp.length());
}
-#endif
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+ Load_log_event::write_data_header()
+
+ ****************************************************************************/
int Load_log_event::write_data_header(IO_CACHE* file)
{
char buf[LOAD_HEADER_LEN];
@@ -980,6 +1130,11 @@ int Load_log_event::write_data_header(IO_CACHE* file)
return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN);
}
+/*****************************************************************************
+
+ Load_log_event::write_data_body()
+
+ ****************************************************************************/
int Load_log_event::write_data_body(IO_CACHE* file)
{
if (sql_ex.write_data(file))
@@ -995,107 +1150,17 @@ int Load_log_event::write_data_body(IO_CACHE* file)
my_b_safe_write(file, (byte*)fname, fname_len));
}
+/*****************************************************************************
+ Load_log_event::Load_log_event()
-static bool write_str(IO_CACHE *file, char *str, byte length)
-{
- return (my_b_safe_write(file, &length, 1) ||
- my_b_safe_write(file, (byte*) str, (int) length));
-}
-
-
-int sql_ex_info::write_data(IO_CACHE* file)
-{
- if (new_format())
- {
- return (write_str(file, field_term, field_term_len) ||
- write_str(file, enclosed, enclosed_len) ||
- write_str(file, line_term, line_term_len) ||
- write_str(file, line_start, line_start_len) ||
- write_str(file, escaped, escaped_len) ||
- my_b_safe_write(file,(byte*) &opt_flags,1));
- }
- else
- {
- old_sql_ex old_ex;
- old_ex.field_term= *field_term;
- old_ex.enclosed= *enclosed;
- old_ex.line_term= *line_term;
- old_ex.line_start= *line_start;
- old_ex.escaped= *escaped;
- old_ex.opt_flags= opt_flags;
- old_ex.empty_flags=empty_flags;
- return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex));
- }
-}
-
-
-static inline int read_str(char * &buf, char *buf_end, char * &str,
- uint8 &len)
-{
- if (buf + (uint) (uchar) *buf >= buf_end)
- return 1;
- len = (uint8) *buf;
- str= buf+1;
- buf+= (uint) len+1;
- return 0;
-}
-
-
-char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
-{
- cached_new_format = use_new_format;
- if (use_new_format)
- {
- empty_flags=0;
- /*
- The code below assumes that buf will not disappear from
- under our feet during the lifetime of the event. This assumption
- holds true in the slave thread if the log is in new format, but is not
- the case when we have old format because we will be reusing net buffer
- to read the actual file before we write out the Create_file event.
- */
- if (read_str(buf, buf_end, field_term, field_term_len) ||
- read_str(buf, buf_end, enclosed, enclosed_len) ||
- read_str(buf, buf_end, line_term, line_term_len) ||
- read_str(buf, buf_end, line_start, line_start_len) ||
- read_str(buf, buf_end, escaped, escaped_len))
- return 0;
- opt_flags = *buf++;
- }
- else
- {
- field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
- field_term = buf++; // Use first byte in string
- enclosed= buf++;
- line_term= buf++;
- line_start= buf++;
- escaped= buf++;
- opt_flags = *buf++;
- empty_flags= *buf++;
- if (empty_flags & FIELD_TERM_EMPTY)
- field_term_len=0;
- if (empty_flags & ENCLOSED_EMPTY)
- enclosed_len=0;
- if (empty_flags & LINE_TERM_EMPTY)
- line_term_len=0;
- if (empty_flags & LINE_START_EMPTY)
- line_start_len=0;
- if (empty_flags & ESCAPED_EMPTY)
- escaped_len=0;
- }
- return buf;
-}
-
-
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
-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),
+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)
+ :Log_event(thd_arg),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)
@@ -1162,25 +1227,32 @@ Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex,
field_lens = (const uchar*)field_lens_buf.ptr();
fields = fields_buf.ptr();
}
+#endif // !MYSQL_CLIENT
-#endif
+/*****************************************************************************
+
+ Load_log_event::Load_log_event()
-/*
The caller must do buf[event_len] = 0 before he starts using the
constructed event.
-*/
-Load_log_event::Load_log_event(const char* buf, int event_len,
+ ****************************************************************************/
+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)
+ 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;
copy_log_event(buf, event_len, old_format);
}
+/*****************************************************************************
+
+ Load_log_event::copy_log_event()
+
+ ****************************************************************************/
int Load_log_event::copy_log_event(const char *buf, ulong event_len,
bool old_format)
{
@@ -1225,8 +1297,12 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len,
return 0;
}
-#ifdef MYSQL_CLIENT
+/*****************************************************************************
+ Load_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
void Load_log_event::print(FILE* file, bool short_form, char* last_db)
{
if (!short_form)
@@ -1307,33 +1383,531 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file, ";\n");
}
-
#endif /* #ifdef MYSQL_CLIENT */
-#ifndef MYSQL_CLIENT
-
-void Log_event::set_log_pos(MYSQL_LOG* log)
-{
- if (!log_pos)
- log_pos = my_b_tell(&log->log_file);
-}
+/*****************************************************************************
+ Load_log_event::set_fields()
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
void Load_log_event::set_fields(List<Item> &field_list)
{
uint i;
- const char *field= fields;
+ const char* field = fields;
for (i= 0; i < num_fields; i++)
{
field_list.push_back(new Item_field(db, table_name, field));
field+= field_lens[i] + 1;
}
}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Load_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
+{
+ init_sql_alloc(&thd->mem_root, 8192,0);
+ thd->db = rewrite_db((char*)db);
+ thd->query = 0;
+ thd->query_error = 0;
+
+ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+ {
+ thd->set_time((time_t)when);
+ thd->current_tablenr = 0;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id = query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+
+ TABLE_LIST tables;
+ bzero((char*) &tables,sizeof(tables));
+ tables.db = thd->db;
+ tables.alias = tables.real_name = (char*)table_name;
+ tables.lock_type = TL_WRITE;
+ // the table will be opened in mysql_load
+ if (table_rules_on && !tables_ok(thd, &tables))
+ {
+ // TODO: this is a bug - this needs to be moved to the I/O thread
+ if (net)
+ skip_load_data_infile(net);
+ }
+ else
+ {
+ char llbuff[22];
+ enum enum_duplicates handle_dup = DUP_IGNORE;
+ if (sql_ex.opt_flags && REPLACE_FLAG)
+ handle_dup = DUP_REPLACE;
+ sql_exchange ex((char*)fname, sql_ex.opt_flags &&
+ DUMPFILE_FLAG );
+ String field_term(sql_ex.field_term,sql_ex.field_term_len,
+ system_charset_info);
+ String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,
+ system_charset_info);
+ String line_term(sql_ex.line_term,sql_ex.line_term_len,
+ system_charset_info);
+ String line_start(sql_ex.line_start,sql_ex.line_start_len,
+ system_charset_info);
+ String escaped(sql_ex.escaped,sql_ex.escaped_len, system_charset_info);
+
+ ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
+ if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
+ ex.field_term->length(0);
+
+ ex.skip_lines = skip_lines;
+ List<Item> field_list;
+ set_fields(field_list);
+ thd->slave_proxy_id = thd->thread_id;
+ if (net)
+ {
+ // mysql_load will use thd->net to read the file
+ thd->net.vio = net->vio;
+ /*
+ Make sure the client does not get confused about the packet sequence
+ */
+ thd->net.pkt_nr = net->pkt_nr;
+ }
+ if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0,
+ TL_WRITE))
+ thd->query_error = 1;
+ if (thd->cuted_fields)
+ sql_print_error("Slave: load data infile at position %s in log \
+'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME,
+ thd->cuted_fields );
+ if (net)
+ net->pkt_nr= thd->net.pkt_nr;
+ }
+ }
+ else
+ {
+ /*
+ We will just ask the master to send us /dev/null if we do not
+ want to load the data.
+ TODO: this a bug - needs to be done in I/O thread
+ */
+ if (net)
+ skip_load_data_infile(net);
+ }
+
+ thd->net.vio = 0;
+ thd->db= 0; // prevent db from being freed
+ close_thread_tables(thd);
+ if (thd->query_error)
+ {
+ int sql_error = thd->net.last_errno;
+ if (!sql_error)
+ sql_error = ER_UNKNOWN_ERROR;
+
+ slave_print_error(rli,sql_error,
+ "Slave: Error '%s' running load data infile ",
+ ER_SAFE(sql_error));
+ free_root(&thd->mem_root,0);
+ return 1;
+ }
+ free_root(&thd->mem_root,0);
+
+ if (thd->fatal_error)
+ {
+ sql_print_error("Slave: Fatal error running LOAD DATA INFILE ");
+ return 1;
+ }
+
+ return Log_event::exec_event(rli);
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Rotate_log_event methods
+ *****************************************************************************
+ ****************************************************************************/
+/*****************************************************************************
+
+ Rotate_log_event::pack_info()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Rotate_log_event::pack_info(String* packet)
+{
+ char buf1[256], buf[22];
+ String tmp(buf1, sizeof(buf1), system_charset_info);
+ tmp.length(0);
+ tmp.append(new_log_ident, ident_len);
+ tmp.append(";pos=");
+ tmp.append(llstr(pos,buf));
+ if (flags & LOG_EVENT_FORCED_ROTATE_F)
+ tmp.append("; forced by master");
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Rotate_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char buf[22];
+ if (short_form)
+ return;
+
+ print_header(file);
+ fprintf(file, "\tRotate to ");
+ if (new_log_ident)
+ my_fwrite(file, (byte*) new_log_ident, (uint)ident_len,
+ MYF(MY_NABP | MY_WME));
+ fprintf(file, " pos: %s", llstr(pos, buf));
+ if (flags & LOG_EVENT_FORCED_ROTATE_F)
+ fprintf(file," forced by master");
+ fputc('\n', file);
+ fflush(file);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Rotate_log_event::Rotate_log_event()
+
+ ****************************************************************************/
+Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
+ bool old_format)
+ :Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
+{
+ // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET
+ int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ uint ident_offset;
+ if (event_len < header_size)
+ return;
+ buf += header_size;
+ if (old_format)
+ {
+ ident_len = (uint)(event_len - OLD_HEADER_LEN);
+ pos = 4;
+ ident_offset = 0;
+ }
+ else
+ {
+ ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD);
+ pos = uint8korr(buf + R_POS_OFFSET);
+ ident_offset = ROTATE_HEADER_LEN;
+ }
+ set_if_smaller(ident_len,FN_REFLEN-1);
+ if (!(new_log_ident= my_strdup_with_length((byte*) buf +
+ ident_offset,
+ (uint) ident_len,
+ MYF(MY_WME))))
+ return;
+ alloced = 1;
+}
+
+/*****************************************************************************
+
+ Rotate_log_event::write_data()
+
+ ****************************************************************************/
+int Rotate_log_event::write_data(IO_CACHE* file)
+{
+ char buf[ROTATE_HEADER_LEN];
+ int8store(buf, pos + R_POS_OFFSET);
+ return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
+ my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
+}
+
+/*****************************************************************************
+
+ Rotate_log_event::exec_event()
+
+ Got a rotate log even from the master
+
+ IMPLEMENTATION
+ This is mainly used so that we can later figure out the logname and
+ position for the master.
+
+ We can't rotate the slave as this will cause infinitive rotations
+ in a A -> B -> A setup.
+
+ RETURN VALUES
+ 0 ok
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char* log_name = rli->master_log_name;
+ DBUG_ENTER("Rotate_log_event::exec_event");
+
+ pthread_mutex_lock(&rli->data_lock);
+ memcpy(log_name, new_log_ident, ident_len+1);
+ rli->master_log_pos = pos;
+ rli->relay_log_pos += get_event_len();
+ DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos));
+ pthread_mutex_unlock(&rli->data_lock);
+ pthread_cond_broadcast(&rli->data_cond);
+ flush_relay_log_info(rli);
+ DBUG_RETURN(0);
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Intvar_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Intvar_log_event::pack_info()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Intvar_log_event::pack_info(String* packet)
+{
+ char buf1[256], buf[22];
+ String tmp(buf1, sizeof(buf1), system_charset_info);
+ tmp.length(0);
+ tmp.append(get_var_type_name());
+ tmp.append('=');
+ tmp.append(llstr(val, buf));
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Intvar_log_event::Intvar_log_event()
+
+ ****************************************************************************/
+Intvar_log_event::Intvar_log_event(const char* buf, bool old_format)
+ :Log_event(buf, old_format)
+{
+ buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ type = buf[I_TYPE_OFFSET];
+ val = uint8korr(buf+I_VAL_OFFSET);
+}
+
+/*****************************************************************************
+
+ Intvar_log_event::get_var_type_name()
+
+ ****************************************************************************/
+const char* Intvar_log_event::get_var_type_name()
+{
+ switch(type) {
+ case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID";
+ case INSERT_ID_EVENT: return "INSERT_ID";
+ default: /* impossible */ return "UNKNOWN";
+ }
+}
+
+/*****************************************************************************
+
+ Intvar_log_event::write_data()
+
+ ****************************************************************************/
+int Intvar_log_event::write_data(IO_CACHE* file)
+{
+ char buf[9];
+ buf[I_TYPE_OFFSET] = type;
+ int8store(buf + I_VAL_OFFSET, val);
+ return my_b_safe_write(file, (byte*) buf, sizeof(buf));
+}
+
+/*****************************************************************************
+
+ Intvar_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void Intvar_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char llbuff[22];
+ const char *msg;
+ LINT_INIT(msg);
+
+ if (!short_form)
+ {
+ print_header(file);
+ fprintf(file, "\tIntvar\n");
+ }
+
+ fprintf(file, "SET ");
+ switch (type) {
+ case LAST_INSERT_ID_EVENT:
+ msg="LAST_INSERT_ID";
+ break;
+ case INSERT_ID_EVENT:
+ msg="INSERT_ID";
+ break;
+ }
+ fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff));
+ fflush(file);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Intvar_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ switch (type) {
+ case LAST_INSERT_ID_EVENT:
+ thd->last_insert_id_used = 1;
+ thd->last_insert_id = val;
+ break;
+ case INSERT_ID_EVENT:
+ thd->next_insert_id = val;
+ break;
+ }
+ rli->inc_pending(get_event_len());
+ return 0;
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Rand_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Rand_log_event::pack_info()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Rand_log_event::pack_info(String* packet)
+{
+ 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
+
+/*****************************************************************************
+
+ Rand_log_event::Rand_log_event()
+
+ ****************************************************************************/
+Rand_log_event::Rand_log_event(const char* buf, bool old_format)
+ :Log_event(buf, old_format)
+{
+ buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ seed1 = uint8korr(buf+RAND_SEED1_OFFSET);
+ seed2 = uint8korr(buf+RAND_SEED2_OFFSET);
+}
+
+/*****************************************************************************
+
+ Rand_log_event::write_data()
+
+ ****************************************************************************/
+int Rand_log_event::write_data(IO_CACHE* file)
+{
+ char buf[16];
+ int8store(buf + RAND_SEED1_OFFSET, seed1);
+ int8store(buf + RAND_SEED2_OFFSET, seed2);
+ return my_b_safe_write(file, (byte*) buf, sizeof(buf));
+}
+
+/*****************************************************************************
+
+ Rand_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char llbuff[22];
+ if (!short_form)
+ {
+ print_header(file);
+ fprintf(file, "\tRand\n");
+ }
+ fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
+ llstr(seed1, llbuff),llstr(seed2, llbuff));
+ fflush(file);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Rand_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Rand_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ thd->rand.seed1= (ulong) seed1;
+ thd->rand.seed2= (ulong) seed2;
+ rli->inc_pending(get_event_len());
+ return 0;
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Slave_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Slave_log_event::pack_info()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Slave_log_event::pack_info(String* packet)
+{
+ char buf1[256], buf[22], *end;
+ String tmp(buf1, sizeof(buf1), system_charset_info);
+ tmp.length(0);
+ tmp.append("host=");
+ tmp.append(master_host);
+ tmp.append(",port=");
+ end= int10_to_str((long) master_port, buf, 10);
+ tmp.append(buf, (uint32) (end-buf));
+ tmp.append(",log=");
+ tmp.append(master_log);
+ tmp.append(",pos=");
+ tmp.append(llstr(master_pos,buf));
+ net_store_data(packet, tmp.ptr(), tmp.length());
+}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Slave_log_event::Slave_log_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
Slave_log_event::Slave_log_event(THD* thd_arg,
- struct st_relay_log_info* rli):
- Log_event(thd_arg,0,0),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 ?
@@ -1364,17 +1938,24 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
pthread_mutex_unlock(&mi->data_lock);
DBUG_VOID_RETURN;
}
+#endif // !MYSQL_CLIENT
-#endif /* ! MYSQL_CLIENT */
+/*****************************************************************************
+ Slave_log_event dtor
+ ****************************************************************************/
Slave_log_event::~Slave_log_event()
{
my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
}
-#ifdef MYSQL_CLIENT
+/*****************************************************************************
+ Slave_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
{
char llbuff[22];
@@ -1386,14 +1967,23 @@ void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
master_log: '%s' master_pos: %s\n",
master_host, master_port, master_log, llstr(master_pos, llbuff));
}
+#endif // MYSQL_CLIENT
-#endif /* MYSQL_CLIENT */
+/*****************************************************************************
+
+ Slave_log_event::get_data_size()
+ ****************************************************************************/
int Slave_log_event::get_data_size()
{
return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
}
+/*****************************************************************************
+
+ Slave_log_event::write_data()
+
+ ****************************************************************************/
int Slave_log_event::write_data(IO_CACHE* file)
{
int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
@@ -1402,7 +1992,11 @@ int Slave_log_event::write_data(IO_CACHE* file)
return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
}
+/*****************************************************************************
+
+ Slave_log_event::init_from_mem_pool()
+ ****************************************************************************/
void Slave_log_event::init_from_mem_pool(int data_size)
{
master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET);
@@ -1419,6 +2013,11 @@ void Slave_log_event::init_from_mem_pool(int data_size)
master_log_len = strlen(master_log);
}
+/*****************************************************************************
+
+ Slave_log_event::Slave_log_event()
+
+ ****************************************************************************/
Slave_log_event::Slave_log_event(const char* buf, int event_len)
:Log_event(buf,0),mem_pool(0),master_host(0)
{
@@ -1432,6 +2031,93 @@ Slave_log_event::Slave_log_event(const char* buf, int event_len)
init_from_mem_pool(event_len);
}
+/*****************************************************************************
+
+ Slave_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Slave_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ return Log_event::exec_event(rli);
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Stop_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Stop_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ if (short_form)
+ return;
+
+ print_header(file);
+ fprintf(file, "\tStop\n");
+ fflush(file);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Stop_log_event::exec_event()
+
+ The master stopped. Clean up all temporary tables + locks that the
+ master may have set.
+
+ TODO
+ - Remove all active user locks
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Stop_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ // do not clean up immediately after rotate event
+ if (rli->master_log_pos > BIN_LOG_HEADER_SIZE)
+ {
+ close_temporary_tables(thd);
+ cleanup_load_tmpdir();
+ }
+ /*
+ We do not want to update master_log pos because we get a rotate event
+ before stop, so by now master_log_name is set to the next log.
+ If we updated it, we will have incorrect master coordinates and this
+ could give false triggers in MASTER_POS_WAIT() that we have reached
+ the target position when in fact we have not.
+ */
+ rli->inc_pos(get_event_len(), 0);
+ flush_relay_log_info(rli);
+ return 0;
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Create_file_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Create_file_log_event ctor
+
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
Create_file_log_event::
Create_file_log_event(THD* thd_arg, sql_exchange* ex,
@@ -1445,8 +2131,13 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex,
{
sql_ex.force_new_format();
}
-#endif
+#endif // !MYSQL_CLIENT
+/*****************************************************************************
+
+ Create_file_log_event::write_data_body()
+
+ ****************************************************************************/
int Create_file_log_event::write_data_body(IO_CACHE* file)
{
int res;
@@ -1456,6 +2147,11 @@ int Create_file_log_event::write_data_body(IO_CACHE* file)
my_b_safe_write(file, (byte*) block, block_len));
}
+/*****************************************************************************
+
+ Create_file_log_event::write_data_header()
+
+ ****************************************************************************/
int Create_file_log_event::write_data_header(IO_CACHE* file)
{
int res;
@@ -1466,6 +2162,11 @@ int Create_file_log_event::write_data_header(IO_CACHE* file)
return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
}
+/*****************************************************************************
+
+ Create_file_log_event::write_base()
+
+ ****************************************************************************/
int Create_file_log_event::write_base(IO_CACHE* file)
{
int res;
@@ -1475,6 +2176,11 @@ int Create_file_log_event::write_base(IO_CACHE* file)
return res;
}
+/*****************************************************************************
+
+ Create_file_log_event ctor
+
+ ****************************************************************************/
Create_file_log_event::Create_file_log_event(const char* buf, int len,
bool old_format)
:Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0)
@@ -1501,7 +2207,11 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len,
}
}
+/*****************************************************************************
+
+ Create_file_log_event::print()
+ ****************************************************************************/
#ifdef MYSQL_CLIENT
void Create_file_log_event::print(FILE* file, bool short_form,
char* last_db)
@@ -1511,13 +2221,18 @@ void Create_file_log_event::print(FILE* file, bool short_form,
Load_log_event::print(file, 1, last_db);
fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len);
}
-#endif
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Create_file_log_event::pack_info()
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
void Create_file_log_event::pack_info(String* packet)
{
char buf1[256],buf[22], *end;
- String tmp(buf1, sizeof(buf1));
+ String tmp(buf1, sizeof(buf1), system_charset_info);
tmp.length(0);
tmp.append("db=");
tmp.append(db, db_len);
@@ -1531,8 +2246,86 @@ void Create_file_log_event::pack_info(String* packet)
tmp.append(buf, (uint32) (end-buf));
net_store_data(packet, (char*) tmp.ptr(), tmp.length());
}
-#endif
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Create_file_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char fname_buf[FN_REFLEN+10];
+ char *p;
+ int fd = -1;
+ IO_CACHE file;
+ int error = 1;
+
+ bzero((char*)&file, sizeof(file));
+ p = slave_load_file_stem(fname_buf, file_id, server_id);
+ strmov(p, ".info"); // strmov takes less code than memcpy
+ if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
+ MYF(MY_WME|MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ goto err;
+ }
+
+ // a trick to avoid allocating another buffer
+ strmov(p, ".data");
+ fname = fname_buf;
+ fname_len = (uint)(p-fname) + 5;
+ if (write_base(&file))
+ {
+ strmov(p, ".info"); // to have it right in the error message
+ slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
+ goto err;
+ }
+ end_io_cache(&file);
+ my_close(fd, MYF(0));
+
+ // fname_buf now already has .data, not .info, because we did our trick
+ if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
+ MYF(MY_WME))) < 0)
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
+ goto err;
+ }
+ if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
+ goto err;
+ }
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ error=0; // Everything is ok
+
+err:
+ if (error)
+ end_io_cache(&file);
+ if (fd >= 0)
+ my_close(fd, MYF(0));
+ return error ? 1 : Log_event::exec_event(rli);
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Append_block_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+ Append_block_log_event ctor
+
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
uint block_len_arg,
@@ -1541,8 +2334,13 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
block_len(block_len_arg), file_id(thd_arg->file_id)
{
}
-#endif
-
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Append_block_log_event ctor
+
+ ****************************************************************************/
Append_block_log_event::Append_block_log_event(const char* buf, int len)
:Log_event(buf, 0),block(0)
{
@@ -1553,6 +2351,11 @@ Append_block_log_event::Append_block_log_event(const char* buf, int len)
block_len = len - APPEND_BLOCK_EVENT_OVERHEAD;
}
+/*****************************************************************************
+
+ Append_block_log_event::write_data()
+
+ ****************************************************************************/
int Append_block_log_event::write_data(IO_CACHE* file)
{
byte buf[APPEND_BLOCK_HEADER_LEN];
@@ -1561,6 +2364,11 @@ int Append_block_log_event::write_data(IO_CACHE* file)
my_b_safe_write(file, (byte*) block, block_len));
}
+/*****************************************************************************
+
+ Append_block_log_event::print()
+
+ ****************************************************************************/
#ifdef MYSQL_CLIENT
void Append_block_log_event::print(FILE* file, bool short_form,
char* last_db)
@@ -1572,23 +2380,86 @@ void Append_block_log_event::print(FILE* file, bool short_form,
fprintf(file, "#Append_block: file_id: %d block_len: %d\n",
file_id, block_len);
}
-#endif
+#endif // MYSQL_CLIENT
+/*****************************************************************************
+
+ Append_block_log_event::pack_info()
+
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
void Append_block_log_event::pack_info(String* packet)
{
- char buf1[256];
- sprintf(buf1, ";file_id=%u;block_len=%u", file_id, block_len);
- net_store_data(packet, buf1);
+ char buf[256];
+ uint length;
+ length= (uint) my_sprintf(buf,
+ (buf, ";file_id=%u;block_len=%u", file_id,
+ block_len));
+ net_store_data(packet, buf, (int32) length);
}
+#endif // !MYSQL_CLIENT
-Delete_file_log_event::Delete_file_log_event(THD* thd_arg, bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
+/*****************************************************************************
+
+ Append_block_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
{
+ char fname[FN_REFLEN+10];
+ char *p= slave_load_file_stem(fname, file_id, server_id);
+ int fd;
+ int error = 1;
+
+ memcpy(p, ".data", 6);
+ if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
+ {
+ slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
+ goto err;
+ }
+ if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
+ {
+ slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
+ goto err;
+ }
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ error=0;
+
+err:
+ if (fd >= 0)
+ my_close(fd, MYF(0));
+ return error ? error : Log_event::exec_event(rli);
}
-#endif
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Delete_file_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+ Delete_file_log_event ctor
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+Delete_file_log_event::Delete_file_log_event(THD *thd_arg, bool using_trans)
+ :Log_event(thd_arg, 0, using_trans),file_id(thd_arg->file_id)
+{
+}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Delete_file_log_event ctor
+
+ ****************************************************************************/
Delete_file_log_event::Delete_file_log_event(const char* buf, int len)
:Log_event(buf, 0),file_id(0)
{
@@ -1597,7 +2468,11 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, int len)
file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
}
+/*****************************************************************************
+
+ Delete_file_log_event::write_data()
+ ****************************************************************************/
int Delete_file_log_event::write_data(IO_CACHE* file)
{
byte buf[DELETE_FILE_HEADER_LEN];
@@ -1605,6 +2480,11 @@ int Delete_file_log_event::write_data(IO_CACHE* file)
return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN);
}
+/*****************************************************************************
+
+ Delete_file_log_event::print()
+
+ ****************************************************************************/
#ifdef MYSQL_CLIENT
void Delete_file_log_event::print(FILE* file, bool short_form,
char* last_db)
@@ -1615,25 +2495,69 @@ void Delete_file_log_event::print(FILE* file, bool short_form,
fputc('\n', file);
fprintf(file, "#Delete_file: file_id=%u\n", file_id);
}
-#endif
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Delete_file_log_event::pack_info()
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
void Delete_file_log_event::pack_info(String* packet)
{
- char buf1[64];
- sprintf(buf1, ";file_id=%u", (uint) file_id);
- net_store_data(packet, buf1);
+ char buf[64];
+ uint length;
+ length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id));
+ net_store_data(packet, buf, (int32) length);
}
-#endif
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Delete_file_log_event::exec_event()
+
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ char fname[FN_REFLEN+10];
+ char *p= slave_load_file_stem(fname, file_id, server_id);
+ memcpy(p, ".data", 6);
+ (void) my_delete(fname, MYF(MY_WME));
+ memcpy(p, ".info", 6);
+ (void) my_delete(fname, MYF(MY_WME));
+ if (mysql_bin_log.is_open())
+ mysql_bin_log.write(this);
+ return Log_event::exec_event(rli);
+}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Execute_load_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+ Execute_load_log_event ctor
+ ****************************************************************************/
#ifndef MYSQL_CLIENT
-Execute_load_log_event::Execute_load_log_event(THD* thd_arg, bool using_trans)
+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
+#endif // !MYSQL_CLIENT
+/*****************************************************************************
+
+ 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)
{
@@ -1642,6 +2566,11 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, int len)
file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET);
}
+/*****************************************************************************
+
+ Execute_load_log_event::write_data()
+
+ ****************************************************************************/
int Execute_load_log_event::write_data(IO_CACHE* file)
{
byte buf[EXEC_LOAD_HEADER_LEN];
@@ -1649,6 +2578,11 @@ int Execute_load_log_event::write_data(IO_CACHE* file)
return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN);
}
+/*****************************************************************************
+
+ Execute_load_log_event::print()
+
+ ****************************************************************************/
#ifdef MYSQL_CLIENT
void Execute_load_log_event::print(FILE* file, bool short_form,
char* last_db)
@@ -1660,426 +2594,29 @@ void Execute_load_log_event::print(FILE* file, bool short_form,
fprintf(file, "#Exec_load: file_id=%d\n",
file_id);
}
-#endif
-#ifndef MYSQL_CLIENT
-void Execute_load_log_event::pack_info(String* packet)
-{
- char buf[64];
- sprintf(buf, ";file_id=%u", (uint) file_id);
- net_store_data(packet, buf);
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-int Query_log_event::exec_event(struct st_relay_log_info* rli)
-{
- int expected_error,actual_error = 0;
- init_sql_alloc(&thd->mem_root, 8192,0);
- thd->db = rewrite_db((char*)db);
-
- /*
- InnoDB internally stores the master log position it has processed so far;
- position to store is really pos + pending + event_len
- since we must store the pos of the END of the current log event
- */
- rli->event_len= get_event_len();
-
- if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
- {
- thd->query = (char*)query;
- thd->set_time((time_t)when);
- thd->current_tablenr = 0;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = query_id++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- thd->query_error = 0; // clear error
- thd->net.last_errno = 0;
- thd->net.last_error[0] = 0;
- thd->slave_proxy_id = thread_id; // for temp tables
-
- /*
- Sanity check to make sure the master did not get a really bad
- error on the query.
- */
- if (ignored_error_code((expected_error = error_code)) ||
- !check_expected_error(thd,rli,expected_error))
- {
- mysql_log.write(thd,COM_QUERY,"%s",thd->query);
- DBUG_PRINT("query",("%s",thd->query));
- mysql_parse(thd, thd->query, q_len);
- if ((expected_error != (actual_error = thd->net.last_errno)) &&
- expected_error &&
- !ignored_error_code(actual_error) &&
- !ignored_error_code(expected_error))
- {
- const char* errmsg = "Slave: did not get the expected error\
- running query from master - expected: '%s' (%d), got '%s' (%d)";
- sql_print_error(errmsg, ER_SAFE(expected_error),
- expected_error,
- actual_error ? thd->net.last_error: "no error",
- actual_error);
- thd->query_error = 1;
- }
- else if (expected_error == actual_error ||
- ignored_error_code(actual_error))
- {
- thd->query_error = 0;
- *rli->last_slave_error = 0;
- rli->last_slave_errno = 0;
- }
- }
- else
- {
- // master could be inconsistent, abort and tell DBA to check/fix it
- thd->db = thd->query = 0;
- thd->variables.convert_set = 0;
- close_thread_tables(thd);
- free_root(&thd->mem_root,0);
- return 1;
- }
- }
- thd->db= 0; // prevent db from being freed
- thd->query= 0; // just to be sure
- // assume no convert for next query unless set explictly
- thd->variables.convert_set = 0;
- close_thread_tables(thd);
-
- if (thd->query_error || thd->fatal_error)
- {
- slave_print_error(rli,actual_error, "error '%s' on query '%s'",
- actual_error ? thd->net.last_error :
- "unexpected success or fatal error", query);
- free_root(&thd->mem_root,0);
- return 1;
- }
- free_root(&thd->mem_root,0);
- return Log_event::exec_event(rli);
-}
-
-
-int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
-{
- init_sql_alloc(&thd->mem_root, 8192,0);
- thd->db = rewrite_db((char*)db);
- thd->query = 0;
- thd->query_error = 0;
-
- if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
- {
- thd->set_time((time_t)when);
- thd->current_tablenr = 0;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_id = query_id++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- TABLE_LIST tables;
- bzero((char*) &tables,sizeof(tables));
- tables.db = thd->db;
- tables.alias = tables.real_name = (char*)table_name;
- tables.lock_type = TL_WRITE;
- // the table will be opened in mysql_load
- if (table_rules_on && !tables_ok(thd, &tables))
- {
- // TODO: this is a bug - this needs to be moved to the I/O thread
- if (net)
- skip_load_data_infile(net);
- }
- else
- {
- char llbuff[22];
- enum enum_duplicates handle_dup = DUP_IGNORE;
- if (sql_ex.opt_flags && REPLACE_FLAG)
- handle_dup = DUP_REPLACE;
- sql_exchange ex((char*)fname, sql_ex.opt_flags &&
- DUMPFILE_FLAG );
- String field_term(sql_ex.field_term,sql_ex.field_term_len);
- String enclosed(sql_ex.enclosed,sql_ex.enclosed_len);
- String line_term(sql_ex.line_term,sql_ex.line_term_len);
- String line_start(sql_ex.line_start,sql_ex.line_start_len);
- String escaped(sql_ex.escaped,sql_ex.escaped_len);
-
- ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
- if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
- ex.field_term->length(0);
-
- ex.skip_lines = skip_lines;
- List<Item> field_list;
- set_fields(field_list);
- thd->slave_proxy_id = thd->thread_id;
- if (net)
- {
- // mysql_load will use thd->net to read the file
- thd->net.vio = net->vio;
- /*
- Make sure the client does not get confused about the packet sequence
- */
- thd->net.pkt_nr = net->pkt_nr;
- }
- if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0,
- TL_WRITE))
- thd->query_error = 1;
- if (thd->cuted_fields)
- sql_print_error("Slave: load data infile at position %s in log \
-'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME,
- thd->cuted_fields );
- if (net)
- net->pkt_nr= thd->net.pkt_nr;
- }
- }
- else
- {
- /*
- We will just ask the master to send us /dev/null if we do not
- want to load the data.
- TODO: this a bug - needs to be done in I/O thread
- */
- if (net)
- skip_load_data_infile(net);
- }
-
- thd->net.vio = 0;
- thd->db= 0; // prevent db from being freed
- close_thread_tables(thd);
- if (thd->query_error)
- {
- int sql_error = thd->net.last_errno;
- if (!sql_error)
- sql_error = ER_UNKNOWN_ERROR;
-
- slave_print_error(rli,sql_error,
- "Slave: Error '%s' running load data infile ",
- ER_SAFE(sql_error));
- free_root(&thd->mem_root,0);
- return 1;
- }
- free_root(&thd->mem_root,0);
-
- if (thd->fatal_error)
- {
- sql_print_error("Slave: Fatal error running LOAD DATA INFILE ");
- return 1;
- }
-
- return Log_event::exec_event(rli);
-}
-
-
-/*
- The master started
-
- IMPLEMENTATION
- - To handle the case where the master died without a stop event,
- we clean up all temporary tables + locks that we got.
-
- TODO
- - Remove all active user locks
- - If we have an active transaction at this point, the master died
- in the middle while writing the transaction to the binary log.
- In this case we should stop the slave.
-*/
-
-int Start_log_event::exec_event(struct st_relay_log_info* rli)
-{
- /* All temporary tables was deleted on the master */
- close_temporary_tables(thd);
- /*
- If we have old format, load_tmpdir is cleaned up by the I/O thread
- */
- if (!rli->mi->old_format)
- cleanup_load_tmpdir();
- return Log_event::exec_event(rli);
-}
-
-
-/*
- The master stopped. Clean up all temporary tables + locks that the
- master may have set.
-
- TODO
- - Remove all active user locks
-*/
-
-int Stop_log_event::exec_event(struct st_relay_log_info* rli)
-{
- // do not clean up immediately after rotate event
- if (rli->master_log_pos > BIN_LOG_HEADER_SIZE)
- {
- close_temporary_tables(thd);
- cleanup_load_tmpdir();
- }
- /*
- We do not want to update master_log pos because we get a rotate event
- before stop, so by now master_log_name is set to the next log.
- If we updated it, we will have incorrect master coordinates and this
- could give false triggers in MASTER_POS_WAIT() that we have reached
- the target position when in fact we have not.
- */
- rli->inc_pos(get_event_len(), 0);
- flush_relay_log_info(rli);
- return 0;
-}
-
-
-/*
- Got a rotate log even from the master
-
- IMPLEMENTATION
- This is mainly used so that we can later figure out the logname and
- position for the master.
-
- We can't rotate the slave as this will cause infinitive rotations
- in a A -> B -> A setup.
-
- RETURN VALUES
- 0 ok
- */
-
-
-int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
-{
- char* log_name = rli->master_log_name;
- DBUG_ENTER("Rotate_log_event::exec_event");
-
- pthread_mutex_lock(&rli->data_lock);
- memcpy(log_name, new_log_ident, ident_len+1);
- rli->master_log_pos = pos;
- rli->relay_log_pos += get_event_len();
- DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos));
- pthread_mutex_unlock(&rli->data_lock);
- pthread_cond_broadcast(&rli->data_cond);
- flush_relay_log_info(rli);
- DBUG_RETURN(0);
-}
-
-
-int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
-{
- switch (type) {
- case LAST_INSERT_ID_EVENT:
- thd->last_insert_id_used = 1;
- thd->last_insert_id = val;
- break;
- case INSERT_ID_EVENT:
- thd->next_insert_id = val;
- break;
- }
- rli->inc_pending(get_event_len());
- return 0;
-}
-
-int Rand_log_event::exec_event(struct st_relay_log_info* rli)
-{
- thd->rand.seed1 = (ulong) seed1;
- thd->rand.seed2 = (ulong) seed2;
- rli->inc_pending(get_event_len());
- return 0;
-}
-
-int Slave_log_event::exec_event(struct st_relay_log_info* rli)
-{
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
- return Log_event::exec_event(rli);
-}
-
-int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
-{
- char fname_buf[FN_REFLEN+10];
- char *p;
- int fd = -1;
- IO_CACHE file;
- int error = 1;
+#endif // MYSQL_CLIENT
- bzero((char*)&file, sizeof(file));
- p = slave_load_file_stem(fname_buf, file_id, server_id);
- strmov(p, ".info"); // strmov takes less code than memcpy
- if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
- MYF(MY_WME|MY_NABP)))
- {
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
- goto err;
- }
-
- // a trick to avoid allocating another buffer
- strmov(p, ".data");
- fname = fname_buf;
- fname_len = (uint)(p-fname) + 5;
- if (write_base(&file))
- {
- strmov(p, ".info"); // to have it right in the error message
- slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf);
- goto err;
- }
- end_io_cache(&file);
- my_close(fd, MYF(0));
-
- // fname_buf now already has .data, not .info, because we did our trick
- if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
- MYF(MY_WME))) < 0)
- {
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf);
- goto err;
- }
- if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
- {
- slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf);
- goto err;
- }
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
- error=0; // Everything is ok
+/*****************************************************************************
-err:
- if (error)
- end_io_cache(&file);
- if (fd >= 0)
- my_close(fd, MYF(0));
- return error ? 1 : Log_event::exec_event(rli);
-}
+ Execute_load_log_event::pack_info()
-int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+void Execute_load_log_event::pack_info(String* packet)
{
- char fname[FN_REFLEN+10];
- char *p= slave_load_file_stem(fname, file_id, server_id);
- memcpy(p, ".data", 6);
- (void) my_delete(fname, MYF(MY_WME));
- memcpy(p, ".info", 6);
- (void) my_delete(fname, MYF(MY_WME));
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
- return Log_event::exec_event(rli);
+ char buf[64];
+ uint length;
+ length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id));
+ net_store_data(packet, buf, (int32) length);
}
+#endif // !MYSQL_CLIENT
-int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
-{
- char fname[FN_REFLEN+10];
- char *p= slave_load_file_stem(fname, file_id, server_id);
- int fd;
- int error = 1;
-
- memcpy(p, ".data", 6);
- if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0)
- {
- slave_print_error(rli,my_errno, "Could not open file '%s'", fname);
- goto err;
- }
- if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP)))
- {
- slave_print_error(rli,my_errno, "Write to '%s' failed", fname);
- goto err;
- }
- if (mysql_bin_log.is_open())
- mysql_bin_log.write(this);
- error=0;
+/*****************************************************************************
-err:
- if (fd >= 0)
- my_close(fd, MYF(0));
- return error ? error : Log_event::exec_event(rli);
-}
+ Execute_load_log_event::exec_event()
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
{
char fname[FN_REFLEN+10];
@@ -2138,5 +2675,100 @@ err:
}
return error ? error : Log_event::exec_event(rli);
}
+#endif // !MYSQL_CLIENT
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ sql_ex_info methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ sql_ex_info::write_data()
+
+ ****************************************************************************/
+int sql_ex_info::write_data(IO_CACHE* file)
+{
+ if (new_format())
+ {
+ return (write_str(file, field_term, field_term_len) ||
+ write_str(file, enclosed, enclosed_len) ||
+ write_str(file, line_term, line_term_len) ||
+ write_str(file, line_start, line_start_len) ||
+ write_str(file, escaped, escaped_len) ||
+ my_b_safe_write(file,(byte*) &opt_flags,1));
+ }
+ else
+ {
+ old_sql_ex old_ex;
+ old_ex.field_term= *field_term;
+ old_ex.enclosed= *enclosed;
+ old_ex.line_term= *line_term;
+ old_ex.line_start= *line_start;
+ old_ex.escaped= *escaped;
+ old_ex.opt_flags= opt_flags;
+ old_ex.empty_flags=empty_flags;
+ return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex));
+ }
+}
+
+/*****************************************************************************
+
+ sql_ex_info::init()
+
+ ****************************************************************************/
+char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
+{
+ cached_new_format = use_new_format;
+ if (use_new_format)
+ {
+ empty_flags=0;
+ /*
+ The code below assumes that buf will not disappear from
+ under our feet during the lifetime of the event. This assumption
+ holds true in the slave thread if the log is in new format, but is not
+ the case when we have old format because we will be reusing net buffer
+ to read the actual file before we write out the Create_file event.
+ */
+ if (read_str(buf, buf_end, field_term, field_term_len) ||
+ read_str(buf, buf_end, enclosed, enclosed_len) ||
+ read_str(buf, buf_end, line_term, line_term_len) ||
+ read_str(buf, buf_end, line_start, line_start_len) ||
+ read_str(buf, buf_end, escaped, escaped_len))
+ return 0;
+ opt_flags = *buf++;
+ }
+ else
+ {
+ field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1;
+ field_term = buf++; // Use first byte in string
+ enclosed= buf++;
+ line_term= buf++;
+ line_start= buf++;
+ escaped= buf++;
+ opt_flags = *buf++;
+ empty_flags= *buf++;
+ if (empty_flags & FIELD_TERM_EMPTY)
+ field_term_len=0;
+ if (empty_flags & ENCLOSED_EMPTY)
+ enclosed_len=0;
+ if (empty_flags & LINE_TERM_EMPTY)
+ line_term_len=0;
+ if (empty_flags & LINE_START_EMPTY)
+ line_start_len=0;
+ if (empty_flags & ESCAPED_EMPTY)
+ escaped_len=0;
+ }
+ return buf;
+}
+
+
+
+
+
+
-#endif /* !MYSQL_CLIENT */
diff --git a/sql/log_event.h b/sql/log_event.h
index 69a70d535ec..20a134ab3cc 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -54,6 +54,11 @@
#define LINE_START_EMPTY 0x8
#define ESCAPED_EMPTY 0x10
+/*****************************************************************************
+
+ old_sql_ex struct
+
+ ****************************************************************************/
struct old_sql_ex
{
char field_term;
@@ -67,6 +72,11 @@ struct old_sql_ex
#define NUM_LOAD_DELIM_STRS 5
+/*****************************************************************************
+
+ sql_ex_info struct
+
+ ****************************************************************************/
struct sql_ex_info
{
char* field_term;
@@ -99,13 +109,19 @@ struct sql_ex_info
}
};
-/*
- Binary log consists of events. Each event has a fixed length header,
- followed by possibly variable ( depending on the type of event) length
- data body. The data body consists of an optional fixed length segment
- (post-header), and an optional variable length segment. See #defines and
- comments below for the format specifics
-*/
+/*****************************************************************************
+
+ MySQL Binary Log
+
+ This log consists of events. Each event has a fixed-length header,
+ possibly followed by a variable length data body.
+
+ The data body consists of an optional fixed length segment (post-header)
+ and an optional variable length segment.
+
+ See the #defines below for the format specifics.
+
+ ****************************************************************************/
/* event-specific post-header sizes */
#define LOG_EVENT_HEADER_LEN 19
@@ -221,6 +237,13 @@ class THD;
struct st_relay_log_info;
+/*****************************************************************************
+
+ Log_event class
+
+ This is the abstract base class for binary log events.
+
+ ****************************************************************************/
class Log_event
{
public:
@@ -304,6 +327,13 @@ public:
};
+/*****************************************************************************
+
+ Query Log Event class
+
+ Logs SQL queries
+
+ ****************************************************************************/
class Query_log_event: public Log_event
{
protected:
@@ -354,6 +384,11 @@ public:
};
+/*****************************************************************************
+
+ Slave Log Event class
+
+ ****************************************************************************/
class Slave_log_event: public Log_event
{
protected:
@@ -383,6 +418,12 @@ public:
int write_data(IO_CACHE* file );
};
+
+/*****************************************************************************
+
+ Load Log Event class
+
+ ****************************************************************************/
class Load_log_event: public Log_event
{
protected:
@@ -448,6 +489,11 @@ public:
extern char server_version[SERVER_VERSION_LENGTH];
+/*****************************************************************************
+
+ Start Log Event class
+
+ ****************************************************************************/
class Start_log_event: public Log_event
{
public:
@@ -479,6 +525,13 @@ public:
};
+/*****************************************************************************
+
+ Intvar Log Event class
+
+ Logs special variables such as auto_increment values
+
+ ****************************************************************************/
class Intvar_log_event: public Log_event
{
public:
@@ -505,9 +558,11 @@ public:
};
/*****************************************************************************
- *
- * Rand log event class
- *
+
+ Rand Log Event class
+
+ Logs random seed used by the next RAND()
+
****************************************************************************/
class Rand_log_event: public Log_event
{
@@ -534,10 +589,15 @@ class Rand_log_event: public Log_event
};
+/*****************************************************************************
+
+ Stop Log Event class
+
+ ****************************************************************************/
class Stop_log_event: public Log_event
{
public:
-#ifndef MYSQL_CLIENT
+#ifndef MYSQL_CLIENT
Stop_log_event() :Log_event()
{}
int exec_event(struct st_relay_log_info* rli);
@@ -554,6 +614,13 @@ public:
};
+/*****************************************************************************
+
+ Rotate Log Event class
+
+ This will be depricated when we move to using sequence ids.
+
+ ****************************************************************************/
class Rotate_log_event: public Log_event
{
public:
@@ -589,6 +656,11 @@ public:
/* the classes below are for the new LOAD DATA INFILE logging */
+/*****************************************************************************
+
+ Create File Log Event class
+
+ ****************************************************************************/
class Create_file_log_event: public Load_log_event
{
protected:
@@ -646,6 +718,11 @@ public:
};
+/*****************************************************************************
+
+ Append Block Log Event class
+
+ ****************************************************************************/
class Append_block_log_event: public Log_event
{
public:
@@ -670,7 +747,11 @@ public:
int write_data(IO_CACHE* file);
};
+/*****************************************************************************
+ Delete File Log Event class
+
+ ****************************************************************************/
class Delete_file_log_event: public Log_event
{
public:
@@ -692,6 +773,11 @@ public:
int write_data(IO_CACHE* file);
};
+/*****************************************************************************
+
+ Execute Load Log Event class
+
+ ****************************************************************************/
class Execute_load_log_event: public Log_event
{
public:
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
index 5600983817b..0f20587ec24 100644
--- a/sql/mini_client.cc
+++ b/sql/mini_client.cc
@@ -40,6 +40,7 @@
#include "mysql_version.h"
#include "mysqld_error.h"
#include "errmsg.h"
+#include <assert.h>
#if defined( OS2) && defined(MYSQL_SERVER)
#undef ER
@@ -124,7 +125,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
if (!host || !strcmp(host,LOCAL_HOST))
host=LOCAL_HOST_NAMEDPIPE;
- sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
+ sprintf(szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket);
DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s",
host, unix_socket));
@@ -450,21 +451,21 @@ mc_simple_command(MYSQL *mysql,enum enum_server_command command,
mysql->net.last_error[0]=0;
mysql->net.last_errno=0;
+ mysql->net.report_error=0;
mysql->info=0;
mysql->affected_rows= ~(my_ulonglong) 0;
net_clear(net); /* Clear receive buffer */
if (!arg)
arg="";
- if (net_write_command(net,(uchar) command,arg,
- length ? length :(uint) strlen(arg)))
+ if (net_write_command(net, (uchar) command, NullS, 0, arg, length))
{
- DBUG_PRINT("error",("Can't send command to server. Error: %d",socket_errno));
+ DBUG_PRINT("error",("Can't send command to server. Error: %d",
+ socket_errno));
mc_end_server(mysql);
if (mc_mysql_reconnect(mysql))
goto end;
- if (net_write_command(net,(uchar) command,arg,
- length ? length :(uint) strlen(arg)))
+ if (net_write_command(net,(uchar) command, NullS, 0, arg, length))
{
net->last_errno=CR_SERVER_GONE_ERROR;
strmov(net->last_error,ER(net->last_errno));
@@ -1027,18 +1028,19 @@ get_info:
DBUG_RETURN(0);
}
-int mc_mysql_query(MYSQL *mysql, const char *query, uint length)
+
+int mc_mysql_query(MYSQL *mysql, const char *query, uint length)
{
- DBUG_ENTER("mysql_real_query");
+ DBUG_ENTER("mc_mysql_query");
DBUG_PRINT("enter",("handle: %lx",mysql));
DBUG_PRINT("query",("Query = \"%s\"",query));
- if (!length)
- length = strlen(query);
+ DBUG_ASSERT(length == strlen(query));
if (mc_simple_command(mysql,COM_QUERY,query,length,1))
DBUG_RETURN(-1);
DBUG_RETURN(mc_mysql_read_query_result(mysql));
}
+
static int mc_send_file_to_server(MYSQL *mysql, const char *filename)
{
int fd, readcount, result= -1;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 43de81cae00..4317ea05041 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -61,6 +61,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#endif
#endif
+#define my_thd_charset default_charset_info
+
/***************************************************************************
Configuration parameters
****************************************************************************/
@@ -200,6 +202,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
@@ -292,7 +299,10 @@ inline THD *_current_thd(void)
#define query_cache_invalidate_by_MyISAM_filename_ref NULL
#endif /*HAVE_QUERY_CACHE*/
-int mysql_create_db(THD *thd, char *db, uint create_info, bool silent);
+#define prepare_execute(A) ((A)->command == COM_EXECUTE)
+
+int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent);
+int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create);
int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent);
void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists);
@@ -306,8 +316,13 @@ int quick_rm_table(enum db_type base,const char *db,
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
+void free_items(Item *item);
+bool alloc_query(THD *thd, char *packet, ulong packet_length);
void mysql_init_select(LEX *lex);
-bool mysql_new_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);
@@ -316,7 +331,7 @@ 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(void);
+void mysql_execute_command(THD *thd);
bool do_command(THD *thd);
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length);
@@ -347,11 +362,12 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
bool check_simple_select();
/* net_pkg.c */
-void send_warning(NET *net, uint sql_errno, const char *err=0);
-void net_printf(NET *net,uint sql_errno, ...);
-void send_ok(NET *net,ha_rows affected_rows=0L,ulonglong id=0L,
+void send_warning(THD *thd, uint sql_errno, const char *err=0);
+void net_printf(THD *thd,uint sql_errno, ...);
+void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
const char *info=0);
-void send_eof(NET *net,bool no_flush=0);
+void send_eof(THD *thd, bool no_flush=0);
+void net_send_error(NET *net, uint sql_errno, const char *err);
char *net_store_length(char *packet,ulonglong length);
char *net_store_length(char *packet,uint length);
char *net_store_data(char *to,const char *from);
@@ -372,19 +388,30 @@ bool net_store_data(String *packet, CONVERT *convert, const char *from);
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
List <Item> &all_fields, ORDER *order);
+int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
+ List<Item> &all_fields, ORDER *order,
+ bool *hidden_group_fields);
int handle_select(THD *thd, LEX *lex, select_result *result);
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
- ulong select_type,select_result *result);
-int mysql_union(THD *thd,LEX *lex,select_result *result);
+ ulong select_type,select_result *result,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
+ bool fake_select_lex);
+void fix_tables_pointers(SELECT_LEX *select_lex);
+int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
+ select_result *result);
+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);
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);
int mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields, List<Key> &keys,
- bool tmp_table, bool no_log);
+ bool tmp_table, bool no_log, uint select_field_count);
TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
const char *db, const char *name,
List<create_field> *extra_fields,
@@ -435,7 +462,9 @@ bool wait_for_tables(THD *thd);
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);
-Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables);
+extern const Field *not_found_field;
+Field *find_field_in_tables(THD *thd, Item_field *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
@@ -457,7 +486,7 @@ bool load_des_key_file(const char *file_name);
/* sql_do.cc */
int mysql_do(THD *thd, List<Item> &values);
-/* sql_list.c */
+/* sql_show.cc */
int mysqld_show_dbs(THD *thd,const char *wild);
int mysqld_show_open_tables(THD *thd,const char *wild);
int mysqld_show_tables(THD *thd,const char *db,const char *wild);
@@ -469,12 +498,33 @@ 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, HA_CREATE_INFO *create);
void mysqld_list_processes(THD *thd,const char *user,bool verbose);
int mysqld_show_status(THD *thd);
int mysqld_show_variables(THD *thd,const char *wild);
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
enum enum_var_type value_type);
+int mysqld_show_charsets(THD *thd,const char *wild);
+int mysqld_show_table_types(THD *thd);
+int mysqld_show_privileges(THD *thd);
+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);
+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_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);
+
+/* sql_error.cc */
+void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
+ const char *msg);
+my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
/* sql_handler.cc */
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
@@ -486,15 +536,11 @@ int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
void set_item_name(Item *item,char *pos,uint length);
bool add_field_to_list(char *field_name, enum enum_field_types type,
char *length, char *decimal,
- uint type_modifier, Item *default_value,char *change,
- TYPELIB *interval);
+ 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);
-TABLE_LIST *add_table_to_list(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);
void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
@@ -503,7 +549,11 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
table_map read_tables, COND *conds, int *error);
-Item ** find_item_in_list(Item *item,List<Item> &items);
+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,
+ find_item_error_report_type report_error);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
List_iterator<Item> *it);
@@ -512,8 +562,8 @@ int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item,
bool set_query_id,List<Item> *sum_func_list,
bool allow_sum_func);
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
-int setup_ftfuncs(THD *thd);
-int init_ftfuncs(THD *thd, bool no_order);
+int setup_ftfuncs(SELECT_LEX* select);
+int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
void wait_for_refresh(THD *thd);
int open_tables(THD *thd,TABLE_LIST *tables);
int open_and_lock_tables(THD *thd,TABLE_LIST *tables);
@@ -564,7 +614,7 @@ extern "C" pthread_handler_decl(handle_manager, arg);
#ifndef DBUG_OFF
void print_where(COND *cond,const char *info);
void print_cached_tables(void);
-void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special);
+void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
#endif
void mysql_print_status(THD *thd);
/* key.cc */
@@ -595,8 +645,9 @@ void clear_error_message(THD *thd);
extern time_t start_time;
extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
- max_sort_char, mysql_real_data_home[], *charsets_list;
-extern my_string mysql_tmpdir;
+ mysql_real_data_home[], *charsets_list, *opt_mysql_tmpdir;
+#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
+extern MY_TMPDIR mysql_tmpdir_list;
extern const char *command_name[];
extern const char *first_keyword, *localhost, *delayed_user;
extern const char **errmesg; /* Error messages */
@@ -655,13 +706,13 @@ extern char f_fyllchar;
extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
extern FILE *bootstrap_file;
extern pthread_key(MEM_ROOT*,THR_MALLOC);
-extern pthread_key(NET*, THR_NET);
extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open,
LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
- LOCK_grant, LOCK_error_log, LOCK_delayed_insert,
+ LOCK_error_log, LOCK_delayed_insert,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager,
LOCK_global_system_variables;
+extern rw_lock_t LOCK_grant;
extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager;
extern pthread_attr_t connection_attrib;
extern I_List<THD> threads;
@@ -669,6 +720,10 @@ extern MY_BITMAP temp_pool;
extern DATE_FORMAT dayord;
extern String empty_string;
extern SHOW_VAR init_vars[],status_vars[], internal_vars[];
+extern struct show_table_type_st table_type_vars[];
+extern SHOW_COMP_OPTION have_isam;
+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;
@@ -709,7 +764,7 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
void unireg_init(ulong options);
void unireg_end(void);
-int rea_create_table(my_string file_name,HA_CREATE_INFO *create_info,
+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);
int format_number(uint inputflag,uint max_length,my_string pos,uint length,
@@ -742,9 +797,9 @@ void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form,
SQL_SELECT *select,
int use_record_cache, bool print_errors);
void end_read_record(READ_RECORD *info);
-ha_rows filesort(TABLE *form,struct st_sort_field *sortorder, uint s_length,
- SQL_SELECT *select, ha_rows special,ha_rows max_rows,
- ha_rows *examined_rows);
+ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder,
+ uint s_length, SQL_SELECT *select,
+ ha_rows max_rows, ha_rows *examined_rows);
void change_double_for_sort(double nr,byte *to);
int get_quick_record(SQL_SELECT *select);
int calc_weekday(long daynr,bool sunday_first_day_of_week);
@@ -758,7 +813,7 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names);
ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames,
const char *newname);
ulong next_io_size(ulong pos);
-void append_unescaped(String *res,const char *pos);
+void append_unescaped(String *res, const char *pos, uint length);
int create_frm(char *name,uint reclength,uchar *fileinfo,
HA_CREATE_INFO *create_info, uint keys);
void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
@@ -767,11 +822,7 @@ bool check_db_name(const char *db);
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(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(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 *wildstr);
/* from hostname.cc */
struct in_addr;
@@ -790,24 +841,26 @@ extern int sql_cache_hit(THD *thd, char *inBuf, uint length);
/* item.cc */
Item *get_system_var(enum_var_type var_type, LEX_STRING name);
+Item *get_system_var(enum_var_type var_type, const char *var_name, uint length,
+ const char *item_name);
/* Some inline functions for more speed */
inline bool add_item_to_list(Item *item)
{
- return current_lex->select->item_list.push_back(item);
+ return current_lex->current_select->add_item_to_list(item);
}
inline bool add_value_to_list(Item *value)
{
return current_lex->value_list.push_back(value);
}
-inline bool add_order_to_list(Item *item,bool asc)
+inline bool add_order_to_list(Item *item, bool asc)
{
- return add_to_list(current_lex->select->order_list,item,asc);
+ return current_lex->current_select->add_order_to_list(item, asc);
}
-inline bool add_group_to_list(Item *item,bool asc)
+inline bool add_group_to_list(Item *item, bool asc)
{
- return add_to_list(current_lex->select->group_list,item,asc);
+ return current_lex->current_select->add_group_to_list(item, asc);
}
inline void mark_as_null_row(TABLE *table)
{
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ffe3d1be47c..ebda24b404a 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -179,10 +179,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;
@@ -240,6 +243,8 @@ SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_YES;
SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO;
#endif
+const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
+
bool opt_large_files= sizeof(my_off_t) > 4;
/*
@@ -333,6 +338,11 @@ ulong query_cache_limit=0;
Query_cache query_cache;
#endif
+#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;
// replication parameters, if master_host is not NULL, we are a slave
@@ -393,7 +403,8 @@ const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF";
ulong rpl_recovery_rank=0;
-my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL, mysql_tmpdir=NULL;
+my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL;
+MY_TMPDIR mysql_tmpdir_list;
ulong my_bind_addr; /* the address we bind to */
char *my_bind_addr_str;
DATE_FORMAT dayord;
@@ -403,8 +414,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};
@@ -413,15 +428,14 @@ my_bool use_temp_pool=0;
pthread_key(MEM_ROOT*,THR_MALLOC);
pthread_key(THD*, THR_THD);
-pthread_key(NET*, THR_NET);
pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count,
- LOCK_mapped_file, LOCK_status, LOCK_grant,
+ LOCK_mapped_file, LOCK_status,
LOCK_error_log,
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received,
LOCK_global_system_variables,
LOCK_user_conn, LOCK_slave_list, LOCK_active_mi;
-
+rw_lock_t LOCK_grant;
pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped,
COND_slave_start;
pthread_cond_t COND_thread_cache,COND_flush_thread_cache;
@@ -457,6 +471,9 @@ static bool read_init_file(char *file_name);
#ifdef __NT__
extern "C" pthread_handler_decl(handle_connections_namedpipes,arg);
#endif
+#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);
@@ -868,7 +885,7 @@ void clean_up(bool print_message)
if (defaults_argv)
free_defaults(defaults_argv);
my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR));
- my_free(mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
+ free_tmpdir(&mysql_tmpdir_list);
my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
x_free(opt_bin_logname);
x_free(opt_relay_logname);
@@ -959,7 +976,7 @@ static void set_user(const char *user)
{
// allow a numeric uid to be used
const char *pos;
- for (pos=user; isdigit(*pos); pos++) ;
+ for (pos=user; my_isdigit(system_charset_info,*pos); pos++) ;
if (*pos) // Not numeric id
{
fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
@@ -1062,7 +1079,7 @@ static void server_init(void)
if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap &&
opt_enable_named_pipe)
{
- sprintf( szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port );
+ sprintf(szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port );
ZeroMemory( &saPipeSecurity, sizeof(saPipeSecurity) );
ZeroMemory( &sdPipeDescriptor, sizeof(sdPipeDescriptor) );
if ( !InitializeSecurityDescriptor(&sdPipeDescriptor,
@@ -1147,12 +1164,12 @@ static void server_init(void)
void yyerror(const char *s)
{
- NET *net=my_pthread_getspecific_ptr(NET*,THR_NET);
- char *yytext=(char*) current_lex->tok_start;
+ THD *thd=current_thd;
+ char *yytext=(char*) thd->lex.tok_start;
if (!strcmp(s,"parse error"))
s=ER(ER_SYNTAX_ERROR);
- net_printf(net,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
- current_lex->yylineno);
+ net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "",
+ thd->lex.yylineno);
}
@@ -1168,7 +1185,7 @@ void close_connection(NET *net,uint errcode,bool lock)
if ((vio=net->vio) != 0)
{
if (errcode)
- send_error(net,errcode,ER(errcode)); /* purecov: inspected */
+ net_send_error(net,errcode,ER(errcode)); /* purecov: inspected */
vio_close(vio); /* vio is freed in delete thd */
}
if (lock)
@@ -1565,8 +1582,8 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0)
{
char buff[21];
- sprintf(buff,"%lu",(ulong) getpid());
- (void) my_write(pidFile, buff,strlen(buff),MYF(MY_WME));
+ ulong length= my_sprintf(buff, (buff,"%lu",(ulong) getpid()));
+ (void) my_write(pidFile, buff, length, MYF(MY_WME));
(void) my_close(pidFile,MYF(0));
}
}
@@ -1664,11 +1681,13 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
extern "C" int my_message_sql(uint error, const char *str,
myf MyFlags __attribute__((unused)))
{
- NET *net;
+ THD *thd;
DBUG_ENTER("my_message_sql");
DBUG_PRINT("error",("Message: '%s'",str));
- if ((net=my_pthread_getspecific_ptr(NET*,THR_NET)))
+ if ((thd=current_thd))
{
+ NET *net= &thd->net;
+ net->report_error= 1;
if (!net->last_error[0]) // Return only first message
{
strmake(net->last_error,str,sizeof(net->last_error)-1);
@@ -1866,17 +1885,6 @@ int main(int argc, char **argv)
load_defaults(MYSQL_CONFIG_NAME,load_default_groups,&argc,&argv);
defaults_argv=argv;
- /* Get default temporary directory */
- opt_mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */
-#if defined( __WIN__) || defined(OS2)
- if (!opt_mysql_tmpdir)
- opt_mysql_tmpdir=getenv("TEMP");
- if (!opt_mysql_tmpdir)
- opt_mysql_tmpdir=getenv("TMP");
-#endif
- if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0])
- opt_mysql_tmpdir=(char*) P_tmpdir; /* purecov: inspected */
-
set_options();
get_options(argc,argv);
if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
@@ -1888,7 +1896,6 @@ int main(int argc, char **argv)
(void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW);
(void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW);
@@ -1906,6 +1913,7 @@ int main(int argc, char **argv)
(void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST);
(void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST);
+ (void) my_rwlock_init(&LOCK_grant, NULL);
(void) pthread_cond_init(&COND_thread_count,NULL);
(void) pthread_cond_init(&COND_refresh,NULL);
(void) pthread_cond_init(&COND_thread_cache,NULL);
@@ -1916,7 +1924,7 @@ int main(int argc, char **argv)
if (set_default_charset_by_name(sys_charset.value, MYF(MY_WME)))
exit(1);
- charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS));
+ charsets_list= list_charsets(MYF(MY_CS_COMPILED | MY_CS_CONFIG));
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
@@ -2064,7 +2072,7 @@ int main(int argc, char **argv)
After this we can't quit by a simple unireg_abort
*/
error_handler_hook = my_message_sql;
- if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) ||
+ if (pthread_key_create(&THR_THD,NULL) ||
pthread_key_create(&THR_MALLOC,NULL))
{
sql_print_error("Can't create thread-keys");
@@ -2173,21 +2181,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++;
@@ -2198,18 +2209,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);
}
@@ -2505,7 +2531,7 @@ static void create_new_thread(THD *thd)
thread_count--;
thd->killed=1; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
- net_printf(net,ER_CANT_CREATE_THREAD,error);
+ net_printf(thd,ER_CANT_CREATE_THREAD,error);
(void) pthread_mutex_lock(&LOCK_thread_count);
close_connection(net,0,0);
delete thd;
@@ -2827,6 +2853,219 @@ extern "C" 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
@@ -2911,6 +3150,7 @@ enum options {
OPT_MAX_JOIN_SIZE, OPT_MAX_SORT_LENGTH,
OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
+ OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT,
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
@@ -2936,7 +3176,9 @@ 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
};
@@ -2973,13 +3215,13 @@ struct my_option my_long_options[] =
#endif /* HAVE_BERKELEY_DB */
{"skip-bdb", OPT_BDB_SKIP, "Don't use berkeley db (will save memory)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"big-tables", OPT_BIG_TABLES,
+ {"big-tables", OPT_BIG_TABLES,
"Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors)",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"binlog-do-db", OPT_BINLOG_DO_DB,
"Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
+ {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
"Tells the master that updates to the given database should not be logged tothe binary log",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"bind-address", OPT_BIND_ADDRESS, "IP address to bind to",
@@ -3043,6 +3285,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,
@@ -3291,6 +3538,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,
@@ -3355,11 +3607,19 @@ struct my_option my_long_options[] =
#ifdef HAVE_OPENSSL
#include "sslopt-longopts.h"
#endif
- {"temp-pool", OPT_TEMP_POOL,
+ {"temp-pool", OPT_TEMP_POOL,
"Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.",
(gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
0, 0, 0, 0, 0},
- {"tmpdir", 't', "Path for temporary files", (gptr*) &opt_mysql_tmpdir,
+ {"tmpdir", 't',
+ "Path for temporary files. Several paths may be specified, separated by a "
+#if defined( __WIN__) || defined(OS2)
+ "semicolon (;)"
+#else
+ "colon (:)"
+#endif
+ ", in this case they are used in a round-robin fashion.",
+ (gptr*) &opt_mysql_tmpdir,
(gptr*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"transaction-isolation", OPT_TX_ISOLATION,
"Default transaction isolation level", 0, 0, 0, GET_STR, REQUIRED_ARG, 0,
@@ -3537,6 +3797,11 @@ struct my_option my_long_options[] =
"Don't start more than this number of threads to handle INSERT DELAYED statements.",
(gptr*) &max_insert_delayed_threads, (gptr*) &max_insert_delayed_threads,
0, GET_ULONG, REQUIRED_ARG, 20, 1, 16384, 0, 1, 0},
+ {"max_error_count", OPT_MAX_ERROR_COUNT,
+ "Max number of errors/warnings to store for a statement",
+ (gptr*) &global_system_variables.max_error_count,
+ (gptr*) &max_system_variables.max_error_count,
+ 0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 1, 65535, 0, 1, 0},
{"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE,
"Don't allow creation of heap tables bigger than this.",
(gptr*) &global_system_variables.max_heap_table_size,
@@ -3547,6 +3812,11 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.max_join_size,
(gptr*) &max_system_variables.max_join_size, 0, GET_ULONG, REQUIRED_ARG,
~0L, 1, ~0L, 0, 1, 0},
+ {"max_prepared_statements", OPT_MAX_PREP_STMT,
+ "Max number of prepared_statements for a thread",
+ (gptr*) &global_system_variables.max_prep_stmt_count,
+ (gptr*) &max_system_variables.max_prep_stmt_count, 0, GET_ULONG,
+ REQUIRED_ARG, DEFAULT_PREP_STMT_COUNT, 0, ~0L, 0, 1, 0},
{"max_sort_length", OPT_MAX_SORT_LENGTH,
"The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).",
(gptr*) &global_system_variables.max_sort_length,
@@ -3932,10 +4202,10 @@ 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_REPEATABLE_READ;
- global_system_variables.select_limit= (ulong) HA_POS_ERROR;
+ 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 */
@@ -3971,8 +4241,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':
@@ -4069,7 +4339,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
exit(1);
}
val= p--;
- while (isspace(*p) && p > argument)
+ while (my_isspace(system_charset_info, *p) && p > argument)
*p-- = 0;
if (p == argument)
{
@@ -4079,7 +4349,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
*val= 0;
val+= 2;
- while (*val && isspace(*val))
+ while (*val && my_isspace(system_charset_info, *val))
*val++;
if (!*val)
{
@@ -4221,7 +4491,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
have_symlink=SHOW_OPTION_DISABLED;
break;
case (int) OPT_BIND_ADDRESS:
- if (argument && isdigit(argument[0]))
+ if (argument && my_isdigit(system_charset_info, argument[0]))
{
my_bind_addr = (ulong) inet_addr(argument);
}
@@ -4534,9 +4804,7 @@ static void fix_paths(void)
charsets_dir=mysql_charsets_dir;
}
- char *end=convert_dirname(buff, opt_mysql_tmpdir, NullS);
- if (!(mysql_tmpdir= my_memdup((byte*) buff,(uint) (end-buff)+1,
- MYF(MY_FAE))))
+ if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir))
exit(1);
if (!slave_load_tmpdir)
{
@@ -4637,7 +4905,8 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
j=pos;
while (j != end)
{
- if (toupper(*i++) != toupper(*j++))
+ if (my_toupper(system_charset_info,*i++) !=
+ my_toupper(system_charset_info,*j++))
goto skipp;
}
found_int=bit;
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
index 8bb601cebcf..1da625e776f 100644
--- a/sql/net_pkg.cc
+++ b/sql/net_pkg.cc
@@ -20,19 +20,18 @@
/* Send a error string to client */
-void send_error(NET *net, uint sql_errno, const char *err)
+void send_error(THD *thd, uint sql_errno, const char *err)
{
uint length;
char buff[MYSQL_ERRMSG_SIZE+2];
- THD *thd=current_thd;
+ NET *net= &thd->net;
DBUG_ENTER("send_error");
DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno,
err ? err : net->last_error[0] ?
- net->last_error : "NULL"));
+ net->last_error : "NULL"));
query_cache_abort(net);
- if (thd)
- thd->query_error = 1; // needed to catch query errors during replication
+ thd->query_error= 1; // needed to catch query errors during replication
if (!err)
{
if (sql_errno)
@@ -50,7 +49,7 @@ void send_error(NET *net, uint sql_errno, const char *err)
}
if (net->vio == 0)
{
- if (thd && thd->bootstrap)
+ if (thd->bootstrap)
{
/* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
@@ -67,46 +66,75 @@ void send_error(NET *net, uint sql_errno, const char *err)
else
{
length=(uint) strlen(err);
- set_if_smaller(length,MYSQL_ERRMSG_SIZE);
+ set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
}
- VOID(net_write_command(net,(uchar) 255,(char*) err,length));
- if (thd)
- thd->fatal_error=0; // Error message is given
+ VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length));
+ thd->fatal_error=0; // Error message is given
+ thd->net.report_error= 0;
DBUG_VOID_RETURN;
}
/*
- At some point we need to be able to distinguish between warnings and
- errors; The following function will help make this easier.
+ Send an error to the client when a connection is forced close
+ This is used by mysqld.cc, which doesn't have a THD
*/
-void send_warning(NET *net, uint sql_errno, const char *err)
+void net_send_error(NET *net, uint sql_errno, const char *err)
{
- DBUG_ENTER("send_warning");
- send_error(net,sql_errno,err);
+ char buff[2];
+ uint length;
+ DBUG_ENTER("send_net_error");
+
+ int2store(buff,sql_errno);
+ length=(uint) strlen(err);
+ set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
+ net_write_command(net,(uchar) 255, buff, 2, err, length);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Send a warning to the end user
+
+ SYNOPSIS
+ send_warning()
+ thd Thread handler
+ sql_errno Warning number (error message)
+ err Error string. If not set, use ER(sql_errno)
+
+ DESCRIPTION
+ Register the warning so that the user can get it with mysql_warnings()
+ Send an ok (+ warning count) to the end user.
+*/
+
+void send_warning(THD *thd, uint sql_errno, const char *err)
+{
+ DBUG_ENTER("send_warning");
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno,
+ err ? err : ER(sql_errno));
+ send_ok(thd);
DBUG_VOID_RETURN;
}
/*
Write error package and flush to client
- It's a little too low level, but I don't want to allow another buffer
+ It's a little too low level, but I don't want to use another buffer for
+ this
*/
-/* VARARGS3 */
void
-net_printf(NET *net, uint errcode, ...)
+net_printf(THD *thd, uint errcode, ...)
{
va_list args;
uint length,offset;
const char *format,*text_pos;
int head_length= NET_HEADER_SIZE;
- THD *thd=current_thd;
+ NET *net= &thd->net;
DBUG_ENTER("net_printf");
DBUG_PRINT("enter",("message: %u",errcode));
- if (thd)
- thd->query_error = 1; // if we are here, something is wrong :-)
+ thd->query_error= 1; // needed to catch query errors during replication
query_cache_abort(net); // Safety
va_start(args,errcode);
/*
@@ -132,7 +160,7 @@ net_printf(NET *net, uint errcode, ...)
if (net->vio == 0)
{
- if (thd && thd->bootstrap)
+ if (thd->bootstrap)
{
/* In bootstrap it's ok to print on stderr */
fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
@@ -147,16 +175,42 @@ net_printf(NET *net, uint errcode, ...)
if (offset)
int2store(text_pos-2, errcode);
VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
- if (thd)
- thd->fatal_error=0; // Error message is given
+ thd->fatal_error=0; // Error message is given
DBUG_VOID_RETURN;
}
+/*
+ Return ok to the client.
+
+ SYNOPSIS
+ send_ok()
+ thd Thread handler
+ affected_rows Number of rows changed by statement
+ id Auto_increment id for first row (if used)
+ message Message to send to the client (Used by mysql_status)
+
+ DESCRIPTION
+ The ok packet has the following structure
+
+ 0 Marker (1 byte)
+ affected_rows Stored in 1-9 bytes
+ id Stored in 1-9 bytes
+ server_status Copy of thd->server_status; Can be used by client
+ to check if we are inside an transaction
+ New in 4.0 protocol
+ warning_count Stored in 2 bytes; New in 4.1 protocol
+ message Stored as packed length (1-9 bytes) + message
+ Is not stored if no message
+
+ If net->no_send_ok return without sending packet
+*/
+
void
-send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
+send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
{
- if (net->no_send_ok) // hack for re-parsing queries
+ NET *net= &thd->net;
+ if (net->no_send_ok || !net->vio) // hack for re-parsing queries
return;
char buff[MYSQL_ERRMSG_SIZE+10],*pos;
@@ -164,31 +218,75 @@ send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
buff[0]=0; // No fields
pos=net_store_length(buff+1,(ulonglong) affected_rows);
pos=net_store_length(pos, (ulonglong) id);
- if (net->return_status)
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- int2store(pos,*net->return_status);
+ int2store(pos,thd->server_status);
pos+=2;
+
+ /* We can only return up to 65535 warnings in two bytes */
+ uint tmp= min(thd->total_warn_count, 65535);
+ int2store(pos, tmp);
+ pos+= 2;
}
- if (message)
- pos=net_store_data((char*) pos,message);
- if (net->vio != 0)
+ else if (net->return_status) // For 4.0 protocol
{
- VOID(my_net_write(net,buff,(uint) (pos-buff)));
- VOID(net_flush(net));
+ int2store(pos,thd->server_status);
+ pos+=2;
}
+ if (message)
+ pos=net_store_data((char*) pos,message);
+ VOID(my_net_write(net,buff,(uint) (pos-buff)));
+ VOID(net_flush(net));
DBUG_VOID_RETURN;
}
+
+/*
+ Send eof (= end of result set) to the client
+
+ SYNOPSIS
+ send_eof()
+ thd Thread handler
+ no_flush Set to 1 if there will be more data to the client,
+ like in send_fields().
+
+ DESCRIPTION
+ The eof packet has the following structure
+
+ 254 Marker (1 byte)
+ warning_count Stored in 2 bytes; New in 4.1 protocol
+ status_flag Stored in 2 bytes;
+ For flags like SERVER_STATUS_MORE_RESULTS
+
+ Note that the warning count will not be sent if 'no_flush' is set as
+ we don't want to report the warning count until all data is sent to the
+ client.
+*/
+
void
-send_eof(NET *net,bool no_flush)
+send_eof(THD *thd, bool no_flush)
{
static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
+ NET *net= &thd->net;
DBUG_ENTER("send_eof");
if (net->vio != 0)
{
- VOID(my_net_write(net,eof_buff,1));
- if (!no_flush)
+ if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41))
+ {
+ uchar buff[5];
+ uint tmp= min(thd->total_warn_count, 65535);
+ buff[0]=254;
+ int2store(buff+1, tmp);
+ int2store(buff+3, 0); // No flags yet
+ VOID(my_net_write(net,(char*) buff,5));
VOID(net_flush(net));
+ }
+ else
+ {
+ VOID(my_net_write(net,eof_buff,1));
+ if (!no_flush)
+ VOID(net_flush(net));
+ }
}
DBUG_VOID_RETURN;
}
@@ -341,7 +439,7 @@ net_store_data(String *packet,struct tm *tmp)
bool net_store_data(String* packet, I_List<i_string>* str_list)
{
char buf[256];
- String tmp(buf, sizeof(buf));
+ String tmp(buf, sizeof(buf), default_charset_info);
tmp.length(0);
I_List_iterator<i_string> it(*str_list);
i_string* s;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 122793b07a7..d165125eb90 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -75,12 +75,12 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#define TEST_BLOCKING 8
#define MAX_THREE_BYTES 255L*255L*255L
-static int net_write_buff(NET *net,const char *packet,ulong len);
+static my_bool net_write_buff(NET *net,const char *packet,ulong len);
/* Init with packet info */
-int my_net_init(NET *net, Vio* vio)
+my_bool my_net_init(NET *net, Vio* vio)
{
DBUG_ENTER("my_net_init");
my_net_local_init(net); /* Set some limits */
@@ -99,6 +99,7 @@ int my_net_init(NET *net, Vio* vio)
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
net->query_cache_query=0;
+ net->report_error= 0;
if (vio != 0) /* If real connection */
{
@@ -127,15 +128,16 @@ void net_end(NET *net)
/* Realloc the packet buffer */
-static my_bool net_realloc(NET *net, ulong length)
+my_bool net_realloc(NET *net, ulong length)
{
uchar *buff;
ulong pkt_length;
if (length >= net->max_packet_size)
{
DBUG_PRINT("error",("Packet too large (%lu)", length));
- net->error=1;
- net->last_errno=ER_NET_PACKET_TOO_LARGE;
+ net->error= 1;
+ net->report_error= 1;
+ net->last_errno= ER_NET_PACKET_TOO_LARGE;
return 1;
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
@@ -147,9 +149,10 @@ static my_bool net_realloc(NET *net, ulong length)
NET_HEADER_SIZE + COMP_HEADER_SIZE,
MYF(MY_WME))))
{
- net->error=1;
+ net->error= 1;
+ net->report_error= 1;
#ifdef MYSQL_SERVER
- net->last_errno=ER_OUT_OF_RESOURCES;
+ net->last_errno= ER_OUT_OF_RESOURCES;
#endif
return 1;
}
@@ -184,14 +187,14 @@ void net_clear(NET *net)
/* Flush write_buffer if not empty. */
-int net_flush(NET *net)
+my_bool net_flush(NET *net)
{
- int error=0;
+ my_bool error= 0;
DBUG_ENTER("net_flush");
if (net->buff != net->write_pos)
{
- error=net_real_write(net,(char*) net->buff,
- (ulong) (net->write_pos - net->buff));
+ error=test(net_real_write(net,(char*) net->buff,
+ (ulong) (net->write_pos - net->buff)));
net->write_pos=net->buff;
}
/* Sync packet number if using compression */
@@ -212,7 +215,7 @@ int net_flush(NET *net)
** NOTE: If compression is used the original package is modified!
*/
-int
+my_bool
my_net_write(NET *net,const char *packet,ulong len)
{
uchar buff[NET_HEADER_SIZE];
@@ -243,17 +246,38 @@ my_net_write(NET *net,const char *packet,ulong len)
/*
Send a command to the server.
- As the command is part of the first data packet, we have to do some data
- juggling to put the command in there, without having to create a new
- packet.
- This function will split big packets into sub-packets if needed.
- (Each sub packet can only be 2^24 bytes)
+
+ SYNOPSIS
+ net_write_command()
+ net NET handler
+ command Command in MySQL server (enum enum_server_command)
+ header Header to write after command
+ head_len Length of header
+ packet Query or parameter to query
+ len Length of packet
+
+ DESCRIPTION
+ The reason for having both header and packet is so that libmysql
+ can easy add a header to a special command (like prepared statements)
+ without having to re-alloc the string.
+
+ As the command is part of the first data packet, we have to do some data
+ juggling to put the command in there, without having to create a new
+ packet.
+ This function will split big packets into sub-packets if needed.
+ (Each sub packet can only be 2^24 bytes)
+
+ RETURN VALUES
+ 0 ok
+ 1 error
*/
-int
-net_write_command(NET *net,uchar command,const char *packet,ulong len)
+my_bool
+net_write_command(NET *net,uchar command,
+ const char *header, ulong head_len,
+ const char *packet, ulong len)
{
- ulong length=len+1; /* 1 extra byte for command */
+ ulong length=len+1+head_len; /* 1 extra byte for command */
uchar buff[NET_HEADER_SIZE+1];
uint header_size=NET_HEADER_SIZE+1;
buff[4]=command; /* For first packet */
@@ -261,25 +285,28 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len)
if (length >= MAX_THREE_BYTES)
{
/* Take into account that we have the command in the first header */
- len= MAX_THREE_BYTES -1;
+ len= MAX_THREE_BYTES - 1 - head_len;
do
{
int3store(buff, MAX_THREE_BYTES);
buff[3]= (uchar) net->pkt_nr++;
if (net_write_buff(net,(char*) buff, header_size) ||
- net_write_buff(net,packet,len))
+ net_write_buff(net, header, head_len) ||
+ net_write_buff(net, packet, len))
return 1;
packet+= len;
length-= MAX_THREE_BYTES;
len=MAX_THREE_BYTES;
+ head_len=0;
header_size=NET_HEADER_SIZE;
} while (length >= MAX_THREE_BYTES);
len=length; /* Data left to be written */
}
int3store(buff,length);
buff[3]= (uchar) net->pkt_nr++;
- return test(net_write_buff(net,(char*) buff,header_size) ||
- net_write_buff(net,packet,len) || net_flush(net));
+ return test(net_write_buff(net, (char*) buff, header_size) ||
+ (head_len && net_write_buff(net, (char*) header, head_len)) ||
+ net_write_buff(net, packet, len) || net_flush(net));
}
/*
@@ -287,7 +314,7 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len)
One can force the buffer to be flushed with 'net_flush'.
*/
-static int
+static my_bool
net_write_buff(NET *net,const char *packet,ulong len)
{
ulong left_length=(ulong) (net->buff_end - net->write_pos);
@@ -345,10 +372,12 @@ net_real_write(NET *net,const char *packet,ulong len)
COMP_HEADER_SIZE, MYF(MY_WME))))
{
#ifdef MYSQL_SERVER
- net->last_errno=ER_OUT_OF_RESOURCES;
- net->error=2;
+ net->last_errno= ER_OUT_OF_RESOURCES;
+ net->error= 2;
+ //TODO is it needed to set this variable if we have no socket
+ net->report_error= 1;
#endif
- net->reading_or_writing=0;
+ net->reading_or_writing= 0;
DBUG_RETURN(1);
}
memcpy(b+header_length,packet,len);
@@ -398,9 +427,10 @@ net_real_write(NET *net,const char *packet,ulong len)
my_progname,vio_errno(net->vio));
#endif /* EXTRA_DEBUG */
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_ERROR_ON_WRITE;
+ net->last_errno= ER_NET_ERROR_ON_WRITE;
#endif
- net->error=2; /* Close socket */
+ net->error= 2; /* Close socket */
+ net->report_error= 1;
goto end;
}
retry_count=0;
@@ -426,7 +456,8 @@ net_real_write(NET *net,const char *packet,ulong len)
continue;
}
#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
- net->error=2; /* Close socket */
+ net->error= 2; /* Close socket */
+ net->report_error= 1;
#ifdef MYSQL_SERVER
net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
ER_NET_ERROR_ON_WRITE);
@@ -562,9 +593,10 @@ my_real_read(NET *net, ulong *complen)
my_progname,vio_errno(net->vio));
#endif /* EXTRA_DEBUG */
len= packet_error;
- net->error=2; /* Close socket */
+ net->error= 2; /* Close socket */
+ net->report_error= 1;
#ifdef MYSQL_SERVER
- net->last_errno=ER_NET_FCNTL_ERROR;
+ net->last_errno= ER_NET_FCNTL_ERROR;
#endif
goto end;
}
@@ -594,7 +626,8 @@ my_real_read(NET *net, ulong *complen)
remain,vio_errno(net->vio), length,
thr_got_alarm(&alarmed)));
len= packet_error;
- net->error=2; /* Close socket */
+ net->error= 2; /* Close socket */
+ net->report_error= 1;
#ifdef MYSQL_SERVER
net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
ER_NET_READ_ERROR);
@@ -624,6 +657,7 @@ my_real_read(NET *net, ulong *complen)
#endif
}
len= packet_error;
+ net->report_error= 1;
#ifdef MYSQL_SERVER
net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
#endif
@@ -797,7 +831,8 @@ my_net_read(NET *net)
if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
&complen))
{
- net->error=2; /* caller will close socket */
+ net->error= 2; /* caller will close socket */
+ net->report_error= 1;
#ifdef MYSQL_SERVER
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
#endif
@@ -817,13 +852,3 @@ my_net_read(NET *net)
#endif /* HAVE_COMPRESS */
return len;
}
-
-bool net_request_file(NET* net, const char* fname)
-{
- char tmp [FN_REFLEN+1],*end;
- DBUG_ENTER("net_request_file");
- tmp[0] = (char) 251; /* NULL_LENGTH */
- end=strnmov(tmp+1,fname,sizeof(tmp)-2);
- DBUG_RETURN(my_net_write(net,tmp,(uint) (end-tmp)) ||
- net_flush(net));
-}
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index f33a2d312b4..b6f81ab07eb 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -174,8 +174,9 @@ public:
void store(uint length,char **min_key,uint min_key_flag,
char **max_key, uint max_key_flag)
{
- if (!(min_flag & NO_MIN_RANGE) &&
- !(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))
+ if ((min_flag & GEOM_FLAG) ||
+ (!(min_flag & NO_MIN_RANGE) &&
+ !(min_key_flag & (NO_MIN_RANGE | NEAR_MIN))))
{
if (maybe_null && *min_value)
{
@@ -298,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,
@@ -661,6 +659,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
key_parts->null_bit= key_info->key_part[part].null_bit;
if (key_parts->field->type() == FIELD_TYPE_BLOB)
key_parts->part_length+=HA_KEY_BLOB_LENGTH;
+ key_parts->image_type =
+ (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
}
param.real_keynr[param.keys++]=idx;
}
@@ -678,6 +678,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
{
SEL_ARG **key,**end,**best_key=0;
+
for (idx=0,key=tree->keys, end=key+param.keys ;
key != end ;
key++,idx++)
@@ -928,7 +929,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
{
bool like_error;
char buff1[MAX_FIELD_WIDTH],*min_str,*max_str;
- String tmp(buff1,sizeof(buff1)),*res;
+ String tmp(buff1,sizeof(buff1),default_charset_info),*res;
uint length,offset,min_length,max_length;
if (!field->optimize_range((uint) key_part->key))
@@ -966,25 +967,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
- {
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- like_error= my_like_range(default_charset_info,
- 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,
- 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
@@ -1024,7 +1014,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
field->cmp_type() != value->result_type())
DBUG_RETURN(0);
- if (value->save_in_field(field))
+ if (value->save_in_field(field) > 0)
{
// TODO; Check if we can we remove the following block.
if (type == Item_func::EQUAL_FUNC)
@@ -1046,7 +1036,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(0);
if (maybe_null)
*str=0; // Not NULL
- field->get_key_image(str+maybe_null,key_part->part_length);
+ 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);
@@ -1071,73 +1061,45 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
case Item_func::GE_FUNC:
tree->max_flag=NO_MAX_RANGE;
break;
- default:
- break;
- }
- DBUG_RETURN(tree);
-}
-
+ case Item_func::SP_EQUALS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_DISJOINT_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_INTERSECTS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_TOUCHES_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
-/*
-** 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 !
-*/
+ case Item_func::SP_CROSSES_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_WITHIN_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
-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;
+ case Item_func::SP_CONTAINS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_OVERLAPS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
- 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;
+ default:
+ break;
}
- *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;
+ DBUG_RETURN(tree);
}
@@ -2192,18 +2154,30 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
!memcmp(param->min_key,param->max_key,min_key_length))
tmp=1; // Max one record
else
+ {
+ if(tmp_min_flag & GEOM_FLAG)
+ {
+ tmp=param->table->file->
+ records_in_range((int) keynr,(byte*)(param->min_key + 1),
+ min_key_length, (ha_rkey_function)(tmp_min_flag ^ GEOM_FLAG),
+ (byte *)NullS,0,HA_READ_KEY_EXACT);
+ }
+ else
+ {
tmp=param->table->file->
records_in_range((int) keynr,
(byte*) (!min_key_length ? NullS :
param->min_key),
min_key_length,
- (tmp_min_flag & NEAR_MIN ?
- HA_READ_AFTER_KEY : HA_READ_KEY_EXACT),
+ tmp_min_flag & NEAR_MIN ?
+ HA_READ_AFTER_KEY : HA_READ_KEY_EXACT,
(byte*) (!max_key_length ? NullS :
param->max_key),
max_key_length,
(tmp_max_flag & NEAR_MAX ?
HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY));
+ }
+ }
end:
if (tmp == HA_POS_ERROR) // Impossible range
return tmp;
@@ -2299,19 +2273,24 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
}
}
else
- flag=key_tree->min_flag | key_tree->max_flag;
+ {
+ flag = (key_tree->min_flag & GEOM_FLAG) ?
+ key_tree->min_flag : key_tree->min_flag | key_tree->max_flag;
+ }
/* Ensure that some part of min_key and max_key are used. If not,
regard this as no lower/upper range */
- if (tmp_min_key != param->min_key)
- flag&= ~NO_MIN_RANGE;
- else
- flag|= NO_MIN_RANGE;
- if (tmp_max_key != param->max_key)
- flag&= ~NO_MAX_RANGE;
- else
- flag|= NO_MAX_RANGE;
-
+ if((flag & GEOM_FLAG) == 0)
+ {
+ if (tmp_min_key != param->min_key)
+ flag&= ~NO_MIN_RANGE;
+ else
+ flag|= NO_MIN_RANGE;
+ if (tmp_max_key != param->max_key)
+ flag&= ~NO_MAX_RANGE;
+ else
+ flag|= NO_MAX_RANGE;
+ }
if (flag == 0)
{
uint length= (uint) (tmp_min_key - param->min_key);
@@ -2444,13 +2423,19 @@ int QUICK_SELECT::get_next()
int result;
if (range)
{ // Already read through key
- result=((range->flag & EQ_RANGE) ?
+/* result=((range->flag & EQ_RANGE) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
+*/
+ result=((range->flag & (EQ_RANGE | GEOM_FLAG) ) ?
+ file->index_next_same(record, (byte*) range->min_key,
+ range->min_length) :
+ file->index_next(record));
+
if (!result)
{
- if (!cmp_next(*it.ref()))
+ if ((range->flag & GEOM_FLAG) || !cmp_next(*it.ref()))
DBUG_RETURN(0);
}
else if (result != HA_ERR_END_OF_FILE)
@@ -2459,6 +2444,23 @@ int QUICK_SELECT::get_next()
if (!(range=it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
+
+ if(range->flag & GEOM_FLAG)
+ {
+ if ((result = file->index_read(record,
+ (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)),
+ range->min_length,
+ (ha_rkey_function)(range->flag ^ GEOM_FLAG))))
+
+ {
+ if (result != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(result);
+ range=0; // Not found, to next range
+ continue;
+ }
+ DBUG_RETURN(0);
+ }
+
if (range->flag & NO_MIN_RANGE) // Read first record
{
int local_error;
@@ -2469,13 +2471,14 @@ int QUICK_SELECT::get_next()
range=0; // No matching records; go to next range
continue;
}
- if ((result = file->index_read(record,(byte*) range->min_key,
+ if ((result = file->index_read(record,
+ (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)),
range->min_length,
- ((range->flag & NEAR_MIN) ?
+ (range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY:
(range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT :
- HA_READ_KEY_OR_NEXT))))
+ HA_READ_KEY_OR_NEXT)))
{
if (result != HA_ERR_KEY_NOT_FOUND)
@@ -2623,20 +2626,28 @@ int QUICK_SELECT_DESC::get_next()
}
else
{
+ DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range));
+#ifdef NOT_IMPLEMENTED_YET
+ result=file->index_read(record, (byte*) range->max_key,
+ range->max_length,
+ ((range->flag & NEAR_MAX) ?
+ HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV));
+#else
/* Heikki changed Sept 11, 2002: since InnoDB does not store the cursor
position if READ_KEY_EXACT is used to a primary key with all
key columns specified, we must use below HA_READ_KEY_OR_NEXT,
so that InnoDB stores the cursor position and is able to move
the cursor one step backward after the search. */
- DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range));
/* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will
* do the right thing - go past all keys which match the prefix */
+
result=file->index_read(record, (byte*) range->max_key,
range->max_length,
((range->flag & NEAR_MAX) ?
HA_READ_KEY_OR_NEXT : HA_READ_AFTER_KEY));
result = file->index_prev(record);
+#endif
}
if (result)
{
@@ -2769,7 +2780,7 @@ static void
print_key(KEY_PART *key_part,const char *key,uint used_length)
{
char buff[1024];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),default_charset_info);
for (uint length=0;
length < used_length ;
diff --git a/sql/opt_range.h b/sql/opt_range.h
index af977eb3093..e96c3792f24 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -31,11 +31,14 @@
#define UNIQUE_RANGE 16
#define EQ_RANGE 32
#define NULL_RANGE 64
+#define GEOM_FLAG 128
+
typedef struct st_key_part {
- uint16 key,part,part_length;
- uint8 null_bit;
- Field *field;
+ uint16 key,part,part_length;
+ uint8 null_bit;
+ Field *field;
+ Field::imagetype image_type;
} KEY_PART;
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 4b6a196051e..1477d46e756 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -364,7 +364,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
// Save found constant
if (part->null_bit)
*key_ptr++= (byte) test(part->field->is_null());
- part->field->get_key_image((char*) key_ptr,part->length);
+ part->field->get_key_image((char*) key_ptr,part->length, Field::itRAW);
key_ptr+=part->store_length - test(part->null_bit);
left_length-=part->store_length;
}
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 437bd82d6e5..7779f5ce085 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -57,7 +57,8 @@ setup_procedure(THD *thd,ORDER *param,select_result *result,
DBUG_RETURN(0);
for (i=0 ; i < array_elements(sql_procs) ; i++)
{
- if (!my_strcasecmp((*param->item)->name,sql_procs[i].name))
+ if (!my_strcasecmp(system_charset_info,
+ (*param->item)->name,sql_procs[i].name))
{
Procedure *proc=(*sql_procs[i].init)(thd,param,result,field_list);
*error= !proc;
diff --git a/sql/procedure.h b/sql/procedure.h
index 349908a8d84..c3280b951d3 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -62,7 +62,7 @@ public:
{ value=atof(str); }
double val() { return value; }
longlong val_int() { return (longlong) value; }
- String *val_str(String *s) { s->set(value,decimals); return s; }
+ String *val_str(String *s) { s->set(value,decimals,thd_charset()); return s; }
unsigned int size_of() { return sizeof(*this);}
};
@@ -80,7 +80,7 @@ public:
{ value=strtoll(str,NULL,10); }
double val() { return (double) value; }
longlong val_int() { return value; }
- String *val_str(String *s) { s->set(value); return s; }
+ String *val_str(String *s) { s->set(value, thd_charset()); return s; }
unsigned int size_of() { return sizeof(*this);}
};
@@ -92,9 +92,9 @@ 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); }
- void set(longlong nr) { str_value.set(nr); }
- void set(const char *str, uint length) { str_value.copy(str,length); }
+ 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) { str_value.copy(str,length, thd_charset()); }
double val() { return atof(str_value.ptr()); }
longlong val_int() { return strtoll(str_value.ptr(),NULL,10); }
String *val_str(String*)
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 4ebb2f5b476..785a253b1ac 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -184,7 +184,7 @@ err:
my_message(ER_UNKNOWN_ERROR, "Wrong parameters to function register_slave",
MYF(0));
err2:
- send_error(&thd->net);
+ send_error(thd);
return 1;
}
@@ -203,7 +203,7 @@ extern "C" void slave_info_free(void *s)
void init_slave_list()
{
- hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0,
+ hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
(hash_get_key) slave_list_key, (hash_free_key) slave_info_free, 0);
pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
}
@@ -441,7 +441,7 @@ int show_new_master(THD* thd)
net_store_data(packet, (longlong)lex_mi->pos);
if (my_net_write(&thd->net, packet->ptr(), packet->length()))
DBUG_RETURN(-1);
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
}
@@ -456,7 +456,7 @@ int update_slave_list(MYSQL* mysql)
int port_ind;
DBUG_ENTER("update_slave_list");
- if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",0) ||
+ if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",16) ||
!(res = mc_mysql_store_result(mysql)))
{
error = "Query error";
@@ -620,7 +620,7 @@ int show_slave_hosts(THD* thd)
}
}
pthread_mutex_unlock(&LOCK_slave_list);
- send_eof(net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -706,7 +706,7 @@ int load_master_data(THD* thd)
(error=terminate_slave_threads(active_mi,restart_thread_mask,
1 /*skip lock*/)))
{
- send_error(&thd->net,error);
+ send_error(thd,error);
unlock_slave_threads(active_mi);
UNLOCK_ACTIVE_MI;
return 1;
@@ -714,7 +714,7 @@ int load_master_data(THD* thd)
if (connect_to_master(thd, &mysql, active_mi))
{
- net_printf(&thd->net, error= ER_CONNECT_TO_MASTER,
+ net_printf(thd, error= ER_CONNECT_TO_MASTER,
mc_mysql_error(&mysql));
goto err;
}
@@ -724,10 +724,10 @@ int load_master_data(THD* thd)
MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
uint num_dbs;
- if (mc_mysql_query(&mysql, "show databases", 0) ||
+ if (mc_mysql_query(&mysql, "SHOW DATABASES", 14) ||
!(db_res = mc_mysql_store_result(&mysql)))
{
- net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
@@ -741,7 +741,7 @@ int load_master_data(THD* thd)
if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
{
- net_printf(&thd->net, error = ER_OUTOFMEMORY);
+ net_printf(thd, error = ER_OUTOFMEMORY);
goto err;
}
@@ -751,11 +751,11 @@ int load_master_data(THD* thd)
we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
can to minimize the lock time.
*/
- if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) ||
- mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) ||
+ if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) ||
+ mc_mysql_query(&mysql, "SHOW MASTER STATUS",18) ||
!(master_status_res = mc_mysql_store_result(&mysql)))
{
- net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
@@ -795,16 +795,16 @@ int load_master_data(THD* thd)
if (mysql_rm_db(thd, db, 1,1) ||
mysql_create_db(thd, db, 0, 1))
{
- send_error(&thd->net, 0, 0);
+ send_error(thd, 0, 0);
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
if (mc_mysql_select_db(&mysql, db) ||
- mc_mysql_query(&mysql, "show tables", 0) ||
+ mc_mysql_query(&mysql, "SHOW TABLES", 11) ||
!(*cur_table_res = mc_mysql_store_result(&mysql)))
{
- net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
@@ -845,9 +845,9 @@ int load_master_data(THD* thd)
mc_mysql_free_result(master_status_res);
}
- if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0))
+ if (mc_mysql_query(&mysql, "UNLOCK TABLES", 13))
{
- net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
+ net_printf(thd, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
@@ -857,7 +857,7 @@ int load_master_data(THD* thd)
0 /* not only reset, but also reinit */,
&errmsg))
{
- send_error(&thd->net, 0, "Failed purging old relay logs");
+ send_error(thd, 0, "Failed purging old relay logs");
unlock_slave_threads(active_mi);
UNLOCK_ACTIVE_MI;
return 1;
@@ -885,7 +885,7 @@ err:
mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init()
if (!error)
- send_ok(&thd->net);
+ send_ok(thd);
return error;
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 0675f7b4286..599c4af06cc 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -24,8 +24,9 @@
- Use one of the 'sys_var... classes from set_var.h or write a specific
one for the variable type.
- Define it in the 'variable definition list' in this file.
- - If the variable should be changeable, it should be added to the
- 'list of all variables' list in this file.
+ - If the variable should be changeable or one should be able to access it
+ with @@variable_name, it should be added to the 'list of all variables'
+ list in this file.
- If the variable should be changed from the command line, add a definition
of it in the my_option structure list in mysqld.dcc
- If the variable should show up in 'show variables' add it to the
@@ -82,6 +83,8 @@ static void fix_net_retry_count(THD *thd, enum_var_type type);
static void fix_max_join_size(THD *thd, enum_var_type type);
static void fix_query_cache_size(THD *thd, enum_var_type type);
static void fix_key_buffer_size(THD *thd, enum_var_type type);
+static byte *get_error_count(THD *thd);
+static byte *get_warning_count(THD *thd);
/*
Variable definition list
@@ -147,16 +150,20 @@ sys_var_long_ptr sys_max_connect_errors("max_connect_errors",
&max_connect_errors);
sys_var_long_ptr sys_max_delayed_threads("max_delayed_threads",
&max_insert_delayed_threads);
+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
+sys_var_thd_ulong sys_max_prep_stmt_count("max_prepared_statements",
+ &SV::max_prep_stmt_count);
sys_var_thd_ulong sys_max_sort_length("max_sort_length",
&SV::max_sort_length);
sys_var_long_ptr sys_max_user_connections("max_user_connections",
@@ -218,8 +225,6 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size",
&SV::tmp_table_size);
sys_var_thd_ulong sys_net_wait_timeout("wait_timeout",
&SV::net_wait_timeout);
-
-
/*
Variables that are bits in THD
*/
@@ -275,12 +280,21 @@ 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");
static sys_var_last_insert_id sys_identity("identity");
static sys_var_insert_id sys_insert_id("insert_id");
+static sys_var_readonly sys_error_count("error_count",
+ OPT_SESSION,
+ SHOW_LONG,
+ get_error_count);
+static sys_var_readonly sys_warning_count("warning_count",
+ OPT_SESSION,
+ SHOW_LONG,
+ get_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");
@@ -311,6 +325,7 @@ sys_var *sys_variables[]=
&sys_delayed_insert_limit,
&sys_delayed_insert_timeout,
&sys_delayed_queue_size,
+ &sys_error_count,
&sys_flush,
&sys_flush_time,
&sys_foreign_key_checks,
@@ -333,8 +348,10 @@ sys_var *sys_variables[]=
&sys_max_connect_errors,
&sys_max_connections,
&sys_max_delayed_threads,
+ &sys_max_error_count,
&sys_max_heap_table_size,
&sys_max_join_size,
+ &sys_max_prep_stmt_count,
&sys_max_sort_length,
&sys_max_tmp_tables,
&sys_max_user_connections,
@@ -376,7 +393,8 @@ sys_var *sys_variables[]=
&sys_timestamp,
&sys_tmp_table_size,
&sys_tx_isolation,
- &sys_unique_checks
+ &sys_unique_checks,
+ &sys_warning_count
};
@@ -466,9 +484,11 @@ struct show_var_st init_vars[]= {
{sys_max_binlog_size.name, (char*) &sys_max_binlog_size, SHOW_SYS},
{sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS},
{sys_max_connect_errors.name, (char*) &sys_max_connect_errors, SHOW_SYS},
+ {sys_max_error_count.name, (char*) &sys_max_error_count, SHOW_SYS},
{sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS},
{sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS},
{sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS},
+ {sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS},
{sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS},
{sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS},
{sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS},
@@ -500,6 +520,10 @@ 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 */
+#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},
@@ -523,7 +547,7 @@ struct show_var_st init_vars[]= {
{"timezone", time_zone, SHOW_CHAR},
#endif
{sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS},
- {"tmpdir", (char*) &mysql_tmpdir, SHOW_CHAR_PTR},
+ {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR},
{"version", server_version, SHOW_CHAR},
{sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS},
{NullS, NullS, SHOW_LONG}
@@ -576,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;
@@ -751,7 +775,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;
}
@@ -795,7 +819,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type)
bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names)
{
char buff[80], *value;
- String str(buff,sizeof(buff)), *res;
+ String str(buff, sizeof(buff), system_charset_info), *res;
if (var->value->result_type() == STRING_RESULT)
{
@@ -833,6 +857,10 @@ err:
We have to use netprintf() instead of my_error() here as this is
called on the parsing stage.
+
+ TODO:
+ With prepared statements/stored procedures this has to be fixed
+ to create an item that gets the current value at fix_fields() stage.
*/
Item *sys_var::item(THD *thd, enum_var_type var_type)
@@ -841,7 +869,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type)
{
if (var_type != OPT_DEFAULT)
{
- net_printf(&thd->net,
+ net_printf(thd,
var_type == OPT_GLOBAL ? ER_LOCAL_VARIABLE :
ER_GLOBAL_VARIABLE, name);
return 0;
@@ -859,10 +887,10 @@ Item *sys_var::item(THD *thd, enum_var_type var_type)
case SHOW_CHAR:
{
char *str= (char*) value_ptr(thd, var_type);
- return new Item_string(str,strlen(str));
+ return new Item_string(str, strlen(str), system_charset_info);
}
default:
- net_printf(&thd->net, ER_VAR_CANT_BE_READ, name);
+ net_printf(thd, ER_VAR_CANT_BE_READ, name);
}
return 0;
}
@@ -920,7 +948,7 @@ bool sys_var_thd_conv_charset::check(THD *thd, set_var *var)
{
CONVERT *tmp;
char buff[80];
- String str(buff,sizeof(buff)), *res;
+ String str(buff,sizeof(buff), system_charset_info), *res;
if (!var->value) // Default value
{
@@ -1115,6 +1143,21 @@ static bool set_log_update(THD *thd, set_var *var)
return 0;
}
+static byte *get_warning_count(THD *thd)
+{
+ thd->sys_var_tmp.long_value=
+ (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] +
+ thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]);
+ return (byte*) &thd->sys_var_tmp.long_value;
+}
+
+static byte *get_error_count(THD *thd)
+{
+ thd->sys_var_tmp.long_value=
+ thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR];
+ return (byte*) &thd->sys_var_tmp.long_value;
+}
+
/****************************************************************************
Main handling of variables:
@@ -1176,7 +1219,8 @@ void set_var_init()
{
extern struct my_option my_long_options[]; // From mysqld
- hash_init(&system_variable_hash,array_elements(sys_variables),0,0,
+ hash_init(&system_variable_hash, system_charset_info,
+ array_elements(sys_variables),0,0,
(hash_get_key) get_sys_var_length,0, HASH_CASE_INSENSITIVE);
sys_var **var, **end;
for (var= sys_variables, end= sys_variables+array_elements(sys_variables) ;
@@ -1228,7 +1272,7 @@ sys_var *find_sys_var(const char *str, uint length)
length ? length :
strlen(str));
if (!var)
- net_printf(&current_thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str);
+ net_printf(current_thd, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str);
return var;
}
@@ -1300,7 +1344,7 @@ int set_var::check(THD *thd)
return 0;
}
- if (value->fix_fields(thd,0))
+ if (value->fix_fields(thd, 0, &value))
return -1;
if (var->check_update_type(value->result_type()))
{
@@ -1329,7 +1373,7 @@ int set_var::update(THD *thd)
int set_var_user::check(THD *thd)
{
- return user_var_item->fix_fields(thd,0) ? -1 : 0;
+ return user_var_item->fix_fields(thd,0, (Item**) 0) ? -1 : 0;
}
diff --git a/sql/set_var.h b/sql/set_var.h
index a171c4f5e76..de1e27e0da8 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -39,6 +39,7 @@ typedef bool (*sys_check_func)(THD *, set_var *);
typedef bool (*sys_update_func)(THD *, set_var *);
typedef void (*sys_after_update_func)(THD *,enum_var_type);
typedef void (*sys_set_default_func)(THD *, enum_var_type);
+typedef byte *(*sys_value_ptr_func)(THD *thd);
class sys_var
{
@@ -202,6 +203,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; }
@@ -367,6 +372,31 @@ public:
};
+/* Variable that you can only read from */
+
+class sys_var_readonly: public sys_var
+{
+public:
+ enum_var_type var_type;
+ SHOW_TYPE show_type;
+ sys_value_ptr_func value_ptr_func;
+ sys_var_readonly(const char *name_arg, enum_var_type type,
+ SHOW_TYPE show_type_arg,
+ sys_value_ptr_func value_ptr_func_arg)
+ :sys_var(name_arg), var_type(type),
+ show_type(show_type_arg), value_ptr_func(value_ptr_func_arg)
+ {}
+ bool update(THD *thd, set_var *var) { return 1; }
+ bool check_default(enum_var_type type) { return 1; }
+ bool check_type(enum_var_type type) { return type != var_type; }
+ bool check_update_type(Item_result type) { return 1; }
+ byte *value_ptr(THD *thd, enum_var_type type)
+ {
+ return (*value_ptr_func)(thd);
+ }
+ SHOW_TYPE type() { return show_type; }
+};
+
/****************************************************************************
Classes for parsing of the SET command
****************************************************************************/
@@ -405,7 +435,8 @@ public:
if (value_arg && value_arg->type() == Item::FIELD_ITEM)
{
Item_field *item= (Item_field*) value_arg;
- if (!(value=new Item_string(item->field_name, strlen(item->field_name))))
+ if (!(value=new Item_string(item->field_name, strlen(item->field_name),
+ system_charset_info)))
value=value_arg; /* Give error message later */
}
else
diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index
index 5cf30682cc0..b2d9fe3e2a1 100644
--- a/sql/share/charsets/Index
+++ b/sql/share/charsets/Index
@@ -20,19 +20,51 @@ sjis 13
cp1251 14
danish 15
hebrew 16
-# The win1251 character set is deprecated. Please use cp1251 instead.
-win1251 17
tis620 18
euc_kr 19
estonia 20
hungarian 21
koi8_ukr 22
+# win1251ukr is depreciated. Use cp1251cias, cp1251csas or cp1251bin instead.
win1251ukr 23
gb2312 24
greek 25
win1250 26
croat 27
gbk 28
+# cp1257 is depreciated.
+# Use cp1257ltlvciai, cp1257ltlvcsas, cp1257bin, cp1257ltlvcias instead
cp1257 29
latin5 30
latin1_de 31
+armscii8 32
+utf8 33
+win1250ch 34
+
+ucs2 35
+cp866 36
+keybcs2 37
+
+macce 38
+macroman 39
+
+pclatin2 40
+latvian 41
+latvian1 42
+maccebin 43
+macceciai 44
+maccecias 45
+maccecsas 46
+latin1bin 47
+latin1cias 48
+latin1csas 49
+cp1251bin 50
+cp1251cias 51
+cp1251csas 52
+macromanbin 53
+macromancias 54
+macromanciai 55
+macromancsas 56
+cp1256 57
+
+binary 63
diff --git a/sql/share/charsets/armscii8.conf b/sql/share/charsets/armscii8.conf
new file mode 100644
index 00000000000..54d2d0fec47
--- /dev/null
+++ b/sql/share/charsets/armscii8.conf
@@ -0,0 +1,93 @@
+# Configuration file for the armscii8 (armenian) character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 10 10
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 AA AB AC AD AE AF
+ B0 B1 B3 B3 B5 B5 B7 B7 B9 B9 BB BB BD BD BF BF
+ C1 C1 C3 C3 C5 C5 C7 C7 C9 C9 CB CB CD CD CF CF
+ D1 D1 D3 D3 D5 D5 D7 D7 D9 D9 DB DB DD DD DF DF
+ E1 E1 E3 E3 E5 E5 E7 E7 E9 E9 EB EB ED ED EF EF
+ F1 F1 F3 F3 F5 F5 F7 F7 F9 F9 FB FB FD FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B2 B4 B4 B6 B6 B8 B8 BA BA BC BC BE BE
+ C0 C0 C2 C2 C4 C4 C6 C6 C8 C8 CA CA CC CC CE CE
+ D0 D0 D2 D2 D4 D4 D6 D6 D8 D8 DA DA DC DC DE DE
+ E0 E0 E2 E2 E4 E4 E6 E6 E8 E8 EA EA EC EC EE EE
+ F0 F0 F2 F2 F4 F4 F6 F6 F8 F8 FA FA FC FC FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 2741 00A7 0589 0029 0028 00BB 00AB 2014 002E 055D 002C 002D 055F 2026 055C
+055B 055E 0531 0561 0532 0562 0533 0563 0534 0564 0535 0565 0536 0566 0537 0567
+0538 0568 0539 0569 053A 056A 053B 056B 053C 056C 053D 056D 053E 056E 053F 056F
+0540 0570 0541 0571 0542 0572 0543 0573 0544 0574 0545 0575 0546 0576 0547 0577
+0548 0578 0549 0579 054A 057A 054B 057B 054C 057C 054D 057D 054E 057E 054F 057F
+0550 0580 0551 0581 0552 0582 0553 0583 0554 0584 0555 0585 0556 0586 2019 0027
diff --git a/sql/share/charsets/cp1251.conf b/sql/share/charsets/cp1251.conf
index 6af97c891b8..ee72c6e7b27 100644
--- a/sql/share/charsets/cp1251.conf
+++ b/sql/share/charsets/cp1251.conf
@@ -72,3 +72,22 @@
6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B
5B 5C 5D 5E 5F 60 62 63 64 65 66 67 68 69 6A 6B
6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F
+ 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F
+ 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407
+ 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457
+ 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+ 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+ 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+ 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
+
diff --git a/sql/share/charsets/cp1251bin.conf b/sql/share/charsets/cp1251bin.conf
new file mode 100644
index 00000000000..4c17fee5934
--- /dev/null
+++ b/sql/share/charsets/cp1251bin.conf
@@ -0,0 +1,95 @@
+#
+# cp1251
+# Binary sort order
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 00 02 00 00 00 00 00 00 01 00 01 01 01 01
+ 02 00 00 00 00 00 00 00 00 00 02 00 02 02 02 02
+ 00 01 02 01 00 01 00 00 01 00 01 00 00 00 00 01
+ 00 00 01 02 02 00 00 00 02 00 02 00 02 01 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B3 B3 B4 B5 B6 B7 B8 B9 BA BB BC BE BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F
+ A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B2 A5 B5 B6 B7 A8 B9 AA BB A3 BD BD AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F
+ 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F
+ 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407
+ 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457
+ 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+ 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+ 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+ 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
+
diff --git a/sql/share/charsets/cp1251cias.conf b/sql/share/charsets/cp1251cias.conf
new file mode 100644
index 00000000000..612be640b11
--- /dev/null
+++ b/sql/share/charsets/cp1251cias.conf
@@ -0,0 +1,99 @@
+#
+# cp1251
+# Case insensitive, accent sensitive
+# Sort order is correct for Belarusian, Bulgarian, Macedonian,
+# Russian, Serbian, Mongolian languages. Almost good for Ukrainian,
+# except that "CYRILLIC LETTER SOFT SIGN" is not in the end of alphabet,
+# but between YERU and E.
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 00 02 00 00 00 00 00 00 01 00 01 01 01 01
+ 02 00 00 00 00 00 00 00 00 00 02 00 02 02 02 02
+ 00 01 02 01 00 01 00 00 01 00 01 00 00 00 00 01
+ 00 00 01 02 02 00 00 00 02 00 02 00 02 01 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B3 B3 B4 B5 B6 B7 B8 B9 BA BB BC BE BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F
+ A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B2 A5 B5 B6 B7 A8 B9 AA BB A3 BD BD AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D
+ 5F 61 63 65 67 69 6B 6D 6F 71 73 D3 D4 D5 D6 D7
+ D8 41 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D
+ 5F 61 63 65 67 69 6B 6D 6F 71 73 D9 DA DB DC DD
+ 81 83 DE 83 DF E0 E1 E2 E3 E4 A1 E5 A7 9D B3 C1
+ 81 E6 E7 E8 E9 EA EB EC ED EE A1 EF A7 9D B3 C1
+ F0 B7 B7 99 F1 7D F2 F3 87 F4 89 F5 F6 F7 F8 95
+ F9 FA 93 93 7D FB FC FD 87 FE 89 FF 99 8F 8F 95
+ 75 77 79 7B 7F 85 8B 8D 91 97 9B 9F A3 A5 A9 AB
+ AD AF B1 B5 B9 BB BD BF C3 C5 C7 C9 CB CD CF D1
+ 75 77 79 7B 7F 85 8B 8D 91 97 9B 9F A3 A5 A9 AB
+ AD AF B1 B5 B9 BB BD BF C3 C5 C7 C9 CB CD CF D1
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F
+ 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F
+ 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407
+ 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457
+ 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+ 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+ 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+ 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
+
diff --git a/sql/share/charsets/cp1251csas.conf b/sql/share/charsets/cp1251csas.conf
new file mode 100644
index 00000000000..b6b2f853ea9
--- /dev/null
+++ b/sql/share/charsets/cp1251csas.conf
@@ -0,0 +1,99 @@
+#
+# cp1251
+# Case sensitive, accent sensitive
+# Sort order is correct for Belarusian, Bulgarian, Macedonian,
+# Russian, Serbian, Mongolian languages. Almost good for Ukrainian,
+# except that "CYRILLIC LETTER SOFT SIGN" is not in the end of alphabet,
+# but between YERU and E.
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 00 02 00 00 00 00 00 00 01 00 01 01 01 01
+ 02 00 00 00 00 00 00 00 00 00 02 00 02 02 02 02
+ 00 01 02 01 00 01 00 00 01 00 01 00 00 00 00 01
+ 00 00 01 02 02 00 00 00 02 00 02 00 02 01 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B3 B3 B4 B5 B6 B7 B8 B9 BA BB BC BE BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F
+ A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B2 A5 B5 B6 B7 A8 B9 AA BB A3 BD BD AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D
+ 5F 61 63 65 67 69 6B 6D 6F 71 73 D3 D4 D5 D6 D7
+ D8 42 44 46 48 4A 4C 4E 50 52 54 56 58 5A 5C 5E
+ 60 62 64 66 68 6A 6C 6E 70 72 74 D9 DA DB DC DD
+ 81 83 DE 84 DF E0 E1 E2 E3 E4 A1 E5 A7 9D B3 C1
+ 82 E6 E7 E8 E9 EA EB EC ED EE A2 EF A8 9E B4 C2
+ F0 B7 B8 99 F1 7D F2 F3 87 F4 89 F5 F6 F7 F8 95
+ F9 FA 93 94 7E FB FC FD 88 FE 8A FF 9A 8F 90 96
+ 75 77 79 7B 7F 85 8B 8D 91 97 9B 9F A3 A5 A9 AB
+ AD AF B1 B5 B9 BB BD BF C3 C5 C7 C9 CB CD CF D1
+ 76 78 7A 7C 80 86 8C 8E 92 98 9C A0 A4 A6 AA AC
+ AE B0 B2 B6 BA BC BE C0 C4 C6 C8 CA CC CE D0 D2
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F
+ 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F
+ 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407
+ 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457
+ 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+ 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+ 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+ 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
+
diff --git a/sql/share/charsets/cp1256.conf b/sql/share/charsets/cp1256.conf
new file mode 100644
index 00000000000..6072551813c
--- /dev/null
+++ b/sql/share/charsets/cp1256.conf
@@ -0,0 +1,94 @@
+#
+# Arabic, Persian, Pakistani, Urdu
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 00 00
+ 00 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 03 00 02 00 00 00 00 00 00 00 00 01 03 03 00
+ 03 10 10 10 10 00 00 00 00 00 00 00 02 00 00 00
+ 00 10 00 00 00 00 00 00 00 00 00 10 10 10 00 00
+ 10 10 00 00 00 00 00 00 00 00 10 10 00 00 00 10
+ 00 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
+ 03 03 03 03 03 03 03 00 03 03 03 03 03 03 03 03
+ 02 03 02 03 03 03 03 02 02 02 02 02 03 03 02 02
+ 03 03 03 03 02 03 03 00 03 02 03 02 02 00 00 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 9C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5F 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7F 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 8C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 45 47 4A 4C 52 55 57 59 5D 5F 61 63 65 67
+ 6C 6E 70 72 74 76 7B 7D 7F 81 83 B9 BA BB BC BD
+ BE 41 45 47 4A 4C 52 55 57 59 5D 5F 61 63 65 67
+ 6C 6E 70 72 74 76 7B 7D 7F 81 83 BF C0 C1 C2 C3
+ C4 8E C5 54 C6 C7 C8 C9 CA CB CC CD 6A 92 99 CE
+ A5 CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 6A DA DB DC
+ DD B6 DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB
+ EC ED EE EF F0 F1 F2 F3 F4 F5 B7 F6 F7 F8 F9 B8
+ FA 85 86 87 88 89 8A 8B 8C 8D 9F 90 91 93 94 95
+ 96 97 98 9A 9B 9C 9D FB 9E 9F A0 A1 AD A2 A3 A4
+ 43 A6 44 A7 A8 A9 AA 49 4E 4F 50 51 AB AC 5B 5C
+ AE AF B0 B1 69 B2 B3 FC B4 78 B5 79 7A FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 20AC 067E 201A 0192 201E 2026 2020 2021 02C6 2030 0000 2039 0152 0686 0698 0000
+ 06AF 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0153 200C 200D 0000
+ 00A0 060C 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 0000 00AB 00AC 00AD 00AE 00AF
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 061B 00BB 00BC 00BD 00BE 061F
+ 0000 0621 0622 0623 0624 0625 0626 0627 0628 0629 062A 062B 062C 062D 062E 062F
+ 0630 0631 0632 0633 0634 0635 0636 00D7 0637 0638 0639 063A 0640 0641 0642 0643
+ 00E0 0644 00E2 0645 0646 0647 0648 00E7 00E8 00E9 00EA 00EB 0649 064A 00EE 00EF
+ 064B 064C 064D 064E 00F4 064F 0650 00F7 0651 00F9 0652 00FB 00FC 200E 200F 0000
+
diff --git a/sql/share/charsets/cp1257.conf b/sql/share/charsets/cp1257.conf
index 610ed5a646f..8338f99c83b 100644
--- a/sql/share/charsets/cp1257.conf
+++ b/sql/share/charsets/cp1257.conf
@@ -72,3 +72,21 @@
5A FF FF FF FF FF FF FF 5E FF FF 5D FF FF FF FF
FF 4F FF FF FF FF 48 FF 45 FF FF 49 FF FF FF FF
5A FF FF FF FF FF FF FF 5E FF FF 5D FF FF FF FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8
+0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000
+00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9
diff --git a/sql/share/charsets/cp1257bin.conf b/sql/share/charsets/cp1257bin.conf
new file mode 100644
index 00000000000..032f8a7e05d
--- /dev/null
+++ b/sql/share/charsets/cp1257bin.conf
@@ -0,0 +1,96 @@
+#
+# cp1257 character set
+#
+# Binary sorting order
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01
+ 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 BA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8
+ 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000
+ 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+ 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+ 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+ 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+ 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9
+
diff --git a/sql/share/charsets/cp1257ltlvciai.conf b/sql/share/charsets/cp1257ltlvciai.conf
new file mode 100644
index 00000000000..246ae4d1fe8
--- /dev/null
+++ b/sql/share/charsets/cp1257ltlvciai.conf
@@ -0,0 +1,97 @@
+#
+# cp1257 character set
+#
+# Case-insensitive, accent insensitive sorting order
+# For Latvian and Lithuanian languages
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01
+ 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 BA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83
+ 8F 91 93 97 9E A0 A8 AA AC AE B0 B8 B9 BA BB BC
+ BD 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83
+ 8F 91 93 97 9E A0 A8 AA AC AE B0 BE BF C0 C1 C4
+ C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4
+ D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4
+ E5 E6 E7 E8 E9 EA EB EC 83 ED 93 EE EF F0 F1 41
+ F2 F3 F4 F5 F6 F7 F8 F9 83 FA 93 FB FC FD FE 41
+ 41 69 41 4F 41 41 57 57 4F 57 B0 57 63 71 69 75
+ 97 7D 7D 83 83 83 83 C2 A0 75 97 A0 A0 B0 B0 97
+ 41 69 41 4F 41 41 57 57 4F 57 B0 57 63 71 69 75
+ 97 7D 7D 83 83 83 83 C3 A0 75 97 A0 A0 B0 B0 FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8
+ 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000
+ 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+ 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+ 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+ 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+ 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9
+
diff --git a/sql/share/charsets/cp1257ltlvcias.conf b/sql/share/charsets/cp1257ltlvcias.conf
new file mode 100644
index 00000000000..6e49f5a245d
--- /dev/null
+++ b/sql/share/charsets/cp1257ltlvcias.conf
@@ -0,0 +1,97 @@
+#
+# cp1257 character set
+#
+# Case-insensitive, accent sensitive sorting order
+# For Latvian and Lithuanian languages
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01
+ 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 BA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83
+ 8F 91 93 97 9E A0 A8 AA AC AE B0 B8 B9 BA BB BC
+ BD 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83
+ 8F 91 93 97 9E A0 A8 AA AC AE B0 BE BF C0 C1 C4
+ C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4
+ D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4
+ E5 E6 E7 E8 E9 EA EB EC 85 ED 95 EE EF F0 F1 4B
+ F2 F3 F4 F5 F6 F7 F8 F9 85 FA 95 FB FC FD FE 4B
+ 43 6B 45 51 47 49 59 5B 53 5D B2 5F 65 73 6D 77
+ 99 7F 81 87 89 8B 8D C2 A2 79 9B A4 A6 B4 B6 9D
+ 43 6B 45 51 47 49 59 5B 53 5D B2 5F 65 73 6D 77
+ 99 7F 81 87 89 8B 8D C3 A2 79 9B A4 A6 B4 B6 FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8
+ 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000
+ 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+ 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+ 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+ 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+ 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9
+
diff --git a/sql/share/charsets/cp1257ltlvcsas.conf b/sql/share/charsets/cp1257ltlvcsas.conf
new file mode 100644
index 00000000000..32cd1390bd5
--- /dev/null
+++ b/sql/share/charsets/cp1257ltlvcsas.conf
@@ -0,0 +1,97 @@
+#
+# cp1257 character set
+#
+# Case-sensitive, accent sensitive sorting order
+# For Latvian and Lithuanian languages
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01
+ 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 BA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83
+ 8F 91 93 97 9E A0 A8 AA AC AE B0 B8 B9 BA BB BC
+ BD 42 4E 50 56 58 62 64 68 6A 70 72 76 7C 7E 84
+ 90 92 94 98 9F A1 A9 AB AD AF B1 BE BF C0 C1 C4
+ C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D2 D3 D4
+ D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 E1 E2 E3 E4
+ E5 E6 E7 E8 E9 EA EB EC 85 ED 95 EE EF F0 F1 4B
+ F2 F3 F4 F5 F6 F7 F8 F9 86 FA 96 FB FC FD FE 4C
+ 43 6B 45 51 47 49 59 5B 53 5D B2 5F 65 73 6D 77
+ 99 7F 81 87 89 8B 8D C2 A2 79 9B A4 A6 B4 B6 9D
+ 44 6C 46 52 48 4A 5A 5C 54 5E B3 60 66 74 6E 78
+ 9A 80 82 88 8A 8C 8E C3 A3 7A 9C A5 A7 B5 B7 FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8
+ 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000
+ 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+ 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+ 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+ 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+ 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9
+
diff --git a/sql/share/charsets/cp866.conf b/sql/share/charsets/cp866.conf
new file mode 100644
index 00000000000..0e4dcb3b9bc
--- /dev/null
+++ b/sql/share/charsets/cp866.conf
@@ -0,0 +1,96 @@
+#
+# cp866_DOSCyrillicRussian
+# Case insensitive, accent sensitive.
+#
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 01 02 01 02 01 02 01 02 00 00 00 00 00 00 00 48
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ A0 A1 A2 A3 A4 A5 86 87 88 89 AA AB AC AD AE AF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ A0 A1 A2 A3 A4 A5 86 87 88 89 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F1 F1 F3 F3 F5 F5 F7 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ F0 F0 F2 F2 F4 F4 F6 F6 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D
+ 5F 61 63 65 67 69 6B 6D 6F 71 73 BD BE BF C0 C1
+ C2 41 43 45 47 49 4B 4D 4F 51 54 55 57 59 5B 5D
+ 5F 61 63 65 67 69 6B 6D 6F 71 73 C3 C4 C5 C6 C7
+ 75 77 79 7B 7D 7F 85 87 89 8D 8F 91 93 95 97 99
+ 9B 9D 9F A1 A5 A7 A9 AB AD AF B1 B3 B5 B7 B9 BB
+ 75 77 79 7B 7D 7F 85 87 89 8D 8F 91 93 95 97 99
+ C8 C9 CA D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ 9B 9D 9F A1 A5 A7 A9 AB AD AF B1 B3 B5 B7 B9 BB
+ 81 81 83 83 8B 8B A3 A3 CB CC CD CE CF D0 D1 D2
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+ 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+ 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+ 2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255D 255C 255B 2510
+ 2514 2534 252C 251C 2500 253C 255E 255F 255A 2554 2569 2566 2560 2550 256C 2567
+ 2568 2564 2565 2559 2558 2552 2553 256B 256A 2518 250C 2588 2584 258C 2590 2580
+ 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
+ 0401 0451 0404 0454 0407 0457 040E 045E 00B0 2219 00B7 221A 207F 00B2 25A0 00A0
+
diff --git a/sql/share/charsets/croat.conf b/sql/share/charsets/croat.conf
index fbbe3328547..bc8c1a376eb 100644
--- a/sql/share/charsets/croat.conf
+++ b/sql/share/charsets/croat.conf
@@ -72,3 +72,21 @@
47 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
41 41 41 41 5C 5B 45 43 44 45 45 45 49 49 49 49
47 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 0104 02D8 0141 00A4 013D 015A 00A7 00A8 0160 015E 0164 0179 00AD 017D 017B
+00B0 0105 02DB 0142 00B4 013E 015B 02C7 00B8 0161 015F 0165 017A 02DD 017E 017C
+0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E
+0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF
+0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F
+0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9
diff --git a/sql/share/charsets/danish.conf b/sql/share/charsets/danish.conf
index f99590ed6f3..1543a64d7c3 100644
--- a/sql/share/charsets/danish.conf
+++ b/sql/share/charsets/danish.conf
@@ -72,3 +72,21 @@
44 4E 4F 4F 4F 4F 5C D7 5C 55 55 55 59 59 DE DF
41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5C F7 5C 55 55 55 59 59 DE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF
+00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF
diff --git a/sql/share/charsets/dec8.conf b/sql/share/charsets/dec8.conf
index a4849aaa04c..d1ffe45032d 100644
--- a/sql/share/charsets/dec8.conf
+++ b/sql/share/charsets/dec8.conf
@@ -72,3 +72,21 @@
44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 00A1 00A2 00A3 0000 00A5 0000 00A7 00A4 00A9 00AA 00AB 0000 0000 0000 0000
+00B0 00B1 00B2 00B3 0000 00B5 00B6 00B7 0000 00B9 00BA 00BB 00BC 00BD 0000 00BF
+00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+0000 00D1 00D2 00D3 00D4 00D5 00D6 0152 00D8 00D9 00DA 00DB 00DC 0178 0000 00DF
+00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+0000 00F1 00F2 00F3 00F4 00F5 00F6 0153 00F8 00F9 00FA 00FB 00FC 00FF 0000 0000
diff --git a/sql/share/charsets/dos.conf b/sql/share/charsets/dos.conf
index dda86d0f3e8..205202711b8 100644
--- a/sql/share/charsets/dos.conf
+++ b/sql/share/charsets/dos.conf
@@ -1,4 +1,4 @@
-# Configuration file for the dos character set
+# Configuration file for the dos (aka cp437 DOSLatinUS) character set
# ctype array (must have 257 elements)
00
@@ -72,3 +72,22 @@
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (256 elements)
+
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000a 000b 000c 000d 000e 000f
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001a 001b 001c 001d 001e 001f
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002a 002b 002c 002d 002e 002f
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003a 003b 003c 003d 003e 003f
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004a 004b 004c 004d 004e 004f
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005a 005b 005c 005d 005e 005f
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006a 006b 006c 006d 006e 006f
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007a 007b 007c 007d 007e 007f
+00c7 00fc 00e9 00e2 00e4 00e0 00e5 00e7 00ea 00eb 00e8 00ef 00ee 00ec 00c4 00c5
+00c9 00e6 00c6 00f4 00f6 00f2 00fb 00f9 00ff 00d6 00dc 00a2 00a3 00a5 20a7 0192
+00e1 00ed 00f3 00fa 00f1 00d1 00aa 00ba 00bf 2310 00ac 00bd 00bc 00a1 00ab 00bb
+2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255d 255c 255b 2510
+2514 2534 252c 251c 2500 253c 255e 255f 255a 2554 2569 2566 2560 2550 256c 2567
+2568 2564 2565 2559 2558 2552 2553 256b 256a 2518 250c 2588 2584 258c 2590 2580
+03b1 00df 0393 03c0 03a3 03c3 00b5 03c4 03a6 0398 03a9 03b4 221e 03c6 03b5 2229
+2261 00b1 2265 2264 2320 2321 00f7 2248 00b0 2219 00b7 221a 207f 00b2 25a0 00a0
diff --git a/sql/share/charsets/estonia.conf b/sql/share/charsets/estonia.conf
index 76bbc021b0c..0226fd1fe82 100644
--- a/sql/share/charsets/estonia.conf
+++ b/sql/share/charsets/estonia.conf
@@ -72,3 +72,21 @@
DB C2 C4 C8 CA F2 F6 64 EC BC D8 EA F8 E1 E3 DA
8D B1 89 95 F5 8B A3 A1 97 9D E0 9F A9 B7 AF BB
DC C3 C5 C9 CB F3 F7 65 ED BD D9 EB F9 E2 E4 53
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 201D 00A2 00A3 00A4 201E 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+00B0 00B1 00B2 00B3 201C 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 2019
diff --git a/sql/share/charsets/german1.conf b/sql/share/charsets/german1.conf
index 3090c921ebe..64f27da3499 100644
--- a/sql/share/charsets/german1.conf
+++ b/sql/share/charsets/german1.conf
@@ -72,3 +72,21 @@
D0 4E 4F 4F 4F 4F 4F D7 4F 55 55 55 55 59 DE 53
41 41 41 41 41 41 41 43 45 45 45 45 49 49 49 49
D0 4E 4F 4F 4F 4F 4F F7 4F 55 55 55 55 59 DE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF
+00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF
diff --git a/sql/share/charsets/greek.conf b/sql/share/charsets/greek.conf
index 73d67d6ee71..5eb38e2efbe 100644
--- a/sql/share/charsets/greek.conf
+++ b/sql/share/charsets/greek.conf
@@ -72,3 +72,22 @@
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 C9 D5 C1 C5 C7 C9
D5 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
D0 D1 D3 D3 D4 D5 D6 D7 D8 D9 C9 D5 CF D5 D9 FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 02BD 02BC 00A3 0000 0000 00A6 00A7 00A8 00A9 0000 00AB 00AC 00AD 0000 2015
+00B0 00B1 00B2 00B3 0384 0385 0386 00B7 0388 0389 038A 00BB 038C 00BD 038E 038F
+0390 0391 0392 0393 0394 0395 0396 0397 0398 0399 039A 039B 039C 039D 039E 039F
+03A0 03A1 0000 03A3 03A4 03A5 03A6 03A7 03A8 03A9 03AA 03AB 03AC 03AD 03AE 03AF
+03B0 03B1 03B2 03B3 03B4 03B5 03B6 03B7 03B8 03B9 03BA 03BB 03BC 03BD 03BE 03BF
+03C0 03C1 03C2 03C3 03C4 03C5 03C6 03C7 03C8 03C9 03CA 03CB 03CC 03CD 03CE 0000
+ \ No newline at end of file
diff --git a/sql/share/charsets/hebrew.conf b/sql/share/charsets/hebrew.conf
index 6a5f88eb228..84581f6f1bb 100644
--- a/sql/share/charsets/hebrew.conf
+++ b/sql/share/charsets/hebrew.conf
@@ -72,3 +72,22 @@
D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 0000 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00D7 00AB 00AC 00AD 00AE 203E
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00F7 00BB 00BC 00BD 00BE 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2017
+05D0 05D1 05D2 05D3 05D4 05D5 05D6 05D7 05D8 05D9 05DA 05DB 05DC 05DD 05DE 05DF
+05E0 05E1 05E2 05E3 05E4 05E5 05E6 05E7 05E8 05E9 05EA 0000 0000 0000 0000 0000
+ \ No newline at end of file
diff --git a/sql/share/charsets/hp8.conf b/sql/share/charsets/hp8.conf
index e9fadacbf76..07036d6f186 100644
--- a/sql/share/charsets/hp8.conf
+++ b/sql/share/charsets/hp8.conf
@@ -72,3 +72,22 @@
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 00C0 00C2 00C8 00CA 00CB 00CE 00CF 00B4 02CB 02C6 00A8 02DC 00D9 00DB 20A4
+00AF 00DD 00FD 00B0 00C7 00E7 00D1 00F1 00A1 00BF 00A4 00A3 00A5 00A7 0192 00A2
+00E2 00EA 00F4 00FB 00E1 00E9 00F3 00FA 00E0 00E8 00F2 00F9 00E4 00EB 00F6 00FC
+00C5 00EE 00D8 00C6 00E5 00ED 00F8 00E6 00C4 00EC 00D6 00DC 00C9 00EF 00DF 00D4
+00C1 00C3 00E3 00D0 00F0 00CD 00CC 00D3 00D2 00D5 00F5 0160 0161 00DA 0178 00FF
+00DE 00FE 00B7 00B5 00B6 00BE 2014 00BC 00BD 00AA 00BA 00AB 25A0 00BB 00B1 0000
+
diff --git a/sql/share/charsets/hungarian.conf b/sql/share/charsets/hungarian.conf
index db58d62575f..dffaff9348d 100644
--- a/sql/share/charsets/hungarian.conf
+++ b/sql/share/charsets/hungarian.conf
@@ -72,3 +72,21 @@
FF 62 63 64 66 67 67 FF 6D 77 75 78 78 7E 74 FF
64 41 44 45 46 5F 49 4B 4A 4E 51 78 50 56 58 4D
FF 62 63 64 66 67 67 FF 6D 77 75 78 78 7E 74 FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 0104 02D8 0141 00A4 013D 015A 00A7 00A8 0160 015E 0164 0179 00AD 017D 017B
+00B0 0105 02DB 0142 00B4 013E 015B 02C7 00B8 0161 015F 0165 017A 02DD 017E 017C
+0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E
+0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF
+0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F
+0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9
diff --git a/sql/share/charsets/keybcs2.conf b/sql/share/charsets/keybcs2.conf
new file mode 100644
index 00000000000..f272960b683
--- /dev/null
+++ b/sql/share/charsets/keybcs2.conf
@@ -0,0 +1,91 @@
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 02 82 02 02 01 01 02 82 81 01 01 02 02 01 01
+ 81 02 01 02 02 01 02 01 02 01 01 01 01 01 01 02
+ 02 02 02 02 02 01 01 01 02 02 02 01 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 02 02 01 02 01 02 00 02 01 01 01 02 00 02 02 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 87 81 82 83 84 83 86 87 88 88 8D A1 8C 8D 84 A0
+ 82 91 91 93 94 A2 96 A3 98 94 81 9B 8C 98 A9 9F
+ A0 A1 A2 A3 A4 A4 96 93 9B A9 AA AA AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 ED E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 68 59 5A 7B 7C 7D 7E 7F
+ 87 9A 90 85 8E 85 86 80 89 89 8A 8B 9C 8A 8E 8F
+ 90 92 92 A7 99 95 A6 97 9D 99 9A A8 9C 9D 9E 9F
+ 8F 8B 95 97 A5 A5 A6 A7 A8 9E AB AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC E8 EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 44 45 47 49 50 51 52 53 54 55 56 57 58 5A
+ 5E 5F 60 63 66 68 6C 6D 6E 6F 72 90 91 92 93 94
+ 95 41 44 45 47 49 50 51 52 53 54 55 56 57 58 5A
+ 5E 5F 60 63 66 68 6C 6D 6E 6F 72 96 97 98 99 9A
+ 45 68 49 47 41 47 66 45 49 49 56 53 56 56 41 41
+ 49 72 72 5A 5A 5A 68 68 6F 5A 68 63 56 6F 60 66
+ 41 53 5A 68 58 58 68 5A 63 60 60 60 A0 A1 A2 A3
+ A4 A5 A6 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC
+ BD BE BF C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC
+ CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC
+ 80 65 83 87 88 89 DD 8A 85 8B 84 81 DE 85 82 DF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mappping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 010C 00FC 00E9 010F 00E4 010E 0164 010D 011B 011A 0139 00CD 013E 013A 00C4 00C1
+ 00C9 017E 017D 00F4 00F6 00D3 016F 00DA 00FD 00D6 00DC 0160 013D 00DD 0158 0165
+ 00E1 00ED 00F3 00FA 0148 0147 016E 00D4 0161 0159 0155 0154 00BC 00A1 00AB 00BB
+ 2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255D 255C 255B 2510
+ 2514 2534 252C 251C 2500 253C 255E 255F 255A 2554 2569 2566 2560 2550 256C 2567
+ 2568 2564 2565 2559 2558 2552 2553 256B 256A 2518 250C 2588 2584 258C 2590 2580
+ 03B1 00DF 0393 03C0 03A3 03C3 00B5 03C4 03A6 0398 03A9 03B4 221E 03C6 03B5 2229
+ 2261 00B1 2265 2264 2320 2321 00F7 2248 00B0 2219 00B7 221A 207F 00B2 25A0 00A0
+
diff --git a/sql/share/charsets/koi8_ru.conf b/sql/share/charsets/koi8_ru.conf
index 4cfee67a236..b1d9755173f 100644
--- a/sql/share/charsets/koi8_ru.conf
+++ b/sql/share/charsets/koi8_ru.conf
@@ -72,3 +72,22 @@
EF FF F0 F1 F2 F3 E6 E1 FC FB E7 F8 FD F9 F7 FA
FE DF E0 F6 E3 E4 F4 E2 F5 E8 E9 EA EB EC ED EE
EF FF F0 F1 F2 F3 E6 E1 FC FB E7 F8 FD F9 F7 FA
+
+# Unicode mapping table (256 elements)
+
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000a 000b 000c 000d 000e 000f
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001a 001b 001c 001d 001e 001f
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002a 002b 002c 002d 002e 002f
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003a 003b 003c 003d 003e 003f
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004a 004b 004c 004d 004e 004f
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005a 005b 005c 005d 005e 005f
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006a 006b 006c 006d 006e 006f
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007a 007b 007c 007d 007e 007f
+2500 2502 250c 2510 2514 2518 251c 2524 252c 2534 253c 2580 2584 2588 258c 2590
+2591 2592 2593 2320 25a0 2219 221a 2248 2264 2265 00a0 2321 00b0 00b2 00b7 00f7
+2550 2551 2552 0451 2553 2554 2555 2556 2557 2558 2559 255a 255b 255c 255d 255e
+255f 2560 2561 0401 2562 2563 2564 2565 2566 2567 2568 2569 256a 256b 256c 00a9
+044e 0430 0431 0446 0434 0435 0444 0433 0445 0438 0439 043a 043b 043c 043d 043e
+043f 044f 0440 0441 0442 0443 0436 0432 044c 044b 0437 0448 044d 0449 0447 044a
+042e 0410 0411 0426 0414 0415 0424 0413 0425 0418 0419 041a 041b 041c 041d 041e
+041f 042f 0420 0421 0422 0423 0416 0412 042c 042b 0417 0428 042d 0429 0427 042a
diff --git a/sql/share/charsets/koi8_ukr.conf b/sql/share/charsets/koi8_ukr.conf
index 3e2c8e27325..5a552900544 100644
--- a/sql/share/charsets/koi8_ukr.conf
+++ b/sql/share/charsets/koi8_ukr.conf
@@ -72,3 +72,21 @@
94 A4 95 96 97 98 89 82 A1 A0 8A 9D A2 9E 9C 9F
A3 80 81 9B 85 86 99 83 9A 8B 8E 8F 90 91 92 93
94 A4 95 96 97 98 89 82 A1 A0 8A 9D A2 9E 9C 9F
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+2500 2502 250C 2510 2514 2518 251C 2524 252C 2534 253C 2580 2584 2588 258C 2590
+2591 2592 2593 2320 25A0 2022 221A 2248 2264 2265 00A0 2321 00B0 00B2 00B7 00F7
+2550 2551 2552 0451 0454 2554 0456 0457 2557 2558 2559 255A 255B 0491 255D 255E
+255F 2560 2561 0401 0404 2563 0406 0407 2566 2567 2568 2569 256A 0490 256C 00A9
+044E 0430 0431 0446 0434 0435 0444 0433 0445 0438 0439 043A 043B 043C 043D 043E
+043F 044F 0440 0441 0442 0443 0436 0432 044C 044B 0437 0448 044D 0449 0447 044A
+042E 0410 0411 0426 0414 0415 0424 0413 0425 0418 0419 041A 041B 041C 041D 041E
+041F 042F 0420 0421 0422 0423 0416 0412 042C 042B 0417 0428 042D 0429 0427 042A
diff --git a/sql/share/charsets/latin1.conf b/sql/share/charsets/latin1.conf
index cf974aefa14..7cb5cfb3cfd 100644
--- a/sql/share/charsets/latin1.conf
+++ b/sql/share/charsets/latin1.conf
@@ -72,3 +72,21 @@
44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF
41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF
+00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF
diff --git a/sql/share/charsets/latin1bin.conf b/sql/share/charsets/latin1bin.conf
new file mode 100644
index 00000000000..37e6350bcb2
--- /dev/null
+++ b/sql/share/charsets/latin1bin.conf
@@ -0,0 +1,96 @@
+#
+# Latin1, accent sensitive, case sensitive
+#
+# Binary sorting order
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 02
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+ 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+ 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+ 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+ 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF
+ 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+ 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF
+
diff --git a/sql/share/charsets/latin1cias.conf b/sql/share/charsets/latin1cias.conf
new file mode 100644
index 00000000000..3b0e104aafd
--- /dev/null
+++ b/sql/share/charsets/latin1cias.conf
@@ -0,0 +1,97 @@
+#
+# Latin1, accent sensitive, case insensitive
+#
+# Sorting for Dutch, English, French, German (Duden),
+# Italian, Latin, Pogtuguese, Spanish
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 02
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 51 53 57 5B 65 67 69 6B 75 77 79 7B 7D 81
+ 8F 91 93 95 98 9A A4 A6 A8 AA AF B3 B4 B5 B6 B7
+ B8 41 51 53 57 5B 65 67 69 6B 75 77 79 7B 7D 81
+ 8F 91 93 95 98 9A A4 A6 A8 AA AF B9 BA BB BC BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ 43 45 47 49 4B 4D 4F 55 5D 5F 61 63 6D 6F 71 73
+ 59 7F 83 85 87 89 8B BD 8D 9C 9E A0 A2 AC B1 97
+ 43 45 47 49 4B 4D 4F 55 5D 5F 61 63 6D 6F 71 73
+ 59 7F 83 85 87 89 8B BE 8D 9C 9E A0 A2 AC B1 AE
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+ 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+ 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+ 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+ 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF
+ 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+ 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF
+
diff --git a/sql/share/charsets/latin1csas.conf b/sql/share/charsets/latin1csas.conf
new file mode 100644
index 00000000000..cb3a1285de8
--- /dev/null
+++ b/sql/share/charsets/latin1csas.conf
@@ -0,0 +1,97 @@
+#
+# Latin1, accent sensitive, case sensitive
+#
+# Sorting for Dutch, English, French, German (Duden),
+# Italian, Latin, Pogtuguese, Spanish
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 02
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 51 53 57 5B 65 67 69 6B 75 77 79 7B 7D 81
+ 8F 91 93 95 98 9A A4 A6 A8 AA AF B3 B4 B5 B6 B7
+ B8 42 52 54 58 5C 66 68 6A 6C 76 78 7A 7C 7E 82
+ 90 92 94 96 99 9B A5 A7 A9 AB B0 B9 BA BB BC BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+ 43 45 47 49 4B 4D 4F 55 5D 5F 61 63 6D 6F 71 73
+ 59 7F 83 85 87 89 8B BD 8D 9C 9E A0 A2 AC B1 97
+ 44 46 48 4A 4C 4E 50 56 5E 60 62 64 6E 70 72 74
+ 5A 80 84 86 88 8A 8C BE 8E 9D 9F A1 A3 AD B2 AE
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+ 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+ 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+ 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+ 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+ 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF
+ 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+ 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF
+
diff --git a/sql/share/charsets/latin2.conf b/sql/share/charsets/latin2.conf
index cc18c22c0a2..cc21af9faa1 100644
--- a/sql/share/charsets/latin2.conf
+++ b/sql/share/charsets/latin2.conf
@@ -72,3 +72,21 @@
FF 55 54 57 56 56 56 FF 5A 5F 5F 5F 5F 63 5E FF
5A 43 43 43 43 51 46 45 47 49 4A 49 49 4E 4E 48
FF 55 54 57 56 56 56 FF 5A 5F 5F 5F 5F 63 5E FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 0104 02D8 0141 00A4 013D 015A 00A7 00A8 0160 015E 0164 0179 00AD 017D 017B
+00B0 0105 02DB 0142 00B4 013E 015B 02C7 00B8 0161 015F 0165 017A 02DD 017E 017C
+0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E
+0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF
+0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F
+0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9
diff --git a/sql/share/charsets/latin5.conf b/sql/share/charsets/latin5.conf
index 92fbd2299bb..d603d019ce6 100644
--- a/sql/share/charsets/latin5.conf
+++ b/sql/share/charsets/latin5.conf
@@ -76,3 +76,21 @@
49 DB DC DD DE DF 53 E0 E1 E2 E3 E4 5B 4C 58 E5
CC CD CE CF D0 D1 D2 44 D3 D4 D5 D6 D7 D8 D9 DA
49 DB DC DD DE DF 53 FA E1 E2 E3 E4 5B 4B 58 FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF
+011E 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 0130 015E 00DF
+00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF
+011F 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 0131 015F 00FF
diff --git a/sql/share/charsets/latvian.conf b/sql/share/charsets/latvian.conf
new file mode 100644
index 00000000000..c3dee95d55c
--- /dev/null
+++ b/sql/share/charsets/latvian.conf
@@ -0,0 +1,95 @@
+# Configuration file for the latvian character set.
+# Created for case-sensitive record search
+# Created accord with windows-1257 (iso-8859-4) codepage
+# Created by Andis Grasis & Rihards Grasis e-mail:andis@cata.lv
+
+# The ctype array must have 257 elements.
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 01 20 10 20 10 10 00 00 20 10 20 10 20 10 10 10
+ 20 10 10 10 10 10 10 10 20 00 20 10 20 10 10 20
+ 48 20 10 10 10 20 10 10 10 10 01 10 10 10 10 01
+ 10 10 10 10 10 10 10 10 10 10 02 10 10 10 10 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10
+
+# The to_lower array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# The to_upper array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 AA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# The sort_order array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 30 32 33 34 35 36 37 2B 38 39 3A 5C 3B 2C 3C 3D
+ 76 7A 7C 7E 80 81 82 83 84 85 3E 3F 5D 5E 5F 40
+ 41 86 92 94 9A 9C A6 A8 AC AE B4 B6 BA C0 C2 C8
+ D4 D6 D8 DC E3 E6 EE F0 F2 F4 F6 42 43 44 45 46
+ 47 87 93 95 9B 9D A7 A9 AD AF B5 B7 BB C1 C3 C9
+ D5 D7 D9 DD E4 E7 EF F1 F3 F5 F7 48 49 4A 4B 20
+ 75 21 56 22 59 73 70 71 23 74 24 5A 25 4D 51 50
+ 26 54 55 57 58 72 2E 2F 27 E5 28 5B 29 4E 53 2A
+ 31 FE 65 66 67 FF 4C 68 D3 69 DA 61 6A 2D 6B 90
+ 6C 60 7D 7F 4F 6D 6E 6F D2 7B DB 62 77 78 79 91
+ 8E B2 8A 96 88 8C A4 A2 98 9E F8 A0 AA B8 B0 BE
+ E1 C4 C6 CA CE D0 CC 63 EC BC DE EA E8 FA FC E0
+ 8F B3 8B 97 89 8D A5 A3 99 9F F9 A1 AB B9 B1 BF
+ E2 C5 C7 CB CF D1 CD 64 ED BD DF EB E9 FB FD 52
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 201D 00A2 00A3 00A4 201E 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+00B0 00B1 00B2 00B3 201C 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 2019
diff --git a/sql/share/charsets/latvian1.conf b/sql/share/charsets/latvian1.conf
new file mode 100644
index 00000000000..3094525052d
--- /dev/null
+++ b/sql/share/charsets/latvian1.conf
@@ -0,0 +1,94 @@
+# Configuration file for the latvian character set.
+# Created for case-insensitive record search
+# Created by Andis & Rihards
+
+# The ctype array must have 257 elements.
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 10 00 10 10 00 00 00 00 00 10 00 10 10 10
+ 00 10 10 10 10 10 10 10 00 00 00 10 00 10 10 00
+ 48 00 10 10 10 00 10 10 10 10 01 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10
+
+# The to_lower array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 BA AB AC AD AE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# The to_upper array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 AA BB BC BD BE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+
+# The sort_order array must have 256 elements.
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 30 32 33 34 35 36 37 2B 38 39 3A 5C 3B 2C 3C 3D
+ 76 7A 7C 7E 80 81 82 83 84 85 3E 3F 5D 5E 5F 40
+ 41 86 92 94 9A 9C A6 A8 AC AE B4 B6 BA C0 C2 C8
+ D4 D6 D8 DC E3 E6 EE F0 F2 F4 F6 42 43 44 45 46
+ 47 86 92 94 9A 9C A6 A8 AC AE B4 B6 BA C0 C2 C8
+ D4 D6 D8 DC E2 E6 EE F0 F2 F4 F6 48 49 4A 4B 20
+ 75 21 56 22 59 73 70 71 23 74 24 5A 25 4D 51 50
+ 26 54 55 57 58 72 2E 2F 27 E5 28 5B 29 4E 53 2A
+ 31 FE 65 66 67 FF 4C 68 2D 69 DA 61 6A 2D 6B 90
+ 6C 60 7D 7F 4F 6D 6E 6F D3 7B DB 62 77 78 79 90
+ 8E B2 8A 96 88 8C A4 A2 98 9E F8 A0 AA B8 B0 BE
+ E1 C4 C6 CA CE D0 CC 63 EC BC DE EA E8 FA FC E0
+ 8E B2 8A 96 88 8C A4 A2 98 9E F8 A0 AA B8 B0 BE
+ E1 C4 C6 CA CE D0 CC 64 EC BC DE EA E8 FA FC 52
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F
+0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F
+00A0 201D 00A2 00A3 00A4 201E 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6
+00B0 00B1 00B2 00B3 201C 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6
+0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B
+0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF
+0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C
+0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 2019
diff --git a/sql/share/charsets/macce.conf b/sql/share/charsets/macce.conf
new file mode 100644
index 00000000000..f3ac08df087
--- /dev/null
+++ b/sql/share/charsets/macce.conf
@@ -0,0 +1,91 @@
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01
+ 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02
+ 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01
+ 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01
+ 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01
+ 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01
+ 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01
+ 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90
+ 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F
+ A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0
+ B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0
+ C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0
+ E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99
+ F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F
+ 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF
+ AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF
+ BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF
+ D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF
+ DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF
+ ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 46 47 4A 4C 52 53 55 56 5A 5B 5D 62 62 67
+ 6F 70 71 75 79 81 88 89 8A 8B 8D 90 91 92 93 94
+ 95 41 46 47 4A 4C 52 53 55 56 5A 5B 5D 62 62 67
+ 6F 70 71 75 79 81 88 89 8A 8B 8D 96 97 98 99 9A
+ 41 41 41 4C 41 67 81 41 41 47 41 47 47 47 4C 8D
+ 8D 4A 56 4A 4C 4C 4C 67 4C 67 67 67 81 4C 4C 81
+ A0 A1 4C A3 A4 A5 A6 75 A8 A9 AA 4C AC AD 53 56
+ 56 56 B2 B3 56 5B B6 B7 5D 5D 5D 5D 5D 5D 5D 62
+ 62 62 C2 C3 62 62 C6 C7 C8 C9 CA 62 67 67 67 67
+ D0 D1 D2 D3 D4 D5 D6 D7 67 71 71 71 DC DD 71 71
+ 71 75 E2 E3 75 75 75 41 79 79 56 8D 8D 81 67 67
+ 81 81 81 81 81 81 81 81 8B 8B 5B 8D 5D 8D 53 FF
+
+# Unicode mappping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179
+ 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC
+ 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E
+ 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145
+ 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156
+ 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4
+ 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7
+
diff --git a/sql/share/charsets/maccebin.conf b/sql/share/charsets/maccebin.conf
new file mode 100644
index 00000000000..f859e64354c
--- /dev/null
+++ b/sql/share/charsets/maccebin.conf
@@ -0,0 +1,96 @@
+# Mac OS Central European, binary sort order
+#
+# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr),
+# Slovak (sk), Slovenian (sl), Sorbian.
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01
+ 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02
+ 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01
+ 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01
+ 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01
+ 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01
+ 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01
+ 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90
+ 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F
+ A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0
+ B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0
+ C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0
+ E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99
+ F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F
+ 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF
+ AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF
+ BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF
+ D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF
+ DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF
+ ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179
+ 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC
+ 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E
+ 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145
+ 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156
+ 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4
+ 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7
+
diff --git a/sql/share/charsets/macceciai.conf b/sql/share/charsets/macceciai.conf
new file mode 100644
index 00000000000..d7cdaddc425
--- /dev/null
+++ b/sql/share/charsets/macceciai.conf
@@ -0,0 +1,96 @@
+# Mac OS Central European, case insensitive, accent sensitive
+#
+# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr),
+# Slovak (sk), Slovenian (sl), Sorbian.
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01
+ 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02
+ 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01
+ 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01
+ 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01
+ 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01
+ 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01
+ 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90
+ 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F
+ A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0
+ B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0
+ C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0
+ E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99
+ F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F
+ 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF
+ AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF
+ BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF
+ D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF
+ DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF
+ ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D
+ 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D2 D3 D4 D5 D6
+ D7 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D
+ 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D8 D9 DA DB DC
+ 41 41 41 57 41 8D B2 41 41 4D 41 4D 4D 4D 57 CA
+ CA 53 6B 53 57 57 57 8D 57 8D 8D 8D B2 57 57 B2
+ DD DE 57 DF E0 E1 E2 A7 E3 E4 E5 57 E6 E7 65 6B
+ 6B 6B E8 E9 6B 75 EA EB 79 79 79 79 79 79 79 85
+ 85 85 EC ED 85 85 EE EF F0 F1 F2 85 8D 8D 8D 8D
+ F3 F4 F5 F6 F7 F8 F9 FA 8D 9F 9F 9F FB FC 9F 9F
+ 9F A7 FD FE A7 A7 A7 41 BE BE 6B CA CA B2 8D 8D
+ B2 B2 B2 B2 B2 B2 B2 B2 C6 C6 75 CA 79 CA 65 FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179
+ 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC
+ 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E
+ 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145
+ 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156
+ 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4
+ 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7
+
diff --git a/sql/share/charsets/maccecias.conf b/sql/share/charsets/maccecias.conf
new file mode 100644
index 00000000000..8cefd4cf9ec
--- /dev/null
+++ b/sql/share/charsets/maccecias.conf
@@ -0,0 +1,96 @@
+# Mac OS Central European, case insensitive, accent sensitive
+#
+# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr),
+# Slovak (sk), Slovenian (sl), Sorbian.
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01
+ 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02
+ 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01
+ 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01
+ 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01
+ 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01
+ 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01
+ 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90
+ 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F
+ A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0
+ B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0
+ C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0
+ E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99
+ F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F
+ 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF
+ AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF
+ BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF
+ D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF
+ DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF
+ ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D
+ 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D2 D3 D4 D5 D6
+ D7 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D
+ 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D8 D9 DA DB DC
+ 45 47 47 59 49 91 B6 43 49 4F 45 4F 51 51 59 CE
+ CE 55 71 55 5B 5B 5D 8F 5D 99 91 97 B8 5F 5F B6
+ DD DE 61 DF E0 E1 E2 AD E3 E4 E5 61 E6 E7 67 6F
+ 6F 6D E8 E9 6D 77 EA EB 7B 81 82 7F 7F 7D 7D 8B
+ 8B 87 EC ED 87 89 EE EF F0 F1 F2 89 93 97 93 95
+ F3 F4 F5 F6 F7 F8 F9 FA 95 A1 A1 A3 FB FC A3 A5
+ A5 A9 FD FE A9 AB AB 43 B0 B0 71 CC CC BC 8F 99
+ BC B4 B8 B4 BA BA BE BE C8 C8 77 D0 7B D0 67 FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179
+ 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC
+ 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E
+ 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145
+ 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156
+ 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4
+ 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7
+
diff --git a/sql/share/charsets/maccecsas.conf b/sql/share/charsets/maccecsas.conf
new file mode 100644
index 00000000000..8cc1de422f2
--- /dev/null
+++ b/sql/share/charsets/maccecsas.conf
@@ -0,0 +1,96 @@
+# Mac OS Central European, case sensitive, accent sensitive
+#
+# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr),
+# Slovak (sk), Slovenian (sl), Sorbian.
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01
+ 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02
+ 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01
+ 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01
+ 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01
+ 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01
+ 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01
+ 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90
+ 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F
+ A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0
+ B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0
+ C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0
+ E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99
+ F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F
+ 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF
+ AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF
+ BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF
+ D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF
+ DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF
+ ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D
+ 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D2 D3 D4 D5 D6
+ D7 42 4C 4E 54 58 64 66 6A 6C 74 76 7A 84 86 8E
+ 9C 9E A0 A8 AF B3 C1 C3 C5 C7 CB D8 D9 DA DB DC
+ 45 47 48 59 49 91 B6 44 4A 4F 46 50 51 52 5A CE
+ CF 55 72 56 5B 5C 5D 90 5E 9A 92 98 B8 5F 60 B7
+ DD DE 61 DF E0 E1 E2 AD E3 E4 E5 62 E6 E7 68 6F
+ 70 6D E8 E9 6E 77 EA EB 7C 81 82 7F 80 7D 7E 8B
+ 8C 87 EC ED 88 89 EE EF F0 F1 F2 8A 93 97 94 95
+ F3 F4 F5 F6 F7 F8 F9 FA 96 A1 A2 A3 FB FC A4 A5
+ A6 A9 FD FE AA AB AC 43 B0 B1 71 CC CD BC 8F 99
+ BD B4 B9 B5 BA BB BE BF C8 C9 78 D0 7B D1 67 FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179
+ 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC
+ 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E
+ 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145
+ 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156
+ 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4
+ 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7
+
diff --git a/sql/share/charsets/macroman.conf b/sql/share/charsets/macroman.conf
new file mode 100644
index 00000000000..11cbee40e94
--- /dev/null
+++ b/sql/share/charsets/macroman.conf
@@ -0,0 +1,91 @@
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 10
+ 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02
+ 00 00 00 00 02 00 00 00 00 00 00 20 01 01 00 00
+ 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00
+ 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01
+ 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 8C 8D 8E 96 9A 9F 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD BE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA 88 8B 9B CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99
+ F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 E7 CB E5 80 CC 81 82 83 E9
+ E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D9 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 49 50 52 53 57 59 60 61 67 68 69 70 71 72
+ 79 80 81 82 84 85 90 91 92 93 95 A0 A1 A2 A3 A4
+ A5 41 49 50 52 53 57 59 60 61 67 68 69 70 71 72
+ 79 80 81 82 84 85 90 91 92 93 95 A6 A7 A8 A9 AA
+ 41 41 50 53 71 72 85 41 41 41 41 41 41 50 53 53
+ 53 53 61 61 61 61 71 72 72 72 72 72 85 85 85 85
+ AB AC AD AE AF B0 B1 82 B2 B3 B4 B5 B6 B7 48 72
+ B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 48 72
+ C6 C7 C8 C9 57 CA CB CC CD CE CF 41 41 72 D0 D1
+ D2 D3 D4 D5 D6 D7 D8 D9 93 93 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 41 53 41 53 53 61 61 61 61 72 72
+ F0 72 85 85 85 61 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mappping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8
+ 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC
+ 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8
+ 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8
+ 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02
+ 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4
+ F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7
+
diff --git a/sql/share/charsets/macromanbin.conf b/sql/share/charsets/macromanbin.conf
new file mode 100644
index 00000000000..d0845c07f2b
--- /dev/null
+++ b/sql/share/charsets/macromanbin.conf
@@ -0,0 +1,96 @@
+#
+# Mac OS Roman, accent insensitive, case insensitive
+#
+# Binary sort order
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 10
+ 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02
+ 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02
+ 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00
+ 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01
+ 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 8C 8D 8E 96 9A 9F 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD BE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA 88 8B 9B CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99
+ F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 E7 CB E5 80 CC 81 82 83 E9
+ E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D9 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8
+ 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC
+ 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8
+ 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8
+ 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02
+ 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4
+ F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7
+
diff --git a/sql/share/charsets/macromanciai.conf b/sql/share/charsets/macromanciai.conf
new file mode 100644
index 00000000000..457e6b4f8d9
--- /dev/null
+++ b/sql/share/charsets/macromanciai.conf
@@ -0,0 +1,97 @@
+#
+# Mac OS Roman, accent insensitive, case insensitive
+#
+# Sort order: Dutch, English, French, German (Duden),
+# Italian, Latin, Pogtuguese, Spanish
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 10
+ 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02
+ 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02
+ 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00
+ 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01
+ 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 8C 8D 8E 96 9A 9F 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD BE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA 88 8B 9B CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99
+ F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 E7 CB E5 80 CC 81 82 83 E9
+ E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D9 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81
+ 91 93 95 97 9A 9C A6 A8 AA AC B0 B2 B3 B4 B5 B6
+ B7 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81
+ 91 93 95 97 9A 9C A6 A8 AA AC B0 B8 B9 BA BB BC
+ 41 41 53 59 7D 81 9C 41 41 41 41 41 41 53 59 59
+ 59 59 6A 6A 6A 6A 7D 81 81 81 81 81 9C 9C 9C 9C
+ BD BE BF C0 C1 C2 C3 97 C4 C5 C6 C7 C8 C9 41 81
+ CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 41 81
+ D8 D9 DA DB 63 DC DD DE DF E0 E1 41 41 81 81 81
+ E2 E3 E4 E5 E6 E7 E8 E9 AC AC EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 41 59 41 59 59 6A 6A 6A 6A 81 81
+ F0 81 9C 9C 9C 6A F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8
+ 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC
+ 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8
+ 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8
+ 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02
+ 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4
+ F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7
+
diff --git a/sql/share/charsets/macromancias.conf b/sql/share/charsets/macromancias.conf
new file mode 100644
index 00000000000..a00d7d412e6
--- /dev/null
+++ b/sql/share/charsets/macromancias.conf
@@ -0,0 +1,97 @@
+#
+# Mac OS Roman, accent sensitive, case insensitive
+#
+# Sort order: Dutch, English, French, German (Duden),
+# Italian, Latin, Pogtuguese, Spanish
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 10
+ 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02
+ 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02
+ 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00
+ 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01
+ 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 8C 8D 8E 96 9A 9F 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD BE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA 88 8B 9B CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99
+ F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 E7 CB E5 80 CC 81 82 83 E9
+ E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D9 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81
+ 91 93 95 97 9A 9C A6 A8 AA AC B0 B2 B3 B4 B5 B6
+ B7 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81
+ 91 93 95 97 9A 9C A6 A8 AA AC B0 B8 B9 BA BB BC
+ 4B 4D 55 5D 7F 8B A4 45 43 47 4B 49 4D 55 5D 5B
+ 5F 61 6E 6C 70 72 7F 85 83 87 8B 89 A0 9E A2 A4
+ BD BE BF C0 C1 C2 C3 99 C4 C5 C6 C7 C8 C9 4F 8D
+ CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 4F 8D
+ D8 D9 DA DB 65 DC DD DE DF E0 E1 43 49 89 8F 8F
+ E2 E3 E4 E5 E6 E7 E8 E9 AE AE EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 47 5F 45 61 5B 6E 70 70 6C 85 87
+ F0 83 A0 A2 9E 72 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8
+ 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC
+ 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8
+ 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8
+ 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02
+ 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4
+ F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7
+
diff --git a/sql/share/charsets/macromancsas.conf b/sql/share/charsets/macromancsas.conf
new file mode 100644
index 00000000000..1f67148680d
--- /dev/null
+++ b/sql/share/charsets/macromancsas.conf
@@ -0,0 +1,97 @@
+#
+# Mac OS Roman, accent sensitive, case sensitive
+#
+# Sort order: Dutch, English, French, German (Duden),
+# Italian, Latin, Pogtuguese, Spanish
+#
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 10
+ 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
+ 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02
+ 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02
+ 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00
+ 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01
+ 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 8A 8C 8D 8E 96 9A 9F 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD BE BF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA 88 8B 9B CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99
+ F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 E7 CB E5 80 CC 81 82 83 E9
+ E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD AE AF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D9 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81
+ 91 93 95 97 9A 9C A6 A8 AA AC B0 B2 B3 B4 B5 B6
+ B7 42 52 54 58 5A 64 67 69 6B 76 78 7A 7C 7E 82
+ 92 94 96 98 9B 9D A7 A9 AB AD B1 B8 B9 BA BB BC
+ 4B 4D 55 5D 7F 8B A4 46 44 48 4C 4A 4E 56 5E 5C
+ 60 62 6F 6D 71 73 80 86 84 88 8C 8A A1 9F A3 A5
+ BD BE BF C0 C1 C2 C3 99 C4 C5 C6 C7 C8 C9 4F 8D
+ CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 50 8E
+ D8 D9 DA DB 65 DC DD DE DF E0 E1 43 49 89 8F 90
+ E2 E3 E4 E5 E6 E7 E8 E9 AF AE EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 47 5F 45 61 5B 6E 70 72 6C 85 87
+ F0 83 A0 A2 9E 74 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8
+ 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC
+ 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8
+ 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8
+ 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153
+ 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02
+ 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4
+ F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7
+
diff --git a/sql/share/charsets/pclatin2.conf b/sql/share/charsets/pclatin2.conf
new file mode 100644
index 00000000000..dea8d085595
--- /dev/null
+++ b/sql/share/charsets/pclatin2.conf
@@ -0,0 +1,91 @@
+# ctype array (must be 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 00
+ 01 02 02 02 02 02 02 02 02 02 01 02 02 01 01 01
+ 01 01 02 02 02 01 02 01 02 01 01 01 02 01 00 02
+ 02 02 02 02 01 02 01 02 01 02 00 02 01 01 00 00
+ 00 00 00 00 00 01 01 01 02 00 00 00 00 01 02 00
+ 00 00 00 00 00 00 01 02 00 00 00 00 00 00 00 00
+ 02 01 01 01 02 01 01 01 02 00 00 00 00 01 01 00
+ 01 02 01 01 02 02 01 02 01 01 02 01 02 01 02 00
+ 00 00 00 00 00 00 00 00 00 00 00 02 01 02 00 48
+
+# to_lower array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 87 81 82 83 84 85 86 87 88 89 8B 8B 8C AB 84 86
+ 82 92 92 93 94 96 96 98 98 94 81 9C 9C 88 9E 9F
+ A0 A1 A2 A3 A5 A5 A7 A7 A9 A9 AA AB 9F B8 AE AF
+ B0 B1 B2 B3 B4 A0 83 D8 B8 B9 BA BB BC BE BE BF
+ C0 C1 C2 C3 C4 C5 C7 C7 C8 C9 CA CB CC CD CE CF
+ D0 D0 D4 89 D4 E5 A1 8C D8 D9 DA DB DC EE 85 DF
+ A2 E1 93 E4 E4 E5 E7 E7 EA A3 E8 FB EC EC EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# to_upper array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 9A 90 B6 8E DE 8F 80 9D D3 8A 8A D7 8D 8E 8F
+ 90 91 91 E2 99 95 95 97 97 99 9A 9B 9B 9D 9E AC
+ B5 D6 E0 E9 A4 A4 A6 A6 A8 A8 AA 8D AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 AD B9 BA BB BC BE BD BF
+ C0 C1 C2 C3 C4 C5 C6 C6 C8 C9 CA CB CC CD CE CF
+ D1 D1 D2 D3 D2 D5 D6 D7 B7 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E3 D5 E6 E6 E8 E9 E8 EB ED ED DD EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA EB FC FC FE FF
+
+# sort_order array (must be 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 47 48 4C 4F 54 55 56 57 5A 5B 5C 5E 5F 62
+ 67 68 69 6C 71 74 75 76 77 78 7B 90 91 92 93 94
+ 95 41 47 48 4C 4F 54 55 56 57 5A 5B 5C 5E 5F 62
+ 67 68 69 6C 71 74 75 76 77 78 7B 96 97 98 99 9A
+ 48 74 4F 41 41 74 48 48 5C 4F 62 62 57 7B 41 48
+ 4F 5C 5C 62 62 5C 5C 6C 6C 62 74 71 71 5C 9E 48
+ 41 57 62 74 41 41 7B 7B 4F 4F AA 7B 48 6C AE AF
+ B0 B1 B2 B3 B4 41 41 4F 6C B5 BA BB BC 7B 7B BF
+ C0 C1 C2 C3 C4 C5 41 41 C8 C9 CA CB CC CD CE CF
+ 4C 4C 4C 4F 4C 60 57 57 4F D9 DA DB DC 71 74 DF
+ 62 70 62 60 60 60 6C 6C 69 74 69 74 78 78 71 EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA 74 69 69 FE FF
+
+# Unicode mappping (must be 256 elements)
+ 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+ 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+ 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+ 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+ 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+ 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+ 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+ 00C7 00FC 00E9 00E2 00E4 016F 0107 00E7 0142 00EB 0150 0151 00EE 0179 00C4 0106
+ 00C9 0139 013A 00F4 00F6 013D 013E 015A 015B 00D6 00DC 0164 0165 0141 00D7 010D
+ 00E1 00ED 00F3 00FA 0104 0105 017D 017E 0118 0119 00AC 017A 010C 015F 00AB 00BB
+ 2591 2592 2593 2502 2524 00C1 00C2 011A 015E 2563 2551 2557 255D 017B 017C 2510
+ 2514 2534 252C 251C 2500 253C 0102 0103 255A 2554 2569 2566 2560 2550 256C 00A4
+ 0111 0110 010E 00CB 010F 0147 00CD 00CE 011B 2518 250C 2588 2584 0162 016E 2580
+ 00D3 00DF 00D4 0143 0144 0148 0160 0161 0154 00DA 0155 0170 00FD 00DD 0163 00B4
+ 00AD 02DD 02DB 02C7 02D8 00A7 00F7 00B8 00B0 00A8 02D9 0171 0158 0159 25A0 00A0
+
diff --git a/sql/share/charsets/swe7.conf b/sql/share/charsets/swe7.conf
index d2de48b4d1c..49938800f39 100644
--- a/sql/share/charsets/swe7.conf
+++ b/sql/share/charsets/swe7.conf
@@ -72,3 +72,21 @@
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+00C9 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 00C4 00D6 00C5 00DC 005F
+00E9 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 00E4 00F6 00E5 00FC 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
diff --git a/sql/share/charsets/usa7.conf b/sql/share/charsets/usa7.conf
index b9e7a44c894..380fc9b5d8b 100644
--- a/sql/share/charsets/usa7.conf
+++ b/sql/share/charsets/usa7.conf
@@ -72,3 +72,21 @@
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
diff --git a/sql/share/charsets/win1250.conf b/sql/share/charsets/win1250.conf
index 31d253d7381..0a5b5074bde 100644
--- a/sql/share/charsets/win1250.conf
+++ b/sql/share/charsets/win1250.conf
@@ -72,3 +72,21 @@
47 53 53 55 55 55 55 D7 58 5C 5C 5C 5C 60 5B 59
58 41 41 41 41 50 45 43 44 49 49 49 49 4D 4D 46
47 53 53 55 55 55 55 F7 58 5C 5C 5C 5C 60 5B FF
+
+# Unicode mapping table (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0160 2039 015A 0164 017D 0179
+0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0161 203A 015B 0165 017E 017A
+00A0 02C7 02D8 0141 00A4 0104 00A6 00A7 00A8 00A9 015E 00AB 00AC 00AD 00AE 017B
+00B0 00B1 02DB 0142 00B4 00B5 00B6 00B7 00B8 0105 015F 00BB 013D 02DD 013E 017C
+0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E
+0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF
+0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F
+0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9
diff --git a/sql/share/charsets/win1251.conf b/sql/share/charsets/win1251.conf
index a5ccc3190ad..2164cb36b9e 100644
--- a/sql/share/charsets/win1251.conf
+++ b/sql/share/charsets/win1251.conf
@@ -80,3 +80,21 @@
D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0
C0 C1 C2 C3 C4 C5 C7 C8 C9 CA CB CC CD CE CF D0
D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F
+0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F
+00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407
+00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457
+0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
diff --git a/sql/share/charsets/win1251ukr.conf b/sql/share/charsets/win1251ukr.conf
index e693958910e..da08e4c7d6f 100644
--- a/sql/share/charsets/win1251ukr.conf
+++ b/sql/share/charsets/win1251ukr.conf
@@ -75,3 +75,21 @@
95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4
80 81 82 83 85 86 89 8A 8B 8E 8F 90 91 92 93 94
95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4
+
+# Unicode mapping (256 elements)
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F
+0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F
+00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407
+00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457
+0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F
+0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F
+0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F
+0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index b69484cb38b..1b1f90abfb3 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -206,7 +206,7 @@
"Nezn-Bámá systémová promìnná '%-.64s'",
"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena",
"Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -247,3 +247,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index ccbc53a0d29..65eb190b48b 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -241,3 +241,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 7fce0c7b4f9..965221dd83f 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -249,3 +249,11 @@
"Foutieve toepassing/plaatsing van '%s'",
"Deze versie van MySQL ondersteunt nog geen '%s'",
"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",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 105cf90ca7d..7472fe14365 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -197,7 +197,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -238,3 +238,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index d0a30b2f434..3f2745a8809 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -243,3 +243,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index ab1761ca042..f1df0c0c2f2 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -238,3 +238,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index a99aea38563..bd51de5a257 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -241,3 +241,11 @@
"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 return more than 1 field",
+"Subselect return more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 554176e340b..915b4e9f64b 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -197,7 +197,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -238,3 +238,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 32333ce4439..aa8567dac87 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -199,7 +199,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -240,3 +240,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 4dd7b02de4e..20430757590 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -238,3 +238,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 663676e0cf3..2f3c61c1fe1 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -199,7 +199,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -240,3 +240,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index da1ee97f6b6..277e53895c3 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -197,7 +197,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -238,3 +238,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index bc334ace9f1..4c3a12d6557 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -199,7 +199,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -240,3 +240,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index e7f54549462..46bf84c409e 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -199,7 +199,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -240,3 +240,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 0e92bf2f9b8..e4d9832725d 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -201,7 +201,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -242,3 +242,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 6f4f86f9024..1c5adc96560 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -238,3 +238,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index b888a2bc8cd..313af2e5f14 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -201,7 +201,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -242,3 +242,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 0329f760e38..3b636aacae7 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -241,3 +241,11 @@
"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",
+"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÇÏ ÐÏÌÑ",
+"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
new file mode 100644
index 00000000000..0ee69010aca
--- /dev/null
+++ b/sql/share/serbian/errmsg.txt
@@ -0,0 +1,244 @@
+/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB
+ This file is public domain and comes with NO WARRANTY of any kind */
+
+/* Serbian Translation, version 1.0:
+ Copyright 2002 Vladimir Kraljevic, vladimir_kraljevic@yahoo.com
+ This file is public domain and comes with NO WARRANTY of any kind.
+ Charset: cp1250
+*/
+
+"hashchk",
+"isamchk",
+"NE",
+"DA",
+"Ne mogu da kreiram file '%-.64s' (errno: %d)",
+"Ne mogu da kreiram tabelu '%-.64s' (errno: %d)",
+"Ne mogu da kreiram bazu '%-.64s'. (errno: %d)",
+"Ne mogu da kreiram bazu '%-.64s'. Baza veæ postoji.",
+"Ne mogu da izbrišem bazu '%-.64s'. Baza ne postoji.",
+"Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)",
+"Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.64s', errno: %d)",
+"Greška pri brisanju '%-.64s' (errno: %d)",
+"Ne mogu da proèitam slog iz sistemske tabele",
+"Ne mogu da dobijem stanje file-a '%-.64s' (errno: %d)",
+"Ne mogu da dobijem trenutni direktorijum (errno: %d)",
+"Ne mogu da zakljuèam file (errno: %d)",
+"Ne mogu da otvorim file: '%-.64s'. (errno: %d)",
+"Ne mogu da pronaðem file: '%-.64s' (errno: %d)",
+"Ne mogu da proèitam direktorijum '%-.64s' (errno: %d)",
+"Ne mogu da promenim direktorijum na '%-.64s' (errno: %d)",
+"Slog je promenjen od zadnjeg èitanja tabele '%-.64s'",
+"Disk je pun (%s). Èekam nekoga da doðe i oslobodi nešto mesta....",
+"Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.64s'",
+"Greška pri zatvaranju '%-.64s' (errno: %d)",
+"Greška pri èitanju file-a '%-.64s' (errno: %d)",
+"Greška pri promeni imena '%-.64s' na '%-.64s' (errno: %d)",
+"Greška pri upisu '%-.64s' (errno: %d)",
+"'%-.64s' je zakljuèan za upis",
+"Sortiranje je prekinuto",
+"View '%-.64s' ne postoji za '%-.64s'",
+"Handler tabela je vratio grešku %d",
+"Handler tabela za '%-.64s' nema ovu opciju",
+"Ne mogu da pronaðem slog u '%-.64s'",
+"Pogrešna informacija u file-u: '%-.64s'",
+"Pogrešan key file za tabelu: '%-.64s'. Probajte da ga ispravite",
+"Zastareo key file za tabelu '%-.64s'; Ispravite ga",
+"Tabelu '%-.64s' je dozvoljeno samo èitati",
+"Nema memorije. Restartujte MySQL server i probajte ponovo (potrebno je %d byte-ova)",
+"Nema memorije za sortiranje. Poveæajte velièinu sort buffer-a MySQL server-u",
+"Neoèekivani kraj pri èitanju file-a '%-.64s' (errno: %d)",
+"Previše konekcija",
+"Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)",
+"Ne mogu da dobijem ime host-a za vašu IP adresu",
+"Loš poèetak komunikacije (handshake)",
+"Pristup je zabranjen korisniku '%-.32s@%-.64s' za bazu '%-.64s'",
+"Pristup je zabranjen korisniku '%-.32s@%-.64s' (koristi lozinku: '%s')",
+"Ni jedna baza nije selektovana",
+"Nepoznata komanda",
+"Kolona '%-.64s' ne može biti NULL",
+"Nepoznata baza '%-.64s'",
+"Tabela '%-.64s' veæ postoji",
+"Nepoznata tabela '%-.64s'",
+"Kolona '%-.64s' u %-.64s nije jedinstvena u kontekstu",
+"Gašenje servera je u toku",
+"Nepoznata kolona '%-.64s' u '%-.64s'",
+"Entitet '%-.64s' nije naveden u komandi 'GROUP BY'",
+"Ne mogu da grupišem po '%-.64s'",
+"Izraz ima 'SUM' agregatnu funkciju i kolone u isto vreme",
+"Broj kolona ne odgovara broju vrednosti",
+"Ime '%-.100s' je predugaèko",
+"Duplirano ime kolone '%-.64s'",
+"Duplirano ime kljuèa '%-.64s'",
+"Dupliran unos '%-.64s' za kljuè '%d'",
+"Pogrešan naziv kolone za kolonu '%-.64s'",
+"'%s' u iskazu '%-.80s' na liniji %d",
+"Upit je bio prazan",
+"Tabela ili alias nisu bili jedinstveni: '%-.64s'",
+"Loša default vrednost za '%-.64s'",
+"Definisani višestruki primarni kljuèevi",
+"Navedeno je previše kljuèeva. Maksimum %d kljuèeva je dozvoljeno",
+"Navedeno je previše delova kljuèa. Maksimum %d delova je dozvoljeno",
+"Navedeni kljuè je predug. Maksimalna dužina kljuèa je %d",
+"Kljuèna kolona '%-.64s' ne postoji u tabeli",
+"BLOB kolona '%-.64s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi",
+"Previše podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje",
+"Pogrešna definicija tabele; U tabeli može postojati samo jedna 'AUTO' kolona i ona mora biti istovremeno definisana kao kolona kljuèa",
+"%s: Spreman za konekcije\n",
+"%s: Normalno gašenje\n",
+"%s: Dobio signal %d. Prekidam!\n",
+"%s: Gašenje završeno\n",
+"%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.32s'\n",
+"Ne mogu da kreiram IP socket",
+"Tabela '%-.64s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo",
+"Argument separatora polja nije ono što se oèekivalo. Proverite uputstvo MySQL server-a",
+"Ne možete koristiti fiksnu velièinu sloga kada imate BLOB polja. Molim koristite 'fields terminated by' opciju.",
+"File '%-.64s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa",
+"File '%-.80s' veæ postoji",
+"Slogova: %ld Izbrisano: %ld Preskoèeno: %ld Upozorenja: %ld",
+"Slogova: %ld Duplikata: %ld",
+"Pogrešan pod-kljuè dela kljuèa. Upotrebljeni deo kljuèa nije string, upotrebljena dužina je veæa od dela kljuèa ili handler tabela ne podržava jedinstvene pod-kljuèeve",
+"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",
+"Nepoznat thread identifikator: %lu",
+"Vi niste vlasnik thread-a %lu",
+"Nema upotrebljenih tabela",
+"Previše string-ova za kolonu '%-.64s' i komandu 'SET'",
+"Ne mogu da generišem jedinstveno ime log-file-a: '%-.64s.(1-999)'\n",
+"Tabela '%-.64s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati",
+"Tabela '%-.64s' nije bila zakljuèana komandom 'LOCK TABLES'",
+"BLOB kolona '%-.64s' ne može imati default vrednost",
+"Pogrešno ime baze '%-.100s'",
+"Pogrešno ime tabele '%-.100s'",
+"Komanda 'SELECT' æe ispitati previše slogova i potrošiti previše vremena. Proverite vaš 'WHERE' filter i upotrebite 'SET OPTION SQL_BIG_SELECTS=1' ako želite baš ovakvu komandu",
+"Nepoznata greška",
+"Nepoznata procedura '%-.64s'",
+"Pogrešan broj parametara za proceduru '%-.64s'",
+"Pogrešni parametri prosleðeni proceduri '%-.64s'",
+"Nepoznata tabela '%-.64s' u '%-.32s'",
+"Kolona '%-.64s' je navedena dva puta",
+"Pogrešna upotreba 'GROUP' funkcije",
+"Tabela '%-.64s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a",
+"Tabela mora imati najmanje jednu kolonu",
+"Tabela '%-.64s' je popunjena do kraja",
+"Nepoznati karakter-set: '%-.64s'",
+"Previše tabela. MySQL može upotrebiti maksimum %d tabela pri 'JOIN' operaciji",
+"Previše kolona",
+"Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %d. Trebali bi da promenite tip nekih polja u BLOB",
+"Prepisivanje thread stack-a: Upotrebljeno: %ld od %ld stack memorije. Upotrebite 'mysqld -O thread_stack=#' da navedete veæi stack ako je potrebno",
+"Unakrsna zavisnost pronaðena u komandi 'OUTER JOIN'. Istražite vaše 'ON' uslove",
+"Kolona '%-.64s' je upotrebljena kao 'UNIQUE' ili 'INDEX' ali nije definisana kao 'NOT NULL'",
+"Ne mogu da uèitam funkciju '%-.64s'",
+"Ne mogu da inicijalizujem funkciju '%-.64s'; %-.80s",
+"Ne postoje dozvoljene putanje do share-ovane biblioteke",
+"Funkcija '%-.64s' veæ postoji",
+"Ne mogu da otvorim share-ovanu biblioteku '%-.64s' (errno: %d %-.64s)",
+"Ne mogu da pronadjem funkciju '%-.64s' u biblioteci",
+"Funkcija '%-.64s' nije definisana",
+"Host '%-.64s' je blokiran zbog previše grešaka u konekciji. Možete ga odblokirati pomoæu komande 'mysqladmin flush-hosts'",
+"Host-u '%-.64s' nije dozvoljeno da se konektuje na ovaj MySQL server",
+"Vi koristite MySQL kao anonimni korisnik a anonimnim korisnicima nije dozvoljeno da menjaju lozinke",
+"Morate imati privilegije da možete da update-ujete odreðene tabele ako želite da menjate lozinke za druge korisnike",
+"Ne mogu da pronaðem odgovarajuæi slog u 'user' tabeli",
+"Odgovarajuæih slogova: %ld Promenjeno: %ld Upozorenja: %ld",
+"Ne mogu da kreiram novi thread (errno %d). Ako imate još slobodne memorije, trebali biste da pogledate u priruèniku da li je ovo specifièna greška vašeg operativnog sistema",
+"Broj kolona ne odgovara broju vrednosti u slogu %ld",
+"Ne mogu da ponovo otvorim tabelu '%-.64s'",
+"Pogrešna upotreba vrednosti NULL",
+"Funkcija regexp je vratila grešku '%-.64s'",
+"Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz",
+"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s'",
+"%-.16s komanda zabranjena za korisnika '%-.32s@%-.64s' za tabelu '%-.64s'",
+"%-.16s komanda zabranjena za korisnika '%-.32s@%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'",
+"Pogrešna 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruèniku koje vrednosti mogu biti upotrebljene.",
+"Argument 'host' ili 'korisnik' prosleðen komandi 'GRANT' je predugaèak",
+"Tabela '%-.64s.%-.64s' ne postoji",
+"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s' tabeli '%-.64s'",
+"Upotrebljena komanda nije dozvoljena sa ovom verzijom MySQL servera",
+"Imate grešku u vašoj SQL sintaksi",
+"Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.64s'",
+"Previše prolongiranih thread-ova je u upotrebi",
+"Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' (%-.64s)",
+"Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'",
+"Greška pri èitanju podataka sa pipe-a",
+"Greška pri izvršavanju funkcije fcntl()",
+"Primio sam mrežne pakete van reda",
+"Ne mogu da dekompresujem mrežne pakete",
+"Greška pri primanju mrežnih paketa",
+"Vremenski limit za èitanje mrežnih paketa je istekao",
+"Greška pri slanju mrežnih paketa",
+"Vremenski limit za slanje mrežnih paketa je istekao",
+"Rezultujuèi string je duži nego što to dozvoljava parametar servera 'max_allowed_packet'",
+"Iskorišteni tip tabele ne podržava kolone tipa 'BLOB' odnosno 'TEXT'",
+"Iskorišteni tip tabele ne podržava kolone tipa 'AUTO_INCREMENT'",
+"Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.64s', zbog toga što je zakljuèana komandom 'LOCK TABLES'",
+"Pogrešno ime kolone '%-.100s'",
+"Handler tabele ne može da indeksira kolonu '%-.64s'",
+"Tabele iskorištene u 'MERGE' tabeli nisu definisane na isti naèin",
+"Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.64s'",
+"BLOB kolona '%-.64s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa",
+"Svi delovi primarnog kljuèa moraju biti razlièiti od NULL; Ako Vam ipak treba NULL vrednost u kljuèu, upotrebite 'UNIQUE'",
+"Rezultat je saèinjen od više slogova",
+"Ovaj tip tabele zahteva da imate definisan primarni kljuè",
+"Ova verzija MySQL servera nije kompajlirana sa podrškom za RAID ureðaje",
+"Vi koristite safe update mod servera, a probali ste da promenite podatke bez 'WHERE' komande koja koristi kolonu kljuèa",
+"Kljuè '%-.64s' ne postoji u tabeli '%-.64s'",
+"Ne mogu da otvorim tabelu",
+"Handler za ovu tabelu ne dozvoljava 'check' odnosno 'repair' komande",
+"Nije Vam dozvoljeno da izvršite ovu komandu u transakciji",
+"Greška %d za vreme izvršavanja komande 'COMMIT'",
+"Greška %d za vreme izvršavanja komande 'ROLLBACK'",
+"Greška %d za vreme izvršavanja komande 'FLUSH_LOGS'",
+"Greška %d za vreme izvršavanja komande 'CHECKPOINT'",
+"Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: `%-.64s' (%-.64s)",
+"Handler tabele ne podržava binarni dump tabele",
+"Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'",
+"Izgradnja indeksa dump-ovane tabele '%-.64s' nije uspela",
+"Greška iz glavnog servera '%-.64s' u klasteru",
+"Greška u primanju mrežnih paketa sa glavnog servera u klasteru",
+"Greška u slanju mrežnih paketa na glavni server u klasteru",
+"Ne mogu da pronaðem 'FULLTEXT' indeks koli odgovara listi kolona",
+"Ne mogu da izvršim datu komandu zbog toga što su tabele zakljuèane ili je transakcija u toku",
+"Nepoznata sistemska promenljiva '%-.64'",
+"Tabela '%-.64s' je markirana kao ošteæena i trebala bi biti popravljena",
+"Tabela '%-.64s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela",
+"Upozorenje: Neke izmenjene tabele ne podržavaju komandu 'ROLLBACK'",
+"Transakcija sa više stavki zahtevala je više od 'max_binlog_cache_size' bajtova skladišnog prostora. Uveæajte ovu promenljivu servera i pokušajte ponovo',
+"Ova operacija ne može biti izvršena dok je aktivan podreðeni server. Zadajte prvo komandu 'SLAVE STOP' da zaustavite podreðeni server.",
+"Ova operacija zahteva da je aktivan podreðeni server. Konfigurišite prvo podreðeni server i onda izvršite komandu 'SLAVE START'",
+"Server nije konfigurisan kao podreðeni server, ispravite konfiguracioni file ili na njemu izvršite komandu 'CHANGE MASTER TO'",
+"Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'",
+"Nisam mogao da startujem thread za podreðeni server, proverite sistemske resurse",
+"Korisnik %-.64s veæ ima više aktivnih konekcija nego što je to odreðeno 'max_user_connections' promenljivom",
+"Možete upotrebiti samo konstantan iskaz sa komandom 'SET'",
+"Vremenski limit za zakljuèavanje tabele je istekao; Probajte da ponovo startujete transakciju",
+"Broj totalnih zakljuèavanja tabele premašuje velièinu tabele zakljuèavanja",
+"Zakljuèavanja izmena ne mogu biti realizovana sve dok traje 'READ UNCOMMITTED' transakcija",
+"Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka",
+"Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka",
+"Pogrešni argumenti prosleðeni na %s",
+"Korisniku %-.32s@%-.64s nije dozvoljeno da kreira nove korisnike",
+"Pogrešna definicija tabele; Sve 'MERGE' tabele moraju biti u istoj bazi podataka",
+"Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju",
+"Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse",
+"Ne mogu da dodam proveru spoljnog kljuèa",
+"Ne mogu da dodam slog: provera spoljnog kljuèa je neuspela",
+"Ne mogu da izbrišem roditeljski slog: provera spoljnog kljuèa je neuspela",
+"Greška pri povezivanju sa glavnim serverom u klasteru: %-.128s",
+"Greška pri izvršavanju upita na glavnom serveru u klasteru: %-.128s",
+"Greška pri izvršavanju komande %s: %-.128s",
+"Pogrešna upotreba %s i %s",
+"Upotrebljene 'SELECT' komande adresiraju razlièit broj kolona",
+"Ne mogu da izvršim upit zbog toga što imate zakljuèavanja èitanja podataka u konfliktu",
+"Mešanje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuèeno",
+"Opcija '%s' je upotrebljena dva puta u istom iskazu",
+"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",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 1dd696affb0..9f610a84bd9 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -205,7 +205,7 @@
"Unknown system variable '%-.64s'",
"Table '%-.64s' is marked as crashed and should be repaired",
"Table '%-.64s' is marked as crashed and last (automatic?) repair failed",
-"Warning: Some non-transactional changed tables couldn't be rolled back",
+"Some non-transactional changed tables couldn't be rolled back",
"Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again',
"This operation cannot be performed with a running slave, run SLAVE STOP first",
"This operation requires a running slave, configure slave and do SLAVE START",
@@ -246,3 +246,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index c91726a6557..ab4e3e93a25 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -239,3 +239,11 @@
"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",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 5b7ed499038..3d91522bf0f 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -197,7 +197,7 @@
"Okänd system variabel '%-.64s'",
"Tabell '%-.64s' är crashad och bör repareras med REPAIR TABLE",
"Tabell '%-.64s' är crashad och senast (automatiska?) reparation misslyckades",
-"Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK",
+"Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK",
"Transaktionen krävde mera än 'max_binlog_cache_size' minne. Utöka denna mysqld variabel och försök på nytt",
"Denna operation kan inte göras under replikering; Gör SLAVE STOP först",
"Denna operation kan endast göras under replikering; Konfigurera slaven och gör SLAVE START",
@@ -229,12 +229,20 @@
"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",
+"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",
+"Subselect returnerade mer än 1 fält",
+"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"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 6eeefa11ff2..d16a8e678d1 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -243,3 +243,11 @@
"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",
+"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÓÔÏ×ÂÅÃØ",
+"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÚÁÐÉÓ",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"ãÉËÌiÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ÐiÄÚÁÐÉÔ",
+"Converting column '%s' from %s to %s"
diff --git a/sql/slave.cc b/sql/slave.cc
index eb53e488856..f8acc592afa 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -56,7 +56,6 @@ static int events_till_disconnect = -1;
typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE;
-void skip_load_data_infile(NET* net);
static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev);
static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev);
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli);
@@ -78,10 +77,14 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi);
char* rewrite_db(char* db);
-/*
- Get a bit mask for which threads are running so that we later can
- restart these threads
-*/
+/*****************************************************************************
+
+ init_thread_mask()
+
+ Get a bit mask for which threads are running so that we can later restart
+ these threads.
+
+*****************************************************************************/
void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
{
@@ -96,7 +99,11 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
*mask = tmp_mask;
}
+/*****************************************************************************
+
+ lock_slave_threads()
+*****************************************************************************/
void lock_slave_threads(MASTER_INFO* mi)
{
//TODO: see if we can do this without dual mutex
@@ -104,6 +111,11 @@ void lock_slave_threads(MASTER_INFO* mi)
pthread_mutex_lock(&mi->rli.run_lock);
}
+/*****************************************************************************
+
+ unlock_slave_threads()
+
+*****************************************************************************/
void unlock_slave_threads(MASTER_INFO* mi)
{
//TODO: see if we can do this without dual mutex
@@ -111,7 +123,11 @@ void unlock_slave_threads(MASTER_INFO* mi)
pthread_mutex_unlock(&mi->run_lock);
}
+/*****************************************************************************
+ init_slave()
+
+*****************************************************************************/
int init_slave()
{
DBUG_ENTER("init_slave");
@@ -154,12 +170,21 @@ int init_slave()
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ free_table_ent()
+*****************************************************************************/
static void free_table_ent(TABLE_RULE_ENT* e)
{
my_free((gptr) e, MYF(0));
}
+/*****************************************************************************
+
+ get_table_key()
+
+*****************************************************************************/
static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
my_bool not_used __attribute__((unused)))
{
@@ -167,8 +192,10 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
return (byte*)e->db;
}
+/*****************************************************************************
+
+ init_relay_log_pos()
-/*
Open the given relay log
SYNOPSIS
@@ -195,8 +222,8 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
RETURN VALUES
0 ok
1 error. errmsg is set to point to the error message
-*/
+*****************************************************************************/
int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,
ulonglong pos, bool need_data_lock,
const char** errmsg)
@@ -277,9 +304,13 @@ err:
DBUG_RETURN ((*errmsg) ? 1 : 0);
}
+/*****************************************************************************
-/* called from get_options() in mysqld.cc on start-up */
+ init_slave_skip_errors()
+ called from get_options() in mysqld.cc on start-up
+
+*****************************************************************************/
void init_slave_skip_errors(const char* arg)
{
const char *p;
@@ -289,9 +320,9 @@ void init_slave_skip_errors(const char* arg)
exit(1);
}
use_slave_mask = 1;
- for (;isspace(*arg);++arg)
+ for (;my_isspace(system_charset_info,*arg);++arg)
/* empty */;
- if (!my_casecmp(arg,"all",3))
+ if (!my_strncasecmp(system_charset_info,arg,"all",3))
{
bitmap_set_all(&slave_error_mask);
return;
@@ -303,17 +334,18 @@ void init_slave_skip_errors(const char* arg)
break;
if (err_code < MAX_SLAVE_ERROR)
bitmap_set_bit(&slave_error_mask,(uint)err_code);
- while (!isdigit(*p) && *p)
+ while (!my_isdigit(system_charset_info,*p) && *p)
p++;
}
}
+/*****************************************************************************
-/*
- We assume we have a run lock on rli and that both slave thread
- are not running
-*/
+ purge_relay_logs()
+
+ Assumes to have a run lock on rli and that no slave thread are running.
+*****************************************************************************/
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
const char** errmsg)
{
@@ -358,6 +390,11 @@ err:
}
+/*****************************************************************************
+
+ terminate_slave_threads()
+
+*****************************************************************************/
int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
{
if (!mi->inited)
@@ -398,7 +435,11 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
DBUG_RETURN(0);
}
+/*****************************************************************************
+ terminate_slave_thread()
+
+*****************************************************************************/
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
pthread_mutex_t *cond_lock,
pthread_cond_t* term_cond,
@@ -443,6 +484,11 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
}
+/*****************************************************************************
+
+ start_slave_thread()
+
+*****************************************************************************/
int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
pthread_mutex_t *cond_lock,
pthread_cond_t *start_cond,
@@ -505,13 +551,15 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ start_slave_threads()
-/*
SLAVE_FORCE_ALL is not implemented here on purpose since it does not make
- sense to do that for starting a slave - we always care if it actually
+ sense to do that for starting a slave--we always care if it actually
started the threads that were not previously running
-*/
+*****************************************************************************/
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname, int thread_mask)
@@ -551,15 +599,24 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
DBUG_RETURN(error);
}
+/*****************************************************************************
+ init_table_rule_hash()
+
+*****************************************************************************/
void init_table_rule_hash(HASH* h, bool* h_inited)
{
- hash_init(h, TABLE_RULE_HASH_SIZE,0,0,
+ hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
(hash_get_key) get_table_key,
(hash_free_key) free_table_ent, 0);
*h_inited = 1;
}
+/*****************************************************************************
+
+ init_table_rule_array()
+
+*****************************************************************************/
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
{
my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
@@ -567,6 +624,11 @@ void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
*a_inited = 1;
}
+/*****************************************************************************
+
+ find_wild()
+
+*****************************************************************************/
static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
uint i;
@@ -576,14 +638,21 @@ 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(key, key_end, (const char*)e->db,
- (const char*)(e->db + e->key_len),'\\'))
+ if (!my_wildcmp(system_charset_info, key, key_end,
+ (const char*)e->db,
+ (const char*)(e->db + e->key_len),
+ '\\',wild_one,wild_many))
return e;
}
return 0;
}
+/*****************************************************************************
+
+ tables_ok()
+
+*****************************************************************************/
int tables_ok(THD* thd, TABLE_LIST* tables)
{
for (; tables; tables = tables->next)
@@ -620,7 +689,11 @@ int tables_ok(THD* thd, TABLE_LIST* tables)
return !do_table_inited && !wild_do_table_inited;
}
+/*****************************************************************************
+ add_table_rule()
+
+*****************************************************************************/
int add_table_rule(HASH* h, const char* table_spec)
{
const char* dot = strchr(table_spec, '.');
@@ -638,6 +711,11 @@ int add_table_rule(HASH* h, const char* table_spec)
return 0;
}
+/*****************************************************************************
+
+ add_wild_table_rule()
+
+*****************************************************************************/
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
{
const char* dot = strchr(table_spec, '.');
@@ -654,6 +732,11 @@ int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
return 0;
}
+/*****************************************************************************
+
+ free_string_array()
+
+*****************************************************************************/
static void free_string_array(DYNAMIC_ARRAY *a)
{
uint i;
@@ -666,8 +749,12 @@ static void free_string_array(DYNAMIC_ARRAY *a)
delete_dynamic(a);
}
-#ifdef NOT_USED_YET
+/*****************************************************************************
+ end_slave_on_walk()
+
+*****************************************************************************/
+#ifdef NOT_USED_YET
static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
{
end_master_info(mi);
@@ -675,6 +762,11 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
}
#endif
+/*****************************************************************************
+
+ end_slave()
+
+*****************************************************************************/
void end_slave()
{
/*
@@ -694,7 +786,11 @@ void end_slave()
free_string_array(&replicate_wild_ignore_table);
}
+/*****************************************************************************
+
+ io_slave_killed()
+*****************************************************************************/
static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
{
DBUG_ASSERT(mi->io_thd == thd);
@@ -702,7 +798,11 @@ static bool io_slave_killed(THD* thd, MASTER_INFO* mi)
return mi->abort_slave || abort_loop || thd->killed;
}
+/*****************************************************************************
+ sql_slave_killed()
+
+*****************************************************************************/
static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
{
DBUG_ASSERT(rli->sql_thd == thd);
@@ -710,7 +810,11 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
return rli->abort_slave || abort_loop || thd->killed;
}
+/*****************************************************************************
+
+ slave_print_error()
+*****************************************************************************/
void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
{
va_list args;
@@ -722,16 +826,36 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
rli->last_slave_errno = err_code;
}
+/*****************************************************************************
+
+ skip_load_data_infile()
+
+ This is used to tell a 3.23 master to break send_file()
+
+*****************************************************************************/
+void skip_load_data_infile(NET *net)
+{
+ (void)net_request_file(net, "/dev/null");
+ (void)my_net_read(net); // discard response
+ (void)net_write_command(net, 0, "", 0, "", 0); // Send ok
+}
+
+/*****************************************************************************
+
+ net_request_file()
-void skip_load_data_infile(NET* net)
+*****************************************************************************/
+bool net_request_file(NET* net, const char* fname)
{
- (void)my_net_write(net, "\xfb/dev/null", 10);
- (void)net_flush(net);
- (void)my_net_read(net); // discard response
- send_ok(net); // the master expects it
+ DBUG_ENTER("net_request_file");
+ DBUG_RETURN(net_write_command(net, 251, fname, strlen(fname), "", 0));
}
+/*****************************************************************************
+ rewrite_db()
+
+*****************************************************************************/
char* rewrite_db(char* db)
{
if (replicate_rewrite_db.is_empty() || !db)
@@ -747,7 +871,11 @@ char* rewrite_db(char* db)
return db;
}
+/*****************************************************************************
+
+ db_ok()
+*****************************************************************************/
int db_ok(const char* db, I_List<i_string> &do_list,
I_List<i_string> &ignore_list )
{
@@ -787,7 +915,11 @@ int db_ok(const char* db, I_List<i_string> &do_list,
}
}
+/*****************************************************************************
+ init_strvar_from_file()
+
+*****************************************************************************/
static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
@@ -816,7 +948,11 @@ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
return 1;
}
+/*****************************************************************************
+
+ init_intvar_from_file()
+*****************************************************************************/
static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
{
char buf[32];
@@ -834,7 +970,11 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
return 1;
}
+/*****************************************************************************
+
+ check_master_version()
+*****************************************************************************/
static int check_master_version(MYSQL* mysql, MASTER_INFO* mi)
{
const char* errmsg= 0;
@@ -860,7 +1000,11 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi)
return 0;
}
+/*****************************************************************************
+ create_table_from_dump()
+
+*****************************************************************************/
static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name)
{
@@ -874,13 +1018,13 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
if (packet_len == packet_error)
{
- send_error(&thd->net, ER_MASTER_NET_READ);
+ send_error(thd, ER_MASTER_NET_READ);
return 1;
}
if (net->read_pos[0] == 255) // error from master
{
net->read_pos[packet_len] = 0;
- net_printf(&thd->net, ER_MASTER, net->read_pos + 3);
+ net_printf(thd, ER_MASTER, net->read_pos + 3);
return 1;
}
thd->command = COM_TABLE_DUMP;
@@ -888,7 +1032,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
if (!thd->query)
{
sql_print_error("create_table_from_dump: out of memory");
- net_printf(&thd->net, ER_GET_ERRNO, "Out of memory");
+ net_printf(thd, ER_GET_ERRNO, "Out of memory");
return 1;
}
memcpy(thd->query, net->read_pos, packet_len);
@@ -918,7 +1062,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
thd->proc_info = "Opening master dump table";
if (!open_ltable(thd, &tables, TL_WRITE))
{
- send_error(&thd->net,0,0); // Send error from open_ltable
+ send_error(thd,0,0); // Send error from open_ltable
sql_print_error("create_table_from_dump: could not open created table");
goto err;
}
@@ -927,7 +1071,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
thd->proc_info = "Reading master dump table data";
if (file->net_read_dump(net))
{
- net_printf(&thd->net, ER_MASTER_NET_READ);
+ net_printf(thd, ER_MASTER_NET_READ);
sql_print_error("create_table_from_dump::failed in\
handler::net_read_dump()");
goto err;
@@ -946,7 +1090,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
error=file->repair(thd,&check_opt) != 0;
thd->net.vio = save_vio;
if (error)
- net_printf(&thd->net, ER_INDEX_REBUILD,tables.table->real_name);
+ net_printf(thd, ER_INDEX_REBUILD,tables.table->real_name);
err:
close_thread_tables(thd);
@@ -954,6 +1098,11 @@ err:
return error;
}
+/*****************************************************************************
+
+ fetch_master_table()
+
+*****************************************************************************/
int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
MASTER_INFO *mi, MYSQL *mysql)
{
@@ -968,12 +1117,12 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
{
if (!(mysql = mc_mysql_init(NULL)))
{
- send_error(&thd->net); // EOM
+ send_error(thd); // EOM
DBUG_RETURN(1);
}
if (connect_to_master(thd, mysql, mi))
{
- net_printf(&thd->net, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql));
+ net_printf(thd, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql));
mc_mysql_close(mysql);
DBUG_RETURN(1);
}
@@ -997,11 +1146,14 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
if (!called_connected)
mc_mysql_close(mysql);
if (errmsg && thd->net.vio)
- send_error(&thd->net, error, errmsg);
+ send_error(thd, error, errmsg);
DBUG_RETURN(test(error)); // Return 1 on error
}
+/*****************************************************************************
+ end_master_info()
+*****************************************************************************/
void end_master_info(MASTER_INFO* mi)
{
DBUG_ENTER("end_master_info");
@@ -1020,7 +1172,11 @@ void end_master_info(MASTER_INFO* mi)
DBUG_VOID_RETURN;
}
+/*****************************************************************************
+
+ init_relay_log_info()
+*****************************************************************************/
int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
{
char fname[FN_REFLEN+128];
@@ -1154,7 +1310,11 @@ err:
DBUG_RETURN(1);
}
+/*****************************************************************************
+ add_relay_log()
+
+*****************************************************************************/
static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo)
{
MY_STAT s;
@@ -1173,7 +1333,11 @@ static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo)
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ wait_for_relay_log_space()
+*****************************************************************************/
static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
{
bool slave_killed=0;
@@ -1182,9 +1346,11 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
THD* thd = mi->io_thd;
DBUG_ENTER("wait_for_relay_log_space");
+
pthread_mutex_lock(&rli->log_space_lock);
save_proc_info = thd->proc_info;
thd->proc_info = "Waiting for relay log space to free";
+
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)))
{
@@ -1195,7 +1361,11 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
DBUG_RETURN(slave_killed);
}
+/*****************************************************************************
+ count_relay_log_space()
+
+*****************************************************************************/
static int count_relay_log_space(RELAY_LOG_INFO* rli)
{
LOG_INFO linfo;
@@ -1214,7 +1384,11 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli)
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ init_master_info()
+*****************************************************************************/
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
bool abort_if_no_master_info_file)
@@ -1332,7 +1506,11 @@ err:
DBUG_RETURN(1);
}
+/*****************************************************************************
+ register_slave_on_master()
+
+*****************************************************************************/
int register_slave_on_master(MYSQL* mysql)
{
String packet;
@@ -1374,6 +1552,11 @@ int register_slave_on_master(MYSQL* mysql)
return 0;
}
+/*****************************************************************************
+
+ show_master_info()
+
+*****************************************************************************/
int show_master_info(THD* thd, MASTER_INFO* mi)
{
// TODO: fix this for multi-master
@@ -1437,11 +1620,15 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ flush_master_info()
+*****************************************************************************/
bool flush_master_info(MASTER_INFO* mi)
{
IO_CACHE* file = &mi->file;
@@ -1459,7 +1646,11 @@ bool flush_master_info(MASTER_INFO* mi)
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ st_relay_log_info::wait_for_pos()
+*****************************************************************************/
int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
ulonglong log_pos)
{
@@ -1480,7 +1671,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
mi->slave_running)
{
bool pos_reached;
- int cmp_result= 0;
+ int different_file= 0;
DBUG_ASSERT(*master_log_name || master_log_pos == 0);
if (*master_log_name)
{
@@ -1492,11 +1683,11 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
mysqlbin.1000
*/
char *basename= master_log_name + dirname_length(master_log_name);
- cmp_result = strncmp(basename, log_name->ptr(),
+ different_file = strncmp(basename, log_name->ptr(),
log_name->length());
}
- pos_reached = ((!cmp_result && master_log_pos >= log_pos) ||
- cmp_result > 0);
+ pos_reached = ((!different_file && master_log_pos >= log_pos) ||
+ different_file > 0);
if (pos_reached || thd->killed)
break;
@@ -1517,7 +1708,11 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
-1 : event_count);
}
+/*****************************************************************************
+ init_slave_thread()
+
+*****************************************************************************/
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{
DBUG_ENTER("init_slave_thread");
@@ -1560,7 +1755,11 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ safe_sleep()
+*****************************************************************************/
static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
void* thread_killed_arg)
{
@@ -1589,7 +1788,11 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed,
return 0;
}
+/*****************************************************************************
+ request_dump()
+
+*****************************************************************************/
static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
bool *suppress_warnings)
{
@@ -1624,7 +1827,11 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi,
DBUG_RETURN(0);
}
+/*****************************************************************************
+
+ request_table_dump()
+*****************************************************************************/
static int request_table_dump(MYSQL* mysql, const char* db, const char* table)
{
char buf[1024];
@@ -1654,8 +1861,11 @@ command");
}
-/*
- read one event from the master
+/*****************************************************************************
+
+ read_event()
+
+ Read one event from the master
SYNOPSIS
read_event()
@@ -1670,8 +1880,7 @@ command");
'packet_error' Error
number Length of packet
-*/
-
+*****************************************************************************/
static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
{
ulong len;
@@ -1720,7 +1929,11 @@ server_errno=%d)",
return len - 1;
}
+/*****************************************************************************
+ check_expected_error()
+
+*****************************************************************************/
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
{
switch (expected_error) {
@@ -1742,7 +1955,11 @@ point. If you are sure that your master is ok, run this query manually on the\
}
}
+/*****************************************************************************
+
+ exec_relay_log_event()
+*****************************************************************************/
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
DBUG_ASSERT(rli->sql_thd==thd);
@@ -1807,8 +2024,10 @@ This may also be a network problem, or just a bug in the master or slave code.\
}
}
+/*****************************************************************************
+ Slave I/O Thread entry point
+*****************************************************************************/
-/* slave I/O thread */
extern "C" pthread_handler_decl(handle_slave_io,arg)
{
THD *thd; // needs to be first for thread_stack
@@ -2077,8 +2296,9 @@ err:
DBUG_RETURN(0); // Can't return anything here
}
-
-/* slave SQL logic thread */
+/*****************************************************************************
+ Slave SQL Thread entry point
+*****************************************************************************/
extern "C" pthread_handler_decl(handle_slave_sql,arg)
{
@@ -2215,13 +2435,18 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_RETURN(0); // Can't return anything here
}
+/*****************************************************************************
+
+ process_io_create_file()
+
+*****************************************************************************/
static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
{
int error = 1;
ulong num_bytes;
bool cev_not_written;
- THD* thd;
- NET* net = &mi->mysql->net;
+ THD *thd = mi->io_thd;
+ NET *net = &mi->mysql->net;
DBUG_ENTER("process_io_create_file");
if (unlikely(!cev->is_valid()))
@@ -2235,7 +2460,6 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
DBUG_RETURN(0);
}
DBUG_ASSERT(cev->inited_from_old);
- thd = mi->io_thd;
thd->file_id = cev->file_id = mi->file_id++;
thd->server_id = cev->server_id;
cev_not_written = 1;
@@ -2264,7 +2488,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev)
}
if (unlikely(!num_bytes)) /* eof */
{
- send_ok(net); /* 3.23 master wants it */
+ net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */
Execute_load_log_event xev(thd,0);
xev.log_pos = mi->master_log_pos;
if (unlikely(mi->rli.relay_log.append(&xev)))
@@ -2310,7 +2534,10 @@ err:
DBUG_RETURN(error);
}
-/*
+/*****************************************************************************
+
+ process_io_rotate()
+
Start using a new binary log on the master
SYNOPSIS
@@ -2328,8 +2555,8 @@ err:
RETURN VALUES
0 ok
1 Log event is illegal
-*/
+*****************************************************************************/
static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
{
int return_val= 1;
@@ -2360,12 +2587,15 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
DBUG_RETURN(0);
}
-/*
+/*****************************************************************************
+
+ queue_old_event()
+
TODO:
Test this code before release - it has to be tested on a separate
setup with 3.23 master
-*/
+*****************************************************************************/
static int queue_old_event(MASTER_INFO *mi, const char *buf,
ulong event_len)
{
@@ -2453,11 +2683,14 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf,
DBUG_RETURN(0);
}
-/*
+/*****************************************************************************
+
+ queue_event()
+
TODO: verify the issue with stop events, see if we need them at all
in the relay log
-*/
+*****************************************************************************/
int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
{
int error= 0;
@@ -2510,7 +2743,11 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len)
DBUG_RETURN(error);
}
+/*****************************************************************************
+ end_relay_log_info()
+
+*****************************************************************************/
void end_relay_log_info(RELAY_LOG_INFO* rli)
{
DBUG_ENTER("end_relay_log_info");
@@ -2535,18 +2772,26 @@ void end_relay_log_info(RELAY_LOG_INFO* rli)
DBUG_VOID_RETURN;
}
-/* try to connect until successful or slave killed */
+/*****************************************************************************
+
+ safe_connect()
+
+ Try to connect until successful or slave killed
+
+*****************************************************************************/
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
{
return connect_to_master(thd, mysql, mi, 0, 0);
}
+/*****************************************************************************
+
+ connect_to_master()
-/*
Try to connect until successful or slave killed or we have retried
master_retry_count times
-*/
+*****************************************************************************/
static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
bool reconnect, bool suppress_warnings)
{
@@ -2625,20 +2870,24 @@ replication resumed in log '%s' at position %s", mi->user,
DBUG_RETURN(slave_was_killed);
}
+/*****************************************************************************
+
+ safe_reconnect()
-/*
Try to connect until successful or slave killed or we have retried
master_retry_count times
-*/
+*****************************************************************************/
static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
bool suppress_warnings)
{
return connect_to_master(thd, mysql, mi, 1, suppress_warnings);
}
+/*****************************************************************************
+
+ flush_relay_log_info()
-/*
Store the file and position where the execute-slave thread are in the
relay log.
@@ -2665,8 +2914,8 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi,
RETURN VALUES
0 ok
1 write error
-*/
+*****************************************************************************/
bool flush_relay_log_info(RELAY_LOG_INFO* rli)
{
bool error=0;
@@ -2695,12 +2944,13 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
return error;
}
+/*****************************************************************************
-/*
- This function is called when we notice that the current "hot" log
- got rotated under our feet.
-*/
+ reopen_relay_log()
+
+ Called when we notice that the current "hot" log got rotated under our feet.
+*****************************************************************************/
static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
{
DBUG_ASSERT(rli->cur_log != &rli->cache_buf);
@@ -2715,7 +2965,11 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg)
DBUG_RETURN(cur_log);
}
+/*****************************************************************************
+
+ next_event()
+*****************************************************************************/
Log_event* next_event(RELAY_LOG_INFO* rli)
{
Log_event* ev;
diff --git a/sql/slave.h b/sql/slave.h
index 721fd8534a0..2c750e415bc 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -7,22 +7,28 @@
#define MAX_SLAVE_ERRMSG 1024
#define MAX_SLAVE_ERROR 2000
-/*
- The replication is accomplished by starting two threads - I/O
- thread, and SQL thread. I/O thread is associated with its
- MASTER_INFO struct, so MASTER_INFO can be viewed as I/O thread
- descriptor. SQL thread is associated with RELAY_LOG_INFO struct.
-
- I/O thread reads maintains a connection to the master, and reads log
- events from the master as they arrive, queueing them by writing them
- out into the temporary slave binary log (relay log). The SQL thread,
- in turn, reads the slave binary log executing each event.
-
- Relay log is needed to be able to handle situations when there is a large
- backlog of unprocessed events from the master (eg. one particular update
- takes a day to finish), and to be able to restart the slave server without
- having to re-read the master updates.
- */
+/*****************************************************************************
+
+ MySQL Replication
+
+ Replication is implemented via two types of threads:
+
+ I/O Thread - One of these threads is started for each master server.
+ They maintain a connection to their master server, read log
+ events from the master as they arrive, and queues them into
+ a single, shared relay log file. A MASTER_INFO struct
+ represents each of these threads.
+
+ SQL Thread - One of these threads is started and reads from the relay log
+ file, executing each event. A RELAY_LOG_INFO struct
+ represents this thread.
+
+ Buffering in the relay log file makes it unnecessary to reread events from
+ a master server across a slave restart. It also decouples the slave from
+ the master where long-running updates and event logging are concerned--ie
+ it can continue to log new events while a slow query executes on the slave.
+
+*****************************************************************************/
extern ulong slave_net_timeout, master_retry_count;
extern MY_BITMAP slave_error_mask;
@@ -48,11 +54,16 @@ struct st_master_info;
--active_mi_in_use; \
pthread_mutex_unlock(&LOCK_active_mi); }
-/*
- st_relay_log_info contains information on the current relay log and
- relay log offset, and master log name and log sequence corresponding to the
- last update. Additionally, misc information specific to the SQL thread is
- included.
+/*****************************************************************************
+
+ Replication SQL Thread
+
+ st_relay_log_info contains:
+ - the current relay log
+ - the current relay log offset
+ - master log name
+ - master log sequence corresponding to the last update
+ - misc information specific to the SQL thread
st_relay_log_info is initialized from the slave.info file if such exists.
Otherwise, data members are intialized with defaults. The initialization is
@@ -66,7 +77,8 @@ struct st_master_info;
master_log_pos
To clean up, call end_relay_log_info()
- */
+
+*****************************************************************************/
typedef struct st_relay_log_info
{
@@ -128,13 +140,18 @@ typedef struct st_relay_log_info
uint32 cur_log_old_open_count;
/*
- Current offset in the relay log.
- pending - in some cases we do not increment offset immediately after
- processing an event, because the following event needs to be processed
- atomically together with this one ( so far, there is only one type of
- such event - Intvar_event that sets auto_increment value). However, once
- both events have been processed, we need to increment by the cumulative
- offset. pending stored the extra offset to be added to the position.
+ relay_log_pos - Current offset in the relay log.
+ pending - In some cases we do not increment offset immediately
+ after processing an event, because the following event
+ needs to be processed atomically together with this one
+ such as:
+
+ Intvar_event - sets auto_increment value
+ Rand_event - sets the random seed
+
+ However, once both events have been processed, we need to
+ increment by the cumulative offset. 'pending' stores the
+ extra offset to be added to the position.
*/
ulonglong relay_log_pos, pending;
ulonglong log_space_limit,log_space_total;
@@ -230,10 +247,15 @@ typedef struct st_relay_log_info
Log_event* next_event(RELAY_LOG_INFO* rli);
-/*
- st_master_info contains information about how to connect to a master,
- current master log name, and current log offset, as well as misc
- control variables
+/*****************************************************************************
+
+ Replication IO Thread
+
+ st_master_info contains:
+ - information about how to connect to a master
+ - current master log name
+ - current master log offset
+ - misc control variables
st_master_info is initialized once from the master.info file if such
exists. Otherwise, data members corresponding to master.info fields
@@ -255,9 +277,9 @@ Log_event* next_event(RELAY_LOG_INFO* rli);
flush_master_info() is required.
To clean up, call end_master_info()
-*/
-
+*****************************************************************************/
+
typedef struct st_master_info
{
char master_log_name[FN_REFLEN];
diff --git a/sql/spatial.cc b/sql/spatial.cc
new file mode 100644
index 00000000000..b21d30e4b53
--- /dev/null
+++ b/sql/spatial.cc
@@ -0,0 +1,1442 @@
+#include "mysql_priv.h"
+
+
+#define MAX_DIGITS_IN_DOUBLE 16
+
+/***************************** GClassInfo *******************************/
+
+#define IMPLEMENT_GEOM(class_name, type_id, name) \
+{ \
+ (GF_InitFromText) &class_name::init_from_text, \
+ (GF_GetDataAsText) &class_name::get_data_as_text, \
+ (GF_GetDataSize) &class_name::get_data_size, \
+ (GF_GetMBR) &class_name::get_mbr, \
+ (GF_GetD) &class_name::get_x, \
+ (GF_GetD) &class_name::get_y, \
+ (GF_GetD) &class_name::length, \
+ (GF_GetD) &class_name::area, \
+ (GF_GetI) &class_name::is_closed, \
+ (GF_GetUI) &class_name::num_interior_ring, \
+ (GF_GetUI) &class_name::num_points, \
+ (GF_GetUI) &class_name::num_geometries, \
+ (GF_GetUI) &class_name::dimension, \
+ (GF_GetWS) &class_name::start_point, \
+ (GF_GetWS) &class_name::end_point, \
+ (GF_GetWS) &class_name::exterior_ring, \
+ (GF_GetWS) &class_name::centroid, \
+ (GF_GetUIWS) &class_name::point_n, \
+ (GF_GetUIWS) &class_name::interior_ring_n, \
+ (GF_GetUIWS) &class_name::geometry_n, \
+ class_name::type_id, \
+ name, \
+ NULL \
+},
+
+
+static Geometry::GClassInfo ci_collection[] =
+{
+ IMPLEMENT_GEOM(GPoint, wkbPoint, "POINT")
+ IMPLEMENT_GEOM(GLineString, wkbLineString, "LINESTRING")
+ IMPLEMENT_GEOM(GPolygon, wkbPolygon, "POLYGON")
+ IMPLEMENT_GEOM(GMultiPoint, wkbMultiPoint, "MULTIPOINT")
+ IMPLEMENT_GEOM(GMultiLineString, wkbMultiLineString, "MULTILINESTRING")
+ IMPLEMENT_GEOM(GMultiPolygon, wkbMultiPolygon, "MULTIPOLYGON")
+ IMPLEMENT_GEOM(GGeometryCollection, wkbGeometryCollection, "GEOMETRYCOLLECTION")
+};
+
+static Geometry::GClassInfo *ci_collection_end = ci_collection + sizeof(ci_collection);
+
+/***************************** Geometry *******************************/
+
+Geometry::GClassInfo *Geometry::find_class(int type_id)
+{
+ for (GClassInfo *cur_rt = ci_collection; cur_rt < ci_collection_end; ++cur_rt)
+ {
+ if (cur_rt->m_type_id == type_id)
+ {
+ return cur_rt;
+ }
+ }
+ return NULL;
+}
+
+Geometry::GClassInfo *Geometry::find_class(const char *name, size_t len)
+{
+ for (GClassInfo *cur_rt = ci_collection;
+ cur_rt < ci_collection_end; ++cur_rt)
+ {
+ if ((cur_rt->m_name[len] == 0) &&
+ (strncmp(cur_rt->m_name, name, len) == 0))
+ {
+ return cur_rt;
+ }
+ }
+ return NULL;
+}
+
+int Geometry::create_from_wkb(const char *data, uint32 data_len)
+{
+ uint32 geom_type;
+
+ if (data_len < 1+4)
+ return 1;
+ data += sizeof(char);
+
+//FIXME: check byte ordering
+ geom_type = uint4korr(data);
+ data += 4;
+ m_vmt = find_class(geom_type);
+ if (!m_vmt) return -1;
+ m_data = data;
+ m_data_end = data + data_len;
+ return 0;
+}
+
+int Geometry::create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream)
+{
+ int name_len;
+ const char *name = trs->get_next_word(&name_len);
+ if (!name)
+ {
+ trs->set_error_msg("Geometry name expected");
+ return -1;
+ }
+ if (!(m_vmt = find_class(name, name_len)))
+ return -1;
+ if (wkt->reserve(1 + 4, 512))
+ return 1;
+ wkt->q_append((char)wkbNDR);
+ wkt->q_append((uint32)get_class_info()->m_type_id);
+ if (trs->get_next_symbol() != '(')
+ {
+ trs->set_error_msg("'(' expected");
+ return -1;
+ }
+ if (init_from_text(trs, wkt)) return 1;
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return -1;
+ }
+ if (init_stream)
+ {
+ init_from_wkb(wkt->ptr(), wkt->length());
+ shift_wkb_header();
+ }
+ return 0;
+}
+
+int Geometry::envelope(String *result) const
+{
+ MBR mbr;
+
+ get_mbr(&mbr);
+
+ if (result->reserve(1+4*3+sizeof(double)*10))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPolygon);
+ result->q_append((uint32)1);
+ result->q_append((uint32)5);
+ result->q_append(mbr.xmin);
+ result->q_append(mbr.ymin);
+ result->q_append(mbr.xmax);
+ result->q_append(mbr.ymin);
+ result->q_append(mbr.xmax);
+ result->q_append(mbr.ymax);
+ result->q_append(mbr.xmin);
+ result->q_append(mbr.ymax);
+ result->q_append(mbr.xmin);
+ result->q_append(mbr.ymin);
+
+ return 0;
+}
+
+/***************************** Point *******************************/
+
+size_t GPoint::get_data_size() const
+{
+ return POINT_DATA_SIZE;
+}
+
+int GPoint::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ double x, y;
+ if (wkb->reserve(sizeof(double)*2))
+ return 1;
+ if (trs->get_next_number(&x))
+ return 1;
+ if (trs->get_next_number(&y))
+ return 1;
+ wkb->q_append(x);
+ wkb->q_append(y);
+
+ return 0;
+}
+
+int GPoint::get_data_as_text(String *txt) const
+{
+ double x, y;
+ if (get_xy(&x, &y))
+ return 1;
+ if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
+ return 1;
+ txt->qs_append(x);
+ txt->qs_append(' ');
+ txt->qs_append(y);
+ return 0;
+}
+
+int GPoint::get_mbr(MBR *mbr) const
+{
+ double x, y;
+ if (get_xy(&x, &y))
+ return 1;
+ mbr->add_xy(x, y);
+ return 0;
+}
+
+/***************************** LineString *******************************/
+
+size_t GLineString::get_data_size() const
+{
+ uint32 n_points = uint4korr(m_data);
+
+ return 4 + n_points*POINT_DATA_SIZE;
+}
+
+int GLineString::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_points = 0;
+ int np_pos = wkb->length();
+ GPoint p;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_points);
+
+ for (;;)
+ {
+ if (p.init_from_text(trs, wkb))
+ return 1;
+ ++n_points;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else break;
+ }
+
+ if (n_points<2)
+ {
+ trs->set_error_msg("Too few points in LINESTRING");
+ return 1;
+ }
+
+ wkb->WriteAtPosition(np_pos, n_points);
+
+ return 0;
+}
+
+int GLineString::get_data_as_text(String *txt) const
+{
+ uint32 n_points;
+ const char *data = m_data;
+
+ if (no_data(data, 4))
+ return 1;
+
+ n_points = uint4korr(data);
+ data += 4;
+
+ if (no_data(data, sizeof(double) * 2 * n_points))
+ return 1;
+
+ if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
+ return 1;
+ for (; n_points>0; --n_points)
+ {
+ double x, y;
+ float8get(x, data);
+ data += sizeof(double);
+ float8get(y, data);
+ data += sizeof(double);
+ txt->qs_append(x);
+ txt->qs_append(' ');
+ txt->qs_append(y);
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GLineString::get_mbr(MBR *mbr) const
+{
+ uint32 n_points;
+ const char *data = m_data;
+
+ if (no_data(data, 4))
+ return 1;
+
+ n_points = uint4korr(data);
+ data += 4;
+
+ if (no_data(data, sizeof(double) * 2 * n_points))
+ return 1;
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy(data, data + 8);
+ data += 8+8;
+ }
+
+ return 0;
+}
+
+int GLineString::length(double *len) const
+{
+ uint32 n_points;
+ double prev_x, prev_y;
+ const char *data = m_data;
+
+ *len=0;
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+ data += 4;
+
+ if (no_data(data, sizeof(double) * 2 * n_points))
+ return 1;
+
+ --n_points;
+ float8get(prev_x, data);
+ data += 8;
+ float8get(prev_y, data);
+ data += 8;
+
+ for (; n_points>0; --n_points)
+ {
+ double x, y;
+ float8get(x, data);
+ data += 8;
+ float8get(y, data);
+ data += 8;
+ *len+=sqrt(pow(prev_x-x,2)+pow(prev_y-y,2));
+ prev_x=x;
+ prev_y=y;
+ }
+ return 0;
+}
+
+int GLineString::is_closed(int *closed) const
+
+{
+ uint32 n_points;
+ double x1, y1, x2, y2;
+
+ const char *data = m_data;
+
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+ float8get(x1, data);
+ data += 8;
+ float8get(y1, data);
+ data += 8 + (n_points-2)*POINT_DATA_SIZE;
+ float8get(x2, data);
+ data += 8;
+ float8get(y2, data);
+
+ *closed=(x1==x2)&&(y1==y2);
+
+ return 0;
+}
+
+int GLineString::num_points(uint32 *n_points) const
+{
+ *n_points = uint4korr(m_data);
+ return 0;
+}
+
+int GLineString::start_point(String *result) const
+{
+ const char *data = m_data + 4;
+ if (no_data(data, 8+8))
+ return 1;
+
+ if (result->reserve(1 + 4 + sizeof(double) * 2))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPoint);
+ result->q_append((double *)data);
+ result->q_append((double *)(data + 8));
+
+ return 0;
+}
+
+int GLineString::end_point(String *result) const
+{
+ const char *data = m_data;
+ uint32 n_points;
+
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+
+ data += 4 + (n_points-1)*POINT_DATA_SIZE;
+
+ if (no_data(data, 8+8))
+ return 1;
+
+ if (result->reserve(1 + 4 + sizeof(double) * 2))
+ return 1;
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPoint);
+ result->q_append((double *)data);
+ result->q_append((double *)(data + 8));
+
+ return 0;
+}
+
+
+int GLineString::point_n(uint32 num, String *result) const
+{
+ const char *data = m_data;
+ uint32 n_points;
+
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+
+ if ((uint32)(num-1) >= n_points) // really means (num > n_points || num < 1)
+ return 1;
+
+ data += 4 + (num - 1)*POINT_DATA_SIZE;
+
+ if (no_data(data, 8+8))
+ return 1;
+ if (result->reserve(1 + 4 + sizeof(double) * 2))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPoint);
+ result->q_append((double *)data);
+ result->q_append((double *)(data + 8));
+
+ return 0;
+}
+
+/***************************** Polygon *******************************/
+
+size_t GPolygon::get_data_size() const
+{
+ uint32 n_linear_rings = 0;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+
+ n_linear_rings = uint4korr(data);
+ data += 4;
+ for (; n_linear_rings>0; --n_linear_rings)
+ {
+ if (no_data(data, 4))
+ return 1;
+ data += 4 + uint4korr(data)*POINT_DATA_SIZE;
+ }
+ return data - m_data;
+}
+
+int GPolygon::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_linear_rings = 0;
+ int lr_pos = wkb->length();
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_linear_rings);
+
+ for (;;)
+ {
+ GLineString ls;
+ size_t ls_pos=wkb->length();
+ if (trs->get_next_symbol() != '(')
+ {
+ trs->set_error_msg("'(' expected");
+ return 1;
+ }
+ if (ls.init_from_text(trs, wkb))
+ return 1;
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return 1;
+ }
+ ls.init_from_wkb(wkb->ptr()+ls_pos, wkb->length()-ls_pos);
+ int closed;
+ ls.is_closed(&closed);
+ if (!closed)
+ {
+ trs->set_error_msg("POLYGON's linear ring isn't closed");
+ return 1;
+ }
+ ++n_linear_rings;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(lr_pos, n_linear_rings);
+ return 0;
+}
+
+int GPolygon::get_data_as_text(String *txt) const
+{
+ uint32 n_linear_rings;
+ const char *data = m_data;
+
+ if (no_data(data, 4))
+ return 1;
+
+ n_linear_rings = uint4korr(data);
+ data += 4;
+
+ for (; n_linear_rings>0; --n_linear_rings)
+ {
+ if(no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+
+ if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
+ return 1;
+ txt->qs_append('(');
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)data);
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + 8));
+ txt->qs_append(',');
+
+ data += 8+8;
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GPolygon::get_mbr(MBR *mbr) const
+{
+ uint32 n_linear_rings;
+
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_linear_rings = uint4korr(data);
+ data += 4;
+ for (; n_linear_rings>0; --n_linear_rings)
+ {
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy(data, data + 8);
+ data += 8+8;
+ }
+ }
+ return 0;
+}
+
+int GPolygon::area(double *ar) const
+{
+ uint32 n_linear_rings;
+ double result = -1.0;
+
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_linear_rings = uint4korr(data);
+ data += 4;
+ for (; n_linear_rings>0; --n_linear_rings)
+ {
+ double prev_x, prev_y;
+ double lr_area=0;
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+ float8get(prev_x, data+4);
+ float8get(prev_y, data+(4+8));
+ data += (4+8+8);
+
+ --n_points;
+ for (; n_points>0; --n_points)
+ {
+ double x, y;
+ float8get(x, data);
+ float8get(y, data + 8);
+ lr_area+=(prev_x+x)*(prev_y-y);
+ prev_x=x;
+ prev_y=y;
+ data += (8+8);
+ }
+ lr_area=fabs(lr_area)/2;
+ if(result==-1) result=lr_area;
+ else result-=lr_area;
+ }
+ *ar=fabs(result);
+ return 0;
+}
+
+
+int GPolygon::exterior_ring(String *result) const
+{
+ uint32 n_points;
+ const char *data = m_data + 4; // skip n_linerings
+
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, n_points * POINT_DATA_SIZE))
+ return 1;
+
+ if (result->reserve(1+4+4+ n_points * POINT_DATA_SIZE))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbLineString);
+ result->q_append(n_points);
+ result->q_append(data, n_points * POINT_DATA_SIZE);
+
+ return 0;
+}
+
+int GPolygon::num_interior_ring(uint32 *n_int_rings) const
+{
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ *n_int_rings = uint4korr(data);
+ --(*n_int_rings);
+
+ return 0;
+}
+
+int GPolygon::interior_ring_n(uint32 num, String *result) const
+{
+ const char *data = m_data;
+ uint32 n_linear_rings;
+ uint32 n_points;
+
+ if (no_data(data, 4))
+ return 1;
+
+ n_linear_rings = uint4korr(data);
+ data += 4;
+ if ((num >= n_linear_rings) || (num < 1))
+ return -1;
+
+ for (; num > 0; --num)
+ {
+ if (no_data(data, 4))
+ return 1;
+ data += 4 + uint4korr(data) * POINT_DATA_SIZE;
+ }
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+ int points_size = n_points * POINT_DATA_SIZE;
+ data += 4;
+ if (no_data(data, points_size))
+ return 1;
+
+ if (result->reserve(1+4+4+ points_size))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbLineString);
+ result->q_append(n_points);
+ result->q_append(data, points_size);
+
+ return 0;
+}
+
+int GPolygon::centroid_xy(double *x, double *y) const
+{
+ uint32 n_linear_rings;
+ uint32 i;
+ double res_area, res_cx, res_cy;
+ const char *data = m_data;
+ LINT_INIT(res_area);
+ LINT_INIT(res_cx);
+ LINT_INIT(res_cy);
+
+ if (no_data(data, 4))
+ return 1;
+ n_linear_rings = uint4korr(data);
+ data += 4;
+
+ for (i = 0; i < n_linear_rings; ++i)
+ {
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ double prev_x, prev_y;
+ double cur_area = 0;
+ double cur_cx = 0;
+ double cur_cy = 0;
+
+ data += 4;
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+ float8get(prev_x, data);
+ float8get(prev_y, data+8);
+ data += (8+8);
+
+ uint32 n = n_points - 1;
+ for (; n > 0; --n)
+ {
+ double x, y;
+ float8get(x, data);
+ float8get(y, data + 8);
+
+ cur_area += (prev_x + x) * (prev_y - y);
+ cur_cx += x;
+ cur_cy += y;
+ prev_x = x;
+ prev_y = y;
+ data += (8+8);
+ }
+ cur_area = fabs(cur_area) / 2;
+ cur_cx = cur_cx / (n_points - 1);
+ cur_cy = cur_cy / (n_points - 1);
+
+ if (i)
+ {
+ double d_area = res_area - cur_area;
+ if (d_area <= 0)
+ return 1;
+ res_cx = (res_area * res_cx - cur_area * cur_cx) / d_area;
+ res_cy = (res_area * res_cy - cur_area * cur_cy) / d_area;
+ }
+ else
+ {
+ res_area = cur_area;
+ res_cx = cur_cx;
+ res_cy = cur_cy;
+ }
+ }
+
+ *x = res_cx;
+ *y = res_cy;
+
+ return 0;
+}
+
+int GPolygon::centroid(String *result) const
+{
+ double x, y;
+
+ this->centroid_xy(&x, &y);
+ if (result->reserve(1 + 4 + sizeof(double) * 2))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPoint);
+ result->q_append(x);
+ result->q_append(y);
+
+ return 0;
+}
+
+
+/***************************** MultiPoint *******************************/
+
+size_t GMultiPoint::get_data_size() const
+{
+ return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
+}
+
+int GMultiPoint::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_points = 0;
+ int np_pos = wkb->length();
+ GPoint p;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+ wkb->q_append((uint32)n_points);
+
+ for (;;)
+ {
+ if (wkb->reserve(1+4, 512))
+ return 1;
+ wkb->q_append((char)wkbNDR);
+ wkb->q_append((uint32)wkbPoint);
+ if (p.init_from_text(trs, wkb))
+ return 1;
+ ++n_points;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(np_pos, n_points);
+
+ return 0;
+}
+
+int GMultiPoint::get_data_as_text(String *txt) const
+{
+ uint32 n_points;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+
+ n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, n_points * (8+8+WKB_HEADER_SIZE)))
+ return 1;
+
+ if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
+ return 1;
+
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)(data + WKB_HEADER_SIZE));
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + (8 + WKB_HEADER_SIZE)));
+ txt->qs_append(',');
+ data += 8+8+WKB_HEADER_SIZE;
+ }
+ txt->length(txt->length()-1);
+ return 0;
+}
+
+int GMultiPoint::get_mbr(MBR *mbr) const
+{
+ uint32 n_points;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, n_points * (8+8+WKB_HEADER_SIZE)))
+ return 1;
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy(data + WKB_HEADER_SIZE, data + 8 + WKB_HEADER_SIZE);
+ data += (8+8+WKB_HEADER_SIZE);
+ }
+ return 0;
+}
+
+/***************************** MultiLineString *******************************/
+
+size_t GMultiLineString::get_data_size() const
+{
+ uint32 n_line_strings = 0;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4;
+
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ if (no_data(data, WKB_HEADER_SIZE + 4))
+ return 1;
+ data += WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * POINT_DATA_SIZE;
+ }
+ return data - m_data;
+}
+
+int GMultiLineString::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_line_strings = 0;
+ int ls_pos = wkb->length();
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_line_strings);
+
+ for (;;)
+ {
+ GLineString ls;
+
+ if (wkb->reserve(1+4, 512))
+ return 1;
+ wkb->q_append((char)wkbNDR);
+ wkb->q_append((uint32)wkbLineString);
+
+ if (trs->get_next_symbol() != '(')
+ {
+ trs->set_error_msg("'(' expected");
+ return 1;
+ }
+ if (ls.init_from_text(trs, wkb))
+ return 1;
+
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return 1;
+ }
+ ++n_line_strings;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(ls_pos, n_line_strings);
+
+ return 0;
+}
+
+int GMultiLineString::get_data_as_text(String *txt) const
+{
+ uint32 n_line_strings;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4;
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ if (no_data(data, (WKB_HEADER_SIZE + 4)))
+ return 1;
+ uint32 n_points = uint4korr(data + WKB_HEADER_SIZE);
+ data += WKB_HEADER_SIZE + 4;
+ if (no_data(data, n_points * (8+8)))
+ return 1;
+
+ if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
+ return 1;
+ txt->qs_append('(');
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)data);
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + 8));
+ txt->qs_append(',');
+ data += 8+8;
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GMultiLineString::get_mbr(MBR *mbr) const
+{
+ uint32 n_line_strings;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4;
+
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ if (no_data(data, WKB_HEADER_SIZE + 4))
+ return 1;
+ uint32 n_points = uint4korr(data + WKB_HEADER_SIZE);
+ data += 4+WKB_HEADER_SIZE;
+ if (no_data(data, (8+8)*n_points))
+ return 1;
+
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy(data, data + 8);
+ data += 8+8;
+ }
+ }
+ return 0;
+}
+
+int GMultiLineString::length(double *len) const
+{
+ uint32 n_line_strings;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4;
+ *len=0;
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ double ls_len;
+ GLineString ls;
+ data += WKB_HEADER_SIZE;
+ ls.init_from_wkb(data, m_data_end - data);
+ if (ls.length(&ls_len))
+ return 1;
+ *len+=ls_len;
+ data += ls.get_data_size();
+ }
+ return 0;
+}
+
+int GMultiLineString::is_closed(int *closed) const
+{
+ uint32 n_line_strings;
+ const char *data = m_data;
+ if (no_data(data, 1))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4 + WKB_HEADER_SIZE;
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ GLineString ls;
+ ls.init_from_wkb(data, m_data_end - data);
+ if (ls.is_closed(closed))
+ return 1;
+ if (!*closed)
+ return 0;
+ data += ls.get_data_size() + WKB_HEADER_SIZE;
+ }
+ return 0;
+}
+
+/***************************** MultiPolygon *******************************/
+
+size_t GMultiPolygon::get_data_size() const
+{
+ uint32 n_polygons;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (; n_polygons>0; --n_polygons)
+ {
+ if (no_data(data, 4 + WKB_HEADER_SIZE))
+ return 1;
+ uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE);
+ data += 4 + WKB_HEADER_SIZE;
+
+ for (; n_linear_rings > 0; --n_linear_rings)
+ {
+ data += 4 + uint4korr(data) * POINT_DATA_SIZE;
+ }
+ }
+ return data - m_data;
+}
+
+int GMultiPolygon::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_polygons = 0;
+ int np_pos = wkb->length();
+ GPolygon p;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_polygons);
+
+ for (;;)
+ {
+ if (wkb->reserve(1+4, 512))
+ return 1;
+ wkb->q_append((char)wkbNDR);
+ wkb->q_append((uint32)wkbPolygon);
+
+ if (trs->get_next_symbol() != '(')
+ {
+ trs->set_error_msg("'(' expected");
+ return 1;
+ }
+ if (p.init_from_text(trs, wkb))
+ return 1;
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return 1;
+ }
+ ++n_polygons;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(np_pos, n_polygons);
+ return 0;
+}
+
+int GMultiPolygon::get_data_as_text(String *txt) const
+{
+ uint32 n_polygons;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (; n_polygons>0; --n_polygons)
+ {
+ if (no_data(data, 4 + WKB_HEADER_SIZE))
+ return 1;
+ data += WKB_HEADER_SIZE;
+ uint32 n_linear_rings = uint4korr(data);
+ data += 4;
+
+ if (txt->reserve(1, 512))
+ return 1;
+ txt->q_append('(');
+ for (; n_linear_rings>0; --n_linear_rings)
+ {
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, (8+8)*n_points)) return 1;
+
+ if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points,
+ 512)) return 1;
+ txt->qs_append('(');
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)data);
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + 8));
+ txt->qs_append(',');
+ data += 8+8;
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GMultiPolygon::get_mbr(MBR *mbr) const
+{
+ uint32 n_polygons;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (; n_polygons>0; --n_polygons)
+ {
+ if (no_data(data, 4+WKB_HEADER_SIZE))
+ return 1;
+ uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE);
+ data += WKB_HEADER_SIZE + 4;
+
+ for (; n_linear_rings>0; --n_linear_rings)
+ {
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ data += 4;
+ if (no_data(data, (8+8)*n_points))
+ return 1;
+
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy(data, data + 8);
+ data += 8+8;
+ }
+ }
+ }
+ return 0;
+}
+
+
+int GMultiPolygon::area(double *ar) const
+{
+ uint32 n_polygons;
+ const char *data = m_data;
+ double result = 0;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (; n_polygons>0; --n_polygons)
+ {
+ double p_area;
+
+ GPolygon p;
+ data += WKB_HEADER_SIZE;
+ p.init_from_wkb(data, m_data_end - data);
+ if (p.area(&p_area))
+ return 1;
+ result += p_area;
+ data += p.get_data_size();
+ }
+ *ar = result;
+ return 0;
+}
+
+int GMultiPolygon::centroid(String *result) const
+{
+ uint32 n_polygons;
+ uint i;
+ GPolygon p;
+ double res_area, res_cx, res_cy;
+ double cur_area, cur_cx, cur_cy;
+
+ LINT_INIT(res_area);
+ LINT_INIT(res_cx);
+ LINT_INIT(res_cy);
+
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (i = 0; i < n_polygons; ++i)
+ {
+ data += WKB_HEADER_SIZE;
+ p.init_from_wkb(data, m_data_end - data);
+ if (p.area(&cur_area))
+ return 1;
+
+ if (p.centroid_xy(&cur_cx, &cur_cy))
+ return 1;
+
+ if (i)
+ {
+ double sum_area = res_area + cur_area;
+ res_cx = (res_area * res_cx + cur_area * cur_cx) / sum_area;
+ res_cy = (res_area * res_cy + cur_area * cur_cy) / sum_area;
+ }
+ else
+ {
+ res_area = cur_area;
+ res_cx = cur_cx;
+ res_cy = cur_cy;
+ }
+
+ data += p.get_data_size();
+ }
+
+ if (result->reserve(1 + 4 + sizeof(double) * 2))
+ return 1;
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPoint);
+ result->q_append(res_cx);
+ result->q_append(res_cy);
+
+ return 0;
+}
+
+/***************************** GeometryCollection *******************************/
+
+size_t GGeometryCollection::get_data_size() const
+{
+ uint32 n_objects;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ for (; n_objects>0; --n_objects)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+
+ Geometry geom;
+
+ if (geom.init(wkb_type))
+ return 0;
+
+ geom.init_from_wkb(data, m_data_end - data);
+ size_t object_size=geom.get_data_size();
+ data += object_size;
+ }
+ return data - m_data;
+}
+
+int GGeometryCollection::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_objects = 0;
+ int no_pos = wkb->length();
+ Geometry g;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+ wkb->q_append((uint32)n_objects);
+
+ for (;;)
+ {
+ if (g.create_from_wkt(trs, wkb))
+ return 1;
+
+ if (g.get_class_info()->m_type_id==wkbGeometryCollection)
+ {
+ trs->set_error_msg("Unexpected GEOMETRYCOLLECTION");
+ return 1;
+ }
+ ++n_objects;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else break;
+ }
+ wkb->WriteAtPosition(no_pos, n_objects);
+
+ return 0;
+}
+
+int GGeometryCollection::get_data_as_text(String *txt) const
+{
+ uint32 n_objects;
+ const char *data = m_data;
+ Geometry geom;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ for (; n_objects>0; --n_objects)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+
+ if (geom.init(wkb_type))
+ return 1;
+ geom.init_from_wkb(data, m_data_end - data);
+ if (geom.as_wkt(txt))
+ return 1;
+ data += geom.get_data_size();
+ txt->reserve(1, 512);
+ txt->q_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GGeometryCollection::get_mbr(MBR *mbr) const
+{
+ uint32 n_objects;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+ for (; n_objects>0; --n_objects)
+ {
+ if(no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+ Geometry geom;
+
+ if (geom.init(wkb_type))
+ return 1;
+ geom.init_from_wkb(data, m_data_end - data);
+ geom.get_mbr(mbr);
+ data += geom.get_data_size();
+ }
+ return 0;
+}
+
+int GGeometryCollection::num_geometries(uint32 *num) const
+{
+ *num = uint4korr(m_data);
+ return 0;
+}
+
+int GGeometryCollection::geometry_n(uint32 num, String *result) const
+{
+ const char *data = m_data;
+ uint32 n_objects;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ if ((num > n_objects) || (num < 1))
+ {
+ return -1;
+ }
+ for (; num > 0; --num)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+
+ Geometry geom;
+ if (geom.init(wkb_type))
+ return 1;
+ geom.init_from_wkb(data, m_data_end - data);
+ if (num == 1)
+ {
+ if (result->reserve(1+4+geom.get_data_size()))
+ return 1;
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkb_type);
+ result->q_append(data, geom.get_data_size());
+ break;
+ }
+ else
+ {
+ data += geom.get_data_size();
+ }
+ }
+ return 0;
+}
+
+int GGeometryCollection::dimension(uint32 *dim) const
+{
+ uint32 n_objects;
+ *dim = 0;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ for (; n_objects > 0; --n_objects)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+
+ uint32 d;
+
+ Geometry geom;
+ if (geom.init(wkb_type))
+ return 1;
+ geom.init_from_wkb(data, m_data_end - data);
+ if (geom.dimension(&d))
+ return 1;
+
+ if (d > *dim)
+ *dim = d;
+ data += geom.get_data_size();
+ }
+ return 0;
+}
+
+/***************************** /objects *******************************/
diff --git a/sql/spatial.h b/sql/spatial.h
new file mode 100644
index 00000000000..3f09e86e823
--- /dev/null
+++ b/sql/spatial.h
@@ -0,0 +1,497 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ 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 */
+
+#ifndef _spatial_h
+#define _spatial_h
+
+const uint POINT_DATA_SIZE = 8+8;
+const uint WKB_HEADER_SIZE = 1+4;
+
+struct stPoint2D
+{
+ double x;
+ double y;
+};
+
+struct stLinearRing
+{
+ size_t n_points;
+ stPoint2D points;
+};
+
+/***************************** MBR *******************************/
+
+struct MBR
+{
+ MBR()
+ {
+ xmin=DBL_MAX;
+ ymin=DBL_MAX;
+ xmax=-DBL_MAX;
+ ymax=-DBL_MAX;
+ }
+
+ MBR(const double &_xmin, const double &_ymin,
+ const double &_xmax, const double &_ymax)
+ {
+ xmin=_xmin;
+ ymin=_ymin;
+ xmax=_xmax;
+ ymax=_ymax;
+ }
+
+ MBR(const stPoint2D &min, const stPoint2D &max)
+ {
+ xmin=min.x;
+ ymin=min.y;
+ xmax=max.x;
+ ymax=max.y;
+ }
+
+ double xmin;
+ double ymin;
+ double xmax;
+ double ymax;
+
+ void add_xy(double x, double y)
+ {
+ /* Not using "else" for proper one point MBR calculation */
+ if (x<xmin)
+ {
+ xmin=x;
+ }
+ if (x>xmax)
+ {
+ xmax=x;
+ }
+ if (y<ymin)
+ {
+ ymin=y;
+ }
+ if (y>ymax)
+ {
+ ymax=y;
+ }
+ }
+
+ void add_xy(const char *px, const char *py)
+ {
+ double x, y;
+ float8get(x, px);
+ float8get(y, py);
+ /* Not using "else" for proper one point MBR calculation */
+ if (x<xmin)
+ {
+ xmin=x;
+ }
+ if (x>xmax)
+ {
+ xmax=x;
+ }
+ if (y<ymin)
+ {
+ ymin=y;
+ }
+ if (y>ymax)
+ {
+ ymax=y;
+ }
+ }
+
+ void add_mbr(const MBR *mbr)
+ {
+ if (mbr->xmin<xmin)
+ {
+ xmin=mbr->xmin;
+ }
+ if (mbr->xmax>xmax)
+ {
+ xmax=mbr->xmax;
+ }
+ if (mbr->ymin<ymin)
+ {
+ ymin=mbr->ymin;
+ }
+ if (mbr->ymax>ymax)
+ {
+ ymax=mbr->ymax;
+ }
+ }
+
+ int equals(const MBR *mbr)
+ {
+ return ((mbr->xmin == xmin) && (mbr->ymin == ymin) &&
+ (mbr->xmax == xmax) && (mbr->ymax == ymax));
+ }
+
+ int disjoint(const MBR *mbr)
+ {
+ return ((mbr->xmin > xmax) || (mbr->ymin > ymax) ||
+ (mbr->xmax < xmin) || (mbr->ymax < ymin));
+ }
+
+ int intersects(const MBR *mbr)
+ {
+ return !disjoint(mbr);
+ }
+
+ int touches(const MBR *mbr)
+ {
+ return ((((mbr->xmin == xmax) || (mbr->xmax == xmin)) &&
+ ((mbr->ymin >= ymin) && (mbr->ymin <= ymax) ||
+ (mbr->ymax >= ymin) && (mbr->ymax <= ymax))) ||
+ (((mbr->ymin == ymax) || (mbr->ymax == ymin)) &&
+ ((mbr->xmin >= xmin) && (mbr->xmin <= xmax) ||
+ (mbr->xmax >= xmin) && (mbr->xmax <= xmax))));
+ }
+
+ int within(const MBR *mbr)
+ {
+ return ((mbr->xmin <= xmin) && (mbr->ymin <= ymin) &&
+ (mbr->xmax >= xmax) && (mbr->ymax >= ymax));
+ }
+
+ int contains(const MBR *mbr)
+ {
+ return ((mbr->xmin >= xmin) && (mbr->ymin >= ymin) &&
+ (mbr->xmax <= xmax) && (mbr->ymax <= ymax));
+ }
+
+ bool inner_point(double x, double y) const
+ {
+ return (xmin<x) && (xmax>x) && (ymin<y) && (ymax>x);
+ }
+
+ int overlaps(const MBR *mbr)
+ {
+ int lb = mbr->inner_point(xmin, ymin);
+ int rb = mbr->inner_point(xmax, ymin);
+ int rt = mbr->inner_point(xmax, ymax);
+ int lt = mbr->inner_point(xmin, ymax);
+
+ int a = lb+rb+rt+lt;
+ return (a>0) && (a<4) && (!within(mbr));
+ }
+};
+
+
+/***************************** Geometry *******************************/
+
+class Geometry;
+
+typedef int (Geometry::*GF_InitFromText)(GTextReadStream *, String *);
+typedef int (Geometry::*GF_GetDataAsText)(String *) const;
+typedef size_t (Geometry::*GF_GetDataSize)() const;
+typedef int (Geometry::*GF_GetMBR)(MBR *) const;
+
+typedef int (Geometry::*GF_GetD)(double *) const;
+typedef int (Geometry::*GF_GetI)(int *) const;
+typedef int (Geometry::*GF_GetUI)(uint32 *) const;
+typedef int (Geometry::*GF_GetWS)(String *) const;
+typedef int (Geometry::*GF_GetUIWS)(uint32, String *) const;
+
+#define GEOM_METHOD_PRESENT(geom_obj, method)\
+ (geom_obj.m_vmt->method != &Geometry::method)
+
+class Geometry
+{
+public:
+ enum wkbType
+ {
+ wkbPoint = 1,
+ wkbLineString = 2,
+ wkbPolygon = 3,
+ wkbMultiPoint = 4,
+ wkbMultiLineString = 5,
+ wkbMultiPolygon = 6,
+ wkbGeometryCollection = 7
+ };
+ enum wkbByteOrder
+ {
+ wkbXDR = 0, /* Big Endian */
+ wkbNDR = 1 /* Little Endian */
+ };
+
+
+ class GClassInfo
+ {
+ public:
+ GF_InitFromText init_from_text;
+ GF_GetDataAsText get_data_as_text;
+ GF_GetDataSize get_data_size;
+ GF_GetMBR get_mbr;
+ GF_GetD get_x;
+ GF_GetD get_y;
+ GF_GetD length;
+ GF_GetD area;
+
+ GF_GetI is_closed;
+
+ GF_GetUI num_interior_ring;
+ GF_GetUI num_points;
+ GF_GetUI num_geometries;
+ GF_GetUI dimension;
+
+ GF_GetWS start_point;
+ GF_GetWS end_point;
+ GF_GetWS exterior_ring;
+ GF_GetWS centroid;
+
+ GF_GetUIWS point_n;
+ GF_GetUIWS interior_ring_n;
+ GF_GetUIWS geometry_n;
+
+ int m_type_id;
+ const char *m_name;
+ GClassInfo *m_next_rt;
+ };
+ GClassInfo *m_vmt;
+
+ const GClassInfo *get_class_info() const { return m_vmt; }
+ size_t get_data_size() const { return (this->*m_vmt->get_data_size)(); }
+
+ int init_from_text(GTextReadStream *trs, String *wkb)
+ { return (this->*m_vmt->init_from_text)(trs, wkb); }
+
+ int get_data_as_text(String *txt) const
+ { return (this->*m_vmt->get_data_as_text)(txt); }
+
+ int get_mbr(MBR *mbr) const { return (this->*m_vmt->get_mbr)(mbr); }
+ int dimension(uint32 *dim) const
+ { return (this->*m_vmt->dimension)(dim); }
+
+ int get_x(double *x) const { return (this->*m_vmt->get_x)(x); }
+ int get_y(double *y) const { return (this->*m_vmt->get_y)(y); }
+ int length(double *len) const { return (this->*m_vmt->length)(len); }
+ int area(double *ar) const { return (this->*m_vmt->area)(ar); }
+
+ int is_closed(int *closed) const
+ { return (this->*m_vmt->is_closed)(closed); }
+
+ int num_interior_ring(uint32 *n_int_rings) const
+ { return (this->*m_vmt->num_interior_ring)(n_int_rings); }
+ int num_points(uint32 *n_points) const
+ { return (this->*m_vmt->num_points)(n_points); }
+
+ int num_geometries(uint32 *num) const
+ { return (this->*m_vmt->num_geometries)(num); }
+
+ int start_point(String *point) const
+ { return (this->*m_vmt->start_point)(point); }
+ int end_point(String *point) const
+ { return (this->*m_vmt->end_point)(point); }
+ int exterior_ring(String *ring) const
+ { return (this->*m_vmt->exterior_ring)(ring); }
+ int centroid(String *point) const
+ { return (this->*m_vmt->centroid)(point); }
+
+ int point_n(uint32 num, String *result) const
+ { return (this->*m_vmt->point_n)(num, result); }
+ int interior_ring_n(uint32 num, String *result) const
+ { return (this->*m_vmt->interior_ring_n)(num, result); }
+ int geometry_n(uint32 num, String *result) const
+ { return (this->*m_vmt->geometry_n)(num, result); }
+
+public:
+ int create_from_wkb(const char *data, uint32 data_len);
+ int create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream=1);
+ int init(int type_id)
+ {
+ m_vmt = find_class(type_id);
+ return !m_vmt;
+ }
+ int new_geometry(const char *name, size_t len)
+ {
+ m_vmt = find_class(name, len);
+ return !m_vmt;
+ }
+
+ int as_wkt(String *wkt) const
+ {
+ if (wkt->reserve(strlen(get_class_info()->m_name) + 2, 512))
+ return 1;
+ wkt->qs_append(get_class_info()->m_name);
+ wkt->qs_append('(');
+ if (get_data_as_text(wkt))
+ return 1;
+ wkt->qs_append(')');
+ return 0;
+ }
+
+ void init_from_wkb(const char *data, uint32 data_len)
+ {
+ m_data = data;
+ m_data_end = data + data_len;
+ }
+
+ void shift_wkb_header()
+ {
+ m_data += WKB_HEADER_SIZE;
+ }
+
+ int envelope(String *result) const;
+
+protected:
+ static GClassInfo *find_class(int type_id);
+ static GClassInfo *find_class(const char *name, size_t len);
+
+ bool no_data(const char *cur_data, uint32 data_amount) const
+ {
+ return (cur_data + data_amount > m_data_end);
+ }
+
+ const char *m_data;
+ const char *m_data_end;
+};
+
+#define SIZEOF_STORED_DOUBLE 8
+
+/***************************** Point *******************************/
+
+class GPoint: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int get_xy(double *x, double *y) const
+ {
+ const char *data = m_data;
+ if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1;
+ float8get(*x, data);
+ float8get(*y, data + SIZEOF_STORED_DOUBLE);
+ return 0;
+ }
+
+ int get_x(double *x) const
+ {
+ if (no_data(m_data, SIZEOF_STORED_DOUBLE)) return 1;
+ float8get(*x, m_data);
+ return 0;
+ }
+
+ int get_y(double *y) const
+ {
+ const char *data = m_data;
+ if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1;
+ float8get(*y, data + SIZEOF_STORED_DOUBLE);
+ return 0;
+ }
+
+ int dimension(uint32 *dim) const { *dim = 0; return 0; }
+};
+
+/***************************** LineString *******************************/
+
+class GLineString: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int length(double *len) const;
+ int is_closed(int *closed) const;
+ int num_points(uint32 *n_points) const;
+ int start_point(String *point) const;
+ int end_point(String *point) const;
+ int point_n(uint32 n, String *result) const;
+ int dimension(uint32 *dim) const { *dim = 1; return 0; }
+// IsRing
+};
+
+/***************************** Polygon *******************************/
+
+class GPolygon: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int area(double *ar) const;
+ int exterior_ring(String *result) const;
+ int num_interior_ring(uint32 *n_int_rings) const;
+ int interior_ring_n(uint32 num, String *result) const;
+ int centroid_xy(double *x, double *y) const;
+ int centroid(String *result) const;
+ int dimension(uint32 *dim) const { *dim = 2; return 0; }
+// PointOnSurface
+};
+
+/***************************** MultiPoint *******************************/
+
+class GMultiPoint: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+ int dimension(uint32 *dim) const { *dim = 0; return 0; }
+};
+
+/***************************** MultiLineString *******************************/
+
+class GMultiLineString: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int length(double *len) const;
+ int is_closed(int *closed) const;
+ int dimension(uint32 *dim) const { *dim = 1; return 0; }
+};
+
+/***************************** MultiPolygon *******************************/
+
+class GMultiPolygon: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int area(double *ar) const;
+ int centroid(String *result) const;
+ int dimension(uint32 *dim) const { *dim = 2; return 0; }
+// PointOnSurface
+};
+
+/***************************** GeometryCollection *******************************/
+
+class GGeometryCollection: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int num_geometries(uint32 *num) const;
+ int geometry_n(uint32 num, String *result) const;
+ int dimension(uint32 *dim) const;
+};
+
+#endif
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 673bc441b6b..8ccd7dbde68 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -422,7 +422,7 @@ static ulong get_access(TABLE *form, uint fieldnr)
{
ulong access_bits=0,bit;
char buff[2];
- String res(buff,sizeof(buff));
+ String res(buff,sizeof(buff),default_charset_info);
Field **pos;
for (pos=form->field+fieldnr, bit=1;
@@ -431,7 +431,7 @@ static ulong get_access(TABLE *form, uint fieldnr)
pos++ , bit<<=1)
{
(*pos)->val_str(&res,&res);
- if (toupper(res[0]) == 'Y')
+ if (my_toupper(system_charset_info, res[0]) == 'Y')
access_bits|= bit;
}
return access_bits;
@@ -649,7 +649,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(host,acl_user->host.hostname))
+ !my_strcasecmp(system_charset_info, host, acl_user->host.hostname))
{
acl_user->access=privileges;
if (mqh->bits & 1)
@@ -738,7 +738,8 @@ static void acl_update_db(const char *user, const char *host, const char *db,
!strcmp(user,acl_db->user))
{
if (!acl_db->host.hostname && !host[0] ||
- acl_db->host.hostname && !my_strcasecmp(host,acl_db->host.hostname))
+ acl_db->host.hostname &&
+ !my_strcasecmp(system_charset_info, host, acl_db->host.hostname))
{
if (!acl_db->db && !db[0] ||
acl_db->db && !strcmp(db,acl_db->db))
@@ -802,7 +803,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)
{
- casedn_str(tmp_db);
+ my_casedn_str(system_charset_info, tmp_db);
db=tmp_db;
}
key_length=(uint) (end-key);
@@ -866,7 +867,7 @@ exit:
}
-int wild_case_compare(const char *str,const char *wildstr)
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
{
reg3 int flag;
DBUG_ENTER("wild_case_compare");
@@ -877,7 +878,8 @@ int wild_case_compare(const char *str,const char *wildstr)
{
if (*wildstr == wild_prefix && wildstr[1])
wildstr++;
- if (toupper(*wildstr++) != toupper(*str++)) DBUG_RETURN(1);
+ if (my_toupper(cs, *wildstr++) !=
+ my_toupper(cs, *str++)) DBUG_RETURN(1);
}
if (! *wildstr ) DBUG_RETURN (*str != 0);
if (*wildstr++ == wild_one)
@@ -895,12 +897,12 @@ int wild_case_compare(const char *str,const char *wildstr)
char cmp;
if ((cmp= *wildstr) == wild_prefix && wildstr[1])
cmp=wildstr[1];
- cmp=toupper(cmp);
- while (*str && toupper(*str) != cmp)
+ cmp=my_toupper(cs, cmp);
+ while (*str && my_toupper(cs, *str) != cmp)
str++;
if (!*str) DBUG_RETURN (1);
}
- if (wild_case_compare(str,wildstr) == 0) DBUG_RETURN (0);
+ if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
} while (*str++);
DBUG_RETURN(1);
}
@@ -919,7 +921,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,acl_users.elements,0,0,
+ VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,HASH_CASE_INSENSITIVE));
if (!allow_all_hosts)
{
@@ -935,7 +937,8 @@ 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(acl_user->host.hostname,acl->hostname))
+ if (!my_strcasecmp(system_charset_info,
+ acl_user->host.hostname, acl->hostname))
break; // already stored
}
if (j == acl_wild_hosts.elements) // If new
@@ -1008,19 +1011,19 @@ bool check_change_password(THD *thd, const char *host, const char *user)
{
if (!initialized)
{
- send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */
+ send_error(thd, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */
return(1); /* purecov: inspected */
}
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
- my_strcasecmp(host,thd->host ? thd->host : thd->ip)))
+ my_strcasecmp(system_charset_info, host, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
return(1);
}
if (!thd->slave_thread && !thd->user[0])
{
- send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER);
+ send_error(thd, ER_PASSWORD_ANONYMOUS_USER);
return(1);
}
return(0);
@@ -1062,7 +1065,7 @@ bool change_password(THD *thd, const char *host, const char *user,
ACL_USER *acl_user;
if (!(acl_user= find_acl_user(host,user)))
{
- send_error(&thd->net, ER_PASSWORD_NO_MATCH);
+ send_error(thd, ER_PASSWORD_NO_MATCH);
VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(1);
}
@@ -1072,7 +1075,7 @@ bool change_password(THD *thd, const char *host, const char *user,
new_password))
{
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
- send_error(&thd->net,0); /* purecov: deadcode */
+ send_error(thd,0); /* purecov: deadcode */
DBUG_RETURN(1); /* purecov: deadcode */
}
get_salt_from_password(acl_user->salt,new_password);
@@ -1173,7 +1176,8 @@ 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(hostname,host->hostname)) ||
+ (hostname && !wild_case_compare(system_charset_info,
+ hostname,host->hostname)) ||
(ip && !wild_compare(ip,host->hostname)));
}
@@ -1196,8 +1200,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));
- table->field[1]->store(user,(uint) strlen(user));
+ table->field[0]->store(host,(uint) strlen(host), system_charset_info);
+ table->field[1]->store(user,(uint) strlen(user), system_charset_info);
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,0,
@@ -1207,7 +1211,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));
+ table->field[2]->store(new_password,(uint) strlen(new_password), system_charset_info);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1273,8 +1277,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);
- table->field[1]->store(combo.user.str,combo.user.length);
+ 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->file->index_init(0);
if (table->file->index_read(table->record[0],
(byte*) table->field[0]->ptr,0,
@@ -1294,17 +1298,17 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
goto end;
}
old_row_exists = 0;
- restore_record(table,2); // cp empty row from record[2]
- table->field[0]->store(combo.host.str,combo.host.length);
- table->field[1]->store(combo.user.str,combo.user.length);
- table->field[2]->store(password,(uint) strlen(password));
+ 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);
}
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));
+ table->field[2]->store(password,(uint) strlen(password), system_charset_info);
}
/* Update table columns with new privileges */
@@ -1317,7 +1321,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);
+ (*tmp_field)->store(&what, 1, system_charset_info);
}
rights=get_access(table,3);
DBUG_PRINT("info",("table->fields: %d",table->fields));
@@ -1326,31 +1330,31 @@ 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);
- table->field[25]->store("",0);
- table->field[26]->store("",0);
- table->field[27]->store("",0);
+ 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);
break;
case SSL_TYPE_X509:
- table->field[24]->store("X509",4);
- table->field[25]->store("",0);
- table->field[26]->store("",0);
- table->field[27]->store("",0);
+ 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);
break;
case SSL_TYPE_SPECIFIED:
- table->field[24]->store("SPECIFIED",9);
- table->field[25]->store("",0);
- table->field[26]->store("",0);
- table->field[27]->store("",0);
+ 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);
if (thd->lex.ssl_cipher)
table->field[25]->store(thd->lex.ssl_cipher,
- strlen(thd->lex.ssl_cipher));
+ strlen(thd->lex.ssl_cipher), system_charset_info);
if (thd->lex.x509_issuer)
table->field[26]->store(thd->lex.x509_issuer,
- strlen(thd->lex.x509_issuer));
+ strlen(thd->lex.x509_issuer), system_charset_info);
if (thd->lex.x509_subject)
table->field[27]->store(thd->lex.x509_subject,
- strlen(thd->lex.x509_subject));
+ strlen(thd->lex.x509_subject), system_charset_info);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
@@ -1447,9 +1451,9 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(-1);
}
- table->field[0]->store(combo.host.str,combo.host.length);
- table->field[1]->store(db,(uint) strlen(db));
- table->field[2]->store(combo.user.str,combo.user.length);
+ 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->file->index_init(0);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
HA_READ_KEY_EXACT))
@@ -1462,9 +1466,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);
- table->field[1]->store(db,(uint) strlen(db));
- table->field[2]->store(combo.user.str,combo.user.length);
+ 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);
}
else
{
@@ -1476,7 +1480,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); // set requested privileges
+ table->field [i]->store(&what,1, system_charset_info);// set requested privileges
}
rights=get_access(table,3);
rights=fix_rights_for_db(rights);
@@ -1557,13 +1561,14 @@ public:
tname= strdup_root(&memex,t);
if (lower_case_table_names)
{
- casedn_str(db);
- casedn_str(tname);
+ my_casedn_str(system_charset_info, db);
+ my_casedn_str(system_charset_info, 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,0,0,0, (hash_get_key) get_key_column,0,
+ (void) hash_init(&hash_columns,system_charset_info,
+ 0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
}
@@ -1585,8 +1590,8 @@ public:
}
if (lower_case_table_names)
{
- casedn_str(db);
- casedn_str(tname);
+ my_casedn_str(system_charset_info, db);
+ my_casedn_str(system_charset_info, tname);
}
key_length = ((uint) strlen(db) + (uint) strlen(user) +
(uint) strlen(tname) + 3);
@@ -1597,21 +1602,22 @@ public:
privs = fix_rights_for_table(privs);
cols = fix_rights_for_column(cols);
- (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
+ (void) hash_init(&hash_columns,system_charset_info,
+ 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));
- col_privs->field[1]->store(db,(uint) strlen(db));
- col_privs->field[2]->store(user,(uint) strlen(user));
- col_privs->field[3]->store(tname,(uint) strlen(tname));
+ 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);
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);
+ col_privs->field[4]->store("",0, system_charset_info);
col_privs->file->index_init(0);
if (col_privs->file->index_read(col_privs->record[0],
(byte*) col_privs->field[0]->ptr,
@@ -1667,7 +1673,6 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
char helping [NAME_LEN*2+USERNAME_LENGTH+3];
uint len;
GRANT_TABLE *grant_table,*found=0;
- safe_mutex_assert_owner(&LOCK_grant);
len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
for (grant_table=(GRANT_TABLE*) hash_search(&hash_tables,(byte*) helping,
@@ -1677,14 +1682,17 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
{
if (exact)
{
- if ((host && !my_strcasecmp(host,grant_table->host)) ||
+ if ((host &&
+ !my_strcasecmp(system_charset_info, host, grant_table->host)) ||
(ip && !strcmp(ip,grant_table->host)))
return grant_table;
}
else
{
- if ((host && !wild_case_compare(host,grant_table->host)) ||
- (ip && !wild_case_compare(ip,grant_table->host)))
+ if ((host && !wild_case_compare(system_charset_info,
+ host,grant_table->host)) ||
+ (ip && !wild_case_compare(system_charset_info,
+ ip,grant_table->host)))
found=grant_table; // Host ok
}
}
@@ -1711,10 +1719,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);
- table->field[1]->store(db,(uint) strlen(db));
- table->field[2]->store(combo.user.str,combo.user.length);
- table->field[3]->store(table_name,(uint) strlen(table_name));
+ 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);
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);
@@ -1731,7 +1739,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());
+ table->field[4]->store(xx->column.ptr(),xx->column.length(),system_charset_info);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
@@ -1745,9 +1753,9 @@ static int replace_column_table(GRANT_TABLE *g_t,
continue; /* purecov: inspected */
}
old_row_exists = 0;
- restore_record(table,2); // Get empty record
+ restore_record(table,2); // Get empty record
key_restore(table,key,0,key_length);
- table->field[4]->store(xx->column.ptr(),xx->column.length());
+ table->field[4]->store(xx->column.ptr(),xx->column.length(), system_charset_info);
}
else
{
@@ -1819,7 +1827,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));
+ String column_name(colum_name_buf,sizeof(colum_name_buf),system_charset_info);
privileges&= ~rights;
table->field[6]->store((longlong)
@@ -1875,7 +1883,6 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
int error=0;
ulong store_table_rights, store_col_rights;
DBUG_ENTER("replace_table_table");
- safe_mutex_assert_owner(&LOCK_grant);
strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS);
@@ -1890,10 +1897,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);
- table->field[1]->store(db,(uint) strlen(db));
- table->field[2]->store(combo.user.str,combo.user.length);
- table->field[3]->store(table_name,(uint) strlen(table_name));
+ 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);
store_record(table,1); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
@@ -1938,7 +1945,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
}
- table->field[4]->store(grantor,(uint) strlen(grantor));
+ table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
table->field[6]->store((longlong) store_table_rights);
table->field[7]->store((longlong) store_col_rights);
rights=fix_rights_for_table(store_table_rights);
@@ -1993,7 +2000,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
if (!initialized)
{
- send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: inspected */
+ send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: inspected */
return 1; /* purecov: inspected */
}
if (rights & ~TABLE_ACLS)
@@ -2059,7 +2066,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
if (!revoke_grant)
create_new_users= test_if_create_new_users(thd);
int result=0;
- pthread_mutex_lock(&LOCK_grant);
+ rw_wrlock(&LOCK_grant);
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
my_pthread_setspecific_ptr(THR_MALLOC,&memex);
@@ -2172,9 +2179,9 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
}
grant_option=TRUE;
my_pthread_setspecific_ptr(THR_MALLOC,old_root);
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
if (!result)
- send_ok(&thd->net);
+ send_ok(thd);
/* Tables are automatically closed */
DBUG_RETURN(result);
}
@@ -2192,14 +2199,14 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
if (!initialized)
{
- send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: tested */
- return 1; /* purecov: tested */
+ send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: tested */
+ return 1; /* purecov: tested */
}
if (lower_case_table_names && db)
{
strmov(tmp_db,db);
- casedn_str(tmp_db);
+ my_casedn_str(system_charset_info, tmp_db);
db=tmp_db;
}
@@ -2222,7 +2229,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
create_new_users= test_if_create_new_users(thd);
// go through users in user_list
- pthread_mutex_lock(&LOCK_grant);
+ rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
grant_version++;
@@ -2255,11 +2262,11 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
}
}
VOID(pthread_mutex_unlock(&acl_cache->lock));
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
close_thread_tables(thd);
if (!result)
- send_ok(&thd->net);
+ send_ok(thd);
DBUG_RETURN(result);
}
@@ -2288,7 +2295,8 @@ my_bool grant_init(THD *org_thd)
DBUG_ENTER("grant_init");
grant_option = FALSE;
- (void) hash_init(&hash_tables,0,0,0, (hash_get_key) get_grant_table,
+ (void) hash_init(&hash_tables,system_charset_info,
+ 0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
init_sql_alloc(&memex,1024,0);
@@ -2372,7 +2380,7 @@ void grant_reload(THD *thd)
// Locked tables are checked by acl_init and doesn't have to be checked here
- pthread_mutex_lock(&LOCK_grant);
+ rw_wrlock(&LOCK_grant);
grant_version++;
old_hash_tables=hash_tables;
old_grant_option = grant_option;
@@ -2390,7 +2398,7 @@ void grant_reload(THD *thd)
hash_free(&old_hash_tables);
free_root(&old_mem,MYF(0));
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
DBUG_VOID_RETURN;
}
@@ -2410,7 +2418,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (!want_access)
return 0; // ok
- pthread_mutex_lock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
for (table=tables; table ;table=table->next)
{
if (!(~table->grant.privilege & want_access))
@@ -2444,11 +2452,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
goto err; // impossible
}
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return 0;
err:
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
if (!no_errors) // Not a silent skip of table
{
const char *command="";
@@ -2470,7 +2478,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
command = "index";
else if (want_access & GRANT_ACL)
command = "grant";
- net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR,
+ net_printf(thd,ER_TABLEACCESS_DENIED_ERROR,
command,
thd->priv_user,
thd->host_or_ip,
@@ -2490,7 +2498,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name,
if (!want_access)
return 0; // Already checked
- pthread_mutex_lock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
// reload table if someone has modified any grants
@@ -2508,20 +2516,20 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name,
grant_column=column_hash_search(grant_table, name, length);
if (grant_column && !(~grant_column->rights & want_access))
{
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return 0;
}
#ifdef NOT_USED
if (show_tables && (grant_column || table->grant.privilege & COL_ACLS))
{
- pthread_mutex_unlock(&LOCK_grant); /* purecov: deadcode */
+ rw_unlock(&LOCK_grant); /* purecov: deadcode */
return 0; /* purecov: deadcode */
}
#endif
/* We must use my_printf_error() here! */
err:
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
if (!show_tables)
{
char command[128];
@@ -2549,7 +2557,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
if (!want_access)
return 0; // Already checked
- pthread_mutex_lock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
// reload table if someone has modified any grants
@@ -2572,12 +2580,12 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
if (!grant_column || (~grant_column->rights & want_access))
goto err;
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return 0;
/* We must use my_printf_error() here! */
err:
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
const char *command="";
if (want_access & SELECT_ACL)
@@ -2609,21 +2617,23 @@ bool check_grant_db(THD *thd,const char *db)
bool error=1;
len = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1;
- pthread_mutex_lock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < hash_tables.records ; idx++)
{
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(thd->host,grant_table->host) ||
- (thd->ip && !wild_case_compare(thd->ip,grant_table->host))))
+ (thd->host && !wild_case_compare(system_charset_info,
+ thd->host,grant_table->host) ||
+ (thd->ip && !wild_case_compare(system_charset_info,
+ thd->ip,grant_table->host))))
{
error=0; // Found match
break;
}
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return error;
}
@@ -2633,12 +2643,12 @@ bool check_grant_db(THD *thd,const char *db)
ulong get_table_grant(THD *thd, TABLE_LIST *table)
{
- uint privilege;
+ ulong privilege;
char *user = thd->priv_user;
const char *db = table->db ? table->db : thd->db;
GRANT_TABLE *grant_table;
- pthread_mutex_lock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
grant_table = table_hash_search(thd->host,thd->ip,db,user,
table->real_name,0);
table->grant.grant_table=grant_table; // Remember for column test
@@ -2646,7 +2656,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
if (grant_table)
table->grant.privilege|= grant_table->privs;
privilege= table->grant.privilege;
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return privilege;
}
@@ -2657,7 +2667,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
GRANT_COLUMN *grant_column;
ulong priv;
- pthread_mutex_lock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
// reload table if someone has modified any grants
if (table->grant.version != grant_version)
{
@@ -2679,7 +2689,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
else
priv=table->grant.privilege | grant_column->rights;
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return priv;
}
@@ -2714,7 +2724,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
LINT_INIT(acl_user);
if (!initialized)
{
- send_error(&(thd->net), ER_UNKNOWN_COM_ERROR);
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
DBUG_RETURN(-1);
}
if (!lex_user->host.str)
@@ -2738,7 +2748,7 @@ 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(lex_user->host.str,host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
break;
}
if (counter == acl_users.elements)
@@ -2748,7 +2758,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
DBUG_RETURN(-1);
}
- Item_string *field=new Item_string("",0);
+ Item_string *field=new Item_string("",0,system_charset_info);
List<Item> field_list;
field->name=buff;
field->max_length=1024;
@@ -2758,7 +2768,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (send_fields(thd,field_list,1))
DBUG_RETURN(-1);
- pthread_mutex_lock(&LOCK_grant);
+ rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
/* Add first global access grants */
@@ -2766,7 +2776,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));
+ String global(buff,sizeof(buff),system_charset_info);
global.length(0);
global.append("GRANT ",6);
@@ -2885,12 +2895,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
host="";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(lex_user->host.str,host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
want_access=acl_db->access;
if (want_access)
{
- String db(buff,sizeof(buff));
+ String db(buff,sizeof(buff),system_charset_info);
db.length(0);
db.append("GRANT ",6);
@@ -2944,12 +2954,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
host="";
if (!strcmp(lex_user->user.str,user) &&
- !my_strcasecmp(lex_user->host.str,host))
+ !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{
want_access=grant_table->privs;
if ((want_access | grant_table->cols) != 0)
{
- String global(buff,sizeof(buff));
+ String global(buff,sizeof(buff),system_charset_info);
global.length(0);
global.append("GRANT ",6);
@@ -3013,18 +3023,17 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
thd->packet.length()))
{
- error=-1;
+ error= -1;
break;
}
}
}
}
-
end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(error);
}
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 96bbd731882..f98eb0e0b26 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->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, 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->net, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name);
+ net_printf(thd, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name);
DBUG_RETURN(0);
}
// second parameter
if ((*param->item)->type() != Item::INT_ITEM ||
(*param->item)->val() < 0)
{
- net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, 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->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
DBUG_RETURN(0);
}
// if only one parameter was given, it will be the value of max_tree_elements
@@ -168,7 +168,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
MySQL removes any endspaces of a string, so we must take care only of
spaces in front of a string
*/
- for (; str != end && isspace(*str); str++) ;
+ for (; str != end && my_isspace(system_charset_info, *str); str++) ;
if (str == end)
return 0;
@@ -181,10 +181,10 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
else
info->negative = 0;
begin = str;
- for (; str != end && isdigit(*str); str++)
+ for (; str != end && my_isdigit(system_charset_info,*str); str++)
{
if (!info->integers && *str == '0' && (str + 1) != end &&
- isdigit(*(str + 1)))
+ my_isdigit(system_charset_info,*(str + 1)))
info->zerofill = 1; // could be a postnumber for example
info->integers++;
}
@@ -210,7 +210,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
str++;
if (*str != '-' && *str != '+')
return 0;
- for (str++; str != end && isdigit(*str); str++) ;
+ for (str++; str != end && my_isdigit(system_charset_info,*str); str++) ;
if (str == end)
{
info->is_float = 1; // we can't use variable decimals here
@@ -225,7 +225,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
info->ullval = (ulonglong) strtoull(begin, NULL, 10);
return 1;
}
- for (; str != end && isdigit(*str); str++)
+ for (; str != end && my_isdigit(system_charset_info,*str); str++)
info->decimals++;
if (str == end)
{
@@ -275,7 +275,7 @@ void free_string(String *s)
void field_str::add()
{
char buff[MAX_FIELD_WIDTH], *ptr;
- String s(buff, sizeof(buff)), *res;
+ String s(buff, sizeof(buff),default_charset_info), *res;
ulong length;
if (!(res = item->val_str(&s)))
@@ -314,10 +314,10 @@ void field_str::add()
{
if (res != &s)
s.copy(*res);
- if (!tree_search(&tree, (void*) &s)) // If not in tree
+ if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree
{
s.copy(); // slow, when SAFE_MALLOC is in use
- if (!tree_insert(&tree, (void*) &s, 0))
+ if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
@@ -349,7 +349,7 @@ void field_str::add()
if (length > max_length)
max_length = length;
- if (item->binary)
+ if (item->binary())
{
if (stringcmp(res, &min_arg) < 0)
min_arg.copy(*res);
@@ -387,8 +387,7 @@ void field_real::add()
if ((decs = decimals()) == NOT_FIXED_DEC)
{
- sprintf(buff, "%g", num);
- length = (uint) strlen(buff);
+ length= my_sprintf(buff, (buff, "%g", num));
if (rint(num) != num)
max_notzero_dec_len = 1;
}
@@ -397,11 +396,11 @@ void field_real::add()
#ifdef HAVE_SNPRINTF
buff[sizeof(buff)-1]=0; // Safety
snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num);
+ length = (uint) strlen(buff);
#else
- sprintf(buff, "%-.*f", (int) decs, num);
+ length= my_sprintf(buff, (buff, "%-.*f", (int) decs, num));
#endif
- length = (uint) strlen(buff);
// We never need to check further than this
end = buff + length - 1 - decs + max_notzero_dec_len;
@@ -416,7 +415,7 @@ void field_real::add()
if (room_in_tree)
{
- if (!(element = tree_insert(&tree, (void*) &num, 0)))
+ if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
@@ -469,7 +468,7 @@ void field_longlong::add()
if (room_in_tree)
{
- if (!(element = tree_insert(&tree, (void*) &num, 0)))
+ if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
@@ -523,7 +522,7 @@ void field_ulonglong::add()
if (room_in_tree)
{
- if (!(element = tree_insert(&tree, (void*) &num, 0)))
+ if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
{
room_in_tree = 0; // Remove tree, out of RAM ?
delete_tree(&tree);
@@ -578,8 +577,9 @@ bool analyse::end_of_records()
{
field_info **f = f_info;
char buff[MAX_FIELD_WIDTH];
- String *res, s_min(buff, sizeof(buff)), s_max(buff, sizeof(buff)),
- ans(buff, sizeof(buff));
+ String *res, s_min(buff, sizeof(buff),default_charset_info),
+ s_max(buff, sizeof(buff),default_charset_info),
+ ans(buff, sizeof(buff),default_charset_info);
for (; f != f_end; f++)
{
@@ -625,14 +625,14 @@ bool analyse::end_of_records()
((*f)->tree.elements_in_tree * 3 - 1 + 6))))
{
char tmp[331]; //331, because one double prec. num. can be this long
- String tmp_str(tmp, sizeof(tmp));
+ String tmp_str(tmp, sizeof(tmp),default_charset_info);
TREE_INFO tree_info;
tree_info.str = &tmp_str;
tree_info.found = 0;
tree_info.item = (*f)->item;
- tmp_str.set("ENUM(", 5);
+ tmp_str.set("ENUM(", 5,default_charset_info);
tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
left_root_right);
tmp_str.append(')');
@@ -738,7 +738,7 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows)
{
if (must_be_blob)
{
- if (item->binary)
+ if (item->binary())
answer->append("TINYBLOB", 8);
else
answer->append("TINYTEXT", 8);
@@ -756,21 +756,21 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows)
}
else if (max_length < (1L << 16))
{
- if (item->binary)
+ if (item->binary())
answer->append("BLOB", 4);
else
answer->append("TEXT", 4);
}
else if (max_length < (1L << 24))
{
- if (item->binary)
+ if (item->binary())
answer->append("MEDIUMBLOB", 10);
else
answer->append("MEDIUMTEXT", 10);
}
else
{
- if (item->binary)
+ if (item->binary())
answer->append("LONGBLOB", 8);
else
answer->append("LONGTEXT", 8);
@@ -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));
+ 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);
+ s.set(*element, info->item->decimals, current_thd->thd_charset);
info->str->append(s);
info->str->append('\'');
return 0;
@@ -915,14 +915,14 @@ int collect_longlong(longlong *element,
TREE_INFO *info)
{
char buff[MAX_FIELD_WIDTH];
- String s(buff, sizeof(buff));
+ String s(buff, sizeof(buff),default_charset_info);
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
- s.set(*element);
+ s.set(*element,default_charset_info);
info->str->append(s);
info->str->append('\'');
return 0;
@@ -934,14 +934,14 @@ int collect_ulonglong(ulonglong *element,
TREE_INFO *info)
{
char buff[MAX_FIELD_WIDTH];
- String s(buff, sizeof(buff));
+ String s(buff, sizeof(buff),default_charset_info);
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
- s.set(*element);
+ s.set(*element,default_charset_info);
info->str->append(s);
info->str->append('\'');
return 0;
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index 1c60d0c150f..ada46374a15 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -110,11 +110,12 @@ class field_str :public field_info
EV_NUM_INFO ev_num_info;
public:
- field_str(Item* a, analyse* b) :field_info(a,b), min_arg(""),
- max_arg(""), sum(0),
+ field_str(Item* a, analyse* b) :field_info(a,b),
+ min_arg("",default_charset_info),
+ max_arg("",default_charset_info), sum(0),
must_be_blob(0), was_zero_fill(0),
was_maybe_zerofill(0), can_be_still_num(1)
- { init_tree(&tree, 0, 0, sizeof(String), a->binary ?
+ { init_tree(&tree, 0, 0, sizeof(String), a->binary() ?
(qsort_cmp2) stringcmp2 : (qsort_cmp2) sortcmp2,
0, (tree_element_free) free_string, NULL); };
@@ -127,10 +128,10 @@ public:
String *avg(String *s, ha_rows rows)
{
if (!(rows - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
s->set((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
- DEC_IN_AVG);
+ DEC_IN_AVG,my_thd_charset);
return s;
}
friend int collect_string(String *element, element_count count,
@@ -159,26 +160,34 @@ public:
void add();
void get_opt_type(String*, ha_rows);
- String *get_min_arg(String *s) { s->set(min_arg, item->decimals); return s; }
- String *get_max_arg(String *s) { s->set(max_arg, item->decimals); return s; }
+ String *get_min_arg(String *s)
+ {
+ s->set(min_arg, item->decimals,my_thd_charset);
+ return s;
+ }
+ String *get_max_arg(String *s)
+ {
+ s->set(max_arg, item->decimals,my_thd_charset);
+ return s;
+ }
String *avg(String *s, ha_rows rows)
{
if (!(rows - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
- s->set(((double)sum / (double) (rows - nulls)), item->decimals);
+ s->set(((double)sum / (double) (rows - nulls)), item->decimals,my_thd_charset);
return s;
}
String *std(String *s, ha_rows rows)
{
double tmp = ulonglong2double(rows);
if (!(tmp - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
{
double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
(tmp - nulls));
- s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals);
+ s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals,my_thd_charset);
}
return s;
}
@@ -205,26 +214,26 @@ public:
void add();
void get_opt_type(String*, ha_rows);
- String *get_min_arg(String *s) { s->set(min_arg); return s; }
- String *get_max_arg(String *s) { s->set(max_arg); return s; }
+ String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
+ String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
String *avg(String *s, ha_rows rows)
{
if (!(rows - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
- s->set(((double) sum / (double) (rows - nulls)), DEC_IN_AVG);
+ s->set(((double) sum / (double) (rows - nulls)), DEC_IN_AVG,my_thd_charset);
return s;
}
String *std(String *s, ha_rows rows)
{
double tmp = ulonglong2double(rows);
if (!(tmp - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
{
double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
(tmp - nulls));
- s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG);
+ s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
}
return s;
}
@@ -249,28 +258,28 @@ public:
(qsort_cmp2) compare_ulonglong2, 0, NULL, NULL); }
void add();
void get_opt_type(String*, ha_rows);
- String *get_min_arg(String *s) { s->set(min_arg); return s; }
- String *get_max_arg(String *s) { s->set(max_arg); return s; }
+ String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
+ String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
String *avg(String *s, ha_rows rows)
{
if (!(rows - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
s->set((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
- DEC_IN_AVG);
+ DEC_IN_AVG,my_thd_charset);
return s;
}
String *std(String *s, ha_rows rows)
{
double tmp = ulonglong2double(rows);
if (!(tmp - nulls))
- s->set((double) 0.0, 1);
+ s->set((double) 0.0, 1,my_thd_charset);
else
{
double tmp2 = ((ulonglong2double(sum_sqr) -
ulonglong2double(sum * sum) / (tmp - nulls)) /
(tmp - nulls));
- s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG);
+ s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
}
return s;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 032882080ff..59310fb00de 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -49,7 +49,8 @@ extern "C" byte *table_cache_key(const byte *record,uint *length,
void table_cache_init(void)
{
- VOID(hash_init(&open_cache,table_cache_size+16,0,0,table_cache_key,
+ VOID(hash_init(&open_cache,system_charset_info,
+ table_cache_size+16,0,0,table_cache_key,
(hash_free_key) free_cache_entry,0));
mysql_rm_tmp_tables();
}
@@ -195,34 +196,36 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
}
-/******************************************************************************
-** Send name and type of result to client.
-** Sum fields has table name empty and field_name.
-** flag is a bit mask with the following functions:
-** 1 send number of rows
-** 2 send default values
-** 4 Don't convert field names
-******************************************************************************/
+/*
+ Send name and type of result to client converted to a given char set
+
+ SYNOPSIS
+ send_convert_fields()
+ THD Thread data object
+ list List of items to send to client
+ convert object used to convertation to another character set
+ flag Bit mask with the following functions:
+ 2 send default values
+ 4 Don't convert field names
+
+ DESCRIPTION
+ Sum fields has table name empty and field_name.
+
+ RETURN VALUES
+ 0 ok
+ 1 Error (Note that in this case the error is not sent to the client)
+*/
bool
-send_fields(THD *thd,List<Item> &list,uint flag)
+send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag)
{
List_iterator_fast<Item> it(list);
Item *item;
char buff[80];
- CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set;
- DBUG_ENTER("send_fields");
-
- String tmp((char*) buff,sizeof(buff)),*res,*packet= &thd->packet;
+ String tmp((char*) buff,sizeof(buff),default_charset_info);
+ String *res,*packet= &thd->packet;
+ DBUG_ENTER("send_convert_fields");
- if (thd->fatal_error) // We have got an error
- goto err;
-
- if (flag & 1)
- { // Packet with number of elements
- char *pos=net_store_length(buff,(uint) list.elements);
- (void) my_net_write(&thd->net, buff,(uint) (pos-buff));
- }
while ((item=it++))
{
char *pos;
@@ -230,19 +233,30 @@ send_fields(THD *thd,List<Item> &list,uint flag)
item->make_field(&field);
packet->length(0);
- if (convert)
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
- if (convert->store(packet,field.table_name,
+ if (convert->store(packet,field.db_name,
+ (uint) strlen(field.db_name)) ||
+ convert->store(packet,field.table_name,
(uint) strlen(field.table_name)) ||
+ convert->store(packet,field.org_table_name,
+ (uint) strlen(field.org_table_name)) ||
convert->store(packet,field.col_name,
(uint) strlen(field.col_name)) ||
+ convert->store(packet,field.org_col_name,
+ (uint) strlen(field.org_col_name)) ||
packet->realloc(packet->length()+10))
goto err;
+ }
+ else
+ {
+ if (convert->store(packet,field.table_name,
+ (uint) strlen(field.table_name)) ||
+ convert->store(packet,field.col_name,
+ (uint) strlen(field.col_name)) ||
+ packet->realloc(packet->length()+10))
+ goto err;
}
- else if (net_store_data(packet,field.table_name) ||
- net_store_data(packet,field.col_name) ||
- packet->realloc(packet->length()+10))
- goto err; /* purecov: inspected */
pos= (char*) packet->ptr()+packet->length();
if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
@@ -266,16 +280,162 @@ send_fields(THD *thd,List<Item> &list,uint flag)
if (net_store_null(packet))
goto err;
}
- else if (net_store_data(packet,res->ptr(),res->length()))
+ else if (convert->store(packet,res->ptr(),res->length()))
goto err;
}
if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
break; /* purecov: inspected */
}
- send_eof(&thd->net,1);
DBUG_RETURN(0);
- err:
- send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */
+
+err:
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Send name and type of result to client.
+
+ SYNOPSIS
+ send_non_convert_fields()
+ THD Thread data object
+ list List of items to send to client
+ flag Bit mask with the following functions:
+ 2 send default values
+ 4 Don't convert field names
+
+ DESCRIPTION
+ Sum fields has table name empty and field_name.
+
+ RETURN VALUES
+ 0 ok
+ 1 Error
+*/
+
+bool
+send_non_convert_fields(THD *thd,List<Item> &list,uint flag)
+{
+ List_iterator_fast<Item> it(list);
+ Item *item;
+ char buff[80];
+
+ String tmp((char*) buff,sizeof(buff),default_charset_info);
+ String *res,*packet= &thd->packet;
+
+ while ((item=it++))
+ {
+ char *pos;
+ Send_field field;
+ item->make_field(&field);
+ packet->length(0);
+
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ if (net_store_data(packet,field.db_name) ||
+ net_store_data(packet,field.table_name) ||
+ net_store_data(packet,field.org_table_name) ||
+ net_store_data(packet,field.col_name) ||
+ net_store_data(packet,field.org_col_name) ||
+ packet->realloc(packet->length()+10))
+ return 1;
+ }
+ else
+ {
+ if (net_store_data(packet,field.table_name) ||
+ net_store_data(packet,field.col_name) ||
+ packet->realloc(packet->length()+10))
+ return 1;
+ }
+
+ pos= (char*) packet->ptr()+packet->length();
+
+ if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
+ {
+ packet->length(packet->length()+9);
+ pos[0]=3; int3store(pos+1,field.length);
+ pos[4]=1; pos[5]=field.type;
+ pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals;
+ }
+ else
+ {
+ packet->length(packet->length()+10);
+ pos[0]=3; int3store(pos+1,field.length);
+ pos[4]=1; pos[5]=field.type;
+ pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals;
+ }
+ if (flag & 2)
+ { // Send default value
+ if (!(res=item->val_str(&tmp)))
+ {
+ if (net_store_null(packet))
+ return 1;
+ }
+ else if (net_store_data(packet,res->ptr(),res->length()))
+ return 1;
+ }
+ if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length()))
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ Send name and type of result to client.
+
+ SYNOPSIS
+ send_fields()
+ THD Thread data object
+ list List of items to send to client
+ convert object used to convertation to another character set
+ flag Bit mask with the following functions:
+ 1 send number of rows
+ 2 send default values
+ 4 Don't convert field names
+
+ DESCRIPTION
+ Sum fields has table name empty and field_name.
+ Uses send_fields_convert() and send_fields() depending on
+ if we have an active character set convert or not.
+
+ RETURN VALUES
+ 0 ok
+ 1 Error (Note that in this case the error is not sent to the client)
+*/
+
+bool
+send_fields(THD *thd, List<Item> &list, uint flag)
+{
+ char buff[9]; // Big enough for store_length
+ CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set;
+ DBUG_ENTER("send_fields");
+
+ if (thd->fatal_error) // We have got an error
+ goto err;
+
+ if (flag & 1)
+ { // Packet with number of elements
+ char *pos=net_store_length(buff, (uint) list.elements);
+ (void) my_net_write(&thd->net, buff,(uint) (pos-buff));
+ }
+
+ /*
+ Avoid check conditions on convert() for each field
+ by having two different functions
+ */
+ if (convert)
+ {
+ if (send_convert_fields(thd, list, convert, flag))
+ goto err;
+ }
+ else if (send_non_convert_fields(thd, list, flag))
+ goto err;
+
+ send_eof(thd);
+ DBUG_RETURN(0);
+
+err:
+ send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
@@ -808,7 +968,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
{
if (table->key_length == key_length &&
!memcmp(table->table_cache_key,key,key_length) &&
- !my_strcasecmp(table->table_name,alias))
+ !my_strcasecmp(system_charset_info,table->table_name,alias))
goto reset;
}
my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias);
@@ -1300,9 +1460,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
}
}
pthread_mutex_unlock(&LOCK_open);
- thd->net.last_error[0]=0; // Clear error message
- thd->net.last_errno=0;
- error=0;
+ thd->clear_error(); // Clear error message
+ error= 0;
if (openfrm(path,alias,
(uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX |
HA_TRY_READ_ONLY),
@@ -1312,8 +1471,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
(entry->file->is_crashed() && entry->file->check_and_repair(thd)))
{
/* Give right error message */
- thd->net.last_error[0]=0;
- thd->net.last_errno=0;
+ thd->clear_error();
my_error(ER_NOT_KEYFILE, MYF(0), name, my_errno);
sql_print_error("Error: Couldn't repair table: %s.%s",db,name);
if (entry->file)
@@ -1322,8 +1480,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
}
else
{
- thd->net.last_error[0]=0; // Clear error message
- thd->net.last_errno=0;
+ thd->clear_error(); // Clear error message
}
pthread_mutex_lock(&LOCK_open);
unlock_table_name(thd,&table_list);
@@ -1649,14 +1806,17 @@ 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(field->field_name, name))
+ if (!my_strcasecmp(system_charset_info, field->field_name, name))
goto found;
}
}
- if (allow_rowid && !my_strcasecmp(name,"_rowid") &&
+ if (allow_rowid &&
+ !my_strcasecmp(system_charset_info, name, "_rowid") &&
(field=table->rowid_field))
goto found;
return (Field*) 0;
@@ -1679,9 +1839,30 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
return field;
}
+// Special Field pointer for find_field_in_tables returning
+const Field *not_found_field= (Field*) 0x1;
+/*
+ Find field in table list.
+
+ SYNOPSIS
+ find_field_in_tables()
+ thd - pointer to current thread structure
+ item - field item that should be found
+ tables - tables for scaning
+ report_error - if FALSE then do not report error if item not found and
+ return not_found_field;
+
+ RETURN VALUES
+ 0 - field is not found or field is not unique, error message is
+ reported
+ not_found_field - function was called with report_error == FALSE and
+ field if not found, no error message reported
+ found field
+*/
Field *
-find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
+find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
+ bool report_error)
{
Field *found=0;
const char *db=item->db_name;
@@ -1718,7 +1899,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
}
if (found)
return found;
- if (!found_table)
+ if (!found_table && report_error)
{
char buff[NAME_LEN*2+1];
if (db)
@@ -1726,12 +1907,18 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
table_name=buff;
}
- my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),table_name,
- thd->where);
+ if (report_error)
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ table_name, thd->where);
+ else
+ return (Field*) not_found_field;
}
else
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- item->full_name(),thd->where);
+ if (report_error)
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
+ item->full_name(),thd->where);
+ else
+ return (Field*) not_found_field;
return (Field*) 0;
}
bool allow_rowid= tables && !tables->next; // Only one table
@@ -1757,13 +1944,42 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
}
if (found)
return found;
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
- MYF(0),item->full_name(),thd->where);
+ if (report_error)
+ my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
+ MYF(0), item->full_name(), thd->where);
+ else
+ return (Field*) not_found_field;
return (Field*) 0;
}
+// Special Item pointer for find_item_in_list returning
+const Item **not_found_item= (const Item**) 0x1;
+
+/*
+ Find Item in list of items (find_field_in_tables analog)
+
+ SYNOPSIS
+ find_item_in_list()
+ find - item to find
+ items - list of items
+ report_error
+ REPORT_ALL_ERRORS - report errors, return 0 if error
+ REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0
+ IGNORE_ERRORS - do not report errors, return 0 if error
+
+ RETURN VALUES
+ 0 - item is not found or item is not unique, error message is
+ reported
+ not_found_item - function was called with report_error ==
+ REPORT_EXCEPT_NOT_FOUND and item if not found, no error
+ message reported
+ found field
+
+*/
+
Item **
-find_item_in_list(Item *find,List<Item> &items)
+find_item_in_list(Item *find, List<Item> &items,
+ find_item_error_report_type report_error)
{
List_iterator<Item> li(items);
Item **found=0,*item;
@@ -1779,7 +1995,8 @@ find_item_in_list(Item *find,List<Item> &items)
{
if (field_name && item->type() == Item::FIELD_ITEM)
{
- if (!my_strcasecmp(((Item_field*) item)->name,field_name))
+ if (!my_strcasecmp(system_charset_info,
+ ((Item_field*) item)->name,field_name))
{
if (!table_name)
{
@@ -1787,7 +2004,7 @@ find_item_in_list(Item *find,List<Item> &items)
{
if ((*found)->eq(item,0))
continue; // Same field twice (Access?)
- if (current_thd->where)
+ if (report_error != IGNORE_ERRORS)
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
find->full_name(), current_thd->where);
return (Item**) 0;
@@ -1802,17 +2019,25 @@ find_item_in_list(Item *find,List<Item> &items)
}
}
else if (!table_name && (item->eq(find,0) ||
- find->name &&
- !my_strcasecmp(item->name,find->name)))
+ find->name &&
+ !my_strcasecmp(system_charset_info,
+ item->name,find->name)))
{
found=li.ref();
break;
}
}
- if (!found && current_thd->where)
- my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- find->full_name(),current_thd->where);
- return found;
+ if (found)
+ return found;
+ else if (report_error != REPORT_EXCEPT_NOT_FOUND)
+ {
+ if (report_error == REPORT_ALL_ERRORS)
+ my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
+ find->full_name(), current_thd->where);
+ return (Item **) 0;
+ }
+ else
+ return (Item **) not_found_item;
}
/****************************************************************************
@@ -1852,7 +2077,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
}
else
{
- if (item->fix_fields(thd,tables))
+ if (item->fix_fields(thd, tables, it.ref()))
DBUG_RETURN(-1); /* purecov: inspected */
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
sum_func_list)
@@ -2005,7 +2230,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
if (*conds)
{
thd->where="where clause";
- if ((*conds)->fix_fields(thd,tables))
+ if ((*conds)->fix_fields(thd, tables, conds))
DBUG_RETURN(1);
}
@@ -2016,7 +2241,7 @@ 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))
+ if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
DBUG_RETURN(1);
thd->cond_count++;
@@ -2044,7 +2269,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
// TODO: This could be optimized to use hashed names if t2 had a hash
for (j=0 ; j < t2->fields ; j++)
{
- if (!my_strcasecmp(t1->field[i]->field_name,
+ if (!my_strcasecmp(system_charset_info,
+ t1->field[i]->field_name,
t2->field[j]->field_name))
{
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
@@ -2093,7 +2319,7 @@ fill_record(List<Item> &fields,List<Item> &values)
while ((field=(Item_field*) f++))
{
value=v++;
- if (value->save_in_field(field->field))
+ if (value->save_in_field(field->field) > 0)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2111,7 +2337,7 @@ fill_record(Field **ptr,List<Item> &values)
while ((field = *ptr++))
{
value=v++;
- if (value->save_in_field(field))
+ if (value->save_in_field(field) == 1)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2120,39 +2346,41 @@ fill_record(Field **ptr,List<Item> &values)
static void mysql_rm_tmp_tables(void)
{
- uint idx;
- char filePath[FN_REFLEN];
+ uint i, idx;
+ char filePath[FN_REFLEN], *tmpdir;
MY_DIR *dirp;
FILEINFO *file;
DBUG_ENTER("mysql_rm_tmp_tables");
+ for (i=0; i<=mysql_tmpdir_list.max; i++)
+ {
+ tmpdir=mysql_tmpdir_list.list[i];
/* See if the directory exists */
- if (!(dirp = my_dir(mysql_tmpdir,MYF(MY_WME | MY_DONT_SORT))))
- DBUG_VOID_RETURN; /* purecov: inspected */
+ if (!(dirp = my_dir(tmpdir,MYF(MY_WME | MY_DONT_SORT))))
+ continue;
- /*
- ** Remove all SQLxxx tables from directory
- */
+ /* Remove all SQLxxx tables from directory */
for (idx=2 ; idx < (uint) dirp->number_off_files ; idx++)
{
file=dirp->dir_entry+idx;
if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length))
{
- sprintf(filePath,"%s%s",mysql_tmpdir,file->name); /* purecov: inspected */
- VOID(my_delete(filePath,MYF(MY_WME))); /* purecov: inspected */
+ sprintf(filePath,"%s%s",tmpdir,file->name);
+ VOID(my_delete(filePath,MYF(MY_WME)));
}
}
my_dirend(dirp);
+ }
DBUG_VOID_RETURN;
}
/*
-** CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
-** the proper arguments. This isn't very fast but it should work for most
-** cases.
-** One should normally create all indexes with CREATE TABLE or ALTER TABLE.
+ CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with
+ the proper arguments. This isn't very fast but it should work for most
+ cases.
+ One should normally create all indexes with CREATE TABLE or ALTER TABLE.
*/
int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
@@ -2164,6 +2392,8 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
+ /* TODO: Fix to use database character set */
+ create_info.table_charset=default_charset_info;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, (ORDER*)0, FALSE,
@@ -2180,6 +2410,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
DBUG_ENTER("mysql_drop_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
+ create_info.table_charset=default_charset_info;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, (ORDER*)0, FALSE,
@@ -2279,10 +2510,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
DBUG_RETURN(result);
}
-int setup_ftfuncs(THD *thd)
+int setup_ftfuncs(SELECT_LEX *select_lex)
{
- List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list),
- lj(thd->lex.select->ftfunc_list);
+ List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)),
+ lj(*(select_lex->ftfunc_list));
Item_func_match *ftf, *ftf2;
while ((ftf=li++))
@@ -2301,11 +2532,11 @@ int setup_ftfuncs(THD *thd)
}
-int init_ftfuncs(THD *thd, bool no_order)
+int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order)
{
- if (thd->lex.select->ftfunc_list.elements)
+ if (select_lex->ftfunc_list->elements)
{
- List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list);
+ List_iterator<Item_func_match> li(*(select_lex->ftfunc_list));
Item_func_match *ifm;
DBUG_PRINT("info",("Performing FULLTEXT search"));
thd->proc_info="FULLTEXT initialization";
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 64c62345182..ef584f4364e 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -278,6 +278,21 @@ TODO list:
- Move MRG_MYISAM table type processing to handlers, something like:
tables_used->table->file->register_used_filenames(callback,
first_argument);
+ - Make derived tables cachable.
+ - QC improvement suggested by Monty:
+ - Add a counter in open_table() for how many MERGE (ISAM or MyISAM)
+ tables are cached in the table cache.
+ (This will be trivial when we have the new table cache in place I
+ have been working on)
+ - After this we can add the following test around the for loop in
+ is_cacheable::
+
+ if (thd->temp_tables || global_merge_table_count)
+
+ - Another option would be to set thd->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)
*/
#include "mysql_priv.h"
@@ -895,8 +910,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Test if the query is a SELECT
(pre-space is removed in dispatch_command)
*/
- if (toupper(sql[0]) != 'S' || toupper(sql[1]) != 'E' ||
- toupper(sql[2]) !='L')
+ if (my_toupper(system_charset_info, sql[0]) != 'S' ||
+ my_toupper(system_charset_info, sql[1]) != 'E' ||
+ my_toupper(system_charset_info,sql[2]) !='L')
{
DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
goto err;
@@ -1383,16 +1399,16 @@ ulong Query_cache::init_cache()
DUMP(this);
- VOID(hash_init(&queries,def_query_hash_size, 0, 0,
+ VOID(hash_init(&queries,system_charset_info,def_query_hash_size, 0, 0,
query_cache_query_get_key, 0, 0));
#ifndef FN_NO_CASE_SENCE
- VOID(hash_init(&tables,def_table_hash_size, 0, 0,
+ VOID(hash_init(&tables,system_charset_info,def_table_hash_size, 0, 0,
query_cache_table_get_key, 0, 0));
#else
// windows, OS/2 or other case insensitive file names work around
- VOID(hash_init(&tables,def_table_hash_size, 0, 0,
+ VOID(hash_init(&tables,system_charset_info,def_table_hash_size, 0, 0,
query_cache_table_get_key, 0,
- (lower_case_table_names?0:HASH_CASE_INSENSITIVE)));
+ (lower_case_table_names?0:HASH_CASE_INSENSITIVE)));
#endif
queries_in_cache = 0;
@@ -2439,14 +2455,14 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
if (lex->sql_command == SQLCOM_SELECT &&
(thd->variables.query_cache_type == 1 ||
- (thd->variables.query_cache_type == 2 && (lex->select->options &
+ (thd->variables.query_cache_type == 2 && (lex->select_lex.options &
OPTION_TO_QUERY_CACHE))) &&
thd->safe_to_cache_query)
{
my_bool has_transactions = 0;
DBUG_PRINT("qcache", ("options %lx %lx, type %u",
OPTION_TO_QUERY_CACHE,
- lex->select->options,
+ lex->select_lex.options,
(int) thd->variables.query_cache_type));
for (; tables_used; tables_used= tables_used->next)
@@ -2493,7 +2509,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
("not interesting query: %d or not cacheable, options %lx %lx, type %u",
(int) lex->sql_command,
OPTION_TO_QUERY_CACHE,
- lex->select->options,
+ lex->select_lex.options,
(int) thd->variables.query_cache_type));
DBUG_RETURN(0);
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a5f14a507f7..e3ee0fb9f72 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -79,14 +79,15 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions
****************************************************************************/
-THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
- insert_id_used(0),rand_used(0),in_lock_tables(0),
- global_read_lock(0),bootstrap(0)
+THD::THD():user_time(0), fatal_error(0),
+ last_insert_id_used(0),
+ insert_id_used(0), rand_used(0), in_lock_tables(0),
+ global_read_lock(0), bootstrap(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=0;
+ query_start_used=safe_to_cache_query=prepare_command=0;
db_length=query_length=col_access=0;
query_error=0;
next_insert_id=last_insert_id=0;
@@ -96,13 +97,16 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
tmp_table=0;
lock=locked_tables=0;
used_tables=0;
- cuted_fields=sent_row_count=0L;
+ cuted_fields= sent_row_count= current_stmt_id= 0L;
start_time=(time_t) 0;
current_linfo = 0;
slave_thread = 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;
#ifndef DBUG_OFF
dbug_sentry=THD_SENTRY_MAGIC;
@@ -135,10 +139,22 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
/* 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, USER_VARS_HASH_SIZE, 0, 0,
+ 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);
+
+ /* Prepared statements */
+ last_prepared_stmt= 0;
+ init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT),
+ (qsort_cmp2) compare_prep_stmt, 1,
+ (tree_element_free) free_prep_stmt, 0);
+
#ifdef USING_TRANSACTIONS
bzero((char*) &transaction,sizeof(transaction));
if (opt_using_transactions)
@@ -270,7 +286,10 @@ THD::~THD()
safeFree(db);
safeFree(ip);
free_root(&mem_root,MYF(0));
+ 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
@@ -320,8 +339,7 @@ void THD::awake(bool prepare_to_die)
bool THD::store_globals()
{
if (my_pthread_setspecific_ptr(THR_THD, this) ||
- my_pthread_setspecific_ptr(THR_MALLOC, &mem_root) ||
- my_pthread_setspecific_ptr(THR_NET, &net))
+ my_pthread_setspecific_ptr(THR_MALLOC, &mem_root))
return 1;
mysys_var=my_thread_var;
dbug_thread_id=my_thread_id();
@@ -417,6 +435,28 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length)
return new_table;
}
+int THD::send_explain_fields(select_result *result)
+{
+ List<Item> field_list;
+ Item *item;
+ field_list.push_back(new Item_int("id",0,3));
+ field_list.push_back(new Item_empty_string("select_type",19));
+ field_list.push_back(new Item_empty_string("table",NAME_LEN));
+ field_list.push_back(new Item_empty_string("type",10));
+ field_list.push_back(item=new Item_empty_string("possible_keys",
+ NAME_LEN*MAX_KEY));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_int("key_len",0,3));
+ item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("ref",
+ NAME_LEN*MAX_REF_PARTS));
+ item->maybe_null=1;
+ field_list.push_back(new Item_real("rows",0.0,0,10));
+ field_list.push_back(new Item_empty_string("Extra",255));
+ return (result->send_fields(field_list,1));
+}
#ifdef SIGNAL_WITH_VIO_CLOSE
void THD::close_active_vio()
@@ -430,6 +470,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
*****************************************************************************/
@@ -439,8 +488,10 @@ select_result::select_result()
thd=current_thd;
}
-static String default_line_term("\n"),default_escaped("\\"),
- default_field_term("\t");
+static String
+ default_line_term("\n",default_charset_info),
+ default_escaped("\\",default_charset_info),
+ default_field_term("\t",default_charset_info);
sql_exchange::sql_exchange(char *name,bool flag)
:file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0)
@@ -465,9 +516,9 @@ bool select_send::send_data(List<Item> &items)
String *packet= &thd->packet;
DBUG_ENTER("send_data");
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
packet->length(0); // Reset packet
@@ -477,13 +528,19 @@ bool select_send::send_data(List<Item> &items)
if (item->send(thd, packet))
{
packet->free(); // Free used
- my_error(ER_OUT_OF_RESOURCES,MYF(0));
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
DBUG_RETURN(1);
}
}
thd->sent_row_count++;
- bool error=my_net_write(&thd->net,(char*) packet->ptr(),packet->length());
- DBUG_RETURN(error);
+ if (!thd->net.report_error)
+ {
+ DBUG_RETURN(my_net_write(&thd->net,
+ (char*) packet->ptr(),
+ packet->length()));
+ }
+ else
+ DBUG_RETURN(1);
}
bool select_send::send_eof()
@@ -493,8 +550,13 @@ bool select_send::send_eof()
{
mysql_unlock_tables(thd, thd->lock); thd->lock=0;
}
- ::send_eof(&thd->net);
- return 0;
+ if (!thd->net.report_error)
+ {
+ ::send_eof(thd);
+ return 0;
+ }
+ else
+ return 1;
}
@@ -515,11 +577,12 @@ select_export::~select_export()
}
int
-select_export::prepare(List<Item> &list)
+select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
char path[FN_REFLEN];
uint option=4;
bool blob_flag=0;
+ unit= u;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
option|=1; // Force use of db directory
#endif
@@ -529,7 +592,7 @@ select_export::prepare(List<Item> &list)
option);
if (!access(path,F_OK))
{
- my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
+ my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
return 1;
}
/* Create the file world readable */
@@ -583,12 +646,12 @@ bool select_export::send_data(List<Item> &items)
DBUG_ENTER("send_data");
char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH];
bool space_inited=0;
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
tmp.length(0);
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
row_count++;
@@ -715,9 +778,9 @@ err:
}
-void select_export::send_error(uint errcode,const char *err)
+void select_export::send_error(uint errcode, const char *err)
{
- ::send_error(&thd->net,errcode,err);
+ my_message(errcode, err, MYF(0));;
(void) end_io_cache(&cache);
(void) my_close(file,MYF(0));
file= -1;
@@ -729,10 +792,8 @@ bool select_export::send_eof()
int error=test(end_io_cache(&cache));
if (my_close(file,MYF(MY_WME)))
error=1;
- if (error)
- ::send_error(&thd->net);
- else
- ::send_ok(&thd->net,row_count);
+ if (!error)
+ ::send_ok(thd,row_count);
file= -1;
return error;
}
@@ -754,9 +815,11 @@ select_dump::~select_dump()
}
int
-select_dump::prepare(List<Item> &list __attribute__((unused)))
+select_dump::prepare(List<Item> &list __attribute__((unused)),
+ SELECT_LEX_UNIT *u)
{
uint option=4;
+ unit= u;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
option|=1; // Force use of db directory
#endif
@@ -790,19 +853,19 @@ bool select_dump::send_data(List<Item> &items)
{
List_iterator_fast<Item> li(items);
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff)),*res;
+ String tmp(buff,sizeof(buff),default_charset_info),*res;
tmp.length(0);
Item *item;
DBUG_ENTER("send_data");
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
if (row_count++ > 1)
{
- my_error(ER_TOO_MANY_ROWS,MYF(0));
+ my_error(ER_TOO_MANY_ROWS, MYF(0));
goto err;
}
while ((item=li++))
@@ -827,23 +890,139 @@ err:
void select_dump::send_error(uint errcode,const char *err)
{
- ::send_error(&thd->net,errcode,err);
+ my_message(errcode, err, MYF(0));
(void) end_io_cache(&cache);
(void) my_close(file,MYF(0));
(void) my_delete(path,MYF(0)); // Delete file on error
file= -1;
}
-
bool select_dump::send_eof()
{
int error=test(end_io_cache(&cache));
if (my_close(file,MYF(MY_WME)))
error=1;
- if (error)
- ::send_error(&thd->net);
- else
- ::send_ok(&thd->net,row_count);
+ if (!error)
+ ::send_ok(thd,row_count);
file= -1;
return error;
}
+
+select_subselect::select_subselect(Item_subselect *item)
+{
+ this->item=item;
+}
+
+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())
+ {
+ my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
+ DBUG_RETURN(1);
+ }
+ if (unit->offset_limit_cnt)
+ { // Using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
+ List_iterator_fast<Item> li(items);
+ Item *val_item= li++; // Only one (single value subselect)
+ /*
+ Following val() call have to be first, because function AVG() & STD()
+ calculate value on it & determinate "is it NULL?".
+ */
+ it->real_value= val_item->val_result();
+ if ((it->null_value= val_item->is_null_result()))
+ {
+ it->assign_null();
+ }
+ else
+ {
+ it->max_length= val_item->max_length;
+ it->decimals= val_item->decimals;
+ it->set_charset(val_item->charset());
+ it->int_value= val_item->val_int_result();
+ String *s= val_item->str_result(&it->string_value);
+ if (s != &it->string_value)
+ {
+ it->string_value.set(*s, 0, s->length());
+ }
+ // TODO: remove when correct charset handling appeared for Item
+ it->str_value.set(*s, 0, s->length()); // store charset
+
+ it->res_type= val_item->result_type();
+ }
+ it->assigned(1);
+ DBUG_RETURN(0);
+}
+
+bool select_exists_subselect::send_data(List<Item> &items)
+{
+ DBUG_ENTER("select_exists_subselect::send_data");
+ Item_exists_subselect *it= (Item_exists_subselect *)item;
+ if (unit->offset_limit_cnt)
+ { // Using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
+ it->value= 1;
+ it->assigned(1);
+ DBUG_RETURN(0);
+}
+
+
+/***************************************************************************
+** Dump of select to variables
+***************************************************************************/
+int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
+{
+ List_iterator_fast<Item> li(list);
+ List_iterator_fast<LEX_STRING> gl(var_list);
+ Item *item;
+ LEX_STRING *ls;
+ if (var_list.elements != list.elements)
+ {
+ my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0));
+ return 1;
+ }
+ while ((item=li++))
+ {
+ ls= gl++;
+ Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
+ xx->fix_fields(current_thd,(TABLE_LIST*) current_thd->lex.select_lex.table_list.first,&item);
+ xx->fix_length_and_dec();
+ vars.push_back(xx);
+ }
+ return 0;
+}
+bool select_dumpvar::send_data(List<Item> &items)
+{
+ List_iterator_fast<Item_func_set_user_var> li(vars);
+ Item_func_set_user_var *xx;
+ DBUG_ENTER("send_data");
+
+ if (row_count++)
+ {
+ my_error(ER_TOO_MANY_ROWS, MYF(0));
+ DBUG_RETURN(1);
+ }
+ while ((xx=li++))
+ xx->update();
+ DBUG_RETURN(0);
+}
+
+bool select_dumpvar::send_eof()
+{
+ if (row_count)
+ {
+ ::send_ok(thd,row_count);
+ return 0;
+ }
+ else
+ {
+ my_error(ER_EMPTY_QUERY,MYF(0));
+ return 1;
+ }
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index dba2ad130bf..acdf2471ba8 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -73,14 +73,14 @@ class MYSQL_LOG {
// current file sequence number for load data infile binary logging
uint file_id;
uint open_count; // For replication
+ volatile enum_log_type log_type;
+ enum cache_type io_cache_type;
+ bool write_error,inited;
/*
For binlog - if log name can never change we should not try to rotate it
or write any rotation events. The user should use FLUSH MASTER instead
of FLUSH LOGS for purging.
*/
- volatile enum_log_type log_type;
- enum cache_type io_cache_type;
- bool write_error,inited;
bool no_rotate;
bool need_start_event;
bool no_auto_events; // for relay binlog
@@ -220,19 +220,40 @@ public:
class Key :public Sql_alloc {
public:
- enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT };
+ enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY};
enum Keytype type;
enum ha_key_alg algorithm;
List<key_part_spec> columns;
- const char *Name;
+ const char *name;
- Key(enum Keytype type_par,const char *name_arg,List<key_part_spec> &cols)
- :type(type_par), algorithm(HA_KEY_ALG_UNDEF), columns(cols), Name(name_arg)
+ Key(enum Keytype type_par, const char *name_arg, enum ha_key_alg alg_par,
+ List<key_part_spec> &cols)
+ :type(type_par), algorithm(alg_par), columns(cols), name(name_arg)
{}
~Key() {}
- const char *name() { return Name; }
};
+class Table_ident;
+
+class foreign_key: public Key {
+public:
+ enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL,
+ FK_MATCH_PARTIAL, FK_MATCH_SIMPLE};
+ enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE,
+ FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT};
+
+ Table_ident *ref_table;
+ List<key_part_spec> ref_columns;
+ uint delete_opt, update_opt, match_opt;
+ foreign_key(const char *name_arg, List<key_part_spec> &cols,
+ Table_ident *table, List<key_part_spec> &ref_cols,
+ uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg)
+ :Key(FOREIGN_KEY, name_arg, HA_KEY_ALG_UNDEF, cols),
+ ref_table(table), ref_columns(cols),
+ delete_opt(delete_opt_arg), update_opt(update_opt_arg),
+ match_opt(match_opt_arg)
+ {}
+};
typedef struct st_mysql_lock
{
@@ -252,8 +273,8 @@ public:
#include "sql_lex.h" /* Must be here */
-// needed to be able to have an I_List of char* strings.in mysqld.cc where we cannot use String
-// because it is Sql_alloc'ed
+/* Needed to be able to have an I_List of char* strings in mysqld.cc. */
+
class i_string: public ilink
{
public:
@@ -262,7 +283,7 @@ public:
i_string(char* s) : ptr(s) {}
};
-//needed for linked list of two strings for replicate-rewrite-db
+/* needed for linked list of two strings for replicate-rewrite-db */
class i_string_pair: public ilink
{
public:
@@ -273,7 +294,43 @@ public:
};
+class MYSQL_ERROR: public Sql_alloc
+{
+public:
+ enum enum_warning_level
+ { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END};
+
+ uint code;
+ enum_warning_level level;
+ char *msg;
+
+ MYSQL_ERROR(uint code_arg, enum_warning_level level_arg,
+ const char *msg_arg)
+ :code(code_arg), level(level_arg)
+ {
+ msg=sql_strdup(msg_arg);
+ }
+};
+
+
+/* This is a struct as it's allocated in tree_insert */
+
+typedef struct st_prep_stmt
+{
+ THD *thd;
+ Item_param *param;
+ Item *free_list;
+ MEM_ROOT mem_root;
+ ulong stmt_id;
+ uint param_count;
+ uint last_errno;
+ char last_error[MYSQL_ERRMSG_SIZE];
+ bool error_in_prepare, long_data_used;
+} PREP_STMT;
+
+
class delayed_insert;
+class select_result;
#define THD_SENTRY_MAGIC 0xfeedd1ff
#define THD_SENTRY_GONE 0xdeadbeef
@@ -284,29 +341,31 @@ 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_prep_stmt_count;
ulong max_sort_length;
- ulong max_join_size;
ulong max_tmp_tables;
ulong myisam_sort_buff_size;
ulong net_buffer_length;
ulong net_interactive_timeout;
ulong net_read_timeout;
+ ulong net_retry_count;
ulong net_wait_timeout;
ulong net_write_timeout;
- ulong net_retry_count;
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;
ulong tx_isolation;
- ulong table_type;
my_bool log_warnings;
my_bool low_priority_updates;
@@ -325,7 +384,10 @@ public:
NET net; // client connection descriptor
LEX lex; // parse tree descriptor
MEM_ROOT mem_root; // 1 command-life memory pool
+ MEM_ROOT con_root; // connection-life memory
+ MEM_ROOT warn_root; // For warnings and errors
HASH user_vars; // hash for user variables
+ TREE prepared_statements;
String packet; // dynamic buffer for network I/O
struct sockaddr_in remote; // client socket address
struct rand_struct rand; // used for authentication
@@ -343,8 +405,7 @@ public:
host - host of the client
user - user of the client, set to NULL until the user has been read from
the connection
- priv_user - not sure why we have it, but it is set to "boot" when we run
- with --bootstrap
+ priv_user - The user privilege we are using. May be '' for anonymous user.
db - currently selected database
ip - client IP
*/
@@ -362,7 +423,6 @@ public:
ulong master_access; /* Global privileges from mysql.user */
ulong db_access; /* Privileges for current db */
-
/*
open_tables - list of regular tables in use by this thread
temporary_tables - list of temp tables in use by this thread
@@ -371,8 +431,10 @@ public:
*/
TABLE *open_tables,*temporary_tables, *handler_tables;
// TODO: document the variables below
- MYSQL_LOCK *lock,*locked_tables;
- ULL *ull;
+ MYSQL_LOCK *lock; /* Current locks */
+ MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */
+ ULL *ull;
+ PREP_STMT *last_prepared_stmt;
#ifndef DBUG_OFF
uint dbug_sentry; // watch out for memory corruption
#endif
@@ -418,7 +480,14 @@ public:
sent_row_count, examined_row_count;
table_map used_tables;
USER_CONN *user_connect;
- ulong query_id,version, options,thread_id, col_access;
+ 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, 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;
@@ -426,6 +495,8 @@ public:
uint server_status,open_options;
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];
@@ -438,6 +509,9 @@ public:
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
that are currently reading it needs to be adjusted. To do that
@@ -451,7 +525,6 @@ public:
ulong slave_proxy_id;
NET* slave_net; // network connection from slave -> m.
my_off_t log_pos;
-
/* Used by the sys_var class to store temporary values */
union
{
@@ -555,6 +628,14 @@ public:
void add_changed_table(TABLE *table);
void add_changed_table(const char *key, long key_length);
CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length);
+ int send_explain_fields(select_result *result);
+ inline void clear_error()
+ {
+ net.last_error[0]= 0;
+ net.last_errno= 0;
+ net.report_error= 0;
+ }
+ void add_possible_loop(Item *);
};
/*
@@ -576,26 +657,31 @@ public:
#include "log_event.h"
/*
-** This is used to get result from a select
+ This is used to get result from a select
*/
class JOIN;
-void send_error(NET *net,uint sql_errno=0, const char *err=0);
+void send_error(THD *thd, uint sql_errno=0, const char *err=0);
class select_result :public Sql_alloc {
protected:
THD *thd;
+ SELECT_LEX_UNIT *unit;
public:
select_result();
virtual ~select_result() {};
- virtual int prepare(List<Item> &list) { return 0; }
+ virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u)
+ {
+ unit= u;
+ return 0;
+ }
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 void send_error(uint errcode,const char *err)
{
- ::send_error(&thd->net,errcode,err);
+ my_message(errcode, err, MYF(0));
}
virtual bool send_eof()=0;
virtual void abort() {}
@@ -622,7 +708,7 @@ class select_export :public select_result {
public:
select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) {}
~select_export();
- int prepare(List<Item> &list);
+ 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);
@@ -641,7 +727,7 @@ public:
select_dump(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L)
{ path[0]=0; }
~select_dump();
- int prepare(List<Item> &list);
+ 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);
@@ -664,7 +750,7 @@ class select_insert :public select_result {
info.handle_duplicates=duplic;
}
~select_insert();
- int prepare(List<Item> &list);
+ 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);
@@ -693,7 +779,7 @@ public:
create_info(create_info_par),
lock(0)
{}
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &values);
bool send_eof();
void abort();
@@ -708,7 +794,7 @@ class select_union :public select_result {
select_union(TABLE *table_par);
~select_union();
- int prepare(List<Item> &list);
+ 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);
@@ -716,6 +802,36 @@ class select_union :public select_result {
bool flush();
};
+/* Base subselect interface class */
+class select_subselect :public select_result
+{
+protected:
+ Item_subselect *item;
+public:
+ select_subselect(Item_subselect *item);
+ bool send_fields(List<Item> &list, uint flag) { return 0; };
+ bool send_data(List<Item> &items)=0;
+ bool send_eof() { return 0; };
+
+ friend class Ttem_subselect;
+};
+
+/* Single value subselect interface class */
+class select_singleval_subselect :public select_subselect
+{
+public:
+ select_singleval_subselect(Item_subselect *item):select_subselect(item){}
+ bool send_data(List<Item> &items);
+};
+
+/* EXISTS subselect interface class */
+class select_exists_subselect :public select_subselect
+{
+public:
+ select_exists_subselect(Item_subselect *item):select_subselect(item){}
+ bool send_data(List<Item> &items);
+};
+
/* Structs used when sorting */
typedef struct st_sort_field {
@@ -742,17 +858,28 @@ class Table_ident :public Sql_alloc {
public:
LEX_STRING db;
LEX_STRING table;
- inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force)
- :table(table_arg)
+ SELECT_LEX_UNIT *sel;
+ inline Table_ident(LEX_STRING db_arg, LEX_STRING table_arg, bool force)
+ :table(table_arg), sel((SELECT_LEX_UNIT *)0)
{
if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
db.str=0;
else
db= db_arg;
}
- inline Table_ident(LEX_STRING table_arg) :table(table_arg) {db.str=0;}
+ inline Table_ident(LEX_STRING table_arg)
+ :table(table_arg), sel((SELECT_LEX_UNIT *)0)
+ {
+ db.str=0;
+ }
+ inline Table_ident(SELECT_LEX_UNIT *s) : sel(s)
+ {
+ db.str=0; table.str=(char *)""; table.length=0;
+ }
inline void change_db(char *db_name)
- { db.str= db_name; db.length=(uint) strlen(db_name); }
+ {
+ db.str= db_name; db.length= (uint) strlen(db_name);
+ }
};
// this is needed for user_vars hash
@@ -763,6 +890,7 @@ class user_var_entry
char *value;
ulong length, update_query_id;
Item_result type;
+ CHARSET_INFO *var_charset;
};
/* Class for unique (removing of duplicates) */
@@ -785,7 +913,7 @@ public:
{
if (tree.elements_in_tree > max_elements && flush())
return 1;
- return !tree_insert(&tree,ptr,0);
+ return !tree_insert(&tree, ptr, 0, tree.custom_arg);
}
bool get(TABLE *table);
@@ -810,7 +938,7 @@ public:
public:
multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
~multi_delete();
- int prepare(List<Item> &list);
+ 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);
@@ -822,7 +950,6 @@ public:
class multi_update : public select_result {
TABLE_LIST *update_tables, *table_being_updated;
-// Unique **tempfiles;
COPY_INFO *infos;
TABLE **tmp_tables;
THD *thd;
@@ -838,7 +965,7 @@ public:
enum enum_duplicates handle_duplicates,
uint num);
~multi_update();
- int prepare(List<Item> &list);
+ 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);
@@ -848,3 +975,15 @@ public:
bool send_eof();
};
+class select_dumpvar :public select_result {
+ ha_rows row_count;
+public:
+ List<LEX_STRING> var_list;
+ List<Item_func_set_user_var> vars;
+ select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;}
+ ~select_dumpvar() {}
+ 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 send_eof();
+};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index cde0c6cc31f..cefad6a0805 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -25,20 +25,139 @@
#include <direct.h>
#endif
+#define MY_DB_OPT_FILE "db.opt"
+
+const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS};
+static TYPELIB deletable_extentions=
+{array_elements(del_exts)-1,"del_exts", del_exts};
+
+const char *known_exts[]=
+{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS};
+static TYPELIB known_extentions=
+{array_elements(known_exts)-1,"known_exts", known_exts};
+
static long mysql_rm_known_files(THD *thd, MY_DIR *dirp,
const char *db, const char *path,
uint level);
-/* db-name is already validated when we come here */
+/*
+ Create database options file:
+
+ DESCRIPTION
+ Currently database default charset is only stored there.
+
+ RETURN VALUES
+ 0 ok
+ 1 Could not create file or write to it. Error sent through my_error()
+*/
+
+static bool write_db_opt(const char *path, HA_CREATE_INFO *create)
+{
+ register File file;
+ char buf[256]; // Should be enough for one option
+ bool error=1;
+
+ if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
+ {
+ ulong length;
+ length= my_sprintf(buf,(buf, "default-character-set=%s\n",
+ (create && create->table_charset) ?
+ create->table_charset->name : "DEFAULT"));
+
+ /* Error is written by my_write */
+ if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME)))
+ error=0;
+ my_close(file,MYF(0));
+ }
+ return error;
+}
+
+
+/*
+ Load database options file
+
+ load_db_opt()
+ path Path for option file
+ create Where to store the read options
+
+ DESCRIPTION
+ For now, only default-character-set is read.
+
+ RETURN VALUES
+ 0 File found
+ 1 No database file or could not open it
+
+*/
+
+static bool load_db_opt(const char *path, HA_CREATE_INFO *create)
+{
+ File file;
+ char buf[256];
+ DBUG_ENTER("load_db_opt");
+ bool error=1;
+ uint nbytes;
+
+ bzero((char*) create,sizeof(*create));
+ if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0)
+ {
+ IO_CACHE cache;
+ init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0));
+
+ while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0)
+ {
+ char *pos= buf+nbytes-1;
+ /* Remove end space and control characters */
+ while (pos > buf && !my_isgraph(system_charset_info, pos[-1]))
+ pos--;
+ *pos=0;
+ if ((pos= strchr(buf, '=')))
+ {
+ if (!strncmp(buf,"default-character-set", (pos-buf)))
+ {
+ if (!(create->table_charset=get_charset_by_name(pos+1, MYF(0))))
+ {
+ sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),
+ pos+1);
+ }
+ }
+ }
+ }
+ error=0;
+ end_io_cache(&cache);
+ my_close(file,MYF(0));
+ }
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Create a database
+
+ SYNOPSIS
+ mysql_create_db()
+ thd Thread handler
+ db Name of database to create
+ Function assumes that this is already validated.
+ create_info Database create options (like character set)
+ silent Used by replication when internally creating a database.
+ In this case the entry should not be logged.
+
+ RETURN VALUES
+ 0 ok
+ -1 Error
+
+*/
-int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
+int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
+ bool silent)
{
char path[FN_REFLEN+16];
MY_DIR *dirp;
long result=1;
int error = 0;
+ uint create_options = create_info ? create_info->options : 0;
DBUG_ENTER("mysql_create_db");
-
+
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
// do not create database if another thread is holding read lock
@@ -73,29 +192,49 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
}
}
+ unpack_dirname(path, path);
+ strcat(path,MY_DB_OPT_FILE);
+ if (write_db_opt(path, create_info))
+ {
+ /*
+ Could not create options file.
+ Restore things to beginning.
+ */
+ if (rmdir(path) >= 0)
+ {
+ error= -1;
+ goto exit;
+ }
+ /*
+ We come here when we managed to create the database, but not the option
+ file. In this case it's best to just continue as if nothing has
+ happened. (This is a very unlikely senario)
+ */
+ }
+
if (!silent)
{
- if (!thd->query)
+ char *query;
+ uint query_length;
+
+ if (!thd->query) // Only in replication
{
- /* The client used the old obsolete mysql_create_db() call */
- thd->query = path;
- thd->query_length = (uint) (strxmov(path,"create database `", db, "`",
- NullS) - path);
+ query= path;
+ query_length= (uint) (strxmov(path,"create database `", db, "`", NullS) -
+ path);
}
+ else
{
- 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, 0);
- 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->net, result);
+ send_ok(thd, result);
}
exit:
@@ -105,14 +244,56 @@ exit2:
DBUG_RETURN(error);
}
-const char *del_exts[]= {".frm", ".BAK", ".TMD", NullS};
-static TYPELIB deletable_extentions=
-{array_elements(del_exts)-1,"del_exts", del_exts};
-const char *known_exts[]=
-{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS};
-static TYPELIB known_extentions=
-{array_elements(known_exts)-1,"known_exts", known_exts};
+/* db-name is already validated when we come here */
+
+int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
+{
+ char path[FN_REFLEN+16];
+ long result=1;
+ int error = 0;
+ uint create_options = create_info ? create_info->options : 0;
+ DBUG_ENTER("mysql_alter_db");
+
+ VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
+
+ // do not alter database if another thread is holding read lock
+ if (wait_if_global_read_lock(thd,0))
+ {
+ error= -1;
+ goto exit2;
+ }
+
+ /* Check directory */
+ (void)sprintf(path,"%s/%s/%s", mysql_data_home, db, MY_DB_OPT_FILE);
+ fn_format(path, path, "", "", MYF(MY_UNPACK_FILENAME));
+ if ((error=write_db_opt(path, create_info)))
+ goto exit;
+
+ /*
+ Change options if current database is being altered
+ TODO: Delete this code
+ */
+ if (thd->db && !strcmp(thd->db,db))
+ {
+ thd->db_charset= create_info ? create_info->table_charset : NULL;
+ }
+
+ 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);
+ }
+ send_ok(thd, result);
+
+exit:
+ start_waiting_global_read_lock(thd);
+exit2:
+ VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
+ DBUG_RETURN(error);
+}
+
/*
Drop all tables in a database.
@@ -151,7 +332,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
my_error(ER_DB_DROP_EXISTS,MYF(0),db);
}
else if (!silent)
- send_ok(&thd->net,0);
+ send_ok(thd,0);
goto exit;
}
pthread_mutex_lock(&LOCK_open);
@@ -165,24 +346,27 @@ 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, 0);
- 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->net,(ulong) deleted);
+ send_ok(thd,(ulong) deleted);
}
error = 0;
}
@@ -221,7 +405,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
DBUG_PRINT("info",("Examining: %s", file->name));
/* Check if file is a raid directory */
- if (isdigit(file->name[0]) && isdigit(file->name[1]) &&
+ if (my_isdigit(system_charset_info,file->name[0]) &&
+ my_isdigit(system_charset_info,file->name[1]) &&
!file->name[2] && !level)
{
char newpath[FN_REFLEN];
@@ -246,7 +431,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
continue;
}
strxmov(filePath,org_path,"/",file->name,NullS);
- if (db && !my_strcasecmp(fn_ext(file->name), reg_ext))
+ if (db && !my_strcasecmp(system_charset_info,
+ fn_ext(file->name), reg_ext))
{
/* Drop the table nicely */
*fn_ext(file->name)=0; // Remove extension
@@ -328,28 +514,47 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
}
-bool mysql_change_db(THD *thd,const char *name)
+/*
+ Change default database.
+
+ SYNOPSIS
+ mysql_change_db()
+ thd Thread handler
+ name Databasename
+
+ DESCRIPTION
+ Becasue the database name may have been given directly from the
+ communication packet (in case of 'connect' or 'COM_INIT_DB')
+ we have to do end space removal in this function.
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
+bool mysql_change_db(THD *thd, const char *name)
{
int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
char path[FN_REFLEN];
ulong db_access;
+ HA_CREATE_INFO create;
DBUG_ENTER("mysql_change_db");
if (!dbname || !(db_length=strip_sp(dbname)))
{
x_free(dbname); /* purecov: inspected */
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if ((db_length > NAME_LEN) || check_db_name(dbname))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, dbname);
+ net_printf(thd,ER_WRONG_DB_NAME, dbname);
x_free(dbname);
DBUG_RETURN(1);
}
if (lower_case_table_names)
- casedn_str(dbname);
+ my_casedn_str(system_charset_info, dbname);
DBUG_PRINT("info",("Use database: %s", dbname));
if (test_all_bits(thd->master_access,DB_ACLS))
db_access=DB_ACLS;
@@ -359,7 +564,7 @@ bool mysql_change_db(THD *thd,const char *name)
thd->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
{
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ net_printf(thd,ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
thd->host_or_ip,
dbname);
@@ -377,16 +582,103 @@ bool mysql_change_db(THD *thd,const char *name)
path[length-1]=0; // remove ending '\'
if (access(path,F_OK))
{
- net_printf(&thd->net,ER_BAD_DB_ERROR,dbname);
+ net_printf(thd,ER_BAD_DB_ERROR,dbname);
my_free(dbname,MYF(0));
DBUG_RETURN(1);
}
- send_ok(&thd->net);
+ send_ok(thd);
x_free(thd->db);
- if (lower_case_table_names)
- casedn_str(dbname);
- thd->db=dbname;
+ thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length;
thd->db_access=db_access;
+
+ strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
+ load_db_opt(path, &create);
+ thd->db_charset=create.table_charset;
+ thd->thd_charset=thd->db_charset ? thd->db_charset : default_charset_info;
+ DBUG_RETURN(0);
+}
+
+
+int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_info)
+{
+ int length;
+ char path[FN_REFLEN], *to;
+ uint db_access;
+ 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))
+ {
+ net_printf(thd,ER_WRONG_DB_NAME, dbname);
+ DBUG_RETURN(1);
+ }
+
+ if (test_all_bits(thd->master_access,DB_ACLS))
+ db_access=DB_ACLS;
+ else
+ db_access= (acl_get(thd->host,thd->ip,(char*) &thd->remote.sin_addr,
+ thd->priv_user,dbname) |
+ thd->master_access);
+ if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
+ {
+ net_printf(thd,ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->host_or_ip,
+ dbname);
+ mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
+ thd->priv_user,
+ thd->host_or_ip,
+ dbname);
+ DBUG_RETURN(1);
+ }
+
+ (void) sprintf(path,"%s/%s",mysql_data_home, dbname);
+ length=unpack_dirname(path,path); // Convert if not unix
+ found_libchar= 0;
+ if (length && path[length-1] == FN_LIBCHAR)
+ {
+ found_libchar= 1;
+ path[length-1]=0; // remove ending '\'
+ }
+ if (access(path,F_OK))
+ {
+ net_printf(thd,ER_BAD_DB_ERROR,dbname);
+ DBUG_RETURN(1);
+ }
+ if (found_libchar)
+ path[length-1]= FN_LIBCHAR;
+ strmov(path+length, MY_DB_OPT_FILE);
+ load_db_opt(path, &create);
+
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("Database",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Create Database",1024));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ String *packet = &thd->packet;
+ packet->length(0);
+ net_store_data(packet, convert, dbname);
+ 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," /*!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);
+
+ send_eof(thd);
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 5f2d7e36a04..cc60ebfb58d 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -35,27 +35,30 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
SQL_SELECT *select=0;
READ_RECORD info;
bool using_limit=limit != HA_POS_ERROR;
- bool transactional_table, log_delayed, safe_update;
+ bool using_transactions, log_delayed, safe_update, const_cond;
ha_rows deleted;
DBUG_ENTER("mysql_delete");
- if (((safe_update=thd->options & OPTION_SAFE_UPDATES)) && !conds)
- {
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
- DBUG_RETURN(1);
- }
-
if (!(table = open_ltable(thd, table_list, table_list->lock_type)))
DBUG_RETURN(-1);
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
table->map=1;
- if (setup_conds(thd,table_list,&conds) || setup_ftfuncs(thd))
+ if (setup_conds(thd,table_list,&conds) ||
+ setup_ftfuncs(&thd->lex.select_lex))
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()) &&
- !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && !safe_update)
+ if (!using_limit && const_cond &&
+ !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)))
{
deleted= table->file->records;
if (!(error=table->file->delete_all_rows()))
@@ -76,12 +79,10 @@ 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->net,0L);
+ send_ok(thd,0L);
DBUG_RETURN(0); // Nothing to delete
}
@@ -92,7 +93,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
if (safe_update && !using_limit)
{
delete select;
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
}
@@ -115,8 +116,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
MYF(MY_FAE | MY_ZEROFILL));
if (setup_order(thd, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
- (table->found_records = filesort(table, sortorder, length,
- (SQL_SELECT *) 0, 0L, HA_POS_ERROR,
+ (table->found_records = filesort(thd, table, sortorder, length,
+ (SQL_SELECT *) 0, HA_POS_ERROR,
&examined_rows))
== HA_POS_ERROR)
{
@@ -127,7 +128,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
init_read_record(&info,thd,table,select,1,1);
deleted=0L;
- init_ftfuncs(thd,1);
+ init_ftfuncs(thd, &thd->lex.select_lex, 1);
thd->proc_info="updating";
while (!(error=info.read_record(&info)) && !thd->killed)
{
@@ -197,10 +198,10 @@ cleanup:
}
delete select;
if (error >= 0) // Fatal error
- send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
else
{
- send_ok(&thd->net,deleted);
+ send_ok(thd,deleted);
DBUG_PRINT("info",("%d records deleted",deleted));
}
DBUG_RETURN(0);
@@ -229,9 +230,10 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
int
-multi_delete::prepare(List<Item> &values)
+multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("multi_delete::prepare");
+ unit= u;
do_delete = true;
thd->proc_info="deleting from main table";
@@ -294,7 +296,7 @@ multi_delete::initialize_tables(JOIN *join)
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
- init_ftfuncs(thd,1);
+ init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
}
@@ -364,7 +366,7 @@ void multi_delete::send_error(uint errcode,const char *err)
DBUG_ENTER("multi_delete::send_error");
/* First send error what ever it is ... */
- ::send_error(&thd->net,errcode,err);
+ ::send_error(thd,errcode,err);
/* If nothing deleted return */
if (!deleted)
@@ -464,6 +466,7 @@ bool multi_delete::send_eof()
/* reset used flags */
thd->proc_info="end";
+
/*
Write the SQL statement to the binlog if we deleted
rows and we succeeded, or also in an error case when there
@@ -486,9 +489,9 @@ bool multi_delete::send_eof()
query_cache_invalidate3(thd, delete_tables, 1);
}
if (local_error)
- ::send_error(&thd->net);
+ ::send_error(thd);
else
- ::send_ok(&thd->net,deleted);
+ ::send_ok(thd, deleted);
return 0;
}
@@ -526,8 +529,9 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK);
bzero((char*) &create_info,sizeof(create_info));
create_info.auto_increment_value= table->file->auto_increment_value;
- db_type table_type=table->db_type;
+ create_info.table_charset=default_charset_info;
+ db_type table_type=table->db_type;
strmov(path,table->path);
*table_ptr= table->next; // Unlink table from list
close_temporary(table,0);
@@ -538,8 +542,8 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
table_list->real_name, 1))))
(void) rm_temporary_table(table_type, path);
/*
- Sasha: if we return here we will not have binloged the truncation and
- we will not send_ok() to the client.
+ If we return here we will not have logged the truncation to the bin log
+ and we will not send_ok() to the client.
*/
goto end;
}
@@ -569,6 +573,8 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
}
bzero((char*) &create_info,sizeof(create_info));
+ create_info.table_charset=default_charset_info;
+
*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);
@@ -585,7 +591,7 @@ end:
thd->tmp_table);
mysql_bin_log.write(&qinfo);
}
- send_ok(&thd->net); // This should return record count
+ send_ok(thd); // This should return record count
}
VOID(pthread_mutex_lock(&LOCK_open));
unlock_table_name(thd, table_list);
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
new file mode 100644
index 00000000000..b3d2b1602d0
--- /dev/null
+++ b/sql/sql_derived.cc
@@ -0,0 +1,134 @@
+/* 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 */
+
+
+/*
+ Derived tables
+ These were introduced by Monty and Sinisa <sinisa@mysql.com>
+*/
+
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include "sql_acl.h"
+
+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)
+{
+ /*
+ TODO: make derived tables with union inside (now only 1 SELECT may be
+ procesed)
+ */
+ SELECT_LEX *sl= unit->first_select();
+ List<Item> item_list;
+ TABLE *table;
+ int res= 0;
+ select_union *derived_result;
+ TABLE_LIST *tables= (TABLE_LIST *)sl->table_list.first;
+ TMP_TABLE_PARAM tmp_table_param;
+ DBUG_ENTER("mysql_derived");
+
+ if (tables)
+ res= check_table_access(thd,SELECT_ACL, tables);
+ else
+ res= check_access(thd, SELECT_ACL, any_db);
+ 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);
+ if (res) DBUG_RETURN(res);
+ }
+ }
+ Item *item;
+ List_iterator<Item> it(sl->item_list);
+
+ while ((item= it++))
+ item_list.push_back(item);
+
+ if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ if (setup_fields(thd,tables,item_list,0,0,1))
+ {
+ res=-1;
+ goto exit;
+ }
+ 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,
+ (sl->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ unit)))
+ {
+ res=-1;
+ goto exit;
+ }
+
+ 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
+ if (derived_result->flush())
+ res=1;
+ else
+ {
+ t->real_name=table->real_name;
+ t->table=table;
+ table->derived_select_number= sl->select_number;
+ table->tmp_table=TMP_TABLE;
+ if (!lex->describe)
+ sl->exclude();
+ t->db=(char *)"";
+ t->derived=(SELECT_LEX *)0; // just in case ...
+ }
+ }
+ delete derived_result;
+ }
+ if (res)
+ free_tmp_table(thd,table);
+exit:
+ close_thread_tables(thd);
+ }
+ DBUG_RETURN(res);
+}
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 70124c2d796..2eef088da5b 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -29,6 +29,6 @@ int mysql_do(THD *thd, List<Item> &values)
DBUG_RETURN(-1);
while ((value = li++))
value->val_int();
- send_ok(&thd->net);
+ send_ok(thd);
DBUG_RETURN(0);
}
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
new file mode 100644
index 00000000000..0740dc428f0
--- /dev/null
+++ b/sql/sql_error.cc
@@ -0,0 +1,165 @@
+/* Copyright (C) 1995-2002 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
+*/
+
+/**********************************************************************
+This file contains the implementation of error and warnings related
+
+ - Whenever an error or warning occurred, it pushes it to a warning list
+ that the user can retrieve with SHOW WARNINGS or SHOW ERRORS.
+
+ - For each statement, we return the number of warnings generated from this
+ command. Note that this can be different from @@warning_count as
+ we reset the warning list only for questions that uses a table.
+ This is done to allow on to do:
+ INSERT ...;
+ SELECT @@warning_count;
+ SHOW WARNINGS;
+ (If we would reset after each command, we could not retrieve the number
+ of warnings)
+
+ - When client requests the information using SHOW command, then
+ server processes from this list and returns back in the form of
+ resultset.
+
+ Supported syntaxes:
+
+ SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows]
+ SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows]
+ SELECT @@warning_count, @@error_count;
+
+***********************************************************************/
+
+#include "mysql_priv.h"
+
+/*
+ Reset all warnings for the thread
+
+ 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)
+{
+ 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();
+ }
+}
+
+
+/*
+ Push the warning/error to error list if there is still room in the list
+
+ SYNOPSIS
+ push_warning()
+ thd Thread handle
+ level Severity of warning (note, warning, error ...)
+ code Error number
+ msg Clear error message
+*/
+
+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)
+ {
+ /*
+ The following code is here to change the allocation to not
+ use the thd->mem_root, which is freed after each query
+ */
+ MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root);
+ MYSQL_ERROR *err= new MYSQL_ERROR(code, level, msg);
+ if (err)
+ thd->warn_list.push_back(err);
+ my_pthread_setspecific_ptr(THR_MALLOC, old_root);
+ }
+ thd->warn_count[(uint) level]++;
+ thd->total_warn_count++;
+}
+
+
+/*
+ Send all notes, errors or warnings to the client in a result set
+
+ SYNOPSIS
+ mysqld_show_warnings()
+ thd Thread handler
+ levels_to_show Bitmap for which levels to show
+
+ DESCRIPTION
+ Takes into account the current LIMIT
+
+ RETURN VALUES
+ 0 ok
+ 1 Error sending data to client
+*/
+
+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");
+
+ field_list.push_back(new Item_empty_string("Level", 7));
+ field_list.push_back(new Item_int("Code",0,4));
+ field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ MYSQL_ERROR *err;
+ SELECT_LEX *sel= &thd->lex.select_lex;
+ ha_rows offset= sel->offset_limit, limit= sel->select_limit;
+
+ List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ while ((err= it++))
+ {
+ /* Skip levels that the user is not interested in */
+ if (!(levels_to_show & ((ulong) 1 << err->level)))
+ continue;
+ if (offset)
+ {
+ offset--;
+ continue;
+ }
+ thd->packet.length(0);
+ net_store_data(&thd->packet,warning_level_names[err->level]);
+ net_store_data(&thd->packet,(uint32) err->code);
+ net_store_data(&thd->packet,err->msg);
+ if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length()))
+ DBUG_RETURN(1);
+ if (!--limit)
+ break;
+ }
+ send_eof(thd);
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index ea02c46c0f4..c43869d9d55 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -62,7 +62,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
return -1;
}
- send_ok(&thd->net);
+ send_ok(thd);
return 0;
}
@@ -83,12 +83,12 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
return -1;
}
if (!dont_send_ok)
- send_ok(&thd->net);
+ send_ok(thd);
return 0;
}
static enum enum_ha_read_modes rkey_to_rnext[]=
- { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };
+ { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
int mysql_ha_read(THD *thd, TABLE_LIST *tables,
@@ -106,7 +106,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- if (cond && cond->fix_fields(thd,tables))
+ if (cond && cond->fix_fields(thd, tables, &cond))
return -1;
if (keyname)
@@ -180,12 +180,12 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
- item->save_in_field(key_part->field);
+ (void) item->save_in_field(key_part->field);
key_len+=key_part->store_length;
}
if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len))))
{
- send_error(&thd->net,ER_OUTOFMEMORY);
+ send_error(thd,ER_OUTOFMEMORY);
goto err;
}
key_copy(key, table, keyno, key_len);
@@ -195,7 +195,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
break;
}
default:
- send_error(&thd->net,ER_ILLEGAL_HA);
+ send_error(thd,ER_ILLEGAL_HA);
goto err;
}
@@ -240,7 +240,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
ok:
mysql_unlock_tables(thd,lock);
- send_eof(&thd->net);
+ send_eof(thd);
return 0;
err:
mysql_unlock_tables(thd,lock);
@@ -271,9 +271,9 @@ static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
for (TABLE *table=*ptr; table ; table=*ptr)
{
if (!memcmp(table->table_cache_key, db, dblen) &&
- !my_strcasecmp(table->table_name,alias))
+ !my_strcasecmp(system_charset_info,table->table_name,alias))
break;
- ptr=&(table->next);
+ ptr= &(table->next);
}
return ptr;
}
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
new file mode 100644
index 00000000000..d2bea9ba44b
--- /dev/null
+++ b/sql/sql_help.cc
@@ -0,0 +1,408 @@
+/* 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 "sql_select.h" // For select_describe
+#include "sql_acl.h"
+
+/***************************************************************************
+** Get help on string
+***************************************************************************/
+
+MI_INFO *open_help_file(THD *thd, const char *name)
+{
+ char path[FN_REFLEN];
+ (void) sprintf(path,"%s/mysql_help/%s",mysql_data_home,name);
+ MI_INFO *res= 0;
+ if (!(res= mi_open(path,O_RDONLY,HA_OPEN_WAIT_IF_LOCKED)))
+ {
+ send_error(thd,ER_CORRUPT_HELP_DB);
+ return 0;
+ }
+ mi_extra(res,HA_EXTRA_WAIT_LOCK,0);
+ return res;
+}
+
+#define size_hf_func_id 4 /* func_id int unsigned, */
+#define size_hf_name 64 /* name varchar(64), */
+#define size_hf_url 128 /* url varchar(128), */
+#define size_hf_description sizeof(char*) /* description text, */
+#define size_hf_example sizeof(char*) /* example text, */
+#define size_hf_min_args 16 /* min_args tinyint, */
+#define size_hf_max_args 16 /* max_args tinyint, */
+#define size_hf_date_created 8 /* date_created datetime, */
+#define size_hf_last_modified 8 /* last_modified timestamp, */
+
+#define offset_hf_func_id 1
+#define offset_hf_name (offset_hf_func_id+size_hf_func_id)
+#define offset_hf_url (offset_hf_name+size_hf_name)
+#define offset_hf_description (offset_hf_url+size_hf_url)
+#define offset_hf_example (offset_hf_description+size_hf_description)
+#define offset_hf_min_args (offset_hf_example+size_hf_example)
+#define offset_hf_max_args (offset_hf_min_args+size_hf_min_args)
+#define offset_hf_date_created (offset_hf_max_args+size_hf_max_args)
+#define offset_hf_last_modified (offset_hf_date_created+size_hf_date_created)
+
+#define HELP_LEAF_SIZE (offset_hf_last_modified+size_hf_last_modified)
+
+class help_leaf{
+public:
+ char record[HELP_LEAF_SIZE];
+
+ inline const char *get_name()
+ {
+ return &record[offset_hf_name];
+ }
+
+ inline const char *get_description()
+ {
+ return *((char**)&record[199/*offset_hf_description*/]);
+ }
+
+ inline const char *get_example()
+ {
+ return *((char**)&record[209/*offset_hf_example*/]);
+ }
+
+ void prepare_fields()
+ {
+ const char *name= get_name();
+ const char *c= name + size_hf_name - 1;
+ while (*c==' ') c--;
+ int len= c-name+1;
+ ((char*)name)[len]= '\0';
+ }
+};
+
+int search_functions(MI_INFO *file_leafs, const char *mask,
+ List<String> *names,
+ String **name, String **description, String **example)
+{
+ DBUG_ENTER("search_functions");
+ int count= 0;
+
+ if(mi_scan_init(file_leafs))
+ DBUG_RETURN(-1);
+
+ help_leaf leaf;
+
+ while (!mi_scan(file_leafs,(byte*)&leaf))
+ {
+ leaf.prepare_fields();
+
+ const char *lname= leaf.get_name();
+ if (wild_case_compare(system_charset_info,lname,mask))
+ continue;
+ count++;
+
+ if (count>2)
+ {
+ String *s= new String(lname,system_charset_info);
+ if (!s->copy())
+ names->push_back(s);
+ }
+ else if (count==1)
+ {
+ *description= new String(leaf.get_description(),system_charset_info);
+ *example= new String(leaf.get_example(),system_charset_info);
+ *name= new String(lname,system_charset_info);
+ (*description)->copy();
+ (*example)->copy();
+ (*name)->copy();
+ }
+ else
+ {
+ names->push_back(*name);
+ delete *description;
+ delete *example;
+ *name= 0;
+ *description= 0;
+ *example= 0;
+
+ String *s= new String(lname,system_charset_info);
+ if (!s->copy())
+ names->push_back(s);
+ }
+ }
+
+ DBUG_RETURN(count);
+}
+
+#define size_hc_cat_id 2 /* cat_id smallint, */
+#define size_hc_name 64 /* name varchar(64), */
+#define size_hc_url 128 /* url varchar(128), */
+#define size_hc_date_created 8 /* date_created datetime, */
+#define size_hc_last_modified 8 /* last_modified timestamp, */
+
+#define offset_hc_cat_id 0
+#define offset_hc_name (offset_hc_cat_id+size_hc_cat_id)
+#define offset_hc_url (offset_hc_name+size_hc_name)
+#define offset_hc_date_created (offset_hc_url+size_hc_url)
+#define offset_hc_last_modified (offset_hc_date_created+size_hc_date_created)
+
+#define HELP_CATEGORY_SIZE (offset_hc_last_modified+size_hc_last_modified)
+
+class help_category{
+public:
+ char record[HELP_CATEGORY_SIZE];
+
+ inline int16 get_cat_id()
+ {
+ return sint2korr(&record[offset_hc_cat_id]);
+ }
+
+ inline const char *get_name()
+ {
+ return &record[offset_hc_name];
+ }
+
+ void prepare_fields()
+ {
+ const char *name= get_name();
+ const char *c= name + size_hc_name - 1;
+ while (*c==' ') c--;
+ int len= c-name+1;
+ ((char*)name)[len]= '\0';
+ }
+};
+
+int search_categories(THD *thd,
+ const char *mask, List<String> *names, int16 *res_id)
+{
+ DBUG_ENTER("search_categories");
+ int count= 0;
+
+ MI_INFO *file_categories= 0;
+ if (!(file_categories= open_help_file(thd,"function_category_name")))
+ DBUG_RETURN(-1);
+
+ if(mi_scan_init(file_categories))
+ {
+ mi_close(file_categories);
+ DBUG_RETURN(-1);
+ }
+
+ help_category category;
+
+
+ while (!mi_scan(file_categories,(byte*)&category))
+ {
+ category.prepare_fields();
+
+ const char *lname= category.get_name();
+ if (mask && wild_case_compare(system_charset_info,lname,mask))
+ continue;
+ count++;
+
+ if (count==1 && res_id)
+ *res_id= category.get_cat_id();
+
+ String *s= new String(lname,system_charset_info);
+ if (!s->copy())
+ names->push_back(s);
+ }
+
+ mi_close(file_categories);
+ DBUG_RETURN(count);
+}
+
+int send_variant_2_list(THD *thd, List<String> *names, my_bool is_category)
+{
+ DBUG_ENTER("send_names");
+
+ List_iterator<String> it(*names);
+ String *cur_name;
+ String *packet= &thd->packet;
+ while ((cur_name = it++))
+ {
+ packet->length(0);
+ net_store_data(packet, cur_name->ptr());
+ net_store_data(packet, is_category ? "Y" : "N");
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_RETURN(0);
+}
+
+#define size_hcn_cat_id 2 /* cat_id smallint, */
+#define size_hcn_func_id 4 /* func_id int, */
+
+#define offset_hcn_cat_id 1
+#define offset_hcn_func_id (offset_hcn_cat_id+size_hcn_cat_id)
+
+#define HELP_CATEGORY_NAME_SIZE (offset_hcn_func_id + size_hcn_func_id)
+
+class help_category_leaf{
+public:
+ char record[HELP_CATEGORY_NAME_SIZE];
+
+ inline int16 get_cat_id()
+ {
+ return sint2korr(&record[offset_hcn_cat_id]);
+ }
+
+ inline int get_func_id()
+ {
+ return sint3korr(&record[offset_hcn_func_id]);
+ }
+};
+
+int get_all_names_for_category(THD *thd,MI_INFO *file_leafs,
+ int16 cat_id, List<String> *res)
+{
+ DBUG_ENTER("get_all_names_for_category");
+
+ MI_INFO *file_names_categories= 0;
+ if (!(file_names_categories= open_help_file(thd,"function_category")))
+ DBUG_RETURN(1);
+
+ help_category_leaf cat_leaf;
+ help_leaf leaf;
+ int key_res= mi_rkey(file_names_categories, (byte*)&cat_leaf, 0,
+ (const byte*)&cat_id,2,HA_READ_KEY_EXACT);
+
+ while (!key_res && cat_leaf.get_cat_id()==cat_id)
+ {
+ int leaf_id= cat_leaf.get_func_id();
+
+ if (!mi_rkey(file_leafs, (byte*)&leaf, 0,
+ (const byte*)&leaf_id,4,HA_READ_KEY_EXACT))
+ {
+ leaf.prepare_fields();
+ String *s= new String(leaf.get_name(),system_charset_info);
+ if (!s->copy())
+ res->push_back(s);
+ }
+
+ key_res= mi_rnext(file_names_categories, (byte*)&cat_leaf, 0);
+ }
+
+ mi_close(file_names_categories);
+
+ DBUG_RETURN(0);
+}
+
+int send_answer_1(THD *thd, const char *s1, const char *s2,
+ const char *s3, const char *s4)
+{
+ DBUG_ENTER("send_answer_1");
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("name",64));
+ field_list.push_back(new Item_empty_string("is_category",1));
+ field_list.push_back(new Item_empty_string("description",1000));
+ field_list.push_back(new Item_empty_string("example",1000));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ String *packet= &thd->packet;
+ packet->length(0);
+ net_store_data(packet, s1);
+ net_store_data(packet, s2);
+ net_store_data(packet, s3);
+ net_store_data(packet, s4);
+
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(-1);
+
+ DBUG_RETURN(0);
+}
+
+int send_header_2(THD *thd)
+{
+ DBUG_ENTER("send_header2");
+ List<Item> field_list;
+ field_list.push_back(new Item_empty_string("name",64));
+ field_list.push_back(new Item_empty_string("is_category",1));
+ DBUG_RETURN(send_fields(thd,field_list,1));
+}
+
+int mysqld_help (THD *thd, const char *mask)
+{
+ DBUG_ENTER("mysqld_help");
+
+ MI_INFO *file_leafs= 0;
+ if (!(file_leafs= open_help_file(thd,"function")))
+ DBUG_RETURN(1);
+
+ List<String> function_list, categories_list;
+ String *name, *description, *example;
+ int res;
+
+ int count= search_functions(file_leafs, mask,
+ &function_list,&name,&description,&example);
+ if (count<0)
+ {
+ res= 1;
+ goto end;
+ }
+ else if (count==0)
+ {
+ int16 category_id;
+ count= search_categories(thd, mask, &categories_list, &category_id);
+ if (count<0)
+ {
+ res= 1;
+ goto end;
+ }
+ else if (count==1)
+ {
+ if ((res= get_all_names_for_category(thd, file_leafs,
+ category_id,&function_list)))
+ goto end;
+ List_iterator<String> it(function_list);
+ String *cur_leaf, example;
+ while ((cur_leaf = it++))
+ {
+ example.append(*cur_leaf);
+ example.append("\n",1);
+ }
+ if ((res= send_answer_1(thd, categories_list.head()->ptr(),
+ "Y","",example.ptr())))
+ goto end;
+ }
+ else
+ {
+ if ((res= send_header_2(thd)) ||
+ (count==0 &&
+ (search_categories(thd, 0, &categories_list, 0)<0 &&
+ (res= 1))) ||
+ (res= send_variant_2_list(thd,&categories_list,true)))
+ goto end;
+ }
+ }
+ else if (count==1)
+ {
+ if ((res= send_answer_1(thd,name->ptr(),"N",
+ description->ptr(), example->ptr())))
+ goto end;
+ }
+ else if((res= send_header_2(thd)) ||
+ (res= send_variant_2_list(thd,&function_list,false)) ||
+ (search_categories(thd, mask, &categories_list, 0)<0 &&
+ (res=1)) ||
+ (res= send_variant_2_list(thd,&categories_list,true)))
+ {
+ goto end;
+ }
+
+ send_eof(thd);
+
+end:
+ mi_close(file_leafs);
+ DBUG_RETURN(res);
+}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 2508314c469..6cb146afb33 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -44,7 +44,7 @@ static void unlink_blobs(register TABLE *table);
Resets form->time_stamp if a timestamp value is set
*/
-static int
+int
check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter)
{
@@ -347,7 +347,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) ||
!thd->cuted_fields))
- send_ok(&thd->net,info.copied+info.deleted,id);
+ send_ok(thd,info.copied+info.deleted,id);
else
{
char buff[160];
@@ -359,7 +359,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
else
sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted,
thd->cuted_fields);
- ::send_ok(&thd->net,info.copied+info.deleted,(ulonglong)id,buff);
+ ::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff);
}
DBUG_RETURN(0);
@@ -681,7 +681,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
delete tmp;
thd->fatal_error=1;
pthread_mutex_unlock(&LOCK_delayed_create);
- net_printf(&thd->net,ER_CANT_CREATE_THREAD,error);
+ net_printf(thd,ER_CANT_CREATE_THREAD,error);
DBUG_RETURN(0);
}
@@ -1192,7 +1192,7 @@ bool delayed_insert::handle_inserts(void)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
using_ignore=1;
}
- thd.net.last_errno = 0; // reset error for binlog
+ thd.clear_error(); // reset error for binlog
if (write_record(table,&info))
{
info.error_count++; // Ignore errors
@@ -1286,10 +1286,11 @@ bool delayed_insert::handle_inserts(void)
***************************************************************************/
int
-select_insert::prepare(List<Item> &values)
+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);
@@ -1322,9 +1323,9 @@ select_insert::~select_insert()
bool select_insert::send_data(List<Item> &values)
{
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
return 0;
}
if (fields->elements)
@@ -1345,7 +1346,8 @@ bool select_insert::send_data(List<Item> &values)
void select_insert::send_error(uint errcode,const char *err)
{
- ::send_error(&thd->net,errcode,err);
+ //TODO error should be sent at the query processing end
+ ::send_error(thd,errcode,err);
table->file->extra(HA_EXTRA_NO_CACHE);
table->file->activate_all_index(thd);
ha_rollback_stmt(thd);
@@ -1371,7 +1373,8 @@ bool select_insert::send_eof()
if (error)
{
table->file->print_error(error,MYF(0));
- ::send_error(&thd->net);
+ //TODO error should be sent at the query processing end
+ ::send_error(thd);
return 1;
}
else
@@ -1385,7 +1388,7 @@ bool select_insert::send_eof()
thd->cuted_fields);
if (last_insert_id)
thd->insert_id(last_insert_id); // For update log
- ::send_ok(&thd->net,info.copied,last_insert_id,buff);
+ ::send_ok(thd,info.copied,last_insert_id,buff);
mysql_update_log.write(thd,thd->query,thd->query_length);
if (mysql_bin_log.is_open())
{
@@ -1403,10 +1406,11 @@ bool select_insert::send_eof()
***************************************************************************/
int
-select_create::prepare(List<Item> &values)
+select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("select_create::prepare");
+ unit= u;
table=create_table_from_items(thd, create_info, db, name,
extra_fields, keys, &values, &lock);
if (!table)
@@ -1436,9 +1440,9 @@ select_create::prepare(List<Item> &values)
bool select_create::send_data(List<Item> &values)
{
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
return 0;
}
fill_record(field,values);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 854f3924155..975c3cfcf2b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -21,6 +21,7 @@
#include "item_create.h"
#include <m_ctype.h>
#include <hash.h>
+#include <assert.h>
LEX_STRING tmp_table_alias= {(char*) "tmp-table",8};
@@ -92,15 +93,15 @@ void lex_init(void)
/* Fill state_map with states to get a faster parser */
for (i=0; i < 256 ; i++)
{
- if (isalpha(i))
+ if (my_isalpha(system_charset_info,i))
state_map[i]=(uchar) STATE_IDENT;
- else if (isdigit(i))
+ else if (my_isdigit(system_charset_info,i))
state_map[i]=(uchar) STATE_NUMBER_IDENT;
#if defined(USE_MB) && defined(USE_MB_IDENT)
- else if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, i))
+ else if (use_mb(system_charset_info) && my_ismbhead(system_charset_info, i))
state_map[i]=(uchar) STATE_IDENT;
#endif
- else if (!isgraph(i))
+ else if (!my_isgraph(system_charset_info,i))
state_map[i]=(uchar) STATE_SKIP;
else
state_map[i]=(uchar) STATE_CHAR;
@@ -142,12 +143,13 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
lex->next_state=STATE_START;
lex->end_of_query=(lex->ptr=buf)+length;
lex->yylineno = 1;
- lex->select->create_refs=lex->in_comment=0;
+ lex->select_lex.create_refs=lex->in_comment=0;
lex->length=0;
- lex->select->in_sum_expr=0;
- lex->select->expr_list.empty();
- lex->select->ftfunc_list.empty();
- lex->convert_set=(lex->thd=thd)->variables.convert_set;
+ lex->select_lex.in_sum_expr=0;
+ 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->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;
@@ -158,7 +160,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
void lex_end(LEX *lex)
{
- lex->select->expr_list.delete_elements(); // If error when parsing sql-varargs
+ lex->select_lex.expr_list.delete_elements(); // If error when parsing sql-varargs
x_free(lex->yacc_yyss);
x_free(lex->yacc_yyvs);
}
@@ -222,8 +224,8 @@ static char *get_text(LEX *lex)
c = yyGet();
#ifdef USE_MB
int l;
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info,
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query))) {
lex->ptr += l-1;
@@ -267,8 +269,8 @@ static char *get_text(LEX *lex)
{
#ifdef USE_MB
int l;
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info,
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info,
(const char *)str, (const char *)end))) {
while (l--)
*to++ = *str++;
@@ -473,11 +475,11 @@ int yylex(void *arg)
break;
}
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- if (my_ismbhead(default_charset_info, yyGetLast()))
+ if (my_ismbhead(system_charset_info, yyGetLast()))
{
- int l = my_ismbchar(default_charset_info,
+ int l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query);
if (l == 0) {
@@ -489,10 +491,10 @@ int yylex(void *arg)
while (state_map[c=yyGet()] == STATE_IDENT ||
state_map[c] == STATE_NUMBER_IDENT)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(system_charset_info, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -525,7 +527,19 @@ int yylex(void *arg)
yylval->lex_str=get_token(lex,length);
if (lex->convert_set)
lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
- return(IDENT);
+
+ /*
+ Note: "SELECT _bla AS 'alias'"
+ _bla should be considered as a IDENT if charset haven't been found.
+ So we don't use MYF(MY_WME) with get_charset_by_name to avoid
+ producing an error.
+ */
+
+ if ((yylval->lex_str.str[0]=='_') &&
+ (lex->charset=get_charset_by_name(yylval->lex_str.str+1,MYF(0))))
+ return(UNDERSCORE_CHARSET);
+ else
+ return(IDENT);
case STATE_IDENT_SEP: // Found ident and now '.'
lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
@@ -535,7 +549,7 @@ int yylex(void *arg)
return((int) c);
case STATE_NUMBER_IDENT: // number or ident which num-start
- while (isdigit((c = yyGet()))) ;
+ while (my_isdigit(system_charset_info,(c = yyGet()))) ;
if (state_map[c] != STATE_IDENT)
{ // Can't be identifier
state=STATE_INT_OR_REAL;
@@ -544,12 +558,13 @@ int yylex(void *arg)
if (c == 'e' || c == 'E')
{
// The following test is written this way to allow numbers of type 1e1
- if (isdigit(yyPeek()) || (c=(yyGet())) == '+' || c == '-')
+ if (my_isdigit(system_charset_info,yyPeek()) ||
+ (c=(yyGet())) == '+' || c == '-')
{ // Allow 1E+10
- if (isdigit(yyPeek())) // Number must have digit after sign
+ if (my_isdigit(system_charset_info,yyPeek())) // Number must have digit after sign
{
yySkip();
- while (isdigit(yyGet())) ;
+ while (my_isdigit(system_charset_info,yyGet())) ;
yylval->lex_str=get_token(lex,yyLength());
return(FLOAT_NUM);
}
@@ -559,7 +574,7 @@ int yylex(void *arg)
else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
lex->tok_start[0] == '0' )
{ // Varbinary
- while (isxdigit((c = yyGet()))) ;
+ while (my_isxdigit(system_charset_info,(c = yyGet()))) ;
if ((lex->ptr - lex->tok_start) >= 4 && state_map[c] != STATE_IDENT)
{
yylval->lex_str=get_token(lex,yyLength());
@@ -573,11 +588,11 @@ int yylex(void *arg)
// fall through
case STATE_IDENT_START: // Incomplete ident
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- if (my_ismbhead(default_charset_info, yyGetLast()))
+ if (my_ismbhead(system_charset_info, yyGetLast()))
{
- int l = my_ismbchar(default_charset_info,
+ int l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query);
if (l == 0)
@@ -590,10 +605,10 @@ int yylex(void *arg)
while (state_map[c=yyGet()] == STATE_IDENT ||
state_map[c] == STATE_NUMBER_IDENT)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(system_charset_info, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -620,15 +635,15 @@ int yylex(void *arg)
case STATE_USER_VARIABLE_DELIMITER:
lex->tok_start=lex->ptr; // Skip first `
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
c != (uchar) NAMES_SEP_CHAR)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(system_charset_info, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -653,17 +668,18 @@ int yylex(void *arg)
if (prev_state == STATE_OPERATOR_OR_IDENT)
{
if (c == '-' && yyPeek() == '-' &&
- (isspace(yyPeek2()) || iscntrl(yyPeek2())))
+ (my_isspace(system_charset_info,yyPeek2()) ||
+ my_iscntrl(system_charset_info,yyPeek2())))
state=STATE_COMMENT;
else
state= STATE_CHAR; // Must be operator
break;
}
- if (!isdigit(c=yyGet()) || yyPeek() == 'x')
+ if (!my_isdigit(system_charset_info,c=yyGet()) || yyPeek() == 'x')
{
if (c != '.')
{
- if (c == '-' && isspace(yyPeek()))
+ if (c == '-' && my_isspace(system_charset_info,yyPeek()))
state=STATE_COMMENT;
else
state = STATE_CHAR; // Return sign as single char
@@ -671,9 +687,9 @@ int yylex(void *arg)
}
yyUnget(); // Fix for next loop
}
- while (isdigit(c=yyGet())) ; // Incomplete real or int number
+ while (my_isdigit(system_charset_info,c=yyGet())) ; // Incomplete real or int number
if ((c == 'e' || c == 'E') &&
- (yyPeek() == '+' || yyPeek() == '-' || isdigit(yyPeek())))
+ (yyPeek() == '+' || yyPeek() == '-' || my_isdigit(system_charset_info,yyPeek())))
{ // Real number
yyUnget();
c= '.'; // Fool next test
@@ -687,19 +703,19 @@ int yylex(void *arg)
}
// fall through
case STATE_REAL: // Incomplete real number
- while (isdigit(c = yyGet())) ;
+ while (my_isdigit(system_charset_info,c = yyGet())) ;
if (c == 'e' || c == 'E')
{
c = yyGet();
if (c == '-' || c == '+')
c = yyGet(); // Skip sign
- if (!isdigit(c))
+ if (!my_isdigit(system_charset_info,c))
{ // No digit after sign
state= STATE_CHAR;
break;
}
- while (isdigit(yyGet())) ;
+ while (my_isdigit(system_charset_info,yyGet())) ;
yylval->lex_str=get_token(lex,yyLength());
return(FLOAT_NUM);
}
@@ -708,7 +724,7 @@ int yylex(void *arg)
case STATE_HEX_NUMBER: // Found x'hexstring'
yyGet(); // Skip '
- while (isxdigit((c = yyGet()))) ;
+ while (my_isxdigit(system_charset_info,(c = yyGet()))) ;
length=(lex->ptr - lex->tok_start); // Length of hexnum+3
if (!(length & 1) || c != '\'')
{
@@ -788,7 +804,7 @@ int yylex(void *arg)
ulong version=MYSQL_VERSION_ID;
yySkip();
state=STATE_START;
- if (isdigit(yyPeek()))
+ if (my_isdigit(system_charset_info,yyPeek()))
{ // Version number
version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
}
@@ -839,11 +855,10 @@ 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 (isdigit(yyPeek()))
+ if (my_isdigit(system_charset_info,yyPeek()))
state = STATE_REAL; // Real
else
{
@@ -868,7 +883,7 @@ int yylex(void *arg)
return((int) '@');
case STATE_HOSTNAME: // end '@' of user@hostname
for (c=yyGet() ;
- isalnum(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);
@@ -902,3 +917,370 @@ int yylex(void *arg)
}
}
}
+
+/*
+ st_select_lex structures initialisations
+*/
+
+void st_select_lex_node::init_query()
+{
+ next= master= slave= link_next= 0;
+ prev= link_prev= 0;
+}
+
+void st_select_lex_node::init_select()
+{
+ order_list.elements= 0;
+ order_list.first= 0;
+ order_list.next= (byte**) &order_list.first;
+ select_limit= HA_POS_ERROR;
+ offset_limit= 0;
+ create_refs= dependent= 0;
+}
+
+void st_select_lex_unit::init_query()
+{
+ linkage= GLOBAL_OPTIONS_TYPE;
+ st_select_lex_node::init_query();
+ global_parameters= this;
+ select_limit_cnt= HA_POS_ERROR;
+ offset_limit_cnt= 0;
+ union_option= 0;
+ prepared= optimized= executed= 0;
+ item= 0;
+}
+
+void st_select_lex::init_query()
+{
+ st_select_lex_node::init_query();
+ table_list.elements= 0;
+ table_list.first= 0;
+ table_list.next= (byte**) &table_list.first;
+ item_list.empty();
+ join= 0;
+ olap= UNSPECIFIED_OLAP_TYPE;
+}
+
+void st_select_lex::init_select()
+{
+ st_select_lex_node::init_select();
+ group_list.elements= 0;
+ group_list.first= 0;
+ group_list.next= (byte**) &group_list.first;
+ options= 0;
+ where= having= 0;
+ when_list.empty();
+ expr_list.empty();
+ interval_list.empty();
+ use_index.empty();
+ ftfunc_list_alloc.empty();
+ ftfunc_list= &ftfunc_list_alloc;
+ linkage= UNSPECIFIED_TYPE;
+ having_fix_field= 0;
+}
+
+/*
+ st_select_lex structures linking
+*/
+
+/* include on level down */
+void st_select_lex_node::include_down(st_select_lex_node *upper)
+{
+ if ((next= upper->slave))
+ next->prev= &next;
+ prev= &upper->slave;
+ upper->slave= this;
+ master= upper;
+}
+
+/* include neighbour (on same level) */
+void st_select_lex_node::include_neighbour(st_select_lex_node *before)
+{
+ if ((next= before->next))
+ next->prev= &next;
+ prev= &before->next;
+ before->next= this;
+ master= before->master;
+}
+
+/* including in global SELECT_LEX list */
+void st_select_lex_node::include_global(st_select_lex_node **plink)
+{
+ if ((link_next= *plink))
+ link_next->link_prev= &link_next;
+ link_prev= plink;
+ *plink= this;
+}
+
+//excluding from global list (internal function)
+void st_select_lex_node::fast_exclude()
+{
+ if(link_prev)
+ {
+ if ((*link_prev= link_next))
+ link_next->link_prev= link_prev;
+ // Remove slave structure
+ for (; slave; slave= slave->next)
+ slave->fast_exclude();
+ }
+}
+
+/*
+ excluding select_lex structure (except first (first select can't be
+ deleted, because it is most upper select))
+*/
+void st_select_lex_node::exclude()
+{
+ //exclude from global list
+ fast_exclude();
+ //exclude from other structures
+ if ((*prev= next))
+ next->prev= prev;
+ /*
+ We do not need following statements, because prev pointer of first
+ list element point to master->slave
+ if (master->slave == this)
+ master->slave= next;
+ */
+}
+
+st_select_lex* st_select_lex_node::select_lex()
+{
+ DBUG_ENTER("st_select_lex_node::select_lex (never should be called)");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0);
+}
+
+bool st_select_lex_node::add_item_to_list(Item *item)
+{
+ return 1;
+}
+
+bool st_select_lex_node::add_group_to_list(Item *item, bool asc)
+{
+ return 1;
+}
+
+bool st_select_lex_node::add_order_to_list(Item *item, bool asc)
+{
+ return add_to_list(order_list,item,asc);
+}
+
+bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func)
+{
+ return 1;
+}
+
+/*
+ st_select_lex_node::mark_as_dependent mark all st_select_lex struct from
+ this to 'last' as dependent
+
+ SYNOPSIS
+ last - pointer to last st_select_lex struct, before wich all
+ st_select_lex have to be marked as dependent
+
+ NOTE
+ 'last' should be reachable from this st_select_lex_node
+
+*/
+
+void st_select_lex_node::mark_as_dependent(SELECT_LEX *last)
+{
+ /*
+ Mark all selects from resolved to 1 before select where was
+ found table as depended (of select where was found table)
+ */
+ for (SELECT_LEX_NODE *s= this;
+ s &&s != last;
+ s= s->outer_select())
+ if( !s->dependent )
+ {
+ // Select is dependent of outer select
+ s->dependent= 1;
+ if (s->linkage != GLOBAL_OPTIONS_TYPE)
+ {
+ //s is st_select_lex*
+
+ s->master_unit()->dependent= 1;
+ //Tables will be reopened many times
+ for (TABLE_LIST *tbl=
+ s->get_table_list();
+ tbl;
+ tbl= tbl->next)
+ tbl->shared= 1;
+ }
+ }
+}
+
+bool st_select_lex_node::set_braces(bool value) { return 1; }
+bool st_select_lex_node::inc_in_sum_expr() { return 1; }
+uint st_select_lex_node::get_in_sum_expr() { return 0; }
+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,
+ LEX_STRING *alias,
+ bool updating,
+ thr_lock_type flags,
+ List<String> *use_index,
+ List<String> *ignore_index)
+{
+ return 0;
+}
+
+/*
+ This is used for UNION & subselect to create a new table list of all used
+ tables.
+ The table_list->table entry in all used tables are set to point
+ to the entries in this list.
+*/
+
+// interface
+bool st_select_lex_unit::create_total_list(THD *thd, st_lex *lex,
+ TABLE_LIST **result)
+{
+ *result= 0;
+ return create_total_list_n_last_return(thd, lex, &result);
+}
+
+// list creator
+bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
+ TABLE_LIST ***result)
+{
+ TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first;
+ TABLE_LIST **new_table_list= *result, *aux;
+ SELECT_LEX *sl= (SELECT_LEX*)slave;
+ for (; sl; sl= sl->next_select())
+ {
+ // check usage of ORDER BY in union
+ if (sl->order_list.first && sl->next_select() && !sl->braces)
+ {
+ net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY");
+ return 1;
+ }
+ for (SELECT_LEX_UNIT *inner= sl->first_inner_unit();
+ inner;
+ inner= inner->next_unit())
+ if (inner->create_total_list_n_last_return(thd, lex,
+ &slave_list_last))
+ return 1;
+ if ((aux= (TABLE_LIST*) sl->table_list.first))
+ {
+ TABLE_LIST *next;
+ for (; aux; aux= next)
+ {
+ TABLE_LIST *cursor;
+ next= aux->next;
+ for (cursor= **result; cursor; cursor= cursor->next)
+ if (!strcmp(cursor->db, aux->db) &&
+ !strcmp(cursor->real_name, aux->real_name) &&
+ !strcmp(cursor->alias, aux->alias))
+ break;
+ 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))))
+ {
+ send_error(thd,0);
+ return 1;
+ }
+ *new_table_list= cursor;
+ new_table_list= &cursor->next;
+ *new_table_list= 0; // end result list
+ }
+ else
+ aux->shared= 1; // Mark that it's used twice
+ aux->table_list= cursor;
+ }
+ }
+ }
+ if (slave_list_first)
+ {
+ *new_table_list= slave_list_first;
+ new_table_list= slave_list_last;
+ }
+ *result= new_table_list;
+ return 0;
+}
+
+st_select_lex_unit* st_select_lex_unit::master_unit()
+{
+ return this;
+}
+
+st_select_lex* st_select_lex_unit::outer_select()
+{
+ return (st_select_lex*) master;
+}
+
+st_select_lex* st_select_lex::select_lex()
+{
+ return this;
+}
+
+bool st_select_lex::add_item_to_list(Item *item)
+{
+ return item_list.push_back(item);
+}
+
+bool st_select_lex::add_group_to_list(Item *item, bool asc)
+{
+ return add_to_list(group_list, item, asc);
+}
+
+bool st_select_lex::add_ftfunc_to_list(Item_func_match *func)
+{
+ return !func || ftfunc_list->push_back(func); // end of memory?
+}
+
+st_select_lex_unit* st_select_lex::master_unit()
+{
+ return (st_select_lex_unit*) master;
+}
+
+st_select_lex* st_select_lex::outer_select()
+{
+ return (st_select_lex*) master->get_master();
+}
+
+bool st_select_lex::set_braces(bool value)
+{
+ braces= value;
+ return 0;
+}
+
+bool st_select_lex::inc_in_sum_expr()
+{
+ in_sum_expr++;
+ return 0;
+}
+
+uint st_select_lex::get_in_sum_expr()
+{
+ return in_sum_expr;
+}
+
+TABLE_LIST* st_select_lex::get_table_list()
+{
+ return (TABLE_LIST*) table_list.first;
+}
+
+List<Item>* st_select_lex::get_item_list()
+{
+ return &item_list;
+}
+
+List<String>* st_select_lex::get_use_index()
+{
+ return use_index_ptr;
+}
+
+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
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 54e72fafdd5..9f8e3200246 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -46,10 +46,12 @@ enum enum_sql_command {
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
SQLCOM_SHOW_INNODB_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
- SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE,
+ SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
+ SQLCOM_SHOW_CREATE_DB,
SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES,
- SQLCOM_GRANT, SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB,
+ SQLCOM_GRANT,
+ SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB,
SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK,
@@ -62,8 +64,9 @@ enum enum_sql_command {
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
- SQLCOM_EMPTY_QUERY,
- SQLCOM_END
+ SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
+ SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
+ SQLCOM_END, SQLCOM_HELP
};
enum lex_states
@@ -78,6 +81,7 @@ enum lex_states
STATE_IDENT_OR_KEYWORD
};
+
typedef List<Item> List_item;
typedef struct st_lex_master_info
@@ -93,7 +97,8 @@ typedef struct st_lex_master_info
enum sub_select_type
{
- UNSPECIFIED_TYPE, UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, OLAP_TYPE, NOT_A_SELECT
+ UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE,
+ EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE
};
enum olap_type
@@ -101,27 +106,274 @@ enum olap_type
UNSPECIFIED_OLAP_TYPE, CUBE_TYPE, ROLLUP_TYPE
};
-/* The state of the lex parsing for selects */
+/*
+ The state of the lex parsing for selects
+
+ All select describing structures linked with following pointers:
+ - list of neighbors (next/prev) (prev of first element point to slave
+ pointer of upper structure)
+ - one level units for unit (union) structure
+ - member of one union(unit) for ordinary select_lex
+ - pointer to master
+ - outer select_lex for unit (union)
+ - unit structure for ordinary select_lex
+ - pointer to slave
+ - first list element of select_lex belonged to this unit for unit
+ - first unit in list of units that belong to this select_lex (as
+ subselects or derived tables) for ordinary select_lex
+ - list of all select_lex (for group operation like correcting list of opened
+ tables)
+ for example for following query:
-typedef struct st_select_lex
-{
- enum sub_select_type linkage;
- enum olap_type olap;
- char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
- Item *where,*having;
- ha_rows select_limit,offset_limit;
+ select *
+ from table1
+ where table1.field IN (select * from table1_1_1 union
+ select * from table1_1_2)
+ union
+ select *
+ from table2
+ where table2.field=(select (select f1 from table2_1_1_1_1
+ where table2_1_1_1_1.f2=table2_1_1.f3)
+ from table2_1_1
+ where table2_1_1.f1=table2.f2)
+ union
+ select * from table3;
+
+ we will have following structure:
+
+
+ main unit
+ select1 select2 select3
+ |^^ |^
+ s||| ||master
+ l||| |+---------------------------------+
+ a||| +---------------------------------+|
+ v|||master slave ||
+ e||+-------------------------+ ||
+ V| neighbor | V|
+ unit 1.1<==================>unit1.2 unit2.1
+ select1.1.1 select 1.1.2 select1.2.1 select2.1.1 select2.1.2
+ |^
+ ||
+ V|
+ unit2.1.1.1
+ select2.1.1.1.1
+
+
+ relation in main unit will be following:
+
+ main unit
+ |^^^
+ ||||
+ |||+------------------------------+
+ ||+--------------+ |
+ slave||master | |
+ V| neighbor | neighbor |
+ select1<========>select2<========>select3
+
+ list of all select_lex will be following (as it will be constructed by
+ parser):
+
+ select1->select2->select3->select2.1.1->select 2.1.2->select2.1.1.1.1-+
+ |
+ +---------------------------------------------------------------------+
+ |
+ +->select1.1.1->select1.1.2
+
+*/
+
+/*
+ Base class for st_select_lex (SELECT_LEX) &
+ st_select_lex_unit (SELECT_LEX_UNIT)
+*/
+class st_select_lex;
+class st_select_lex_unit;
+class st_select_lex_node {
+protected:
+ st_select_lex_node *next, **prev, /* neighbor list */
+ *master, *slave, /* vertical links */
+ *link_next, **link_prev; /* list of whole SELECT_LEX */
+public:
ulong options;
+ enum sub_select_type linkage;
+ SQL_LIST order_list; /* ORDER clause */
List<List_item> expr_list;
- List<List_item> when_list;
- SQL_LIST order_list,table_list,group_list;
- List<Item> item_list;
- List<String> interval_list,use_index, *use_index_ptr,
+ List<List_item> when_list; /* WHEN clause (expression) */
+ ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
+ bool create_refs;
+ bool dependent; /* dependent from outer select subselect */
+
+ static void *operator new(size_t size)
+ {
+ return (void*) sql_calloc((uint) size);
+ }
+ static void operator delete(void *ptr,size_t size) {}
+ virtual ~st_select_lex_node() {}
+ inline st_select_lex_node* get_master() { return master; }
+ virtual void init_query();
+ virtual void init_select();
+ void include_down(st_select_lex_node *upper);
+ void include_neighbour(st_select_lex_node *before);
+ void include_global(st_select_lex_node **plink);
+ 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_ftfunc_to_list(Item_func_match *func);
+
+ virtual st_select_lex_unit* master_unit()= 0;
+ virtual st_select_lex* outer_select()= 0;
+
+ virtual bool set_braces(bool value);
+ virtual bool inc_in_sum_expr();
+ virtual uint get_in_sum_expr();
+ virtual TABLE_LIST* get_table_list();
+ 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,
+ LEX_STRING *alias,
+ bool updating,
+ thr_lock_type flags= TL_UNLOCK,
+ List<String> *use_index= 0,
+ List<String> *ignore_index= 0);
+
+ void mark_as_dependent(st_select_lex *last);
+private:
+ void fast_exclude();
+};
+typedef class st_select_lex_node SELECT_LEX_NODE;
+
+/*
+ SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group
+ SELECT_LEXs
+*/
+struct st_lex;
+class THD;
+class select_result;
+class JOIN;
+class select_union;
+class st_select_lex_unit: public st_select_lex_node {
+protected:
+ List<Item> item_list;
+ List<JOIN*> joins; /* list of *JOINs, to delete it in cleanup() */
+ TABLE_LIST result_table_list;
+ select_union *union_result;
+ TABLE *table; /* temporary table using for appending UNION results */
+ THD *thd;
+ select_result *result;
+ int res;
+ bool describe, found_rows_for_union,
+ prepared, // prepare phase already performed for UNION (unit)
+ optimized, // optimize phase already performed for UNION (unit)
+ executed; // already executed
+public:
+ /*
+ Pointer to 'last' select or pointer to unit where stored
+ global parameters for union
+ */
+ st_select_lex_node *global_parameters;
+ /* LIMIT clause runtime counters */
+ ha_rows select_limit_cnt, offset_limit_cnt;
+ /* not NULL if union used in subselect, point to subselect item */
+ Item_subselect *item;
+ uint union_option;
+
+ void init_query();
+ bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result);
+ st_select_lex_unit* master_unit();
+ 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; }
+
+ /* UNION methods */
+ int prepare(THD *thd, select_result *result);
+ int exec();
+ int cleanup();
+
+ friend void mysql_init_query(THD *thd);
+private:
+ bool create_total_list_n_last_return(THD *thd, st_lex *lex,
+ TABLE_LIST ***result);
+};
+typedef class st_select_lex_unit SELECT_LEX_UNIT;
+
+/*
+ SELECT_LEX - store information of parsed SELECT_LEX statment
+*/
+class st_select_lex: public st_select_lex_node
+{
+public:
+ char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */
+ Item *where, *having; /* WHERE & HAVING clauses */
+ enum olap_type olap;
+ SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
+ List<Item> item_list; /* list of fields & expressions */
+ List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
- List<Item_func_match> ftfunc_list;
- uint in_sum_expr, sort_default;
- bool create_refs, braces;
- st_select_lex *next;
-} SELECT_LEX;
+ /*
+ Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
+ select_lex for calling mysql_select under results of union
+ */
+ List<Item_func_match> *ftfunc_list;
+ List<Item_func_match> ftfunc_list_alloc;
+ JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
+ const char *type; /* type of select for EXPLAIN */
+ uint in_sum_expr;
+ uint select_number; /* number of select (used for EXPLAIN) */
+ bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
+ /* TRUE when having fix field called in processing of this SELECT */
+ bool having_fix_field;
+
+ void init_query();
+ void init_select();
+ st_select_lex_unit* master_unit();
+ st_select_lex_unit* first_inner_unit()
+ {
+ return (st_select_lex_unit*) slave;
+ }
+ st_select_lex* outer_select();
+ st_select_lex* next_select() { return (st_select_lex*) next; }
+ st_select_lex* next_select_in_list()
+ {
+ return (st_select_lex*) link_next;
+ }
+ st_select_lex_node** next_select_in_list_addr()
+ {
+ return &link_next;
+ }
+
+ bool set_braces(bool value);
+ bool inc_in_sum_expr();
+ 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_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,
+ LEX_STRING *alias,
+ bool updating,
+ thr_lock_type flags= TL_UNLOCK,
+ List<String> *use_index= 0,
+ List<String> *ignore_index= 0);
+ inline void init_order()
+ {
+ order_list.elements= 0;
+ order_list.first= 0;
+ order_list.next= (byte**) &order_list.first;
+ }
+
+ friend void mysql_init_query(THD *thd);
+};
+typedef class st_select_lex SELECT_LEX;
/* The state of the lex parsing. This is saved in the THD struct */
@@ -130,7 +382,10 @@ typedef struct st_lex
{
uint yylineno,yytoklen; /* Simulate lex */
LEX_YYSTYPE yylval;
- SELECT_LEX select_lex, *select, *last_selects;
+ SELECT_LEX_UNIT unit; /* most upper unit */
+ SELECT_LEX select_lex; /* first SELECT_LEX */
+ /* current SELECT_LEX in parsing */
+ SELECT_LEX_NODE *current_select;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */
@@ -139,8 +394,10 @@ typedef struct st_lex
enum SSL_type ssl_type; /* defined in violite.h */
String *wild;
sql_exchange *exchange;
+ select_result *result;
List<key_part_spec> col_list;
+ List<key_part_spec> ref_list;
List<Alter_drop> drop_list;
List<Alter_column> alter_list;
List<String> interval_list;
@@ -151,10 +408,11 @@ typedef struct st_lex
List<Item> *insert_list,field_list,value_list;
List<List_item> many_values;
List<set_var_base> var_list;
+ List<Item> param_list;
SQL_LIST proc_list, auxilliary_table_list;
TYPELIB *interval;
create_field *last_field;
- Item *default_value;
+ Item *default_value, *comment;
CONVERT *convert_set;
CONVERT *thd_convert_set; // Set with SET CHAR SET
LEX_USER *grant_user;
@@ -167,6 +425,7 @@ typedef struct st_lex
USER_RESOURCES mqh;
ulong thread_id,type;
enum_sql_command sql_command;
+ thr_lock_type lock_option;
enum lex_states next_state;
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
@@ -174,11 +433,15 @@ typedef struct st_lex
enum ha_rkey_function ha_rkey_mode;
enum enum_enable_or_disable alter_keys_onoff;
enum enum_var_type option_type;
- uint grant,grant_tot_col,which_columns, union_option;
- thr_lock_type lock_option;
- bool drop_primary, drop_if_exists, drop_temporary, local_file, olap;
- bool in_comment,ignore_space,verbose,simple_alter;
+ 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, drop_temporary, local_file;
+ bool in_comment, ignore_space, verbose, simple_alter;
+ bool derived_tables, describe, olap;
uint slave_thd_opt;
+ CHARSET_INFO *charset;
+ char *help_arg;
} LEX;
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 542eef623f0..56e6528f214 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -82,6 +82,7 @@ public:
first=tmp.first;
last=tmp.last;
}
+ inline base_list(bool error) { }
inline bool push_back(void *info)
{
if (((*last)=new list_node(info, &end_of_list)))
@@ -122,11 +123,15 @@ public:
last= &first;
return tmp->info;
}
+ inline list_node* last_node() { return *last; }
+ inline list_node* first_node() { return first;}
inline void *head() { return first->info; }
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
inline bool is_empty() { return first == &end_of_list ; }
inline list_node *last_ref() { return &end_of_list; }
friend class base_list_iterator;
+ friend class error_list;
+ friend class error_list_iterator;
protected:
void after(void *info,list_node *node)
@@ -204,6 +209,7 @@ public:
{
return el == &list->last_ref()->next;
}
+ friend class error_list_iterator;
};
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index cfb12b8a5bf..00450a3b86c 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -296,7 +296,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted,
info.records-info.copied,thd->cuted_fields);
- send_ok(&thd->net,info.copied+info.deleted,0L,name);
+ send_ok(thd,info.copied+info.deleted,0L,name);
// on the slave thd->query is never initialized
if (!thd->slave_thread)
mysql_update_log.write(thd,thd->query,thd->query_length);
@@ -374,7 +374,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
field->field_length)
length=field->field_length;
save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
- field->store((char*) pos,length);
+ field->store((char*) pos,length,default_charset_info);
pos[length]=save_chr;
if ((pos+=length) > read_info.row_end)
pos= read_info.row_end; /* Fills rest with space */
@@ -443,7 +443,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
}
field->set_notnull();
read_info.row_end[0]=0; // Safe to change end marker
- field->store((char*) read_info.row_start,length);
+ field->store((char*) read_info.row_start,length,default_charset_info);
}
if (read_info.error)
break;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0cebde364f7..4816a0539f3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -57,17 +57,15 @@ extern "C" pthread_mutex_t THR_LOCK_keycache;
extern "C" int gethostname(char *name, int namelen);
#endif
-static int check_for_max_user_connections(USER_CONN *uc);
+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 mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, char **filename_ptr,
char *table_name);
-static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result);
const char *any_db="*any*"; // Special symbol for check_access
@@ -75,10 +73,11 @@ const char *command_name[]={
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
- "Binlog Dump","Table Dump", "Connect Out", "Register Slave"
+ "Binlog Dump","Table Dump", "Connect Out", "Register Slave",
+ "Prepare", "Prepare Execute", "Long Data"
};
-bool volatile abort_slave = 0;
+static char empty_c_string[1]= {0}; // Used for not defined 'db'
#ifdef __WIN__
static void test_signal(int sig_ptr)
@@ -151,7 +150,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)))))
{
- send_error(&current_thd->net, 0, NullS); // Out of memory
+ send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
@@ -169,7 +168,7 @@ static int get_or_create_user_conn(THD *thd, const char *user,
if (hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
- send_error(&current_thd->net, 0, NullS); // Out of memory
+ send_error(thd, 0, NullS); // Out of memory
return_val=1;
goto end;
}
@@ -191,14 +190,13 @@ end:
static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count)
{
- NET *net= &thd->net;
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
if (!(thd->user = my_strdup(user, MYF(0))))
{
- send_error(net,ER_OUT_OF_RESOURCES);
+ send_error(thd,ER_OUT_OF_RESOURCES);
return 1;
}
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
@@ -214,7 +212,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
thd->master_access, thd->db ? thd->db : "*none*"));
if (thd->master_access & NO_ACCESS)
{
- net_printf(net, ER_ACCESS_DENIED_ERROR,
+ net_printf(thd, ER_ACCESS_DENIED_ERROR,
thd->user,
thd->host_or_ip,
passwd[0] ? ER(ER_YES) : ER(ER_NO));
@@ -232,7 +230,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (tmp)
{ // Too many connections
- send_error(net, ER_CON_COUNT_ERROR);
+ send_error(thd, ER_CON_COUNT_ERROR);
return(1);
}
}
@@ -249,7 +247,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
return -1;
if (thd->user_connect && thd->user_connect->user_resources.connections &&
- check_for_max_user_connections(thd->user_connect))
+ check_for_max_user_connections(thd, thd->user_connect))
return -1;
if (db && db[0])
{
@@ -259,7 +257,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
return error;
}
else
- send_ok(net); // Ready to handle questions
+ send_ok(thd); // Ready to handle questions
return 0; // ok
}
@@ -283,13 +281,14 @@ extern "C" void free_user(struct user_conn *uc)
void init_max_user_conn(void)
{
- (void) hash_init(&hash_user_connections,max_connections,0,0,
+ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
+ 0,0,
(hash_get_key) get_key_conn, (hash_free_key) free_user,
0);
}
-static int check_for_max_user_connections(USER_CONN *uc)
+static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
{
int error=0;
DBUG_ENTER("check_for_max_user_connections");
@@ -297,7 +296,7 @@ static int check_for_max_user_connections(USER_CONN *uc)
if (max_user_connections &&
(max_user_connections <= (uint) uc->connections))
{
- net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user);
+ net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
error=1;
goto end;
}
@@ -305,11 +304,10 @@ static int check_for_max_user_connections(USER_CONN *uc)
if (uc->user_resources.connections &&
uc->conn_per_hour++ >= uc->user_resources.connections)
{
- net_printf(&current_thd->net, ER_USER_LIMIT_REACHED, uc->user,
+ net_printf(thd, ER_USER_LIMIT_REACHED, uc->user,
"max_connections",
(long) uc->user_resources.connections);
error=1;
- goto end;
}
end:
DBUG_RETURN(error);
@@ -400,7 +398,7 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.questions &&
uc->questions++ >= uc->user_resources.questions)
{
- net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
+ net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions",
(long) uc->user_resources.questions);
error=1;
goto end;
@@ -411,7 +409,7 @@ static bool check_mqh(THD *thd, uint check_command)
if (uc->user_resources.updates && uc_update_queries[check_command] &&
uc->updates++ >= uc->user_resources.updates)
{
- net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
+ net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates",
(long) uc->user_resources.updates);
error=1;
goto end;
@@ -516,7 +514,7 @@ check_connections(THD *thd)
{
/* 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;
+ int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41;
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
@@ -538,7 +536,7 @@ check_connections(THD *thd)
int2store(end+3,thd->server_status);
bzero(end+5,13);
end+=18;
- if (net_write_command(net,(uchar) protocol_version, buff,
+ if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
(uint) (end-buff)) ||
(pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
@@ -669,7 +667,7 @@ pthread_handler_decl(handle_one_connection,arg)
if ((error=check_connections(thd)))
{ // Wrong permissions
if (error > 0)
- net_printf(net,error,thd->host_or_ip);
+ net_printf(thd,error,thd->host_or_ip);
#ifdef __NT__
if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE)
sleep(1); /* must wait after eof() */
@@ -678,7 +676,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
@@ -698,7 +696,7 @@ pthread_handler_decl(handle_one_connection,arg)
if (thd->user_connect)
decrease_user_connections(thd->user_connect);
free_root(&thd->mem_root,MYF(0));
- if (net->error && net->vio != 0)
+ if (net->error && net->vio != 0 && net->report_error)
{
if (!thd->killed && thd->variables.log_warnings)
sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
@@ -707,7 +705,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->host_or_ip,
(net->last_errno ? ER(net->last_errno) :
ER(ER_UNKNOWN_ERROR)));
- send_error(net,net->last_errno,NullS);
+ send_error(thd,net->last_errno,NullS);
statistic_increment(aborted_threads,&LOCK_status);
}
@@ -754,7 +752,7 @@ extern "C" 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;
@@ -768,7 +766,8 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
- while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
+ while (length && (my_isspace(system_charset_info, buff[length-1]) ||
+ buff[length-1] == ';'))
length--;
buff[length]=0;
thd->current_tablenr=0;
@@ -802,11 +801,11 @@ end:
DBUG_RETURN(0); // Never reached
}
+ /* This works because items are allocated with sql_alloc() */
-inline void free_items(THD *thd)
+void free_items(Item *item)
{
- /* This works because items are allocated with sql_alloc() */
- for (Item *item=thd->free_list ; item ; item=item->next)
+ for (; item ; item=item->next)
delete item;
}
@@ -830,7 +829,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if (!db || check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
goto err;
}
if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege))
@@ -874,8 +873,7 @@ bool do_command(THD *thd)
old_timeout=net->read_timeout;
// Wait max for 8 hours
net->read_timeout=(uint) thd->variables.net_wait_timeout;
- net->last_error[0]=0; // Clear error message
- net->last_errno=0;
+ thd->clear_error(); // Clear error message
net_new_transaction(net);
if ((packet_length=my_net_read(net)) == packet_error)
@@ -928,7 +926,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_REGISTER_SLAVE:
{
if (!register_slave(thd, (uchar*)packet, packet_length))
- send_ok(&thd->net);
+ send_ok(thd);
break;
}
case COM_TABLE_DUMP:
@@ -944,7 +942,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
memcpy(tbl_name, packet + db_len + 2, tbl_len);
tbl_name[tbl_len] = 0;
if (mysql_table_dump(thd, db, tbl_name, -1))
- send_error(&thd->net); // dump to NET
+ send_error(thd); // dump to NET
break;
}
@@ -969,7 +967,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
{ // Check if protocol is ok
- send_error(net, ER_UNKNOWN_COM_ERROR);
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
break;
}
if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
@@ -991,35 +989,28 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->password=test(passwd[0]);
break;
}
-
+ case COM_EXECUTE:
+ {
+ mysql_stmt_execute(thd, packet);
+ break;
+ }
+ case COM_LONG_DATA:
+ {
+ mysql_stmt_get_longdata(thd, packet, packet_length);
+ break;
+ }
+ case COM_PREPARE:
+ {
+ mysql_stmt_prepare(thd, packet, packet_length);
+ break;
+ }
case COM_QUERY:
{
- packet_length--; // Remove end null
- /* Remove garage at start and end of query */
- while (isspace(packet[0]) && packet_length > 0)
- {
- packet++;
- packet_length--;
- }
- char *pos=packet+packet_length; // Point at end null
- while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
- {
- pos--;
- packet_length--;
- }
- /* We must allocate some extra memory for query cache */
- if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
- packet_length,
- thd->db_length+2)))
- break;
- thd->query[packet_length]=0;
- thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory
- if (!(specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ if (alloc_query(thd, packet, packet_length))
+ break; // fatal error is set
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query));
- /* thd->query_length is set by mysql_parse() */
- mysql_parse(thd,thd->query,packet_length);
+ mysql_parse(thd,thd->query, thd->query_length);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
@@ -1027,7 +1018,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_FIELD_LIST: // This isn't actually needed
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
break;
#else
{
@@ -1037,7 +1028,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
- send_error(net,ER_NO_DB_ERROR);
+ send_error(thd,ER_NO_DB_ERROR);
break;
}
thd->free_list=0;
@@ -1055,7 +1046,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2))
break;
mysqld_list_fields(thd,&table_list,fields);
- free_items(thd);
+ free_items(thd->free_list);
break;
}
#endif
@@ -1073,11 +1064,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
if (lower_case_table_names)
- casedn_str(db);
+ my_casedn_str(system_charset_info, db);
if (check_access(thd,CREATE_ACL,db,0,1))
break;
mysql_log.write(thd,command,packet);
@@ -1091,14 +1082,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
// null test to handle EOM
if (!db || !strip_sp(db) || check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
+ net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
if (lower_case_table_names)
- casedn_str(db);
+ my_casedn_str(system_charset_info, db);
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
break;
}
mysql_log.write(thd,command,db);
@@ -1137,9 +1128,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
mysql_log.write(thd,command,NullS);
if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0))
- send_error(net,0);
+ send_error(thd,0);
else
- send_eof(net);
+ send_eof(thd);
break;
}
case COM_SHUTDOWN:
@@ -1148,12 +1139,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; /* purecov: inspected */
DBUG_PRINT("quit",("Got shutdown command"));
mysql_log.write(thd,command,NullS);
- send_eof(net);
+ send_eof(thd);
#ifdef __WIN__
sleep(1); // must wait after eof()
#endif
#ifndef OS2
- send_eof(net); // This is for 'quit request'
+ send_eof(thd); // This is for 'quit request'
#endif
close_connection(net);
close_thread_tables(thd); // Free before kill
@@ -1186,7 +1177,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_PING:
statistic_increment(com_other,&LOCK_status);
- send_ok(net); // Tell client we are alive
+ send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
@@ -1209,14 +1200,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; /* purecov: inspected */
mysql_print_status(thd);
mysql_log.write(thd,command,NullS);
- send_eof(net);
+ send_eof(thd);
break;
case COM_SLEEP:
case COM_CONNECT: // Impossible here
case COM_TIME: // Impossible from client
case COM_DELAYED_INSERT:
default:
- send_error(net, ER_UNKNOWN_COM_ERROR);
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
break;
}
if (thd->lock || thd->open_tables)
@@ -1226,7 +1217,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
if (thd->fatal_error)
- send_error(net,0); // End of memory ?
+ send_error(thd,0); // End of memory ?
time_t start_of_query=thd->start_time;
thd->end_time(); // Set start time
@@ -1258,21 +1249,82 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
DBUG_RETURN(error);
}
+
+/*
+ Read query from packet and store in thd->query
+ Used in COM_QUERY and COM_PREPARE
+
+ DESCRIPTION
+ Sets the following THD variables:
+ query
+ query_length
+
+ RETURN VALUES
+ 0 ok
+ 1 error; In this case thd->fatal_error is set
+*/
+
+bool alloc_query(THD *thd, char *packet, ulong packet_length)
+{
+ packet_length--; // Remove end null
+ /* Remove garage at start and end of query */
+ while (my_isspace(system_charset_info,packet[0]) && packet_length > 0)
+ {
+ packet++;
+ packet_length--;
+ }
+ char *pos=packet+packet_length; // Point at end null
+ while (packet_length > 0 &&
+ (pos[-1] == ';' || my_isspace(system_charset_info,pos[-1])))
+ {
+ pos--;
+ packet_length--;
+ }
+ /* We must allocate some extra memory for query cache */
+ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
+ packet_length,
+ thd->db_length+2)))
+ return 1;
+ thd->query[packet_length]=0;
+ thd->query_length= packet_length;
+ thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory
+
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),QUERY_PRIOR);
+ return 0;
+}
+
/****************************************************************************
** mysql_execute_command
** Execute command saved in thd and current_lex->sql_command
****************************************************************************/
void
-mysql_execute_command(void)
+mysql_execute_command(THD *thd)
{
- int res=0;
- THD *thd=current_thd;
+ int res= 0;
LEX *lex= &thd->lex;
- TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
- SELECT_LEX *select_lex = lex->select;
+ TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
+ TABLE_LIST *cursor;
+ SELECT_LEX *select_lex= &lex->select_lex;
+ SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_execute_command");
+ /*
+ Reset warning count for each query that uses tables
+ A better approach would be to reset this for any commands
+ that is not a SHOW command or a select that only access local
+ variables, but for now this is probably good enough.
+ */
+ if (tables || lex->select_lex.next_select_in_list())
+ mysql_reset_errors(thd);
+ /*
+ Save old warning count to be able to send to client how many warnings we
+ got
+ */
+ thd->old_total_warn_count= thd->total_warn_count;
+
+ thd->net.report_error= 0;
if (thd->slave_thread)
{
/*
@@ -1296,10 +1348,28 @@ mysql_execute_command(void)
}
/*
- 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
+ TODO: make derived tables processing 'inside' SELECT processing.
+ TODO: solve problem with depended derived tables in subselects
*/
- if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) ||
+ if (lex->derived_tables)
+ {
+ for (SELECT_LEX *sl= &lex->select_lex; sl; sl= sl->next_select_in_list())
+ if (sl->linkage != DERIVED_TABLE_TYPE)
+ 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)))
+ {
+ if (res < 0 || thd->net.report_error)
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ DBUG_VOID_RETURN;
+ }
+ }
+ if ((lex->select_lex.next_select_in_list() &&
+ lex->unit.create_total_list(thd, lex, &tables)) ||
(table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables)))
DBUG_VOID_RETURN;
@@ -1308,9 +1378,7 @@ mysql_execute_command(void)
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
- select_result *result;
- if (select_lex->options & SELECT_DESCRIBE)
- lex->exchange=0;
+ select_result *result=lex->result;
if (tables)
{
res=check_table_access(thd,
@@ -1327,62 +1395,64 @@ mysql_execute_command(void)
break; // Error message is given
}
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
+ 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;
- if (lex->exchange)
+ if (!(res=open_and_lock_tables(thd,tables)))
{
- if (lex->exchange->dumpfile)
+ if (lex->describe)
{
- if (!(result=new select_dump(lex->exchange)))
+ if (!(result= new select_send()))
{
- res= -1;
- break;
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_VOID_RETURN;
}
+ else
+ thd->send_explain_fields(result);
+ fix_tables_pointers(select_lex);
+ res= mysql_explain_union(thd, &thd->lex.unit, result);
+ MYSQL_LOCK *save_lock= thd->lock;
+ thd->lock= (MYSQL_LOCK *)0;
+ result->send_eof();
+ thd->lock= save_lock;
}
else
{
- if (!(result=new select_export(lex->exchange)))
+ if (!result)
{
- res= -1;
- break;
- }
- }
- }
- else if (!(result=new select_send()))
- {
- res= -1;
+ if ((result=new select_send()))
+ {
+ /*
+ Normal select:
+ Change lock if we are using SELECT HIGH PRIORITY,
+ FOR UPDATE or IN SHARE MODE
+
+ TODO: Delete the following loop when locks is set by sql_yacc
+ */
+ TABLE_LIST *table;
+ for (table = tables ; table ; table=table->next)
+ table->lock_type= lex->lock_option;
+ }
+ else
+ {
+ res= -1;
#ifdef DELETE_ITEMS
- delete select_lex->having;
- delete select_lex->where;
+ delete select_lex->having;
+ delete select_lex->where;
#endif
- break;
- }
- else
- {
- /*
- Normal select:
- Change lock if we are using SELECT HIGH PRIORITY,
- FOR UPDATE or IN SHARE MODE
-
- TODO: Delete the following loop when locks is set by sql_yacc
- */
- TABLE_LIST *table;
- for (table = tables ; table ; table=table->next)
- table->lock_type= lex->lock_option;
- }
-
- if (!(res=open_and_lock_tables(thd,tables)))
- {
- query_cache_store_query(thd, tables);
- res=handle_select(thd, lex, result);
+ break;
+ }
+ }
+ query_cache_store_query(thd, tables);
+ res=handle_select(thd, lex, result);
+ }
}
- else
- delete result;
break;
}
case SQLCOM_DO:
@@ -1390,7 +1460,11 @@ mysql_execute_command(void)
break;
case SQLCOM_EMPTY_QUERY:
- send_ok(&thd->net);
+ send_ok(thd);
+ break;
+
+ case SQLCOM_HELP:
+ res= mysqld_help(thd,lex->help_arg);
break;
case SQLCOM_PURGE:
@@ -1400,12 +1474,25 @@ mysql_execute_command(void)
res = purge_master_logs(thd, lex->to_log);
break;
}
+ case SQLCOM_SHOW_WARNS:
+ {
+ res= mysqld_show_warnings(thd, (ulong)
+ ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN)));
+ break;
+ }
+ case SQLCOM_SHOW_ERRORS:
+ {
+ res= mysqld_show_warnings(thd, (ulong)
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR));
+ break;
+ }
case SQLCOM_SHOW_NEW_MASTER:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
#ifndef WORKING_NEW_MASTER
- net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
+ net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER");
res= 1;
#else
res = show_new_master(thd);
@@ -1508,7 +1595,7 @@ mysql_execute_command(void)
}
if (strlen(tables->real_name) > NAME_LEN)
{
- net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->real_name);
+ net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
break;
}
LOCK_ACTIVE_MI;
@@ -1516,7 +1603,7 @@ mysql_execute_command(void)
if (!fetch_master_table(thd, tables->db, tables->real_name,
active_mi, 0))
{
- send_ok(&thd->net);
+ send_ok(thd);
}
UNLOCK_ACTIVE_MI;
break;
@@ -1544,7 +1631,7 @@ mysql_execute_command(void)
}
if (strlen(tables->real_name) > NAME_LEN)
{
- net_printf(&thd->net, ER_WRONG_TABLE_NAME, tables->alias);
+ net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias);
res=0;
break;
}
@@ -1568,7 +1655,7 @@ mysql_execute_command(void)
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
check_dup(tables->db, tables->real_name, tables->next))
{
- net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
if (tables->next)
@@ -1580,10 +1667,11 @@ mysql_execute_command(void)
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // No limit
+ unit->offset_limit_cnt= select_lex->offset_limit;
+ unit->select_limit_cnt= select_lex->select_limit+
+ select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // No limit
/* Skip first table, which is the table we are creating */
lex->select_lex.table_list.first=
@@ -1605,9 +1693,9 @@ mysql_execute_command(void)
res = mysql_create_table(thd,tables->db ? tables->db : thd->db,
tables->real_name, &lex->create_info,
lex->create_list,
- lex->key_list,0, 0); // do logging
+ lex->key_list,0,0,0); // do logging
if (!res)
- send_ok(&thd->net);
+ send_ok(thd);
}
break;
}
@@ -1640,14 +1728,14 @@ mysql_execute_command(void)
}
case SQLCOM_ALTER_TABLE:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
break;
#else
{
ulong priv=0;
if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN))
{
- net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name);
+ net_printf(thd,ER_WRONG_TABLE_NAME,lex->name);
res=0;
break;
}
@@ -1730,7 +1818,7 @@ mysql_execute_command(void)
}
case SQLCOM_SHOW_BINLOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
@@ -1742,7 +1830,7 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_CREATE:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
@@ -1796,6 +1884,7 @@ mysql_execute_command(void)
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
create_info.row_type=ROW_TYPE_DEFAULT;
+ create_info.table_charset=default_charset_info;
res= mysql_alter_table(thd, NullS, NullS, &create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
@@ -1813,7 +1902,7 @@ mysql_execute_command(void)
goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
- send_error(&thd->net,ER_WRONG_VALUE_COUNT);
+ send_error(thd,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
if (select_lex->table_list.elements == 1)
@@ -1834,27 +1923,28 @@ mysql_execute_command(void)
const char *msg=0;
lex->sql_command=SQLCOM_MULTI_UPDATE;
- for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
+ for (auxi= (TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
table_count++;
+
if (select_lex->order_list.elements)
msg="ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit !=
HA_POS_ERROR)
msg="LIMIT";
-
if (msg)
{
- net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", 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;
- thd->select_limit=HA_POS_ERROR;
+ 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 &&
+ !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, table_count)))
{
@@ -1867,13 +1957,13 @@ mysql_execute_command(void)
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);
+ 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
@@ -1923,14 +2013,14 @@ mysql_execute_command(void)
}
select_result *result;
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // No limit
+ unit->offset_limit_cnt= select_lex->offset_limit;
+ unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
+ 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))
{
- net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
{
@@ -1962,7 +2052,7 @@ mysql_execute_command(void)
*/
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS);
goto error;
}
res=mysql_truncate(thd,tables);
@@ -1994,7 +2084,7 @@ mysql_execute_command(void)
goto error;
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
{
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
goto error;
}
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
@@ -2010,34 +2100,33 @@ mysql_execute_command(void)
}
if (!walk)
{
- net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name);
+ net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name);
goto error;
}
walk->lock_type= auxi->lock_type;
- auxi->table= (TABLE *) walk; // Remember corresponding table
+ auxi->table_list= walk; // Remember corresponding table
}
if (add_item_to_list(new Item_null()))
{
res= -1;
break;
}
- tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
thd->proc_info="init";
if ((res=open_and_lock_tables(thd,tables)))
break;
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
- auxi->table= ((TABLE_LIST*) auxi->table)->table;
+ auxi->table= auxi->table_list->table;
if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
table_count)))
{
- res=mysql_select(thd,tables,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);
+ res= mysql_select(thd,tables,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);
delete result;
}
else
@@ -2069,7 +2158,7 @@ mysql_execute_command(void)
break;
case SQLCOM_SHOW_DATABASES:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
@@ -2084,6 +2173,15 @@ mysql_execute_command(void)
mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS :
thd->priv_user,lex->verbose);
break;
+ case SQLCOM_SHOW_TABLE_TYPES:
+ res= mysqld_show_table_types(thd);
+ break;
+ case SQLCOM_SHOW_PRIVILEGES:
+ res= mysqld_show_privileges(thd);
+ break;
+ case SQLCOM_SHOW_COLUMN_TYPES:
+ res= mysqld_show_column_types(thd);
+ break;
case SQLCOM_SHOW_STATUS:
res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
OPT_GLOBAL);
@@ -2093,27 +2191,34 @@ mysql_execute_command(void)
init_vars, lex->option_type);
break;
case SQLCOM_SHOW_LOGS:
- {
- res= mysqld_show_logs(thd);
- break;
- }
+#ifdef DONT_ALLOW_SHOW_COMMANDS
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ DBUG_VOID_RETURN;
+#else
+ {
+ if (grant_option && check_access(thd, FILE_ACL, any_db))
+ goto error;
+ res= mysqld_show_logs(thd);
+ break;
+ }
+#endif
case SQLCOM_SHOW_TABLES:
/* FALL THROUGH */
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
char *db=select_lex->db ? select_lex->db : thd->db;
if (!db)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
if (check_db_name(db))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, db);
+ net_printf(thd,ER_WRONG_DB_NAME, db);
goto error;
}
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
@@ -2131,16 +2236,19 @@ mysql_execute_command(void)
case SQLCOM_SHOW_OPEN_TABLES:
res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS));
break;
+ case SQLCOM_SHOW_CHARSETS:
+ res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS));
+ break;
case SQLCOM_SHOW_FIELDS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
char *db=tables->db;
if (!*db)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
@@ -2158,14 +2266,14 @@ mysql_execute_command(void)
#endif
case SQLCOM_SHOW_KEYS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
+ send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */
DBUG_VOID_RETURN;
#else
{
char *db=tables->db;
if (!db)
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
@@ -2199,7 +2307,7 @@ mysql_execute_command(void)
if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) ||
! opt_local_infile)
{
- send_error(&thd->net,ER_NOT_ALLOWED_COMMAND);
+ send_error(thd,ER_NOT_ALLOWED_COMMAND);
goto error;
}
if (check_access(thd,privilege,tables->db,&tables->grant.privilege) ||
@@ -2212,7 +2320,7 @@ mysql_execute_command(void)
}
case SQLCOM_SET_OPTION:
if (!(res=sql_set_variables(thd, &lex->var_list)))
- send_ok(&thd->net);
+ send_ok(thd);
break;
case SQLCOM_UNLOCK_TABLES:
unlock_locked_tables(thd);
@@ -2223,7 +2331,7 @@ mysql_execute_command(void)
}
if (thd->global_read_lock)
unlock_global_read_lock(thd);
- send_ok(&thd->net);
+ send_ok(thd);
break;
case SQLCOM_LOCK_TABLES:
unlock_locked_tables(thd);
@@ -2237,7 +2345,7 @@ mysql_execute_command(void)
{
thd->locked_tables=thd->lock;
thd->lock=0;
- send_ok(&thd->net);
+ send_ok(thd);
}
else
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
@@ -2247,41 +2355,75 @@ mysql_execute_command(void)
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
break;
}
if (lower_case_table_names)
- casedn_str(lex->name);
+ my_casedn_str(system_charset_info, lex->name);
if (check_access(thd,CREATE_ACL,lex->name,0,1))
break;
- res=mysql_create_db(thd,lex->name,lex->create_info.options,0);
+ res=mysql_create_db(thd,lex->name,&lex->create_info,0);
break;
}
case SQLCOM_DROP_DB:
{
if (!strip_sp(lex->name) || check_db_name(lex->name))
{
- net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
break;
}
if (lower_case_table_names)
- casedn_str(lex->name);
+ my_casedn_str(system_charset_info, lex->name);
if (check_access(thd,DROP_ACL,lex->name,0,1))
break;
if (thd->locked_tables || thd->active_transaction())
{
- send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
goto error;
}
res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0);
break;
}
+ case SQLCOM_ALTER_DB:
+ {
+ if (!strip_sp(lex->name) || check_db_name(lex->name))
+ {
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ break;
+ }
+ if (check_access(thd,ALTER_ACL,lex->name,0,1))
+ break;
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ goto error;
+ }
+ res=mysql_alter_db(thd,lex->name,&lex->create_info);
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_DB:
+ {
+ if (!strip_sp(lex->name) || check_db_name(lex->name))
+ {
+ net_printf(thd,ER_WRONG_DB_NAME, lex->name);
+ break;
+ }
+ if (check_access(thd,DROP_ACL,lex->name,0,1))
+ break;
+ if (thd->locked_tables || thd->active_transaction())
+ {
+ send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION);
+ goto error;
+ }
+ res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
+ break;
+ }
case SQLCOM_CREATE_FUNCTION:
if (check_access(thd,INSERT_ACL,"mysql",0,1))
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_create_function(thd,&lex->udf)))
- send_ok(&thd->net);
+ send_ok(thd);
#else
res= -1;
#endif
@@ -2291,7 +2433,7 @@ mysql_execute_command(void)
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_drop_function(thd,lex->udf.name)))
- send_ok(&thd->net);
+ send_ok(thd);
#else
res= -1;
#endif
@@ -2319,7 +2461,8 @@ mysql_execute_command(void)
if (user->password.str &&
(strcmp(thd->user,user->user.str) ||
user->host.str &&
- my_strcasecmp(user->host.str, thd->host_or_ip)))
+ my_strcasecmp(system_charset_info,
+ user->host.str, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
goto error;
@@ -2350,7 +2493,7 @@ mysql_execute_command(void)
{
if (lex->columns.elements)
{
- send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE);
res=1;
}
else
@@ -2380,9 +2523,9 @@ mysql_execute_command(void)
if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
goto error;
if (reload_acl_and_cache(thd, lex->type, tables))
- send_error(&thd->net,0);
+ send_error(thd,0);
else
- send_ok(&thd->net);
+ send_ok(thd);
break;
case SQLCOM_KILL:
kill_one_thread(thd,lex->thread_id);
@@ -2432,7 +2575,7 @@ mysql_execute_command(void)
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
- send_ok(&thd->net);
+ send_ok(thd);
}
break;
case SQLCOM_COMMIT:
@@ -2446,7 +2589,7 @@ mysql_execute_command(void)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
{
- send_ok(&thd->net);
+ send_ok(thd);
}
else
res= -1;
@@ -2457,21 +2600,21 @@ mysql_execute_command(void)
if (!ha_rollback(thd))
{
if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
- send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
+ send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
else
- send_ok(&thd->net);
+ send_ok(thd);
}
else
res= -1;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
break;
default: /* Impossible */
- send_ok(&thd->net);
+ send_ok(thd);
break;
}
thd->proc_info="query end"; // QQ
if (res < 0)
- send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
error:
DBUG_VOID_RETURN;
@@ -2504,7 +2647,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if ((!db || !db[0]) && !thd->db && !dont_check_global_grants)
{
if (!no_errors)
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
DBUG_RETURN(TRUE); /* purecov: tested */
}
@@ -2517,7 +2660,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
! db && dont_check_global_grants)
{ // We can never grant this
if (!no_errors)
- net_printf(&thd->net,ER_ACCESS_DENIED_ERROR,
+ net_printf(thd,ER_ACCESS_DENIED_ERROR,
thd->priv_user,
thd->host_or_ip,
thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */
@@ -2542,7 +2685,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
!(want_access & ~TABLE_ACLS)))
DBUG_RETURN(FALSE); /* Ok */
if (!no_errors)
- net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR,
+ net_printf(thd,ER_DBACCESS_DENIED_ERROR,
thd->priv_user,
thd->host_or_ip,
db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */
@@ -2558,7 +2701,7 @@ bool check_global_access(THD *thd, ulong want_access)
if ((thd->master_access & want_access) == want_access)
return 0;
get_privilege_desc(command, sizeof(command), want_access);
- net_printf(&thd->net,ER_SPECIFIC_ACCESS_DENIED_ERROR,
+ net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR,
command);
return 1;
}
@@ -2578,6 +2721,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;
@@ -2613,7 +2758,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables)
{
if (!(tables->db=thd->db))
{
- send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */
+ send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */
return TRUE; /* purecov: tested */
}
}
@@ -2636,7 +2781,7 @@ static bool check_merge_table_access(THD *thd, char *db,
tmp->db=db;
else if (strcmp(tmp->db,db))
{
- send_error(&thd->net,ER_UNION_TABLES_IN_DIFFERENT_DIR);
+ send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR);
return 1;
}
}
@@ -2707,82 +2852,120 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
Initialize global thd variables needed for query
****************************************************************************/
-static void
+void
mysql_init_query(THD *thd)
{
DBUG_ENTER("mysql_init_query");
- thd->lex.select_lex.item_list.empty();
- thd->lex.value_list.empty();
- thd->lex.select_lex.table_list.elements=0;
- thd->free_list=0; thd->lex.union_option=0;
- thd->lex.select = &thd->lex.select_lex;
- thd->lex.select_lex.table_list.first=0;
- thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
- thd->lex.select_lex.next=0;
- thd->lex.olap=0;
- thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE;
- thd->fatal_error=0; // Safety
- thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
- thd->rand_used=0;
- thd->sent_row_count=thd->examined_row_count=0;
- thd->safe_to_cache_query=1;
+ 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->select_lex;
+ lex->select_lex.master= &lex->unit;
+ lex->select_lex.prev= &lex->unit.slave;
+ 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->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->fatal_error= thd->rand_used= 0;
+ thd->safe_to_cache_query= 1;
+ thd->possible_loops= 0;
DBUG_VOID_RETURN;
}
void
mysql_init_select(LEX *lex)
{
- SELECT_LEX *select_lex = lex->select;
- select_lex->where=select_lex->having=0;
- select_lex->select_limit= lex->thd->variables.select_limit;
- select_lex->offset_limit=0;
- select_lex->options=0;
- select_lex->linkage=UNSPECIFIED_TYPE;
- select_lex->olap= UNSPECIFIED_OLAP_TYPE;
- lex->exchange = 0;
- lex->proc_list.first=0;
- select_lex->order_list.elements=select_lex->group_list.elements=0;
- select_lex->order_list.first=0;
- select_lex->order_list.next= (byte**) &select_lex->order_list.first;
- select_lex->group_list.first=0;
- select_lex->group_list.next= (byte**) &select_lex->group_list.first;
- select_lex->next = (SELECT_LEX *)NULL;
+ 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=
+ lex->thd->variables.select_limit;
+ lex->exchange= 0;
+ lex->result= 0;
+ lex->proc_list.first= 0;
}
bool
-mysql_new_select(LEX *lex)
+mysql_new_select(LEX *lex, bool move_down)
{
- SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
+ SELECT_LEX *select_lex = new SELECT_LEX();
+ select_lex->select_number= ++lex->thd->select_number;
if (!select_lex)
return 1;
- lex->select->next=select_lex;
- lex->select=select_lex;
- select_lex->table_list.next= (byte**) &select_lex->table_list.first;
- select_lex->item_list.empty();
- select_lex->when_list.empty();
- select_lex->expr_list.empty();
- select_lex->interval_list.empty();
- select_lex->use_index.empty();
- select_lex->ftfunc_list.empty();
+ select_lex->init_query();
+ select_lex->init_select();
+ if (move_down)
+ {
+ /* first select_lex of subselect or derived table */
+ SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT();
+ if (!unit)
+ return 1;
+ unit->init_query();
+ unit->init_select();
+ unit->include_down(lex->current_select);
+ select_lex->include_down(unit);
+ }
+ 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());
+ lex->current_select= select_lex;
return 0;
}
+/*
+ Create a select to return the same output as 'SELECT @@var_name'.
+
+ SYNOPSIS
+ create_select_for_variable()
+ var_name Variable name
+
+ DESCRIPTION
+ Used for SHOW COUNT(*) [ WARNINGS | ERROR]
+
+ This will crash with a core dump if the variable doesn't exists
+*/
+
+void create_select_for_variable(const char *var_name)
+{
+ LEX *lex;
+ LEX_STRING tmp;
+ DBUG_ENTER("create_select_for_variable");
+ lex= current_lex;
+ mysql_init_select(lex);
+ 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));
+ DBUG_VOID_RETURN;
+}
+
void mysql_init_multi_delete(LEX *lex)
{
- lex->sql_command = SQLCOM_DELETE_MULTI;
+ lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
- lex->select->select_limit=lex->thd->select_limit=HA_POS_ERROR;
- lex->auxilliary_table_list=lex->select_lex.table_list;
- lex->select->table_list.elements=0;
- lex->select->table_list.first=0;
- lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
+ lex->select_lex.select_limit= lex->unit.select_limit_cnt=
+ HA_POS_ERROR;
+ lex->auxilliary_table_list= lex->select_lex.table_list;
+ lex->select_lex.init_query();
}
void
-mysql_parse(THD *thd,char *inBuf,uint length)
+mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_ENTER("mysql_parse");
@@ -2794,13 +2977,13 @@ mysql_parse(THD *thd,char *inBuf,uint length)
if (!yyparse() && ! 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();
+ mysql_execute_command(thd);
query_cache_end_of_result(&thd->net);
}
}
@@ -2811,7 +2994,7 @@ mysql_parse(THD *thd,char *inBuf,uint length)
query_cache_abort(&thd->net);
}
thd->proc_info="freeing items";
- free_items(thd); /* Free strings used by items */
+ free_items(thd->free_list); /* Free strings used by items */
lex_end(lex);
}
DBUG_VOID_RETURN;
@@ -2835,31 +3018,33 @@ link_in_list(SQL_LIST *list,byte *element,byte **next)
bool add_field_to_list(char *field_name, enum_field_types type,
char *length, char *decimals,
- uint type_modifier, Item *default_value,char *change,
- TYPELIB *interval)
+ 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)
{
- net_printf(&thd->net, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
+ net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
if (type_modifier & PRI_KEY_FLAG)
{
lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::PRIMARY,NullS,
+ lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF,
lex->col_list));
lex->col_list.empty();
}
if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG))
{
lex->col_list.push_back(new key_part_spec(field_name,0));
- lex->key_list.push_back(new Key(Key::UNIQUE,NullS,
+ lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF,
lex->col_list));
lex->col_list.empty();
}
@@ -2869,7 +3054,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
NOT_NULL_FLAG)
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
default_value=0;
@@ -2889,6 +3074,19 @@ bool add_field_to_list(char *field_name, enum_field_types type,
new_field->change=change;
new_field->interval=0;
new_field->pack_length=0;
+ new_field->charset=cs;
+
+ if (!comment)
+ {
+ new_field->comment.str=0;
+ new_field->comment.length=0;
+ }
+ else
+ {
+ /* In this case comment is always of type Item_string */
+ new_field->comment.str= (char*) comment->str_value.ptr();
+ new_field->comment.length=comment->str_value.length();
+ }
if (length)
if (!(new_field->length= (uint) atoi(length)))
length=0; /* purecov: inspected */
@@ -2920,8 +3118,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;
@@ -2932,17 +3128,42 @@ 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;
res=default_value->val_str(&str);
if (res->length())
{
- net_printf(&thd->net,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
+ net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
new_field->def=0;
@@ -2962,7 +3183,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
uint tmp_length=new_field->length;
if (tmp_length > PRECISION_FOR_DOUBLE)
{
- net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
+ net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
DBUG_RETURN(1);
}
else if (tmp_length > PRECISION_FOR_FLOAT)
@@ -3016,7 +3237,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
{
if (interval->count > sizeof(longlong)*8)
{
- net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
+ net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
new_field->pack_length=(interval->count+7)/8;
@@ -3038,7 +3259,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
(void) find_set(interval,res->ptr(),res->length());
if (thd->cuted_fields)
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
}
@@ -3061,7 +3282,7 @@ bool add_field_to_list(char *field_name, enum_field_types type,
res=default_value->val_str(&str);
if (!find_enum(interval,res->ptr(),res->length()))
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
}
@@ -3073,14 +3294,14 @@ bool add_field_to_list(char *field_name, enum_field_types type,
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
{
- net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name,
+ net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
MAX_FIELD_WIDTH-1); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
type_modifier&= AUTO_INCREMENT_FLAG;
if ((~allowed_type_modifier) & type_modifier)
{
- net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name);
+ net_printf(thd,ER_WRONG_FIELD_SPEC,field_name);
DBUG_RETURN(1);
}
if (!new_field->pack_length)
@@ -3133,8 +3354,8 @@ static void remove_escape(char *name)
#ifdef USE_MB
int l;
/* if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info, name, strend)))
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info, name, strend)))
{
while (l--)
*to++ = *name++;
@@ -3172,12 +3393,12 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc)
}
-TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
- bool updating,
- thr_lock_type flags,
- List<String> *use_index,
- List<String> *ignore_index
- )
+TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table,
+ LEX_STRING *alias,
+ bool updating,
+ thr_lock_type flags,
+ List<String> *use_index,
+ List<String> *ignore_index)
{
register TABLE_LIST *ptr;
THD *thd=current_thd;
@@ -3188,10 +3409,10 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
DBUG_RETURN(0); // End of memory
alias_str= alias ? alias->str : table->table.str;
if (table->table.length > NAME_LEN ||
- 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->net,ER_WRONG_TABLE_NAME,table->table.str);
+ net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str);
DBUG_RETURN(0);
}
@@ -3213,20 +3434,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
}
else
{
- ptr->db= (char*) "";
+ /* The following can't be "" as we may do 'casedn_str()' on it */
+ ptr->db= empty_c_string;
ptr->db_length= 0;
}
ptr->alias= alias_str;
if (lower_case_table_names)
{
- casedn_str(ptr->db);
- casedn_str(table->table.str);
+ my_casedn_str(system_charset_info,ptr->db);
+ my_casedn_str(system_charset_info,table->table.str);
}
ptr->real_name=table->table.str;
ptr->real_name_length=table->table.length;
ptr->lock_type=flags;
ptr->updating=updating;
+ ptr->derived= (SELECT_LEX_UNIT *) table->sel;
if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
sizeof(*use_index));
@@ -3237,21 +3460,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
/* check that used name is unique */
if (flags != TL_IGNORE)
{
- for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ;
+ for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ;
tables ;
tables=tables->next)
{
if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
{
- net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
+ net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
- link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next);
+ link_in_list(&table_list, (byte*) ptr, (byte**) &ptr->next);
DBUG_RETURN(ptr);
}
+
/*
Set lock for all tables in current select level
@@ -3284,68 +3508,6 @@ void set_lock_for_tables(thr_lock_type lock_type)
}
-/*
-** This is used for UNION to create a new table list of all used tables
-** The table_list->table entry in all used tables are set to point
-** to the entries in this list.
-*/
-
-static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
-{
- /* Handle the case when we are not using union */
- if (!lex->select_lex.next)
- {
- *result= (TABLE_LIST*) lex->select_lex.table_list.first;
- return 0;
- }
-
- SELECT_LEX *sl;
- TABLE_LIST **new_table_list= result, *aux;
-
- *new_table_list=0; // end result list
- for (sl= &lex->select_lex; sl; sl=sl->next)
- {
- if (sl->order_list.first && sl->next && !sl->braces)
- {
- net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
- return 1;
- }
- if ((aux= (TABLE_LIST*) sl->table_list.first))
- {
- TABLE_LIST *next;
- for (; aux; aux=next)
- {
- TABLE_LIST *cursor;
- aux->do_redirect=true;
- next= aux->next;
- for (cursor= *result; cursor; cursor=cursor->next)
- if (!strcmp(cursor->db,aux->db) &&
- !strcmp(cursor->real_name,aux->real_name) &&
- !strcmp(cursor->alias, aux->alias))
- break;
- if (!cursor)
- {
- /* Add not used table to the total table list */
- if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
- sizeof(*aux))))
- {
- send_error(&thd->net,0);
- return 1;
- }
- *new_table_list= cursor;
- new_table_list= &cursor->next;
- *new_table_list=0; // end result list
- }
- else
- aux->shared=1; // Mark that it's used twice
- aux->table=(TABLE *) cursor;
- }
- }
- }
- return 0;
-}
-
-
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (expr)
@@ -3488,9 +3650,9 @@ void kill_one_thread(THD *thd, ulong id)
}
if (!error)
- send_ok(&thd->net);
+ send_ok(thd);
else
- net_printf(&thd->net,error,id);
+ net_printf(thd,error,id);
}
/* Clear most status variables */
@@ -3548,12 +3710,12 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name)
bool check_simple_select()
{
THD *thd= current_thd;
- if (thd->lex.select != &thd->lex.select_lex)
+ if (thd->lex.current_select != &thd->lex.select_lex)
{
char command[80];
strmake(command, thd->lex.yylval->symbol.str,
min(thd->lex.yylval->symbol.length, sizeof(command)-1));
- net_printf(&thd->net, ER_CANT_USE_OPTION_HERE, command);
+ net_printf(thd, ER_CANT_USE_OPTION_HERE, command);
return 1;
}
return 0;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
new file mode 100644
index 00000000000..08377a10501
--- /dev/null
+++ b/sql/sql_prepare.cc
@@ -0,0 +1,835 @@
+/* Copyright (C) 1995-2002 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
+*/
+
+/**********************************************************************
+This file contains the implementation of prepare and executes.
+
+Prepare:
+
+ - Server gets the query from client with command 'COM_PREPARE'
+ - Parse the query and recognize any parameter markers '?' and
+ store its information list lex->param_list
+ - Without executing the query, return back to client the total
+ number of parameters along with result-set metadata information
+ (if any)
+
+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]..
+ - 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]
+ - 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.
+
+***********************************************************************/
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#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);
+
+
+/*
+ Find prepared statement in thd
+
+ SYNOPSIS
+ find_prepared_statement()
+ thd Thread handler
+ stmt_id Statement id server specified to the client on prepare
+
+ RETURN VALUES
+ 0 error. In this case the error is sent with my_error()
+ ptr Pointer to statement
+*/
+
+static PREP_STMT *find_prepared_statement(THD *thd, ulong stmt_id,
+ const char *when)
+{
+ PREP_STMT *stmt;
+ DBUG_ENTER("find_prepared_statement");
+ DBUG_PRINT("enter",("stmt_id: %d", stmt_id));
+
+ if (thd->last_prepared_stmt && thd->last_prepared_stmt->stmt_id == stmt_id)
+ DBUG_RETURN(thd->last_prepared_stmt);
+ if ((stmt= (PREP_STMT*) tree_search(&thd->prepared_statements, &stmt_id,
+ (void*) 0)))
+ DBUG_RETURN (thd->last_prepared_stmt= stmt);
+ my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, when);
+ DBUG_RETURN(0);
+}
+
+/*
+ Compare two prepared statements; Used to find a prepared statement
+*/
+
+int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used)
+{
+ return (a->stmt_id < b->stmt_id) ? -1 : (a->stmt_id == b->stmt_id) ? 0 : 1;
+}
+
+
+/*
+ Free prepared statement.
+
+ SYNOPSIS
+ standard tree_element_free function.
+
+ DESCRIPTION
+ We don't have to free the stmt itself as this was stored in the tree
+ and will be freed when the node is deleted
+*/
+
+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);
+}
+
+/*
+ Send prepared stmt info to client after prepare
+*/
+
+bool send_prep_stmt(PREP_STMT *stmt, uint columns)
+{
+ 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));
+}
+
+/*
+ Send information about all item parameters
+
+ TODO: Not yet ready
+*/
+
+bool send_item_params(PREP_STMT *stmt)
+{
+ 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)++;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ Read the length of the parameter data and retun back to
+ caller by positing the pointer to param data
+*/
+
+static ulong get_param_length(uchar **packet)
+{
+ reg1 uchar *pos= *packet;
+ if (*pos < 251)
+ {
+ (*packet)++;
+ return (ulong) *pos;
+ }
+ if (*pos == 252)
+ {
+ (*packet)+=3;
+ return (ulong) uint2korr(pos+1);
+ }
+ if (*pos == 253)
+ {
+ (*packet)+=4;
+ return (ulong) uint3korr(pos+1);
+ }
+ (*packet)+=9; // Must be 254 when here
+ return (ulong) uint4korr(pos+1);
+}
+
+/*
+ Read and return the data for parameters supplied by client
+*/
+
+static uchar* setup_param_field(Item_param *item_param,
+ uchar *pos, uint buffer_type)
+{
+ if (param_is_null(&pos))
+ {
+ item_param->set_null();
+ return(pos);
+ }
+ switch (buffer_type) {
+ case FIELD_TYPE_TINY:
+ item_param->set_int((longlong)(*pos));
+ pos += 1;
+ 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;
+ break;
+ case FIELD_TYPE_LONG:
+ item_param->set_int((longlong)sint4korr(pos));
+ pos += 4;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ item_param->set_int((longlong)sint8korr(pos));
+ pos += 8;
+ break;
+ case FIELD_TYPE_FLOAT:
+ float data;
+ float4get(data,pos);
+ item_param->set_double((double) data);
+ pos += 4;
+ break;
+ case FIELD_TYPE_DOUBLE:
+ double j;
+ float8get(j,pos)
+ item_param->set_double(j);
+ pos += 8;
+ break;
+ default:
+ {
+ ulong len=get_param_length(&pos);
+ item_param->set_value((const char*)pos,len,current_thd->thd_charset);
+ pos+=len;
+ }
+ }
+ return(pos);
+}
+
+/*
+ Update the parameter markers by reading the data
+ 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
+
+
+ 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;
+
+ if (!(pos=setup_param_field(item_param,pos,item_param->buffer_type)))
+ DBUG_RETURN(1);
+ }
+ }
+ else // Types supplied, read and store it along with param data
+ {
+ while ((item_param=(Item_param *)it++) &&
+ (param_count++ < thd->param_count))
+ {
+ 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);
+ }
+ }
+#endif
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Validates insert fields
+*/
+
+static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields,
+ List<Item> &values, ulong counter)
+{
+ if (fields.elements == 0 && values.elements != 0)
+ {
+ if (values.elements != table->fields)
+ {
+ my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
+ ER(ER_WRONG_VALUE_COUNT_ON_ROW),
+ MYF(0),counter);
+ return -1;
+ }
+ }
+ else
+ {
+ if (fields.elements != values.elements)
+ {
+ my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
+ ER(ER_WRONG_VALUE_COUNT_ON_ROW),
+ MYF(0),counter);
+ return -1;
+ }
+ TABLE_LIST table_list;
+ bzero((char*) &table_list,sizeof(table_list));
+ table_list.db= table->table_cache_key;
+ table_list.real_name= table_list.alias= table->table_name;
+ table_list.table= table;
+ table_list.grant= table->grant;
+
+ thd->dupp_field=0;
+ if (setup_tables(&table_list) ||
+ setup_fields(thd,&table_list,fields,1,0,0))
+ return -1;
+ if (thd->dupp_field)
+ {
+ my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ Validate the following information for INSERT statement:
+ - field existance
+ - fields count
+*/
+
+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)
+{
+ THD *thd= stmt->thd;
+ TABLE *table;
+ List_iterator_fast<List_item> its(values_list);
+ List_item *values;
+ DBUG_ENTER("mysql_test_insert_fields");
+
+ if (!(table = open_ltable(thd,table_list,lock_type)))
+ DBUG_RETURN(1);
+
+ if ((values= its++))
+ {
+ uint value_count;
+ ulong counter= 0;
+
+ if (check_insert_fields(thd,table,fields,*values,1))
+ DBUG_RETURN(1);
+
+ value_count= values->elements;
+ its.rewind();
+
+ while ((values= its++))
+ {
+ counter++;
+ if (values->elements != value_count)
+ {
+ my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
+ ER(ER_WRONG_VALUE_COUNT_ON_ROW),
+ MYF(0), counter);
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ if (send_prep_stmt(stmt, 0) || send_item_params(stmt))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Validate the following information
+ UPDATE - set and where clause DELETE - where clause
+
+ And send update-set clause column list fields info
+ back to client. For DELETE, just validate where clause
+ and return no fields information back to client.
+*/
+
+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)
+{
+ THD *thd= stmt->thd;
+ TABLE *table;
+ DBUG_ENTER("mysql_test_upd_fields");
+
+ if (!(table = open_ltable(thd,table_list,lock_type)))
+ DBUG_RETURN(1);
+
+ if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) ||
+ setup_conds(thd,table_list,&conds))
+ DBUG_RETURN(1);
+
+ /*
+ Currently return only column list info only, and we are not
+ sending any info on where clause.
+ */
+ if (send_prep_stmt(stmt, 0) || send_item_params(stmt))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+/*
+ Validate the following information:
+
+ SELECT - column list
+ - where clause
+ - order clause
+ - having clause
+ - group by clause
+ - if no column spec i.e. '*', then setup all fields
+
+ And send column list fields info back to client.
+*/
+
+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)
+{
+ TABLE *table;
+ bool hidden_group_fields;
+ THD *thd= stmt->thd;
+ List<Item> all_fields(fields);
+ DBUG_ENTER("mysql_test_select_fields");
+
+ if (!(table = open_ltable(thd,tables,lock_type)))
+ DBUG_RETURN(1);
+
+ thd->used_tables=0; // Updated by setup_fields
+ if (setup_tables(tables) ||
+ setup_fields(thd,tables,fields,1,&all_fields,1) ||
+ setup_conds(thd,tables,&conds) ||
+ setup_order(thd,tables,fields,all_fields,order) ||
+ setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
+ DBUG_RETURN(1);
+
+ if (having)
+ {
+ thd->where="having clause";
+ thd->allow_sum_func=1;
+ if (having->fix_fields(thd, tables, &having) || thd->fatal_error)
+ DBUG_RETURN(1);
+ if (having->with_sum_func)
+ having->split_sum_func(all_fields);
+ }
+ if (setup_ftfuncs(&thd->lex.select_lex))
+ DBUG_RETURN(1);
+
+ /*
+ Currently return only column list info only, and we are not
+ sending any info on where clause.
+ */
+ if (send_prep_stmt(stmt, fields.elements) ||
+ send_fields(thd,fields,0) || send_item_params(stmt))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Check the access privileges
+*/
+
+static bool check_prepare_access(THD *thd, TABLE_LIST *tables,
+ uint type)
+{
+ if (check_access(thd,type,tables->db,&tables->grant.privilege))
+ return 1;
+ if (grant_option && check_grant(thd,type,tables))
+ return 1;
+ return 0;
+}
+
+/*
+ Send the prepare query results back to client
+*/
+
+static bool send_prepare_results(PREP_STMT *stmt)
+{
+ THD *thd= stmt->thd;
+ LEX *lex= &thd->lex;
+ enum enum_sql_command sql_command = thd->lex.sql_command;
+ DBUG_ENTER("send_prepare_results");
+ DBUG_PRINT("enter",("command: %d, param_count: %ld",
+ sql_command, lex->param_count));
+
+ /* Setup prepared stmt */
+ stmt->param_count= lex->param_count;
+ stmt->free_list= thd->free_list; // Save items used in stmt
+ thd->free_list= 0;
+
+ SELECT_LEX *select_lex = &lex->select_lex;
+ TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
+
+ switch (sql_command) {
+
+ case SQLCOM_INSERT:
+ if (mysql_test_insert_fields(stmt, tables, lex->field_list,
+ lex->many_values, lex->lock_option))
+ 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))
+ 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))
+ goto abort;
+ break;
+
+ case SQLCOM_SELECT:
+ 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))
+ goto abort;
+ break;
+
+ default:
+ {
+ /*
+ Rest fall through to default category, no parsing
+ for non-DML statements
+ */
+ }
+ }
+ DBUG_RETURN(0);
+
+abort:
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
+ DBUG_RETURN(1);
+}
+
+/*
+ Parse the prepare query
+*/
+
+static bool parse_prepare_query(PREP_STMT *stmt,
+ char *packet, uint length)
+{
+ bool error= 1;
+ THD *thd= stmt->thd;
+ DBUG_ENTER("parse_prepare_query");
+
+ mysql_log.write(thd,COM_PREPARE,"%s",packet);
+ mysql_init_query(thd);
+ thd->prepare_command=true;
+ thd->safe_to_cache_query= 0;
+
+ LEX *lex=lex_start(thd, (uchar*) packet, length);
+ if (!yyparse() && !thd->fatal_error)
+ error= send_prepare_results(stmt);
+ lex_end(lex);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Parse the query and send the total number of parameters
+ and resultset metadata information back to client (if any),
+ without executing the query i.e. with out any log/disk
+ writes. This will allow the queries to be re-executed
+ without re-parsing during execute.
+
+ If parameter markers are found in the query, then store
+ the information using Item_param along with maintaining a
+ list in lex->param_list, so that a fast and direct
+ retrieveal can be made without going through all field
+ items.
+*/
+
+bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
+{
+ MEM_ROOT thd_root = thd->mem_root;
+ PREP_STMT stmt;
+ DBUG_ENTER("mysql_stmt_prepare");
+
+ bzero((char*) &stmt, sizeof(stmt));
+ stmt.thd= thd;
+ stmt.stmt_id= ++thd->current_stmt_id;
+ init_sql_alloc(&stmt.mem_root, 8192, 8192);
+
+ thd->mem_root= stmt.mem_root;
+ if (alloc_query(thd, packet, packet_length))
+ goto err;
+ if (parse_prepare_query(&stmt, thd->query, thd->query_length))
+ goto err;
+
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),WAIT_PRIOR);
+
+ stmt.mem_root= thd->mem_root;
+ thd->mem_root= thd_root; // restore main mem_root
+ DBUG_RETURN(0);
+
+err:
+ stmt.mem_root= thd->mem_root;
+ free_prep_stmt(&stmt, free_free, (void*) 0);
+ thd->mem_root = thd_root; // restore main mem_root
+ DBUG_RETURN(1);
+}
+
+
+/*
+ Executes previously prepared query
+
+ If there is any parameters(thd->param_count), then replace
+ markers with the data supplied from client, and then
+ execute the query
+*/
+
+void mysql_stmt_execute(THD *thd, char *packet)
+{
+ ulong stmt_id= uint4korr(packet);
+ PREP_STMT *stmt;
+ DBUG_ENTER("mysql_stmt_execute");
+
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "execute")))
+ {
+ send_error(thd);
+ DBUG_VOID_RETURN;
+ }
+
+ /* Check if we got an error when sending long data */
+ if (stmt->error_in_prepare)
+ {
+ send_error(thd);
+ DBUG_VOID_RETURN;
+ }
+
+ if (stmt->param_count && setup_param_fields(thd, 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);
+
+ /*
+ TODO:
+ Also, have checks on basic executions such as mysql_insert(),
+ mysql_delete(), mysql_update() and mysql_select() to not to
+ have re-check on setup_* and other things ..
+ */
+ mysql_execute_command(thd);
+
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(), WAIT_PRIOR);
+
+ thd->mem_root= thd_root;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Reset a prepared statement
+
+ SYNOPSIS
+ mysql_stmt_reset()
+ thd Thread handle
+ packet Packet with stmt handle
+
+ DESCRIPTION
+ This function is useful when one gets an error after calling
+ mysql_stmt_getlongdata() and one wants to reset the handle
+ so that one can call execute again.
+*/
+
+void mysql_stmt_reset(THD *thd, char *packet)
+{
+ ulong stmt_id= uint4korr(packet);
+ PREP_STMT *stmt;
+ DBUG_ENTER("mysql_stmt_reset");
+
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "close")))
+ {
+ send_error(thd);
+ DBUG_VOID_RETURN;
+ }
+
+ 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)
+ {
+ stmt->long_data_used= 0;
+ for (; item < end ; item++)
+ item->reset();
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Delete a prepared statement from memory
+*/
+
+void mysql_stmt_close(THD *thd, char *packet)
+{
+ ulong stmt_id= uint4korr(packet);
+ PREP_STMT *stmt;
+ DBUG_ENTER("mysql_stmt_close");
+
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "close")))
+ {
+ send_error(thd);
+ DBUG_VOID_RETURN;
+ }
+ /* Will call free_prep_stmt() */
+ tree_delete(&thd->prepared_statements, (void*) stmt, NULL);
+ thd->last_prepared_stmt=0;
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Long data in pieces from client
+
+ SYNOPSIS
+ mysql_stmt_get_longdata()
+ thd Thread handle
+ pos String to append
+ packet_length Length of string
+
+ DESCRIPTION
+ Get a part of a long data.
+ To make the protocol efficient, we are not sending any return packages
+ here.
+ If something goes wrong, then we will send the error on 'execute'
+
+ We assume that the client takes care of checking that all parts are sent
+ to the server. (No checking that we get a 'end of column' in the server)
+*/
+
+void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length)
+{
+ PREP_STMT *stmt;
+ DBUG_ENTER("mysql_stmt_get_longdata");
+
+ /* The following should never happen */
+ if (packet_length < 9)
+ {
+ 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
+
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
+ {
+ /*
+ There is a chance that the client will never see this as
+ it doesn't expect an answer from this call...
+ */
+ send_error(thd);
+ DBUG_VOID_RETURN;
+ }
+
+ if (param_number >= stmt->param_count)
+ {
+ 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, current_thd->thd_charset);
+ stmt->long_data_used= 1;
+ DBUG_VOID_RETURN;
+}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 3eddd2646d5..5b0ec2ec843 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -97,7 +97,7 @@ end:
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
- send_ok(&thd->net);
+ send_ok(thd);
}
for (TABLE_LIST *table=table_list ; table != lock_table ; table=table->next)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index ee16b84f87e..23951cec29f 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -283,11 +283,11 @@ binlog purge"; break;
if (errmsg)
{
- send_error(&thd->net, 0, errmsg);
+ send_error(thd, 0, errmsg);
return 1;
}
else
- send_ok(&thd->net);
+ send_ok(thd);
return 0;
}
@@ -372,7 +372,7 @@ impossible position";
We need to start a packet with something other than 255
to distiquish it from error
*/
- packet->set("\0", 1);
+ packet->set("\0", 1, system_charset_info);
// if we are at the start of the log
if (pos == BIN_LOG_HEADER_SIZE)
@@ -383,7 +383,7 @@ impossible position";
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err;
}
- packet->set("\0", 1);
+ packet->set("\0", 1, system_charset_info);
}
while (!net->error && net->vio != 0 && !thd->killed)
@@ -418,7 +418,7 @@ impossible position";
goto err;
}
}
- packet->set("\0", 1);
+ packet->set("\0", 1, system_charset_info);
}
/*
TODO: now that we are logging the offset, check to make sure
@@ -538,7 +538,7 @@ Increase max_allowed_packet on master";
goto err;
}
}
- packet->set("\0", 1);
+ packet->set("\0", 1, system_charset_info);
/*
No need to net_flush because we will get to flush later when
we hit EOF pretty quick
@@ -593,7 +593,7 @@ Increase max_allowed_packet on master";
end_io_cache(&log);
(void)my_close(file, MYF(MY_WME));
- send_eof(&thd->net);
+ send_eof(thd);
thd->proc_info = "waiting to finalize termination";
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
@@ -615,15 +615,15 @@ Increase max_allowed_packet on master";
pthread_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
(void) my_close(file, MYF(MY_WME));
- send_error(&thd->net, my_errno, errmsg);
+ send_error(thd, my_errno, errmsg);
DBUG_VOID_RETURN;
}
int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
{
int slave_errno = 0;
- if (!thd) thd = current_thd;
- NET* net = &thd->net;
+ if (!thd)
+ thd = current_thd;
int thread_mask;
DBUG_ENTER("start_slave");
@@ -654,20 +654,21 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
if (slave_errno)
{
if (net_report)
- send_error(net, slave_errno);
+ send_error(thd, slave_errno);
DBUG_RETURN(1);
}
else if (net_report)
- send_ok(net);
+ send_ok(thd);
DBUG_RETURN(0);
}
+
int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
{
int slave_errno = 0;
- if (!thd) thd = current_thd;
- NET* net = &thd->net;
+ if (!thd)
+ thd = current_thd;
if (check_access(thd, SUPER_ACL, any_db))
return 1;
@@ -686,11 +687,11 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report )
if (slave_errno)
{
if (net_report)
- send_error(net, slave_errno);
+ send_error(thd, slave_errno);
return 1;
}
else if (net_report)
- send_ok(net);
+ send_ok(thd);
return 0;
}
@@ -779,7 +780,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
restart_thread_mask,
1 /*skip lock*/)))
{
- send_error(&thd->net,error);
+ send_error(thd,error);
unlock_slave_threads(mi);
DBUG_RETURN(1);
}
@@ -788,7 +789,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
// TODO: see if needs re-write
if (init_master_info(mi, master_info_file, relay_log_info_file, 0))
{
- send_error(&thd->net, 0, "Could not initialize master info");
+ send_error(thd, 0, "Could not initialize master info");
unlock_slave_threads(mi);
DBUG_RETURN(1);
}
@@ -850,7 +851,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
0 /* not only reset, but also reinit */,
&errmsg))
{
- net_printf(&thd->net, 0, "Failed purging old relay logs: %s",errmsg);
+ net_printf(thd, 0, "Failed purging old relay logs: %s",errmsg);
DBUG_RETURN(1);
}
}
@@ -864,7 +865,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
0 /*no data lock*/,
&msg))
{
- net_printf(&thd->net,0,"Failed initializing relay log position: %s",msg);
+ net_printf(thd,0,"Failed initializing relay log position: %s",msg);
unlock_slave_threads(mi);
DBUG_RETURN(1);
}
@@ -890,9 +891,9 @@ int change_master(THD* thd, MASTER_INFO* mi)
unlock_slave_threads(mi);
thd->proc_info = 0;
if (error)
- send_error(&thd->net,error);
+ send_error(thd,error);
else
- send_ok(&thd->net);
+ send_ok(thd);
DBUG_RETURN(0);
}
@@ -948,8 +949,8 @@ int show_binlog_events(THD* thd)
LOG_INFO linfo;
Log_event* ev;
- limit_start = thd->lex.select->offset_limit;
- limit_end = thd->lex.select->select_limit + limit_start;
+ limit_start = thd->lex.current_select->offset_limit;
+ limit_end = thd->lex.current_select->select_limit + limit_start;
name= search_file_name;
if (log_file_name)
@@ -1021,7 +1022,7 @@ err:
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -1052,7 +1053,7 @@ int show_binlog_info(THD* thd)
if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -1105,11 +1106,11 @@ int show_binlogs(THD* thd)
goto err;
}
mysql_bin_log.unlock_index();
- send_eof(net);
+ send_eof(thd);
return 0;
err_with_msg:
- send_error(net, 0, errmsg);
+ send_error(thd, ER_UNKNOWN_ERROR, errmsg);
err:
mysql_bin_log.unlock_index();
return 1;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index a7e378420f2..20b000392df 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -38,7 +38,8 @@ static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse);
static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,
JOIN_TAB *join_tab,
- uint tables,COND *conds,table_map table_map);
+ uint tables, COND *conds,
+ table_map table_map, SELECT_LEX *select_lex);
static int sort_keyuse(KEYUSE *a,KEYUSE *b);
static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key);
static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
@@ -65,7 +66,8 @@ static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
List<Item> &fields, bool send_row,
uint select_options, const char *info,
- Item *having, Procedure *proc);
+ Item *having, Procedure *proc,
+ SELECT_LEX_UNIT *unit);
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
@@ -111,7 +113,9 @@ static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
-static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows filesort_limit,
+static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order,
+ ha_rows filesort_limit, ha_rows select_limit);
+static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order,
ha_rows select_limit);
static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
Item *having);
@@ -126,8 +130,6 @@ static bool store_record_in_cache(JOIN_CACHE *cache);
static void reset_cache(JOIN_CACHE *cache);
static void read_cached_record(JOIN_TAB *tab);
static bool cmp_buffer_with_ref(JOIN_TAB *tab);
-static int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &all_fields, ORDER *order, bool *hidden);
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);
@@ -146,7 +148,7 @@ static void init_sum_functions(Item_sum **func);
static bool update_sum_func(Item_sum **func);
static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct, const char *message=NullS);
-static void describe_info(JOIN *join, const char *info);
+
/*
This handles SELECT with and without UNION
@@ -156,26 +158,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
{
int res;
register SELECT_LEX *select_lex = &lex->select_lex;
-
-#ifdef DISABLED_UNTIL_REWRITTEN_IN_4_1
- if (lex->olap)
- {
- SELECT_LEX *sl, *sl_next;
- int error;
- for (sl= &select_lex; sl; sl=sl_next)
- {
- sl_next=sl->next; // Save if sl->next changes
- if (sl->olap != UNSPECIFIED_OLAP_TYPE)
- {
- if ((error=handle_olaps(lex,sl)))
- return error;
- lex->last_selects->next=sl_next;
- }
- }
- lex->select = select_lex;
- }
-#endif /* DISABLED_UNTIL_REWRITTEN_IN_4_1 */
- if (select_lex->next)
+ fix_tables_pointers(select_lex);
+ if (select_lex->next_select())
res=mysql_union(thd,lex,result);
else
res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first,
@@ -186,66 +170,88 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
select_lex->having,
(ORDER*) lex->proc_list.first,
select_lex->options | thd->options,
- result);
+ result, &(lex->unit), &(lex->select_lex), 0);
if (res && result)
result->abort();
+ if (res || thd->net.report_error)
+ {
+ send_error(thd, 0, NullS);
+ res= 1;
+ }
delete result;
return res;
}
+void fix_tables_pointers(SELECT_LEX *select_lex)
+{
+ if (select_lex->next_select_in_list())
+ {
+ /* Fix tables 'to-be-unioned-from' list to point at opened tables */
+ for (SELECT_LEX *sl= select_lex;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ cursor->table= cursor->table_list->table;
+ }
+ }
+}
/*****************************************************************************
Check fields, find best join, do the select and output fields.
mysql_select assumes that all tables are already opened
*****************************************************************************/
+/*
+ Prepare of whole select (including subselect in future).
+ return -1 on error
+ 0 on success
+*/
int
-mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
- ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
- ulong select_options,select_result *result)
-{
- TABLE *tmp_table;
- int error, tmp_error;
- bool need_tmp,hidden_group_fields;
- bool simple_order,simple_group,no_order, skip_sort_order;
- ha_rows select_limit;
- Item::cond_result cond_value;
- SQL_SELECT *select;
- DYNAMIC_ARRAY keyuse;
- JOIN join;
- Procedure *procedure;
- List<Item> all_fields(fields);
- bool select_distinct;
- SELECT_LEX *cur_sel = thd->lex.select;
- DBUG_ENTER("mysql_select");
-
+JOIN::prepare(TABLE_LIST *tables_init,
+ COND *conds_init, ORDER *order_init, ORDER *group_init,
+ Item *having_init,
+ ORDER *proc_param_init, SELECT_LEX *select,
+ SELECT_LEX_UNIT *unit, bool fake_select_lex)
+{
+ DBUG_ENTER("JOIN::prepare");
+
+ conds= conds_init;
+ order= order_init;
+ group_list= group_init;
+ having= having_init;
+ proc_param= proc_param_init;
+ tables_list= tables_init;
+ select_lex= select;
+ 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 */
- select_distinct=test(select_options & SELECT_DISTINCT);
- tmp_table=0;
- select=0;
- no_order=skip_sort_order=0;
- bzero((char*) &keyuse,sizeof(keyuse));
- thd->proc_info="init";
- thd->used_tables=0; // Updated by setup_fields
-
- if (setup_tables(tables) ||
- setup_fields(thd,tables,fields,1,&all_fields,1) ||
- setup_conds(thd,tables,&conds) ||
- setup_order(thd,tables,fields,all_fields,order) ||
- setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
+ 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))
DBUG_RETURN(-1); /* purecov: inspected */
if (having)
{
thd->where="having clause";
thd->allow_sum_func=1;
- if (having->fix_fields(thd,tables) || thd->fatal_error)
+ select_lex->having_fix_field= 1;
+ bool having_fix_rc= 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 */
if (having->with_sum_func)
having->split_sum_func(all_fields);
}
- if (setup_ftfuncs(thd)) /* should be after having->fix_fields */
+ if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
DBUG_RETURN(-1);
/*
Check if one one uses a not constant column with group functions
@@ -253,13 +259,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
TODO: Add check of calculation of GROUP functions and fields:
SELECT COUNT(*)+table.col1 from table1;
*/
- join.table=0;
- join.tables=0;
{
- if (!group)
+ if (!group_list)
{
uint flag=0;
- List_iterator_fast<Item> it(fields);
+ List_iterator_fast<Item> it(fields_list);
Item *item;
while ((item= it++))
{
@@ -275,22 +279,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
}
TABLE_LIST *table;
- for (table=tables ; table ; table=table->next)
- join.tables++;
+ for (table=tables_list ; table ; table=table->next)
+ tables++;
}
- procedure=setup_procedure(thd,proc_param,result,fields,&error);
+ procedure=setup_procedure(thd,proc_param,result,fields_list,&error);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
if (procedure)
{
- if (setup_new_fields(thd,tables,fields,all_fields,procedure->param_fields))
+ if (setup_new_fields(thd, tables_list, fields_list, all_fields,
+ procedure->param_fields))
{ /* purecov: inspected */
delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
if (procedure->group)
{
- if (!test_if_subpart(procedure->group,group))
+ if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */
@@ -299,7 +304,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
}
#ifdef NOT_NEEDED
- else if (!group && procedure->flags & PROC_GROUP)
+ else if (!group_list && procedure->flags & PROC_GROUP)
{
my_message(0,"Select must have a group with this procedure",MYF(0));
delete procedure;
@@ -315,150 +320,139 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
/* Init join struct */
- join.thd=thd;
- join.lock=thd->lock;
- join.join_tab=0;
- join.tmp_table_param.copy_field=0;
- join.sum_funcs=0;
- join.send_records=join.found_records=join.examined_rows=0;
- join.tmp_table_param.end_write_records= HA_POS_ERROR;
- join.first_record=join.sort_and_group=0;
- join.select_options=select_options;
- join.result=result;
- count_field_types(&join.tmp_table_param,all_fields,0);
- join.const_tables=0;
- join.having=0;
- join.do_send_rows = 1;
- join.group= group != 0;
- join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR :
- thd->select_limit);
+ count_field_types(&tmp_table_param, all_fields, 0);
+ this->group= group_list != 0;
+ row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
+ unit->select_limit_cnt);
+ do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
+ this->unit= unit;
#ifdef RESTRICTED_GROUP
- if (join.sum_func_count && !group && (join.func_count || join.field_count))
+ if (sum_func_count && !group_list && (func_count || field_count))
{
my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
delete procedure;
DBUG_RETURN(-1);
}
#endif
- if (!procedure && result->prepare(fields))
+ if (!procedure && result->prepare(fields_list, unit))
{ /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
+ DBUG_RETURN(0); // All OK
+}
+
+/*
+ global select optimisation.
+ return 0 - success
+ 1 - go out
+ -1 - go out with cleaning
+ error code saved in field 'error'
+*/
+int
+JOIN::optimize()
+{
+ DBUG_ENTER("JOIN::optimize");
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
- if (having && !group && ! join.sum_func_count)
+ if (having && !group_list && ! sum_func_count)
{
if (!conds)
{
- conds=having;
- having=0;
+ conds= having;
+ having= 0;
}
else if ((conds=new Item_cond_and(conds,having)))
{
- conds->fix_fields(thd,tables);
- conds->change_ref_to_fields(thd,tables);
+ conds->fix_fields(thd, tables_list, &conds);
+ conds->change_ref_to_fields(thd, tables_list);
conds->top_level_item();
- having=0;
+ having= 0;
}
}
#endif
- conds=optimize_cond(conds,&cond_value);
- if (thd->fatal_error) // Out of memory
+ conds= optimize_cond(conds,&cond_value);
+ if (thd->fatal_error)
{
+ // quick abort
delete procedure;
- DBUG_RETURN(0);
- }
- if (cond_value == Item::COND_FALSE || !thd->select_limit)
+ error= 0;
+ DBUG_RETURN(1);
+ } else if (thd->net.report_error)
+ // normal error processing & cleanup
+ DBUG_RETURN(-1);
+
+ if (cond_value == Item::COND_FALSE || (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
{ /* Impossible cond */
- error=return_zero_rows(&join, result, tables, fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,"Impossible WHERE",having,
- procedure);
- delete procedure;
- DBUG_RETURN(error);
+ zero_result_cause= "Impossible WHERE";
+ DBUG_RETURN(0);
}
/* Optimize count(*), min() and max() */
- if (tables && join.tmp_table_param.sum_func_count && ! group)
+ if (tables_list && tmp_table_param.sum_func_count && ! group_list)
{
int res;
- if ((res=opt_sum_query(tables, all_fields, conds)))
+ if ((res=opt_sum_query(tables_list, all_fields, conds)))
{
if (res < 0)
{
- error=return_zero_rows(&join, result, tables, fields, !group,
- select_options,"No matching min/max row",
- having,procedure);
- delete procedure;
- DBUG_RETURN(error);
- }
- if (select_options & SELECT_DESCRIBE)
- {
- describe_info(&join, "Select tables optimized away");
- delete procedure;
- DBUG_RETURN(error);
+ zero_result_cause= "No matching min/max row";
+ DBUG_RETURN(0);
}
- tables=0; // All tables resolved
+ zero_result_cause= "Select tables optimized away";
+ tables_list= 0; // All tables resolved
}
}
- if (!tables)
- { // Only test of functions
- error=0;
- if (select_options & SELECT_DESCRIBE)
- describe_info(&join, "No tables used");
- else
- {
- result->send_fields(fields,1);
- if (!having || having->val_int())
- {
- if (join.do_send_rows && result->send_data(fields))
- {
- result->send_error(0,NullS); /* purecov: inspected */
- error=1;
- }
- else
- error=(int) result->send_eof();
- }
- else
- error=(int) result->send_eof();
- }
- delete procedure;
- DBUG_RETURN(error);
+
+ if (!tables_list)
+ {
+ test_function_query= 1;
+ DBUG_RETURN(0);
}
- error = -1;
- join.sort_by_table=get_sort_by_table(order,group,tables);
+ error= -1;
+ 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(&join,tables,conds,&keyuse) || thd->fatal_error)
- goto err;
- thd->proc_info="preparing";
- result->initialize_tables(&join);
- if (join.const_table_map != join.found_const_table_map &&
+ thd->proc_info= "statistics";
+ if (make_join_statistics(this, tables_list, conds, &keyuse) ||
+ thd->fatal_error)
+ DBUG_RETURN(-1);
+
+ if (select_lex->dependent)
+ {
+ /*
+ Just remove all const-table optimization in case of depended query
+ TODO: optimize
+ */
+ const_table_map= 0;
+ const_tables= 0;
+ found_const_table_map= 0;
+ }
+ thd->proc_info= "preparing";
+ result->initialize_tables(this);
+ if (const_table_map != found_const_table_map &&
!(select_options & SELECT_DESCRIBE))
{
- error=return_zero_rows(&join,result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 &&
- !group,0,"",having,procedure);
- goto err;
+ zero_result_cause= "";
+ select_options= 0; //TODO why option in return_zero_rows was droped
+ DBUG_RETURN(0);
}
if (!(thd->options & OPTION_BIG_SELECTS) &&
- join.best_read > (double) thd->variables.max_join_size &&
+ 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 */
- goto err; /* purecov: inspected */
+ DBUG_RETURN(-1);
}
- if (join.const_tables && !thd->locked_tables &&
+ if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK))
{
TABLE **table, **end;
- for (table=join.table, end=table + join.const_tables ;
+ for (table=this->table, end=table + const_tables ;
table != end;
table++)
{
@@ -470,80 +464,79 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
(*table)->file->index_end();
}
- mysql_unlock_some_tables(thd, join.table,join.const_tables);
+ mysql_unlock_some_tables(thd, this->table, const_tables);
}
- if (!conds && join.outer_join)
+ if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true
}
- select=make_select(*join.table, join.const_table_map,
- join.const_table_map,conds,&error);
+ select=make_select(*table, const_table_map,
+ const_table_map, conds, &error);
if (error)
{ /* purecov: inspected */
error= -1; /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_RETURN(-1);
}
- if (make_join_select(&join,select,conds))
+ if (make_join_select(this, select, conds))
{
- error=return_zero_rows(&join, result, tables, fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,
- "Impossible WHERE noticed after reading const tables",
- having,procedure);
- goto err;
+ zero_result_cause=
+ "Impossible WHERE noticed after reading const tables";
+ DBUG_RETURN(0);
}
error= -1; /* if goto err */
/* Optimize distinct away if possible */
- order=remove_const(&join,order,conds,&simple_order);
- if (group || join.tmp_table_param.sum_func_count)
+ order= remove_const(this, order, conds, &simple_order);
+ if (group_list || tmp_table_param.sum_func_count)
{
if (! hidden_group_fields)
select_distinct=0;
}
- else if (select_distinct && join.tables - join.const_tables == 1 &&
- (thd->select_limit == HA_POS_ERROR ||
- (join.select_options & OPTION_FOUND_ROWS) ||
+ 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.join_tab[join.const_tables],
- order, thd->select_limit,1))))
+ test_if_skip_sort_order(&join_tab[const_tables],
+ order,
+ unit->select_limit_cnt,
+ 1))))
{
- if ((group=create_distinct_group(order,fields)))
+ if ((group_list= create_distinct_group(order, fields_list)))
{
- select_distinct=0;
+ select_distinct= 0;
no_order= !order;
- join.group=1; // For end_write_group
+ group= 1; // For end_write_group
}
else if (thd->fatal_error) // End of memory
- goto err;
+ DBUG_RETURN(-1);
}
- group=remove_const(&join,group,conds,&simple_group);
- if (!group && join.group)
+ group_list= remove_const(this, group_list, conds, &simple_group);
+ if (!group_list && group)
{
order=0; // The output has only one row
simple_order=1;
}
- calc_group_buffer(&join,group);
- join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */
+ calc_group_buffer(this, group_list);
+ send_group_parts= tmp_table_param.group_parts; /* Save org parts */
if (procedure && procedure->group)
{
- group=procedure->group=remove_const(&join,procedure->group,conds,
- &simple_group);
- calc_group_buffer(&join,group);
+ group_list= procedure->group= remove_const(this, procedure->group, conds,
+ &simple_group);
+ calc_group_buffer(this, group_list);
}
- if (test_if_subpart(group,order) ||
- (!group && join.tmp_table_param.sum_func_count))
+ if (test_if_subpart(group_list, order) ||
+ (!group_list && tmp_table_param.sum_func_count))
order=0;
// Can't use sort on head table if using row cache
- if (join.full_join)
+ if (full_join)
{
- if (group)
+ if (group_list)
simple_group=0;
if (order)
simple_order=0;
@@ -558,17 +551,18 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
- We are using different ORDER BY and GROUP BY orders
- The user wants us to buffer the result.
*/
- need_tmp= (join.const_tables != join.tables &&
+ need_tmp= (const_tables != tables &&
((select_distinct || !simple_order || !simple_group) ||
- (group && order) ||
+ (group_list && order) ||
test(select_options & OPTION_BUFFER_RESULT)));
// No cache for MATCH
- make_join_readinfo(&join,
+ make_join_readinfo(this,
(select_options & (SELECT_DESCRIBE |
SELECT_NO_JOIN_CACHE)) |
- (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE :
- 0));
+ (select_lex->ftfunc_list->elements ?
+ SELECT_NO_JOIN_CACHE : 0));
+
/*
Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL may build row
@@ -578,63 +572,157 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
*/
#ifdef HAVE_INNOBASE_DB
- if (need_tmp || select_distinct || group || order)
+ if (need_tmp || select_distinct || group_list || order)
{
- for (uint i_h = join.const_tables; i_h < join.tables; i_h++)
+ for (uint i_h = const_tables; i_h < tables; i_h++)
{
- TABLE* table_h = join.join_tab[i_h].table;
+ TABLE* table_h = join_tab[i_h].table;
if (table_h->db_type == DB_TYPE_INNODB)
table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
}
}
#endif
- DBUG_EXECUTE("info",TEST_join(&join););
+ DBUG_EXECUTE("info",TEST_join(this););
/*
Because filesort always does a full table scan or a quick range scan
we must add the removed reference to the select for the table.
We only need to do this when we have a simple_order or simple_group
as in other cases the join is done before the sort.
*/
- if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL &&
- join.join_tab[join.const_tables].type != JT_FT &&
- (order && simple_order || group && simple_group))
+ if ((order || group_list) && join_tab[const_tables].type != JT_ALL &&
+ join_tab[const_tables].type != JT_FT &&
+ (order && simple_order || group_list && simple_group))
{
- if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables]))
- goto err;
+ if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
+ DBUG_RETURN(-1);
}
if (!(select_options & SELECT_BIG_RESULT) &&
- ((group && join.const_tables != join.tables &&
+ ((group_list && const_tables != tables &&
(!simple_group ||
- !test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
- thd->select_limit,0))) ||
+ !test_if_skip_sort_order(&join_tab[const_tables], group_list,
+ unit->select_limit_cnt,
+ 0))) ||
select_distinct) &&
- join.tmp_table_param.quick_group && !procedure)
+ tmp_table_param.quick_group && !procedure)
{
need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort
}
+ DBUG_RETURN(0);
+}
+
+/*
+ Global optimization (with subselect) must be here (TODO)
+*/
+
+int
+JOIN::global_optimize()
+{
+ return 0;
+}
+
+int
+JOIN::reinit()
+{
+ DBUG_ENTER("JOIN::reinit");
+ //TODO move to unit reinit
+ unit->offset_limit_cnt =select_lex->offset_limit;
+ unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->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;
+
+ if (setup_tables(tables_list))
+ DBUG_RETURN(1);
+
+ // Reset of sum functions
+ first_record= 0;
+ if (sum_funcs)
+ {
+ Item_sum *func, **func_ptr= sum_funcs;
+ while ((func= *(func_ptr++)))
+ func->null_value= 1;
+ }
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Exec select
+*/
+void
+JOIN::exec()
+{
+ int tmp_error;
+
+ DBUG_ENTER("JOIN::exec");
+
+ if (test_function_query)
+ { // Only test of functions
+ error=0;
+ if (select_options & SELECT_DESCRIBE)
+ 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))
+ error= 1;
+ else
+ {
+ error= (int) result->send_eof();
+ send_records=1;
+ }
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ delete procedure;
+ DBUG_VOID_RETURN;
+ }
+
+ if (zero_result_cause)
+ {
+ error=0;
+
+ (void) return_zero_rows(this, result, tables_list, fields_list,
+ tmp_table_param.sum_func_count != 0 &&
+ !group_list,
+ select_options,
+ zero_result_cause,
+ having,procedure,
+ unit);
+ DBUG_VOID_RETURN;
+ }
+
+ Item *having_list = having;
+ having = 0;
if (select_options & SELECT_DESCRIBE)
{
if (!order && !no_order)
- order=group;
+ order=group_list;
if (order &&
- (join.const_tables == join.tables ||
+ (const_tables == tables ||
(simple_order &&
- test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
- (join.select_options & OPTION_FOUND_ROWS) ?
- HA_POS_ERROR : thd->select_limit,0))))
+ test_if_skip_sort_order(&join_tab[const_tables], order,
+ (select_options & OPTION_FOUND_ROWS) ?
+ HA_POS_ERROR : unit->select_limit_cnt,
+ 0))))
order=0;
- select_describe(&join,need_tmp,
+ select_describe(this, need_tmp,
order != 0 && !skip_sort_order,
select_distinct);
error=0;
- goto err;
+ DBUG_VOID_RETURN;
}
/* Perform FULLTEXT search before all regular searches */
- init_ftfuncs(thd,test(order));
+ init_ftfuncs(thd, select_lex, test(order));
/* Create a tmp table if distinct or if the sort is too complicated */
if (need_tmp)
@@ -642,46 +730,47 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
DBUG_PRINT("info",("Creating tmp table"));
thd->proc_info="Creating tmp table";
- join.tmp_table_param.hidden_field_count= (all_fields.elements -
- fields.elements);
- if (!(tmp_table =
- create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ tmp_table_param.hidden_field_count= (all_fields.elements -
+ fields_list.elements);
+ if (!(exec_tmp_table =
+ create_tmp_table(thd, &tmp_table_param, all_fields,
((!simple_group && !procedure &&
!(test_flags & TEST_NO_KEY_GROUP)) ?
- group : (ORDER*) 0),
- group ? 0 : select_distinct,
- group && simple_group,
+ group_list : (ORDER*) 0),
+ group_list ? 0 : select_distinct,
+ group_list && simple_group,
(order == 0 || skip_sort_order) &&
- !(join.select_options & OPTION_FOUND_ROWS),
- join.select_options)))
- goto err; /* purecov: inspected */
+ !(select_options & OPTION_FOUND_ROWS),
+ select_options, unit)))
+ DBUG_VOID_RETURN;
- if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
- join.having=having;
+ if (having_list &&
+ (sort_and_group || (exec_tmp_table->distinct && !group_list)))
+ having=having_list;
/* if group or order on first table, sort first */
- if (group && simple_group)
+ if (group_list && simple_group)
{
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
- if (create_sort_index(&join.join_tab[join.const_tables],group,
+ if (create_sort_index(thd, &join_tab[const_tables], group_list,
HA_POS_ERROR, HA_POS_ERROR) ||
- make_sum_func_list(&join,all_fields) ||
- alloc_group_fields(&join,group))
- goto err;
- group=0;
+ make_sum_func_list(this, all_fields) ||
+ alloc_group_fields(this, group_list))
+ DBUG_VOID_RETURN;
+ group_list=0;
}
else
{
- if (make_sum_func_list(&join,all_fields))
- goto err;
- if (!group && ! tmp_table->distinct && order && simple_order)
+ if (make_sum_func_list(this, all_fields))
+ DBUG_VOID_RETURN;
+ if (!group_list && ! exec_tmp_table->distinct && order && simple_order)
{
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
- if (create_sort_index(&join.join_tab[join.const_tables],order,
- HA_POS_ERROR, HA_POS_ERROR))
- goto err; /* purecov: inspected */
+ if (create_sort_index(thd, &join_tab[const_tables], order,
+ HA_POS_ERROR, HA_POS_ERROR))
+ DBUG_VOID_RETURN;
order=0;
}
}
@@ -692,58 +781,58 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
In this case we can stop scanning t2 when we have found one t1.a
*/
- if (tmp_table->distinct)
+ if (exec_tmp_table->distinct)
{
table_map used_tables= thd->used_tables;
- JOIN_TAB *join_tab=join.join_tab+join.tables-1;
+ JOIN_TAB *join_tab= this->join_tab+tables-1;
do
{
if (used_tables & join_tab->table->map)
break;
join_tab->not_used_in_distinct=1;
- } while (join_tab-- != join.join_tab);
+ } while (join_tab-- != this->join_tab);
/* Optimize "select distinct b from t1 order by key_part_1 limit #" */
if (order && skip_sort_order)
{
- (void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
- order, thd->select_limit,0);
+ (void) test_if_skip_sort_order(&this->join_tab[const_tables],
+ order, unit->select_limit_cnt, 0);
order=0;
}
}
/* Copy data to the temporary table */
- thd->proc_info="Copying to tmp table";
- if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
+ thd->proc_info= "Copying to tmp table";
+ if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0)))
{
- error=tmp_error;
- goto err; /* purecov: inspected */
+ error= tmp_error;
+ DBUG_VOID_RETURN;
}
- if (join.having)
- join.having=having=0; // Allready done
+ if (having)
+ having= having_list= 0; // Allready done
/* Change sum_fields reference to calculated fields in tmp_table */
- if (join.sort_and_group || tmp_table->group)
+ if (sort_and_group || exec_tmp_table->group)
{
if (change_to_use_tmp_fields(all_fields))
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+
- join.tmp_table_param.func_count;
- join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.sum_func_count+
+ tmp_table_param.func_count;
+ tmp_table_param.sum_func_count= tmp_table_param.func_count= 0;
}
else
{
if (change_refs_to_tmp_fields(thd,all_fields))
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.func_count;
- join.tmp_table_param.func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.func_count;
+ tmp_table_param.func_count= 0;
}
if (procedure)
procedure->update_refs();
- if (tmp_table->group)
+ if (exec_tmp_table->group)
{ // Already grouped
if (!order && !no_order)
- order=group; /* order by group */
- group=0;
+ order= group_list; /* order by group */
+ group_list= 0;
}
/*
@@ -754,176 +843,302 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
like SEC_TO_TIME(SUM(...)).
*/
- if (group && (!test_if_subpart(group,order) || select_distinct) ||
+ if (group_list && (!test_if_subpart(group_list,order) ||
+ select_distinct) ||
(select_distinct &&
- join.tmp_table_param.using_indirect_summary_function))
+ tmp_table_param.using_indirect_summary_function))
{ /* Must copy to another table */
TABLE *tmp_table2;
DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */
- join_free(&join);
- if (make_simple_join(&join,tmp_table))
- goto err;
- calc_group_buffer(&join,group);
- count_field_types(&join.tmp_table_param,all_fields,
- select_distinct && !group);
- join.tmp_table_param.hidden_field_count=(all_fields.elements-
- fields.elements);
+ join_free(this);
+ if (make_simple_join(this, exec_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(this, group_list);
+ count_field_types(&tmp_table_param, all_fields,
+ select_distinct && !group_list);
+ tmp_table_param.hidden_field_count= (all_fields.elements-
+ fields_list.elements);
/* group data to new table */
- if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields,
(ORDER*) 0,
- select_distinct && !group,
+ select_distinct && !group_list,
1, 0,
- join.select_options)))
- goto err; /* purecov: inspected */
- if (group)
+ select_options, unit)))
+ DBUG_VOID_RETURN;
+ if (group_list)
{
thd->proc_info="Creating sort index";
- if (create_sort_index(join.join_tab,group,HA_POS_ERROR, HA_POS_ERROR) ||
- alloc_group_fields(&join,group))
+ if (create_sort_index(thd, join_tab, group_list, HA_POS_ERROR,
+ HA_POS_ERROR) ||
+ alloc_group_fields(this, group_list))
{
free_tmp_table(thd,tmp_table2); /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- group=0;
+ group_list= 0;
}
thd->proc_info="Copying to group table";
tmp_error= -1;
- if (make_sum_func_list(&join,all_fields) ||
- (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
+ if (make_sum_func_list(this, all_fields) ||
+ (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0)))
{
error=tmp_error;
free_tmp_table(thd,tmp_table2);
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- end_read_record(&join.join_tab->read_record);
- free_tmp_table(thd,tmp_table);
- join.const_tables=join.tables; // Mark free for join_free()
- tmp_table=tmp_table2;
- join.join_tab[0].table=0; // Table is freed
+ end_read_record(&join_tab->read_record);
+ free_tmp_table(thd,exec_tmp_table);
+ const_tables= tables; // Mark free for join_free()
+ exec_tmp_table= tmp_table2;
+ join_tab[0].table= 0; // Table is freed
if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count;
- join.tmp_table_param.sum_func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.sum_func_count;
+ tmp_table_param.sum_func_count= 0;
}
- if (tmp_table->distinct)
+ if (exec_tmp_table->distinct)
select_distinct=0; /* Each row is unique */
- join_free(&join); /* Free quick selects */
- if (select_distinct && ! group)
+ join_free(this); /* Free quick selects */
+ if (select_distinct && ! group_list)
{
thd->proc_info="Removing duplicates";
- if (having)
- having->update_used_tables();
- if (remove_duplicates(&join,tmp_table,fields, having))
- goto err; /* purecov: inspected */
- having=0;
+ if (having_list)
+ having_list->update_used_tables();
+ if (remove_duplicates(this, exec_tmp_table, fields_list, having_list))
+ DBUG_VOID_RETURN;
+ having_list=0;
select_distinct=0;
}
- tmp_table->reginfo.lock_type=TL_UNLOCK;
- if (make_simple_join(&join,tmp_table))
- goto err;
- calc_group_buffer(&join,group);
- count_field_types(&join.tmp_table_param,all_fields,0);
+ exec_tmp_table->reginfo.lock_type=TL_UNLOCK;
+ if (make_simple_join(this, exec_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(this, group_list);
+ count_field_types(&tmp_table_param, all_fields, 0);
}
if (procedure)
{
- if (procedure->change_columns(fields) ||
- result->prepare(fields))
- goto err;
- count_field_types(&join.tmp_table_param,all_fields,0);
+ if (procedure->change_columns(fields_list) ||
+ result->prepare(fields_list, unit))
+ DBUG_VOID_RETURN;
+ count_field_types(&tmp_table_param, all_fields, 0);
}
- if (join.group || join.tmp_table_param.sum_func_count ||
+ if (group || tmp_table_param.sum_func_count ||
(procedure && (procedure->flags & PROC_GROUP)))
{
- alloc_group_fields(&join,group);
- setup_copy_fields(thd, &join.tmp_table_param,all_fields);
- if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
- goto err; /* purecov: inspected */
+ alloc_group_fields(this, group_list);
+ setup_copy_fields(thd, &tmp_table_param,all_fields);
+ if (make_sum_func_list(this, all_fields) || thd->fatal_error)
+ DBUG_VOID_RETURN;
}
- if (group || order)
+ if (group_list || order)
{
DBUG_PRINT("info",("Sorting for send_fields"));
thd->proc_info="Sorting result";
/* If we have already done the group, add HAVING to sorted table */
- if (having && ! group && ! join.sort_and_group)
+ if (having_list && ! group_list && ! sort_and_group)
{
- having->update_used_tables(); // Some tables may have been const
- JOIN_TAB *table=&join.join_tab[join.const_tables];
- table_map used_tables= join.const_table_map | table->table->map;
+ having_list->update_used_tables(); // Some tables may have been const
+ JOIN_TAB *table= &join_tab[const_tables];
+ table_map used_tables= const_table_map | table->table->map;
- Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables);
+ Item* sort_table_cond= make_cond_for_table(having_list, used_tables,
+ used_tables);
if (sort_table_cond)
{
if (!table->select)
if (!(table->select=new SQL_SELECT))
- goto err;
+ DBUG_VOID_RETURN;
if (!table->select->cond)
table->select->cond=sort_table_cond;
else // This should never happen
if (!(table->select->cond=new Item_cond_and(table->select->cond,
sort_table_cond)))
- goto err;
+ 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=make_cond_for_table(having,~ (table_map) 0,~used_tables);
+ having_list= make_cond_for_table(having_list, ~ (table_map) 0,
+ ~used_tables);
DBUG_EXECUTE("where",print_where(conds,"having after sort"););
}
}
- select_limit= thd->select_limit;
- if (having || group || (join.select_options & OPTION_FOUND_ROWS))
- select_limit= HA_POS_ERROR;
- else
{
- /*
- We can abort sorting after thd->select_limit rows if we there is no
- WHERE clause for any tables after the sorted one.
- */
- JOIN_TAB *table= &join.join_tab[join.const_tables+1];
- JOIN_TAB *end_table= &join.join_tab[join.tables];
- for (; table < end_table ; table++)
+ ha_rows select_limit= unit->select_limit_cnt;
+ if (having || group || (select_options & OPTION_FOUND_ROWS))
+ select_limit= HA_POS_ERROR;
+ else
{
- if (table->select_cond)
+ /*
+ We can abort sorting after thd->select_limit rows if we there is no
+ WHERE clause for any tables after the sorted one.
+ */
+ JOIN_TAB *table= &join_tab[const_tables+1];
+ JOIN_TAB *end_table= &join_tab[tables];
+ for (; table < end_table ; table++)
{
- /* We have to sort all rows */
- select_limit= HA_POS_ERROR;
- break;
+ if (table->select_cond)
+ {
+ /* We have to sort all rows */
+ select_limit= HA_POS_ERROR;
+ break;
+ }
}
}
+ if (create_sort_index(thd, &join_tab[const_tables],
+ group_list ? group_list : order,
+ select_limit, unit->select_limit_cnt))
+ DBUG_VOID_RETURN;
}
- if (create_sort_index(&join.join_tab[join.const_tables],
- group ? group : order,
- select_limit,
- thd->select_limit))
- goto err; /* purecov: inspected */
}
- join.having=having; // Actually a parameter
+ having=having_list; // Actually a parameter
thd->proc_info="Sending data";
- error=do_select(&join,&fields,NULL,procedure);
+ error= thd->net.report_error ||
+ do_select(this, &fields_list, NULL, procedure);
+ DBUG_VOID_RETURN;
+}
-err:
- thd->limit_found_rows = join.send_records;
- thd->examined_row_count = join.examined_rows;
- thd->proc_info="end";
- join.lock=0; // It's faster to unlock later
- join_free(&join);
- thd->proc_info="end2"; // QQ
- if (tmp_table)
- free_tmp_table(thd,tmp_table);
- thd->proc_info="end3"; // QQ
+/*
+ Clean up join. Return error that hold JOIN.
+*/
+
+int
+JOIN::cleanup(THD *thd)
+{
+ DBUG_ENTER("JOIN::cleanup");
+
+ lock=0; // It's faster to unlock later
+ join_free(this);
+ if (exec_tmp_table)
+ free_tmp_table(thd, exec_tmp_table);
delete select;
delete_dynamic(&keyuse);
delete procedure;
- thd->proc_info="end4"; // QQ
+ for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit();
+ unit != 0;
+ unit= unit->next_unit())
+ {
+ for (SELECT_LEX *sl= unit->first_select();
+ sl != 0;
+ sl= sl->next_select())
+ {
+ if (sl->join)
+ {
+ int err= sl->join->cleanup(thd);
+ if (err)
+ error= err;
+ sl->join= 0;
+ }
+ }
+ }
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,
+ ulong select_options, select_result *result,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
+ bool fake_select_lex)
+{
+ DBUG_ENTER("mysql_select");
+
+ bool free_join= 1;
+ JOIN *join;
+ if (!fake_select_lex && select_lex->join != 0)
+ {
+ //here is EXPLAIN of subselect or derived table
+ join= select_lex->join;
+ join->result= result;
+ if (!join->procedure && result->prepare(join->fields_list, unit))
+ {
+ DBUG_RETURN(-1);
+ }
+ join->select_options= select_options;
+ free_join= 0;
+ }
+ else
+ {
+ join= new JOIN(thd, fields, select_options, result);
+ thd->proc_info="init";
+ thd->used_tables=0; // Updated by setup_fields
+
+ if (join->prepare(tables, conds, order, group, having, proc_param,
+ select_lex, unit, fake_select_lex))
+ {
+ 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())
+ {
+ case 1:
+ DBUG_RETURN(join->error);
+ case -1:
+ goto err;
+ }
+
+ if (thd->net.report_error || (free_join && join->global_optimize()))
+ goto err;
+
+ join->exec();
+
+err:
+ if (free_join)
+ {
+ thd->limit_found_rows = join->send_records;
+ thd->examined_row_count = join->examined_rows;
+ thd->proc_info="end";
+ int error= (fake_select_lex?join->error:join->cleanup(thd)) ||
+ thd->net.report_error;
+ delete join;
+ DBUG_RETURN(error);
+ }
+ else
+ DBUG_RETURN(join->error);
+}
+
/*****************************************************************************
Create JOIN_TABS, make a guess about the table types,
Approximate how many records will be used in each table
@@ -1064,8 +1279,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
}
if (conds || outer_join)
- if (update_ref_and_keys(join->thd,keyuse_array,stat,join->tables,
- conds,~outer_join))
+ if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables,
+ conds, ~outer_join, join->select_lex))
DBUG_RETURN(1);
/* Read tables with 0 or 1 rows (system tables) */
@@ -1625,7 +1840,8 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
static bool
update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
- uint tables, COND *cond, table_map normal_tables)
+ uint tables, COND *cond, table_map normal_tables,
+ SELECT_LEX *select_lex)
{
uint and_level,i,found_eq_constant;
@@ -1653,7 +1869,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
add_key_part(keyuse,field);
}
- if (thd->lex.select->ftfunc_list.elements)
+ if (select_lex->ftfunc_list->elements)
{
add_ft_keys(keyuse,join_tab,cond,normal_tables);
}
@@ -1753,7 +1969,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
ha_rows rec;
double tmp;
- THD *thd= current_thd;
+ THD *thd= join->thd;
if (!rest_tables)
{
@@ -2041,7 +2257,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
join->positions[idx].table= s;
if (!best_key && idx == join->const_tables &&
s->table == join->sort_by_table &&
- join->thd->select_limit >= records)
+ join->unit->select_limit_cnt >= records)
join->sort_by_table= (TABLE*) 1; // Must use temporary table
/*
@@ -2375,7 +2591,7 @@ store_val_in_field(Field *field,Item *item)
THD *thd=current_thd;
ha_rows cuted_fields=thd->cuted_fields;
thd->count_cuted_fields=1;
- item->save_in_field(field);
+ (void) item->save_in_field(field);
thd->count_cuted_fields=0;
return cuted_fields != thd->cuted_fields;
}
@@ -2402,8 +2618,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->thd->select_limit;
+ 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;
@@ -2520,7 +2736,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if ((tab->keys & ~ tab->const_keys && i > 0) ||
(tab->const_keys && i == join->const_tables &&
- join->thd->select_limit < join->best_positions[i].records_read &&
+ join->unit->select_limit_cnt <
+ join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
/* Join with outer join condition */
@@ -2531,7 +2748,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
(join->select_options &
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
- join->thd->select_limit)) < 0)
+ join->unit->select_limit_cnt)) < 0)
DBUG_RETURN(1); // Impossible range
sel->cond=orig_cond;
}
@@ -2573,7 +2790,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
static void
-make_join_readinfo(JOIN *join,uint options)
+make_join_readinfo(JOIN *join, uint options)
{
uint i;
SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
@@ -2735,25 +2952,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)
+ 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;
}
- join->table=0;
}
/*
We are not using tables anymore
@@ -2972,18 +3207,20 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
static int
return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
List<Item> &fields, bool send_row, uint select_options,
- const char *info, Item *having, Procedure *procedure)
+ const char *info, Item *having, Procedure *procedure,
+ SELECT_LEX_UNIT *unit)
{
DBUG_ENTER("return_zero_rows");
if (select_options & SELECT_DESCRIBE)
- {
- describe_info(join, info);
+ {
+ select_describe(join, false, false, false, info);
DBUG_RETURN(0);
}
+
if (procedure)
{
- if (result->prepare(fields)) // This hasn't been done yet
+ if (result->prepare(fields, unit)) // This hasn't been done yet
DBUG_RETURN(-1);
}
if (send_row)
@@ -3302,7 +3539,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
21))))
{
cond=new_cond;
- cond->fix_fields(thd,0);
+ cond->fix_fields(thd, 0, &cond);
}
thd->insert_id(0); // Clear for next request
}
@@ -3316,7 +3553,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2))))
{
cond=new_cond;
- cond->fix_fields(thd,0);
+ cond->fix_fields(thd, 0, &cond);
}
}
}
@@ -3420,14 +3657,14 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item_sum::AVG_FUNC: /* Place for sum & count */
if (group)
return new Field_string(sizeof(double)+sizeof(longlong),
- maybe_null, item->name,table,1);
+ maybe_null, item->name,table,my_charset_bin);
else
return new Field_double(item_sum->max_length,maybe_null,
item->name, table, item_sum->decimals);
case Item_sum::STD_FUNC: /* Place for sum & count */
if (group)
return new Field_string(sizeof(double)*2+sizeof(longlong),
- maybe_null, item->name,table,1);
+ maybe_null, item->name,table,my_charset_bin);
else
return new Field_double(item_sum->max_length, maybe_null,
item->name,table,item_sum->decimals);
@@ -3444,9 +3681,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case STRING_RESULT:
if (item_sum->max_length > 255)
return new Field_blob(item_sum->max_length,maybe_null,
- item->name,table,item->binary);
+ item->name,table,item->charset());
return new Field_string(item_sum->max_length,maybe_null,
- item->name,table,item->binary);
+ item->name,table,item->charset());
}
}
thd->fatal_error=1;
@@ -3474,6 +3711,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::COND_ITEM:
case Item::FIELD_AVG_ITEM:
case Item::FIELD_STD_ITEM:
+ case Item::SUBSELECT_ITEM:
/* The following can only happen with 'CREATE TABLE ... SELECT' */
case Item::INT_ITEM:
case Item::REAL_ITEM:
@@ -3497,10 +3735,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case STRING_RESULT:
if (item->max_length > 255)
new_field= new Field_blob(item->max_length,maybe_null,
- item->name,table,item->binary);
+ item->name,table,item->str_value.charset());
else
new_field= new Field_string(item->max_length,maybe_null,
- item->name,table,item->binary);
+ item->name,table,item->str_value.charset());
break;
}
if (copy_func)
@@ -3518,7 +3756,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
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)
+ bool allow_distinct_limit, ulong select_options,
+ SELECT_LEX_UNIT *unit)
{
TABLE *table;
uint i,field_count,reclength,null_count,null_pack_length,
@@ -3616,6 +3855,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->blob_ptr_size=mi_portable_sizeof_char_ptr;
table->map=1;
table->tmp_table= TMP_TABLE;
+ table->derived_select_number= 0;
table->db_low_byte_first=1; // True for HEAP and MyISAM
table->temp_pool_slot = temp_pool_slot;
table->copy_blobs= 1;
@@ -3906,8 +4146,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
test(null_pack_length));
if (allow_distinct_limit)
{
- set_if_smaller(table->max_rows,thd->select_limit);
- param->end_write_records=thd->select_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;
@@ -3936,7 +4176,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(uchar*) 0,
(uint) 0,
Field::NONE,
- NullS, table, (bool) 1);
+ NullS, table, my_charset_bin);
key_part_info->key_type=FIELDFLAG_BINARY;
key_part_info->type= HA_KEYTYPE_BINARY;
key_part_info++;
@@ -4009,7 +4249,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
if (table->keys)
{ // Get keys for ni_create
bool using_unique_constraint=0;
- MI_KEYSEG *seg= (MI_KEYSEG*) sql_calloc(sizeof(*seg) *
+ HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) *
keyinfo->key_parts);
if (!seg)
goto err;
@@ -4046,7 +4286,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= MY_CHARSET_CURRENT;
+ seg->language= field->charset()->number;
seg->length= keyinfo->key_part[i].length;
seg->start= keyinfo->key_part[i].offset;
if (field->flags & BLOB_FLAG)
@@ -4085,6 +4325,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
}
MI_CREATE_INFO create_info;
bzero((char*) &create_info,sizeof(create_info));
+
if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) ==
OPTION_BIG_TABLES)
create_info.data_file_length= ~(ulonglong) 0;
@@ -4244,7 +4485,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
empty_record(table);
}
- join->tmp_table=table; /* Save for easy recursion */
+ join->tmp_table= table; /* Save for easy recursion */
join->fields= fields;
/* Set up select_end */
@@ -4294,20 +4535,14 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
}
else
{
- error=sub_select(join,join_tab,0);
+ error= sub_select(join,join_tab,0);
if (error >= 0)
- error=sub_select(join,join_tab,1);
+ error= sub_select(join,join_tab,1);
if (error == -3)
- error=0; /* select_limit used */
+ error= 0; /* select_limit used */
}
- /* Return 1 if error is sent; -1 if error should be sent */
- if (error < 0)
- {
- join->result->send_error(0,NullS); /* purecov: inspected */
- error=1; // Error sent
- }
- else
+ if (error >= 0)
{
error=0;
if (!table) // If sending data to client
@@ -4334,7 +4569,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);
}
@@ -4960,7 +5195,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
error=join->result->send_data(*join->fields);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
- if (++join->send_records >= join->thd->select_limit &&
+ if (++join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (join->select_options & OPTION_FOUND_ROWS)
@@ -4989,8 +5224,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
else
{
- join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->do_send_rows= 0;
+ join->unit->select_limit= HA_POS_ERROR;
DBUG_RETURN(0);
}
}
@@ -5053,14 +5288,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
join->send_records++;
DBUG_RETURN(0);
}
- if (!error &&
- ++join->send_records >= join->thd->select_limit &&
+ if (!error && ++join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(-3); // Abort nicely
join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->unit->select_limit_cnt = HA_POS_ERROR;
}
}
}
@@ -5141,7 +5375,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(-3);
join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->unit->select_limit_cnt = HA_POS_ERROR;
DBUG_RETURN(0);
}
}
@@ -5687,8 +5921,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*****************************************************************************/
static int
-create_sort_index(JOIN_TAB *tab, ORDER *order, ha_rows filesort_limit,
- ha_rows select_limit)
+create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
+ ha_rows filesort_limit, ha_rows select_limit)
{
SORT_FIELD *sortorder;
uint length;
@@ -5732,8 +5966,8 @@ create_sort_index(JOIN_TAB *tab, ORDER *order, ha_rows filesort_limit,
}
if (table->tmp_table)
table->file->info(HA_STATUS_VARIABLE); // Get record count
- table->found_records=filesort(table,sortorder,length,
- select, 0L, filesort_limit, &examined_rows);
+ table->found_records=filesort(thd, table,sortorder, length,
+ select, filesort_limit, &examined_rows);
tab->records=table->found_records; // For SQL_CALC_ROWS
delete select; // filesort did select
tab->select=0;
@@ -5832,7 +6066,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
int error;
ulong reclength,offset;
uint field_count;
- THD *thd= current_thd;
+ THD *thd= join->thd;
DBUG_ENTER("remove_duplicates");
entry->reginfo.lock_type=TL_WRITE;
@@ -5849,7 +6083,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
if (!field_count)
{ // only const items
- join->thd->select_limit=1; // Only send first row
+ join->unit->select_limit_cnt= 1; // Only send first row
DBUG_RETURN(0);
}
Field **first_field=entry->field+entry->fields - field_count;
@@ -5986,8 +6220,10 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
(uint) (field_count*sizeof(*field_lengths)),
NullS))
DBUG_RETURN(1);
- if (hash_init(&hash, (uint) file->records, 0, key_length,
- (hash_get_key) 0, 0, 0))
+
+ // BAR TODO: this must be fixed to use charset from "table" argument
+ if (hash_init(&hash, default_charset_info, (uint) file->records, 0,
+ key_length,(hash_get_key) 0, 0, 0))
{
my_free((char*) key_buffer,MYF(0));
DBUG_RETURN(1);
@@ -6380,10 +6616,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
order->in_field_list=1;
return 0;
}
- const char *save_where=thd->where;
- thd->where=0; // No error if not found
- Item **item=find_item_in_list(*order->item,fields);
- thd->where=save_where;
+ Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS);
if (item)
{
order->item=item; // use it
@@ -6391,7 +6624,7 @@ 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) || thd->fatal_error)
+ if ((*order->item)->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();
@@ -6417,7 +6650,7 @@ int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields,
}
-static int
+int
setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
{
@@ -6481,17 +6714,15 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
DBUG_ENTER("setup_new_fields");
thd->set_query_id=1; // Not really needed, but...
- thd->where=0; // Don't give error
- for (; new_field ; new_field=new_field->next)
+ for (; new_field ; new_field= new_field->next)
{
- if ((item=find_item_in_list(*new_field->item,fields)))
+ if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS)))
new_field->item=item; /* Change to shared Item */
else
{
thd->where="procedure list";
- if ((*new_field->item)->fix_fields(thd,tables))
+ if ((*new_field->item)->fix_fields(thd, tables, new_field->item))
DBUG_RETURN(1); /* purecov: inspected */
- thd->where=0;
all_fields.push_front(*new_field->item);
new_field->item=all_fields.head_ref();
}
@@ -6882,7 +7113,7 @@ change_to_use_tmp_fields(List<Item> &items)
if (_db_on_ && !item_field->name)
{
char buff[256];
- String str(buff,sizeof(buff));
+ String str(buff,sizeof(buff),default_charset_info);
str.length(0);
item->print(&str);
item_field->name=sql_strmake(str.ptr(),str.length());
@@ -7054,7 +7285,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
Here we pass 0 as the first argument to fix_fields that don't need
to do any stack checking (This is already done in the initial fix_fields).
*/
- cond->fix_fields((THD *) 0,(TABLE_LIST *) 0);
+ cond->fix_fields((THD *) 0,(TABLE_LIST *) 0, (Item**)&cond);
if (join_tab->select)
{
error=(int) cond->add(join_tab->select->cond);
@@ -7074,44 +7305,30 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
bool distinct,const char *message)
{
List<Item> field_list;
- Item *item;
List<Item> item_list;
THD *thd=join->thd;
- MYSQL_LOCK *save_lock;
SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
select_result *result=join->result;
Item *item_null= new Item_null();
DBUG_ENTER("select_describe");
-
+ DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s",
+ (ulong)join->select_lex, join->select_lex->type,
+ message));
/* Don't log this into the slow query log */
select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED);
- thd->offset_limit=0;
- if (thd->lex.select == select_lex)
- {
- field_list.push_back(new Item_empty_string("table",NAME_LEN));
- field_list.push_back(new Item_empty_string("type",10));
- field_list.push_back(item=new Item_empty_string("possible_keys",
- NAME_LEN*MAX_KEY));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("key",NAME_LEN));
- item->maybe_null=1;
- field_list.push_back(item=new Item_int("key_len",0,3));
- item->maybe_null=1;
- field_list.push_back(item=new Item_empty_string("ref",
- NAME_LEN*MAX_REF_PARTS));
- item->maybe_null=1;
- field_list.push_back(new Item_real("rows",0.0,0,10));
- field_list.push_back(new Item_empty_string("Extra",255));
- if (result->send_fields(field_list,1))
- return;
- }
+ join->unit->offset_limit_cnt= 0;
if (message)
{
+ item_list.push_back(new Item_int((int32) join->select_lex->select_number));
+ item_list.push_back(new Item_string(join->select_lex->type,
+ strlen(join->select_lex->type),
+ default_charset_info));
Item *empty= new Item_empty_string("",0);
for (uint i=0 ; i < 7; i++)
item_list.push_back(empty);
- item_list.push_back(new Item_string(message,strlen(message)));
+ item_list.push_back(new Item_string(message,strlen(message),
+ default_charset_info));
if (result->send_data(item_list))
result->send_error(0,NullS);
}
@@ -7124,18 +7341,32 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
TABLE *table=tab->table;
char buff[512],*buff_ptr=buff;
char buff1[512], buff2[512], buff3[512];
- String tmp1(buff1,sizeof(buff1));
- String tmp2(buff2,sizeof(buff2));
+ String tmp1(buff1,sizeof(buff1),default_charset_info);
+ String tmp2(buff2,sizeof(buff2),default_charset_info);
tmp1.length(0);
tmp2.length(0);
- item_list.empty();
+ item_list.empty();
+ item_list.push_back(new Item_int((int32)
+ join->select_lex->select_number));
+ item_list.push_back(new Item_string(join->select_lex->type,
+ strlen(join->select_lex->type),
+ default_charset_info));
if (tab->type == JT_ALL && tab->select && tab->select->quick)
tab->type= JT_RANGE;
- item_list.push_back(new Item_string(table->table_name,
- strlen(table->table_name)));
- item_list.push_back(new Item_string(join_type_str[tab->type],
- strlen(join_type_str[tab->type])));
+ if (table->tmp_table == TMP_TABLE && table->derived_select_number != 0)
+ {
+ // Derived table name generation
+ char buff[512];
+ int len= my_snprintf(buff, 512, "<derived%u>",
+ table->derived_select_number);
+ item_list.push_back(new Item_string(buff, len, default_charset_info));
+ }
+ else
+ item_list.push_back(new Item_string(table->table_name,
+ strlen(table->table_name),
+ default_charset_info));
+ item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type]),default_charset_info));
key_map bits;
uint j;
for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
@@ -7148,14 +7379,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
}
}
if (tmp1.length())
- item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length()));
+ item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),
+ default_charset_info));
else
- item_list.push_back(item_null);
+ item_list.push_back(item_null);
if (tab->ref.key_parts)
{
KEY *key_info=table->key_info+ tab->ref.key;
item_list.push_back(new Item_string(key_info->name,
- strlen(key_info->name)));
+ strlen(key_info->name),
+ system_charset_info));
item_list.push_back(new Item_int((int32) tab->ref.key_length));
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
{
@@ -7163,13 +7396,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
tmp2.append(',');
tmp2.append((*ref)->name());
}
- item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length()));
+ item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(),
+ default_charset_info));
}
else if (tab->type == JT_NEXT)
{
KEY *key_info=table->key_info+ tab->index;
item_list.push_back(new Item_string(key_info->name,
- strlen(key_info->name)));
+ strlen(key_info->name),
+ default_charset_info));
item_list.push_back(new Item_int((int32) key_info->key_length));
item_list.push_back(item_null);
}
@@ -7177,8 +7412,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
KEY *key_info=table->key_info+ tab->select->quick->index;
item_list.push_back(new Item_string(key_info->name,
- strlen(key_info->name)));
- item_list.push_back(new Item_int((int32) tab->select->quick->max_used_key_length));
+ strlen(key_info->name),
+ default_charset_info));
+ item_list.push_back(new Item_int((int32) tab->select->quick->
+ max_used_key_length));
item_list.push_back(item_null);
}
else
@@ -7188,14 +7425,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(item_null);
}
sprintf(buff3,"%.0f",join->best_positions[i].records_read);
- item_list.push_back(new Item_string(buff3,strlen(buff3)));
+ item_list.push_back(new Item_string(buff3,strlen(buff3),
+ default_charset_info));
my_bool key_read=table->key_read;
if (tab->type == JT_NEXT &&
((table->used_keys & ((key_map) 1 << tab->index))))
key_read=1;
if (tab->info)
- item_list.push_back(new Item_string(tab->info,strlen(tab->info)));
+ item_list.push_back(new Item_string(tab->info,strlen(tab->info),
+ default_charset_info));
else if (tab->select)
{
if (tab->use_quick == 2)
@@ -7221,48 +7460,75 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
need_order=0;
buff_ptr= strmov(buff_ptr,"; Using filesort");
}
- if (distinct && test_all_bits(used_tables,thd->used_tables))
+ if (distinct & test_all_bits(used_tables,thd->used_tables))
buff_ptr= strmov(buff_ptr,"; Distinct");
if (buff_ptr == buff)
- buff_ptr+= 2;
- item_list.push_back(new Item_string(buff+2,(uint) (buff_ptr - buff)-2));
+ 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;
if (result->send_data(item_list))
result->send_error(0,NullS);
}
}
- if (!thd->lex.select->next) // Not union
+ for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
{
- save_lock=thd->lock;
- thd->lock=(MYSQL_LOCK *)0;
- result->send_eof();
- thd->lock=save_lock;
+ if (mysql_explain_union(thd, unit, result))
+ DBUG_VOID_RETURN;
}
DBUG_VOID_RETURN;
}
-
-static void describe_info(JOIN *join, const char *info)
+int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
{
- THD *thd= join->thd;
+ DBUG_ENTER("mysql_explain_union");
+ int res= 0;
+ SELECT_LEX *first= unit->first_select();
+ for (SELECT_LEX *sl= first;
+ sl;
+ sl= sl->next_select())
+ {
+ res= mysql_explain_select(thd, sl,
+ (((&thd->lex.select_lex)==sl)?
+ ((sl->next_select_in_list())?"PRIMARY":
+ "SIMPLE"):
+ ((sl == first)?
+ ((sl->linkage == DERIVED_TABLE_TYPE) ?
+ "DERIVED":
+ ((sl->dependent)?"DEPENDENT SUBSELECT":
+ "SUBSELECT")):
+ ((sl->dependent)?"DEPENDENT UNION":
+ "UNION"))),
+ result);
+ if (res)
+ break;
- if (thd->lex.select_lex.next) /* If in UNION */
- {
- select_describe(join,FALSE,FALSE,FALSE,info);
- return;
}
- List<Item> field_list;
- String *packet= &thd->packet;
+ if (res > 0 || thd->net.report_error)
+ res= -1; // mysql_explain_select do not report error
+ DBUG_RETURN(res);
+}
- /* Don't log this into the slow query log */
- thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED |
- QUERY_NO_GOOD_INDEX_USED);
- field_list.push_back(new Item_empty_string("Comment",80));
- if (send_fields(thd,field_list,1))
- return; /* purecov: inspected */
- packet->length(0);
- net_store_data(packet,info);
- if (!my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
- send_eof(&thd->net);
+int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type,
+ select_result *result)
+{
+ DBUG_ENTER("mysql_explain_select");
+ DBUG_PRINT("info", ("Select 0x%lx, type %s", (ulong)select_lex, type))
+ select_lex->type= type;
+ thd->lex.current_select= select_lex;
+ SELECT_LEX_UNIT *unit= select_lex->master_unit();
+ int res= mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first,
+ select_lex->item_list,
+ select_lex->where,
+ (ORDER*) select_lex->order_list.first,
+ (ORDER*) select_lex->group_list.first,
+ select_lex->having,
+ (ORDER*) thd->lex.proc_list.first,
+ select_lex->options | thd->options | SELECT_DESCRIBE,
+ result, unit, select_lex, 0);
+ DBUG_RETURN(res);
}
+
diff --git a/sql/sql_select.h b/sql/sql_select.h
index befa1efde53..3b89c1ce0d3 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -149,8 +149,8 @@ class TMP_TABLE_PARAM {
}
};
-
-class JOIN {
+class JOIN :public Sql_alloc
+{
public:
JOIN_TAB *join_tab,**best_ref,**map2table;
TABLE **table,**all_tables,*sort_by_table;
@@ -173,6 +173,79 @@ class JOIN {
select_result *result;
TMP_TABLE_PARAM tmp_table_param;
MYSQL_LOCK *lock;
+ // unit structure (with global parameters) for this select
+ SELECT_LEX_UNIT *unit;
+ // select that processed
+ SELECT_LEX *select_lex;
+
+ bool select_distinct, //Is select distinct?
+ no_order, simple_order, simple_group,
+ skip_sort_order, need_tmp,
+ hidden_group_fields,
+ buffer_result;
+ DYNAMIC_ARRAY keyuse;
+ Item::cond_result cond_value;
+ List<Item> all_fields;
+ List<Item> & fields_list; // hold field list passed to mysql_select
+ int error;
+
+ ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
+ COND *conds; // ---"---
+ TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
+ 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
+
+ JOIN(THD *thd, List<Item> &fields,
+ ulong select_options, select_result *result):
+ join_tab(0),
+ table(0),
+ tables(0), const_tables(0),
+ sort_and_group(0), first_record(0),
+ do_send_rows(1),
+ send_records(0), found_records(0), examined_rows(0),
+ thd(thd),
+ sum_funcs(0),
+ procedure(0),
+ having(0),
+ select_options(select_options),
+ result(result),
+ lock(thd->lock),
+ select_lex(0), //for safety
+ select_distinct(test(select_options & SELECT_DISTINCT)),
+ no_order(0), simple_order(0), simple_group(0), skip_sort_order(0),
+ need_tmp(0),
+ hidden_group_fields (0), /*safety*/
+ buffer_result(test(select_options & OPTION_BUFFER_RESULT) &&
+ !test(select_options & OPTION_FOUND_ROWS)),
+ all_fields(fields),
+ fields_list(fields),
+ error(0),
+ select(0),
+ exec_tmp_table(0),
+ test_function_query(0),
+ zero_result_cause(0)
+ {
+ fields_list = fields;
+ bzero((char*) &keyuse,sizeof(keyuse));
+ tmp_table_param.copy_field=0;
+ tmp_table_param.end_write_records= HA_POS_ERROR;
+ }
+
+ int prepare(TABLE_LIST *tables,
+ COND *conds, ORDER *order, ORDER *group, Item *having,
+ ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit,
+ bool fake_select_lex);
+ int optimize();
+ int global_optimize();
+ int reinit();
+ void exec();
+ int cleanup(THD *thd);
+ bool check_loop(uint id);
};
@@ -187,7 +260,8 @@ 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);
+ bool allow_distinct_limit, ulong select_options,
+ SELECT_LEX_UNIT *unit);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
@@ -217,7 +291,7 @@ class store_key :public Sql_alloc
if (field_arg->type() == FIELD_TYPE_BLOB)
to_field=new Field_varstring(ptr, length, (uchar*) null, 1,
Field::NONE, field_arg->field_name,
- field_arg->table, field_arg->binary());
+ field_arg->table, field_arg->charset());
else
{
to_field=field_arg->new_field(&thd->mem_root,field_arg->table);
@@ -269,7 +343,7 @@ public:
{}
bool copy()
{
- item->save_in_field(to_field);
+ (void) item->save_in_field(to_field);
return err != 0;
}
const char *name() const { return "func"; }
@@ -293,7 +367,7 @@ public:
if (!inited)
{
inited=1;
- item->save_in_field(to_field);
+ (void)item->save_in_field(to_field);
}
return err != 0;
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 8dfe5e9e948..ebf5b210d6c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* 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
@@ -57,7 +57,7 @@ extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
int
mysqld_show_dbs(THD *thd,const char *wild)
{
- Item_string *field=new Item_string("",0);
+ Item_string *field=new Item_string("",0,default_charset_info);
List<Item> field_list;
char *end;
List<char> files;
@@ -76,6 +76,8 @@ mysqld_show_dbs(THD *thd,const char *wild)
if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
DBUG_RETURN(1);
List_iterator_fast<char> it(files);
+
+ String *packet= &thd->packet;
while ((file_name=it++))
{
if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
@@ -83,19 +85,20 @@ mysqld_show_dbs(THD *thd,const char *wild)
thd->priv_user, file_name) ||
(grant_option && !check_grant_db(thd, file_name)))
{
- thd->packet.length(0);
- net_store_data(&thd->packet, thd->variables.convert_set, file_name);
- if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
- thd->packet.length()))
+ packet->length(0);
+ net_store_data(packet, thd->variables.convert_set, file_name);
+ if (my_net_write(&thd->net, (char*) packet->ptr(),
+ packet->length()))
DBUG_RETURN(-1);
}
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
+
/***************************************************************************
-** List all open tables in a database
+ List all open tables in a database
***************************************************************************/
int mysqld_show_open_tables(THD *thd,const char *wild)
@@ -116,19 +119,20 @@ int mysqld_show_open_tables(THD *thd,const char *wild)
if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error)
DBUG_RETURN(-1);
+ String *packet= &thd->packet;
for (; open_list ; open_list=open_list->next)
{
- thd->packet.length(0);
- net_store_data(&thd->packet,convert, open_list->db);
- net_store_data(&thd->packet,convert, open_list->table);
- net_store_data(&thd->packet,open_list->in_use);
- net_store_data(&thd->packet,open_list->locked);
- if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
+ packet->length(0);
+ net_store_data(packet,convert, open_list->db);
+ net_store_data(packet,convert, open_list->table);
+ net_store_data(packet,open_list->in_use);
+ net_store_data(packet,open_list->locked);
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
{
DBUG_RETURN(-1);
}
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -140,7 +144,7 @@ int mysqld_show_open_tables(THD *thd,const char *wild)
int mysqld_show_tables(THD *thd,const char *db,const char *wild)
{
- Item_string *field=new Item_string("",0);
+ Item_string *field=new Item_string("",0,default_charset_info);
List<Item> field_list;
char path[FN_LEN],*end;
List<char> files;
@@ -160,14 +164,228 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
if (mysql_find_files(thd,&files,db,path,wild,0))
DBUG_RETURN(-1);
List_iterator_fast<char> it(files);
+ String *packet= &thd->packet;
while ((file_name=it++))
{
- thd->packet.length(0);
- net_store_data(&thd->packet, thd->variables.convert_set, file_name);
- if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length()))
+ packet->length(0);
+ net_store_data(packet, thd->variables.convert_set, file_name);
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
+ DBUG_RETURN(0);
+}
+
+/***************************************************************************
+** List all table types supported
+***************************************************************************/
+
+struct show_table_type_st {
+ const char *type;
+ SHOW_COMP_OPTION *value;
+ const char *comment;
+};
+
+
+SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
+
+static struct show_table_type_st sys_table_types[]=
+{
+ {"MyISAM", &have_yes,
+ "Default type from 3.23 with great performance"},
+ {"HEAP" , &have_yes,
+ "Hash based, stored in memory, useful for temporary tables"},
+ {"MERGE", &have_yes,
+ "Collection of identical MyISAM tables"},
+ {"ISAM", &have_isam,
+ "Obsolete table type; Is replaced by MyISAM"},
+ {"InnoDB", &have_innodb,
+ "Supports transactions, row-level locking and foreign keys"},
+ {"BDB", &have_berkeley_db,
+ "Supports transactions and page-level locking"},
+ {NullS, NULL, NullS}
+};
+
+
+int mysqld_show_table_types(THD *thd)
+{
+ List<Item> field_list;
+ DBUG_ENTER("mysqld_show_table_types");
+
+ field_list.push_back(new Item_empty_string("Type",10));
+ field_list.push_back(new Item_empty_string("Support",10));
+ field_list.push_back(new Item_empty_string("Comment",80));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ const char *default_type_name= ha_table_typelib.type_names[thd->variables.table_type];
+
+ show_table_type_st *types;
+ String *packet= &thd->packet;
+ for (types= sys_table_types; types->type; types++)
+ {
+ packet->length(0);
+ net_store_data(packet, types->type);
+ const char *option_name= show_comp_option_name[(int) *types->value];
+
+ if (*types->value == SHOW_OPTION_YES &&
+ !my_strcasecmp(system_charset_info, default_type_name, types->type))
+ option_name= "DEFAULT";
+ net_store_data(packet, option_name);
+ net_store_data(packet, types->comment);
+ if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length()))
+ DBUG_RETURN(-1);
+ }
+ send_eof(thd);
+ DBUG_RETURN(0);
+}
+
+
+/***************************************************************************
+ List all privileges supported
+***************************************************************************/
+
+struct show_privileges_st {
+ const char *privilege;
+ const char *context;
+ const char *comment;
+};
+
+
+/*
+ TODO: Update with new privileges
+*/
+static struct show_privileges_st sys_privileges[]=
+{
+ {"Select", "Tables", "To retrieve rows from table"},
+ {"Insert", "Tables", "To insert data into tables"},
+ {"Update", "Tables", "To update existing rows "},
+ {"Delete", "Tables", "To delete existing rows"},
+ {"Index", "Tables", "To create or drop indexes"},
+ {"Alter", "Tables", "To alter the table"},
+ {"Create", "Databases,Tables,Indexes", "To create new databases and tables"},
+ {"Drop", "Databases,Tables", "To drop databases and tables"},
+ {"Grant", "Databases,Tables", "To give to other users those privileges you possess"},
+ {"References", "Databases,Tables", "To have references on tables"},
+ {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"},
+ {"Shutdown","Server Admin", "To shutdown the server"},
+ {"Process", "Server Admin", "To view the plain text of currently executing queries"},
+ {"File", "File access on server", "To read and write files on the server"},
+ {NullS, NullS, NullS}
+};
+
+
+int mysqld_show_privileges(THD *thd)
+{
+ List<Item> field_list;
+ DBUG_ENTER("mysqld_show_privileges");
+
+ field_list.push_back(new Item_empty_string("Privilege",10));
+ field_list.push_back(new Item_empty_string("Context",15));
+ field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ show_privileges_st *privilege= sys_privileges;
+ String *packet= &thd->packet;
+ for (privilege= sys_privileges; privilege->privilege ; privilege++)
+ {
+ packet->length(0);
+ net_store_data(packet,privilege->privilege);
+ net_store_data(packet,privilege->context);
+ net_store_data(packet,privilege->comment);
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(-1);
+ }
+ send_eof(thd);
+ DBUG_RETURN(0);
+}
+
+
+/***************************************************************************
+ List all column types
+***************************************************************************/
+
+struct show_column_type_st
+{
+ const char *type;
+ uint size;
+ const char *min_value;
+ const char *max_value;
+ uint precision;
+ uint scale;
+ const char *nullable;
+ const char *auto_increment;
+ const char *unsigned_attr;
+ const char *zerofill;
+ const char *searchable;
+ const char *case_sensitivity;
+ const char *default_value;
+ const char *comment;
+};
+
+/* TODO: Add remaning types */
+
+static struct show_column_type_st sys_column_types[]=
+{
+ {"tinyint",
+ 1, "-128", "127", 0, 0, "YES", "YES",
+ "NO", "YES", "YES", "NO", "NULL,0",
+ "A very small integer"},
+ {"tinyint unsigned",
+ 1, "0" , "255", 0, 0, "YES", "YES",
+ "YES", "YES", "YES", "NO", "NULL,0",
+ "A very small integer"},
+};
+
+int mysqld_show_column_types(THD *thd)
+{
+ List<Item> field_list;
+ DBUG_ENTER("mysqld_show_column_types");
+
+ field_list.push_back(new Item_empty_string("Type",30));
+ field_list.push_back(new Item_int("Size",(longlong) 1,21));
+ field_list.push_back(new Item_empty_string("Min_Value",20));
+ field_list.push_back(new Item_empty_string("Max_Value",20));
+ field_list.push_back(new Item_int("Prec", 0,4));
+ field_list.push_back(new Item_int("Scale", 0,4));
+ field_list.push_back(new Item_empty_string("Nullable",4));
+ field_list.push_back(new Item_empty_string("Auto_Increment",4));
+ field_list.push_back(new Item_empty_string("Unsigned",4));
+ field_list.push_back(new Item_empty_string("Zerofill",4));
+ field_list.push_back(new Item_empty_string("Searchable",4));
+ field_list.push_back(new Item_empty_string("Case_Sensitive",4));
+ field_list.push_back(new Item_empty_string("Default",NAME_LEN));
+ field_list.push_back(new Item_empty_string("Comment",NAME_LEN));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ /* TODO: Change the loop to not use 'i' */
+ String *packet= &thd->packet;
+ for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
+ {
+ packet->length(0);
+ net_store_data(packet,sys_column_types[i].type);
+ net_store_data(packet,(longlong)sys_column_types[i].size);
+ net_store_data(packet,sys_column_types[i].min_value);
+ net_store_data(packet,sys_column_types[i].max_value);
+ net_store_data(packet,(uint32)sys_column_types[i].precision);
+ net_store_data(packet,(uint32)sys_column_types[i].scale);
+ net_store_data(packet,sys_column_types[i].nullable);
+ net_store_data(packet,sys_column_types[i].auto_increment);
+ net_store_data(packet,sys_column_types[i].unsigned_attr);
+ net_store_data(packet,sys_column_types[i].zerofill);
+ net_store_data(packet,sys_column_types[i].searchable);
+ net_store_data(packet,sys_column_types[i].case_sensitivity);
+ net_store_data(packet,sys_column_types[i].default_value);
+ net_store_data(packet,sys_column_types[i].comment);
+ if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ DBUG_RETURN(-1);
+ }
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -211,7 +429,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
else
{
// Return only .frm files which aren't temp files.
- if (my_strcasecmp(ext=fn_ext(file->name),reg_ext) ||
+ if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
is_prefix(file->name,tmp_file_prefix))
continue;
*ext=0;
@@ -219,7 +437,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
{
if (lower_case_table_names)
{
- if (wild_case_compare(file->name,wild))
+ if (wild_case_compare(system_charset_info,file->name,wild))
continue;
}
else if (wild_compare(file->name,wild))
@@ -246,8 +464,9 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
DBUG_RETURN(0);
}
+
/***************************************************************************
-** Extended version of mysqld_show_tables
+ Extended version of mysqld_show_tables
***************************************************************************/
int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
@@ -264,7 +483,6 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
(void) sprintf(path,"%s/%s",mysql_data_home,db);
(void) unpack_dirname(path,path);
-
field_list.push_back(item=new Item_empty_string("Name",NAME_LEN));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Type",10));
@@ -291,6 +509,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
item->maybe_null=1;
field_list.push_back(item=new Item_datetime("Check_time"));
item->maybe_null=1;
+ field_list.push_back(item=new Item_empty_string("Charset",32));
+ item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Create_options",255));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Comment",80));
@@ -366,6 +586,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
localtime_r(&file->check_time,&tm_tmp);
net_store_data(packet, &tm_tmp);
}
+ net_store_data(packet, convert, table->table_charset ?
+ table->table_charset->name : "default");
{
char option_buff[350],*ptr;
ptr=option_buff;
@@ -417,12 +639,11 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
packet->length()))
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
-
/***************************************************************************
** List all columns in a table_list->real_name
***************************************************************************/
@@ -442,7 +663,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
{
- send_error(&thd->net);
+ send_error(thd);
DBUG_RETURN(1);
}
file=table->file;
@@ -458,8 +679,10 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
item->maybe_null=1;
field_list.push_back(new Item_empty_string("Extra",20));
if (verbose)
+ {
field_list.push_back(new Item_empty_string("Privileges",80));
-
+ field_list.push_back(new Item_empty_string("Comment",255));
+ }
// Send first number of fields and records
{
char *pos;
@@ -476,7 +699,8 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
String *packet= &thd->packet;
for (ptr=table->field; (field= *ptr) ; ptr++)
{
- if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
+ if (!wild || !wild[0] ||
+ !wild_case_compare(system_charset_info, field->field_name,wild))
{
#ifdef NOT_USED
if (thd->col_access & TABLE_ACLS ||
@@ -486,7 +710,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
{
byte *pos;
uint flags=field->flags;
- String type(tmp,sizeof(tmp));
+ String type(tmp,sizeof(tmp),default_charset_info);
uint col_access;
bool null_default_value=0;
@@ -509,7 +733,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
null_default_value=1;
if (!null_default_value && !field->is_null())
{ // Not null by default
- type.set(tmp,sizeof(tmp));
+ type.set(tmp,sizeof(tmp),default_charset_info);
field->val_str(&type,&type);
net_store_data(packet,convert,type.ptr(),type.length());
}
@@ -525,7 +749,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
if (verbose)
{
- /* Add grant options */
+ /* Add grant options & comments */
col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
end=tmp;
for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
@@ -537,16 +761,18 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
}
}
net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
+ net_store_data(packet, field->comment.str,field->comment.length);
}
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
DBUG_RETURN(1);
}
}
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
+
int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
@@ -559,7 +785,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
/* Only one table for now */
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
{
- send_error(&thd->net);
+ send_error(thd);
DBUG_RETURN(1);
}
@@ -584,6 +810,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
if (store_create_info(thd, table, packet))
DBUG_RETURN(-1);
ulong create_len = packet->length() - store_len_offset - 4;
+ /*
+ Just in case somebody manages to create a table
+ with *that* much stuff in the definition
+ */
if (create_len > 0x00ffffff) // better readable in HEX ...
{
/*
@@ -606,7 +836,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
DBUG_RETURN(1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -629,7 +859,7 @@ mysqld_show_logs(THD *thd)
DBUG_RETURN(-1);
#endif
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -646,7 +876,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
{
- send_error(&thd->net);
+ send_error(thd);
DBUG_RETURN(1);
}
@@ -730,14 +960,14 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
DBUG_RETURN(1); /* purecov: inspected */
}
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
/****************************************************************************
-** Return only fields for API mysql_list_fields
-** Use "show table wildcard" in mysql instead of this
+ Return only fields for API mysql_list_fields
+ Use "show table wildcard" in mysql instead of this
****************************************************************************/
void
@@ -749,7 +979,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
{
- send_error(&thd->net);
+ send_error(thd);
DBUG_VOID_RETURN;
}
List<Item> field_list;
@@ -757,7 +987,8 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
Field **ptr,*field;
for (ptr=table->field ; (field= *ptr); ptr++)
{
- if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
+ if (!wild || !wild[0] ||
+ !wild_case_compare(system_charset_info, field->field_name,wild))
field_list.push_back(new Item_field(field));
}
restore_record(table,2); // Get empty record
@@ -767,6 +998,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
DBUG_VOID_RETURN;
}
+
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
@@ -774,7 +1006,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
DBUG_ENTER("mysqld_dump_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
- String* packet = &thd->packet;
+ String *packet = &thd->packet;
packet->length(0);
if (store_create_info(thd,table,packet))
DBUG_RETURN(-1);
@@ -796,6 +1028,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
DBUG_RETURN(0);
}
+
static void
append_identifier(THD *thd, String *packet, const char *name)
{
@@ -811,6 +1044,7 @@ append_identifier(THD *thd, String *packet, const char *name)
}
}
+
static int
store_create_info(THD *thd, TABLE *table, String *packet)
{
@@ -821,7 +1055,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
List<Item> field_list;
char tmp[MAX_FIELD_WIDTH];
- String type(tmp, sizeof(tmp));
+ String type(tmp, sizeof(tmp),default_charset_info);
if (table->tmp_table)
packet->append("CREATE TEMPORARY TABLE ", 23);
else
@@ -841,7 +1075,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append(' ');
// check for surprises from the previous call to Field::sql_type()
if (type.ptr() != tmp)
- type.set(tmp, sizeof(tmp));
+ type.set(tmp, sizeof(tmp),default_charset_info);
field->sql_type(type);
packet->append(type.ptr(),type.length());
@@ -857,12 +1091,12 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append(" default ", 9);
if (!field->is_null())
{ // Not null by default
- type.set(tmp,sizeof(tmp));
+ type.set(tmp,sizeof(tmp),default_charset_info);
field->val_str(&type,&type);
- packet->append('\'');
if (type.length())
- append_unescaped(packet, type.c_ptr());
- packet->append('\'');
+ append_unescaped(packet, type.ptr(), type.length());
+ else
+ packet->append("''",2);
}
else if (field->maybe_null())
packet->append("NULL", 4); // Null as default
@@ -871,7 +1105,13 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
if (field->unireg_check == Field::NEXT_NUMBER)
- packet->append(" auto_increment", 15 );
+ packet->append(" auto_increment", 15 );
+
+ if (field->comment.length)
+ {
+ packet->append(" COMMENT ",9);
+ append_unescaped(packet, field->comment.str, field->comment.length);
+ }
}
KEY *key_info=table->key_info;
@@ -893,11 +1133,22 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append("UNIQUE ", 7);
else if (key_info->flags & HA_FULLTEXT)
packet->append("FULLTEXT ", 9);
+ else if (key_info->flags & HA_SPATIAL)
+ packet->append("SPATIAL ", 8);
packet->append("KEY ", 4);
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))
+ packet->append(" USING RTREE",12);
+
packet->append(" (", 2);
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
@@ -941,6 +1192,12 @@ store_create_info(THD *thd, TABLE *table, String *packet)
char buff[128];
char* p;
+ if (table->table_charset)
+ {
+ packet->append(" CHARSET=");
+ packet->append(table->table_charset->name);
+ }
+
if (table->min_rows)
{
packet->append(" MIN_ROWS=");
@@ -977,9 +1234,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
table->file->append_create_info(packet);
if (table->comment && table->comment[0])
{
- packet->append(" COMMENT='", 10);
- append_unescaped(packet, table->comment);
- packet->append('\'');
+ packet->append(" COMMENT=", 9);
+ append_unescaped(packet, table->comment, strlen(table->comment));
}
if (file->raid_type)
{
@@ -993,8 +1249,8 @@ store_create_info(THD *thd, TABLE *table, String *packet)
/****************************************************************************
-** Return info about all processes
-** returns for each thread: thread id, user, host, db, command, info
+ Return info about all processes
+ returns for each thread: thread id, user, host, db, command, info
****************************************************************************/
class thread_info :public ilink {
@@ -1135,25 +1391,66 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
break; /* purecov: inspected */
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_VOID_RETURN;
}
/*****************************************************************************
-** Status functions
+ Status functions
*****************************************************************************/
+int mysqld_show_charsets(THD *thd, const char *wild)
+{
+ char buff[8192];
+ String packet2(buff,sizeof(buff),default_charset_info);
+ List<Item> field_list;
+ CONVERT *convert=thd->variables.convert_set;
+ CHARSET_INFO **cs;
+ DBUG_ENTER("mysqld_show_charsets");
+
+ field_list.push_back(new Item_empty_string("Name",30));
+ field_list.push_back(new Item_int("Id",0,7));
+ field_list.push_back(new Item_int("strx_maxlen",0,7));
+ field_list.push_back(new Item_int("mb_maxlen",0,7));
+
+ if (send_fields(thd,field_list,1))
+ DBUG_RETURN(1);
+
+ for (cs=all_charsets ; cs < all_charsets+255 ; cs++ )
+ {
+ if (!cs[0])
+ continue;
+ if (!(wild && wild[0] &&
+ wild_case_compare(system_charset_info,cs[0]->name,wild)))
+ {
+ packet2.length(0);
+ 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));
+
+ if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
+ goto err;
+ }
+ }
+ send_eof(thd);
+ DBUG_RETURN(0);
+err:
+ DBUG_RETURN(1);
+}
+
+
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
enum enum_var_type value_type)
{
char buff[8192];
- String packet2(buff,sizeof(buff));
+ String packet2(buff,sizeof(buff), system_charset_info);
List<Item> field_list;
CONVERT *convert=thd->variables.convert_set;
-
DBUG_ENTER("mysqld_show");
+
field_list.push_back(new Item_empty_string("Variable_name",30));
field_list.push_back(new Item_empty_string("Value",256));
if (send_fields(thd,field_list,1))
@@ -1163,7 +1460,8 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
pthread_mutex_lock(&LOCK_status);
for (; variables->name; variables++)
{
- if (!(wild && wild[0] && wild_case_compare(variables->name,wild)))
+ if (!(wild && wild[0] && wild_case_compare(system_charset_info,
+ variables->name,wild)))
{
packet2.length(0);
net_store_data(&packet2,convert,variables->name);
@@ -1196,9 +1494,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
case SHOW_HAVE:
{
SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value;
- net_store_data(&packet2, (tmp == SHOW_OPTION_NO ? "NO" :
- tmp == SHOW_OPTION_YES ? "YES" :
- "DISABLED"));
+ net_store_data(&packet2, show_comp_option_name[(int) tmp]);
break;
}
case SHOW_CHAR:
@@ -1398,7 +1694,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
}
pthread_mutex_unlock(&LOCK_status);
/* pthread_mutex_unlock(&THR_LOCK_keycache); */
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
err:
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 2dcda2d40c2..5083fb13105 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -91,36 +91,58 @@ bool String::realloc(uint32 alloc_length)
return FALSE;
}
-bool String::set(longlong num)
+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);
+ if (cs->snprintf == my_snprintf_8bit)
+ {
+ str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr);
+ }
+ else
+ {
+ str_length=cs->snprintf(cs,Ptr,l,"%d",num);
+ }
+ str_charset=cs;
return FALSE;
}
-bool String::set(ulonglong num)
+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);
+ if (cs->snprintf == my_snprintf_8bit)
+ {
+ str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr);
+ }
+ else
+ {
+ str_length=cs->snprintf(cs,Ptr,l,"%d",num);
+ }
+ str_charset=cs;
return FALSE;
}
-bool String::set(double num,uint decimals)
+bool String::set(double num,uint decimals, CHARSET_INFO *cs)
{
char buff[331];
+
+ str_charset=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 (!isdigit(buff[1]))
+ if (!my_isdigit(my_charset_latin1, buff[1]))
{ // Nan or Inf
pos=buff+1;
if (sign)
@@ -128,7 +150,7 @@ bool String::set(double num,uint decimals)
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;
@@ -178,7 +200,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
}
@@ -200,16 +222,67 @@ bool String::copy(const String &str)
str_length=str.str_length;
bmove(Ptr,str.Ptr,str_length); // May be overlapping
Ptr[str_length]=0;
+ str_charset=str.str_charset;
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;
}
@@ -231,7 +304,7 @@ bool String::fill(uint32 max_length,char fill_char)
void String::strip_sp()
{
- while (str_length && isspace(Ptr[str_length-1]))
+ while (str_length && my_isspace(str_charset,Ptr[str_length-1]))
str_length--;
}
@@ -293,10 +366,10 @@ uint32 String::numchars()
register uint32 n=0,mblen;
register const char *mbstr=Ptr;
register const char *end=mbstr+str_length;
- if (use_mb(default_charset_info))
+ if (use_mb(str_charset))
{
while (mbstr < end) {
- if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
else ++mbstr;
++n;
}
@@ -313,11 +386,11 @@ int String::charpos(int i,uint32 offset)
register uint32 mblen;
register const char *mbstr=Ptr+offset;
register const char *end=Ptr+str_length;
- if (use_mb(default_charset_info))
+ if (use_mb(str_charset))
{
if (i<=0) return i;
while (i && mbstr < end) {
- if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
else ++mbstr;
--i;
}
@@ -377,12 +450,14 @@ int String::strstr_case(const String &s,uint32 offset)
skipp:
while (str != end)
{
- if (my_sort_order[*str++] == my_sort_order[*search])
+ if (str_charset->sort_order[*str++] == str_charset->sort_order[*search])
{
register char *i,*j;
i=(char*) str; j=(char*) search+1;
while (j != search_end)
- if (my_sort_order[*i++] != my_sort_order[*j++]) goto skipp;
+ if (str_charset->sort_order[*i++] !=
+ str_charset->sort_order[*j++])
+ goto skipp;
return (int) (str-Ptr) -1;
}
}
@@ -456,6 +531,44 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
return FALSE;
}
+// added by Holyfoot for "geometry" needs
+int String::reserve(uint32 space_needed, uint32 grow_by)
+{
+ if (Alloced_length < str_length + space_needed)
+ {
+ if (realloc(Alloced_length + max(space_needed, grow_by) - 1))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void String::qs_append(const char *str)
+{
+ int len = strlen(str);
+ memcpy(Ptr + str_length, str, len + 1);
+ str_length += len;
+}
+
+void String::qs_append(double d)
+{
+ char *buff = Ptr + str_length;
+ sprintf(buff,"%.14g", d);
+ str_length += strlen(buff);
+}
+
+void String::qs_append(double *d)
+{
+ double ld;
+ float8get(ld, (char*) d);
+ qs_append(ld);
+}
+
+void String::qs_append(const char &c)
+{
+ Ptr[str_length] = c;
+ str_length += sizeof(c);
+}
+
int sortcmp(const String *x,const String *y)
{
@@ -464,15 +577,15 @@ int sortcmp(const String *x,const String *y)
uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (use_strnxfrm(x->str_charset))
{
#ifndef CMP_ENDSPACE
- while (x_len && isspace(s[x_len-1]))
+ while (x_len && my_isspace(x->str_charset,s[x_len-1]))
x_len--;
- while (y_len && isspace(t[y_len-1]))
+ while (y_len && my_isspace(x->str_charset,t[y_len-1]))
y_len--;
#endif
- return my_strnncoll(default_charset_info,
+ return my_strnncoll(x->str_charset,
(unsigned char *)s,x_len,(unsigned char *)t,y_len);
}
else
@@ -480,11 +593,23 @@ int sortcmp(const String *x,const String *y)
#endif /* USE_STRCOLL */
x_len-=len; // For easy end space test
y_len-=len;
- while (len--)
+ if (x->str_charset->sort_order)
{
- if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
- return ((int) my_sort_order[(uchar) s[-1]] -
- (int) my_sort_order[(uchar) t[-1]]);
+ while (len--)
+ {
+ if (x->str_charset->sort_order[(uchar) *s++] !=
+ x->str_charset->sort_order[(uchar) *t++])
+ return ((int) x->str_charset->sort_order[(uchar) s[-1]] -
+ (int) x->str_charset->sort_order[(uchar) t[-1]]);
+ }
+ }
+ else
+ {
+ while (len--)
+ {
+ if (*s++ != *t++)
+ return ((int) s[-1] - (int) t[-1]);
+ }
}
#ifndef CMP_ENDSPACE
/* Don't compare end space in strings */
@@ -493,14 +618,14 @@ int sortcmp(const String *x,const String *y)
{
const char *end=t+y_len;
for (; t != end ; t++)
- if (!isspace(*t))
+ if (!my_isspace(x->str_charset,*t))
return -1;
}
else
{
const char *end=s+x_len;
for (; s != end ; s++)
- if (!isspace(*s))
+ if (!my_isspace(x->str_charset,*s))
return 1;
}
return 0;
@@ -542,263 +667,9 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
return from; // Actually an error
if ((to->str_length=min(from->str_length,from_length)))
memcpy(to->Ptr,from->Ptr,to->str_length);
+ to->str_charset=from->str_charset;
return to;
}
-/* Make it easier to handle different charactersets */
-#ifdef USE_MB
-#define INC_PTR(A,B) A+=((use_mb_flag && \
- my_ismbchar(default_charset_info,A,B)) ? \
- my_ismbchar(default_charset_info,A,B) : 1)
-#else
-#define INC_PTR(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(A) (uchar) toupper(A)
-#else
-#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
-#endif
-
-int wild_case_compare(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(default_charset_info);
-#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(default_charset_info, 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(*wildstr++) != likeconv(*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(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(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(default_charset_info, wildstr, wildend);
-#endif
- INC_PTR(wildstr,wildend); // This is compared trough cmp
- cmp=likeconv(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(default_charset_info, str, str_end) &&
- likeconv(*str) == cmp)
- {
- str++;
- break;
- }
- INC_PTR(str, str_end);
- }
- }
- else
- {
-#endif /* USE_MB */
- while (str != str_end && likeconv(*str) != cmp)
- str++;
- if (str++ == str_end) return (-1);
-#ifdef USE_MB
- }
-#endif
- {
- int tmp=wild_case_compare(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.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 ad7455ecbf1..42f9e446981 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -28,34 +28,52 @@ 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
{
char *Ptr;
uint32 str_length,Alloced_length;
bool alloced;
+ CHARSET_INFO *str_charset;
public:
String()
- { Ptr=0; str_length=Alloced_length=0; alloced=0; }
+ {
+ Ptr=0; str_length=Alloced_length=0; alloced=0;
+ str_charset=default_charset_info;
+ }
String(uint32 length_arg)
- { alloced=0; Alloced_length=0; (void) real_alloc(length_arg); }
- String(const char *str)
- { Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;}
- String(const char *str,uint32 len)
- { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;}
- String(char *str,uint32 len)
- { Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;}
+ {
+ alloced=0; Alloced_length=0; (void) real_alloc(length_arg);
+ str_charset=default_charset_info;
+ }
+ String(const char *str, CHARSET_INFO *cs)
+ {
+ Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;
+ str_charset=cs;
+ }
+ String(const char *str,uint32 len, CHARSET_INFO *cs)
+ {
+ Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;
+ str_charset=cs;
+ }
+ String(char *str,uint32 len, CHARSET_INFO *cs)
+ {
+ Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;
+ str_charset=cs;
+ }
String(const String &str)
- { Ptr=str.Ptr ; str_length=str.str_length ;
- Alloced_length=str.Alloced_length; alloced=0; }
-
+ {
+ Ptr=str.Ptr ; str_length=str.str_length ;
+ Alloced_length=str.Alloced_length; alloced=0;
+ str_charset=str.str_charset;
+ }
static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
{ sql_element_free(ptr_arg); }
~String() { free(); }
+ 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;}
inline char& operator [] (uint32 i) const { return Ptr[i]; }
@@ -83,28 +101,31 @@ public:
Alloced_length=str.Alloced_length-offset;
else
Alloced_length=0;
+ str_charset=str.str_charset;
}
- inline void set(char *str,uint32 arg_length)
+ inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs)
{
free();
Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0;
+ str_charset=cs;
}
- inline void set(const char *str,uint32 arg_length)
+ inline void set(const char *str,uint32 arg_length, CHARSET_INFO *cs)
{
free();
Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0;
+ str_charset=cs;
}
- inline void set_quick(char *str,uint32 arg_length)
+ inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs)
{
if (!alloced)
{
Ptr=(char*) str; str_length=Alloced_length=arg_length;
}
+ str_charset=cs;
}
- bool set(longlong num);
- /* bool set(long num); */
- bool set(ulonglong num);
- bool set(double num,uint decimals=2);
+ bool set(longlong num, CHARSET_INFO *cs);
+ bool set(ulonglong num, CHARSET_INFO *cs);
+ bool set(double num,uint decimals, CHARSET_INFO *cs);
inline void free()
{
if (alloced)
@@ -155,7 +176,8 @@ 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);
@@ -179,13 +201,57 @@ public:
}
bool fill(uint32 max_length,char fill);
void strip_sp();
- inline void caseup() { ::caseup(Ptr,str_length); }
- inline void casedn() { ::casedn(Ptr,str_length); }
+ inline void caseup() { my_caseup(str_charset,Ptr,str_length); }
+ inline void casedn() { my_casedn(str_charset,Ptr,str_length); }
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);
+
+ int reserve(uint32 space_needed)
+ {
+ return realloc(str_length + space_needed);
+ }
+ int reserve(uint32 space_needed, uint32 grow_by);
+
+ /*
+ The following append operations do NOT check alloced memory
+ q_*** methods writes values of parameters itself
+ qs_*** methods writes string representation of value
+ */
+ void q_append(const char &c)
+ {
+ Ptr[str_length++] = c;
+ }
+ void q_append(const uint32 &n)
+ {
+ int4store(Ptr + str_length, n);
+ str_length += 4;
+ }
+ void q_append(double d)
+ {
+ float8store(Ptr + str_length, d);
+ str_length += 8;
+ }
+ void q_append(double *d)
+ {
+ float8store(Ptr + str_length, *d);
+ str_length += 8;
+ }
+ void q_append(const char *data, uint32 data_len)
+ {
+ memcpy(Ptr + str_length, data, data_len);
+ str_length += data_len;
+ }
+
+ void WriteAtPosition(int position, uint32 value)
+ {
+ int4store(Ptr + position,value);
+ }
+
+ void qs_append(const char *str);
+ void qs_append(double d);
+ void qs_append(double *d);
+ void qs_append(const char &c);
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index aa0946113c9..00077bda39f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -74,7 +74,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
}
error=mysql_rm_table_part2(thd,tables,if_exists,0);
- err:
+ err:
pthread_mutex_unlock(&LOCK_open);
VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
@@ -85,7 +85,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
if (error)
DBUG_RETURN(-1);
- send_ok(&thd->net);
+ send_ok(thd);
DBUG_RETURN(0);
}
@@ -185,7 +185,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
{
if (wrong_tables.length())
wrong_tables.append(',');
- wrong_tables.append(String(table->real_name));
+ wrong_tables.append(String(table->real_name,default_charset_info));
}
}
if (some_tables_deleted || tmp_table_deleted)
@@ -239,7 +239,6 @@ int quick_rm_table(enum db_type base,const char *db,
PRIMARY keys are prioritized.
*/
-
static int sort_keys(KEY *a, KEY *b)
{
if (a->flags & HA_NOSAME)
@@ -304,7 +303,8 @@ static int sort_keys(KEY *a, KEY *b)
int mysql_create_table(THD *thd,const char *db, const char *table_name,
HA_CREATE_INFO *create_info,
List<create_field> &fields,
- List<Key> &keys,bool tmp_table,bool no_log)
+ List<Key> &keys,bool tmp_table,bool no_log,
+ uint select_field_count)
{
char path[FN_REFLEN];
const char *key_name;
@@ -312,14 +312,15 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
int error= -1;
uint db_options,field,null_fields,blob_columns;
ulong pos;
- KEY *key_info,*key_info_buffer;
+ KEY *key_info,*key_info_buffer;
KEY_PART_INFO *key_part_info;
int auto_increment=0;
handler *file;
+ int field_no,dup_no;
DBUG_ENTER("mysql_create_table");
/*
- ** Check for duplicate fields and check type of table to create
+ Check for duplicate fields and check type of table to create
*/
if (!fields.elements)
@@ -328,6 +329,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
List_iterator<create_field> it(fields),it2(fields);
+ int select_field_pos=fields.elements - select_field_count;
null_fields=blob_columns=0;
db_options=create_info->table_options;
if (create_info->row_type == ROW_TYPE_DYNAMIC)
@@ -341,10 +343,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
- /* Don't pack keys in old tables if the user has requested this */
-
- while ((sql_field=it++))
+ for (field_no=0; (sql_field=it++) ; field_no++)
{
+ /* Don't pack keys in old tables if the user has requested this */
if ((sql_field->flags & BLOB_FLAG) ||
sql_field->sql_type == FIELD_TYPE_VAR_STRING &&
create_info->row_type != ROW_TYPE_FIXED)
@@ -353,12 +354,36 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
- while ((dup_field=it2++) != sql_field)
+
+ /* Check if we have used the same field name before */
+ for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++)
{
- if (my_strcasecmp(sql_field->field_name, dup_field->field_name) == 0)
+ if (my_strcasecmp(system_charset_info,
+ sql_field->field_name,
+ dup_field->field_name) == 0)
{
- my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name);
- DBUG_RETURN(-1);
+ /*
+ If this was a CREATE ... SELECT statement, accept a field
+ redefinition if we are changing a field in the SELECT part
+ */
+ if (field_no < select_field_pos || dup_no >= select_field_pos)
+ {
+ my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name);
+ DBUG_RETURN(-1);
+ }
+ else
+ {
+ /* Field redefined */
+ sql_field->length= dup_field->length;
+ sql_field->decimals= dup_field->decimals;
+ sql_field->flags= dup_field->flags;
+ sql_field->pack_length= dup_field->pack_length;
+ sql_field->unireg_check= dup_field->unireg_check;
+ sql_field->sql_type= dup_field->sql_type;
+ it2.remove(); // Remove first (create) definition
+ select_field_pos--;
+ break;
+ }
}
}
it2.rewind();
@@ -371,6 +396,12 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
it.rewind();
while ((sql_field=it++))
{
+ if(!sql_field->charset)
+ sql_field->charset = create_info->table_charset ?
+ create_info->table_charset :
+ thd->db_charset? thd->db_charset :
+ default_charset_info;
+
switch (sql_field->sql_type) {
case FIELD_TYPE_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
@@ -379,7 +410,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
sql_field->pack_flag=FIELDFLAG_BLOB |
pack_length_to_packflag(sql_field->pack_length -
portable_sizeof_char_ptr);
- if (sql_field->flags & BINARY_FLAG)
+ if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->length=8; // Unireg field length
sql_field->unireg_check=Field::BLOB_FIELD;
@@ -388,17 +419,21 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
case FIELD_TYPE_VAR_STRING:
case FIELD_TYPE_STRING:
sql_field->pack_flag=0;
- if (sql_field->flags & BINARY_FLAG)
+ if (sql_field->charset->state & MY_CS_BINSORT)
sql_field->pack_flag|=FIELDFLAG_BINARY;
break;
case FIELD_TYPE_ENUM:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_INTERVAL;
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::INTERVAL_FIELD;
break;
case FIELD_TYPE_SET:
sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) |
FIELDFLAG_BITFIELD;
+ if (sql_field->charset->state & MY_CS_BINSORT)
+ sql_field->pack_flag|=FIELDFLAG_BINARY;
sql_field->unireg_check=Field::BIT_FIELD;
break;
case FIELD_TYPE_DATE: // Rest of string types
@@ -449,35 +484,50 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
/* Create keys */
List_iterator<Key> key_iterator(keys);
- uint key_parts=0,key_count=keys.elements;
+ uint key_parts=0, key_count=0, fk_key_count=0;
List<Key> keys_in_order; // Add new keys here
bool primary_key=0,unique_key=0;
Key *key;
uint tmp, key_number;
- tmp=min(file->max_keys(), MAX_KEY);
- if (key_count > tmp)
- {
- my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
- DBUG_RETURN(-1);
- }
/* Calculate number of key segements */
while ((key=key_iterator++))
{
+ if (key->type == Key::FOREIGN_KEY)
+ {
+ fk_key_count++;
+ foreign_key *fk_key= (foreign_key*) key;
+ if (fk_key->ref_columns.elements &&
+ fk_key->ref_columns.elements != fk_key->columns.elements)
+ {
+ my_error(ER_WRONG_FK_DEF, MYF(0), fk_key->name ? fk_key->name :
+ "foreign key without name",
+ ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF));
+ DBUG_RETURN(-1);
+ }
+ continue;
+ }
+ key_count++;
tmp=max(file->max_key_parts(),MAX_REF_PARTS);
if (key->columns.elements > tmp)
{
my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp);
DBUG_RETURN(-1);
}
- if (key->name() && strlen(key->name()) > NAME_LEN)
+ if (key->name && strlen(key->name) > NAME_LEN)
{
- my_error(ER_TOO_LONG_IDENT, MYF(0), key->name());
+ my_error(ER_TOO_LONG_IDENT, MYF(0), key->name);
DBUG_RETURN(-1);
}
key_parts+=key->columns.elements;
}
+ tmp=min(file->max_keys(), MAX_KEY);
+ if (key_count > tmp)
+ {
+ my_error(ER_TOO_MANY_KEYS,MYF(0),tmp);
+ DBUG_RETURN(-1);
+ }
key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count);
key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts);
@@ -486,13 +536,28 @@ 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;
- key_info->flags= (key->type == Key::MULTIPLE) ? 0 :
- (key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME;
+ switch(key->type){
+ case Key::MULTIPLE:
+ key_info->flags = 0;
+ break;
+ case Key::FULLTEXT:
+ key_info->flags = HA_FULLTEXT;
+ break;
+ case Key::SPATIAL:
+ key_info->flags = HA_SPATIAL;
+ break;
+ case Key::FOREIGN_KEY:
+ key_number--; // Skip this key
+ continue;
+ default:
+ key_info->flags = HA_NOSAME;
+ }
+
key_info->key_parts=(uint8) key->columns.elements;
key_info->key_part=key_part_info;
key_info->usable_key_parts= key_number;
@@ -507,14 +572,42 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
}
-
+ /*
+ Make SPATIAL to be RTREE by default
+ SPATIAL only on BLOB or at least BINARY, this
+ actually should be replaced by special GEOM type
+ in near future when new frm file is ready
+ checking for proper key parts number:
+ */
+
+ if (key_info->flags == HA_SPATIAL)
+ {
+ if (key_info->key_parts != 1)
+ {
+ my_printf_error(ER_WRONG_ARGUMENTS,
+ ER(ER_WRONG_ARGUMENTS),MYF(0),"SPATIAL INDEX");
+ DBUG_RETURN(-1);
+ }
+ }
+ else if (key_info->algorithm == HA_KEY_ALG_RTREE)
+ {
+ if ((key_info->key_parts & 1) == 1)
+ {
+ my_printf_error(ER_WRONG_ARGUMENTS,
+ ER(ER_WRONG_ARGUMENTS),MYF(0),"RTREE INDEX");
+ DBUG_RETURN(-1);
+ }
+ }
+
List_iterator<key_part_spec> cols(key->columns);
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
it.rewind();
field=0;
while ((sql_field=it++) &&
- my_strcasecmp(column->field_name,sql_field->field_name))
+ my_strcasecmp(system_charset_info,
+ column->field_name,
+ sql_field->field_name))
field++;
if (!sql_field)
{
@@ -535,6 +628,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
{
if (key->type == Key::FULLTEXT)
column->length=1; /* ft-code ignores it anyway :-) */
+ else if (key->type == Key::SPATIAL)
+ {
+ /*
+ BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
+ */
+ column->length=4*sizeof(double);
+ }
else
{
my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
@@ -626,7 +727,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
key_name=primary_key_name;
primary_key=1;
}
- else if (!(key_name = key->name()))
+ else if (!(key_name = key->name))
key_name=make_unique_key_name(sql_field->field_name,
key_info_buffer,key_info);
if (check_if_keyname_exists(key_name,key_info_buffer,key_info))
@@ -646,6 +747,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))
@@ -696,7 +798,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
thd->proc_info="creating table";
create_info->table_options=db_options;
- if (rea_create_table(path, create_info, fields, key_count,
+ if (rea_create_table(thd, path, create_info, fields, key_count,
key_info_buffer))
{
/* my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,my_errno); */
@@ -738,7 +840,7 @@ static bool
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
{
for (KEY *key=start ; key != end ; key++)
- if (!my_strcasecmp(name,key->name))
+ if (!my_strcasecmp(system_charset_info,name,key->name))
return 1;
return 0;
}
@@ -774,6 +876,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE tmp_table; // Used during 'create_field()'
TABLE *table;
tmp_table.table_name=0;
+ uint select_field_count= items->elements;
DBUG_ENTER("create_table_from_items");
/* Add selected items to field list */
@@ -811,7 +914,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
/* create and lock table */
/* QQ: This should be done atomic ! */
if (mysql_create_table(thd,db,name,create_info,*extra_fields,
- *keys,0,1)) // no logging
+ *keys,0,1,select_field_count)) // no logging
DBUG_RETURN(0);
if (!(table=open_table(thd,db,name,name,(bool*) 0)))
{
@@ -1225,7 +1328,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
goto err;
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
err:
close_thread_tables(thd); // Shouldn't be needed
@@ -1344,9 +1447,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
strmov(new_name_buff,new_name);
fn_same(new_name_buff,table_name,3);
if (lower_case_table_names)
- casedn_str(new_name);
+ my_casedn_str(system_charset_info,new_name);
if ((lower_case_table_names &&
- !my_strcasecmp(new_name_buff,table_name)) ||
+ !my_strcasecmp(system_charset_info, new_name_buff,table_name)) ||
(!lower_case_table_names &&
!strcmp(new_name_buff,table_name)))
new_name=table_name; // No. Make later check easier
@@ -1430,7 +1533,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
- send_ok(&thd->net);
+ send_ok(thd);
}
DBUG_RETURN(error);
}
@@ -1444,7 +1547,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<Key> key_list; // Add new keys here
/*
- ** First collect all fields from table which isn't in drop_list
+ First collect all fields from table which isn't in drop_list
*/
create_field *def;
@@ -1457,7 +1560,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
while ((drop=drop_it++))
{
if (drop->type == Alter_drop::COLUMN &&
- !my_strcasecmp(field->field_name, drop->name))
+ !my_strcasecmp(system_charset_info,field->field_name, drop->name))
{
/* Reset auto_increment value if it was dropped */
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
@@ -1478,7 +1581,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
def_it.rewind();
while ((def=def_it++))
{
- if (def->change && !my_strcasecmp(field->field_name, def->change))
+ if (def->change &&
+ !my_strcasecmp(system_charset_info,field->field_name, def->change))
break;
}
if (def)
@@ -1502,7 +1606,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_column *alter;
while ((alter=alter_it++))
{
- if (!my_strcasecmp(field->field_name, alter->name))
+ if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
break;
}
if (alter)
@@ -1536,7 +1640,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
find_it.rewind();
while ((find=find_it++)) // Add new columns
{
- if (!my_strcasecmp(def->after, find->field_name))
+ if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
break;
}
if (!find)
@@ -1559,8 +1663,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
/*
- ** Collect all keys which isn't in drop list. Add only those
- ** for which some fields exists.
+ Collect all keys which isn't in drop list. Add only those
+ for which some fields exists.
*/
List_iterator<Key> key_it(keys);
@@ -1582,7 +1686,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
while ((drop=drop_it++))
{
if (drop->type == Alter_drop::KEY &&
- !my_strcasecmp(key_name, drop->name))
+ !my_strcasecmp(system_charset_info,key_name, drop->name))
break;
}
if (drop)
@@ -1604,11 +1708,13 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (cfield->change)
{
- if (!my_strcasecmp(key_part_name, cfield->change))
+ if (!my_strcasecmp(system_charset_info, key_part_name,
+ cfield->change))
break;
}
- else if (!my_strcasecmp(key_part_name, cfield->field_name))
- break;
+ else if (!my_strcasecmp(system_charset_info,
+ key_part_name, cfield->field_name))
+ break;
}
if (!cfield)
continue; // Field is removed
@@ -1625,18 +1731,24 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
key_part_length));
}
if (key_parts.elements)
- key_list.push_back(new Key(key_info->flags & HA_NOSAME ?
- (!my_strcasecmp(key_name, "PRIMARY") ?
+ key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
+ (key_info->flags & HA_NOSAME ?
+ (!my_strcasecmp(system_charset_info,
+ key_name, "PRIMARY") ?
Key::PRIMARY : Key::UNIQUE) :
- (key_info->flags & HA_FULLTEXT ?
- Key::FULLTEXT : Key::MULTIPLE),
- key_name,key_parts));
+ (key_info->flags & HA_FULLTEXT ?
+ Key::FULLTEXT : Key::MULTIPLE)),
+ key_name,
+ key_info->algorithm,
+ key_parts));
}
- key_it.rewind();
{
Key *key;
while ((key=key_it++)) // Add new keys
- key_list.push_back(key);
+ {
+ if (key->type != Key::FOREIGN_KEY)
+ key_list.push_back(key);
+ }
}
if (drop_list.elements)
@@ -1664,6 +1776,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
create_info->max_rows=table->max_rows;
if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
create_info->avg_row_length=table->avg_row_length;
+ if (!(used_fields & HA_CREATE_USED_CHARSET))
+ create_info->table_charset=table->table_charset;
table->file->update_create_info(create_info);
if ((create_info->table_options &
@@ -1731,7 +1845,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if ((error=mysql_create_table(thd, new_db, tmp_name,
create_info,
- create_list,key_list,1,1))) // no logging
+ create_list,key_list,1,1,0))) // no logging
DBUG_RETURN(error);
if (table->tmp_table)
@@ -1808,9 +1922,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
goto err;
}
/*
- ** Data is copied. Now we rename the old table to a temp name,
- ** rename the new one to the old name, remove all entries from the old table
- ** from the cash, free all locks, close the old table and remove it.
+ Data is copied. Now we rename the old table to a temp name,
+ rename the new one to the old name, remove all entries from the old table
+ from the cash, free all locks, close the old table and remove it.
*/
thd->proc_info="rename result table";
@@ -1955,7 +2069,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
end_temporary:
sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted),
(ulong) deleted, thd->cuted_fields);
- send_ok(&thd->net,copied+deleted,0L,tmp_name);
+ send_ok(thd,copied+deleted,0L,tmp_name);
thd->some_tables_deleted=0;
DBUG_RETURN(0);
@@ -2018,8 +2132,8 @@ copy_data_between_tables(TABLE *from,TABLE *to,
if (setup_order(thd, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
- (from->found_records = filesort(from, sortorder, length,
- (SQL_SELECT *) 0, 0L, HA_POS_ERROR,
+ (from->found_records = filesort(thd, from, sortorder, length,
+ (SQL_SELECT *) 0, HA_POS_ERROR,
&examined_rows))
== HA_POS_ERROR)
goto err;
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index b226bc1300a..3fbeaa753db 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -26,6 +26,24 @@
/* Intern key cache variables */
extern "C" pthread_mutex_t THR_LOCK_keycache;
+static const char *lock_descriptions[] =
+{
+ "No lock",
+ "Low priority read lock",
+ "Shared Read lock",
+ "High priority read lock",
+ "Read lock without concurrent inserts",
+ "Write lock that allows other writers",
+ "Write lock, but allow reading",
+ "Concurrent insert lock",
+ "Lock Used by delayed insert",
+ "Low priority write lock",
+ "High priority write lock",
+ "Highest priority write lock"
+};
+extern HASH open_cache;
+
+
#ifndef DBUG_OFF
void
@@ -34,7 +52,7 @@ print_where(COND *cond,const char *info)
if (cond)
{
char buff[256];
- String str(buff,(uint32) sizeof(buff));
+ String str(buff,(uint32) sizeof(buff), default_charset_info);
str.length(0);
cond->print(&str);
str.append('\0');
@@ -45,10 +63,8 @@ print_where(COND *cond,const char *info)
DBUG_UNLOCK_FILE;
}
}
-
/* This is for debugging purposes */
-extern HASH open_cache;
extern TABLE *unused_tables;
void print_cached_tables(void)
@@ -57,16 +73,16 @@ void print_cached_tables(void)
TABLE *start_link,*lnk;
VOID(pthread_mutex_lock(&LOCK_open));
- puts("DB Table Version Thread L.thread Open");
+ puts("DB Table Version Thread L.thread Open Lock");
for (idx=unused=0 ; idx < open_cache.records ; idx++)
{
TABLE *entry=(TABLE*) hash_element(&open_cache,idx);
- printf("%-14.14s %-32s%6ld%8ld%10ld%6d\n",
+ printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n",
entry->table_cache_key,entry->real_name,entry->version,
entry->in_use ? entry->in_use->thread_id : 0L,
entry->in_use ? entry->in_use->dbug_thread_id : 0L,
- entry->db_stat ? 1 : 0);
+ entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use");
if (!entry->in_use)
unused++;
}
@@ -97,10 +113,11 @@ void print_cached_tables(void)
}
-void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special)
+void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
{
char buff[256],buff2[256];
- String str(buff,sizeof(buff)),out(buff2,sizeof(buff2));
+ String str(buff,sizeof(buff),default_charset_info);
+ String out(buff2,sizeof(buff2),default_charset_info);
const char *sep;
DBUG_ENTER("TEST_filesort");
@@ -130,8 +147,6 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special)
out.append('\0'); // Purify doesn't like c_ptr()
DBUG_LOCK_FILE;
VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE));
- if (special)
- fprintf(DBUG_FILE,"Records to sort: %ld\n",special);
fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
DBUG_UNLOCK_FILE;
DBUG_VOID_RETURN;
@@ -187,6 +202,99 @@ TEST_join(JOIN *join)
#endif
+typedef struct st_debug_lock
+{
+ ulong thread_id;
+ char table_name[FN_REFLEN];
+ bool waiting;
+ const char *lock_text;
+ enum thr_lock_type type;
+} TABLE_LOCK_INFO;
+
+static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b)
+{
+ if (a->thread_id > b->thread_id)
+ return 1;
+ if (a->thread_id < b->thread_id)
+ return -1;
+ if (a->waiting == b->waiting)
+ return 0;
+ else if (a->waiting)
+ return -1;
+ return 1;
+}
+
+static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, bool wait, const char *text)
+{
+ if (data)
+ {
+ TABLE *table=(TABLE *)data->debug_print_param;
+ if (table && table->tmp_table == NO_TMP_TABLE)
+ {
+ TABLE_LOCK_INFO table_lock_info;
+ table_lock_info.thread_id=table->in_use->thread_id;
+ memcpy(table_lock_info.table_name, table->table_cache_key, table->key_length);
+ table_lock_info.table_name[strlen(table_lock_info.table_name)]='.';
+ table_lock_info.waiting=wait;
+ table_lock_info.lock_text=text;
+ table_lock_info.type=table->reginfo.lock_type; // obtainable also from THR_LOCK_DATA
+ VOID(push_dynamic(ar,(gptr) &table_lock_info));
+ }
+ }
+}
+/*
+ Regarding MERGE tables:
+
+For now, the best option is to use the common TABLE *pointer for all
+cases; The drawback is that for MERGE tables we will see many locks
+for the merge tables even if some of them are for individual tables.
+
+The way to solve this is to add to 'THR_LOCK' structure a pointer to
+the filename and use this when printing the data.
+(We can for now ignore this and just print the same name for all merge
+table parts; Please add the above as a comment to the display_lock
+function so that we can easily add this if we ever need this.
+
+*/
+
+static void display_table_locks (void)
+{
+ LIST *list;
+ DYNAMIC_ARRAY saved_table_locks;
+
+ VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50));
+ VOID(pthread_mutex_lock(&THR_LOCK_lock));
+ for (list=thr_lock_thread_list ; list ; list=rest(list))
+ {
+ THR_LOCK *lock=(THR_LOCK*) list->data;
+
+ VOID(pthread_mutex_lock(&lock->mutex));
+ push_locks_into_array(&saved_table_locks, lock->write.data, false, "Locked - write");
+ push_locks_into_array(&saved_table_locks, lock->write_wait.data, true, "Waiting - write");
+ push_locks_into_array(&saved_table_locks, lock->read.data, false, "Locked - read");
+ push_locks_into_array(&saved_table_locks, lock->read_wait.data, true, "Waiting - read");
+ VOID(pthread_mutex_unlock(&lock->mutex));
+ }
+ VOID(pthread_mutex_unlock(&THR_LOCK_lock));
+ if (!saved_table_locks.elements) goto end;
+
+ qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare);
+ freeze_size(&saved_table_locks);
+
+ puts("\nThread database.table_name Locked/Waiting Lock_type\n");
+
+ for (uint i=0 ; i < saved_table_locks.elements ; i++)
+ {
+ TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*);
+ printf("%-8ld%-28.28s%-22s%s\n",
+ dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]);
+ }
+ puts("\n\n");
+end:
+ delete_dynamic(&saved_table_locks);
+}
+
+
void mysql_print_status(THD *thd)
{
char current_dir[FN_REFLEN];
@@ -252,6 +360,7 @@ Next alarm time: %lu\n",
alarm_info.max_used_alarms,
alarm_info.next_alarm_time);
#endif
+ display_table_locks();
fflush(stdout);
if (thd)
thd->proc_info="malloc";
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 420ec67f0c5..35e33caf572 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -127,7 +127,8 @@ void udf_init()
init_sql_alloc(&mem, 1024,0);
THD *new_thd = new THD;
if (!new_thd ||
- hash_init(&udf_hash,32,0,0,get_hash_key, NULL, HASH_CASE_INSENSITIVE))
+ hash_init(&udf_hash,system_charset_info,
+ 32,0,0,get_hash_key, NULL, HASH_CASE_INSENSITIVE))
{
sql_print_error("Can't allocate memory for udf structures");
hash_free(&udf_hash);
@@ -352,7 +353,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (!initialized)
{
- send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
DBUG_RETURN(1);
}
@@ -363,19 +364,19 @@ int mysql_create_function(THD *thd,udf_func *udf)
*/
if (strchr(udf->dl, '/'))
{
- send_error(&thd->net, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS));
+ send_error(thd, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS));
DBUG_RETURN(1);
}
if (udf->name_length > NAME_LEN)
{
- net_printf(&thd->net, ER_TOO_LONG_IDENT,udf->name);
+ net_printf(thd, ER_TOO_LONG_IDENT,udf->name);
DBUG_RETURN(1);
}
pthread_mutex_lock(&THR_LOCK_udf);
if ((hash_search(&udf_hash,(byte*) udf->name, udf->name_length)))
{
- net_printf(&thd->net, ER_UDF_EXISTS, udf->name);
+ net_printf(thd, ER_UDF_EXISTS, udf->name);
goto err;
}
if (!(dl = find_udf_dl(udf->dl)))
@@ -384,7 +385,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
{
DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)",
udf->dl,errno,dlerror()));
- net_printf(&thd->net, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror());
+ net_printf(thd, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror());
goto err;
}
new_dl=1;
@@ -394,14 +395,14 @@ int mysql_create_function(THD *thd,udf_func *udf)
if (udf->func == NULL)
{
- net_printf(&thd->net, ER_CANT_FIND_DL_ENTRY, udf->name);
+ net_printf(thd, ER_CANT_FIND_DL_ENTRY, udf->name);
goto err;
}
udf->name=strdup_root(&mem,udf->name);
udf->dl=strdup_root(&mem,udf->dl);
if (!(u_d=add_udf(udf->name,udf->returns,udf->dl,udf->type)))
{
- send_error(&thd->net,0); // End of memory
+ send_error(thd,0); // End of memory
goto err;
}
u_d->dlhandle = dl;
@@ -421,9 +422,9 @@ int mysql_create_function(THD *thd,udf_func *udf)
goto err;
restore_record(table,2); // Get default values for fields
- table->field[0]->store(u_d->name, u_d->name_length);
+ table->field[0]->store(u_d->name, u_d->name_length, default_charset_info);
table->field[1]->store((longlong) u_d->returns);
- table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl));
+ table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), default_charset_info);
if (table->fields >= 4) // If not old func format
table->field[3]->store((longlong) u_d->type);
error = table->file->write_row(table->record[0]);
@@ -431,7 +432,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
close_thread_tables(thd);
if (error)
{
- net_printf(&thd->net, ER_ERROR_ON_WRITE, "func@mysql",error);
+ net_printf(thd, ER_ERROR_ON_WRITE, "func@mysql",error);
del_udf(u_d);
goto err;
}
@@ -454,14 +455,14 @@ int mysql_drop_function(THD *thd,const char *udf_name)
DBUG_ENTER("mysql_drop_function");
if (!initialized)
{
- send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
+ send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES));
DBUG_RETURN(1);
}
pthread_mutex_lock(&THR_LOCK_udf);
if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name,
(uint) strlen(udf_name))))
{
- net_printf(&thd->net, ER_FUNCTION_NOT_DEFINED, udf_name);
+ net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name);
goto err;
}
del_udf(udf);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 9d20a4bd7c9..0e6de306c0d 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -24,108 +24,137 @@
#include "mysql_priv.h"
#include "sql_select.h"
-
-int mysql_union(THD *thd, LEX *lex,select_result *result)
+int mysql_union(THD *thd, LEX *lex, select_result *result)
{
- SELECT_LEX *sl, *last_sl, *lex_sl;
- ORDER *order;
- List<Item> item_list;
- TABLE *table;
- int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0;
- int res;
- bool found_rows_for_union=false;
- TABLE_LIST result_table_list;
- TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first;
- TMP_TABLE_PARAM tmp_table_param;
- select_union *union_result;
DBUG_ENTER("mysql_union");
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ int res= 0;
+ if (!(res= unit->prepare(thd, result)))
+ res= unit->exec();
+ res|= unit->cleanup();
+ DBUG_RETURN(res);
+}
+
+
+/***************************************************************************
+** store records in temporary table for UNION
+***************************************************************************/
+
+select_union::select_union(TABLE *table_par)
+ :table(table_par)
+{
+ bzero((char*) &info,sizeof(info));
+ /*
+ We can always use DUP_IGNORE because the temporary table will only
+ contain a unique key if we are using not using UNION ALL
+ */
+ info.handle_duplicates= DUP_IGNORE;
+}
- /* Fix tables 'to-be-unioned-from' list to point at opened tables */
- last_sl= &lex->select_lex;
- for (sl= last_sl;
- sl && sl->linkage != NOT_A_SELECT;
- last_sl=sl, sl=sl->next)
+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)
{
- for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
- cursor;
- cursor=cursor->next)
- {
- if (cursor->do_redirect) // False if CUBE/ROLLUP
- {
- cursor->table= ((TABLE_LIST*) cursor->table)->table;
- cursor->do_redirect=false;
- }
- }
+ my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
+ ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
+ return -1;
}
+ return 0;
+}
- /* last_sel now points at the last select where the ORDER BY is stored */
- if (sl)
- {
- /*
- The found SL is an extra SELECT_LEX argument that contains
- the ORDER BY and LIMIT parameter for the whole UNION
- */
- lex_sl= sl;
- order= (ORDER *) lex_sl->order_list.first;
- found_rows_for_union = (lex->select_lex.options & OPTION_FOUND_ROWS &&
- !describe && sl->select_limit);
- if (found_rows_for_union)
- lex->select_lex.options ^= OPTION_FOUND_ROWS;
- // This is done to eliminate unnecessary slowing down of the first query
- if (!order || !describe)
- last_sl->next=0; // Remove this extra element
+bool select_union::send_data(List<Item> &values)
+{
+ if (unit->offset_limit_cnt)
+ { // using limit offset,count
+ unit->offset_limit_cnt--;
+ return 0;
}
- else if (!last_sl->braces)
+ fill_record(table->field,values);
+ if ((write_record(table,&info)))
{
- lex_sl= last_sl; // ORDER BY is here
- order= (ORDER *) lex_sl->order_list.first;
+ if (thd->net.last_errno == ER_RECORD_FILE_FULL)
+ {
+ thd->clear_error(); // do not report user about table overflow
+ if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0))
+ return 1;
+ }
+ else
+ return 1;
}
- else
+ return 0;
+}
+
+bool select_union::send_eof()
+{
+ return 0;
+}
+
+bool select_union::flush()
+{
+ int error;
+ if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{
- lex_sl=0;
- order=0;
+ table->file->print_error(error,MYF(0));
+ ::send_error(thd);
+ return 1;
}
-
- if (describe)
+ return 0;
+}
+
+typedef JOIN * JOIN_P;
+int st_select_lex_unit::prepare(THD *thd, select_result *result)
+{
+ DBUG_ENTER("st_select_lex_unit::prepare");
+
+ if (prepared)
+ DBUG_RETURN(0);
+ prepared= 1;
+ union_result=0;
+ res= 0;
+ found_rows_for_union= false;
+ TMP_TABLE_PARAM tmp_table_param;
+ this->thd= thd;
+ this->result= result;
+ SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
+ SELECT_LEX *sl;
+
+ /* Global option */
+ if (((void*)(global_parameters)) == ((void*)this))
{
- Item *item;
- item_list.push_back(new Item_empty_string("table",NAME_LEN));
- item_list.push_back(new Item_empty_string("type",10));
- item_list.push_back(item=new Item_empty_string("possible_keys",
- NAME_LEN*MAX_KEY));
- item->maybe_null=1;
- item_list.push_back(item=new Item_empty_string("key",NAME_LEN));
- item->maybe_null=1;
- item_list.push_back(item=new Item_int("key_len",0,3));
- item->maybe_null=1;
- item_list.push_back(item=new Item_empty_string("ref",
- NAME_LEN*MAX_REF_PARTS));
- item->maybe_null=1;
- item_list.push_back(new Item_real("rows",0.0,0,10));
- item_list.push_back(new Item_empty_string("Extra",255));
+ found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS &&
+ global_parameters->select_limit;
+ if (found_rows_for_union)
+ first_select()->options ^= OPTION_FOUND_ROWS;
}
- else
+ item_list.empty();
{
Item *item;
- List_iterator<Item> it(lex->select_lex.item_list);
- TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.table_list.first;
+ List_iterator<Item> it(first_select()->item_list);
+ TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first;
/* Create a list of items that will be in the result set */
while ((item= it++))
if (item_list.push_back(item))
- DBUG_RETURN(-1);
+ goto err;
if (setup_fields(thd,first_table,item_list,0,0,1))
- DBUG_RETURN(-1);
+ goto err;
}
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, !describe & !lex->union_option,
- 1, 0,
- (lex->select_lex.options | thd->options |
- TMP_TABLE_ALL_COLUMNS))))
- DBUG_RETURN(-1);
+ 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)))
+ goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
bzero((char*) &result_table_list,sizeof(result_table_list));
@@ -134,43 +163,97 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
result_table_list.table=table;
if (!(union_result=new select_union(table)))
- {
- res= -1;
- goto exit;
- }
- union_result->save_time_stamp=!describe;
+ goto err;
+
+ union_result->save_time_stamp=1;
union_result->tmp_table_param=&tmp_table_param;
- for (sl= &lex->select_lex; sl; sl=sl->next)
+
+ // prepare selects
+ joins.empty();
+ for (sl= first_select(); sl; sl= sl->next_select())
{
- lex->select=sl;
- thd->offset_limit=sl->offset_limit;
- thd->select_limit=sl->select_limit+sl->offset_limit;
- if (thd->select_limit < sl->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
+ JOIN *join= new JOIN(thd, sl->item_list,
+ sl->options | thd->options | SELECT_NO_UNLOCK,
+ union_result);
+ joins.push_back(new JOIN_P(join));
+ thd->lex.current_select= sl;
+ offset_limit_cnt= sl->offset_limit;
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ if (select_limit_cnt < sl->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
+ if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
- res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first,
- sl->item_list,
- sl->where,
- (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0,
- (ORDER*) sl->group_list.first,
- sl->having,
- (ORDER*) NULL,
- sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
- union_result);
- if (res)
- goto exit;
+ res= join->prepare((TABLE_LIST*) sl->table_list.first,
+ sl->where,
+ (sl->braces) ?
+ (ORDER *)sl->order_list.first : (ORDER *) 0,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (ORDER*) NULL,
+ sl, this, 0);
+ if (res | thd->fatal_error)
+ goto err;
}
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(res | thd->fatal_error);
+err:
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(-1);
+}
+
+int st_select_lex_unit::exec()
+{
+ DBUG_ENTER("st_select_lex_unit::exec");
+ SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
+
+ if (executed && !dependent)
+ DBUG_RETURN(0);
+ executed= 1;
+
+ if (dependent || !item || !item->assigned())
+ {
+ if (optimized && item && item->assigned())
+ item->assigned(0); // We will reinit & rexecute unit
+ for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+ {
+ thd->lex.current_select= sl;
+ offset_limit_cnt= sl->offset_limit;
+ select_limit_cnt= sl->select_limit+sl->offset_limit;
+ if (select_limit_cnt < sl->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
+ if (select_limit_cnt == HA_POS_ERROR)
+ sl->options&= ~OPTION_FOUND_ROWS;
+
+ if (!optimized)
+ res= sl->join->optimize();
+ else
+ res= sl->join->reinit();
+
+ if (!res)
+ {
+ sl->join->exec();
+ res= sl->join->error;
+ }
+ if (res)
+ {
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(res);
+ }
+ }
+ optimized= 1;
+ }
+
if (union_result->flush())
{
- res= 1; // Error is already sent
- goto exit;
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(1);
}
- delete union_result;
/* Send result to 'result' */
- lex->select = &lex->select_lex;
+
+ // to correct ORDER BY reference resolving
+ thd->lex.current_select = first_select();
res =-1;
{
/* Create a list of fields in the temporary table */
@@ -180,7 +263,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
List<Item_func_match> ftfunc_list;
ftfunc_list.empty();
#else
- thd->lex.select_lex.ftfunc_list.empty();
+ List<Item_func_match> empty_list;
+ empty_list.empty();
+ thd->lex.select_lex.ftfunc_list= &empty_list;
#endif
for (field=table->field ; *field ; field++)
@@ -190,98 +275,44 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
}
if (!thd->fatal_error) // Check if EOM
{
- if (lex_sl)
- {
- thd->offset_limit=lex_sl->offset_limit;
- thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit;
- if (thd->select_limit < lex_sl->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
- thd->options&= ~OPTION_FOUND_ROWS;
- }
- else
- {
- thd->offset_limit= 0;
- thd->select_limit= thd->variables.select_limit;
- }
- if (describe)
- thd->select_limit= HA_POS_ERROR; // no limit
- res=mysql_select(thd,&result_table_list,
- item_list, NULL, (describe) ? 0 : order,
- (ORDER*) NULL, NULL, (ORDER*) NULL,
- thd->options, result);
+ offset_limit_cnt= global_parameters->offset_limit;
+ select_limit_cnt= global_parameters->select_limit+
+ global_parameters->offset_limit;
+ if (select_limit_cnt < global_parameters->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
+ if (select_limit_cnt == HA_POS_ERROR)
+ thd->options&= ~OPTION_FOUND_ROWS;
+ res= mysql_select(thd,&result_table_list,
+ item_list, NULL,
+ (ORDER*)global_parameters->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ thd->options, result, this, first_select(), 1);
if (found_rows_for_union && !res)
thd->limit_found_rows = (ulonglong)table->file->records;
}
}
-
-exit:
- free_tmp_table(thd,table);
+ thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc;
+ thd->lex.current_select= lex_select_save;
DBUG_RETURN(res);
}
-
-/***************************************************************************
-** store records in temporary table for UNION
-***************************************************************************/
-
-select_union::select_union(TABLE *table_par)
- :table(table_par)
-{
- bzero((char*) &info,sizeof(info));
- /*
- We can always use DUP_IGNORE because the temporary table will only
- contain a unique key if we are using not using UNION ALL
- */
- info.handle_duplicates=DUP_IGNORE;
-}
-
-select_union::~select_union()
-{
-}
-
-
-int select_union::prepare(List<Item> &list)
+int st_select_lex_unit::cleanup()
{
- if (save_time_stamp && list.elements != table->fields)
+ DBUG_ENTER("st_select_lex_unit::cleanup");
+ if (union_result)
{
- my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
- ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0));
- return -1;
+ delete union_result;
+ free_tmp_table(thd,table);
+ table= 0; // Safety
}
- return 0;
-}
-
-bool select_union::send_data(List<Item> &values)
-{
- if (thd->offset_limit)
- { // using limit offset,count
- thd->offset_limit--;
- return 0;
- }
-
- fill_record(table->field,values);
- if ((write_record(table,&info)))
+ List_iterator<JOIN*> j(joins);
+ JOIN** join;
+ while ((join= j++))
{
- if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0))
- return 1;
- }
- return 0;
-}
-
-bool select_union::send_eof()
-{
- return 0;
-}
-
-bool select_union::flush()
-{
- int error;
- if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
- {
- table->file->print_error(error,MYF(0));
- ::send_error(&thd->net);
- return 1;
+ (*join)->cleanup(thd);
+ delete *join;
+ delete join;
}
- return 0;
+ joins.empty();
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index b5263322301..73343ab1a50 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -77,7 +77,7 @@ int mysql_update(THD *thd,
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))
+ || setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(-1); /* purecov: inspected */
old_used_keys=table->used_keys; // Keys used in WHERE
@@ -124,7 +124,7 @@ int mysql_update(THD *thd,
{
DBUG_RETURN(-1); // Error in where
}
- send_ok(&thd->net); // No matching records
+ send_ok(thd); // No matching records
DBUG_RETURN(0);
}
/* If running in safe sql mode, don't allow updates without keys */
@@ -135,11 +135,11 @@ int mysql_update(THD *thd,
{
delete select;
table->time_stamp=save_time_stamp;
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
}
- init_ftfuncs(thd,1);
+ init_ftfuncs(thd, &thd->lex.select_lex, 1);
/* Check if we are modifying a key that we are used to search with */
if (select && select->quick)
used_key_is_modified= (!select->quick->unique_key_range() &&
@@ -187,8 +187,8 @@ int mysql_update(THD *thd,
MYF(MY_FAE | MY_ZEROFILL));
if (setup_order(thd, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
- (table->found_records = filesort(table, sortorder, length,
- (SQL_SELECT *) 0, 0L,
+ (table->found_records = filesort(thd, table, sortorder, length,
+ (SQL_SELECT *) 0,
HA_POS_ERROR, &examined_rows))
== HA_POS_ERROR)
{
@@ -337,13 +337,13 @@ int mysql_update(THD *thd,
delete select;
if (error >= 0)
- send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
+ send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
else
{
char buff[80];
sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated,
(long) thd->cuted_fields);
- send_ok(&thd->net,
+ send_ok(thd,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
DBUG_PRINT("info",("%d records updated",updated));
@@ -390,9 +390,10 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
}
int
-multi_update::prepare(List<Item> &values)
+multi_update::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("multi_update::prepare");
+ unit= u;
do_update = true;
thd->count_cuted_fields=1;
thd->cuted_fields=0L;
@@ -448,7 +449,7 @@ multi_update::prepare(List<Item> &values)
}
if (!table_ref)
{
- net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES");
+ net_printf(thd, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES");
DBUG_RETURN(1);
}
else
@@ -456,7 +457,7 @@ multi_update::prepare(List<Item> &values)
}
if (!num_updated--)
{
- net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE");
+ net_printf(thd, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE");
DBUG_RETURN(1);
}
@@ -490,9 +491,11 @@ multi_update::prepare(List<Item> &values)
}
if (counter)
{
- Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true);
+ 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)));
- // Here I make tmp tables
+
+ // Make a temporary table
int cnt=counter-1;
TMP_TABLE_PARAM tmp_table_param;
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
@@ -500,7 +503,8 @@ multi_update::prepare(List<Item> &values)
if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param,
*temp_fields,
(ORDER*) 0, 1, 0, 0,
- TMP_TABLE_ALL_COLUMNS)))
+ TMP_TABLE_ALL_COLUMNS,
+ unit)))
{
error = 1; // A proper error message is due here
DBUG_RETURN(1);
@@ -514,7 +518,7 @@ multi_update::prepare(List<Item> &values)
counter++;
}
}
- init_ftfuncs(thd,1);
+ init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
error = 0; // Timestamps do not need to be restored, so far ...
DBUG_RETURN(0);
}
@@ -648,7 +652,8 @@ bool multi_update::send_data(List<Item> &values)
{
// Here we insert into each temporary table
values_by_table.push_front(new Item_string((char*) table->file->ref,
- table->file->ref_length));
+ 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]));
@@ -665,8 +670,10 @@ bool multi_update::send_data(List<Item> &values)
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->net,errcode,err);
+ ::send_error(thd,errcode,err);
/* reset used flags */
// update_tables->table->no_keyread=0;
@@ -788,6 +795,7 @@ bool multi_update::send_eof()
if (local_error == -1)
local_error= 0;
thd->proc_info= "end";
+ // TODO: Error should be sent at the query processing end
if (local_error)
send_error(local_error, "An error occured in multi-table update");
@@ -826,7 +834,7 @@ bool multi_update::send_eof()
{
query_cache_invalidate3(thd, update_tables, 1);
}
- ::send_ok(&thd->net,
+ ::send_ok(thd,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
thd->insert_id_used ? thd->insert_id() : 0L,buff);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f6a0c483bb9..a994a2539f7 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -21,11 +21,12 @@
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
#define Lex current_lex
-#define Select Lex->select
+#define Select Lex->current_select
#include "mysql_priv.h"
#include "slave.h"
#include "sql_acl.h"
#include "lex_symbol.h"
+#include "item_create.h"
#include <myisam.h>
#include <myisammrg.h>
@@ -60,12 +61,14 @@ inline Item *or_or_concat(Item* A, Item* B)
LEX_USER *lex_user;
sys_var *variable;
Key::Keytype key_type;
+ enum ha_key_alg key_alg;
enum db_type db_type;
enum row_type row_type;
enum ha_rkey_function ha_rkey_mode;
enum enum_tx_isolation tx_isolation;
enum Item_cast cast_type;
enum Item_udftype udf_type;
+ CHARSET_INFO *charset;
thr_lock_type lock_type;
interval_type interval;
}
@@ -84,6 +87,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
@@ -92,6 +96,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
@@ -113,6 +118,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
@@ -163,13 +169,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BOOL_SYM
%token BOOLEAN_SYM
%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 COMMITTED_SYM
+%token COLLATE_SYM
%token COLUMNS
%token COLUMN_SYM
%token CONCURRENT
@@ -193,6 +203,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
@@ -207,6 +218,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token GREATEST_SYM
%token GROUP
%token HAVING
+%token HASH_SYM
%token HEAP_SYM
%token HEX_NUM
%token HIGH_PRIORITY
@@ -302,11 +314,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ROWS_SYM
%token ROW_FORMAT_SYM
%token ROW_SYM
+%token RTREE_SYM
%token SET
+%token SERIAL_SYM
%token SERIALIZABLE_SYM
%token SESSION_SYM
+%token SIMPLE_SYM
%token SHUTDOWN
-%token SSL_SYM
+%token SPATIAL_SYM
+%token SSL_SYM
%token STARTING
%token STATUS_SYM
%token STRAIGHT_JOIN
@@ -319,7 +335,9 @@ 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
%token FUNC_ARG1
%token FUNC_ARG2
@@ -328,21 +346,26 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token UDF_SONAME_SYM
%token UDF_SYM
%token UNCOMMITTED_SYM
+%token UNDERSCORE_CHARSET
%token UNION_SYM
%token UNIQUE_SYM
%token USAGE
%token USE_FRM
%token USE_SYM
%token USING
+%token VALUE_SYM
%token VALUES
%token VARIABLES
%token WHERE
%token WITH
%token WRITE_SYM
%token X509_SYM
-%token XOR
+%token XOR
%token COMPRESSED_SYM
+%token ERRORS
+%token WARNINGS
+
%token BIGINT
%token BLOB_SYM
%token CHAR_SYM
@@ -355,6 +378,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ENUM
%token FAST_SYM
%token FLOAT_SYM
+%token GEOMETRY_SYM
%token INT_SYM
%token LIMIT
%token LONGBLOB
@@ -412,6 +436,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FORMAT_SYM
%token FOR_SYM
%token FROM_UNIXTIME
+%token GEOMCOLLFROMTEXT
+%token GEOMFROMTEXT
+%token GEOMETRYCOLLECTION
%token GROUP_UNIQUE_USERS
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
@@ -422,6 +449,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token INTERVAL_SYM
%token LAST_INSERT_ID
%token LEFT
+%token LINEFROMTEXT
+%token LINESTRING
%token LOCATE
%token MAKE_SET_SYM
%token MINUTE_SECOND_SYM
@@ -429,8 +458,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MODE_SYM
%token MODIFY_SYM
%token MONTH_SYM
+%token MLINEFROMTEXT
+%token MPOINTFROMTEXT
+%token MPOLYFROMTEXT
+%token MULTILINESTRING
+%token MULTIPOINT
+%token MULTIPOLYGON
%token NOW_SYM
%token PASSWORD
+%token POINTFROMTEXT
+%token POLYFROMTEXT
+%token POLYGON
%token POSITION_SYM
%token PROCEDURE
%token RAND
@@ -472,6 +510,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SUBJECT_SYM
%token CIPHER_SYM
+%token HELP
+
%left SET_VAR
%left OR_OR_CONCAT OR
%left AND
@@ -481,13 +521,12 @@ 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 '^'
%right NOT
-%right BINARY
-
+%right BINARY COLLATE_SYM
/* These don't actually affect the way the query is really evaluated, but
they silence a few warnings for shift/reduce conflicts. */
%left ','
@@ -496,16 +535,16 @@ 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
+ ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET
%type <lex_str_ptr>
opt_table_alias
%type <table>
- table_ident
+ 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>
@@ -515,7 +554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
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
- opt_temporary
+ delete_option opt_temporary
%type <ulong_num>
ULONG_NUM raid_types merge_insert_types
@@ -531,6 +570,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
using_list expr_or_default set_expr_or_default
+ param_marker singleval_subselect singleval_subselect_init
+ exists_subselect exists_subselect_init
%type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg
@@ -538,6 +579,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <key_type>
key_type opt_unique_or_fulltext
+%type <key_alg>
+ key_alg opt_btree_or_rtree
+
%type <string_list>
key_usage_list
@@ -545,7 +589,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
key_part
%type <table_list>
- join_table_list join_table
+ join_table_list join_table
%type <udf>
UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC
@@ -569,6 +613,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_user> user grant_user
+%type <charset>
+ charset_name
+ charset_name_or_default
+ opt_db_default_character_set
+
%type <variable> internal_variable_name
%type <NONE>
@@ -585,7 +634,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
opt_precision opt_ignore opt_column opt_restrict
grant revoke set lock unlock string_list field_options field_option
field_opt_list opt_binary table_lock_list table_lock varchar
- references opt_on_delete opt_on_delete_list opt_on_delete_item use
+ 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_attribute opt_attribute_list attribute column_list column_list_id
@@ -596,13 +645,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
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 opt_union union_list
- precision union_option opt_and
+ single_multi table_wild_list table_wild_one opt_wild
+ union opt_union union_list union_option
+ precision opt_on_delete_item 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
%%
@@ -613,7 +665,7 @@ query:
if (!thd->bootstrap &&
(!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
{
- send_error(&current_thd->net,ER_EMPTY_QUERY);
+ send_error(current_thd,ER_EMPTY_QUERY);
YYABORT;
}
else
@@ -659,7 +711,18 @@ verb_clause:
| handler
| unlock
| update
- | use;
+ | use
+ | help;
+
+/* help */
+
+help:
+ HELP TEXT_STRING
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_HELP;
+ lex->help_arg= $2.str;
+ };
/* change master */
@@ -719,7 +782,8 @@ master_def:
RELAY_LOG_POS_SYM EQ ULONG_NUM
{
Lex->mi.relay_log_pos = $3;
- };
+ }
+ ;
/* create a table */
@@ -727,11 +791,14 @@ master_def:
create:
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
{
+ THD *thd=current_thd;
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_TABLE;
- if (!add_table_to_list($5,
- ($2 & HA_LEX_CREATE_TMP_TABLE ?
- &tmp_table_alias : (LEX_STRING*) 0),1))
+ if (!lex->select_lex.add_table_to_list($5,
+ ($2 &
+ HA_LEX_CREATE_TMP_TABLE ?
+ &tmp_table_alias :
+ (LEX_STRING*) 0),1))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
@@ -740,32 +807,35 @@ create:
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.options=$2 | $4;
lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type;
+ lex->create_info.table_charset=thd->db_charset?thd->db_charset:default_charset_info;
}
create2
- | CREATE opt_unique_or_fulltext INDEX ident ON table_ident
+ | CREATE opt_unique_or_fulltext INDEX ident key_alg ON table_ident
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_INDEX;
- if (!add_table_to_list($6,NULL,1))
+ if (!lex->current_select->add_table_to_list($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;
- lex->key_list.push_back(new Key($2,$4.str,lex->col_list));
+
+ lex->key_list.push_back(new Key($2,$4.str, $5, lex->col_list));
lex->col_list.empty();
}
- | CREATE DATABASE opt_if_not_exists ident
+ | CREATE DATABASE opt_if_not_exists ident opt_db_default_character_set
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CREATE_DB;
lex->name=$4.str;
lex->create_info.options=$3;
+ lex->create_info.table_charset=$5;
}
| CREATE udf_func_type UDF_SYM ident
{
@@ -780,11 +850,13 @@ create:
LEX *lex=Lex;
lex->udf.returns=(Item_result) $7;
lex->udf.dl=$9.str;
- };
+ }
+ ;
create2:
'(' field_list ')' opt_create_table_options create3 {}
- | opt_create_table_options create3 {};
+ | opt_create_table_options create3 {}
+ ;
create3:
/* empty */ {}
@@ -794,7 +866,8 @@ 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 opt_union {};
+ select_options select_item_list opt_select_from union {}
+ ;
opt_as:
/* empty */ {}
@@ -819,42 +892,61 @@ opt_create_table_options:
/* empty */
| create_table_options;
+create_table_options_space_separated:
+ create_table_option
+ | create_table_option 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 EQ table_types { Lex->create_info.db_type= $3; }
- | MAX_ROWS EQ ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
- | MIN_ROWS EQ ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
- | AVG_ROW_LENGTH EQ ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
- | PASSWORD EQ TEXT_STRING { Lex->create_info.password=$3.str; }
- | COMMENT_SYM EQ TEXT_STRING { Lex->create_info.comment=$3.str; }
- | AUTO_INC EQ ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
- | PACK_KEYS_SYM 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 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 EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; }
- | DELAY_KEY_WRITE_SYM EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; }
- | ROW_FORMAT_SYM EQ row_types { Lex->create_info.row_type= $3; }
- | RAID_TYPE EQ raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKS EQ ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | RAID_CHUNKSIZE EQ ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
- | UNION_SYM EQ '(' table_list ')'
+ 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 ')'
{
/* Move the union list to the merge_list */
LEX *lex=Lex;
- TABLE_LIST *table_list= (TABLE_LIST*) lex->select->table_list.first;
- lex->create_info.merge_list= lex->select->table_list;
+ TABLE_LIST *table_list= lex->select_lex.get_table_list();
+ lex->create_info.merge_list= lex->select_lex.table_list;
lex->create_info.merge_list.elements--;
lex->create_info.merge_list.first= (byte*) (table_list->next);
- lex->select->table_list.elements=1;
- lex->select->table_list.next= (byte**) &(table_list->next);
+ lex->select_lex.table_list.elements=1;
+ lex->select_lex.table_list.next= (byte**) &(table_list->next);
table_list->next=0;
lex->create_info.used_fields|= HA_CREATE_USED_UNION;
}
- | INSERT_METHOD 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 EQ TEXT_STRING { Lex->create_info.data_file_name= $4.str; }
- | INDEX DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.index_file_name= $4.str; };
+ | opt_default CHARSET o_eq 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
+ {
+ 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; };
table_types:
ISAM_SYM { $$= DB_TYPE_ISAM; }
@@ -904,15 +996,22 @@ field_list_item:
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
}
- | key_type opt_ident '(' key_list ')'
+ | key_type opt_ident key_alg '(' key_list ')'
{
LEX *lex=Lex;
- lex->key_list.push_back(new Key($1,$2,lex->col_list));
+ lex->key_list.push_back(new Key($1,$2, $3, lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
{
- Lex->col_list.empty(); /* Alloced by sql_alloc */
+ LEX *lex=Lex;
+ lex->key_list.push_back(new foreign_key($4, lex->col_list,
+ $8,
+ lex->ref_list,
+ lex->fk_delete_opt,
+ lex->fk_update_opt,
+ lex->fk_match_option));
+ lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint CHECK_SYM '(' expr ')'
{
@@ -928,7 +1027,8 @@ field_spec:
{
LEX *lex=Lex;
lex->length=lex->dec=0; lex->type=0; lex->interval=0;
- lex->default_value=0;
+ lex->default_value=lex->comment=0;
+ lex->charset=NULL;
}
type opt_attribute
{
@@ -936,69 +1036,81 @@ field_spec:
if (add_field_to_list($1.str,
(enum enum_field_types) $3,
lex->length,lex->dec,lex->type,
- lex->default_value,lex->change,
- lex->interval))
+ lex->default_value, lex->comment,
+ lex->change,lex->interval,lex->charset))
YYABORT;
};
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";
$$=FIELD_TYPE_TINY; }
| BOOL_SYM { Lex->length=(char*) "1";
$$=FIELD_TYPE_TINY; }
- | char '(' NUM ')' opt_binary { Lex->length=$3.str;
+ | char '(' NUM ')' opt_binary { Lex->length=$3.str;
$$=FIELD_TYPE_STRING; }
| char opt_binary { Lex->length=(char*) "1";
$$=FIELD_TYPE_STRING; }
| BINARY '(' NUM ')' { Lex->length=$3.str;
- Lex->type|=BINARY_FLAG;
+ Lex->charset=my_charset_bin;
$$=FIELD_TYPE_STRING; }
| varchar '(' NUM ')' opt_binary { Lex->length=$3.str;
$$=FIELD_TYPE_VAR_STRING; }
| VARBINARY '(' NUM ')' { Lex->length=$3.str;
- Lex->type|=BINARY_FLAG;
+ 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 (current_thd->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->type|=BINARY_FLAG;
+ | TINYBLOB { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_TINY_BLOB; }
- | BLOB_SYM { Lex->type|=BINARY_FLAG;
+ | BLOB_SYM opt_len { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_BLOB; }
- | MEDIUMBLOB { Lex->type|=BINARY_FLAG;
+ | GEOMETRY_SYM { Lex->charset=my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | MEDIUMBLOB { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_MEDIUM_BLOB; }
- | LONGBLOB { Lex->type|=BINARY_FLAG;
+ | LONGBLOB { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_LONG_BLOB; }
- | LONG_SYM VARBINARY { Lex->type|=BINARY_FLAG;
+ | LONG_SYM VARBINARY { Lex->charset=my_charset_bin;
$$=FIELD_TYPE_MEDIUM_BLOB; }
- | LONG_SYM varchar { $$=FIELD_TYPE_MEDIUM_BLOB; }
- | TINYTEXT { $$=FIELD_TYPE_TINY_BLOB; }
- | TEXT_SYM { $$=FIELD_TYPE_BLOB; }
- | MEDIUMTEXT { $$=FIELD_TYPE_MEDIUM_BLOB; }
- | LONGTEXT { $$=FIELD_TYPE_LONG_BLOB; }
+ | LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
+ | TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_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;}
- | ENUM {Lex->interval_list.empty();} '(' string_list ')'
+ | FIXED_SYM float_options field_options
+ { $$=FIELD_TYPE_DECIMAL;}
+ | ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
{
LEX *lex=Lex;
lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_ENUM;
}
- | SET { Lex->interval_list.empty();} '(' string_list ')'
+ | SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary
{
LEX *lex=Lex;
lex->interval=typelib(lex->interval_list);
$$=FIELD_TYPE_SET;
- };
+ }
+ | LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
+ ;
char:
CHAR_SYM {}
@@ -1051,8 +1163,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 */ {}
@@ -1071,21 +1183,70 @@ 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; }
+ | SERIAL_SYM DEFAULT VALUE_SYM
+ { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
| PRIMARY_SYM 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 {};
+ | COMMENT_SYM text_literal { Lex->comment= $2; };
-opt_binary:
+charset_name:
+ BINARY
+ {
+ if (!($$=get_charset_by_name("binary",MYF(0))))
+ {
+ net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,"binary");
+ YYABORT;
+ }
+ }
+ | ident
+ {
+ if (!($$=get_charset_by_name($1.str,MYF(0))))
+ {
+ net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ YYABORT;
+ }
+ };
+
+charset_name_or_default:
+ charset_name { $$=$1; }
+ | DEFAULT { $$=NULL; } ;
+
+opt_default:
/* empty */ {}
- | BINARY { Lex->type|=BINARY_FLAG; };
+ | DEFAULT {};
+
+opt_db_default_character_set:
+ /* empty */ { $$=default_charset_info; }
+ | opt_default CHAR_SYM SET charset_name_or_default { $$=$4; }
+ | opt_default CHARSET charset_name_or_default { $$=$3; };
+
+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; } ;
references:
- REFERENCES table_ident opt_on_delete {}
- | REFERENCES table_ident '(' key_list ')' opt_on_delete
- {
- Lex->col_list.empty(); /* Alloced by sql_alloc */
- };
+ REFERENCES table_ident
+ {
+ LEX *lex=Lex;
+ lex->fk_delete_opt= lex->fk_update_opt= lex->fk_match_option= 0;
+ lex->ref_list.empty();
+ }
+ opt_ref_list
+ {
+ $$=$2;
+ };
+
+opt_ref_list:
+ /* empty */ opt_on_delete {}
+ | '(' ref_list ')' opt_on_delete {};
+
+ref_list:
+ ref_list ',' ident { Lex->ref_list.push_back(new key_part_spec($3.str)); }
+ | ident { Lex->ref_list.push_back(new key_part_spec($1.str)); };
+
opt_on_delete:
/* empty */ {}
@@ -1095,25 +1256,27 @@ opt_on_delete_list:
opt_on_delete_list opt_on_delete_item {}
| opt_on_delete_item {};
-
opt_on_delete_item:
- ON DELETE_SYM delete_option {}
- | ON UPDATE_SYM delete_option {}
- | MATCH FULL {}
- | MATCH PARTIAL {};
+ ON DELETE_SYM delete_option { Lex->fk_delete_opt= $3; }
+ | ON UPDATE_SYM delete_option { Lex->fk_update_opt= $3; }
+ | MATCH FULL { Lex->fk_match_option= foreign_key::FK_MATCH_FULL; }
+ | MATCH PARTIAL { Lex->fk_match_option= foreign_key::FK_MATCH_PARTIAL; }
+ | MATCH SIMPLE_SYM { Lex->fk_match_option= foreign_key::FK_MATCH_SIMPLE; };
delete_option:
- RESTRICT {}
- | CASCADE {}
- | SET NULL_SYM {}
- | NO_SYM ACTION {}
- | SET DEFAULT {};
+ RESTRICT { $$= (int) foreign_key::FK_OPTION_RESTRICT; }
+ | CASCADE { $$= (int) foreign_key::FK_OPTION_CASCADE; }
+ | SET NULL_SYM { $$= (int) foreign_key::FK_OPTION_SET_NULL; }
+ | NO_SYM ACTION { $$= (int) foreign_key::FK_OPTION_NO_ACTION; }
+ | SET DEFAULT { $$= (int) foreign_key::FK_OPTION_DEFAULT; };
key_type:
opt_constraint PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; }
| key_or_index { $$= Key::MULTIPLE; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
| FULLTEXT_SYM key_or_index { $$= Key::FULLTEXT; }
+ | SPATIAL_SYM { $$= Key::SPATIAL; }
+ | SPATIAL_SYM key_or_index { $$= Key::SPATIAL; }
| opt_constraint UNIQUE_SYM { $$= Key::UNIQUE; }
| opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; };
@@ -1129,7 +1292,16 @@ keys_or_index:
opt_unique_or_fulltext:
/* empty */ { $$= Key::MULTIPLE; }
| UNIQUE_SYM { $$= Key::UNIQUE; }
- | FULLTEXT_SYM { $$= Key::FULLTEXT; };
+ | SPATIAL_SYM { $$= Key::SPATIAL; };
+
+key_alg:
+ /* empty */ { $$= HA_KEY_ALG_UNDEF; }
+ | USING opt_btree_or_rtree { $$= $2; };
+
+opt_btree_or_rtree:
+ BTREE_SYM { $$= HA_KEY_ALG_BTREE; }
+ | RTREE_SYM { $$= HA_KEY_ALG_RTREE; }
+ | HASH_SYM { $$= HA_KEY_ALG_HASH; };
key_list:
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
@@ -1154,10 +1326,11 @@ string_list:
alter:
ALTER opt_ignore TABLE_SYM table_ident
{
- LEX *lex=Lex;
+ THD *thd=current_thd;
+ LEX *lex=&thd->lex;
lex->sql_command = SQLCOM_ALTER_TABLE;
lex->name=0;
- if (!add_table_to_list($4, NULL,1))
+ if (!lex->select_lex.add_table_to_list($4, NULL,1))
YYABORT;
lex->drop_primary=0;
lex->create_list.empty();
@@ -1165,18 +1338,26 @@ alter:
lex->col_list.empty();
lex->drop_list.empty();
lex->alter_list.empty();
- lex->select->order_list.elements=0;
- lex->select->order_list.first=0;
- lex->select->order_list.next= (byte**) &lex->select->order_list.first;
- lex->select->db=lex->name=0;
+ lex->select_lex.init_order();
+ lex->select_lex.db=lex->name=0;
bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.db_type= DB_TYPE_DEFAULT;
+ lex->create_info.table_charset=thd->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 DATABASE ident opt_db_default_character_set
+ {
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_ALTER_DB;
+ lex->name=$3.str;
+ lex->create_info.table_charset=$4;
+ };
+
+
alter_list:
| alter_list_item
| alter_list ',' alter_list_item;
@@ -1193,24 +1374,24 @@ alter_list_item:
lex->change= $3.str; lex->simple_alter=0;
}
field_spec opt_place
- | MODIFY_SYM opt_column field_ident
- {
- LEX *lex=Lex;
- lex->length=lex->dec=0; lex->type=0; lex->interval=0;
- lex->default_value=0;
+ | MODIFY_SYM opt_column field_ident
+ {
+ LEX *lex=Lex;
+ lex->length=lex->dec=0; lex->type=0; lex->interval=0;
+ lex->default_value=lex->comment=0;
lex->simple_alter=0;
- }
- type opt_attribute
- {
- LEX *lex=Lex;
- if (add_field_to_list($3.str,
- (enum enum_field_types) $5,
- lex->length,lex->dec,lex->type,
- lex->default_value, $3.str,
- lex->interval))
- YYABORT;
- }
- opt_place
+ }
+ type opt_attribute
+ {
+ LEX *lex=Lex;
+ if (add_field_to_list($3.str,
+ (enum enum_field_types) $5,
+ lex->length,lex->dec,lex->type,
+ lex->default_value, lex->comment,
+ $3.str, lex->interval, lex->charset))
+ YYABORT;
+ }
+ opt_place
| DROP opt_column field_ident opt_restrict
{
LEX *lex=Lex;
@@ -1247,10 +1428,10 @@ alter_list_item:
| RENAME opt_to table_ident
{
LEX *lex=Lex;
- lex->select->db=$3->db.str;
+ lex->select_lex.db=$3->db.str;
lex->name= $3->table.str;
}
- | create_table_options { Lex->simple_alter=0; }
+ | create_table_options_space_separated { Lex->simple_alter=0; }
| order_clause { Lex->simple_alter=0; };
opt_column:
@@ -1278,36 +1459,23 @@ opt_to:
| AS {};
/*
- * The first two deprecate the last two--delete the last two for 4.1 release
- */
+ 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;
- }
- |
- SLAVE START_SYM slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_START;
- lex->type = 0;
- }
- |
- SLAVE STOP_SYM slave_thread_opts
- {
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SLAVE_STOP;
- lex->type = 0;
- };
+ {
+ 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
@@ -1416,9 +1584,11 @@ table_to_table_list:
table_to_table:
table_ident TO_SYM table_ident
- { if (!add_table_to_list($1,NULL,1,TL_IGNORE) ||
- !add_table_to_list($3,NULL,1,TL_IGNORE))
- YYABORT;
+ {
+ 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))
+ YYABORT;
};
/*
@@ -1430,10 +1600,30 @@ select:
select_init { Lex->sql_command=SQLCOM_SELECT; };
select_init:
- SELECT_SYM select_part2 { Select->braces=false; } opt_union
+ 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_part2 ')' { Select->braces=true;} union_opt;
-
+ '(' SELECT_SYM select_part2 ')'
+ {
+ LEX *lex= Lex;
+ SELECT_LEX_NODE * sel= lex->current_select;
+ if (sel->set_braces(true))
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ /* select in braces, can't contain global parameters */
+ sel->master_unit()->global_parameters=
+ sel->master_unit();
+ } union_opt;
select_part2:
{
@@ -1446,6 +1636,8 @@ select_part2:
select_into:
limit_clause {}
| select_from
+ | FROM DUAL_SYM
+ | opt_into
| opt_into select_from
| select_from opt_into;
@@ -1552,8 +1744,8 @@ optional_braces:
| '(' ')' {};
/* all possible expressions */
-expr: expr_expr {$$ = $1; }
- | simple_expr {$$ = $1; };
+expr: expr_expr { $$= $1; }
+ | simple_expr { $$= $1; };
/* expressions that begin with 'expr' */
expr_expr:
@@ -1588,6 +1780,8 @@ expr_expr:
| 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_and($1,$3); }
@@ -1595,7 +1789,9 @@ expr_expr:
| expr '+' INTERVAL_SYM expr interval
{ $$= new Item_date_add_interval($1,$4,$5,0); }
| expr '-' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,1); };
+ { $$= new Item_date_add_interval($1,$4,$5,1); }
+ | expr COLLATE_SYM charset_name
+ { $$= new Item_func_set_collation($1,$3); };
/* expressions that begin with 'expr' that do NOT follow IN_SYM */
no_in_expr:
@@ -1626,10 +1822,12 @@ no_in_expr:
| 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
@@ -1668,10 +1866,12 @@ no_and_expr:
| 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
@@ -1681,6 +1881,7 @@ no_and_expr:
simple_expr:
simple_ident
| literal
+ | param_marker
| '@' ident_or_text SET_VAR expr
{
$$= new Item_func_set_user_var($2,$4);
@@ -1702,18 +1903,24 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; }
+ | EXISTS exists_subselect { $$= $2; }
+ | singleval_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')'
- { Select->ftfunc_list.push_back((Item_func_match *)
+ { Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_nl(*$2,$5))); }
| MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
- { Select->ftfunc_list.push_back((Item_func_match *)
+ { Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_bool(*$2,$5))); }
- | BINARY expr %prec NEG { $$= new Item_func_binary($2); }
+ | BINARY expr %prec NEG { $$= new Item_func_set_collation($2,my_charset_bin); }
| CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); }
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
| CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast($3, $5); }
+ | CONVERT_SYM '(' expr USING charset_name ')'
+ { $$= new Item_func_conv_charset($3,$5); }
+ | CONVERT_SYM '(' expr ',' expr ',' expr ')'
+ { $$= new Item_func_conv_charset3($3,$7,$5); }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
| FUNC_ARG1 '(' expr ')'
@@ -1728,6 +1935,8 @@ simple_expr:
{ $$= new Item_func_atan($3,$5); }
| CHAR_SYM '(' expr_list ')'
{ $$= new Item_func_char(*$3); }
+ | CHARSET '(' expr ')'
+ { $$= new Item_func_charset($3); }
| COALESCE '(' expr_list ')'
{ $$= new Item_func_coalesce(* $3); }
| CONCAT '(' expr_list ')'
@@ -1780,6 +1989,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 ')'
@@ -1790,6 +2001,14 @@ simple_expr:
}
| FIELD_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_field($3, *$5); }
+ | GEOMFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | GEOMFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | GEOMETRYCOLLECTION '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbGeometryCollection,
+ Geometry::wkbPoint); }
| HOUR_SYM '(' expr ')'
{ $$= new Item_func_hour($3); }
| IF '(' expr ',' expr ',' expr ')'
@@ -1803,9 +2022,8 @@ simple_expr:
{ $$= new Item_func_interval($3,* $5); }
| LAST_INSERT_ID '(' ')'
{
- $$= new Item_int((char*) "last_insert_id()",
- current_thd->insert_id(),21);
- current_thd->safe_to_cache_query=0;
+ $$= get_system_var(OPT_SESSION, "last_insert_id", 14,
+ "last_insert_id()");
}
| LAST_INSERT_ID '(' expr ')'
{
@@ -1814,22 +2032,56 @@ simple_expr:
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
+ | LINESTRING '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbLineString, Geometry::wkbPoint); }
| LOCATE '(' expr ',' expr ')'
{ $$= new Item_func_locate($5,$3); }
| LOCATE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_locate($5,$3,$7); }
- | GREATEST_SYM '(' expr ',' expr_list ')'
+ | GEOMCOLLFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | GEOMCOLLFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | GREATEST_SYM '(' expr ',' expr_list ')'
{ $5->push_front($3); $$= new Item_func_max(*$5); }
| LEAST_SYM '(' expr ',' expr_list ')'
{ $5->push_front($3); $$= new Item_func_min(*$5); }
| LOG_SYM '(' expr ')'
- { $$= new Item_func_log($3); }
+ { $$= new Item_func_log($3); }
| LOG_SYM '(' expr ',' expr ')'
- { $$= new Item_func_log($3, $5); }
+ { $$= new Item_func_log($3, $5); }
+ | LINEFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | LINEFROMTEXT '(' expr ',' 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,
+ Geometry::wkbMultiLineString, Geometry::wkbLineString); }
+ | MLINEFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | MLINEFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | MPOINTFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | MPOINTFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | MPOLYFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | MPOLYFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | MULTIPOINT '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbMultiPoint, Geometry::wkbPoint); }
+ | MULTIPOLYGON '(' expr_list ')'
+ { $$= 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;}
| NOW_SYM '(' expr ')'
@@ -1838,6 +2090,17 @@ simple_expr:
{
$$= new Item_func_password($3);
}
+ | POINTFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | POINTFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | POLYFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | POLYFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3); }
+ | POLYGON '(' expr_list ')'
+ { $$= 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 ')'
@@ -1864,7 +2127,7 @@ simple_expr:
| SUBSTRING_INDEX '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_substr_index($3,$5,$7); }
| TRIM '(' expr ')'
- { $$= new Item_func_trim($3,new Item_string(" ",1)); }
+ { $$= new Item_func_trim($3,new Item_string(" ",1,default_charset_info)); }
| TRIM '(' LEADING opt_pad FROM expr ')'
{ $$= new Item_func_ltrim($6,$4); }
| TRIM '(' TRAILING opt_pad FROM expr ')'
@@ -1875,6 +2138,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)
@@ -1977,10 +2242,17 @@ sum_expr:
{ $$=new Item_sum_sum($3); };
in_sum_expr:
- { Select->in_sum_expr++; }
+ {
+ LEX *lex= Lex;
+ if (lex->current_select->inc_in_sum_expr())
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ }
expr
{
- Select->in_sum_expr--;
+ Select->select_lex()->in_sum_expr--;
$$=$2;
};
@@ -2032,19 +2304,19 @@ when_list:
when_list2:
expr THEN_SYM expr
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX_NODE *sel=Select;
sel->when_list.head()->push_back($1);
sel->when_list.head()->push_back($3);
}
| when_list2 WHEN_SYM expr THEN_SYM expr
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX_NODE *sel=Select;
sel->when_list.head()->push_back($3);
sel->when_list.head()->push_back($5);
};
opt_pad:
- /* empty */ { $$=new Item_string(" ",1); }
+ /* empty */ { $$=new Item_string(" ",1,default_charset_info); }
| expr { $$=$1; };
join_table_list:
@@ -2057,7 +2329,7 @@ join_table_list:
{ add_join_on($4,$6); $$=$4; }
| join_table_list INNER_SYM JOIN_SYM join_table_list
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$4->db; sel->table2=$4->alias;
}
@@ -2067,7 +2339,7 @@ join_table_list:
{ add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; }
| join_table_list LEFT opt_outer JOIN_SYM join_table_list
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$5->db; sel->table2=$5->alias;
}
@@ -2079,7 +2351,7 @@ join_table_list:
{ add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; }
| join_table_list RIGHT opt_outer JOIN_SYM join_table_list
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$5->db; sel->table2=$5->alias;
}
@@ -2097,18 +2369,44 @@ normal_join:
join_table:
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->use_index_ptr=sel->ignore_index_ptr=0;
}
table_ident opt_table_alias opt_key_definition
{
- SELECT_LEX *sel=Select;
- if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, sel->use_index_ptr,
- sel->ignore_index_ptr)))
+ SELECT_LEX_NODE *sel=Select;
+ if (!($$= sel->add_table_to_list($2, $3, 0, TL_UNLOCK,
+ 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; };
+ { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+ | '(' SELECT_SYM select_part3 ')' 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)))
+ YYABORT;
+ };
+
+select_part3:
+ {
+ LEX *lex= Lex;
+ lex->derived_tables= true;
+ 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;
opt_outer:
/* empty */ {}
@@ -2118,39 +2416,49 @@ opt_key_definition:
/* empty */ {}
| USE_SYM key_usage_list
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->use_index= *$2;
sel->use_index_ptr= &sel->use_index;
}
| IGNORE_SYM key_usage_list
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->ignore_index= *$2;
sel->ignore_index_ptr= &sel->ignore_index;
};
key_usage_list:
- key_or_index { Select->interval_list.empty(); } '(' key_usage_list2 ')'
- { $$= &Select->interval_list; };
+ key_or_index { Select->select_lex()->interval_list.empty(); }
+ '(' key_usage_list2 ')'
+ { $$= &Select->select_lex()->interval_list; };
key_usage_list2:
key_usage_list2 ',' ident
- { Select->interval_list.push_back(new String((const char*) $3.str,$3.length)); }
+ { Select->select_lex()->
+ interval_list.push_back(new String((const char*) $3.str, $3.length,
+ default_charset_info)); }
| ident
- { Select->interval_list.push_back(new String((const char*) $1.str,$1.length)); }
+ { Select->select_lex()->
+ interval_list.push_back(new String((const char*) $1.str, $1.length,
+ default_charset_info)); }
| PRIMARY_SYM
- { Select->interval_list.push_back(new String("PRIMARY",7)); };
+ { Select->select_lex()->
+ interval_list.push_back(new String("PRIMARY", 7,
+ default_charset_info)); };
using_list:
ident
{
- SELECT_LEX *sel=Select;
- if (!($$= new Item_func_eq(new Item_field(sel->db1,sel->table1, $1.str), new Item_field(sel->db2,sel->table2,$1.str))))
+ SELECT_LEX *sel= Select->select_lex();
+ if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1,
+ $1.str),
+ new Item_field(sel->db2, sel->table2,
+ $1.str))))
YYABORT;
}
| using_list ',' ident
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1)))
YYABORT;
};
@@ -2182,25 +2490,24 @@ opt_table_alias:
where_clause:
- /* empty */ { Select->where= 0; }
+ /* empty */ { Select->select_lex()->where= 0; }
| WHERE expr
{
- Select->where= $2;
+ Select->select_lex()->where= $2;
if ($2)
$2->top_level_item();
}
- ;
+ ;
having_clause:
/* empty */
- | HAVING { Select->create_refs=1; } expr
- {
- SELECT_LEX *sel=Select;
- sel->having= $3;
- sel->create_refs=0;
- if ($3)
- $3->top_level_item();
- }
+ | HAVING { Select->select_lex()->create_refs= 1; } expr
+ {
+ SELECT_LEX *sel= Select->select_lex();
+ sel->having= $3; sel->create_refs=0;
+ if ($3)
+ $3->top_level_item();
+ }
;
opt_escape:
@@ -2228,16 +2535,28 @@ olap_opt:
{
LEX *lex=Lex;
lex->olap = true;
- lex->select->olap= CUBE_TYPE;
- net_printf(&lex->thd->net, ER_NOT_SUPPORTED_YET, "CUBE");
+ if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
+ {
+ net_printf(lex->thd, ER_WRONG_USAGE, "WITH CUBE",
+ "global union parameters");
+ YYABORT;
+ }
+ lex->current_select->select_lex()->olap= CUBE_TYPE;
+ net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE");
YYABORT; /* To be deleted in 4.1 */
}
| WITH ROLLUP_SYM
{
- LEX *lex=Lex;
- lex->olap = true;
- lex->select->olap= ROLLUP_TYPE;
- net_printf(&lex->thd->net, ER_NOT_SUPPORTED_YET, "ROLLUP");
+ LEX *lex= Lex;
+ lex->olap= true;
+ if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
+ {
+ net_printf(lex->thd, ER_WRONG_USAGE, "WITH ROLLUP",
+ "global union parameters");
+ YYABORT;
+ }
+ lex->current_select->select_lex()->olap= ROLLUP_TYPE;
+ net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "ROLLUP");
YYABORT; /* To be deleted in 4.1 */
}
;
@@ -2254,14 +2573,15 @@ order_clause:
ORDER_SYM BY
{
LEX *lex=Lex;
- if (lex->select->olap != UNSPECIFIED_OLAP_TYPE)
+ if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
+ lex->current_select->select_lex()->olap !=
+ UNSPECIFIED_OLAP_TYPE)
{
- net_printf(&lex->thd->net, ER_WRONG_USAGE,
+ net_printf(lex->thd, ER_WRONG_USAGE,
"CUBE/ROLLUP",
"ORDER BY");
YYABORT;
}
- lex->select->sort_default=1;
} order_list;
order_list:
@@ -2280,43 +2600,46 @@ limit_clause:
/* empty */ {}
| LIMIT
{
- LEX *lex=Lex;
- if (lex->select->olap != UNSPECIFIED_OLAP_TYPE)
+ LEX *lex= Lex;
+ if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE &&
+ lex->current_select->select_lex()->olap !=
+ UNSPECIFIED_OLAP_TYPE)
{
- net_printf(&lex->thd->net, ER_WRONG_USAGE, "CUBE/ROLLUP",
+ net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP",
"LIMIT");
YYABORT;
}
}
limit_options
- ;
+ ;
limit_options:
ULONG_NUM
{
- SELECT_LEX *sel= Select;
+ SELECT_LEX_NODE *sel= Select;
sel->select_limit= $1;
sel->offset_limit= 0L;
}
| ULONG_NUM ',' ULONG_NUM
{
- SELECT_LEX *sel= Select;
+ SELECT_LEX_NODE *sel= Select;
sel->select_limit= $3;
sel->offset_limit= $1;
}
| ULONG_NUM OFFSET_SYM ULONG_NUM
{
- SELECT_LEX *sel= Select;
+ SELECT_LEX_NODE *sel= Select;
sel->select_limit= $1;
sel->offset_limit= $3;
}
;
+
delete_limit_clause:
/* empty */
{
LEX *lex=Lex;
- lex->select->select_limit= HA_POS_ERROR;
+ lex->current_select->select_limit= HA_POS_ERROR;
}
| LIMIT ulonglong_num
{ Select->select_limit= (ha_rows) $2; };
@@ -2364,20 +2687,61 @@ procedure_item:
YYABORT;
if (!$2->name)
$2->set_name($1,(uint) ((char*) Lex->tok_end - $1));
- };
+ }
+ ;
+
+
+select_var_list_init:
+ {
+ LEX *lex=Lex;
+ if (!lex->describe && (!(lex->result= new select_dumpvar())))
+ YYABORT;
+ }
+ select_var_list
+ ;
+
+select_var_list:
+ select_var_list ',' select_var_ident
+ | select_var_ident {}
+ ;
+
+select_var_ident: '@' ident_or_text
+ {
+ LEX *lex=Lex;
+ if (lex->result && ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING))))
+ YYABORT;
+ }
+ ;
opt_into:
- INTO OUTFILE TEXT_STRING
+ INTO OUTFILE TEXT_STRING
{
- if (!(Lex->exchange= new sql_exchange($3.str,0)))
- YYABORT;
+ LEX *lex=Lex;
+ if (!lex->describe)
+ {
+ if (!(lex->exchange= new sql_exchange($3.str,0)))
+ YYABORT;
+ if (!(lex->result= new select_export(lex->exchange)))
+ YYABORT;
+ }
}
opt_field_term opt_line_term
| INTO DUMPFILE TEXT_STRING
{
- if (!(Lex->exchange= new sql_exchange($3.str,1)))
- YYABORT;
- };
+ LEX *lex=Lex;
+ if (!lex->describe)
+ {
+ if (!(lex->exchange= new sql_exchange($3.str,1)))
+ YYABORT;
+ if (!(lex->result= new select_dump(lex->exchange)))
+ YYABORT;
+ }
+ }
+ | INTO select_var_list_init
+ {
+ current_thd->safe_to_cache_query=0;
+ }
+ ;
/*
DO statement
@@ -2410,7 +2774,7 @@ drop:
lex->drop_list.empty();
lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY,
$3.str));
- if (!add_table_to_list($5,NULL, 1))
+ if (!lex->current_select->add_table_to_list($5,NULL, 1))
YYABORT;
}
| DROP DATABASE if_exists ident
@@ -2434,7 +2798,7 @@ table_list:
table_name:
table_ident
- { if (!add_table_to_list($1,NULL,1)) YYABORT; };
+ { if (!Select->add_table_to_list($1, NULL, 1)) YYABORT; };
if_exists:
/* empty */ { $$=0; }
@@ -2596,11 +2960,9 @@ expr_or_default:
update:
UPDATE_SYM
{
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_UPDATE;
- lex->select->order_list.elements=0;
- lex->select->order_list.first=0;
- lex->select->order_list.next= (byte**) &lex->select->order_list.first;
+ 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
@@ -2630,12 +2992,11 @@ opt_low_priority:
delete:
DELETE_SYM
{
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_DELETE; lex->select->options=0;
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_DELETE;
+ lex->select_lex.options= 0;
lex->lock_option= lex->thd->update_lock_default;
- lex->select->order_list.elements=0;
- lex->select->order_list.first=0;
- lex->select->order_list.next= (byte**) &lex->select->order_list.first;
+ lex->select_lex.init_order();
}
opt_delete_options single_multi {}
;
@@ -2660,18 +3021,18 @@ table_wild_list:
| table_wild_list ',' table_wild_one {};
table_wild_one:
- ident opt_wild
- {
- if (!add_table_to_list(new Table_ident($1), NULL, 1,
- Lex->lock_option))
- YYABORT;
- }
- | ident '.' ident opt_wild
- {
- if (!add_table_to_list(new Table_ident($1,$3,0), NULL, 1,
- Lex->lock_option))
+ ident opt_wild
+ {
+ if (!Select->add_table_to_list(new Table_ident($1), NULL, 1,
+ Lex->lock_option))
+ YYABORT;
+ }
+ | ident '.' ident opt_wild
+ {
+ if (!Select->add_table_to_list(new Table_ident($1, $3, 0), NULL, 1,
+ Lex->lock_option))
YYABORT;
- }
+ }
;
opt_wild:
@@ -2690,12 +3051,10 @@ opt_delete_option:
truncate:
TRUNCATE_SYM opt_table_sym table_name
{
- LEX* lex = Lex;
+ LEX* lex= Lex;
lex->sql_command= SQLCOM_TRUNCATE;
- lex->select->options=0;
- lex->select->order_list.elements=0;
- lex->select->order_list.first=0;
- lex->select->order_list.next= (byte**) &lex->select->order_list.first;
+ lex->select_lex.options= 0;
+ lex->select_lex.init_order();
}
;
@@ -2705,37 +3064,44 @@ opt_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
{ Lex->sql_command= SQLCOM_SHOW_DATABASES; }
| TABLES opt_db wild
{
- LEX *lex=Lex;
+ LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->select->db= $2; lex->select->options=0;
+ lex->select_lex.db= $2;
+ lex->select_lex.options= 0;
}
| TABLE_SYM STATUS_SYM opt_db wild
{
- LEX *lex=Lex;
+ LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_TABLES;
- lex->select->options|= SELECT_DESCRIBE;
- lex->select->db= $3;
+ lex->select_lex.options|= SELECT_DESCRIBE;
+ lex->select_lex.db= $3;
}
| OPEN_SYM TABLES opt_db wild
{
- LEX *lex=Lex;
+ LEX *lex= Lex;
lex->sql_command= SQLCOM_SHOW_OPEN_TABLES;
- lex->select->db= $3;
- lex->select->options=0;
+ lex->select_lex.db= $3;
+ lex->select_lex.options= 0;
}
| opt_full COLUMNS from_or_in table_ident opt_db wild
{
Lex->sql_command= SQLCOM_SHOW_FIELDS;
if ($5)
$4->change_db($5);
- if (!add_table_to_list($4,NULL,0))
+ if (!Select->add_table_to_list($4, NULL, 0))
YYABORT;
}
| NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
@@ -2748,7 +3114,7 @@ show_param:
Lex->mi.pos = $12;
Lex->mi.server_id = $16;
}
- | MASTER_SYM LOGS_SYM
+ | BINARY LOGS_SYM
{
Lex->sql_command = SQLCOM_SHOW_BINLOGS;
}
@@ -2758,19 +3124,42 @@ show_param:
}
| BINLOG_SYM EVENTS_SYM binlog_in binlog_from
{
- LEX *lex=Lex;
- lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS;
- lex->select->select_limit= lex->thd->variables.select_limit;
- lex->select->offset_limit= 0L;
+ LEX *lex= Lex;
+ 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
| keys_or_index FROM table_ident opt_db
{
Lex->sql_command= SQLCOM_SHOW_KEYS;
if ($4)
$3->change_db($4);
- if (!add_table_to_list($3,NULL,0))
+ if (!Select->add_table_to_list($3, NULL, 0))
YYABORT;
}
+ | COLUMN_SYM TYPES_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_COLUMN_TYPES;
+ }
+ | TABLE_SYM TYPES_SYM
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_TABLE_TYPES;
+ }
+ | PRIVILEGES
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_SHOW_PRIVILEGES;
+ }
+ | COUNT_SYM '(' '*' ')' WARNINGS
+ { (void) create_select_for_variable("warning_count"); }
+ | COUNT_SYM '(' '*' ')' ERRORS
+ { (void) create_select_for_variable("error_count"); }
+ | WARNINGS {Select->offset_limit=0L;} limit_clause
+ { Lex->sql_command = SQLCOM_SHOW_WARNS;}
+ | ERRORS {Select->offset_limit=0L;} limit_clause
+ { Lex->sql_command = SQLCOM_SHOW_ERRORS;}
| STATUS_SYM wild
{ Lex->sql_command= SQLCOM_SHOW_STATUS; }
| INNOBASE_SYM STATUS_SYM
@@ -2778,11 +3167,13 @@ show_param:
| opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
| opt_var_type VARIABLES wild
- {
+ {
THD *thd= current_thd;
thd->lex.sql_command= SQLCOM_SHOW_VARIABLES;
thd->lex.option_type= (enum_var_type) $1;
}
+ | CHAR_SYM SET wild
+ { Lex->sql_command= SQLCOM_SHOW_CHARSETS; }
| LOGS_SYM
{ Lex->sql_command= SQLCOM_SHOW_LOGS; }
| GRANTS FOR_SYM user
@@ -2792,10 +3183,16 @@ show_param:
lex->grant_user=$3;
lex->grant_user->password.str=NullS;
}
+ | CREATE DATABASE opt_if_not_exists ident
+ {
+ Lex->sql_command=SQLCOM_SHOW_CREATE_DB;
+ Lex->create_info.options=$3;
+ Lex->name=$4.str;
+ }
| CREATE TABLE_SYM table_ident
{
Lex->sql_command = SQLCOM_SHOW_CREATE;
- if(!add_table_to_list($3, NULL,0))
+ if(!Select->add_table_to_list($3, NULL,0))
YYABORT;
}
| MASTER_SYM STATUS_SYM
@@ -2840,12 +3237,16 @@ describe:
lex->wild=0;
lex->verbose=0;
lex->sql_command=SQLCOM_SHOW_FIELDS;
- if (!add_table_to_list($2, NULL,0))
+ if (!Select->add_table_to_list($2, NULL,0))
YYABORT;
}
opt_describe_column
| describe_command select
- { Lex->select_lex.options|= SELECT_DESCRIBE; };
+ {
+ LEX *lex=Lex;
+ lex->select_lex.options|= SELECT_DESCRIBE;
+ lex->describe=1;
+ };
describe_command:
@@ -2856,7 +3257,7 @@ opt_describe_column:
/* empty */ {}
| text_string { Lex->wild= $1; }
| ident
- { Lex->wild= new String((const char*) $1.str,$1.length); };
+ { Lex->wild= new String((const char*) $1.str,$1.length,default_charset_info); };
/* flush things */
@@ -2923,9 +3324,9 @@ kill:
KILL_SYM expr
{
LEX *lex=Lex;
- if ($2->fix_fields(lex->thd,0))
+ if ($2->fix_fields(lex->thd, 0, &$2))
{
- send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY);
+ send_error(lex->thd, ER_SET_CONSTANTS_ONLY);
YYABORT;
}
lex->sql_command=SQLCOM_KILL;
@@ -2937,7 +3338,8 @@ kill:
use: USE_SYM ident
{
LEX *lex=Lex;
- lex->sql_command=SQLCOM_CHANGE_DB; lex->select->db= $2.str;
+ lex->sql_command=SQLCOM_CHANGE_DB;
+ lex->select_lex.db= $2.str;
};
/* import, export of files */
@@ -2955,14 +3357,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 (!add_table_to_list($11,NULL,1))
+ if (!Select->add_table_to_list($11, NULL, 1))
YYABORT;
}
|
LOAD TABLE_SYM table_ident FROM MASTER_SYM
{
Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
- if (!add_table_to_list($3,NULL,1))
+ if (!Select->add_table_to_list($3, NULL, 1))
YYABORT;
}
@@ -3026,18 +3428,33 @@ opt_ignore_lines:
/* Common definitions */
text_literal:
- TEXT_STRING { $$ = new Item_string($1.str,$1.length); }
+ TEXT_STRING { $$ = new Item_string($1.str,$1.length,current_thd->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); }
+ TEXT_STRING { $$= new String($1.str,$1.length,current_thd->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());
+ lex->param_count++;
+ }
+ else
+ {
+ yyerror("You have an error in your SQL syntax");
+ YYABORT;
+ }
+ };
literal:
text_literal { $$ = $1; }
| NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); }
@@ -3072,23 +3489,23 @@ order_ident:
simple_ident:
ident
{
- SELECT_LEX *sel=Select;
- $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str);
+ SELECT_LEX_NODE *sel=Select;
+ $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str);
}
| ident '.' ident
{
- SELECT_LEX *sel=Select;
- $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str);
+ SELECT_LEX_NODE *sel=Select;
+ $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str);
}
| '.' ident '.' ident
{
- SELECT_LEX *sel=Select;
- $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str);
+ SELECT_LEX_NODE *sel=Select;
+ $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str);
}
| ident '.' ident '.' ident
{
- SELECT_LEX *sel=Select;
- $$ = !sel->create_refs || sel->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);
+ 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);
};
@@ -3151,8 +3568,10 @@ keyword:
| BIT_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
+ | BYTE_SYM {}
| CACHE_SYM {}
| CHANGED {}
+ | CHARSET {}
| CHECKSUM_SYM {}
| CHECK_SYM {}
| CIPHER_SYM {}
@@ -3173,6 +3592,7 @@ keyword:
| DIRECTORY_SYM {}
| DO_SYM {}
| DUMPFILE {}
+ | DUAL_SYM {}
| DYNAMIC_SYM {}
| END {}
| ENUM {}
@@ -3181,14 +3601,14 @@ keyword:
| EXECUTE_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
- | DISABLE_SYM {}
- | ENABLE_SYM {}
+ | DISABLE_SYM {}
+ | ENABLE_SYM {}
| FULL {}
| FILE_SYM {}
| FIRST_SYM {}
| FIXED_SYM {}
| FLUSH_SYM {}
- | GRANTS {}
+ | GRANTS {}
| GLOBAL_SYM {}
| HEAP_SYM {}
| HANDLER_SYM {}
@@ -3201,7 +3621,7 @@ keyword:
| ISSUER_SYM {}
| INNOBASE_SYM {}
| INSERT_METHOD {}
- | IO_THREAD {}
+ | IO_THREAD {}
| LAST_SYM {}
| LEVEL_SYM {}
| LOCAL_SYM {}
@@ -3216,9 +3636,9 @@ keyword:
| MASTER_USER_SYM {}
| MASTER_PASSWORD_SYM {}
| MASTER_CONNECT_RETRY_SYM {}
- | MAX_CONNECTIONS_PER_HOUR {}
- | MAX_QUERIES_PER_HOUR {}
- | MAX_UPDATES_PER_HOUR {}
+ | MAX_CONNECTIONS_PER_HOUR {}
+ | MAX_QUERIES_PER_HOUR {}
+ | MAX_UPDATES_PER_HOUR {}
| MEDIUM_SYM {}
| MERGE_SYM {}
| MINUTE_SYM {}
@@ -3236,19 +3656,20 @@ keyword:
| OFFSET_SYM {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
+ | PARTIAL {}
| PASSWORD {}
| PREV_SYM {}
| PROCESS {}
| PROCESSLIST_SYM {}
| QUERY_SYM {}
| QUICK {}
- | RAID_0_SYM {}
+ | RAID_0_SYM {}
| RAID_CHUNKS {}
| RAID_CHUNKSIZE {}
- | RAID_STRIPED_SYM {}
+ | RAID_STRIPED_SYM {}
| RAID_TYPE {}
- | RELAY_LOG_FILE_SYM {}
- | RELAY_LOG_POS_SYM {}
+ | RELAY_LOG_FILE_SYM {}
+ | RELAY_LOG_POS_SYM {}
| RELOAD {}
| REPAIR {}
| REPEATABLE_SYM {}
@@ -3262,16 +3683,18 @@ keyword:
| ROW_FORMAT_SYM {}
| ROW_SYM {}
| SECOND_SYM {}
+ | SERIAL_SYM {}
| SERIALIZABLE_SYM {}
| SESSION_SYM {}
| SIGNED_SYM {}
+ | SIMPLE_SYM {}
| SHARE_SYM {}
| SHUTDOWN {}
- | SLAVE {}
+ | SLAVE {}
| SQL_CACHE_SYM {}
| SQL_BUFFER_RESULT {}
| SQL_NO_CACHE_SYM {}
- | SQL_THREAD {}
+ | SQL_THREAD {}
| START_SYM {}
| STATUS_SYM {}
| STOP_SYM {}
@@ -3289,8 +3712,10 @@ keyword:
| UNCOMMITTED_SYM {}
| USE_FRM {}
| VARIABLES {}
+ | VALUE_SYM {}
| WORK_SYM {}
- | YEAR_SYM {};
+ | YEAR_SYM {}
+ ;
/* Option functions */
@@ -3321,16 +3746,16 @@ option_type:
opt_var_type:
/* empty */ { $$=OPT_SESSION; }
+ | GLOBAL_SYM { $$=OPT_GLOBAL; }
| LOCAL_SYM { $$=OPT_SESSION; }
| SESSION_SYM { $$=OPT_SESSION; }
- | GLOBAL_SYM { $$=OPT_GLOBAL; }
;
opt_var_ident_type:
/* empty */ { $$=OPT_DEFAULT; }
+ | GLOBAL_SYM '.' { $$=OPT_GLOBAL; }
| LOCAL_SYM '.' { $$=OPT_SESSION; }
| SESSION_SYM '.' { $$=OPT_SESSION; }
- | GLOBAL_SYM '.' { $$=OPT_GLOBAL; }
;
option_value:
@@ -3386,7 +3811,7 @@ internal_variable_name:
YYABORT;
$$=tmp;
}
- ;
+ ;
isolation_types:
READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; }
@@ -3394,7 +3819,7 @@ isolation_types:
| REPEATABLE_SYM READ_SYM { $$= ISO_REPEATABLE_READ; }
| SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; }
;
-
+
text_or_password:
TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')'
@@ -3407,14 +3832,15 @@ text_or_password:
make_scrambled_password(buff,$3.str);
$$=buff;
}
- };
+ }
+ ;
set_expr_or_default:
expr { $$=$1; }
| DEFAULT { $$=0; }
- | ON { $$=new Item_string("ON",2); }
- | ALL { $$=new Item_string("ALL",3); }
+ | ON { $$=new Item_string("ON", 2, system_charset_info); }
+ | ALL { $$=new Item_string("ALL", 3, system_charset_info); }
;
@@ -3437,16 +3863,22 @@ table_lock_list:
table_lock:
table_ident opt_table_alias lock_option
- { if (!add_table_to_list($1,$2,0,(thr_lock_type) $3)) YYABORT; };
+ {
+ if (!Select->add_table_to_list($1, $2, 0, (thr_lock_type) $3))
+ YYABORT;
+ }
+ ;
lock_option:
READ_SYM { $$=TL_READ_NO_INSERT; }
| WRITE_SYM { $$=current_thd->update_lock_default; }
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
- | READ_SYM LOCAL_SYM { $$= TL_READ; };
+ | READ_SYM LOCAL_SYM { $$= TL_READ; }
+ ;
unlock:
- UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; };
+ UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
+ ;
/*
@@ -3456,14 +3888,16 @@ unlock:
handler:
HANDLER_SYM table_ident OPEN_SYM opt_table_alias
{
- Lex->sql_command = SQLCOM_HA_OPEN;
- if (!add_table_to_list($2,$4,0))
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_HA_OPEN;
+ if (!lex->current_select->add_table_to_list($2, $4, 0))
YYABORT;
}
| HANDLER_SYM table_ident CLOSE_SYM
{
- Lex->sql_command = SQLCOM_HA_CLOSE;
- if (!add_table_to_list($2,0,0))
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_HA_CLOSE;
+ if (!lex->current_select->add_table_to_list($2, 0, 0))
YYABORT;
}
| HANDLER_SYM table_ident READ_SYM
@@ -3471,20 +3905,23 @@ handler:
LEX *lex=Lex;
lex->sql_command = SQLCOM_HA_READ;
lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */
- lex->select->select_limit= 1;
- lex->select->offset_limit= 0L;
- if (!add_table_to_list($2,0,0))
+ lex->current_select->select_limit= 1;
+ lex->current_select->offset_limit= 0L;
+ if (!lex->current_select->add_table_to_list($2, 0, 0))
YYABORT;
}
- handler_read_or_scan where_clause limit_clause { };
+ handler_read_or_scan where_clause limit_clause { }
+ ;
handler_read_or_scan:
handler_scan_function { Lex->backup_dir= 0; }
- | ident handler_rkey_function { Lex->backup_dir= $1.str; };
+ | ident handler_rkey_function { Lex->backup_dir= $1.str; }
+ ;
handler_scan_function:
FIRST_SYM { Lex->ha_read_mode = RFIRST; }
- | NEXT_SYM { Lex->ha_read_mode = RNEXT; };
+ | NEXT_SYM { Lex->ha_read_mode = RNEXT; }
+ ;
handler_rkey_function:
FIRST_SYM { Lex->ha_read_mode = RFIRST; }
@@ -3498,14 +3935,16 @@ handler_rkey_function:
lex->ha_rkey_mode=$1;
if (!(lex->insert_list = new List_item))
YYABORT;
- } '(' values ')' { };
+ } '(' values ')' { }
+ ;
handler_rkey_mode:
EQ { $$=HA_READ_KEY_EXACT; }
| GE { $$=HA_READ_KEY_OR_NEXT; }
| LE { $$=HA_READ_KEY_OR_PREV; }
| GT_SYM { $$=HA_READ_AFTER_KEY; }
- | LT { $$=HA_READ_BEFORE_KEY; };
+ | LT { $$=HA_READ_BEFORE_KEY; }
+ ;
/* GRANT / REVOKE */
@@ -3517,7 +3956,7 @@ revoke:
lex->users_list.empty();
lex->columns.empty();
lex->grant= lex->grant_tot_col=0;
- lex->select->db=0;
+ lex->select_lex.db=0;
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero((char*) &lex->mqh, sizeof(lex->mqh));
@@ -3532,7 +3971,7 @@ grant:
lex->columns.empty();
lex->sql_command = SQLCOM_GRANT;
lex->grant= lex->grant_tot_col= 0;
- lex->select->db= 0;
+ lex->select_lex.db= 0;
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
bzero(&(lex->mqh),sizeof(lex->mqh));
@@ -3543,7 +3982,8 @@ grant:
grant_privileges:
grant_privilege_list {}
| ALL PRIVILEGES { Lex->grant = GLOBAL_ACLS;}
- | ALL { Lex->grant = GLOBAL_ACLS;};
+ | ALL { Lex->grant = GLOBAL_ACLS;}
+ ;
grant_privilege_list:
grant_privilege
@@ -3591,7 +4031,7 @@ require_list_element:
LEX *lex=Lex;
if (lex->x509_subject)
{
- net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "SUBJECT");
+ net_printf(lex->thd,ER_DUP_ARGUMENT, "SUBJECT");
YYABORT;
}
lex->x509_subject=$2.str;
@@ -3601,7 +4041,7 @@ require_list_element:
LEX *lex=Lex;
if (lex->x509_issuer)
{
- net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "ISSUER");
+ net_printf(lex->thd,ER_DUP_ARGUMENT, "ISSUER");
YYABORT;
}
lex->x509_issuer=$2.str;
@@ -3611,7 +4051,7 @@ require_list_element:
LEX *lex=Lex;
if (lex->ssl_cipher)
{
- net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "CIPHER");
+ net_printf(lex->thd,ER_DUP_ARGUMENT, "CIPHER");
YYABORT;
}
lex->ssl_cipher=$2.str;
@@ -3621,48 +4061,49 @@ require_list_element:
opt_table:
'*'
{
- LEX *lex=Lex;
- lex->select->db=lex->thd->db;
+ LEX *lex= Lex;
+ lex->current_select->select_lex()->db= lex->thd->db;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
- send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| ident '.' '*'
{
- LEX *lex=Lex;
- lex->select->db = $1.str;
+ LEX *lex= Lex;
+ lex->current_select->select_lex()->db = $1.str;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
- send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| '*' '.' '*'
{
- LEX *lex=Lex;
- lex->select->db = NULL;
+ LEX *lex= Lex;
+ lex->current_select->select_lex()->db = NULL;
if (lex->grant == GLOBAL_ACLS)
lex->grant= GLOBAL_ACLS & ~GRANT_ACL;
else if (lex->columns.elements)
{
- send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
+ send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE);
YYABORT;
}
}
| table_ident
{
LEX *lex=Lex;
- if (!add_table_to_list($1,NULL,0))
+ if (!lex->current_select->add_table_to_list($1,NULL,0))
YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
- };
+ }
+ ;
user_list:
@@ -3693,7 +4134,8 @@ grant_user:
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
{ $$=$1; $1->password=$5 ; }
| user
- { $$=$1; $1->password.str=NullS; };
+ { $$=$1; $1->password.str=NullS; }
+ ;
opt_column_list:
@@ -3711,13 +4153,14 @@ column_list:
column_list_id:
ident
{
- String *new_str = new String((const char*) $1.str,$1.length);
+ String *new_str = new String((const char*) $1.str,$1.length,default_charset_info);
List_iterator <LEX_COLUMN> iter(Lex->columns);
class LEX_COLUMN *point;
LEX *lex=Lex;
while ((point=iter++))
{
- if (!my_strcasecmp(point->column.ptr(),new_str->ptr()))
+ if (!my_strcasecmp(system_charset_info,
+ point->column.ptr(), new_str->ptr()))
break;
}
lex->grant_tot_col|= lex->which_columns;
@@ -3725,7 +4168,8 @@ column_list_id:
point->rights |= lex->which_columns;
else
lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
- };
+ }
+ ;
require_clause: /* empty */
@@ -3745,7 +4189,7 @@ require_clause: /* empty */
{
Lex->ssl_type=SSL_TYPE_NONE;
}
- ;
+ ;
grant_options:
/* empty */ {}
@@ -3753,7 +4197,8 @@ grant_options:
grant_option_list:
grant_option_list grant_option {}
- | grant_option {};
+ | grant_option {}
+ ;
grant_option:
GRANT OPTION { Lex->grant |= GRANT_ACL;}
@@ -3771,14 +4216,16 @@ grant_option:
{
Lex->mqh.connections=$2;
Lex->mqh.bits |= 4;
- };
+ }
+ ;
begin:
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work;
opt_work:
/* empty */ {}
- | WORK_SYM {;};
+ | WORK_SYM {;}
+ ;
commit:
COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;};
@@ -3788,7 +4235,7 @@ rollback:
/*
-** UNIONS : glue selects together
+ UNIONS : glue selects together
*/
@@ -3797,24 +4244,24 @@ opt_union:
| union_list;
union_list:
- UNION_SYM union_option
+ UNION_SYM union_option
{
LEX *lex=Lex;
if (lex->exchange)
{
/* Only the last SELECT can have INTO...... */
- net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
+ net_printf(lex->thd, ER_WRONG_USAGE, "UNION", "INTO");
YYABORT;
- }
- if (lex->select->linkage == NOT_A_SELECT)
+ }
+ if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
- send_error(&lex->thd->net, ER_SYNTAX_ERROR);
+ send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT;
}
- if (mysql_new_select(lex))
+ if (mysql_new_select(lex, 0))
YYABORT;
- lex->select->linkage=UNION_TYPE;
- }
+ lex->current_select->linkage=UNION_TYPE;
+ }
select_init
;
@@ -3829,22 +4276,66 @@ optional_order_or_limit:
when neither ORDER BY nor LIMIT are used */ {}
|
{
- LEX *lex=Lex;
- if (!lex->select->braces)
+ LEX *lex=Lex;
+ if (!lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
{
- send_error(&lex->thd->net, ER_SYNTAX_ERROR);
+ send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT;
}
- if (mysql_new_select(lex))
- YYABORT;
- mysql_init_select(lex);
- lex->select->linkage=NOT_A_SELECT;
- lex->select->select_limit=lex->thd->variables.select_limit;
+ SELECT_LEX *sel= lex->current_select->select_lex();
+ 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
+ opt_order_clause limit_clause
;
union_option:
/* empty */ {}
- | ALL { Lex->union_option=1; }
- ;
+ | ALL {Select->master_unit()->union_option= 1;};
+
+singleval_subselect:
+ subselect_start singleval_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+singleval_subselect_init:
+ select_init
+ {
+ $$= new Item_singleval_subselect(current_thd,
+ Lex->current_select->master_unit()->
+ first_select());
+ };
+
+exists_subselect:
+ subselect_start exists_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+exists_subselect_init:
+ select_init
+ {
+ $$= new Item_exists_subselect(current_thd,
+ Lex->current_select->master_unit()->
+ first_select());
+ };
+
+subselect_start:
+ '('
+ {
+ if (mysql_new_select(Lex, 1))
+ YYABORT;
+ };
+
+subselect_end:
+ ')'
+ {
+ LEX *lex=Lex;
+ lex->current_select = lex->current_select->outer_select();
+ };
diff --git a/sql/structs.h b/sql/structs.h
index bd058a08e46..7873de4db63 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -148,14 +148,19 @@ enum SHOW_TYPE
};
enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
+
+extern const char *show_comp_option_name[];
+
typedef int *(*update_var)(THD *, struct show_var_st *);
+
typedef struct show_var_st {
const char *name;
char *value;
SHOW_TYPE type;
} SHOW_VAR;
+
typedef struct lex_string {
char *str;
uint length;
diff --git a/sql/table.cc b/sql/table.cc
index 62163819599..84a072c886d 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -49,7 +49,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
interval_count,interval_parts,read_length,db_create_options;
uint key_info_length, com_length;
ulong pos;
- char index_file[FN_REFLEN], *names, *keynames;
+ char index_file[FN_REFLEN], *names, *keynames, *comment_pos;
uchar head[288],*disk_buff,new_field_pack_flag;
my_string record;
const char **int_array;
@@ -117,6 +117,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->raid_type= head[41];
outparam->raid_chunks= head[42];
outparam->raid_chunksize= uint4korr(head+43);
+ if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0))))
+ outparam->table_charset=NULL; // QQ display error message?
null_field_first=1;
}
outparam->db_record_offset=1;
@@ -279,7 +281,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->comment=strdup_root(&outparam->mem_root,
(char*) head+47);
- DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length));
+ DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length, com_length));
if (!(field_ptr = (Field **)
alloc_root(&outparam->mem_root,
@@ -310,6 +312,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->intervals=0; // For better debugging
memcpy((char*) names, strpos+(outparam->fields*field_pack_length),
(uint) (n_length+int_length));
+ comment_pos=names+(n_length+int_length);
+ memcpy(comment_pos, disk_buff+read_length-com_length, com_length);
fix_type_pointers(&int_array,&outparam->fieldnames,1,&names);
fix_type_pointers(&int_array,outparam->intervals,interval_count,
@@ -337,6 +341,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash)
use_hash= !hash_init(&outparam->name_hash,
+ system_charset_info,
outparam->fields,0,0,
(hash_get_key) get_field_name,0,
HASH_CASE_INSENSITIVE);
@@ -346,35 +351,55 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
uint pack_flag= uint2korr(strpos+6);
uint interval_nr= (uint) strpos[10];
enum_field_types field_type;
+ CHARSET_INFO *charset=NULL;
+ LEX_STRING comment;
if (new_frm_ver == 2)
{
/* new frm file in 4.1 */
+ uint comment_length=uint2korr(strpos+13);
field_type=(enum_field_types) (uint) strpos[11];
+ if (!(charset=get_charset((uint) strpos[12], MYF(0))))
+ charset=outparam->table_charset?outparam->table_charset:default_charset_info;
+ if (!comment_length)
+ {
+ comment.str= (char*) "";
+ comment.length=0;
+ }
+ else
+ {
+ comment.str= (char*) comment_pos;
+ comment.length= comment_length;
+ comment_pos+= comment_length;
+ }
}
else
{
/* old frm file */
field_type= (enum_field_types) f_packtype(pack_flag);
+ charset=outparam->table_charset?outparam->table_charset:default_charset_info;
+ bzero((char*) &comment, sizeof(comment));
}
-
*field_ptr=reg_field=
make_field(record+uint2korr(strpos+4),
(uint32) strpos[3], // field_length
null_pos,null_bit,
pack_flag,
field_type,
+ charset,
(Field::utype) MTYP_TYPENR((uint) strpos[8]),
(interval_nr ?
outparam->intervals+interval_nr-1 :
(TYPELIB*) 0),
outparam->fieldnames.type_names[i],
outparam);
- if (!*field_ptr) // Field in 4.1
+ if (!reg_field) // Not supported field type
{
error= 4;
goto err_not_open; /* purecov: inspected */
}
+ reg_field->comment=comment;
+ reg_field->set_charset(charset);
if (!(reg_field->flags & NOT_NULL_FLAG))
{
if ((null_bit<<=1) == 256)
@@ -472,13 +497,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
if (i == 0)
field->key_start|= ((key_map) 1 << key);
- if ((index_flags & HA_KEY_READ_ONLY) &&
- field->key_length() == key_part->length &&
+ if (field->key_length() == key_part->length &&
field->type() != FIELD_TYPE_BLOB)
{
- if (field->key_type() != HA_KEYTYPE_TEXT ||
- (!(ha_option & HA_KEY_READ_WRONG_STR) &&
- !(keyinfo->flags & HA_FULLTEXT)))
+ if ((index_flags & HA_KEY_READ_ONLY) &&
+ (field->key_type() != HA_KEYTYPE_TEXT ||
+ (!(ha_option & HA_KEY_READ_WRONG_STR) &&
+ !(keyinfo->flags & HA_FULLTEXT))))
field->part_of_key|= ((key_map) 1 << key);
if ((field->key_type() != HA_KEYTYPE_TEXT ||
!(keyinfo->flags & HA_FULLTEXT)) &&
@@ -968,9 +993,14 @@ ulong next_io_size(register ulong pos)
} /* next_io_size */
-void append_unescaped(String *res,const char *pos)
+ /* Store in String an SQL quoted string */
+
+void append_unescaped(String *res,const char *pos, uint length)
{
- for (; *pos ; pos++)
+ const char *end= pos+length;
+ res->append('\'');
+
+ for (; pos != end ; pos++)
{
switch (*pos) {
case 0: /* Must be escaped for 'mysql' */
@@ -998,6 +1028,7 @@ void append_unescaped(String *res,const char *pos)
break;
}
}
+ res->append('\'');
}
/* Create a .frm file */
@@ -1021,7 +1052,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0)
{
bzero((char*) fileinfo,64);
- fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header
+ fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+2; // Header
fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
@@ -1037,6 +1068,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo,
int2store(fileinfo+30,create_info->table_options);
fileinfo[32]=0; // No filename anymore
int4store(fileinfo+34,create_info->avg_row_length);
+ fileinfo[38]= create_info->table_charset?create_info->table_charset->number:0;
fileinfo[40]= (uchar) create_info->row_type;
fileinfo[41]= (uchar) create_info->raid_type;
fileinfo[42]= (uchar) create_info->raid_chunks;
@@ -1067,6 +1099,7 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table)
create_info->raid_type=table->raid_type;
create_info->raid_chunks=table->raid_chunks;
create_info->raid_chunksize=table->raid_chunksize;
+ create_info->table_charset=table->table_charset;
DBUG_VOID_RETURN;
}
@@ -1089,7 +1122,7 @@ char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr)
{
Field *field=table->field[fieldnr];
char buff[MAX_FIELD_WIDTH];
- String str(buff,sizeof(buff));
+ String str(buff,sizeof(buff),default_charset_info);
field->val_str(&str,&str);
uint length=str.length();
if (!length)
@@ -1106,9 +1139,10 @@ bool check_db_name(const char *name)
while (*name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
+ int len=my_ismbchar(system_charset_info, name,
+ name+system_charset_info->mbmaxlen);
if (len)
{
name += len;
@@ -1121,7 +1155,7 @@ bool check_db_name(const char *name)
return 1;
name++;
}
- return (uint) (name - start) > NAME_LEN;
+ return (uint) (name - start) > NAME_LEN || name == start;
}
@@ -1139,9 +1173,9 @@ bool check_table_name(const char *name, uint length)
while (name != end)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- int len=my_ismbchar(default_charset_info, name, end);
+ int len=my_ismbchar(system_charset_info, name, end);
if (len)
{
name += len;
@@ -1161,9 +1195,10 @@ bool check_column_name(const char *name)
while (*name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
+ int len=my_ismbchar(system_charset_info, name,
+ name+system_charset_info->mbmaxlen);
if (len)
{
name += len;
@@ -1195,7 +1230,7 @@ db_type get_table_type(const char *name)
error=my_read(file,(byte*) head,4,MYF(MY_NABP));
my_close(file,MYF(0));
if (error || head[0] != (uchar) 254 || head[1] != 1 ||
- (head[2] != FRM_VER && head[2] != FRM_VER+1))
+ (head[2] < FRM_VER && head[2] > FRM_VER+2))
DBUG_RETURN(DB_TYPE_UNKNOWN);
DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3)));
}
diff --git a/sql/table.h b/sql/table.h
index f998a0fd4e6..18079e183ce 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -106,6 +106,7 @@ struct st_table {
*rowid_field;
Field_timestamp *timestamp_field;
my_string comment; /* Comment about table */
+ CHARSET_INFO *table_charset; /* Default charset of string fields */
REGINFO reginfo; /* field connections */
MEM_ROOT mem_root;
GRANT_INFO grant;
@@ -128,6 +129,9 @@ struct st_table {
uint temp_pool_slot;
+ /* number of select if it is derived table */
+ uint derived_select_number;
+
THD *in_use; /* Which thread uses this */
struct st_table *next,*prev;
};
@@ -143,9 +147,18 @@ typedef struct st_table_list
Item *on_expr; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
- List<String> *use_index,*ignore_index;
- TABLE *table;
- GRANT_INFO grant;
+ List<String> *use_index, *ignore_index;
+ /*
+ Usually hold reference on opened table, but may hold reference
+ to node of complete list of tables used in UNION & subselect.
+ */
+ union
+ {
+ TABLE *table; /* opened table */
+ st_table_list *table_list; /* pointer to node of list of all tables */
+ };
+ void *derived; /* SELECT_LEX_UNIT of derived table */
+ GRANT_INFO grant;
thr_lock_type lock_type;
uint outer_join; /* Which join type */
uint32 db_length, real_name_length;
@@ -155,7 +168,6 @@ typedef struct st_table_list
bool do_redirect; /* To get the struct in UNION's */
} TABLE_LIST;
-
typedef struct st_changed_table_list
{
struct st_changed_table_list *next;
@@ -163,7 +175,6 @@ typedef struct st_changed_table_list
uint32 key_length;
} CHANGED_TABLE_LIST;
-
typedef struct st_open_table_list
{
struct st_open_table_list *next;
diff --git a/sql/time.cc b/sql/time.cc
index 4fe79966404..0811b896bfc 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -268,13 +268,13 @@ void find_date(string pos,uint *vek,uint flag)
DBUG_PRINT("enter",("pos: '%s' flag: %d",pos,flag));
bzero((char*) vek,sizeof(int)*4);
- while (*pos && !isdigit(*pos))
+ while (*pos && !my_isdigit(system_charset_info,*pos))
pos++;
length=(uint) strlen(pos);
for (uint i=0 ; i< 3; i++)
{
start=pos; value=0;
- while (isdigit(pos[0]) &&
+ while (my_isdigit(system_charset_info,pos[0]) &&
((pos-start) < 2 || ((pos-start) < 4 && length >= 8 &&
!(flag & 3))))
{
@@ -282,7 +282,8 @@ void find_date(string pos,uint *vek,uint flag)
pos++;
}
vek[flag & 3]=value; flag>>=2;
- while (*pos && (ispunct(*pos) || isspace(*pos)))
+ while (*pos && (my_ispunct(system_charset_info,*pos) ||
+ my_isspace(system_charset_info,*pos)))
pos++;
}
DBUG_PRINT("exit",("year: %d month: %d day: %d",vek[0],vek[1],vek[2]));
@@ -417,13 +418,28 @@ ulong convert_month_to_period(ulong month)
}
-/*****************************************************************************
-** convert a timestamp string to a TIME value.
-** At least the following formats are recogniced (based on number of digits)
-** YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS
-** YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS
-** Returns the type of string
-*****************************************************************************/
+/*
+ Convert a timestamp string to a TIME value.
+
+ SYNOPSIS
+ str_to_TIME()
+ str String to parse
+ length Length of string
+ l_time Date is stored here
+ fuzzy_date 1 if we should allow dates where one part is zero
+
+ DESCRIPTION
+ At least the following formats are recogniced (based on number of digits)
+ YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS
+ YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS
+ YYYYMMDDTHHMMSS where T is a the character T (ISO8601)
+ Also dates where all parts are zero are allowed
+
+ RETURN VALUES
+ TIMESTAMP_NONE String wasn't a timestamp
+ TIMESTAMP_DATE DATE string (YY MM and DD parts ok)
+ TIMESTAMP_FULL Full timestamp
+*/
timestamp_type
str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
@@ -435,23 +451,25 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
DBUG_ENTER("str_to_TIME");
DBUG_PRINT("enter",("str: %.*s",length,str));
- for (; str != end && !isdigit(*str) ; str++) ; // Skip garbage
+ // Skip garbage
+ for (; str != end && !my_isdigit(system_charset_info, *str) ; str++) ;
if (str == end)
DBUG_RETURN(TIMESTAMP_NONE);
/*
- ** calculate first number of digits.
- ** If length= 8 or >= 14 then year is of format YYYY.
- (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
+ calculate first number of digits.
+ If length= 8 or >= 14 then year is of format YYYY.
+ (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
*/
- for (pos=str; pos != end && isdigit(*pos) ; pos++) ;
+ for (pos=str; pos != end && my_isdigit(system_charset_info,*pos) ; pos++) ;
digits= (uint) (pos-str);
year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
field_length=year_length-1;
not_zero_date= 0;
- for (i=0 ; i < 6 && str != end && isdigit(*str) ; i++)
+ for (i=0 ; i < 6 && str != end && my_isdigit(system_charset_info,*str) ; i++)
{
uint tmp_value=(uint) (uchar) (*str++ - '0');
- while (str != end && isdigit(str[0]) && field_length--)
+ while (str != end && my_isdigit(system_charset_info,str[0]) &&
+ field_length--)
{
tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
str++;
@@ -462,10 +480,12 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
str++; // ISO8601: CCYYMMDDThhmmss
else if ( i != 5 ) // Skip inter-field delimiters
{
- while (str != end && (ispunct(*str) || isspace(*str)))
+ while (str != end &&
+ (my_ispunct(system_charset_info,*str) ||
+ my_isspace(system_charset_info,*str)))
{
// Only allow space between days and hours
- if (isspace(*str) && i != 2)
+ if (my_isspace(system_charset_info,*str) && i != 2)
DBUG_RETURN(TIMESTAMP_NONE);
str++;
}
@@ -473,12 +493,14 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
field_length=1; // Rest fields can only be 2
}
/* Handle second fractions */
- if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && isdigit(str[1]))
+ if (i == 6 && (uint) (end-str) >= 2 && *str == '.' &&
+ my_isdigit(system_charset_info,str[1]))
{
str++;
uint tmp_value=(uint) (uchar) (*str - '0');
field_length=3;
- while (str++ != end && isdigit(str[0]) && field_length--)
+ while (str++ != end && my_isdigit(system_charset_info,str[0]) &&
+ field_length--)
tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
date[6]=tmp_value;
not_zero_date|= tmp_value;
@@ -500,7 +522,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
{
for (; str != end ; str++)
{
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info, *str))
{
not_zero_date= 1; // Give warning
break;
@@ -515,7 +537,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
{
for (; str != end ; str++)
{
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
{
current_thd->cuted_fields++;
break;
@@ -576,7 +598,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
uint state;
l_time->neg=0;
- for (; str != end && !isdigit(*str) && *str != '-' ; str++)
+ for (; str != end &&
+ !my_isdigit(system_charset_info,*str) && *str != '-' ; str++)
length--;
if (str != end && *str == '-')
{
@@ -595,7 +618,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
}
/* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
- for (value=0; str != end && isdigit(*str) ; str++)
+ for (value=0; str != end && my_isdigit(system_charset_info,*str) ; str++)
value=value*10L + (long) (*str - '0');
if (*str == ' ')
@@ -606,14 +629,16 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
LINT_INIT(state);
found_days=found_hours=0;
- if ((uint) (end-str) > 1 && (*str == ' ' && isdigit(str[1])))
+ if ((uint) (end-str) > 1 && (*str == ' ' &&
+ my_isdigit(system_charset_info,str[1])))
{ // days !
date[0]=value;
state=1; // Assume next is hours
found_days=1;
str++; // Skip space;
}
- else if ((end-str) > 1 && *str == ':' && isdigit(str[1]))
+ else if ((end-str) > 1 && *str == ':' &&
+ my_isdigit(system_charset_info,str[1]))
{
date[0]=0; // Assume we found hours
date[1]=value;
@@ -635,10 +660,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
/* Read hours, minutes and seconds */
for (;;)
{
- for (value=0; str != end && isdigit(*str) ; str++)
+ for (value=0; str != end && my_isdigit(system_charset_info,*str) ; str++)
value=value*10L + (long) (*str - '0');
date[state++]=value;
- if (state == 4 || (end-str) < 2 || *str != ':' || !isdigit(str[1]))
+ if (state == 4 || (end-str) < 2 || *str != ':' ||
+ !my_isdigit(system_charset_info,str[1]))
break;
str++; // Skip ':'
}
@@ -658,11 +684,13 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
fractional:
/* Get fractional second part */
- if ((end-str) >= 2 && *str == '.' && isdigit(str[1]))
+ if ((end-str) >= 2 && *str == '.' && my_isdigit(system_charset_info,str[1]))
{
uint field_length=3;
str++; value=(uint) (uchar) (*str - '0');
- while (++str != end && isdigit(str[0]) && field_length--)
+ while (++str != end &&
+ my_isdigit(system_charset_info,str[0]) &&
+ field_length--)
value=value*10 + (uint) (uchar) (*str - '0');
date[4]=value;
}
@@ -687,7 +715,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
{
do
{
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
{
current_thd->cuted_fields++;
break;
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 60905567ba0..ed256a4b791 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -53,7 +53,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
:max_in_memory_size(max_in_memory_size_arg),elements(0)
{
my_b_clear(&file);
- init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg);
+ init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL,
+ comp_func_fixed_arg);
/* If the following fail's the next add will also fail */
my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16);
max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size);
diff --git a/sql/unireg.cc b/sql/unireg.cc
index cc8440da1e4..81310c4a863 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -28,7 +28,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
-#define FCOMP 11 /* Byte per packat f{lt */
+#define FCOMP 15 /* Bytes for a packed field */
static uchar * pack_screens(List<create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
@@ -46,7 +46,7 @@ static bool make_empty_rec(int file, enum db_type table_type,
uint reclength,uint null_fields);
-int rea_create_table(my_string file_name,
+int rea_create_table(THD *thd, my_string file_name,
HA_CREATE_INFO *create_info,
List<create_field> &create_fields,
uint keys, KEY *key_info)
@@ -67,13 +67,12 @@ int rea_create_table(my_string file_name,
if (pack_header(forminfo, create_info->db_type,create_fields,info_length,
screens, create_info->table_options, db_file))
{
- NET *net=my_pthread_getspecific_ptr(NET*,THR_NET);
my_free((gptr) screen_buff,MYF(0));
- if (net->last_errno != ER_TOO_MANY_FIELDS)
+ if (thd->net.last_errno != ER_TOO_MANY_FIELDS)
DBUG_RETURN(1);
// Try again without UNIREG screens (to get more columns)
- net->last_error[0]=0;
+ thd->net.last_error[0]=0;
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
DBUG_RETURN(1);
if (pack_header(forminfo, create_info->db_type, create_fields,info_length,
@@ -246,7 +245,7 @@ static uchar * pack_screens(List<create_field> &create_fields,
static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
{
uint key_parts,length;
- uchar *pos, *keyname_pos, *key_alg_pos;
+ uchar *pos, *keyname_pos;
KEY *key,*end;
KEY_PART_INFO *key_part,*key_part_end;
DBUG_ENTER("pack_keys");
@@ -255,10 +254,12 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
key_parts=0;
for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++)
{
- pos[0]=(uchar) (key->flags ^ HA_NOSAME);
- int2store(pos+1,key->key_length);
- pos[3]=key->key_parts;
- pos+=4;
+ int2store(pos, (key->flags ^ HA_NOSAME));
+ int2store(pos+2,key->key_length);
+ pos[4]= (uchar) key->key_parts;
+ pos[5]= (uchar) key->algorithm;
+ pos[6]=pos[7]=0; // For the future
+ pos+=8;
key_parts+=key->key_parts;
DBUG_PRINT("loop",("flags: %d key_parts: %d at %lx",
key->flags,key->key_parts,
@@ -290,18 +291,11 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
}
*(pos++)=0;
- /* For MySQL 4.0; Store key algoritms last */
- key_alg_pos= pos;
- for (key=keyinfo ; key != end ; key++)
- {
- *(pos++)= (uchar) key->algorithm;
- }
-
keybuff[0]=(uchar) key_count;
keybuff[1]=(uchar) key_parts;
length=(uint) (keyname_pos-keybuff);
int2store(keybuff+2,length);
- length=(uint) (key_alg_pos-keyname_pos);
+ length=(uint) (pos-keyname_pos);
int2store(keybuff+4,length);
DBUG_RETURN((uint) (pos-keybuff));
} /* pack_keys */
@@ -314,9 +308,9 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
uint info_length, uint screens,uint table_options,
handler *file)
{
- uint length,int_count,int_length,no_empty, int_parts,
- time_stamp_pos,null_fields;
- ulong reclength,totlength,n_length;
+ uint length,int_count,int_length,no_empty, int_parts;
+ uint time_stamp_pos,null_fields;
+ ulong reclength, totlength, n_length, com_length;
DBUG_ENTER("pack_header");
if (create_fields.elements > MAX_FIELDS)
@@ -326,7 +320,8 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
}
totlength=reclength=0L;
- no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=0;
+ no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=
+ com_length=0;
n_length=2L;
/* Check fields */
@@ -336,6 +331,7 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
while ((field=it++))
{
totlength+= field->length;
+ com_length+= field->comment.length;
if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY ||
field->unireg_check & MTYP_NOEMPTY_BIT)
{
@@ -378,14 +374,15 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
/* Hack to avoid bugs with small static rows in MySQL */
reclength=max(file->min_record_length(table_options),reclength);
if (info_length+(ulong) create_fields.elements*FCOMP+288+
- n_length+int_length > 65535L || int_count > 255)
+ n_length+int_length+com_length > 65535L || int_count > 255)
{
my_error(ER_TOO_MANY_FIELDS,MYF(0));
DBUG_RETURN(1);
}
bzero((char*)forminfo,288);
- length=info_length+create_fields.elements*FCOMP+288+n_length+int_length;
+ length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+
+ com_length);
int2store(forminfo,length);
forminfo[256] = (uint8) screens;
int2store(forminfo+258,create_fields.elements);
@@ -401,6 +398,7 @@ static bool pack_header(uchar *forminfo, enum db_type table_type,
int2store(forminfo+278,80); /* Columns needed */
int2store(forminfo+280,22); /* Rows needed */
int2store(forminfo+282,null_fields);
+ int2store(forminfo+284,com_length);
DBUG_RETURN(0);
} /* pack_header */
@@ -438,7 +436,7 @@ static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
static bool pack_fields(File file,List<create_field> &create_fields)
{
reg2 uint i;
- uint int_count;
+ uint int_count, comment_length=0;
uchar buff[MAX_FIELD_WIDTH];
create_field *field;
DBUG_ENTER("pack_fields");
@@ -459,6 +457,10 @@ static bool pack_fields(File file,List<create_field> &create_fields)
int2store(buff+6,field->pack_flag);
int2store(buff+8,field->unireg_check);
buff[10]= (uchar) field->interval_id;
+ buff[11]= (uchar) field->sql_type;
+ buff[12]= (uchar) field->charset->number;
+ int2store(buff+13, field->comment.length);
+ comment_length+= field->comment.length;
set_if_bigger(int_count,field->interval_id);
if (my_write(file,(byte*) buff,FCOMP,MYF_RW))
DBUG_RETURN(1);
@@ -484,7 +486,7 @@ static bool pack_fields(File file,List<create_field> &create_fields)
/* Write intervals */
if (int_count)
{
- String tmp((char*) buff,sizeof(buff));
+ String tmp((char*) buff,sizeof(buff), default_charset_info);
tmp.length(0);
it.rewind();
int_count=0;
@@ -505,6 +507,18 @@ static bool pack_fields(File file,List<create_field> &create_fields)
if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW))
DBUG_RETURN(1);
}
+ if (comment_length)
+ {
+ it.rewind();
+ int_count=0;
+ while ((field=it++))
+ {
+ if (field->comment.length)
+ if (my_write(file, (byte*) field->comment.str, field->comment.length,
+ MYF_RW))
+ DBUG_RETURN(1);
+ }
+ }
DBUG_RETURN(0);
}
@@ -558,10 +572,12 @@ static bool make_empty_rec(File file,enum db_type table_type,
1 << (null_count & 7),
field->pack_flag,
field->sql_type,
+ field->charset,
field->unireg_check,
field->interval,
field->field_name,
&table);
+
if (!(field->flags & NOT_NULL_FLAG))
null_count++;
@@ -574,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))
- field->def->save_in_field(regfield);
+ (void) field->def->save_in_field(regfield);
else if (regfield->real_type() == FIELD_TYPE_ENUM &&
(field->flags & NOT_NULL_FLAG))
{
@@ -582,9 +598,9 @@ static bool make_empty_rec(File file,enum db_type table_type,
regfield->store((longlong) 1);
}
else if (type == Field::YES) // Old unireg type
- regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)));
+ regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),default_charset_info);
else if (type == Field::NO) // Old unireg type
- regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)));
+ regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),default_charset_info);
else
regfield->reset();
delete regfield;
diff --git a/sql/unireg.h b/sql/unireg.h
index eec89fcee0f..724ff3f6197 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -63,6 +63,8 @@
#define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD)
#define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD)
+#define DEFAULT_ERROR_COUNT 64
+#define DEFAULT_PREP_STMT_COUNT 64
#define EXTRA_RECORDS 10 /* Extra records in sort */
#define SCROLL_EXTRA 5 /* Extra scroll-rows. */
#define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */