summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am24
-rw-r--r--sql/convert.cc7
-rw-r--r--sql/des_key_file.cc7
-rw-r--r--sql/field.cc1834
-rw-r--r--sql/field.h367
-rw-r--r--sql/field_conv.cc21
-rw-r--r--sql/filesort.cc140
-rw-r--r--sql/gen_lex_hash.cc764
-rw-r--r--sql/gstream.cc139
-rw-r--r--sql/gstream.h69
-rw-r--r--sql/ha_berkeley.cc97
-rw-r--r--sql/ha_berkeley.h2
-rw-r--r--sql/ha_heap.cc230
-rw-r--r--sql/ha_heap.h6
-rw-r--r--sql/ha_innodb.cc150
-rw-r--r--sql/ha_innodb.h3
-rw-r--r--sql/ha_myisam.cc62
-rw-r--r--sql/ha_myisam.h2
-rw-r--r--sql/ha_myisammrg.cc10
-rw-r--r--sql/ha_myisammrg.h9
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/handler.h20
-rw-r--r--sql/hash_filo.h11
-rw-r--r--sql/hostname.cc7
-rw-r--r--sql/init.cc11
-rw-r--r--sql/item.cc1013
-rw-r--r--sql/item.h542
-rw-r--r--sql/item_buff.cc6
-rw-r--r--sql/item_cmpfunc.cc921
-rw-r--r--sql/item_cmpfunc.h514
-rw-r--r--sql/item_create.cc203
-rw-r--r--sql/item_create.h44
-rw-r--r--sql/item_func.cc608
-rw-r--r--sql/item_func.h297
-rw-r--r--sql/item_row.cc131
-rw-r--r--sql/item_row.h79
-rw-r--r--sql/item_strfunc.cc911
-rw-r--r--sql/item_strfunc.h370
-rw-r--r--sql/item_subselect.cc869
-rw-r--r--sql/item_subselect.h267
-rw-r--r--sql/item_sum.cc293
-rw-r--r--sql/item_sum.h207
-rw-r--r--sql/item_timefunc.cc267
-rw-r--r--sql/item_timefunc.h274
-rw-r--r--sql/item_uniq.h15
-rw-r--r--sql/key.cc8
-rw-r--r--sql/lex.h92
-rw-r--r--sql/lock.cc12
-rw-r--r--sql/log.cc183
-rw-r--r--sql/log_event.cc2903
-rw-r--r--sql/log_event.h231
-rw-r--r--sql/mf_iocache.cc5
-rw-r--r--sql/mini_client.cc139
-rw-r--r--sql/mysql_priv.h271
-rw-r--r--sql/mysqld.cc1136
-rw-r--r--sql/net_pkg.cc401
-rw-r--r--sql/net_serv.cc113
-rw-r--r--sql/nt_servc.cc32
-rw-r--r--sql/opt_range.cc262
-rw-r--r--sql/opt_range.h9
-rw-r--r--sql/opt_sum.cc895
-rw-r--r--sql/password.c569
-rw-r--r--sql/procedure.cc3
-rw-r--r--sql/procedure.h44
-rw-r--r--sql/protocol.cc1109
-rw-r--r--sql/protocol.h144
-rw-r--r--sql/repl_failsafe.cc93
-rw-r--r--sql/repl_failsafe.h2
-rw-r--r--sql/set_var.cc254
-rw-r--r--sql/set_var.h72
-rw-r--r--sql/share/Makefile.am5
-rw-r--r--sql/share/charsets/Index38
-rw-r--r--sql/share/charsets/Index.xml497
-rw-r--r--sql/share/charsets/MacCE.xml189
-rw-r--r--sql/share/charsets/MacRoman.xml182
-rw-r--r--sql/share/charsets/armscii8.xml121
-rw-r--r--sql/share/charsets/ascii.xml121
-rw-r--r--sql/share/charsets/cp1250.xml (renamed from sql/share/charsets/win1250.conf)59
-rw-r--r--sql/share/charsets/cp1251.conf74
-rw-r--r--sql/share/charsets/cp1251.xml197
-rw-r--r--sql/share/charsets/cp1256.xml124
-rw-r--r--sql/share/charsets/cp1257.conf74
-rw-r--r--sql/share/charsets/cp1257.xml210
-rw-r--r--sql/share/charsets/cp866.xml124
-rw-r--r--sql/share/charsets/croat.conf74
-rw-r--r--sql/share/charsets/danish.conf74
-rw-r--r--sql/share/charsets/dec8.conf74
-rw-r--r--sql/share/charsets/dec8.xml (renamed from sql/share/charsets/latin1.conf)58
-rw-r--r--sql/share/charsets/dos.conf74
-rw-r--r--sql/share/charsets/estonia.conf74
-rw-r--r--sql/share/charsets/german1.conf74
-rw-r--r--sql/share/charsets/greek.conf74
-rw-r--r--sql/share/charsets/greek.xml122
-rw-r--r--sql/share/charsets/hebrew.conf74
-rw-r--r--sql/share/charsets/hebrew.xml122
-rw-r--r--sql/share/charsets/hp8.conf74
-rw-r--r--sql/share/charsets/hp8.xml122
-rw-r--r--sql/share/charsets/hungarian.conf74
-rw-r--r--sql/share/charsets/keybcs2.xml122
-rw-r--r--sql/share/charsets/koi8_ru.conf74
-rw-r--r--sql/share/charsets/koi8r.xml121
-rw-r--r--sql/share/charsets/koi8u.xml (renamed from sql/share/charsets/koi8_ukr.conf)58
-rw-r--r--sql/share/charsets/latin1.xml214
-rw-r--r--sql/share/charsets/latin2.conf74
-rw-r--r--sql/share/charsets/latin2.xml168
-rw-r--r--sql/share/charsets/latin5.conf78
-rw-r--r--sql/share/charsets/latin5.xml126
-rw-r--r--sql/share/charsets/latin7.xml169
-rw-r--r--sql/share/charsets/pclatin1.xml121
-rw-r--r--sql/share/charsets/pclatin2.xml119
-rw-r--r--sql/share/charsets/swe7.xml (renamed from sql/share/charsets/swe7.conf)59
-rw-r--r--sql/share/charsets/usa7.conf74
-rw-r--r--sql/share/charsets/win1251.conf82
-rw-r--r--sql/share/charsets/win1251ukr.conf77
-rw-r--r--sql/share/czech/errmsg.txt27
-rw-r--r--sql/share/danish/errmsg.txt23
-rw-r--r--sql/share/dutch/errmsg.txt23
-rw-r--r--sql/share/english/errmsg.txt25
-rw-r--r--sql/share/estonian/errmsg.txt23
-rw-r--r--sql/share/french/errmsg.txt23
-rw-r--r--sql/share/german/errmsg.txt198
-rw-r--r--sql/share/greek/errmsg.txt25
-rw-r--r--sql/share/hungarian/errmsg.txt25
-rw-r--r--sql/share/italian/errmsg.txt23
-rw-r--r--sql/share/japanese/errmsg.txt25
-rw-r--r--sql/share/korean/errmsg.txt25
-rw-r--r--sql/share/norwegian-ny/errmsg.txt25
-rw-r--r--sql/share/norwegian/errmsg.txt25
-rw-r--r--sql/share/polish/errmsg.txt25
-rw-r--r--sql/share/portuguese/errmsg.txt23
-rw-r--r--sql/share/romanian/errmsg.txt25
-rw-r--r--sql/share/russian/errmsg.txt21
-rw-r--r--sql/share/serbian/errmsg.txt253
-rw-r--r--sql/share/slovak/errmsg.txt25
-rw-r--r--sql/share/spanish/errmsg.txt23
-rw-r--r--sql/share/swedish/errmsg.txt43
-rw-r--r--sql/share/ukrainian/errmsg.txt23
-rw-r--r--sql/slave.cc345
-rw-r--r--sql/slave.h101
-rw-r--r--sql/spatial.cc1570
-rw-r--r--sql/spatial.h501
-rw-r--r--sql/sql_acl.cc812
-rw-r--r--sql/sql_acl.h52
-rw-r--r--sql/sql_analyse.cc103
-rw-r--r--sql/sql_analyse.h57
-rw-r--r--sql/sql_base.cc503
-rw-r--r--sql/sql_cache.cc78
-rw-r--r--sql/sql_class.cc322
-rw-r--r--sql/sql_class.h338
-rw-r--r--sql/sql_db.cc407
-rw-r--r--sql/sql_delete.cc92
-rw-r--r--sql/sql_derived.cc226
-rw-r--r--sql/sql_do.cc4
-rw-r--r--sql/sql_error.cc195
-rw-r--r--sql/sql_handler.cc60
-rw-r--r--sql/sql_help.cc519
-rw-r--r--sql/sql_insert.cc163
-rw-r--r--sql/sql_lex.cc870
-rw-r--r--sql/sql_lex.h404
-rw-r--r--sql/sql_list.h33
-rw-r--r--sql/sql_load.cc42
-rw-r--r--sql/sql_olap.cc18
-rw-r--r--sql/sql_parse.cc1683
-rw-r--r--sql/sql_prepare.cc974
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_repl.cc178
-rw-r--r--sql/sql_repl.h5
-rw-r--r--sql/sql_select.cc2208
-rw-r--r--sql/sql_select.h116
-rw-r--r--sql/sql_show.cc1118
-rw-r--r--sql/sql_sort.h2
-rw-r--r--sql/sql_string.cc535
-rw-r--r--sql/sql_string.h149
-rw-r--r--sql/sql_table.cc571
-rw-r--r--sql/sql_test.cc130
-rw-r--r--sql/sql_udf.cc105
-rw-r--r--sql/sql_udf.h7
-rw-r--r--sql/sql_union.cc490
-rw-r--r--sql/sql_update.cc98
-rw-r--r--sql/sql_yacc.yy2095
-rw-r--r--sql/stacktrace.c6
-rw-r--r--sql/structs.h8
-rw-r--r--sql/table.cc124
-rw-r--r--sql/table.h25
-rw-r--r--sql/thr_malloc.cc2
-rw-r--r--sql/time.cc147
-rw-r--r--sql/udf_example.cc55
-rw-r--r--sql/unireg.cc84
-rw-r--r--sql/unireg.h11
189 files changed, 33661 insertions, 11780 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index a589f1379f9..b1d9149ddf4 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -22,9 +22,8 @@ MYSQLSHAREdir = $(pkgdatadir)
MYSQLBASEdir= $(prefix)
INCLUDES = @MT_INCLUDES@ \
@bdb_includes@ @innodb_includes@ \
- -I$(srcdir)/../include \
- -I$(srcdir)/../regex \
- -I$(srcdir) -I../include -I. $(openssl_includes)
+ -I$(top_srcdir)/include -I$(top_srcdir)/regex \
+ -I$(srcdir) $(openssl_includes)
WRAPLIBS= @WRAPLIBS@
SUBDIRS = share
libexec_PROGRAMS = mysqld
@@ -46,27 +45,31 @@ 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 item_row.h \
+ mysql_priv.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
field.h handler.h \
ha_isammrg.h ha_isam.h ha_myisammrg.h\
ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \
- opt_range.h opt_ft.h \
+ opt_range.h opt_ft.h protocol.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 \
+ item_row.cc \
field.cc key.cc sql_class.cc sql_list.cc \
- net_serv.cc net_pkg.cc lock.cc my_lock.c \
+ net_serv.cc protocol.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 +82,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..84003af3922 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -433,7 +433,7 @@ CONVERT *get_convert_set(const char *name)
{
for (CONVERT **ptr=convert_tables ; *ptr ; ptr++)
{
- if (!my_strcasecmp((*ptr)->name,name))
+ if (!my_strcasecmp(&my_charset_latin1,(*ptr)->name,name))
return (*ptr);
}
return 0;
@@ -457,9 +457,6 @@ bool CONVERT::store(String *packet,const char *from,uint length)
return 1;
char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
(ulonglong)length);
-
- for (const char *end=from+length ; from != end ; from++)
- *to++= to_map[(uchar) *from];
- packet->length((uint) (to-packet->ptr()));
+ packet->length((uint) (store_dest(to, from, length)-packet->ptr()));
return 0;
}
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index 891cf18ee53..5b25819b657 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -34,6 +34,8 @@ static int initialized;
1 Error
*/
+#define des_cs &my_charset_latin1
+
bool
load_des_key_file(const char *file_name)
{
@@ -70,9 +72,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(des_cs, *start) ; start++) ;
end=buf+length;
- for (end=strend(buf) ; end > start && !isgraph(end[-1]) ; end--) ;
+ for (end=strend(buf) ;
+ end > start && !my_isgraph(des_cs, end[-1]) ; end--) ;
if (start != end)
{
diff --git a/sql/field.cc b/sql/field.cc
index ce5e240aba8..0c17209003c 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -15,16 +15,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/*
- NOTES:
- Some of the number class uses the system functions strtol(), strtoll()...
- To avoid patching the end \0 or copying the buffer unnecessary, all calls
- to system functions are wrapped to a String object that adds the end null
- if it only if it isn't there.
- This adds some overhead when assigning numbers from strings but makes
- everything simpler.
- */
-
/*****************************************************************************
** This file implements classes defined in field.h
*****************************************************************************/
@@ -44,8 +34,6 @@
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024
-
-
/*****************************************************************************
Instansiate templates and static variables
*****************************************************************************/
@@ -77,44 +65,54 @@ void Field_num::prepend_zeros(String *value)
/*
Test if given number is a int (or a fixed format float with .000)
- This is only used to give warnings in ALTER TABLE or LOAD DATA...
+
+ SYNOPSIS
+ test_if_int()
+ str String to test
+ end Pointer to char after last used digit
+ cs Character set
+
+ NOTES
+ This is called after one has called my_strntol() or similar function.
+ This is only used to give warnings in ALTER TABLE or LOAD DATA...
+
+ TODO
+ Make this multi-byte-character safe
+
+ RETURN
+ 0 ok
+ 1 error
*/
-bool test_if_int(const char *str,int length)
+bool test_if_int(const char *str, int length, const char *int_end,
+ CHARSET_INFO *cs)
{
+ if (str == int_end)
+ return 0; // Empty string
const char *end=str+length;
+ if ((str= int_end) == end)
+ return 1; // All digits was used
- while (str != end && isspace(*str)) // Allow start space
- str++; /* purecov: inspected */
- if (str != end && (*str == '-' || *str == '+'))
- str++;
- if (str == end)
- return 0; // Error: Empty string
- for (; str != end ; str++)
+ /* Allow end .0000 */
+ if (*str == '.')
{
- if (!isdigit(*str))
- {
- if (*str == '.')
- { // Allow '.0000'
- for (str++ ; str != end && *str == '0'; str++) ;
- if (str == end)
- return 1;
- }
- if (!isspace(*str))
- return 0;
- for (str++ ; str != end ; str++)
- if (!isspace(*str))
- return 0;
- return 1;
- }
+ for (str++ ; str != end && *str == '0'; str++) ;
+ }
+ /* Allow end space */
+ for (str++ ; str != end ; str++)
+ {
+ if (!my_isspace(cs,*str))
+ return 0;
}
return 1;
}
-static bool test_if_real(const char *str,int length)
+static bool test_if_real(const char *str,int length, CHARSET_INFO *cs)
{
- while (length && isspace(*str))
+ cs= system_charset_info; // QQ move test_if_real into CHARSET_INFO struct
+
+ while (length && my_isspace(cs,*str))
{ // Allow start space
length--; str++;
}
@@ -123,10 +121,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(cs,*str) || *str == '.'))
return 0;
}
- while (length && isdigit(*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
@@ -135,7 +133,7 @@ static bool test_if_real(const char *str,int length)
if (*str == '.')
{
length--; str++;
- while (length && isdigit(*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
@@ -144,18 +142,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(cs,str[2]))
return 0;
length-=3;
str+=3;
- while (length && isdigit(*str))
+ while (length && my_isdigit(cs,*str))
{
length--; str++;
}
}
for (; length ; length--, str++)
{ // Allow end space
- if (!isspace(*str))
+ if (!my_isspace(cs,*str))
return 0;
}
return 1;
@@ -179,6 +178,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()
@@ -198,23 +199,17 @@ void Field::copy_from_tmp(int row_offset)
}
-bool Field::send(THD *thd, String *packet)
+bool Field::send_binary(Protocol *protocol)
{
- if (is_null())
- return net_store_null(packet);
char buff[MAX_FIELD_WIDTH];
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff),charset());
val_str(&tmp,&tmp);
- CONVERT *convert;
- if ((convert=thd->variables.convert_set))
- return convert->store(packet,tmp.ptr(),tmp.length());
- return net_store_data(packet,tmp.ptr(),tmp.length());
+ return protocol->store(tmp.ptr(), tmp.length(), tmp.charset());
}
void Field_num::add_zerofill_and_unsigned(String &res) const
{
- res.length((uint) strlen(res.ptr())); // Fix length
if (unsigned_flag)
res.append(" unsigned");
if (zerofill)
@@ -223,8 +218,12 @@ 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->charsetnr= charset()->number;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
@@ -234,8 +233,12 @@ 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->charsetnr= charset()->number;
field->length=field_length;
field->type=type();
field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
@@ -243,6 +246,26 @@ void Field_str::make_field(Send_field *field)
}
+void Field_str::add_binary_or_charset(String &res) const
+{
+ if (charset() == &my_charset_bin)
+ res.append(" binary");
+ else if (field_charset != table->table_charset &&
+ !(current_thd->variables.sql_mode & MODE_NO_FIELD_OPTIONS) &&
+ !(current_thd->variables.sql_mode & MODE_MYSQL323) &&
+ !(current_thd->variables.sql_mode & MODE_MYSQL40) &&
+ !(current_thd->variables.sql_mode & MODE_POSTGRESQL) &&
+ !(current_thd->variables.sql_mode & MODE_ORACLE) &&
+ !(current_thd->variables.sql_mode & MODE_MSSQL) &&
+ !(current_thd->variables.sql_mode & MODE_DB2) &&
+ !(current_thd->variables.sql_mode & MODE_SAPDB))
+ {
+ res.append(" character set ");
+ res.append(field_charset->csname);
+ }
+}
+
+
uint Field::fill_cache_field(CACHE_FIELD *copy)
{
copy->str=ptr;
@@ -266,7 +289,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),&my_charset_bin),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
return 1;
@@ -276,7 +299,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),&my_charset_bin),tmp2,*res;
if (!(res=val_str(&tmp,&tmp2)) ||
str_to_time(res->ptr(),res->length(),ltime))
return 1;
@@ -290,24 +313,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,&my_charset_bin); // Probably an error
break;
case TIMESTAMP_DATE:
sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day);
- store(buff,10);
+ store(buff,10,&my_charset_bin);
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,&my_charset_bin);
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, &my_charset_bin);
break;
}
+ }
}
@@ -317,6 +342,16 @@ bool Field::optimize_range(uint idx)
}
/****************************************************************************
+ Field_null, a field that always return NULL
+****************************************************************************/
+
+void Field_null::sql_type(String &res) const
+{
+ res.set_latin1("null", 4);
+}
+
+
+/****************************************************************************
Functions for the Field_decimal class
This is an number stored as a pre-space (or pre-zero) string
****************************************************************************/
@@ -324,7 +359,7 @@ bool Field::optimize_range(uint idx)
void
Field_decimal::reset(void)
{
- Field_decimal::store("0",1);
+ Field_decimal::store("0",1,&my_charset_bin);
}
void Field_decimal::overflow(bool negative)
@@ -366,8 +401,19 @@ 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)
{
+ char buff[80];
+ String tmp(buff,sizeof(buff), &my_charset_bin);
+
+ /* Convert character set if the old one is multi byte */
+ if (cs->mbmaxlen > 1)
+ {
+ tmp.copy(from, len, cs, &my_charset_bin);
+ from= tmp.ptr();
+ len= tmp.length();
+ }
+
const char *end= from+len;
/* The pointer where the field value starts (i.e., "where to write") */
char *to=ptr;
@@ -377,13 +423,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 +439,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 +463,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(&my_charset_bin,*from))
+ from++;
if (from == end)
{
current_thd->cuted_fields++;
@@ -445,11 +493,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 +510,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(&my_charset_bin, *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(&my_charset_bin, *from); from++) ;
frac_digits_end=from;
// Some exponentiation symbol ?
if (from != end && (*from == 'e' || *from == 'E'))
@@ -484,7 +532,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(&my_charset_bin, *from); from++)
{
exponent=10*exponent+(*from-'0');
if (exponent>MAX_EXPONENT)
@@ -501,7 +549,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(&my_charset_bin, *from); from++) ;
if (from != end) // If still something left, warn
{
current_thd->cuted_fields++;
@@ -513,21 +562,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 +638,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 +719,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 +732,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 +749,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 +758,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 +786,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,40 +835,40 @@ void Field_decimal::store(longlong nr)
to[length]='.';
bfill(to+length+1,dec,'0');
}
+ return 0;
}
}
double Field_decimal::val_real(void)
{
- char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
- double nr=atod(ptr);
- *(ptr+field_length)=temp;
- return(nr);
+ int not_used;
+ return my_strntod(&my_charset_bin, ptr, field_length, NULL, &not_used);
}
longlong Field_decimal::val_int(void)
{
- char temp= *(ptr+field_length); *(ptr+field_length) = '\0';
- longlong nr;
+ int not_used;
if (unsigned_flag)
- nr=(longlong) strtoull(ptr,NULL,10);
+ return my_strntoull(&my_charset_bin, ptr, field_length, 10, NULL,
+ &not_used);
else
- nr=strtoll(ptr,NULL,10);
- *(ptr+field_length)=temp;
- return(nr);
+ return my_strntoll(&my_charset_bin, ptr, field_length, 10, NULL,
+ &not_used);
}
+
String *Field_decimal::val_str(String *val_buffer __attribute__((unused)),
String *val_ptr)
{
char *str;
for (str=ptr ; *str == ' ' ; str++) ;
uint tmp_length=(uint) (str-ptr);
+ val_ptr->set_charset(&my_charset_bin);
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_latin1((const char*) str, field_length-tmp_length);
return val_ptr;
}
@@ -829,8 +885,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(&my_charset_bin,*a_ptr) || *a_ptr == '+' ||
+ *a_ptr == '0') &&
+ (my_isspace(&my_charset_bin,*b_ptr) || *b_ptr == '+' ||
+ *b_ptr == '0')));
a_ptr++,b_ptr++)
{
if (*a_ptr == '-') // If both numbers are negative
@@ -857,8 +915,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(&my_charset_bin,*str) || *str == '+' ||
+ *str == '0')) ;
str++)
*to++=' ';
if (str == end)
@@ -869,7 +927,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(&my_charset_bin,*str))
*to++= (char) ('9' - *str++);
else
*to++= *str++;
@@ -877,14 +935,17 @@ void Field_decimal::sort_string(char *to,uint length)
else memcpy(to,str,(uint) (end-str));
}
+
void Field_decimal::sql_type(String &res) const
{
+ CHARSET_INFO *cs=res.charset();
uint tmp=field_length;
if (!unsigned_flag)
tmp--;
if (dec)
tmp--;
- sprintf((char*) res.ptr(),"decimal(%d,%d)",tmp,dec);
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "decimal(%d,%d)",tmp,dec));
add_zerofill_and_unsigned(res);
}
@@ -893,10 +954,12 @@ 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);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
+ int error= 0;
if (unsigned_flag)
{
@@ -904,14 +967,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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
else
{
@@ -919,21 +987,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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
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 +1016,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 +1033,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 +1073,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;
}
@@ -1019,19 +1105,27 @@ longlong Field_tiny::val_int(void)
String *Field_tiny::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,5));
+ uint mlength=max(field_length+1,5*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
+
if (unsigned_flag)
- length= (uint) (int10_to_str((long) *((uchar*) ptr),to,10)-to);
+ length= (uint) cs->long10_to_str(cs,to,mlength, 10,(long) *((uchar*) ptr));
else
- length= (uint) (int10_to_str((long) *((signed char*) ptr),to,-10)-to);
+ length= (uint) cs->long10_to_str(cs,to,mlength,-10,(long) *((signed char*) ptr));
+
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
return val_buffer;
}
+bool Field_tiny::send_binary(Protocol *protocol)
+{
+ return protocol->store_tiny((longlong) (int8) ptr[0]);
+}
int Field_tiny::cmp(const char *a_ptr, const char *b_ptr)
{
@@ -1052,36 +1146,42 @@ void Field_tiny::sort_string(char *to,uint length __attribute__((unused)))
void Field_tiny::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"tinyint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "tinyint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
/****************************************************************************
-** short int
+ Field type short int (2 byte)
****************************************************************************/
-
-// 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);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
+ 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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
else
{
@@ -1089,14 +1189,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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1106,11 +1211,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 +1226,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 +1243,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 +1262,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 +1275,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 +1292,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 +1311,7 @@ void Field_short::store(longlong nr)
else
#endif
shortstore(ptr,res);
+ return error;
}
@@ -1221,11 +1339,14 @@ longlong Field_short::val_int(void)
return unsigned_flag ? (longlong) (unsigned short) j : (longlong) j;
}
+
String *Field_short::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,7));
+ uint mlength=max(field_length+1,7*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
short j;
#ifdef WORDS_BIGENDIAN
@@ -1236,9 +1357,9 @@ String *Field_short::val_str(String *val_buffer,
shortget(j,ptr);
if (unsigned_flag)
- length=(uint) (int10_to_str((long) (uint16) j,to,10)-to);
+ length=(uint) cs->long10_to_str(cs, to, mlength, 10, (long) (uint16) j);
else
- length=(uint) (int10_to_str((long) j,to,-10)-to);
+ length=(uint) cs->long10_to_str(cs, to, mlength,-10, (long) j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1246,6 +1367,12 @@ String *Field_short::val_str(String *val_buffer,
}
+bool Field_short::send_binary(Protocol *protocol)
+{
+ return protocol->store_short(Field_short::val_int());
+}
+
+
int Field_short::cmp(const char *a_ptr, const char *b_ptr)
{
short a,b;
@@ -1292,22 +1419,23 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused)))
void Field_short::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"smallint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "smallint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
/****************************************************************************
-** medium int
+ Field type medium int (3 byte)
****************************************************************************/
-// 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);
- long tmp= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long tmp= my_strntol(cs, from, len, 10, &end, &not_used);
+ int error= 0;
if (unsigned_flag)
{
@@ -1315,14 +1443,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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
current_thd->cuted_fields++;
+ error= 1;
+ }
}
else
{
@@ -1330,22 +1463,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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
+ {
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 +1493,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 +1512,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 +1555,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;
}
@@ -1426,21 +1577,25 @@ double Field_medium::val_real(void)
return (double) j;
}
+
longlong Field_medium::val_int(void)
{
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
return (longlong) j;
}
+
String *Field_medium::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,10));
+ uint mlength=max(field_length+1,10*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr);
- length=(uint) (int10_to_str(j,to,-10)-to);
+ length=(uint) cs->long10_to_str(cs,to,mlength,-10,j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer); /* purecov: inspected */
@@ -1448,6 +1603,12 @@ String *Field_medium::val_str(String *val_buffer,
}
+bool Field_medium::send_binary(Protocol *protocol)
+{
+ return protocol->store_long(Field_medium::val_int());
+}
+
+
int Field_medium::cmp(const char *a_ptr, const char *b_ptr)
{
long a,b;
@@ -1477,7 +1638,9 @@ void Field_medium::sort_string(char *to,uint length __attribute__((unused)))
void Field_medium::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"mediumint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "mediumint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
@@ -1486,36 +1649,35 @@ 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)
{
- char *end;
- while (len && isspace(*from))
- {
- len--; from++;
- }
long tmp;
- String tmp_str(from,len);
- from= tmp_str.c_ptr(); // Add end null if needed
- errno=0;
+ int error= 0;
+ char *end;
+
+ tmp= cs->scan(cs, from, from+len, MY_SEQ_SPACES);
+ len-= tmp;
+ from+= tmp;
+ my_errno=0;
if (unsigned_flag)
{
if (!len || *from == '-')
{
tmp=0; // Set negative to 0
- errno=ERANGE;
+ my_errno=ERANGE;
+ error= 1;
}
else
- tmp=(long) strtoul(from, &end, 10);
+ tmp=(long) my_strntoul(cs,from,len,10,&end,&error);
}
else
- tmp=strtol(from, &end, 10);
- if (errno ||
+ tmp=my_strntol(cs,from,len,10,&end,&error);
+ if (error ||
(from+len != end && current_thd->count_cuted_fields &&
- !test_if_int(from,len)))
+ !test_if_int(from,len,end,cs)))
+ {
current_thd->cuted_fields++;
+ }
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
{
@@ -1524,11 +1686,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)
@@ -1537,11 +1701,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;
@@ -1552,11 +1718,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;
@@ -1569,11 +1737,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)
{
@@ -1581,11 +1751,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;
@@ -1596,11 +1768,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;
@@ -1613,6 +1787,7 @@ void Field_long::store(longlong nr)
else
#endif
longstore(ptr,res);
+ return error;
}
@@ -1643,8 +1818,10 @@ longlong Field_long::val_int(void)
String *Field_long::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,12));
+ uint mlength=max(field_length+1,12*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
int32 j;
#ifdef WORDS_BIGENDIAN
@@ -1654,9 +1831,10 @@ String *Field_long::val_str(String *val_buffer,
#endif
longget(j,ptr);
- length=(uint) (int10_to_str((unsigned_flag ? (long) (uint32) j : (long) j),
- to,
- unsigned_flag ? 10 : -10)-to);
+ if (unsigned_flag)
+ length=cs->long10_to_str(cs,to,mlength, 10,(long) (uint32)j);
+ else
+ length=cs->long10_to_str(cs,to,mlength,-10,(long) j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1664,6 +1842,11 @@ String *Field_long::val_str(String *val_buffer,
}
+bool Field_long::send_binary(Protocol *protocol)
+{
+ return protocol->store_long(Field_long::val_int());
+}
+
int Field_long::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -1713,40 +1896,42 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused)))
void Field_long::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"int(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "int(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
/****************************************************************************
-** longlong int
+ Field type longlong int (8 bytes)
****************************************************************************/
-void Field_longlong::store(const char *from,uint len)
+int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs)
{
- char *end;
- while (len && isspace(*from))
- { // For easy error check
- len--; from++;
- }
longlong tmp;
- String tmp_str(from,len);
- from= tmp_str.c_ptr(); // Add end null if needed
- errno=0;
+ int error= 0;
+ char *end;
+
+ tmp= cs->scan(cs, from, from+len, MY_SEQ_SPACES);
+ len-= (uint)tmp;
+ from+= tmp;
+ my_errno=0;
if (unsigned_flag)
{
if (!len || *from == '-')
{
tmp=0; // Set negative to 0
- errno=ERANGE;
+ my_errno= ERANGE;
+ error= 1;
}
else
- tmp=(longlong) strtoull(from, &end, 10);
+ tmp=(longlong) my_strntoull(cs,from,len,10,&end,&error);
}
else
- tmp=strtoll(from, &end, 10);
- if (errno ||
+ tmp=my_strntoll(cs,from,len,10,&end,&error);
+ if (error ||
(from+len != end && current_thd->count_cuted_fields &&
- !test_if_int(from,len)))
+ !test_if_int(from,len,end,cs)))
current_thd->cuted_fields++;
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -1756,11 +1941,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)
@@ -1769,11 +1956,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;
@@ -1784,11 +1973,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;
@@ -1801,10 +1992,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)
@@ -1814,6 +2006,7 @@ void Field_longlong::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
+ return 0;
}
@@ -1847,8 +2040,10 @@ longlong Field_longlong::val_int(void)
String *Field_longlong::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ CHARSET_INFO *cs= &my_charset_bin;
uint length;
- val_buffer->alloc(max(field_length+1,22));
+ uint mlength=max(field_length+1,22*cs->mbmaxlen);
+ val_buffer->alloc(mlength);
char *to=(char*) val_buffer->ptr();
longlong j;
#ifdef WORDS_BIGENDIAN
@@ -1858,7 +2053,8 @@ String *Field_longlong::val_str(String *val_buffer,
#endif
longlongget(j,ptr);
- length=(uint) (longlong10_to_str(j,to,unsigned_flag ? 10 : -10)-to);
+ length=(uint) (cs->longlong10_to_str)(cs,to,mlength,
+ unsigned_flag ? 10 : -10, j);
val_buffer->length(length);
if (zerofill)
prepend_zeros(val_buffer);
@@ -1866,6 +2062,12 @@ String *Field_longlong::val_str(String *val_buffer,
}
+bool Field_longlong::send_binary(Protocol *protocol)
+{
+ return protocol->store_longlong(Field_longlong::val_int(), unsigned_flag);
+}
+
+
int Field_longlong::cmp(const char *a_ptr, const char *b_ptr)
{
longlong a,b;
@@ -1924,7 +2126,9 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused)))
void Field_longlong::sql_type(String &res) const
{
- sprintf((char*) res.ptr(),"bigint(%d)",(int) field_length);
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "bigint(%d)",(int) field_length));
add_zerofill_and_unsigned(res);
}
@@ -1932,35 +2136,42 @@ 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);
- errno=0;
- Field_float::store(atof(tmp_str.c_ptr()));
- if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
+ int err;
+ Field_float::store(my_strntod(cs,(char*) from,len,(char**)NULL,&err));
+ if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
+ {
current_thd->cuted_fields++;
+ return 1;
+ }
+ return (err) ? 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;
@@ -1972,16 +2183,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)
@@ -1991,6 +2205,7 @@ void Field_float::store(longlong nr)
else
#endif
memcpy_fixed(ptr,(byte*) &j,sizeof(j));
+ return error;
}
@@ -2090,10 +2305,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
@@ -2169,12 +2384,24 @@ void Field_float::sort_string(char *to,uint length __attribute__((unused)))
}
+bool Field_float::send_binary(Protocol *protocol)
+{
+ return protocol->store((float) Field_float::val_real(), dec, (String*) 0);
+}
+
+
void Field_float::sql_type(String &res) const
{
if (dec == NOT_FIXED_DEC)
- strmov((char*) res.ptr(),"float");
+ {
+ res.set_latin1("float", 5);
+ }
else
- sprintf((char*) res.ptr(),"float(%d,%d)",(int) field_length,dec);
+ {
+ CHARSET_INFO *cs= res.charset();
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "float(%d,%d)",(int) field_length,dec));
+ }
add_zerofill_and_unsigned(res);
}
@@ -2182,17 +2409,19 @@ 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);
- errno=0;
- double j= atof(tmp_str.c_ptr());
- if (errno || current_thd->count_cuted_fields && !test_if_real(from,len))
+ int err;
+ double j= my_strntod(cs,(char*) from,len,(char**)0,&err);
+ if (err || current_thd->count_cuted_fields && !test_if_real(from,len,cs))
+ {
current_thd->cuted_fields++;
+ }
if (unsigned_flag && j < 0)
{
current_thd->cuted_fields++;
j=0;
+ err= 1;
}
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2202,17 +2431,20 @@ void Field_double::store(const char *from,uint len)
else
#endif
doublestore(ptr,j);
+ return err;
}
-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)
@@ -2222,15 +2454,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
@@ -2241,6 +2476,7 @@ void Field_double::store(longlong nr)
else
#endif
doublestore(ptr,j);
+ return error;
}
@@ -2339,10 +2575,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
@@ -2355,6 +2591,11 @@ String *Field_double::val_str(String *val_buffer,
return val_buffer;
}
+bool Field_double::send_binary(Protocol *protocol)
+{
+ return protocol->store((double) Field_double::val_real(), dec, (String*) 0);
+}
+
int Field_double::cmp(const char *a_ptr, const char *b_ptr)
{
@@ -2407,10 +2648,16 @@ void Field_double::sort_string(char *to,uint length __attribute__((unused)))
void Field_double::sql_type(String &res) const
{
+ CHARSET_INFO *cs=res.charset();
if (dec == NOT_FIXED_DEC)
- strmov((char*) res.ptr(),"double");
+ {
+ res.set_latin1("double",6);
+ }
else
- sprintf((char*) res.ptr(),"double(%d,%d)",(int) field_length,dec);
+ {
+ res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(),
+ "double(%d,%d)",(int) field_length,dec));
+ }
add_zerofill_and_unsigned(res);
}
@@ -2421,21 +2668,13 @@ void Field_double::sql_type(String &res) const
** by handler.cc. The form->timestamp points at the automatic timestamp.
****************************************************************************/
-enum Item_result Field_timestamp::result_type() const
-{
- return (!current_thd->variables.new_mode &&
- (field_length == 8 || field_length == 14) ? INT_RESULT :
- STRING_RESULT);
-}
-
-
Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg,
const char *field_name_arg,
- struct st_table *table_arg)
- :Field_num(ptr_arg, len_arg, (uchar*) 0,0,
- unireg_check_arg, field_name_arg, table_arg,
- 0, 1, 1)
+ struct st_table *table_arg,
+ CHARSET_INFO *cs)
+ :Field_str(ptr_arg, 19, (uchar*) 0,0,
+ unireg_check_arg, field_name_arg, table_arg, cs)
{
if (table && !table->timestamp_field)
{
@@ -2446,7 +2685,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
@@ -2457,52 +2696,27 @@ 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)
-{
- uint res_length;
- if (len <= field_length)
- res_length=field_length;
- else if (len <= 12)
- res_length=12; /* purecov: inspected */
- else if (len <= 14)
- res_length=14; /* purecov: inspected */
- else
- res_length=(len+1)/2*2; // must be even
- if (res_length != len)
- {
- bmove_upp(from+res_length,from+len,len);
- bfill(from,res_length-len,'0');
- len=res_length;
- }
- long tmp=(long) str_to_timestamp(from,len);
-#ifdef WORDS_BIGENDIAN
- if (table->db_low_byte_first)
- {
- int4store(ptr,tmp);
- }
- else
-#endif
- longstore(ptr,tmp);
-}
-
-
-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;
}
/*
-** Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to
-** YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this
-** function.
+ Convert a datetime of formats YYMMDD, YYYYMMDD or YYMMDDHHMSS to
+ YYYYMMDDHHMMSS. The high date '99991231235959' is checked before this
+ function.
*/
static longlong fix_datetime(longlong nr)
@@ -2536,7 +2750,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;
@@ -2564,6 +2778,7 @@ void Field_timestamp::store(longlong nr)
else
#endif
longstore(ptr,(uint32) timestamp);
+ return 0;
}
@@ -2574,7 +2789,6 @@ double Field_timestamp::val_real(void)
longlong Field_timestamp::val_int(void)
{
- uint len,pos;
int part_time;
uint32 temp;
time_t time_arg;
@@ -2594,44 +2808,34 @@ longlong Field_timestamp::val_int(void)
time_arg=(time_t) temp;
localtime_r(&time_arg,&tm_tmp);
l_time=&tm_tmp;
- res=(longlong) 0;
- for (pos=len=0; len+1 < (uint) field_length ; len+=2,pos++)
- {
- bool year_flag=0;
- switch (dayord.pos[pos]) {
- case 0: part_time=l_time->tm_year % 100; year_flag=1 ; break;
- case 1: part_time=l_time->tm_mon+1; break;
- case 2: part_time=l_time->tm_mday; break;
- case 3: part_time=l_time->tm_hour; break;
- case 4: part_time=l_time->tm_min; break;
- case 5: part_time=l_time->tm_sec; break;
- default: part_time=0; break; /* purecov: deadcode */
- }
- if (year_flag && (field_length == 8 || field_length == 14))
- {
- res=res*(longlong) 10000+(part_time+
- ((part_time < YY_PART_YEAR) ? 2000 : 1900));
- len+=2;
- }
- else
- res=res*(longlong) 100+part_time;
- }
- return (longlong) res;
+
+ part_time= l_time->tm_year % 100;
+ res= ((longlong) (part_time+ ((part_time < YY_PART_YEAR) ? 2000 : 1900))*
+ LL(10000000000));
+ part_time= l_time->tm_mon+1;
+ res+= (longlong) part_time * LL(100000000);
+ part_time=l_time->tm_mday;
+ res+= (longlong) ((long) part_time * 1000000L);
+ part_time=l_time->tm_hour;
+ res+= (longlong) (part_time * 10000L);
+ part_time=l_time->tm_min;
+ res+= (longlong) (part_time * 100);
+ part_time=l_time->tm_sec;
+ return res+part_time;
}
String *Field_timestamp::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
- uint pos;
- int part_time;
- uint32 temp;
+ uint32 temp, temp2;
time_t time_arg;
struct tm *l_time;
struct tm tm_tmp;
- my_bool new_format= (current_thd->variables.new_mode),
- full_year=(field_length == 8 || field_length == 14 || new_format);
- int real_field_length= new_format ? 19 : field_length;
+
+ val_buffer->alloc(field_length+1);
+ char *to=(char*) val_buffer->ptr(),*end=to+field_length;
+ val_buffer->length(field_length);
#ifdef WORDS_BIGENDIAN
if (table->db_low_byte_first)
@@ -2642,57 +2846,58 @@ String *Field_timestamp::val_str(String *val_buffer,
if (temp == 0L)
{ /* Zero time is "000000" */
- if (new_format)
- val_buffer->copy("0000-00-00 00:00:00", real_field_length);
- else
- val_buffer->copy("00000000000000", real_field_length);
- return val_buffer;
+ val_ptr->set("0000-00-00 00:00:00", 19, &my_charset_bin);
+ return val_ptr;
}
+ val_buffer->set_charset(&my_charset_bin); // Safety
time_arg=(time_t) temp;
localtime_r(&time_arg,&tm_tmp);
l_time=&tm_tmp;
- val_buffer->alloc(real_field_length+1);
- char *to=(char*) val_buffer->ptr(),*end=to+real_field_length;
-
- for (pos=0; to < end ; pos++)
- {
- bool year_flag=0;
- switch (pos) {
- case 0: part_time=l_time->tm_year % 100; year_flag=1; break;
- case 1: part_time=l_time->tm_mon+1; break;
- case 2: part_time=l_time->tm_mday; break;
- case 3: part_time=l_time->tm_hour; break;
- case 4: part_time=l_time->tm_min; break;
- case 5: part_time=l_time->tm_sec; break;
- default: part_time=0; break; /* purecov: deadcode */
- }
- if (year_flag && full_year)
- {
- if (part_time < YY_PART_YEAR)
- {
- *to++='2'; *to++='0'; /* purecov: inspected */
- }
- else
- {
- *to++='1'; *to++='9';
- }
- }
- *to++=(char) ('0'+((uint) part_time/10));
- *to++=(char) ('0'+((uint) part_time % 10));
- if (new_format)
- {
- static const char delim[6]="-- ::";
- *to++=delim[pos];
- }
- }
- if (new_format)
- to--;
- *to=0; // Safeguard
- val_buffer->length((uint) (to-val_buffer->ptr()));
+ temp= l_time->tm_year % 100;
+ if (temp < YY_PART_YEAR)
+ {
+ *to++= '2';
+ *to++= '0';
+ }
+ else
+ {
+ *to++= '1';
+ *to++= '9';
+ }
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= '-';
+ temp=l_time->tm_mon+1;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= '-';
+ temp=l_time->tm_mday;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= ' ';
+ temp=l_time->tm_hour;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= ':';
+ temp=l_time->tm_min;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to++= ':';
+ temp=l_time->tm_sec;
+ temp2=temp/10; temp=temp-temp2*10;
+ *to++= (char) ('0'+(char) (temp2));
+ *to++= (char) ('0'+(char) (temp));
+ *to= 0;
return val_buffer;
}
+
bool Field_timestamp::get_date(TIME *ltime, bool fuzzydate)
{
long temp;
@@ -2732,6 +2937,15 @@ bool Field_timestamp::get_time(TIME *ltime)
return Field_timestamp::get_date(ltime,0);
}
+
+bool Field_timestamp::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_timestamp::get_date(&tm, 1);
+ return protocol->store(&tm);
+}
+
+
int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -2750,6 +2964,7 @@ int Field_timestamp::cmp(const char *a_ptr, const char *b_ptr)
return ((uint32) a < (uint32) b) ? -1 : ((uint32) a > (uint32) b) ? 1 : 0;
}
+
void Field_timestamp::sort_string(char *to,uint length __attribute__((unused)))
{
#ifdef WORDS_BIGENDIAN
@@ -2773,8 +2988,7 @@ 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()));
+ res.set_latin1("timestamp", 9);
}
@@ -2791,23 +3005,6 @@ void Field_timestamp::set_time()
longstore(ptr,tmp);
}
-/*
- This is an exact copy of Field_num except that 'length' is depending
- on --new mode
-*/
-
-void Field_timestamp::make_field(Send_field *field)
-{
- field->table_name=table_name;
- field->col_name=field_name;
- /* If --new, then we are using "YYYY-MM-DD HH:MM:SS" format */
- field->length= current_thd->variables.new_mode ? 19 : field_length;
- field->type=type();
- field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags;
- field->decimals=dec;
-}
-
-
/****************************************************************************
** time type
** In string context: HH:MM:SS
@@ -2815,12 +3012,16 @@ void Field_timestamp::make_field(Send_field *field)
** 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)
@@ -2830,26 +3031,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
{
@@ -2860,24 +3066,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
{
@@ -2886,9 +3097,11 @@ void Field_time::store(longlong nr)
{
tmp=0;
current_thd->cuted_fields++;
+ error= 1;
}
}
int3store(ptr,tmp);
+ return error;
}
@@ -2903,6 +3116,12 @@ longlong Field_time::val_int(void)
return (longlong) sint3korr(ptr);
}
+
+/*
+ This function is multi-byte safe as the result string is always of type
+ my_charset_bin
+*/
+
String *Field_time::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
@@ -2914,10 +3133,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;
}
@@ -2938,6 +3158,17 @@ bool Field_time::get_time(TIME *ltime)
return 0;
}
+
+bool Field_time::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_time::get_time(&tm);
+ tm.day= tm.hour/3600; // Move hours to days
+ tm.hour-= tm.day*3600;
+ return protocol->store_time(&tm);
+}
+
+
int Field_time::cmp(const char *a_ptr, const char *b_ptr)
{
int32 a,b;
@@ -2955,7 +3186,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_latin1("time", 4);
}
/****************************************************************************
@@ -2964,18 +3195,19 @@ 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);
- long nr= strtol(tmp_str.c_ptr(),NULL,10);
+ int not_used; // We can ignore result from str2int
+ char *end;
+ long nr= my_strntol(cs, from, len, 10, &end, &not_used);
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))
+ else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))
current_thd->cuted_fields++;
if (nr != 0 || len != 4)
{
@@ -2985,23 +3217,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
{
@@ -3011,8 +3247,14 @@ void Field_year::store(longlong nr)
nr-= 1900;
}
*ptr= (char) (unsigned char) nr;
+ return 0;
}
+bool Field_year::send_binary(Protocol *protocol)
+{
+ ulonglong tmp= Field_year::val_int();
+ return protocol->store_short(tmp);
+}
double Field_year::val_real(void)
{
@@ -3041,8 +3283,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()));
+ CHARSET_INFO *cs=res.charset();
+ res.length(cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(),
+ "year(%d)",(int) field_length));
}
@@ -3053,12 +3296,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
@@ -3069,18 +3316,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);
@@ -3092,18 +3342,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;
@@ -3115,6 +3368,18 @@ void Field_date::store(longlong nr)
else
#endif
longstore(ptr,tmp);
+ return error;
+}
+
+
+bool Field_date::send_binary(Protocol *protocol)
+{
+ longlong tmp= Field_date::val_int();
+ TIME tm;
+ tm.year= (uint32) tmp/10000L % 10000;
+ tm.month= (uint32) tmp/100 % 100;
+ tm.day= (uint32) tmp % 100;
+ return protocol->store_date(&tm);
}
@@ -3201,7 +3466,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_latin1("date", 4);
}
/****************************************************************************
@@ -3210,35 +3475,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
{
@@ -3256,11 +3531,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)
@@ -3276,7 +3553,12 @@ void Field_newdate::store_time(TIME *ltime,timestamp_type type)
int3store(ptr,tmp);
}
-
+bool Field_newdate::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_newdate::get_date(&tm,0);
+ return protocol->store_date(&tm);
+}
double Field_newdate::val_real(void)
{
@@ -3352,7 +3634,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_latin1("date", 4);
}
@@ -3363,7 +3645,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
@@ -3374,26 +3656,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);
@@ -3405,6 +3693,7 @@ void Field_datetime::store(longlong nr)
else
#endif
longlongstore(ptr,nr);
+ return error;
}
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
@@ -3428,6 +3717,13 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type)
longlongstore(ptr,tmp);
}
+bool Field_datetime::send_binary(Protocol *protocol)
+{
+ TIME tm;
+ Field_datetime::get_date(&tm, 1);
+ return protocol->store(&tm);
+}
+
double Field_datetime::val_real(void)
{
@@ -3569,7 +3865,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_latin1("datetime", 8);
}
/****************************************************************************
@@ -3579,21 +3875,28 @@ void Field_datetime::sql_type(String &res) const
/* Copy a string and fill with space */
-void Field_string::store(const char *from,uint length)
+static bool use_conversion(CHARSET_INFO *cs1, CHARSET_INFO *cs2)
{
-#ifdef USE_TIS620
- if (!binary_flag) {
- ThNormalize((uchar *)ptr, field_length, (uchar *)from, length);
- if (length < field_length) {
- bfill(ptr + length, field_length - length, ' ');
- }
+ return (cs1 != &my_charset_bin) && (cs2 != &my_charset_bin) && (cs1!=cs2);
+}
+
+int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
+{
+ int error= 0;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
}
-#else
if (length <= field_length)
{
memcpy(ptr,from,length);
if (length < field_length)
- bfill(ptr+length,field_length-length,' ');
+ field_charset->fill(field_charset,ptr+length,field_length-length,' ');
}
else
{
@@ -3601,57 +3904,52 @@ void Field_string::store(const char *from,uint length)
if (current_thd->count_cuted_fields)
{ // Check if we loosed some info
const char *end=from+length;
- for (from+=field_length ; from != end ; from++)
+ from+= field_length;
+ from+= field_charset->scan(field_charset, from, end, MY_SEQ_SPACES);
+ if (from != end)
{
- if (!isspace(*from))
- {
- current_thd->cuted_fields++;
- break;
- }
+ current_thd->cuted_fields++;
+ error=1;
}
}
}
-#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), &my_charset_bin);
}
-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));
+ char buff[64];
+ int l;
+ CHARSET_INFO *cs=charset();
+ l= (cs->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
+ return Field_string::store(buff,(uint)l,cs);
}
double Field_string::val_real(void)
{
- double value;
- char save=ptr[field_length]; // Ok to patch record
- ptr[field_length]=0;
- value=atof(ptr);
- ptr[field_length]=save;
- return value;
+ int not_used;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr,field_length,(char**)0,&not_used);
}
longlong Field_string::val_int(void)
{
- longlong value;
- char save=ptr[field_length]; // Ok to patch record
- ptr[field_length]=0;
- value=strtoll(ptr,NULL,10);
- ptr[field_length]=save;
- return value;
+ int not_used;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,ptr,field_length,10,NULL,&not_used);
}
@@ -3664,51 +3962,40 @@ 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)
- 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 (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++];
- }
+ uint tmp=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *) ptr, field_length);
+ if (tmp < length)
+ bzero(to + tmp, length - tmp);
}
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)
- res.append(" binary");
+ CHARSET_INFO *cs=res.charset();
+ ulong length= cs->snprintf(cs,(char*) res.ptr(),
+ res.alloced_length(), "%s(%d)",
+ (field_length > 3 &&
+ (table->db_options_in_use &
+ HA_OPTION_PACK_RECORD) ?
+ "varchar" : "char"),
+ (int) field_length);
+ res.length(length);
+ add_binary_or_charset(res);
}
@@ -3737,13 +4024,9 @@ 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)
- {
- 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);
}
@@ -3754,13 +4037,9 @@ int Field_string::pack_cmp(const char *b, uint length)
while (end > ptr && end[-1] == ' ')
end--;
uint a_length = (uint) (end - ptr);
-
- if (binary_flag)
- {
- 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);
}
@@ -3783,68 +4062,65 @@ 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)
{
-#ifdef USE_TIS620
- if (!binary_flag)
- {
- ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length);
- }
-#else
- if (length <= field_length)
- {
- memcpy(ptr+2,from,length);
+ int error= 0;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
}
- else
+ if (length > field_length)
{
length=field_length;
- memcpy(ptr+2,from,field_length);
current_thd->cuted_fields++;
+ error= 1;
}
-#endif /* USE_TIS620 */
- int2store(ptr,length);
+ memcpy(ptr+2,from,length);
+ 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), &my_charset_bin);
}
-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));
+ char buff[64];
+ int l;
+ CHARSET_INFO *cs=charset();
+ l= (cs->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr);
+ return Field_varstring::store(buff,(uint)l,cs);
}
double Field_varstring::val_real(void)
{
- double value;
+ int not_used;
uint length=uint2korr(ptr)+2;
- char save=ptr[length]; // Ok to patch record
- ptr[length]=0;
- value=atof(ptr+2);
- ptr[length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,ptr+2,length,(char**)0, &not_used);
}
longlong Field_varstring::val_int(void)
{
- longlong value;
+ int not_used;
uint length=uint2korr(ptr)+2;
- char save=ptr[length]; // Ok to patch record
- ptr[length]=0;
- value=strtoll(ptr+2,NULL,10);
- ptr[length]=save;
- return value;
+ CHARSET_INFO *cs=charset();
+ return my_strntoll(cs,ptr+2,length,10,NULL, &not_used);
}
@@ -3852,7 +4128,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;
}
@@ -3862,37 +4138,18 @@ 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)
- 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);
- else
- {
-#endif
- char *tmp=to;
- 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++];
-#ifdef USE_STRCOLL
- }
-#endif
- }
+ tot_length=my_strnxfrm(field_charset,
+ (unsigned char *) to, length,
+ (unsigned char *)ptr+2, tot_length);
if (tot_length < length)
bzero(to+tot_length,length-tot_length);
}
@@ -3900,10 +4157,12 @@ 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)
- res.append(" binary");
+ CHARSET_INFO *cs=res.charset();
+ ulong length= cs->snprintf(cs,(char*) res.ptr(),
+ res.alloced_length(),"varchar(%u)",
+ field_length);
+ res.length(length);
+ add_binary_or_charset(res);
}
char *Field_varstring::pack(char *to, const char *from, uint max_length)
@@ -3954,12 +4213,9 @@ 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)
- {
- 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)
@@ -3975,12 +4231,9 @@ int Field_varstring::pack_cmp(const char *b, uint key_length)
{
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
- {
- 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)
@@ -3996,6 +4249,29 @@ uint Field_varstring::max_packed_col_length(uint max_length)
return (max_length > 255 ? 2 : 1)+max_length;
}
+void Field_varstring::get_key_image(char *buff, uint length, CHARSET_INFO *cs,
+ imagetype type)
+{
+ length-= HA_KEY_BLOB_LENGTH;
+ uint f_length=uint2korr(ptr);
+ if (f_length > length)
+ f_length= length;
+ int2store(buff,length);
+ memcpy(buff+2,ptr+2,length);
+#ifdef HAVE_purify
+ if (f_length < length)
+ bzero(buff+2+f_length, (length-f_length));
+#endif
+}
+
+void Field_varstring::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
+{
+ length=uint2korr(buff); // Real length is here
+ (void) Field_varstring::store(buff+2, length, cs);
+}
+
+
+
/****************************************************************************
** blob type
** A blob is saved as a length and a pointer. The length is stored in the
@@ -4005,15 +4281,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++;
}
@@ -4100,86 +4374,73 @@ 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 length,CHARSET_INFO *cs)
{
- if (!len)
+ if (!length)
{
bzero(ptr,Field_blob::pack_length());
}
else
{
-#ifdef USE_TIS620
- char *th_ptr=0;
-#endif
- Field_blob::store_length(len);
- if (table->copy_blobs || len <= MAX_FIELD_WIDTH)
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
+ }
+ Field_blob::store_length(length);
+ if (table->copy_blobs || length <= MAX_FIELD_WIDTH)
{ // Must make a copy
-#ifdef USE_TIS620
- if (!binary_flag)
- {
- /* If there isn't enough memory, use original string */
- if ((th_ptr=(char * ) my_malloc(sizeof(char) * len,MYF(0))))
- {
- ThNormalize((uchar *) th_ptr, len, (uchar *) from, len);
- from= (const char*) th_ptr;
- }
- }
-#endif /* USE_TIS620 */
- value.copy(from,len);
+ value.copy(from,length,charset());
from=value.ptr();
-#ifdef USE_TIS620
- my_free(th_ptr,MYF(MY_ALLOW_ZERO_PTR));
-#endif
}
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());
+ CHARSET_INFO *cs=charset();
+ value.set(nr, 2, cs);
+ return Field_blob::store(value.ptr(),(uint) value.length(), cs);
}
-void Field_blob::store(longlong nr)
+int Field_blob::store(longlong nr)
{
- value.set(nr);
- Field_blob::store(value.ptr(), (uint) value.length());
+ CHARSET_INFO *cs=charset();
+ value.set(nr, cs);
+ return Field_blob::store(value.ptr(), (uint) value.length(), cs);
}
double Field_blob::val_real(void)
{
+ int not_used;
char *blob;
-
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0.0;
uint32 length=get_length(ptr);
-
- char save=blob[length]; // Ok to patch blob in NISAM
- blob[length]=0;
- double nr=atof(blob);
- blob[length]=save;
- return nr;
+ CHARSET_INFO *cs=charset();
+ return my_strntod(cs,blob,length,(char**)0, &not_used);
}
longlong Field_blob::val_int(void)
{
+ int not_used;
char *blob;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
if (!blob)
return 0;
uint32 length=get_length(ptr);
-
- char save=blob[length]; // Ok to patch blob in NISAM
- blob[length]=0;
- longlong nr=strtoll(blob,NULL,10);
- blob[length]=save;
- return nr;
+ return my_strntoll(charset(),blob,length,10,NULL,&not_used);
}
@@ -4189,9 +4450,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,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),charset());
return val_ptr;
}
@@ -4199,11 +4460,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);
}
@@ -4251,11 +4510,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,
+ CHARSET_INFO *cs, 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;
+ }
+
if ((uint32) length > blob_length)
{
/*
@@ -4270,10 +4548,40 @@ void Field_blob::get_key_image(char *buff,uint length)
memcpy(buff+2,blob,length);
}
-void Field_blob::set_key_image(char *buff,uint length)
+void Field_blob::set_key_image(char *buff,uint length, CHARSET_INFO *cs)
{
length=uint2korr(buff);
- Field_blob::store(buff+2,length);
+ (void) Field_blob::store(buff+2,length,cs);
+}
+
+
+void Field_geom::get_key_image(char *buff,uint length,CHARSET_INFO *cs,
+ imagetype type)
+{
+ length-=HA_KEY_BLOB_LENGTH;
+ ulong blob_length=get_length(ptr);
+ char *blob;
+ 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;
+}
+
+void Field_geom::set_key_image(char *buff,uint length,CHARSET_INFO *cs)
+{
+ Field_blob::set_key_image(buff, length, cs);
+}
+
+void Field_geom::sql_type(String &res) const
+{
+ res.set("geometry", 8, &my_charset_latin1);
}
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
@@ -4297,39 +4605,18 @@ void Field_blob::sort_string(char *to,uint length)
{
char *blob;
uint blob_length=get_length();
-#ifdef USE_STRCOLL
- uint blob_org_length=blob_length;
-#endif
+
if (!blob_length)
bzero(to,length);
else
{
- if (blob_length > length)
- blob_length=length;
memcpy_fixed(&blob,ptr+packlength,sizeof(char*));
- if (binary_flag)
- {
- memcpy(to,blob,blob_length);
- to+=blob_length;
- }
- else
- {
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- {
- blob_length=my_strnxfrm(default_charset_info,
- (unsigned char *)to,(unsigned char *)blob,
- length,blob_org_length);
- if (blob_length >= length)
- return;
- to+=blob_length;
- }
- else
-#endif
- for (char *end=blob+blob_length ; blob != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *blob++];
- }
- bzero(to,length-blob_length);
+
+ blob_length=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *)blob, blob_length);
+ if (blob_length < length)
+ bzero(to+blob_length, length-blob_length);
}
}
@@ -4337,14 +4624,25 @@ void Field_blob::sort_string(char *to,uint length)
void Field_blob::sql_type(String &res) const
{
const char *str;
+ uint length;
switch (packlength) {
- default: str="tiny"; break;
- case 2: str=""; break;
- case 3: str="medium"; break;
- case 4: str="long"; break;
+ default: str="tiny"; length=4; break;
+ case 2: str=""; length=0; break;
+ case 3: str="medium"; length= 6; break;
+ case 4: str="long"; length=4; break;
+ }
+ res.set_latin1(str,length);
+ if (charset() == &my_charset_bin)
+ res.append("blob");
+ else
+ {
+ res.append("text");
+ if (field_charset != table->table_charset)
+ {
+ res.append(" character set ");
+ res.append(field_charset->csname);
+ }
}
- res.set(str,(uint) strlen(str));
- res.append(binary_flag ? "blob" : "text");
}
@@ -4400,12 +4698,9 @@ 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)
- {
- 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);
}
@@ -4426,12 +4721,9 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
{
b_length= (uint) (uchar) *b++;
}
- if (binary_flag)
- {
- 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 */
@@ -4542,14 +4834,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);
}
@@ -4562,24 +4856,27 @@ 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 err= 0;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
+ }
uint tmp=find_enum(typelib,from,length);
if (!tmp)
{
if (length < 6) // Can't be more than 99999 enums
{
/* This is for reading numbers with LOAD DATA INFILE */
- char buff[7], *end;
- const char *conv=from;
- if (from[length])
- {
- strmake(buff, from, length);
- conv=buff;
- }
- my_errno=0;
- tmp=(uint) strtoul(conv,&end,10);
- if (my_errno || end != conv+length || tmp > typelib->count)
+ char *end;
+ tmp=(uint) my_strntoul(cs,from,length,10,&end,&err);
+ if (err || end != from+length || tmp > typelib->count)
{
tmp=0;
current_thd->cuted_fields++;
@@ -4589,23 +4886,27 @@ void Field_enum::store(const char *from,uint length)
current_thd->cuted_fields++;
}
store_type((ulonglong) tmp);
+ return err;
}
-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;
}
@@ -4668,7 +4969,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;
}
@@ -4705,47 +5007,60 @@ 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(')');
+ add_binary_or_charset(res);
}
-/****************************************************************************
-** set type.
-** This is a string which can have a collection of different values.
-** Each string value is separated with a ','.
-** For example "One,two,five"
-** If one uses this string in a number context one gets the bits as a longlong
-** number.
-****************************************************************************/
+/*
+ set type.
+ This is a string which can have a collection of different values.
+ Each string value is separated with a ','.
+ For example "One,two,five"
+ If one uses this string in a number context one gets the bits as a longlong
+ number.
+
+ If there was a value in string that wasn't in set, the 'err_pos' points to
+ the last invalid value found. 'err_len' will be set to length of the
+ error string.
+*/
-ulonglong find_set(TYPELIB *lib,const char *x,uint length)
+ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos,
+ uint *err_len)
{
- const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ const char *end= x + length;
+ *err_pos= 0; // No error yet
+ while (end > x && my_isspace(system_charset_info, end[-1]))
end--;
- ulonglong found=0;
+ *err_len= 0;
+ ulonglong found= 0;
if (x != end)
{
- const char *start=x;
- bool error=0;
+ const char *start= x;
+ bool error= 0;
for (;;)
{
- const char *pos=start;
- for (; pos != end && *pos != field_separator ; pos++) ;
- uint find=find_enum(lib,start,(uint) (pos-start));
+ const char *pos= start;
+ uint var_len;
+
+ for (; pos != end && *pos != field_separator; pos++) ;
+ var_len= (uint) (pos - start);
+ uint find= find_enum(lib, start, var_len);
if (!find)
- error=1;
+ {
+ *err_pos= (char*) start;
+ *err_len= var_len;
+ error= 1;
+ }
else
- found|= ((longlong) 1 << (find-1));
+ found|= ((longlong) 1 << (find - 1));
if (pos == end)
- break;
- start=pos+1;
+ break;
+ start= pos + 1;
}
if (error)
current_thd->cuted_fields++;
@@ -4754,40 +5069,51 @@ 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)
{
- ulonglong tmp=find_set(typelib,from,length);
+ int err= 0;
+ char *not_used;
+ uint not_used2;
+ char buff[80];
+ String tmpstr(buff,sizeof(buff), &my_charset_bin);
+ /* Convert character set if nesessary */
+ if (use_conversion(cs, field_charset))
+ {
+ tmpstr.copy(from, length, cs, field_charset);
+ from= tmpstr.ptr();
+ length= tmpstr.length();
+ }
+ ulonglong tmp= find_set(typelib, from, length, &not_used, &not_used2);
if (!tmp && length && length < 22)
{
/* This is for reading numbers with LOAD DATA INFILE */
- char buff[22], *end;
- const char *conv=from;
- if (from[length])
- {
- strmake(buff, from, length);
- conv=buff;
- }
- my_errno=0;
- tmp=strtoull(conv,&end,10);
- if (my_errno || end != conv+length ||
+ char *end;
+ tmp=my_strntoull(cs,from,length,10,&end,&err);
+ if (err || end != from+length ||
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
+ {
tmp=0;
+ }
else
current_thd->cuted_fields--; // Remove warning from find_set
}
store_type(tmp);
+ return err;
}
-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;
}
@@ -4805,7 +5131,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;
@@ -4825,19 +5152,18 @@ 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(')');
+ add_binary_or_charset(res);
}
/* returns 1 if the fields are equally defined */
bool Field::eq_def(Field *field)
{
- if (real_type() != field->real_type() || binary() != field->binary() ||
+ if (real_type() != field->real_type() || charset() != field->charset() ||
pack_length() != field->pack_length())
return 0;
return 1;
@@ -4852,7 +5178,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;
}
@@ -4900,7 +5227,8 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_LONGLONG: return 8; /* Don't crash if no longlong */
case FIELD_TYPE_NULL : return 0;
case FIELD_TYPE_TINY_BLOB: return 1+portable_sizeof_char_ptr;
- case FIELD_TYPE_BLOB: return 2+portable_sizeof_char_ptr;
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_GEOMETRY: return 2+portable_sizeof_char_ptr;
case FIELD_TYPE_MEDIUM_BLOB: return 3+portable_sizeof_char_ptr;
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
@@ -4928,6 +5256,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,
@@ -4942,30 +5271,30 @@ 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),
field_length);
+ if (f_is_geom(pack_flag))
+ return new Field_geom(ptr,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_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);
- if (f_is_geom(pack_flag))
- return 0;
-
+ pack_length, field_charset);
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);
}
}
@@ -5015,28 +5344,28 @@ Field *make_field(char *ptr, uint32 field_length,
f_is_dec(pack_flag) == 0);
case FIELD_TYPE_TIMESTAMP:
return new Field_timestamp(ptr,field_length,
- unireg_check, field_name, table);
+ unireg_check, field_name, table, field_charset);
case FIELD_TYPE_YEAR:
return new Field_year(ptr,field_length,null_pos,null_bit,
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;
}
@@ -5051,6 +5380,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)
@@ -5059,6 +5390,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;
}
@@ -5072,7 +5404,7 @@ create_field::create_field(Field *old_field,Field *orig_field)
orig_field)
{
char buff[MAX_FIELD_WIDTH],*pos;
- String tmp(buff,sizeof(buff));
+ String tmp(buff,sizeof(buff), 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);
@@ -5084,7 +5416,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(), charset);
}
}
}
diff --git a/sql/field.h b/sql/field.h
index 842bbb89988..3877068aa0e 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -27,10 +27,12 @@
#define NOT_FIXED_DEC 31
class Send_field;
+class Protocol;
struct st_cache_field;
void field_conv(Field *to,Field *from);
-class Field {
+class Field
+{
Field(const Item &); /* Prevent use of these */
void operator=(Field &);
public:
@@ -41,12 +43,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 +62,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;
@@ -72,10 +78,11 @@ public:
virtual void reset_fields() {}
virtual void set_default()
{
- memcpy(ptr, ptr + table->rec_buff_length, pack_length());
+ my_ptrdiff_t offset = table->default_values() - table->record[0];
+ memcpy(ptr, ptr + offset, pack_length());
if (null_ptr)
*null_ptr= ((*null_ptr & (uchar) ~null_bit) |
- null_ptr[table->rec_buff_length] & null_bit);
+ null_ptr[offset] & null_bit);
}
virtual bool binary() const { return 1; }
virtual bool zero_pack() const { return 1; }
@@ -122,10 +129,14 @@ public:
Field *tmp= (Field*) memdup_root(root,(char*) this,size_of());
if (tmp)
{
- tmp->table=new_table;
- tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=0;
+ tmp->table= new_table;
+ tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0;
tmp->unireg_check=Field::NONE;
- tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+ tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
+ ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);
+#ifdef PROBABLY_WRONG
+ tmp->table_name= new_table->table_name;
+#endif
tmp->reset_fields();
}
return tmp;
@@ -141,21 +152,14 @@ public:
if (null_ptr)
null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*);
}
- inline void get_image(char *buff,uint length)
+ inline void get_image(char *buff,uint length, CHARSET_INFO *cs)
{ memcpy(buff,ptr,length); }
- inline void set_image(char *buff,uint length)
+ inline void set_image(char *buff,uint length, CHARSET_INFO *cs)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff,uint length)
- { 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);
- }
+ virtual void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type)
+ { get_image(buff,length,cs); }
+ virtual void set_key_image(char *buff,uint length, CHARSET_INFO *cs)
+ { set_image(buff,length,cs); }
inline longlong val_int_offset(uint row_offset)
{
ptr+=row_offset;
@@ -163,7 +167,7 @@ public:
ptr-=row_offset;
return tmp;
}
- bool send(THD *thd, String *packet);
+ virtual bool send_binary(Protocol *protocol);
virtual char *pack(char* to, const char *from, uint max_length=~(uint) 0)
{
uint32 length=pack_length();
@@ -199,6 +203,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 +252,30 @@ 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;
+ if (charset->state & MY_CS_BINSORT)
+ flags|=BINARY_FLAG;
+ }
Item_result result_type () const { return STRING_RESULT; }
+ void add_binary_or_charset(String &res) const;
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; }
+ friend class create_field;
};
@@ -275,11 +292,11 @@ public:
{}
enum_field_types type() const { return FIELD_TYPE_DECIMAL;}
enum ha_base_keytype key_type() const
- { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
+ { 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,13 +323,14 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 1; }
@@ -335,13 +353,14 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 2; }
@@ -364,13 +383,14 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 3; }
@@ -398,12 +418,13 @@ 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);
+ bool send_binary(Protocol *protocol);
String *val_str(String*,String *);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
@@ -434,13 +455,14 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 8; }
@@ -462,13 +484,14 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return sizeof(float); }
@@ -494,13 +517,14 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return sizeof(double); }
@@ -515,14 +539,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,26 +555,28 @@ 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;
uint size_of() const { return sizeof(*this); }
};
-class Field_timestamp :public Field_num {
+class Field_timestamp :public Field_str {
public:
Field_timestamp(char *ptr_arg, uint32 len_arg,
enum utype unireg_check_arg, const char *field_name_arg,
- struct st_table *table_arg);
- enum Item_result result_type () const;
+ struct st_table *table_arg,
+ CHARSET_INFO *cs);
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);
+ enum Item_result cmp_type () const { return INT_RESULT; }
+ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 4; }
@@ -572,10 +598,8 @@ public:
longget(tmp,ptr);
return tmp;
}
- void fill_and_store(char *from,uint len);
bool get_date(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
- void make_field(Send_field *field);
};
@@ -589,12 +613,13 @@ 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 *);
+ bool send_binary(Protocol *protocol);
void sql_type(String &str) const;
};
@@ -603,24 +628,25 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 4; }
@@ -633,22 +659,23 @@ 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);
longlong val_int(void);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 3; }
@@ -664,24 +691,25 @@ 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);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
bool get_time(TIME *ltime);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
@@ -696,27 +724,28 @@ 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);
longlong val_int(void);
String *val_str(String*,String *);
+ bool send_binary(Protocol *protocol);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
uint32 pack_length() const { return 8; }
@@ -729,28 +758,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
{
@@ -759,13 +777,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);
+ void reset(void) { charset()->fill(charset(),ptr,field_length,' '); }
+ 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 *);
@@ -784,45 +801,35 @@ 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 *);
int cmp(const char *,const char*);
void sort_string(char *buff,uint length);
+ void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
+ void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
void sql_type(String &str) const;
char *pack(char *to, const char *from, uint max_length=~(uint) 0);
const char *unpack(char* to, const char *from);
@@ -838,28 +845,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 *);
@@ -880,7 +885,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*));
@@ -895,13 +899,13 @@ public:
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- void get_key_image(char *buff,uint length);
- void set_key_image(char *buff,uint length);
+ void get_key_image(char *buff,uint length, CHARSET_INFO *cs, imagetype type);
+ void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
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;
@@ -924,6 +928,26 @@ 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; }
+ enum_field_types type() const { return FIELD_TYPE_GEOMETRY;}
+ void sql_type(String &str) const;
+
+ void get_key_image(char *buff,uint length, CHARSET_INFO *cs,imagetype type);
+ void set_key_image(char *buff,uint length, CHARSET_INFO *cs);
+};
+
+
class Field_enum :public Field_str {
protected:
uint packlength;
@@ -933,9 +957,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;
@@ -943,9 +968,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);
@@ -959,7 +984,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);
};
@@ -970,17 +994,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;
@@ -997,12 +1021,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
@@ -1018,8 +1044,11 @@ public:
class Send_field {
public:
- const char *table_name,*col_name;
- uint length,flags,decimals;
+ const char *db_name;
+ const char *table_name,*org_table_name;
+ const char *col_name,*org_col_name;
+ ulong length;
+ uint charsetnr, flags, decimals;
enum_field_types type;
Send_field() {}
};
@@ -1051,8 +1080,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);
@@ -1061,8 +1090,10 @@ uint32 calc_pack_length(enum_field_types type,uint32 length);
bool set_field_to_null(Field *field);
bool set_field_to_null_with_conversions(Field *field, bool no_conversions);
uint find_enum(TYPELIB *typelib,const char *x, uint length);
-ulonglong find_set(TYPELIB *typelib,const char *x, uint length);
-bool test_if_int(const char *str,int length);
+ulonglong find_set(TYPELIB *typelib,const char *x, uint length,
+ char **err_pos, uint *err_len);
+bool test_if_int(const char *str, int length, const char *int_end,
+ CHARSET_INFO *cs);
/*
The following are for the interface with the .frm file
@@ -1077,6 +1108,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
@@ -1099,7 +1131,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 42272dd616f..47996606638 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -272,7 +272,8 @@ static void do_conv_blob(Copy_field *copy)
{
copy->from_field->val_str(&copy->tmp,&copy->tmp);
((Field_blob *) copy->to_field)->store(copy->tmp.ptr(),
- copy->tmp.length());
+ copy->tmp.length(),
+ copy->tmp.charset());
}
/* Save blob in copy->tmp for GROUP BY */
@@ -280,20 +281,21 @@ 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),copy->tmp.charset());
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(),
+ copy->tmp.charset());
}
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),copy->tmp.charset());
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(),copy->tmp.charset());
}
@@ -320,7 +322,7 @@ static void do_cut_string(Copy_field *copy)
ptr != end ;
ptr++)
{
- if (!isspace(*ptr))
+ if (!my_isspace(system_charset_info, *ptr)) // QQ: ucs incompatible
{
current_thd->cuted_fields++; // Give a warning
break;
@@ -552,7 +554,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 &&
@@ -562,9 +564,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),from->charset());
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 86574e4dd57..0f6e4d7abba 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -49,7 +49,8 @@ static int merge_index(SORTPARAM *param,uchar *sort_buffer,
uint maxbuffer,IO_CACHE *tempfile,
IO_CACHE *outfile);
static bool save_index(SORTPARAM *param,uchar **sort_keys, uint count);
-static uint sortlength(SORT_FIELD *sortorder,uint length);
+static uint sortlength(SORT_FIELD *sortorder, uint s_length,
+ bool *multi_byte_charset);
/*
Creates a set of pointers that can be used to read the rows
@@ -63,9 +64,8 @@ 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, min_sort_memory;
@@ -75,10 +75,9 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
uchar **sort_keys;
IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile;
SORTPARAM param;
- THD *thd= current_thd;
-
+ bool multi_byte_charset;
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
@@ -91,7 +90,8 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
error= 1;
bzero((char*) &param,sizeof(param));
param.ref_length= table->file->ref_length;
- param.sort_length=sortlength(sortorder,s_length)+ param.ref_length;
+ param.sort_length= (sortlength(sortorder,s_length, &multi_byte_charset)+
+ param.ref_length);
param.max_rows= max_rows;
if (select && select->quick)
@@ -102,27 +102,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;
@@ -130,11 +118,9 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (param.sort_length == param.ref_length && records > param.max_rows)
records=param.max_rows; /* purecov: inspected */
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info) &&
+ if (multi_byte_charset &&
!(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME))))
goto err;
-#endif
memavl= thd->variables.sortbuff_size;
min_sort_memory= max(MIN_SORT_MEMORY, param.sort_length*MERGEBUFF2);
@@ -208,10 +194,8 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
error =0;
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);
x_free((gptr) buffpek);
close_cached_file(&tempfile);
@@ -480,10 +464,11 @@ static void make_sortkey(register SORTPARAM *param,
switch (sort_field->result_type) {
case STRING_RESULT:
{
+ CHARSET_INFO *cs=item->charset();
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,cs);
String *res=item->val_str(&tmp);
if (!res)
{
@@ -504,43 +489,27 @@ static void make_sortkey(register SORTPARAM *param,
diff=0; /* purecov: inspected */
length=sort_field->length;
}
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (sort_field->need_strxnfrm)
{
- if (item->binary)
- {
- if (res->ptr() != (char*) to)
- memcpy(to,res->ptr(),length);
- bzero((char*) to+length,diff);
- }
- else
- {
- char *from=(char*) res->ptr();
- if ((unsigned char *)from == to)
- {
- set_if_smaller(length,sort_field->length);
- 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);
- if (tmp_length < sort_field->length)
- bzero((char*) to+tmp_length,sort_field->length-tmp_length);
- }
+ char *from=(char*) res->ptr();
+ if ((unsigned char *)from == to)
+ {
+ set_if_smaller(length,sort_field->length);
+ memcpy(param->tmp_buffer,from,length);
+ from=param->tmp_buffer;
+ }
+ 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);
}
else
{
-#endif
if (res->ptr() != (char*) to)
memcpy(to,res->ptr(),length);
bzero((char *)to+length,diff);
- if (!item->binary)
- case_sort((char*) to,length);
-#ifdef USE_STRCOLL
+ my_tosort(cs, (char*) to,length);
}
-#endif
break;
}
case INT_RESULT:
@@ -591,6 +560,11 @@ static void make_sortkey(register SORTPARAM *param,
change_double_for_sort(value,(byte*) to);
break;
}
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
}
if (sort_field->reverse)
@@ -920,28 +894,51 @@ static int merge_index(SORTPARAM *param, uchar *sort_buffer,
} /* merge_index */
- /* Calculate length of sort key */
+/*
+ Calculate length of sort key
+
+ SYNOPSIS
+ sortlength()
+ sortorder Order of items to sort
+ uint s_length Number of items to sort
+ multi_byte_charset (out)
+ Set to 1 if we are using multi-byte charset
+ (In which case we have to use strxnfrm())
+
+ NOTES
+ sortorder->length is updated for each sort item
+ sortorder->need_strxnfrm is set 1 if we have to use strxnfrm
+
+ RETURN
+ Total length of sort buffer in bytes
+*/
static uint
-sortlength(SORT_FIELD *sortorder, uint s_length)
+sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
{
reg2 uint length;
THD *thd= current_thd;
+ CHARSET_INFO *cs;
+ *multi_byte_charset= 0;
length=0;
for (; s_length-- ; sortorder++)
{
+ sortorder->need_strxnfrm= 0;
if (sortorder->field)
{
+
if (sortorder->field->type() == FIELD_TYPE_BLOB)
sortorder->length= thd->variables.max_sort_length;
else
{
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;
-#endif
+ if (use_strnxfrm((cs=sortorder->field->charset())))
+ {
+ sortorder->need_strxnfrm= 1;
+ *multi_byte_charset= 1;
+ sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ }
}
if (sortorder->field->maybe_null())
length++; // Place for NULL marker
@@ -951,10 +948,12 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
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;
-#endif
+ if (use_strnxfrm((cs=sortorder->item->charset())))
+ {
+ sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ sortorder->need_strxnfrm= 1;
+ *multi_byte_charset= 1;
+ }
break;
case INT_RESULT:
#if SIZEOF_LONG_LONG > 4
@@ -966,6 +965,11 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
case REAL_RESULT:
sortorder->length=sizeof(double);
break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
if (sortorder->item->maybe_null)
length++; // Place for NULL marker
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 1f604659272..1c6f124aac7 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,337 +83,260 @@
#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
+{
+ int 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++)
+ if (!root->first_char)
{
- 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;
- }
+ root->first_char= -1;
+ root->iresult= index;
+ return;
+ }
+
+ 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= (int) (uchar) name2[0];
+ root->last_char= (char) root->first_char;
+ tails= (hash_lex_struct*)malloc(sizeof(hash_lex_struct));
+ root->char_tails= tails;
+ tails->first_char= -1;
+ tails->iresult= index2;
}
- char_table[0]|=1+257; // Avoid problems with 0
- for (i=0 ; i < 256 ; i++)
+
+ size_t real_size= (root->last_char-root->first_char+1);
+
+ if (root->first_char>(*name))
{
- uint tmp=(uint) (rnd(&rand_st)*255);
- swap(uint,char_table[i],char_table[tmp]);
+ 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= (int) (uchar) *name;
}
- /* lower characters should be mapped to upper */
- for (i= 'a' ; i <= 'z' ; i++)
+
+ if (root->last_char<(*name))
{
- /* 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];
+ 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);
}
+
+ insert_into_hash(root->char_tails+(*name)-root->first_char,
+ name+1,len_from_begin+1,index,function);
}
-/* 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);
+hash_lex_struct *root_by_len= 0;
+int max_len=0;
- bzero((char*) primes,sizeof(primes[0])*max_allowed_array);
+hash_lex_struct *root_by_len2= 0;
+int max_len2=0;
- i=2;
- while (i < max_index)
- {
- for (j=i+i ; j <= max_allowed_array ; j+=i)
- primes[j]=1;
- while (primes[++i]) ;
+void insert_symbols()
+{
+ 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);
}
-
- to=primes;
- for (i=start ; i <= max_allowed_array ; i++)
- if (!primes[i])
- *to++=i;
- *to=0; // end marker
}
-#define USE_char_table
-
-static ulong tab_index_function(const char *s,uint add, uint type)
+void insert_sql_functions()
{
- 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= 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);
}
- return nr & INT_MAX24;
}
-static int search(bool write_warning)
+void calc_length()
+{
+ 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);
+}
+
+void generate_find_structs()
{
- 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];
+ root_by_len= 0;
+ max_len=0;
- how_long_symbols = sizeof(symbols)/sizeof(SYMBOL);
+ insert_symbols();
- bzero((char*) possible_plus,sizeof(possible_plus));
- found=0;
+ root_by_len2= root_by_len;
+ max_len2= max_len;
+
+ root_by_len= 0;
+ max_len= 0;
+
+ insert_symbols();
+ insert_sql_functions();
+}
- /* Check first which function_plus are possible */
- for (type=0 ; type < type_count ; type ++)
+char *hash_map= 0;
+int size_hash_map= 0;
+
+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]= (char) (st->first_char == -1 ? 0 :
+ st->first_char);
+ hash_map[size_hash_map-3]= (char) (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++)
+void set_links(hash_lex_struct *st, int len)
+{
+ hash_lex_struct *cur, *end= st+len;
+ for (cur= st; cur<end; cur++)
{
- uint *plus_ptr=possible_plus;
- for (type=0 ; type < type_count ; type++ )
+ if (cur->first_char != 0 && cur->first_char != -1)
{
- 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
- }
- }
+ 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);
+ char *cur;
+ int i;
- 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++)
+ printf("uchar %s[%d]= {\n",name,size_hash_map);
+ for (i=0, cur= hash_map; i<size_hash_map; i++, cur++)
{
- 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);
+ 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
- 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]);
+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 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);
+ hash_map= 0;
+ size_hash_map= 0;
+
+ 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)
{
- printf("%s Ver 3.5 Distrib %s, for %s (%s)\n",
+ printf("%s Ver 3.6 Distrib %s, for %s (%s)\n",
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);
}
@@ -364,10 +344,7 @@ 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);
@@ -389,139 +366,68 @@ 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)
+
+int check_dup_symbols(SYMBOL *s1, SYMBOL *s2)
{
- 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;
+ if (s1->length!=s2->length || strncmp(s1->name,s2->name,s1->length))
+ return 0;
+
+ const char *err_tmpl= "\ngen_lex_hash fatal error : \
+Unfortunately gen_lex_hash can not generate a hash,\n since \
+your lex.h has duplicate definition for a symbol \"%s\"\n\n";
+ printf (err_tmpl,s1->name);
+ fprintf (stderr,err_tmpl,s1->name);
+
+ return 1;
}
-static void make_max_length_table(void)
+int check_duplicates()
{
- uint i;
- for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++)
+ SYMBOL *cur1, *cur2, *s_end, *f_end;
+
+ s_end= symbols + array_elements(symbols);
+ f_end= sql_functions + array_elements(sql_functions);
+
+ for (cur1= symbols; cur1<s_end; cur1++)
{
- uint length=max_prefix(symbols[i].name);
- if (length > unique_length[(uchar) symbols[i].name[0]])
+ for (cur2= cur1+1; cur2<s_end; cur2++)
+ {
+ if (check_dup_symbols(cur1,cur2))
+ return 1;
+ }
+ for (cur2= sql_functions; cur2<f_end; cur2++)
{
- unique_length[(uchar) symbols[i].name[0]]=length;
- unique_length[(uchar) tolower(symbols[i].name[0])]=length;
+ if (check_dup_symbols(cur1,cur2))
+ return 1;
}
}
- for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++)
+
+ for (cur1= sql_functions; cur1<f_end; cur1++)
{
- uint length=max_prefix(sql_functions[i].name);
- if (length > unique_length[(uchar) sql_functions[i].name[0]])
+ for (cur2= cur1+1; cur2< f_end; cur2++)
{
- unique_length[(uchar) sql_functions[i].name[0]]=length;
- unique_length[(uchar) tolower(sql_functions[i].name[0])]=length;
+ if (check_dup_symbols(cur1,cur2))
+ return 1;
}
}
+ return 0;
}
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 +439,90 @@ 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();
+ calc_length();
+
+ if (check_duplicates())
+ exit(1);
+
+ 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\
+ {\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..a97ed9cae03
--- /dev/null
+++ b/sql/gstream.cc
@@ -0,0 +1,139 @@
+#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 = strtod(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..a3914a534dd
--- /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 2154fbd7a32..dbed955c0a9 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -55,7 +55,6 @@
#ifdef HAVE_BERKELEY_DB
#include <m_ctype.h>
#include <myisampack.h>
-#include <assert.h>
#include <hash.h>
#include "ha_berkeley.h"
#include "sql_manager.h"
@@ -168,7 +167,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 +193,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 */
@@ -231,10 +230,9 @@ int berkeley_rollback(THD *thd, void *trans)
}
-int berkeley_show_logs(THD *thd)
+int berkeley_show_logs(Protocol *protocol)
{
char **all_logs, **free_logs, **a, **f;
- String *packet= &thd->packet;
int error=1;
MEM_ROOT show_logs_root;
MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC);
@@ -243,10 +241,9 @@ 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");
@@ -259,18 +256,18 @@ int berkeley_show_logs(THD *thd)
{
for (a = all_logs, f = free_logs; *a; ++a)
{
- packet->length(0);
- net_store_data(packet,*a);
- net_store_data(packet,"BDB");
+ protocol->prepare_for_resend();
+ protocol->store(*a, system_charset_info);
+ protocol->store("BDB", 3, system_charset_info);
if (f && *f && strcmp(*a, *f) == 0)
{
- ++f;
- net_store_data(packet, SHOW_LOG_STATUS_FREE);
+ f++;
+ protocol->store(SHOW_LOG_STATUS_FREE, system_charset_info);
}
else
- net_store_data(packet, SHOW_LOG_STATUS_INUSE);
+ protocol->store(SHOW_LOG_STATUS_INUSE, system_charset_info);
- if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ if (protocol->write())
{
error=1;
goto err;
@@ -309,10 +306,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 +509,12 @@ 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 */
@@ -1414,10 +1416,21 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
DBT row;
int error;
KEY *key_info= &table->key_info[active_index];
+ int do_prev= 0;
DBUG_ENTER("ha_berkeley::index_read");
statistic_increment(ha_read_key_count,&LOCK_status);
bzero((char*) &row,sizeof(row));
+ if (find_flag == HA_READ_BEFORE_KEY)
+ {
+ find_flag= HA_READ_KEY_OR_NEXT;
+ do_prev= 1;
+ }
+ else if (find_flag == HA_READ_PREFIX_LAST_OR_PREV)
+ {
+ find_flag= HA_READ_AFTER_KEY;
+ do_prev= 1;
+ }
if (key_len == key_info->key_length)
{
error=read_row(cursor->c_get(cursor, pack_key(&last_key,
@@ -1451,6 +1464,12 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
error=HA_ERR_KEY_NOT_FOUND;
}
}
+ if (do_prev)
+ {
+ bzero((char*) &row, sizeof(row));
+ error= read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
+ (char*) buf, active_index, &row, &last_key, 1);
+ }
DBUG_RETURN(error);
}
@@ -1836,7 +1855,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 +1911,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];
@@ -1921,6 +1940,7 @@ int ha_berkeley::delete_table(const char *name)
DBUG_RETURN(error);
}
+
int ha_berkeley::rename_table(const char * from, const char * to)
{
int error;
@@ -2066,8 +2086,7 @@ void ha_berkeley::print_error(int error, myf errflag)
static void print_msg(THD *thd, const char *table_name, const char *op_name,
const char *msg_type, const char *fmt, ...)
{
- String* packet = &thd->packet;
- packet->length(0);
+ Protocol *protocol= thd->protocol;
char msgbuf[256];
msgbuf[0] = 0;
va_list args;
@@ -2075,15 +2094,15 @@ static void print_msg(THD *thd, const char *table_name, const char *op_name,
my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
-
DBUG_PRINT(msg_type,("message: %s",msgbuf));
- net_store_data(packet, table_name);
- net_store_data(packet, op_name);
- net_store_data(packet, msg_type);
- net_store_data(packet, msgbuf);
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(),
- thd->packet.length()))
+ protocol->set_nfields(4);
+ protocol->prepare_for_resend();
+ protocol->store(table_name);
+ protocol->store(op_name);
+ protocol->store(msg_type);
+ protocol->store(msgbuf);
+ if (protocol->write())
thd->killed=1;
}
#endif
@@ -2100,7 +2119,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));
@@ -2113,7 +2132,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);
@@ -2316,7 +2335,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 */
@@ -2392,7 +2411,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_berkeley.h b/sql/ha_berkeley.h
index d2dc5e3216d..dd42e7ab9e2 100644
--- a/sql/ha_berkeley.h
+++ b/sql/ha_berkeley.h
@@ -181,4 +181,4 @@ bool berkeley_end(void);
bool berkeley_flush_logs(void);
int berkeley_commit(THD *thd, void *trans);
int berkeley_rollback(THD *thd, void *trans);
-int berkeley_show_logs(THD *thd);
+int berkeley_show_logs(Protocol *protocol);
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 2edc3b1478e..fb4061b31e0 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,28 +72,32 @@ 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)))
+int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
- int error=heap_rkey(file, buf, 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,
+ HA_READ_PREFIX_LAST);
+ table->status= error ? STATUS_NOT_FOUND : 0;
return error;
}
+int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ 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;
+}
int ha_heap::index_next(byte * buf)
{
@@ -167,7 +118,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 +126,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 +173,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 +208,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 +224,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 +231,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;
+
+ 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);
+}
-int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info)
+void ha_heap::update_create_info(HA_CREATE_INFO *create_info)
+{
+ 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()
{
- char buff[FN_REFLEN];
- return heap_create(fn_format(buff,name,"","",4+2));
+ ha_heap::info(HA_STATUS_AUTO);
+ return auto_increment_value;
}
diff --git a/sql/ha_heap.h b/sql/ha_heap.h
index 504f5262bf3..fe874dab3f2 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,10 +62,12 @@ 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,
uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);
@@ -87,6 +88,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 ea8eaf6653e..ce26ee705dd 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -32,7 +32,6 @@ InnoDB */
#ifdef HAVE_INNOBASE_DB
#include <m_ctype.h>
-#include <assert.h>
#include <hash.h>
#include <myisampack.h>
@@ -82,7 +81,8 @@ are declared in mysqld.cc: */
long innobase_mirrored_log_groups, innobase_log_files_in_group,
innobase_log_file_size, innobase_log_buffer_size,
- innobase_buffer_pool_size, innobase_additional_mem_pool_size,
+ innobase_buffer_pool_size, innobase_buffer_pool_awe_mem_mb,
+ innobase_additional_mem_pool_size,
innobase_file_io_threads, innobase_lock_wait_timeout,
innobase_thread_concurrency, innobase_force_recovery;
@@ -766,7 +766,25 @@ innobase_init(void)
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
srv_flush_log_at_trx_commit = (ulint) innobase_flush_log_at_trx_commit;
- srv_pool_size = (ulint) innobase_buffer_pool_size;
+ /* We set srv_pool_size here in units of 1 kB. InnoDB internally
+ changes the value so that it becomes the number of database pages. */
+
+ if (innobase_buffer_pool_awe_mem_mb == 0) {
+ /* Careful here: we first convert the signed long int to ulint
+ and only after that divide */
+
+ srv_pool_size = ((ulint) innobase_buffer_pool_size) / 1024;
+ } else {
+ srv_use_awe = TRUE;
+ srv_pool_size = (ulint)
+ (1024 * innobase_buffer_pool_awe_mem_mb);
+ srv_awe_window_size = (ulint) innobase_buffer_pool_size;
+
+ /* Note that what the user specified as
+ innodb_buffer_pool_size is actually the AWE memory window
+ size in this case, and the real buffer pool size is
+ determined by .._awe_mem_mb. */
+ }
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
@@ -805,9 +823,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,
@@ -890,6 +907,7 @@ innobase_commit_low(
/*================*/
trx_t* trx) /* in: transaction handle */
{
+#ifdef HAVE_REPLICATION
/* TODO: Guilhem should check if master_log_name, pending
etc. are right if the master log gets rotated! Possible bug here.
Comment by Heikki March 4, 2003. */
@@ -904,6 +922,7 @@ innobase_commit_low(
active_mi->rli.event_len +
active_mi->rli.pending));
}
+#endif /* HAVE_REPLICATION */
trx_commit_for_mysql(trx);
}
@@ -1439,8 +1458,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) {
@@ -1476,7 +1498,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(
@@ -1486,7 +1508,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(
@@ -1600,6 +1622,8 @@ build_template(
ibool fetch_all_in_key = FALSE;
ulint i;
+ ut_a(templ_type != ROW_MYSQL_REC_FIELDS || thd == current_thd);
+
clust_index = dict_table_get_first_index_noninline(prebuilt->table);
if (!prebuilt->hint_no_need_to_fetch_extra_cols) {
@@ -1624,6 +1648,12 @@ build_template(
}
if (prebuilt->select_lock_type == LOCK_X) {
+ /* In versions < 3.23.50 we always retrieved the clustered
+ index record if prebuilt->select_lock_type == LOCK_S,
+ but there is really not need for that, and in some cases
+ performance could be seriously degraded because the MySQL
+ optimizer did not know about our convention! */
+
/* We always retrieve the whole clustered index record if we
use exclusive row level locks, for example, if the read is
done in an UPDATE statement. */
@@ -1632,12 +1662,6 @@ build_template(
}
if (templ_type == ROW_MYSQL_REC_FIELDS) {
- /* In versions < 3.23.50 we always retrieved the clustered
- index record if prebuilt->select_lock_type == LOCK_S,
- but there is really not need for that, and in some cases
- performance could be seriously degraded because the MySQL
- optimizer did not know about our convention! */
-
index = prebuilt->index;
} else {
index = clust_index;
@@ -1669,18 +1693,31 @@ build_template(
field = table->field[i];
if (templ_type == ROW_MYSQL_REC_FIELDS
+ && prebuilt->read_just_key
+ && dict_index_get_nth_col_pos(index, i)
+ == ULINT_UNDEFINED) {
+ /* Skip a column which is not in the index */
+
+ goto skip_field;
+ }
+
+
+ /* TODO: we have removed temporarily the test of which columns
+ to fetch, until the new client/server protocol of 4.1
+ is fixed!!!!!!!!!!!!!!!!!
+
+ if (templ_type == ROW_MYSQL_REC_FIELDS
&& !(fetch_all_in_key &&
- ULINT_UNDEFINED != dict_index_get_nth_col_pos(
- index, i))
+ ULINT_UNDEFINED != dict_index_get_nth_col_pos(
+ index, i))
&& thd->query_id != field->query_id
&& thd->query_id != (field->query_id ^ MAX_ULONG_BIT)
&& thd->query_id !=
(field->query_id ^ (MAX_ULONG_BIT >> 1))) {
- /* This field is not needed in the query, skip it */
-
goto skip_field;
}
+ */
n_requested_fields++;
@@ -2276,20 +2313,15 @@ convert_search_mode_to_innobase(
case HA_READ_BEFORE_KEY: return(PAGE_CUR_L);
case HA_READ_PREFIX: return(PAGE_CUR_GE);
case HA_READ_PREFIX_LAST: return(PAGE_CUR_LE);
- /* In MySQL-4.0 HA_READ_PREFIX and HA_READ_PREFIX_LAST always
- pass a complete-field prefix of a key value as the search
+ case HA_READ_PREFIX_LAST_OR_PREV:return(PAGE_CUR_LE);
+ /* In MySQL HA_READ_PREFIX and HA_READ_PREFIX_LAST always
+ use a complete-field-prefix of a kay value as the search
tuple. I.e., it is not allowed that the last field would
just contain n first bytes of the full field value.
MySQL uses a 'padding' trick to convert LIKE 'abc%'
type queries so that it can use as a search tuple
a complete-field-prefix of a key value. Thus, the InnoDB
- search mode PAGE_CUR_LE_OR_EXTENDS is never used.
- TODO: when/if MySQL starts to use also partial-field
- prefixes, we have to deal with stripping of spaces
- and comparison of non-latin1 char type fields in
- innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to
- work correctly. */
-
+ search mode PAGE_CUR_LE_OR_EXTENDS is never used. */
default: assert(0);
}
@@ -2473,7 +2505,9 @@ ha_innobase::index_read_last(
}
/************************************************************************
-Changes the active index of a handle. */
+Changes the active index of a handle. Note that since we build also the
+template for a search, update_thd() must already have been called, in
+::external_lock, for example. */
int
ha_innobase::change_active_index(
@@ -2489,6 +2523,10 @@ ha_innobase::change_active_index(
DBUG_ENTER("change_active_index");
ut_a(prebuilt->trx ==
+ (trx_t*) current_thd->transaction.all.innobase_tid);
+ ut_a(user_thd == current_thd);
+
+ ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
active_index = keynr;
@@ -2516,11 +2554,13 @@ ha_innobase::change_active_index(
dict_index_copy_types(prebuilt->search_tuple, prebuilt->index,
prebuilt->index->n_fields);
- /* Maybe MySQL changes the active index for a handle also
- during some queries, we do not know: then it is safest to build
- the template such that all columns will be fetched. */
+ /* MySQL changes the active index for a handle also during some
+ queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX()
+ and then calculates te sum. Previously we played safe and used
+ the flag ROW_MYSQL_WHOLE_ROW below, but that caused unnecessary
+ copying. Starting from MySQL-4.1 we use a more efficient flag here. */
- build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
+ build_template(prebuilt, user_thd, table, ROW_MYSQL_REC_FIELDS);
DBUG_RETURN(0);
}
@@ -3305,8 +3345,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();
@@ -3862,8 +3902,18 @@ ha_innobase::extra(
obsolete! */
switch (operation) {
+ case HA_EXTRA_FLUSH:
+ if (prebuilt->blob_heap) {
+ row_mysql_prebuilt_free_blob_heap(prebuilt);
+ }
+ break;
case HA_EXTRA_RESET:
- case HA_EXTRA_RESET_STATE:
+ if (prebuilt->blob_heap) {
+ row_mysql_prebuilt_free_blob_heap(prebuilt);
+ }
+ prebuilt->read_just_key = 0;
+ break;
+ case HA_EXTRA_RESET_STATE:
prebuilt->read_just_key = 0;
break;
case HA_EXTRA_NO_KEYREAD:
@@ -4068,9 +4118,8 @@ innodb_show_status(
/*===============*/
THD* thd) /* in: the MySQL query thread of the caller */
{
- String* packet = &thd->packet;
char* buf;
-
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("innodb_show_status");
if (innodb_skip) {
@@ -4091,27 +4140,20 @@ innodb_show_status(
field_list.push_back(new Item_empty_string("Status", strlen(buf)));
- if(send_fields(thd, field_list, 1)) {
-
+ if (protocol->send_fields(&field_list, 1))
+ {
ut_free(buf);
-
DBUG_RETURN(-1);
}
- packet->length(0);
-
- net_store_data(packet, buf);
-
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(),
- packet->length())) {
- ut_free(buf);
-
- DBUG_RETURN(-1);
- }
-
+ protocol->prepare_for_resend();
+ protocol->store(buf, strlen(buf), system_charset_info);
ut_free(buf);
+
+ if (protocol->write())
+ DBUG_RETURN(-1);
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 8031fa0aa29..56546e3e8d0 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -178,7 +178,8 @@ extern char *innobase_home, *innobase_tmpdir, *innobase_logdir;
extern long innobase_lock_scan_time;
extern long innobase_mirrored_log_groups, innobase_log_files_in_group;
extern long innobase_log_file_size, innobase_log_buffer_size;
-extern long innobase_buffer_pool_size, innobase_additional_mem_pool_size;
+extern long innobase_buffer_pool_size, innobase_buffer_pool_awe_mem_mb,
+ innobase_additional_mem_pool_size;
extern long innobase_file_io_threads, innobase_lock_wait_timeout;
extern long innobase_force_recovery, innobase_thread_concurrency;
extern char *innobase_data_home_dir, *innobase_data_file_path;
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index fd1a115ddff..126d0628f79 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;
@@ -49,36 +50,38 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type,
const char *fmt, va_list args)
{
THD* thd = (THD*)param->thd;
- String* packet = &thd->packet;
- uint length;
+ Protocol *protocol= thd->protocol;
+ uint length, msg_length;
char msgbuf[MI_MAX_MSG_BUF];
char name[NAME_LEN*2+2];
- packet->length(0);
- msgbuf[0] = 0; // healthy paranoia ?
- my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
+ msg_length= my_vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
msgbuf[sizeof(msgbuf) - 1] = 0; // healthy paranoia
DBUG_PRINT(msg_type,("message: %s",msgbuf));
+#ifndef EMBEDDED_LIBRARY
if (thd->net.vio == 0)
{
sql_print_error(msgbuf);
return;
}
- if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR | T_AUTO_REPAIR))
+#endif
+
+ if (param->testflag & (T_CREATE_MISSING_KEYS | T_SAFE_REPAIR |
+ T_AUTO_REPAIR))
{
my_message(ER_NOT_KEYFILE,msgbuf,MYF(MY_WME));
return;
}
length=(uint) (strxmov(name, param->db_name,".",param->table_name,NullS) -
name);
- net_store_data(packet, name, length);
- net_store_data(packet, param->op_name);
- net_store_data(packet, msg_type);
-
- net_store_data(packet, msgbuf);
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(), thd->packet.length()))
+ protocol->prepare_for_resend();
+ protocol->store(name, length, system_charset_info);
+ protocol->store(param->op_name, system_charset_info);
+ protocol->store(msg_type, system_charset_info);
+ protocol->store(msgbuf, msg_length, system_charset_info);
+ if (protocol->write())
sql_print_error("Failed on my_net_write, writing to stderr instead: %s\n",
msgbuf);
return;
@@ -86,6 +89,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,11 +130,16 @@ 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");
}
+#ifdef HAVE_REPLICATION
int ha_myisam::net_read_dump(NET* net)
{
int data_fd = file->dfile;
@@ -151,7 +164,6 @@ int ha_myisam::net_read_dump(NET* net)
goto err;
}
}
-
err:
return error;
}
@@ -208,6 +220,7 @@ err:
my_free((gptr) buf, MYF(0));
return error;
}
+#endif /* HAVE_REPLICATION */
/* Name is here without an extension */
@@ -554,7 +567,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);
@@ -727,7 +740,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;
}
@@ -788,7 +801,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;
}
@@ -797,7 +810,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;
}
@@ -1027,7 +1040,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");
@@ -1036,14 +1049,17 @@ 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 ?
+ (pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
+ pos->algorithm;
keydef[i].seg=keyseg;
keydef[i].keysegs=pos->key_parts;
for (j=0 ; j < pos->key_parts ; j++)
@@ -1078,7 +1094,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)
{
@@ -1091,7 +1107,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg,
keydef[i].seg[j].null_bit=0;
keydef[i].seg[j].null_pos=0;
}
- if (field->type() == FIELD_TYPE_BLOB)
+ if ((field->type() == FIELD_TYPE_BLOB) || (field->type() == FIELD_TYPE_GEOMETRY))
{
keydef[i].seg[j].flag|=HA_BLOB_PART;
/* save number of bytes used to pack length */
diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h
index 215608f8f0a..5dc294b3b9f 100644
--- a/sql/ha_myisam.h
+++ b/sql/ha_myisam.h
@@ -127,6 +127,8 @@ class ha_myisam: public handler
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int restore(THD* thd, HA_CHECK_OPT* check_opt);
int backup(THD* thd, HA_CHECK_OPT* check_opt);
+#ifdef HAVE_REPLICATION
int dump(THD* thd, int fd);
int net_read_dump(NET* net);
+#endif
};
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 616248b2cf3..5f07bbc4140 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -160,6 +160,16 @@ int ha_myisammrg::index_last(byte * buf)
return error;
}
+int ha_myisammrg::index_next_same(byte * buf,
+ const byte *key __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ statistic_increment(ha_read_next_count,&LOCK_status);
+ int error=myrg_rnext_same(file,buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
int ha_myisammrg::rnd_init(bool scan)
{
return myrg_extra(file,HA_EXTRA_RESET,0);
diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h
index 440b51e660f..008f5339caf 100644
--- a/sql/ha_myisammrg.h
+++ b/sql/ha_myisammrg.h
@@ -65,15 +65,16 @@ class ha_myisammrg: public handler
int index_prev(byte * buf);
int index_first(byte * buf);
int index_last(byte * buf);
+ int index_next_same(byte *buf, const byte *key, uint keylen);
int rnd_init(bool scan=1);
int rnd_next(byte *buf);
int rnd_pos(byte * buf, byte *pos);
void position(const byte *record);
ha_rows records_in_range(int inx,
- const byte *start_key,uint start_key_len,
- enum ha_rkey_function start_search_flag,
- const byte *end_key,uint end_key_len,
- enum ha_rkey_function end_search_flag);
+ const byte *start_key,uint start_key_len,
+ enum ha_rkey_function start_search_flag,
+ const byte *end_key,uint end_key_len,
+ enum ha_rkey_function end_search_flag);
my_off_t row_position() { return myrg_position(file); }
void info(uint);
int extra(enum ha_extra_function operation);
diff --git a/sql/handler.cc b/sql/handler.cc
index 6e3f8486b45..5353e78cd11 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -727,7 +727,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),system_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 8f1d00f64b5..c6a4578a26c 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..92cd2658967 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -42,6 +42,7 @@ class hash_filo
const hash_get_key get_key;
hash_free_key free_element;
bool init;
+ CHARSET_INFO *hash_charset;
hash_filo_element *first_link,*last_link;
public:
@@ -49,9 +50,11 @@ public:
HASH cache;
hash_filo(uint size_arg, uint key_offset_arg , uint key_length_arg,
- hash_get_key get_key_arg, hash_free_key free_element_arg)
+ hash_get_key get_key_arg, hash_free_key free_element_arg,
+ CHARSET_INFO *hash_charset_arg)
:size(size_arg), key_offset(key_offset_arg), key_length(key_length_arg),
- get_key(get_key_arg), free_element(free_element_arg),init(0)
+ get_key(get_key_arg), free_element(free_element_arg),init(0),
+ hash_charset(hash_charset_arg)
{
bzero((char*) &cache,sizeof(cache));
}
@@ -75,8 +78,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,hash_charset,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 ed56e199c3c..5c4bde99256 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -65,7 +65,8 @@ bool hostname_cache_init()
if (!(hostname_cache=new hash_filo(HOST_CACHE_SIZE, offset,
sizeof(struct in_addr),NULL,
- (hash_free_key) free)))
+ (hash_free_key) free,
+ &my_charset_latin1)))
return 1;
hostname_cache->clear();
return 0;
@@ -223,10 +224,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(&my_charset_latin1,name[0]))
{
char *pos;
- for (pos= name+1 ; isdigit(*pos); pos++) ;
+ for (pos= name+1 ; my_isdigit(&my_charset_latin1,*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 0046f53c6fb..d362ff9ff40 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -34,23 +34,69 @@ void item_init(void)
item_user_lock_init();
}
-Item::Item()
+Item::Item():
+ fixed(0)
{
- marker=0;
- binary=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;
+ marker= 0;
+ maybe_null=null_value=with_sum_func=unsigned_flag=0;
+ coercibility=COER_NOCOLL;
+ name= 0;
+ decimals= 0; max_length= 0;
+ THD *thd= current_thd;
+ next= thd->free_list; // Put in free list
+ thd->free_list= this;
+ loop_id= 0;
}
-void Item::set_name(char *str,uint length)
+/*
+ Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Used for duplicating lists in processing queries with temporary
+ tables
+*/
+Item::Item(THD *thd, Item &item):
+ loop_id(0),
+ str_value(item.str_value),
+ name(item.name),
+ max_length(item.max_length),
+ marker(item.marker),
+ decimals(item.decimals),
+ maybe_null(item.maybe_null),
+ null_value(item.null_value),
+ unsigned_flag(item.unsigned_flag),
+ with_sum_func(item.with_sum_func),
+ fixed(item.fixed),
+ coercibility(item.coercibility)
+{
+ next=thd->free_list; // Put in free list
+ thd->free_list= this;
+}
+
+// Constructor used by Item_field & Item_ref (see Item comment)
+Item_ident::Item_ident(THD *thd, Item_ident &item):
+ Item(thd, item),
+ db_name(item.db_name),
+ table_name(item.table_name),
+ field_name(item.field_name),
+ depended_from(item.depended_from)
+{}
+
+bool Item::check_cols(uint c)
+{
+ if (c != 1)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
+
+void Item::set_name(const char *str,uint length)
{
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 +112,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
@@ -74,8 +120,8 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
if (type() == item->type())
{
if (binary_cmp)
- return !stringcmp(&str_value, &item->str_value);
- return !sortcmp(&str_value, &item->str_value);
+ return !sortcmp(&str_value, &item->str_value, &my_charset_bin);
+ return !sortcmp(&str_value, &item->str_value, charset());
}
return 0;
}
@@ -89,7 +135,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), &my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE)
{
@@ -107,7 +153,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),&my_charset_bin),*res;
if (!(res=val_str(&tmp)) ||
str_to_time(res->ptr(),res->length(),ltime))
{
@@ -117,11 +163,24 @@ bool Item::get_time(TIME *ltime)
return 0;
}
+CHARSET_INFO * Item::default_charset() const
+{
+ return current_thd->db_charset;
+}
+
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
{
set_field(f);
+ coercibility= COER_IMPLICIT;
+ fixed= 1; // This item is not needed in fix_fields
}
+// Constructor need to process subselect with temporary tables (see Item)
+Item_field::Item_field(THD *thd, Item_field &item):
+ Item_ident(thd, item),
+ field(item.field),
+ result_field(item.result_field)
+{ coercibility= COER_IMPLICIT; }
void Item_field::set_field(Field *field_par)
{
@@ -131,8 +190,9 @@ 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());
+ coercibility= COER_IMPLICIT;
}
const char *Item_ident::full_name() const
@@ -140,7 +200,7 @@ const char *Item_ident::full_name() const
char *tmp;
if (!table_name)
return field_name ? field_name : name ? name : "tmp_field";
- if (db_name)
+ if (db_name && db_name[0])
{
tmp=(char*) sql_alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
(uint) strlen(field_name)+3);
@@ -160,6 +220,7 @@ String *Item_field::val_str(String *str)
{
if ((null_value=field->is_null()))
return 0;
+ str->set_charset(str_value.charset());
return field->val_str(str,&str_value);
}
@@ -182,6 +243,7 @@ String *Item_field::str_result(String *str)
{
if ((null_value=result_field->is_null()))
return 0;
+ str->set_charset(str_value.charset());
return result_field->val_str(str,&str_value);
}
@@ -239,13 +301,20 @@ table_map Item_field::used_tables() const
{
if (field->table->const_table)
return 0; // const item
- return field->table->map;
+ return (depended_from ? RAND_TABLE_BIT : field->table->map);
}
+Item *Item_field::get_tmp_table_item(THD *thd)
+{
+ Item_field *new_item= new Item_field(thd, *this);
+ if (new_item)
+ new_item->field= new_item->result_field;
+ return new_item;
+}
String *Item_int::val_str(String *str)
{
- str->set(value);
+ str->set(value, default_charset());
return str;
}
@@ -253,7 +322,7 @@ void Item_int::print(String *str)
{
if (!name)
{
- str_value.set(value);
+ str_value.set(value, default_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -261,7 +330,7 @@ void Item_int::print(String *str)
String *Item_uint::val_str(String *str)
{
- str->set((ulonglong) value);
+ str->set((ulonglong) value, default_charset());
return str;
}
@@ -269,7 +338,7 @@ void Item_uint::print(String *str)
{
if (!name)
{
- str_value.set((ulonglong) value);
+ str_value.set((ulonglong) value, default_charset());
name=str_value.c_ptr();
}
str->append(name);
@@ -278,7 +347,7 @@ void Item_uint::print(String *str)
String *Item_real::val_str(String *str)
{
- str->set(value,decimals);
+ str->set(value,decimals,default_charset());
return str;
}
@@ -298,6 +367,136 @@ 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_type = INT_ITEM;
+}
+
+void Item_param::set_double(double value)
+{
+ real_value=value;
+ item_type = REAL_ITEM;
+}
+
+
+void Item_param::set_value(const char *str, uint length)
+{
+ str_value.set(str,length,default_charset());
+ item_type = STRING_ITEM;
+}
+
+
+void Item_param::set_time(TIME *tm, timestamp_type type)
+{
+ ltime.year= tm->year;
+ ltime.month= tm->month;
+ ltime.day= tm->day;
+
+ ltime.hour= tm->hour;
+ ltime.minute= tm->minute;
+ ltime.second= tm->second;
+
+ ltime.second_part= tm->second_part;
+
+ ltime.time_type= type;
+
+ item_is_time= true;
+ item_type= STRING_ITEM;
+}
+
+
+void Item_param::set_longdata(const char *str, ulong length)
+{
+ str_value.append(str,length);
+ long_data_supplied= 1;
+}
+
+
+int Item_param::save_in_field(Field *field, bool no_conversions)
+{
+ 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;
+ }
+ if (item_is_time)
+ {
+ field->store_time(&ltime, ltime.time_type);
+ return 0;
+ }
+ String *result=val_str(&str_value);
+ return (field->store(result->ptr(),result->length(),field->charset())) ? -1 : 0;
+}
+
+bool Item_param::get_time(TIME *res)
+{
+ *res=ltime;
+ return 0;
+}
+
+double Item_param::val()
+{
+ int err;
+ switch (item_result_type) {
+ case STRING_RESULT:
+ return (double) my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(), (char**) 0, &err);
+ case INT_RESULT:
+ return (double)int_value;
+ default:
+ return real_value;
+ }
+}
+
+
+longlong Item_param::val_int()
+{
+ int err;
+ switch (item_result_type) {
+ case STRING_RESULT:
+ return my_strntoll(str_value.charset(),
+ str_value.ptr(),str_value.length(),10,
+ (char**) 0,&err);
+ 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, default_charset());
+ return str;
+ case REAL_RESULT:
+ str->set(real_value, 2, default_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);
@@ -315,23 +514,210 @@ 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)
{
+ fixed= 1;
return 0;
}
-bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
+bool Item_asterisk_remover::fix_fields(THD *thd,
+ struct st_table_list *list,
+ Item ** ref)
+{
+ DBUG_ENTER("Item_asterisk_remover::fix_fields");
+
+ bool res= 1;
+ if (item)
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ Item_field *fitem= (Item_field*) item;
+ if (list)
+ if (!list->next || fitem->db_name || fitem->table_name)
+ {
+ TABLE_LIST *table= find_table_in_list(list,
+ fitem->db_name,
+ fitem->table_name);
+ if (table)
+ {
+ TABLE * tb= table->table;
+ if (find_table_in_list(table->next, fitem->db_name,
+ fitem->table_name) != 0 ||
+ tb->fields == 1)
+ {
+ if ((item= new Item_field(tb->field[0])))
+ {
+ res= 0;
+ tb->field[0]->query_id= thd->query_id;
+ tb->used_keys&= tb->field[0]->part_of_key;
+ tb->used_fields= tb->fields;
+ }
+ else
+ thd->fatal_error(); // can't create Item => out of memory
+ }
+ else
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ }
+ else
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), fitem->table_name);
+ }
+ else
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ else
+ my_error(ER_NO_TABLES_USED, MYF(0));
+ }
+ else
+ res= item->fix_fields(thd, list, &item);
+ else
+ thd->fatal_error(); // no item given => out of memory
+ DBUG_RETURN(res);
+}
+
+bool Item_ref_on_list_position::fix_fields(THD *thd,
+ struct st_table_list *tables,
+ Item ** reference)
+{
+ if (select_lex->item_list.elements <= pos)
+ {
+ ref= 0;
+ my_error(ER_CARDINALITY_COL, MYF(0), pos);
+ return 1;
+ }
+ ref= select_lex->ref_pointer_array + pos;
+ return Item_ref_null_helper::fix_fields(thd, tables, reference);
+}
+
+double Item_ref_null_helper::val()
+{
+ double tmp= (*ref)->val_result();
+ owner->was_null|= null_value= (*ref)->null_value;
+ return tmp;
+}
+longlong Item_ref_null_helper::val_int()
+{
+ longlong tmp= (*ref)->val_int_result();
+ owner->was_null|= null_value= (*ref)->null_value;
+ return tmp;
+}
+String* Item_ref_null_helper::val_str(String* s)
+{
+ String* tmp= (*ref)->str_result(s);
+ owner->was_null|= null_value= (*ref)->null_value;
+ return tmp;
+}
+bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate)
+{
+ return (owner->was_null|= null_value= (*ref)->get_date(ltime, fuzzydate));
+}
+
+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;
+ TABLE_LIST *where= 0;
+ Field *tmp= (Field *)not_found_field;
+ if (outer_resolving ||
+ (tmp= find_field_in_tables(thd, this, tables, &where, 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;
+#ifdef EMBEDDED_LIBRARY
+ thd->net.last_errno= 0;
+#endif
+ Item **refer= (Item **)not_found_item;
+ uint counter;
+ // Prevent using outer fields in subselects, that is not supported now
+ SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
+ if (outer_resolving ||
+ cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE)
+ for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select());
+ sl;
+ sl= sl->outer_select())
+ {
+ if ((tmp= find_field_in_tables(thd, this,
+ (last= sl)->get_table_list(), &where,
+ 0)) != not_found_field)
+ break;
+ if ((refer= find_item_in_list(this, sl->item_list, &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item)
+ break;
+ if (sl->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE)
+ break; // do not look over derived table
+ }
+ if (!tmp)
+ return -1;
+ else if (!refer)
+ return 1;
+ else if (tmp == not_found_field && refer == (Item **)not_found_item)
+ {
+ // call to return error code
+ find_field_in_tables(thd, this, tables, &where, 1);
+ return -1;
+ }
+ else if (refer != (Item **)not_found_item)
+ {
+ if (!(*refer)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ "forward reference in item list");
+ return -1;
+ }
+
+ Item_ref *r;
+ *ref= r= new Item_ref(last->ref_pointer_array + counter
+ , (char *)table_name,
+ (char *)field_name);
+ if (!r)
+ return 1;
+ if (r->fix_fields(thd, tables, ref) || r->check_cols(1))
+ return 1;
+ // store pointer on SELECT_LEX from which item is dependent
+ r->depended_from= last;
+ cursel->mark_as_dependent(last);
+ return 0;
+ }
+ else
+ {
+ // store pointer on SELECT_LEX from wich item is dependent
+ 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);
+ if (depended_from->having_fix_field)
+ {
+ Item_ref *rf;
+ *ref= rf= new Item_ref((where->db[0]?where->db:0),
+ (char *)where->alias,
+ (char *)field_name);
+ if (!rf)
+ return 1;
+ (rf)->outer_resolving= outer_resolving;
+ return rf->fix_fields(thd, tables, ref) || rf->check_cols(1);
+ }
+ }
+ }
+ else if (!tmp)
+ return -1;
+
set_field(tmp);
}
else if (thd && thd->set_query_id && field->query_id != thd->query_id)
@@ -342,15 +728,21 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
table->used_fields++;
table->used_keys&=field->part_of_key;
}
+ fixed= 1;
return 0;
}
void Item::init_make_field(Send_field *tmp_field,
enum enum_field_types field_type)
-{
- tmp_field->table_name=(char*) "";
- tmp_field->col_name=name;
+{
+ char *empty_name= (char*) "";
+ tmp_field->db_name= empty_name;
+ tmp_field->org_table_name= empty_name;
+ tmp_field->org_col_name= empty_name;
+ tmp_field->table_name= empty_name;
+ tmp_field->col_name= name;
+ tmp_field->charsetnr= charset()->number;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
tmp_field->type=field_type;
tmp_field->length=max_length;
@@ -359,65 +751,24 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->flags |= UNSIGNED_FLAG;
}
-/* ARGSUSED */
-void Item_field::make_field(Send_field *tmp_field)
-{
- field->make_field(tmp_field);
- if (name)
- tmp_field->col_name=name; // Use user supplied name
-}
-
-void Item_int::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
-}
-
-void Item_uint::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_LONGLONG);
- tmp_field->flags|= UNSIGNED_FLAG;
- unsigned_flag=1;
-}
-
-void Item_real::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
-}
-
-void Item_string::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_STRING);
-}
-
-void Item_datetime::make_field(Send_field *tmp_field)
+void Item::make_field(Send_field *tmp_field)
{
- init_make_field(tmp_field,FIELD_TYPE_DATETIME);
+ init_make_field(tmp_field, field_type());
}
-
-void Item_null::make_field(Send_field *tmp_field)
+enum_field_types Item::field_type() const
{
- init_make_field(tmp_field,FIELD_TYPE_NULL);
- tmp_field->length=4;
+ return ((result_type() == STRING_RESULT) ? FIELD_TYPE_VAR_STRING :
+ (result_type() == INT_RESULT) ? FIELD_TYPE_LONGLONG :
+ FIELD_TYPE_DOUBLE);
}
-
-void Item_func::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field, ((result_type() == STRING_RESULT) ?
- FIELD_TYPE_VAR_STRING :
- (result_type() == INT_RESULT) ?
- FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE));
-}
-
-void Item_avg_field::make_field(Send_field *tmp_field)
-{
- init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
-}
-
-void Item_std_field::make_field(Send_field *tmp_field)
+/* ARGSUSED */
+void Item_field::make_field(Send_field *tmp_field)
{
- init_make_field(tmp_field,FIELD_TYPE_DOUBLE);
+ field->make_field(tmp_field);
+ if (name)
+ tmp_field->col_name=name; // Use user supplied name
}
/*
@@ -440,7 +791,7 @@ void Item_field::save_org_in_field(Field *to)
}
}
-bool Item_field::save_in_field(Field *to, bool no_conversions)
+int Item_field::save_in_field(Field *to, bool no_conversions)
{
if (result_field->is_null())
{
@@ -456,6 +807,7 @@ bool Item_field::save_in_field(Field *to, bool no_conversions)
return 0;
}
+
/*
Store null in field
@@ -472,7 +824,7 @@ bool Item_field::save_in_field(Field *to, bool no_conversions)
1 Field doesn't support NULL values and can't handle 'field = NULL'
*/
-bool Item_null::save_in_field(Field *field, bool no_conversions)
+int Item_null::save_in_field(Field *field, bool no_conversions)
{
return set_field_to_null_with_conversions(field, no_conversions);
}
@@ -490,27 +842,29 @@ bool Item_null::save_in_field(Field *field, bool no_conversions)
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, bool no_conversions)
+int Item::save_in_field(Field *field, bool no_conversions)
{
+ int error;
if (result_type() == STRING_RESULT ||
result_type() == REAL_RESULT &&
field->result_type() == STRING_RESULT)
{
String *result;
+ CHARSET_INFO *cs=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, no_conversions);
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)
{
@@ -518,7 +872,7 @@ bool Item::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- field->store(nr);
+ error=field->store(nr);
}
else
{
@@ -526,41 +880,40 @@ bool Item::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null_with_conversions(field, no_conversions);
field->set_notnull();
- field->store(nr);
+ error=field->store(nr);
}
- return 0;
+ return (error) ? -1 : 0;
}
-bool Item_string::save_in_field(Field *field, bool no_conversions)
+int Item_string::save_in_field(Field *field, bool no_conversions)
{
String *result;
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(),charset())) ? -1 : 0;
}
-bool Item_int::save_in_field(Field *field, bool no_conversions)
+
+int Item_int::save_in_field(Field *field, bool no_conversions)
{
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, bool no_conversions)
+
+int Item_real::save_in_field(Field *field, bool no_conversions)
{
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;
}
/****************************************************************************
@@ -583,7 +936,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
@@ -593,7 +946,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()
@@ -608,46 +960,135 @@ longlong Item_varbinary::val_int()
}
-bool Item_varbinary::save_in_field(Field *field, bool no_conversions)
+int Item_varbinary::save_in_field(Field *field, bool no_conversions)
{
+ int error;
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(),charset());
}
else
{
longlong nr=val_int();
- field->store(nr);
+ error=field->store(nr);
}
- return 0;
+ return (error) ? -1 : 0;
}
-void Item_varbinary::make_field(Send_field *tmp_field)
+/*
+ Pack data in buffer for sending
+*/
+
+bool Item_null::send(Protocol *protocol, String *packet)
{
- init_make_field(tmp_field,FIELD_TYPE_STRING);
+ return protocol->store_null();
}
/*
-** pack data in buffer for sending
+ This is only called from items that is not of type item_field
*/
-bool Item::send(THD *thd, String *packet)
+bool Item::send(Protocol *protocol, String *buffer)
{
- char buff[MAX_FIELD_WIDTH];
- CONVERT *convert;
- String s(buff,sizeof(buff)),*res;
- if (!(res=val_str(&s)))
- return net_store_null(packet);
- if ((convert=thd->variables.convert_set))
- return convert->store(packet,res->ptr(),res->length());
- return net_store_data(packet,res->ptr(),res->length());
+ bool result;
+ enum_field_types type;
+ LINT_INIT(result);
+
+ switch ((type=field_type())) {
+ default:
+ case MYSQL_TYPE_NULL:
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_GEOMETRY:
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ {
+ String *res;
+ if ((res=val_str(buffer)))
+ result= protocol->store(res->ptr(),res->length(),res->charset());
+ break;
+ }
+ case MYSQL_TYPE_TINY:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_tiny(nr);
+ break;
+ }
+ case MYSQL_TYPE_SHORT:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_short(nr);
+ break;
+ }
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_long(nr);
+ break;
+ }
+ case MYSQL_TYPE_LONGLONG:
+ {
+ longlong nr;
+ nr= val_int();
+ if (!null_value)
+ result= protocol->store_longlong(nr, unsigned_flag);
+ break;
+ }
+ case MYSQL_TYPE_DOUBLE:
+ {
+ double nr;
+ nr= val();
+ if (!null_value)
+ result= protocol->store(nr, decimals, buffer);
+ break;
+ }
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_TIMESTAMP:
+ {
+ TIME tm;
+ get_date(&tm, 1);
+ if (!null_value)
+ {
+ if (type == MYSQL_TYPE_DATE)
+ return protocol->store_date(&tm);
+ else
+ result= protocol->store(&tm);
+ }
+ break;
+ }
+ case MYSQL_TYPE_TIME:
+ {
+ TIME tm;
+ get_time(&tm);
+ if (!null_value)
+ result= protocol->store_time(&tm);
+ break;
+ }
+ }
+ if (null_value)
+ result= protocol->store_null();
+ return result;
}
-bool Item_null::send(THD *thd, String *packet)
+
+bool Item_field::send(Protocol *protocol, String *buffer)
{
- return net_store_null(packet);
+ return protocol->store(result_field);
}
/*
@@ -655,21 +1096,186 @@ 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)
{
+ uint counter;
if (!ref)
{
- if (!(ref=find_item_in_list(this,thd->lex.select->item_list)))
+ TABLE_LIST *where= 0;
+ SELECT_LEX *sl= (outer_resolving?
+ thd->lex.current_select->select_lex():
+ 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 (outer_resolving ||
+ (ref= find_item_in_list(this,
+ *(thd->lex.current_select->get_item_list()),
+ &counter,
+ ((sl &&
+ thd->lex.current_select->master_unit()->
+ first_select()->linkage !=
+ DERIVED_TABLE_TYPE) ?
+ REPORT_EXCEPT_NOT_FOUND :
+ REPORT_ALL_ERRORS))) ==
+ (Item **)not_found_item)
+ {
+ Field *tmp= (Field*) not_found_field;
+ /*
+ We can't find table field in table list of current select,
+ consequently we have to find it in outer subselect(s).
+ 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,
+ &counter,
+ REPORT_EXCEPT_NOT_FOUND)) !=
+ (Item **)not_found_item)
+ break;
+ if ((tmp= find_field_in_tables(thd, this,
+ sl->get_table_list(), &where,
+ 0)) != not_found_field)
+ break;
+ if (sl->master_unit()->first_select()->linkage ==
+ DERIVED_TABLE_TYPE)
+ break; // do not look over derived table
+ }
+
+ if (!ref)
+ return 1;
+ else if (!tmp)
+ return -1;
+ else if (ref == (Item **)not_found_item && tmp == not_found_field)
+ {
+ // Call to report error
+ find_item_in_list(this,
+ *(thd->lex.current_select->get_item_list()),
+ &counter,
+ REPORT_ALL_ERRORS);
+ ref= 0;
+ return 1;
+ }
+ else if (tmp != not_found_field)
+ {
+ ref= 0; // To prevent "delete *ref;" on ~Item_erf() of this item
+ Item_field* f;
+ if (!((*reference)= f= new Item_field(tmp)))
+ return 1;
+ // store pointer on SELECT_LEX from wich item is dependent
+ f->depended_from= last;
+ thd->lex.current_select->mark_as_dependent(last);
+ return 0;
+ }
+ else
+ {
+ if (!(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ "forward reference in item list");
+ return -1;
+ }
+ /*
+ depended_from: pointer on SELECT_LEX from wich item is dependent
+ */
+ ref= (depended_from= last)->ref_pointer_array + counter;
+ thd->lex.current_select->mark_as_dependent(last);
+ }
+ }
+ else if (!ref)
return 1;
- max_length= (*ref)->max_length;
- maybe_null= (*ref)->maybe_null;
- decimals= (*ref)->decimals;
- binary= (*ref)->binary;
+ else
+ {
+ if (!(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ "forward reference in item list");
+ return -1;
+ }
+ ref= thd->lex.current_select->ref_pointer_array + counter;
+ }
}
+
+ if (((*ref)->with_sum_func &&
+ (depended_from ||
+ !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
+ thd->lex.current_select->select_lex()->having_fix_field))) ||
+ !(*ref)->fixed)
+ {
+ my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
+ ((*ref)->with_sum_func?
+ "reference on group function":
+ "forward reference in item list"));
+ return 1;
+ }
+ max_length= (*ref)->max_length;
+ maybe_null= (*ref)->maybe_null;
+ decimals= (*ref)->decimals;
+ set_charset((*ref)->charset());
+ fixed= 1;
+
+ if (ref && (*ref)->check_cols(1))
+ return 1;
return 0;
}
+bool Item_default_value::eq(const Item *item, bool binary_cmp) const
+{
+ return item->type() == DEFAULT_VALUE_ITEM &&
+ ((Item_default_value *)item)->arg->eq(arg, binary_cmp);
+}
+
+
+bool Item_default_value::fix_fields(THD *thd, struct st_table_list *table_list, Item **items)
+{
+ if (!arg)
+ return false;
+ bool res= arg->fix_fields(thd, table_list, items);
+ if (res)
+ return res;
+ /* arg->type() can be only REF_ITEM or FIELD_ITEM for it defined as
+ simple_ident in sql_yacc.yy
+ */
+ if (arg->type() == REF_ITEM)
+ {
+ Item_ref *ref= (Item_ref *)arg;
+ if (ref->ref[0]->type() != FIELD_ITEM)
+ {
+ return 1;
+ }
+ arg= ref->ref[0];
+ }
+ Item_field *field_arg= (Item_field *)arg;
+ Field *def_field= (Field*) sql_alloc(field_arg->field->size_of());
+ if (!def_field)
+ return 1;
+ memcpy(def_field, field_arg->field, field_arg->field->size_of());
+ def_field->move_field(def_field->table->default_values() -
+ def_field->table->record[0]);
+ set_field(def_field);
+ return 0;
+}
+
+void Item_default_value::print(String *str)
+{
+ if (!arg)
+ {
+ str->append("DEFAULT");
+ return;
+ }
+ str->append("DEFAULT(");
+ arg->print(str);
+ str->append(')');
+}
+
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
@@ -681,6 +1287,8 @@ Item_result item_cmp_type(Item_result a,Item_result b)
return STRING_RESULT;
else if (a == INT_RESULT && b == INT_RESULT)
return INT_RESULT;
+ else if (a == ROW_RESULT || b == ROW_RESULT)
+ return ROW_RESULT;
else
return REAL_RESULT;
}
@@ -697,7 +1305,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),&my_charset_bin),*result;
result=item->val_str(&tmp);
if (item->null_value)
{
@@ -711,7 +1319,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,result->charset());
}
if (res_type == INT_RESULT)
{
@@ -752,13 +1360,13 @@ 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),&my_charset_bin),*item_result;
+ String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin);
item_result=item->val_str(&item_tmp);
if (item->null_value)
return 1; // This must be true
field->val_str(&field_tmp,&field_tmp);
- return !stringcmp(&field_tmp,item_result);
+ return !sortcmp(&field_tmp,item_result,&my_charset_bin);
}
if (res_type == INT_RESULT)
return 1; // Both where of type int
@@ -768,6 +1376,143 @@ bool field_is_equal_to_item(Field *field,Item *item)
return result == field->val_real();
}
+Item_cache* Item_cache::get_cache(Item_result type)
+{
+ switch (type)
+ {
+ case INT_RESULT:
+ return new Item_cache_int();
+ case REAL_RESULT:
+ return new Item_cache_real();
+ case STRING_RESULT:
+ return new Item_cache_str();
+ case ROW_RESULT:
+ return new Item_cache_row();
+ default:
+ // should never be in real life
+ DBUG_ASSERT(0);
+ return 0;
+ }
+}
+
+void Item_cache_str::store(Item *item)
+{
+ str_value.set(buffer, sizeof(buffer), item->charset());
+ value= item->str_result(&str_value);
+ if ((null_value= item->null_value))
+ value= 0;
+ else if (value != &str_value)
+ {
+ /*
+ We copy string value to avoid changing value if 'item' is table field
+ in queries like following (where t1.c is varchar):
+ select a,
+ (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),
+ (select c from t1 where a=t2.a)
+ from t2;
+ */
+ str_value.copy(*value);
+ value= &str_value;
+ }
+
+}
+double Item_cache_str::val()
+{
+ int err;
+ if (value)
+ return my_strntod(value->charset(), (char*) value->ptr(),
+ value->length(), (char**) 0, &err);
+ else
+ return (double)0;
+}
+longlong Item_cache_str::val_int()
+{
+ int err;
+ if (value)
+ return my_strntoll(value->charset(), value->ptr(),
+ value->length(), 10, (char**) 0, &err);
+ else
+ return (longlong)0;
+}
+
+bool Item_cache_row::allocate(uint num)
+{
+ item_count= num;
+ THD *thd= current_thd;
+ return (!(values=
+ (Item_cache **) thd->calloc(sizeof(Item_cache *)*item_count)));
+}
+
+bool Item_cache_row::setup(Item * item)
+{
+ if (!values && allocate(item->cols()))
+ return 1;
+ for (uint i= 0; i < item_count; i++)
+ {
+ Item *el= item->el(i);
+ Item_cache *tmp;
+ if (!(tmp= values[i]= Item_cache::get_cache(el->result_type())))
+ return 1;
+ tmp->setup(el);
+ }
+ return 0;
+}
+
+void Item_cache_row::store(Item * item)
+{
+ null_value= 0;
+ item->bring_value();
+ for (uint i= 0; i < item_count; i++)
+ {
+ values[i]->store(item->el(i));
+ null_value|= values[i]->null_value;
+ }
+}
+
+void Item_cache_row::illegal_method_call(const char *method)
+{
+ DBUG_ENTER("Item_cache_row::illegal_method_call");
+ DBUG_PRINT("error", ("!!! %s method was called for row item", method));
+ DBUG_ASSERT(0);
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ DBUG_VOID_RETURN;
+}
+
+bool Item_cache_row::check_cols(uint c)
+{
+ if (c != item_count)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
+
+bool Item_cache_row::null_inside()
+{
+ for (uint i= 0; i < item_count; i++)
+ {
+ if (values[i]->cols() > 1)
+ {
+ if (values[i]->null_inside())
+ return 1;
+ }
+ else
+ {
+ values[i]->val_int();
+ if (values[i]->null_value)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void Item_cache_row::bring_value()
+{
+ for (uint i= 0; i < item_count; i++)
+ values[i]->bring_value();
+ return;
+}
/*****************************************************************************
** Instantiate templates
diff --git a/sql/item.h b/sql/item.h
index 5e2c2ccc056..d7ca9bf855a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003
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
@@ -19,21 +19,28 @@
#pragma interface /* gcc class implementation */
#endif
+class Protocol;
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); }
static void operator delete(void *ptr,size_t size) {} /*lint -e715 */
- 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};
+ 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_VALUE_ITEM,
+ PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
+ FIELD_VARIANCE_ITEM, CONST_ITEM,
+ SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM};
+
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
+ enum coercion { COER_NOCOLL=3, COER_COERCIBLE=2,
+ COER_IMPLICIT=1, COER_EXPLICIT=0 };
String str_value; /* used to store value */
my_string name; /* Name from select */
@@ -42,31 +49,39 @@ 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;
-
+ my_bool fixed; /* If item fixed with fix_fields */
+ enum coercion coercibility; /* Precedence order of collation */
// alloc & destruct is done as start of select using sql_alloc
Item();
+ /*
+ Constructor used by Item_field, Item_ref & agregate (sum) functions.
+ Used for duplicating lists in processing queries with temporary
+ tables
+ */
+ Item(THD *thd, Item &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, bool no_conversions);
+ virtual void make_field(Send_field *field);
+ virtual bool fix_fields(THD *, struct st_table_list *, Item **);
+ virtual int save_in_field(Field *field, bool no_conversions);
virtual void save_org_in_field(Field *field)
{ (void) save_in_field(field, 1); }
- virtual bool save_safe_in_field(Field *field)
+ virtual int save_safe_in_field(Field *field)
{ return save_in_field(field, 1); }
- virtual bool send(THD *thd, String *str);
+ virtual bool send(Protocol *protocol, String *str);
virtual bool eq(const Item *, bool binary_cmp) const;
virtual Item_result result_type () const { return REAL_RESULT; }
+ virtual enum_field_types field_type() const;
virtual enum Type type() const =0;
virtual double val()=0;
virtual longlong val_int()=0;
virtual String *val_str(String*)=0;
- virtual void make_field(Send_field *field)=0;
- virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; }
+ virtual Field *tmp_table_field() { return 0; }
+ virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); }
@@ -80,33 +95,58 @@ public:
virtual bool const_item() const { return used_tables() == 0; }
virtual void print(String *str_arg) { str_arg->append(full_name()); }
virtual void update_used_tables() {}
- virtual void split_sum_func(List<Item> &fields) {}
+ virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {}
virtual bool get_date(TIME *ltime,bool fuzzydate);
virtual bool get_time(TIME *ltime);
virtual bool get_date_result(TIME *ltime,bool fuzzydate)
{ return get_date(ltime,fuzzydate); }
- virtual bool is_null() { return 0; }
- virtual unsigned int size_of()= 0;
+ virtual bool is_null() { return 0; };
virtual void top_level_item() {}
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
virtual void save_in_result_field(bool no_conversions) {}
virtual void no_rows_in_result() {}
+ virtual Item *copy_or_same(THD *thd) { return this; }
+ virtual Item *real_item() { return this; }
+ virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
+
+ virtual bool binary() const
+ { return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
+ CHARSET_INFO *default_charset() const;
+ CHARSET_INFO *charset() const { return str_value.charset(); };
+ void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
+ virtual void set_outer_resolving() {}
+
+ // Row emulation
+ virtual uint cols() { return 1; }
+ virtual Item* el(uint i) { return this; }
+ virtual Item** addr(uint i) { return 0; }
+ virtual bool check_cols(uint c);
+ // It is not row => null inside is impossible
+ virtual bool null_inside() { return 0; }
+ // used in row subselects to get value of elements
+ virtual void bring_value() {}
};
+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;
+ bool outer_resolving; /* used for items from reduced subselect */
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), outer_resolving(0)
{ name = (char*) field_name_par; }
+ // Constructor used by Item_field & Item_ref (see Item comment)
+ Item_ident(THD *thd, Item_ident &item);
const char *full_name() const;
- unsigned int size_of() { return sizeof(*this);}
+ void set_outer_resolving() { outer_resolving= 1; }
};
@@ -120,7 +160,9 @@ public:
Item_field(const char *db_par,const char *table_name_par,
const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0)
- {}
+ { coercibility= COER_IMPLICIT; }
+ // Constructor need to process subselect with temporary tables (see Item)
+ Item_field(THD *thd, Item_field &item);
Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
@@ -130,28 +172,30 @@ public:
double val_result();
longlong val_int_result();
String *str_result(String* tmp);
- 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 no_conversions);
+ bool send(Protocol *protocol, String *str_arg);
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ void make_field(Send_field *tmp_field);
+ int save_in_field(Field *field,bool no_conversions);
void save_org_in_field(Field *field);
table_map used_tables() const;
enum Item_result result_type () const
{
return field->result_type();
}
- Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
+ enum_field_types field_type() const
+ {
+ return field->type();
+ }
+ Field *tmp_table_field() { return result_field; }
+ Field *tmp_table_field(TABLE *t_arg) { return result_field; }
bool get_date(TIME *ltime,bool fuzzydate);
bool get_date_result(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); }
- unsigned int size_of() { return sizeof(*this);}
+ Item *get_tmp_table_item(THD *thd);
+ friend class Item_default_value;
};
-
class Item_null :public Item
{
public:
@@ -162,18 +206,64 @@ public:
double val();
longlong val_int();
String *val_str(String *str);
- void make_field(Send_field *field);
- bool save_in_field(Field *field, bool no_conversions);
- bool save_safe_in_field(Field *field);
- enum Item_result result_type () const
- { return STRING_RESULT; }
- bool send(THD *thd, String *str);
+ int save_in_field(Field *field, bool no_conversions);
+ int save_safe_in_field(Field *field);
+ bool send(Protocol *protocol, String *str);
+ enum Item_result result_type () const { return STRING_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
+ bool fix_fields(THD *thd, struct st_table_list *list, Item **item)
+ {
+ bool res= Item::fix_fields(thd, list, item);
+ max_length=0;
+ return res;
+ }
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;
+ TIME ltime;
+ enum Item_result item_result_type;
+ enum Type item_type;
+ enum enum_field_types buffer_type;
+ bool item_is_time;
+ 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;
+ item_is_time= false;
+ }
+ enum Type type() const { return item_type; }
+ double val();
+ longlong val_int();
+ String *val_str(String*);
+ int save_in_field(Field *field, bool no_conversions);
+ void set_null();
+ void set_int(longlong i);
+ void set_double(double i);
+ void set_value(const char *str, uint length);
+ void set_long_str(const char *str, ulong length);
+ void set_long_binary(const char *str, ulong length);
+ void set_longdata(const char *str, ulong length);
+ void set_long_end();
+ void set_time(TIME *tm, timestamp_type type);
+ bool get_time(TIME *tm);
+ void reset() {}
+ void (*setup_param_func)(Item_param *param, uchar **pos);
+ enum Item_result result_type () const
+ { return item_result_type; }
+ enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
+ Item *new_item() { return new Item_param(name); }
+};
class Item_int :public Item
{
@@ -192,16 +282,15 @@ public:
(longlong) strtoull(str_arg,(char**) 0,10))
{ max_length= (uint) strlen(str_arg); name=(char*) str_arg;}
enum Type type() const { return INT_ITEM; }
- virtual enum Item_result result_type () const { return INT_RESULT; }
+ enum Item_result result_type () const { return INT_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
longlong val_int() { return value; }
double val() { return (double) value; }
String *val_str(String*);
- void make_field(Send_field *field);
- bool save_in_field(Field *field, bool no_conversions);
+ int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); }
void print(String *str);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -213,15 +302,14 @@ public:
Item_uint(uint32 i) :Item_int((longlong) i, 10) {}
double val() { return ulonglong2double(value); }
String *val_str(String*);
- void make_field(Send_field *field);
Item *new_item() { return new Item_uint(name,max_length); }
- bool fix_fields(THD *thd,struct st_table_list *table_list)
+ bool fix_fields(THD *thd, struct st_table_list *list, Item **item)
{
+ bool res= Item::fix_fields(thd, list, item);
unsigned_flag= 1;
- return 0;
+ return res;
}
void print(String *str);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -244,15 +332,14 @@ public:
max_length=length;
}
Item_real(double value_par) :value(value_par) {}
- bool save_in_field(Field *field, bool no_conversions);
+ int save_in_field(Field *field, bool no_conversions);
enum Type type() const { return REAL_ITEM; }
+ enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
double val() { return value; }
longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));}
String *val_str(String*);
- 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);}
};
@@ -264,84 +351,91 @@ 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, enum coercion coer= COER_COERCIBLE)
{
- str_value.set(str,length);
+ str_value.set(str,length,cs);
+ coercibility= coer;
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, enum coercion coer= COER_COERCIBLE)
{
- str_value.set(str,length);
+ str_value.set(str,length,cs);
+ coercibility= coer;
max_length=length;
name=(char*) name_par;
decimals=NOT_FIXED_DEC;
}
~Item_string() {}
enum Type type() const { return STRING_ITEM; }
- double val() { return atof(str_value.ptr()); }
- longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); }
+ double val()
+ {
+ int err;
+ return my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(), (char**) 0, &err);
+ }
+ longlong val_int()
+ {
+ int err;
+ return my_strntoll(str_value.charset(), str_value.ptr(),
+ str_value.length(), 10, (char**) 0, &err);
+ }
String *val_str(String*) { return (String*) &str_value; }
- bool save_in_field(Field *field, bool no_conversions);
- void make_field(Send_field *field);
+ int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return STRING_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
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); }
- 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);}
-};
-
-
-/* For INSERT ... VALUES (DEFAULT) */
-
-class Item_default :public Item
-{
-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, bool no_conversions)
+ Item *new_item()
{
- field->set_default();
- return 0;
+ return new Item_string(name, str_value.ptr(), max_length, &my_charset_bin);
}
- virtual double val() { return 0.0; }
- 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);}
+ String *const_string() { return &str_value; }
+ inline void append(char *str, uint length) { str_value.append(str, length); }
+ void print(String *str);
};
-
/* for show tables */
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,
+ &my_charset_bin)
{ max_length=19;}
- void make_field(Send_field *field);
- unsigned int size_of() { return sizeof(*this);}
+ enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
};
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,
+ &my_charset_bin)
{ name=(char*) header; max_length=length;}
- unsigned int size_of() { return sizeof(*this);}
};
+class Item_return_int :public Item_int
+{
+ enum_field_types int_field_type;
+public:
+ Item_return_int(const char *name, uint length,
+ enum_field_types field_type_arg)
+ :Item_int(name, 0, length), int_field_type(field_type_arg)
+ {
+ unsigned_flag=1;
+ }
+ enum_field_types field_type() const { return int_field_type; }
+};
+
+
class Item_varbinary :public Item
{
public:
@@ -351,10 +445,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, bool no_conversions);
- void make_field(Send_field *field);
+ int save_in_field(Field *field, bool no_conversions);
enum Item_result result_type () const { return INT_RESULT; }
- unsigned int size_of() { return sizeof(*this);}
+ enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
};
@@ -363,11 +456,15 @@ class Item_result_field :public Item /* Item with result field */
public:
Field *result_field; /* Save result here */
Item_result_field() :result_field(0) {}
+ // Constructor used for Item_sum (see Item comment)
+ Item_result_field(THD *thd, Item_result_field &item):
+ Item(thd, item), result_field(item.result_field)
+ {}
~Item_result_field() {} /* Required with gcc 2.95 */
- Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
+ Field *tmp_table_field() { return result_field; }
+ Field *tmp_table_field(TABLE *t_arg) { return result_field; }
table_map used_tables() const { return 1; }
virtual void fix_length_and_dec()=0;
- unsigned int size_of() { return sizeof(*this);}
void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return 1; }
void save_in_result_field(bool no_conversions)
@@ -382,14 +479,18 @@ class Item_ref :public Item_ident
public:
Field *result_field; /* Save result here */
Item **ref;
- Item_ref(char *db_par,char *table_name_par,char *field_name_par)
+ Item_ref(const char *db_par, const char *table_name_par,
+ const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),ref(0) {}
- Item_ref(Item **item, char *table_name_par,char *field_name_par)
+ Item_ref(Item **item, const char *table_name_par, const char *field_name_par)
:Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
+ // Constructor need to process subselect with temporary tables (see Item)
+ Item_ref(THD *thd, Item_ref &item)
+ :Item_ident(thd, item), ref(item.ref) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
- { return (*ref)->eq(item, binary_cmp); }
- ~Item_ref() { if (ref) delete *ref; }
+ { return ref && (*ref)->eq(item, binary_cmp); }
+ ~Item_ref() { if (ref && (*ref) && (*ref) != this) delete *ref; }
double val()
{
double tmp=(*ref)->val_result();
@@ -417,23 +518,82 @@ public:
{
return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
}
- bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); }
+ bool send(Protocol *prot, String *tmp){ return (*ref)->send(prot, 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, bool no_conversions)
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ int save_in_field(Field *field, bool no_conversions)
{ return (*ref)->save_in_field(field, no_conversions); }
void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
enum Item_result result_type () const { return (*ref)->result_type(); }
+ enum_field_types field_type() const { return (*ref)->field_type(); }
table_map used_tables() const { return (*ref)->used_tables(); }
- unsigned int size_of() { return sizeof(*this);}
- void set_result_field(Field *field) { result_field= field; }
+ void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return 1; }
void save_in_result_field(bool no_conversions)
{
(*ref)->save_in_field(result_field, no_conversions);
}
+ Item *real_item() { return *ref; }
};
+class Item_in_subselect;
+class Item_ref_null_helper: public Item_ref
+{
+protected:
+ Item_in_subselect* owner;
+public:
+ Item_ref_null_helper(Item_in_subselect* master, Item **item,
+ const char *table_name_par, const char *field_name_par):
+ Item_ref(item, table_name_par, field_name_par), owner(master) {}
+ double val();
+ longlong val_int();
+ String* val_str(String* s);
+ bool get_date(TIME *ltime, bool fuzzydate);
+};
+
+
+/*
+ Used to find item in list of select items after '*' items processing.
+
+ Because item '*' can be used in item list. when we create
+ Item_ref_on_list_position we do not know how item list will be changed, but
+ we know number of item position (I mean queries like "select * from t").
+*/
+class Item_ref_on_list_position: public Item_ref_null_helper
+{
+protected:
+ /*
+ select_lex used for:
+ 1) receiving expanded variant of item list (to check max possible
+ number of elements);
+ 2) to have access to ref_pointer_array, via wich item will refered.
+ */
+ st_select_lex *select_lex;
+ uint pos;
+public:
+ Item_ref_on_list_position(Item_in_subselect* master,
+ st_select_lex *sl, uint num,
+ char *table_name, char *field_name):
+ Item_ref_null_helper(master, 0, table_name, field_name),
+ select_lex(sl), pos(num) {}
+ bool fix_fields(THD *, struct st_table_list *, Item ** ref);
+};
+
+/*
+ To resolve '*' field moved to condition
+ and register NULL values
+*/
+class Item_asterisk_remover :public Item_ref_null_helper
+{
+ Item *item;
+public:
+ Item_asterisk_remover(Item_in_subselect *master, Item *it,
+ char *table, char *field):
+ Item_ref_null_helper(master, &item, table, field),
+ item(it)
+ {}
+ bool fix_fields(THD *, struct st_table_list *, Item ** ref);
+};
/*
The following class is used to optimize comparing of date columns
@@ -447,23 +607,27 @@ 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, bool no_conversions)
+ int save_in_field(Field *field, bool no_conversions)
{
return ref->save_in_field(field, no_conversions);
}
- unsigned int size_of() { return sizeof(*this);}
};
+#include "gstream.h"
+#include "spatial.h"
#include "item_sum.h"
#include "item_func.h"
+#include "item_row.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
{
+ enum enum_field_types cached_field_type;
public:
Item *item;
Item_copy_string(Item *i) :item(i)
@@ -472,21 +636,30 @@ public:
decimals=item->decimals;
max_length=item->max_length;
name=item->name;
+ cached_field_type= item->field_type();
}
~Item_copy_string() { delete item; }
enum Type type() const { return COPY_STR_ITEM; }
enum Item_result result_type () const { return STRING_RESULT; }
+ enum_field_types field_type() const { return cached_field_type; }
double val()
- { return null_value ? 0.0 : atof(str_value.c_ptr()); }
+ {
+ int err;
+ return (null_value ? 0.0 :
+ my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(),NULL,&err));
+ }
longlong val_int()
- { return null_value ? LL(0) : strtoll(str_value.c_ptr(),(char**) 0,10); }
+ {
+ int err;
+ return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err);
+ }
String *val_str(String*);
void make_field(Send_field *field) { item->make_field(field); }
void copy();
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);}
};
@@ -497,7 +670,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
@@ -508,7 +680,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);}
};
@@ -519,7 +690,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
@@ -529,7 +699,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);}
};
@@ -546,7 +715,154 @@ public:
buff= (char*) sql_calloc(length=field->pack_length());
}
bool cmp(void);
- unsigned int size_of() { return sizeof(*this);}
+};
+
+class Item_default_value : public Item_field
+{
+public:
+ Item *arg;
+ Item_default_value() :
+ Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {}
+ Item_default_value(Item *a) :
+ Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {}
+ enum Type type() const { return DEFAULT_VALUE_ITEM; }
+ bool eq(const Item *item, bool binary_cmp) const;
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ void set_outer_resolving() { arg->set_outer_resolving(); }
+ void print(String *str);
+ virtual bool basic_const_item() const { return true; }
+ int save_in_field(Field *field, bool no_conversions)
+ {
+ if (!arg)
+ {
+ field->set_default();
+ return 0;
+ }
+ return Item_field::save_in_field(field, no_conversions);
+ }
+ table_map used_tables() const { return (table_map)0L; }
+};
+
+class Item_cache: public Item
+{
+ table_map used_table_map;
+public:
+ Item_cache(): used_table_map(0) {fixed= 1; null_value= 1;}
+
+ void set_used_tables(table_map map) { used_table_map= map; }
+
+ virtual bool allocate(uint i) { return 0; };
+ virtual bool setup(Item *) { return 0; };
+ virtual void store(Item *)= 0;
+ void set_len_n_dec(uint32 max_len, uint8 dec)
+ {
+ max_length= max_len;
+ decimals= dec;
+ }
+ enum Type type() const { return CACHE_ITEM; }
+ static Item_cache* get_cache(Item_result type);
+ table_map used_tables() const { return used_table_map; }
+};
+
+class Item_cache_int: public Item_cache
+{
+ longlong value;
+public:
+ Item_cache_int(): Item_cache() {}
+
+ void store(Item *item)
+ {
+ value= item->val_int_result();
+ null_value= item->null_value;
+ }
+ double val() { return (double) value; }
+ longlong val_int() { return value; }
+ String* val_str(String *str) { str->set(value, default_charset()); return str; }
+ enum Item_result result_type() const { return INT_RESULT; }
+};
+
+class Item_cache_real: public Item_cache
+{
+ double value;
+public:
+ Item_cache_real(): Item_cache() {}
+
+ void store(Item *item)
+ {
+ value= item->val_result();
+ null_value= item->null_value;
+ }
+ double val() { return value; }
+ longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5)); }
+ String* val_str(String *str)
+ {
+ str->set(value, decimals, default_charset());
+ return str;
+ }
+ enum Item_result result_type() const { return REAL_RESULT; }
+};
+
+class Item_cache_str: public Item_cache
+{
+ char buffer[80];
+ String *value;
+public:
+ Item_cache_str(): Item_cache() { }
+
+ void store(Item *item);
+ double val();
+ longlong val_int();
+ String* val_str(String *) { return value; }
+ enum Item_result result_type() const { return STRING_RESULT; }
+ CHARSET_INFO *charset() const { return value->charset(); };
+};
+
+class Item_cache_row: public Item_cache
+{
+ Item_cache **values;
+ uint item_count;
+public:
+ Item_cache_row(): Item_cache(), values(0), item_count(2) {}
+
+ /*
+ 'allocate' used only in row transformer, to preallocate space for row
+ cache.
+ */
+ bool allocate(uint num);
+ /*
+ 'setup' is needed only by row => it not called by simple row subselect
+ (only by IN subselect (in subselect optimizer))
+ */
+ bool setup(Item *item);
+ void store(Item *item);
+ void illegal_method_call(const char *);
+ void make_field(Send_field *)
+ {
+ illegal_method_call((const char*)"make_field");
+ };
+ double val()
+ {
+ illegal_method_call((const char*)"val");
+ return 0;
+ };
+ longlong val_int()
+ {
+ illegal_method_call((const char*)"val_int");
+ return 0;
+ };
+ String *val_str(String *)
+ {
+ illegal_method_call((const char*)"val_str");
+ return 0;
+ };
+ enum Item_result result_type() const { return ROW_RESULT; }
+
+ uint cols() { return item_count; }
+ Item* el(uint i) { return values[i]; }
+ Item** addr(uint i) { return (Item **) (values + i); }
+ bool check_cols(uint c);
+ bool null_inside();
+ void bring_value();
};
extern Item_buff *new_Item_buff(Item *item);
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index b55a4dc66a0..c4431294dff 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -56,10 +56,8 @@ bool Item_str_buff::cmp(void)
}
else if (null_value)
return 0; // new and old value was null
- else if (!item->binary)
- tmp= sortcmp(&value,res) != 0;
else
- tmp= stringcmp(&value,res) != 0;
+ tmp= sortcmp(&value,res,item->charset()) != 0;
if (tmp)
value.copy(*res); // Remember for next cmp
return tmp;
@@ -99,7 +97,7 @@ bool Item_field_buff::cmp(void)
{
bool tmp= field->cmp(buff) != 0; // This is not a blob!
if (tmp)
- field->get_image(buff,length);
+ field->get_image(buff,length,field->charset());
if (null_value != field->is_null())
{
null_value= !null_value;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index d96069a17aa..a88b269eedd 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003
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
@@ -23,6 +23,30 @@
#include "mysql_priv.h"
#include <m_ctype.h>
+Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b)
+{
+ return new Item_func_eq(a, b);
+}
+Item_bool_func2* Item_bool_func2::ne_creator(Item *a, Item *b)
+{
+ return new Item_func_ne(a, b);
+}
+Item_bool_func2* Item_bool_func2::gt_creator(Item *a, Item *b)
+{
+ return new Item_func_gt(a, b);
+}
+Item_bool_func2* Item_bool_func2::lt_creator(Item *a, Item *b)
+{
+ return new Item_func_lt(a, b);
+}
+Item_bool_func2* Item_bool_func2::ge_creator(Item *a, Item *b)
+{
+ return new Item_func_ge(a, b);
+}
+Item_bool_func2* Item_bool_func2::le_creator(Item *a, Item *b)
+{
+ return new Item_func_le(a, b);
+}
/*
Test functions
@@ -42,14 +66,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, 1) &&
- !((*item)->null_value))
+ if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
Item *tmp=new Item_int_with_ref(field->val_int(), *item);
if (tmp)
@@ -60,10 +87,9 @@ static bool convert_constant_item(Field *field, Item **item)
return 0;
}
-
void Item_bool_func2::fix_length_and_dec()
{
- max_length=1; // Function returns 0 or 1
+ max_length= 1; // Function returns 0 or 1
/*
As some compare functions are generated after sql_yacc,
@@ -79,7 +105,8 @@ void Item_bool_func2::fix_length_and_dec()
{
if (convert_constant_item(field,&args[1]))
{
- cmp_func= &Item_bool_func2::compare_int; // Works for all types.
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
return;
}
}
@@ -91,164 +118,287 @@ void Item_bool_func2::fix_length_and_dec()
{
if (convert_constant_item(field,&args[0]))
{
- cmp_func= &Item_bool_func2::compare_int; // Works for all types.
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1,
+ INT_RESULT); // Works for all types.
return;
}
}
}
- set_cmp_func(item_cmp_type(args[0]->result_type(),args[1]->result_type()));
+ set_cmp_func();
+ /* QQ: COERCIBILITY */
+ cmp_charset= (args[0]->binary() || args[1]->binary()) ?
+ &my_charset_bin : args[0]->charset();
}
-void Item_bool_func2::set_cmp_func(Item_result type)
+int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
{
- switch (type) {
- case STRING_RESULT:
- cmp_func=&Item_bool_func2::compare_string;
- break;
- case REAL_RESULT:
- cmp_func=&Item_bool_func2::compare_real;
- break;
- case INT_RESULT:
- cmp_func=&Item_bool_func2::compare_int;
- break;
+ owner= item;
+ func= comparator_matrix[type][(owner->functype() == Item_func::EQUAL_FUNC)?
+ 1:0];
+ if (type == ROW_RESULT)
+ {
+ uint n= (*a)->cols();
+ if (n != (*b)->cols())
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), n);
+ comparators= 0;
+ return 1;
+ }
+ if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n)))
+ for (uint i=0; i < n; i++)
+ {
+ if ((*a)->el(i)->cols() != (*b)->el(i)->cols())
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols());
+ return 1;
+ }
+ comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i));
+ }
+ else
+ return 1;
}
+ return 0;
}
-
-int Item_bool_func2::compare_string()
+int Arg_comparator::compare_string()
{
String *res1,*res2;
- if ((res1=args[0]->val_str(&tmp_value1)))
+ if ((res1= (*a)->val_str(&owner->tmp_value1)))
{
- if ((res2=args[1]->val_str(&tmp_value2)))
+ if ((res2= (*b)->val_str(&owner->tmp_value2)))
{
- null_value=0;
- return binary ? stringcmp(res1,res2) : sortcmp(res1,res2);
+ owner->null_value= 0;
+ return sortcmp(res1,res2,owner->cmp_charset);
}
}
- null_value=1;
+ owner->null_value= 1;
return -1;
}
-int Item_bool_func2::compare_real()
+int Arg_comparator::compare_e_string()
{
- double val1=args[0]->val();
- if (!args[0]->null_value)
+ String *res1,*res2;
+ res1= (*a)->val_str(&owner->tmp_value1);
+ res2= (*b)->val_str(&owner->tmp_value2);
+ if (!res1 || !res2)
+ return test(res1 == res2);
+ return test(sortcmp(res1, res2, owner->cmp_charset) == 0);
+}
+
+
+int Arg_comparator::compare_real()
+{
+ double val1= (*a)->val();
+ if (!(*a)->null_value)
{
- double val2=args[1]->val();
- if (!args[1]->null_value)
+ double val2= (*b)->val();
+ if (!(*b)->null_value)
{
- null_value=0;
+ owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
- null_value=1;
+ owner->null_value= 1;
return -1;
}
+int Arg_comparator::compare_e_real()
+{
+ double val1= (*a)->val();
+ double val2= (*b)->val();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2);
+}
-int Item_bool_func2::compare_int()
+int Arg_comparator::compare_int()
{
- longlong val1=args[0]->val_int();
- if (!args[0]->null_value)
+ longlong val1= (*a)->val_int();
+ if (!(*a)->null_value)
{
- longlong val2=args[1]->val_int();
- if (!args[1]->null_value)
+ longlong val2= (*b)->val_int();
+ if (!(*b)->null_value)
{
- null_value=0;
+ owner->null_value= 0;
if (val1 < val2) return -1;
if (val1 == val2) return 0;
return 1;
}
}
- null_value=1;
+ owner->null_value= 1;
return -1;
}
+int Arg_comparator::compare_e_int()
+{
+ longlong val1= (*a)->val_int();
+ longlong val2= (*b)->val_int();
+ if ((*a)->null_value || (*b)->null_value)
+ return test((*a)->null_value && (*b)->null_value);
+ return test(val1 == val2);
+}
-longlong Item_func_eq::val_int()
+int Arg_comparator::compare_row()
{
- int value=(this->*cmp_func)();
- return value == 0 ? 1 : 0;
+ int res= 0;
+ (*a)->bring_value();
+ (*b)->bring_value();
+ uint n= (*a)->cols();
+ for (uint i= 0; i<n; i++)
+ {
+ if ((res= comparators[i].compare()))
+ return res;
+ if (owner->null_value)
+ return -1;
+ }
+ return res;
}
-/* Same as Item_func_eq, but NULL = NULL */
+int Arg_comparator::compare_e_row()
+{
+ int res= 0;
+ (*a)->bring_value();
+ (*b)->bring_value();
+ uint n= (*a)->cols();
+ for (uint i= 0; i<n; i++)
+ {
+ if ((res= !comparators[i].compare()))
+ return 0;
+ }
+ return 1;
+}
-void Item_func_equal::fix_length_and_dec()
+bool Item_in_optimizer::preallocate_row()
{
- Item_bool_func2::fix_length_and_dec();
- cmp_result_type=item_cmp_type(args[0]->result_type(),args[1]->result_type());
- maybe_null=null_value=0;
+ return (!(cache= Item_cache::get_cache(ROW_RESULT)));
}
-longlong Item_func_equal::val_int()
+
+bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
+ Item ** ref)
{
- switch (cmp_result_type) {
- case STRING_RESULT:
+ if (args[0]->fix_fields(thd, tables, args))
+ return 1;
+ if (args[0]->maybe_null)
+ maybe_null=1;
+ /*
+ TODO: Check if following is right
+ (set_charset set type of result, not how compare should be used)
+ */
+ if (args[0]->binary())
+ set_charset(&my_charset_bin);
+ with_sum_func= args[0]->with_sum_func;
+ used_tables_cache= args[0]->used_tables();
+ const_item_cache= args[0]->const_item();
+ if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
+ return 1;
+ cache->setup(args[0]);
+ if (cache->cols() == 1)
{
- String *res1,*res2;
- res1=args[0]->val_str(&tmp_value1);
- res2=args[1]->val_str(&tmp_value2);
- if (!res1 || !res2)
- return test(res1 == res2);
- return (binary ? test(stringcmp(res1,res2) == 0) :
- test(sortcmp(res1,res2) == 0));
+ if (args[0]->used_tables())
+ cache->set_used_tables(RAND_TABLE_BIT);
+ else
+ cache->set_used_tables(0);
}
- case REAL_RESULT:
+ else
{
- double val1=args[0]->val();
- double val2=args[1]->val();
- if (args[0]->null_value || args[1]->null_value)
- return test(args[0]->null_value && args[1]->null_value);
- return test(val1 == val2);
+ uint n= cache->cols();
+ for (uint i= 0; i < n; i++)
+ {
+ if (args[0]->el(i)->used_tables())
+ ((Item_cache *)cache->el(i))->set_used_tables(RAND_TABLE_BIT);
+ else
+ ((Item_cache *)cache->el(i))->set_used_tables(0);
+ }
}
- case INT_RESULT:
+ if (args[1]->fix_fields(thd, tables, args))
+ return 1;
+ Item_in_subselect * sub= (Item_in_subselect *)args[1];
+ if (args[0]->cols() != sub->engine->cols())
{
- longlong val1=args[0]->val_int();
- longlong val2=args[1]->val_int();
- if (args[0]->null_value || args[1]->null_value)
- return test(args[0]->null_value && args[1]->null_value);
- return test(val1 == val2);
+ my_error(ER_CARDINALITY_COL, MYF(0), args[0]->cols());
+ return 1;
}
+ if (args[1]->maybe_null)
+ maybe_null=1;
+ with_sum_func= with_sum_func || args[1]->with_sum_func;
+ used_tables_cache|= args[1]->used_tables();
+ const_item_cache&= args[1]->const_item();
+ return 0;
+}
+
+longlong Item_in_optimizer::val_int()
+{
+ cache->store(args[0]);
+ if (cache->null_value)
+ {
+ null_value= 1;
+ return 0;
}
- return 0; // Impossible
+ longlong tmp= args[1]->val_int_result();
+ null_value= args[1]->null_value;
+ return tmp;
}
+bool Item_in_optimizer::is_null()
+{
+ cache->store(args[0]);
+ return (null_value= (cache->null_value || args[1]->is_null()));
+}
+
+longlong Item_func_eq::val_int()
+{
+ int value= cmp.compare();
+ return value == 0 ? 1 : 0;
+}
+
+/* Same as Item_func_eq, but NULL = NULL */
+
+void Item_func_equal::fix_length_and_dec()
+{
+ Item_bool_func2::fix_length_and_dec();
+ maybe_null=null_value=0;
+}
+
+longlong Item_func_equal::val_int()
+{
+ return cmp.compare();
+}
longlong Item_func_ne::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value != 0 && !null_value ? 1 : 0;
}
longlong Item_func_ge::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value >= 0 ? 1 : 0;
}
longlong Item_func_gt::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value > 0 ? 1 : 0;
}
longlong Item_func_le::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value <= 0 && !null_value ? 1 : 0;
}
longlong Item_func_lt::val_int()
{
- int value=(this->*cmp_func)();
+ int value= cmp.compare();
return value < 0 && !null_value ? 1 : 0;
}
@@ -262,7 +412,7 @@ longlong Item_func_strcmp::val_int()
null_value=1;
return 0;
}
- int value= binary ? stringcmp(a,b) : sortcmp(a,b);
+ int value= sortcmp(a,b,cmp_charset);
null_value=0;
return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1);
}
@@ -270,60 +420,45 @@ longlong Item_func_strcmp::val_int()
void Item_func_interval::fix_length_and_dec()
{
- bool nums=1;
- uint i;
- for (i=0 ; i < arg_count ; i++)
+ if (row->cols() > 8)
{
- if (!args[i])
- return; // End of memory
- if (args[i]->type() != Item::INT_ITEM &&
- args[i]->type() != Item::REAL_ITEM)
+ bool consts=1;
+
+ for (uint i=1 ; consts && i < row->cols() ; i++)
{
- nums=0;
- break;
+ consts&= row->el(i)->const_item();
}
- }
- if (nums && arg_count >= 8)
- {
- if ((intervals=(double*) sql_alloc(sizeof(double)*arg_count)))
+
+ if (consts &&
+ (intervals=(double*) sql_alloc(sizeof(double)*(row->cols()-1))))
{
- for (i=0 ; i < arg_count ; i++)
- intervals[i]=args[i]->val();
+ for (uint i=1 ; i < row->cols(); i++)
+ intervals[i-1]=row->el(i)->val();
}
}
- maybe_null=0; max_length=2;
- used_tables_cache|=item->used_tables();
- with_sum_func= with_sum_func || item->with_sum_func;
+ maybe_null= 0;
+ max_length= 2;
+ used_tables_cache|= row->used_tables();
+ with_sum_func= with_sum_func || row->with_sum_func;
}
-void Item_func_interval::split_sum_func(List<Item> &fields)
-{
- if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
- item->split_sum_func(fields);
- else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
- {
- fields.push_front(item);
- item= new Item_ref((Item**) fields.head_ref(), 0, item->name);
- }
- Item_int_func::split_sum_func(fields);
-}
/*
return -1 if null value,
0 if lower than lowest
- 1 - arg_count if between args[n] and args[n+1]
- arg_count+1 if higher than biggest argument
+ 1 - arg_count-1 if between args[n] and args[n+1]
+ arg_count if higher than biggest argument
*/
longlong Item_func_interval::val_int()
{
- double value=item->val();
- if (item->null_value)
- return -1; // -1 if null /* purecov: inspected */
+ double value=row->el(0)->val();
+ if (row->el(0)->null_value)
+ return -1; // -1 if null
if (intervals)
{ // Use binary search to find interval
uint start,end;
- start=0; end=arg_count-1;
+ start=1; end=row->cols()-2;
while (start != end)
{
uint mid=(start+end+1)/2;
@@ -334,28 +469,19 @@ longlong Item_func_interval::val_int()
}
return (value < intervals[start]) ? 0 : start+1;
}
- if (args[0]->val() > value)
- return 0;
- for (uint i=1 ; i < arg_count ; i++)
+
+ uint i;
+ for (i=1 ; i < row->cols() ; i++)
{
- if (args[i]->val() > value)
- return i;
+ if (row->el(i)->val() > value)
+ return i-1;
}
- return (longlong) arg_count;
-}
-
-
-void Item_func_interval::update_used_tables()
-{
- Item_func::update_used_tables();
- item->update_used_tables();
- used_tables_cache|=item->used_tables();
- const_item_cache&=item->const_item();
+ return i-1;
}
void Item_func_between::fix_length_and_dec()
{
- max_length=1;
+ max_length= 1;
/*
As some compare functions are generated after sql_yacc,
@@ -366,10 +492,11 @@ 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)
- string_compare=stringcmp;
+ /* QQ: COERCIBILITY */
+ if (args[0]->binary() | args[1]->binary() | args[2]->binary())
+ cmp_charset= &my_charset_bin;
else
- string_compare=sortcmp;
+ cmp_charset= args[0]->charset();
/*
Make a special case of compare with date/time and longlong fields.
@@ -401,17 +528,17 @@ longlong Item_func_between::val_int()
a=args[1]->val_str(&value1);
b=args[2]->val_str(&value2);
if (!args[1]->null_value && !args[2]->null_value)
- return (string_compare(value,a) >= 0 && string_compare(value,b) <= 0) ?
- 1 : 0;
+ return (sortcmp(value,a,cmp_charset) >= 0 &&
+ sortcmp(value,b,cmp_charset) <= 0) ? 1 : 0;
if (args[1]->null_value && args[2]->null_value)
null_value=1;
else if (args[1]->null_value)
{
- null_value= string_compare(value,b) <= 0; // not null if false range.
+ null_value= sortcmp(value,b,cmp_charset) <= 0; // not null if false range.
}
else
{
- null_value= string_compare(value,a) >= 0; // not null if false range.
+ null_value= sortcmp(value,a,cmp_charset) >= 0; // not null if false range.
}
}
else if (cmp_type == INT_RESULT)
@@ -540,21 +667,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
@@ -615,7 +743,7 @@ double
Item_func_nullif::val()
{
double value;
- if (!(this->*cmp_func)() || null_value)
+ if (!cmp.compare() || null_value)
{
null_value=1;
return 0.0;
@@ -629,7 +757,7 @@ longlong
Item_func_nullif::val_int()
{
longlong value;
- if (!(this->*cmp_func)() || null_value)
+ if (!cmp.compare() || null_value)
{
null_value=1;
return 0;
@@ -643,7 +771,7 @@ String *
Item_func_nullif::val_str(String *str)
{
String *res;
- if (!(this->*cmp_func)() || null_value)
+ if (!cmp.compare() || null_value)
{
null_value=1;
return 0;
@@ -692,12 +820,13 @@ 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)
+ /* QQ: COERCIBILITY */
+ if (first_expr_is_binary || args[i]->binary())
{
- if (stringcmp(tmp,first_expr_str)==0)
+ if (sortcmp(tmp,first_expr_str,&my_charset_bin)==0)
return args[i+1];
}
- else if (sortcmp(tmp,first_expr_str)==0)
+ else if (sortcmp(tmp,first_expr_str,tmp->charset())==0)
return args[i+1];
}
break;
@@ -722,6 +851,12 @@ Item *Item_func_case::find_item(String *str)
}
if (args[i]->val()==first_expr_real && !args[i]->null_value)
return args[i+1];
+ break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
}
// No, WHEN clauses all missed, return ELSE expression
@@ -750,7 +885,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());
Item *item=find_item(&dummy_str);
longlong res;
@@ -767,7 +902,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());
Item *item=find_item(&dummy_str);
double res;
@@ -783,18 +918,21 @@ 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) ||
+ first_expr->check_cols(1)) ||
+ else_expr && (else_expr->fix_fields(thd, tables, &else_expr) ||
+ else_expr->check_cols(1)))
return 1;
- if (Item_func::fix_fields(thd,tables))
+ if (Item_func::fix_fields(thd, tables, ref))
return 1;
if (first_expr)
{
used_tables_cache|=(first_expr)->used_tables();
const_item_cache&= (first_expr)->const_item();
with_sum_func= with_sum_func || (first_expr)->with_sum_func;
+ first_expr_is_binary= first_expr->binary();
}
if (else_expr)
{
@@ -807,30 +945,43 @@ Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables)
return 0;
}
-void Item_func_case::split_sum_func(List<Item> &fields)
+
+void Item_func_case::split_sum_func(Item **ref_pointer_array,
+ List<Item> &fields)
{
if (first_expr)
{
if (first_expr->with_sum_func && first_expr->type() != SUM_FUNC_ITEM)
- first_expr->split_sum_func(fields);
+ first_expr->split_sum_func(ref_pointer_array, fields);
else if (first_expr->used_tables() || first_expr->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(first_expr);
- first_expr= new Item_ref((Item**) fields.head_ref(), 0,
- first_expr->name);
+ ref_pointer_array[el]= first_expr;
+ first_expr= new Item_ref(ref_pointer_array + el, 0, first_expr->name);
}
}
if (else_expr)
{
if (else_expr->with_sum_func && else_expr->type() != SUM_FUNC_ITEM)
- else_expr->split_sum_func(fields);
+ else_expr->split_sum_func(ref_pointer_array, fields);
else if (else_expr->used_tables() || else_expr->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(else_expr);
- else_expr= new Item_ref((Item**) fields.head_ref(), 0, else_expr->name);
+ ref_pointer_array[el]= else_expr;
+ else_expr= new Item_ref(ref_pointer_array + el, 0, else_expr->name);
}
}
- Item_func::split_sum_func(fields);
+ Item_func::split_sum_func(ref_pointer_array, fields);
+}
+
+
+void Item_func_case::set_outer_resolving()
+{
+ first_expr->set_outer_resolving();
+ else_expr->set_outer_resolving();
+ Item_func::set_outer_resolving();
}
void Item_func_case::update_used_tables()
@@ -919,8 +1070,8 @@ double Item_func_coalesce::val()
void Item_func_coalesce::fix_length_and_dec()
{
- max_length=0;
- decimals=0;
+ max_length= 0;
+ decimals= 0;
cached_result_type = args[0]->result_type();
for (uint i=0 ; i < arg_count ; i++)
{
@@ -943,6 +1094,11 @@ static int cmp_double(double *a,double *b)
return *a < *b ? -1 : *a == *b ? 0 : 1;
}
+static int cmp_row(cmp_item_row* a, cmp_item_row* b)
+{
+ return a->compare(b);
+}
+
int in_vector::find(Item *item)
{
byte *result=get_value(item);
@@ -965,15 +1121,19 @@ int in_vector::find(Item *item)
return (int) ((*compare)(base+start*size,result) == 0);
}
-
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), &my_charset_bin)
{}
in_string::~in_string()
{
- for (uint i=0 ; i < count ; i++)
- ((String*) base)[i].free();
+ if (base)
+ {
+ // base was allocated with help of sql_alloc => following is OK
+ for (uint i=0 ; i < count ; i++)
+ ((String*) base)[i].free();
+ }
}
void in_string::set(uint pos,Item *item)
@@ -982,13 +1142,48 @@ void in_string::set(uint pos,Item *item)
String *res=item->val_str(str);
if (res && res != str)
*str= *res;
+ if (!str->charset())
+ {
+ CHARSET_INFO *cs;
+ if (!(cs= item->charset()))
+ cs= &my_charset_bin; // Should never happen for STR items
+ str->set_charset(cs);
+ }
}
+
byte *in_string::get_value(Item *item)
{
return (byte*) item->val_str(&tmp);
}
+in_row::in_row(uint elements, Item * item)
+{
+ base= (char*) new cmp_item_row[count= elements];
+ size= sizeof(cmp_item_row);
+ compare= (qsort_cmp) cmp_row;
+ tmp.store_value(item);
+}
+
+in_row::~in_row()
+{
+ if (base)
+ delete [] (cmp_item_row*) base;
+}
+
+byte *in_row::get_value(Item *item)
+{
+ tmp.store_value(item);
+ return (byte *)&tmp;
+}
+
+void in_row::set(uint pos, Item *item)
+{
+ DBUG_ENTER("in_row::set");
+ DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item));
+ ((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item);
+ DBUG_VOID_RETURN;
+}
in_longlong::in_longlong(uint elements)
:in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong)
@@ -1001,13 +1196,12 @@ void in_longlong::set(uint pos,Item *item)
byte *in_longlong::get_value(Item *item)
{
- tmp=item->val_int();
+ tmp= item->val_int();
if (item->null_value)
- return 0; /* purecov: inspected */
+ return 0;
return (byte*) &tmp;
}
-
in_double::in_double(uint elements)
:in_vector(elements,sizeof(double),(qsort_cmp) cmp_double)
{}
@@ -1019,23 +1213,173 @@ void in_double::set(uint pos,Item *item)
byte *in_double::get_value(Item *item)
{
- tmp=item->val();
+ tmp= item->val();
if (item->null_value)
return 0; /* purecov: inspected */
return (byte*) &tmp;
}
+cmp_item* cmp_item::get_comparator(Item *item)
+{
+ switch (item->result_type()) {
+ case STRING_RESULT:
+ return new cmp_item_sort_string(item->charset());
+ break;
+ case INT_RESULT:
+ return new cmp_item_int;
+ break;
+ case REAL_RESULT:
+ return new cmp_item_real;
+ break;
+ case ROW_RESULT:
+ return new cmp_item_row;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ break;
+ }
+ return 0; // to satisfy compiler :)
+}
+
+cmp_item* cmp_item_sort_string::make_same()
+{
+ return new cmp_item_sort_string_in_static(cmp_charset);
+}
+
+cmp_item* cmp_item_int::make_same()
+{
+ return new cmp_item_int();
+}
+
+cmp_item* cmp_item_real::make_same()
+{
+ return new cmp_item_real();
+}
+
+cmp_item* cmp_item_row::make_same()
+{
+ return new cmp_item_row();
+}
+
+void cmp_item_row::store_value(Item *item)
+{
+ THD *thd= current_thd;
+ n= item->cols();
+ if ((comparators= (cmp_item **) thd->calloc(sizeof(cmp_item *)*n)))
+ {
+ item->bring_value();
+ item->null_value= 0;
+ for (uint i=0; i < n; i++)
+ if ((comparators[i]= cmp_item::get_comparator(item->el(i))))
+ {
+ comparators[i]->store_value(item->el(i));
+ item->null_value|= item->el(i)->null_value;
+ }
+ else
+ return;
+ }
+ else
+ return;
+}
+
+void cmp_item_row::store_value_by_template(cmp_item *t, Item *item)
+{
+ cmp_item_row *tmpl= (cmp_item_row*) t;
+ if (tmpl->n != item->cols())
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), tmpl->n);
+ return;
+ }
+ n= tmpl->n;
+ if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n)))
+ {
+ item->bring_value();
+ item->null_value= 0;
+ for (uint i=0; i < n; i++)
+ if ((comparators[i]= tmpl->comparators[i]->make_same()))
+ {
+ comparators[i]->store_value_by_template(tmpl->comparators[i],
+ item->el(i));
+ item->null_value|= item->el(i)->null_value;
+ }
+ else
+ return;
+ }
+ else
+ return;
+}
+
+int cmp_item_row::cmp(Item *arg)
+{
+ arg->null_value= 0;
+ if (arg->cols() != n)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), n);
+ return 1;
+ }
+ bool was_null= 0;
+ arg->bring_value();
+ for (uint i=0; i < n; i++)
+ if (comparators[i]->cmp(arg->el(i)))
+ {
+ if (!arg->el(i)->null_value)
+ return 1;
+ was_null= 1;
+ }
+ return (arg->null_value= was_null);
+}
+
+int cmp_item_row::compare(cmp_item *c)
+{
+ int res;
+ cmp_item_row *cmp= (cmp_item_row *) c;
+ for (uint i=0; i < n; i++)
+ if ((res= comparators[i]->compare(cmp->comparators[i])))
+ return res;
+ return 0;
+}
+
+bool Item_func_in::nulls_in_row()
+{
+ Item **arg,**arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++)
+ {
+ if ((*arg)->null_inside())
+ return 1;
+ }
+ return 0;
+}
+
+static int srtcmp_in(const String *x,const String *y)
+{
+ CHARSET_INFO *cs= x->charset();
+ return cs->strnncollsp(cs,
+ (unsigned char *) x->ptr(),x->length(),
+ (unsigned char *) y->ptr(),y->length());
+}
+
+static int bincmp_in(const String *x,const String *y)
+{
+ CHARSET_INFO *cs= &my_charset_bin;
+ return cs->strnncollsp(cs,
+ (unsigned char *) x->ptr(),x->length(),
+ (unsigned char *) y->ptr(),y->length());
+}
void Item_func_in::fix_length_and_dec()
{
- if (const_item())
+ /*
+ Row item with NULLs inside can return NULL or FALSE =>
+ they can't be processed as static
+ */
+ if (const_item() && !nulls_in_row())
{
switch (item->result_type()) {
case STRING_RESULT:
- if (item->binary)
- array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */
+ if (item->binary())
+ array=new in_string(arg_count,(qsort_cmp) srtcmp_in);
else
- array=new in_string(arg_count,(qsort_cmp) sortcmp);
+ array=new in_string(arg_count,(qsort_cmp) bincmp_in);
break;
case INT_RESULT:
array= new in_longlong(arg_count);
@@ -1043,6 +1387,12 @@ void Item_func_in::fix_length_and_dec()
case REAL_RESULT:
array= new in_double(arg_count);
break;
+ case ROW_RESULT:
+ array= new in_row(arg_count, item);
+ break;
+ default:
+ DBUG_ASSERT(0);
+ return;
}
uint j=0;
for (uint i=0 ; i < arg_count ; i++)
@@ -1050,29 +1400,18 @@ void Item_func_in::fix_length_and_dec()
array->set(j,args[i]);
if (!args[i]->null_value) // Skip NULL values
j++;
+ else
+ have_null= 1;
}
if ((array->used_count=j))
array->sort();
}
else
{
- switch (item->result_type()) {
- case STRING_RESULT:
- if (item->binary)
- in_item= new cmp_item_binary_string;
- else
- in_item= new cmp_item_sort_string;
- break;
- case INT_RESULT:
- in_item= new cmp_item_int;
- break;
- case REAL_RESULT:
- in_item= new cmp_item_real;
- break;
- }
+ in_item= cmp_item::get_comparator(item);
}
maybe_null= item->maybe_null;
- max_length=2;
+ max_length= 1;
used_tables_cache|=item->used_tables();
const_item_cache&=item->const_item();
}
@@ -1092,17 +1431,20 @@ longlong Item_func_in::val_int()
if (array)
{
int tmp=array->find(item);
- null_value=item->null_value;
+ null_value=item->null_value || (!tmp && have_null);
return tmp;
}
in_item->store_value(item);
if ((null_value=item->null_value))
return 0;
+ have_null= 0;
for (uint i=0 ; i < arg_count ; i++)
{
if (!in_item->cmp(args[i]) && !args[i]->null_value)
return 1; // Would maybe be nice with i ?
+ have_null|= args[i]->null_value;
}
+ null_value= have_null;
return 0;
}
@@ -1115,16 +1457,18 @@ void Item_func_in::update_used_tables()
const_item_cache&=item->const_item();
}
-void Item_func_in::split_sum_func(List<Item> &fields)
+void Item_func_in::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
- item->split_sum_func(fields);
+ item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(item);
- item= new Item_ref((Item**) fields.head_ref(), 0, item->name);
+ ref_pointer_array[el]= item;
+ item= new Item_ref(ref_pointer_array + el, 0, item->name);
}
- Item_func::split_sum_func(fields);
+ Item_func::split_sum_func(ref_pointer_array, fields);
}
@@ -1167,7 +1511,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;
@@ -1191,7 +1535,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()) || item->check_cols(1))
return 1; /* purecov: inspected */
used_tables_cache|=item->used_tables();
with_sum_func= with_sum_func || item->with_sum_func;
@@ -1202,11 +1546,20 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
if (thd)
thd->cond_count+=list.elements;
fix_length_and_dec();
+ fixed= 1;
return 0;
}
+void Item_cond::set_outer_resolving()
+{
+ Item_func::set_outer_resolving();
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ item->set_outer_resolving();
+}
-void Item_cond::split_sum_func(List<Item> &fields)
+void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
{
List_iterator<Item> li(list);
Item *item;
@@ -1215,11 +1568,13 @@ void Item_cond::split_sum_func(List<Item> &fields)
while ((item=li++))
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
- item->split_sum_func(fields);
+ item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(item);
- li.replace(new Item_ref((Item**) fields.head_ref(),0,item->name));
+ ref_pointer_array[el]= item;
+ li.replace(new Item_ref(ref_pointer_array + el, 0, item->name));
}
item->update_used_tables();
used_tables_cache|=item->used_tables();
@@ -1369,18 +1724,13 @@ longlong Item_func_isnull::val_int()
return args[0]->is_null() ? 1: 0;
}
+
longlong Item_func_isnotnull::val_int()
{
return args[0]->is_null() ? 0 : 1;
}
-void Item_func_like::fix_length_and_dec()
-{
- decimals=0; max_length=1;
- // cmp_type=STRING_RESULT; // For quick select
-}
-
longlong Item_func_like::val_int()
{
String* res = args[0]->val_str(&tmp_value1);
@@ -1398,10 +1748,10 @@ longlong Item_func_like::val_int()
null_value=0;
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;
}
@@ -1425,16 +1775,27 @@ 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;
/*
- TODO--we could do it for non-const, but we'd have to
- recompute the tables for each row--probably not worth it.
+ Comparision is by default done according to character set of LIKE
+ QQ: COERCIBILITY
+ */
+ if (cmp_charset == &my_charset_bin)
+ set_charset(&my_charset_bin);
+ else
+ set_charset(args[1]->charset());
+
+ /*
+ We could also do boyer-more for non-const items, but as we would have to
+ recompute the tables for each row it's not worth it.
*/
- if (args[1]->const_item() && !(specialflag & SPECIAL_NO_NEW_FUNC))
+ if (args[1]->const_item() && !use_strnxfrm(charset()) &&
+ !(specialflag & SPECIAL_NO_NEW_FUNC))
{
String* res2 = args[1]->val_str(&tmp_value2);
if (!res2)
@@ -1477,19 +1838,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[0]->check_cols(1) ||
+ args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(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;
+ max_length= 1;
+ decimals= 0;
+ binary_cmp= (args[0]->binary() || args[1]->binary());
+
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),&my_charset_bin);
String *res=args[1]->val_str(&tmp);
if (args[1]->null_value)
{ // Will always return NULL
@@ -1498,8 +1862,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_cmp ? 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);
@@ -1510,13 +1875,15 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
}
else
maybe_null=1;
+ fixed= 1;
return 0;
}
+
longlong Item_func_regex::val_int()
{
char buff[MAX_FIELD_WIDTH];
- String *res, tmp(buff,sizeof(buff));
+ String *res, tmp(buff,sizeof(buff),&my_charset_bin);
res=args[0]->val_str(&tmp);
if (args[0]->null_value)
@@ -1527,7 +1894,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),&my_charset_bin);
res2= args[1]->val_str(&tmp2);
if (args[1]->null_value)
@@ -1535,7 +1902,7 @@ longlong Item_func_regex::val_int()
null_value=1;
return 0;
}
- if (!regex_compiled || stringcmp(res2,&prev_regexp))
+ if (!regex_compiled || sortcmp(res2,&prev_regexp,&my_charset_bin))
{
prev_regexp.copy(*res2);
if (regex_compiled)
@@ -1544,8 +1911,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_cmp ? REG_EXTENDED | REG_NOSUB :
+ REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ res->charset()))
{
null_value=1;
@@ -1572,9 +1940,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
@@ -1589,10 +1957,11 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
int f = 0;
int g = plm1;
int *const splm1 = suff + plm1;
+ CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed
*splm1 = pattern_len;
- if (binary)
+ if (cmp_charset == &my_charset_bin)
{
int i;
for (i = pattern_len - 2; i >= 0; i--)
@@ -1625,7 +1994,7 @@ void Item_func_like::turboBM_compute_suffixes(int *suff)
g = i; // g = min(i, g)
f = i;
while (g >= 0 &&
- likeconv(pattern[g]) == likeconv(pattern[g + plm1 - f]))
+ likeconv(cs, pattern[g]) == likeconv(cs, pattern[g + plm1 - f]))
g--;
suff[i] = f - g;
}
@@ -1688,12 +2057,14 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
{
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 (cmp_charset == &my_charset_bin)
{
for (j = 0; j < plm1; j++)
bmBc[(uint) (uchar) pattern[j]] = plm1 - j;
@@ -1701,7 +2072,7 @@ void Item_func_like::turboBM_compute_bad_character_shifts()
else
{
for (j = 0; j < plm1; j++)
- bmBc[(uint) likeconv(pattern[j])] = plm1 - j;
+ bmBc[(uint) likeconv(cs,pattern[j])] = plm1 - j;
}
}
@@ -1718,12 +2089,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 (cmp_charset == &my_charset_bin)
{
while (j <= tlmpl)
{
@@ -1759,7 +2131,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)
@@ -1770,7 +2142,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[(uint) likeconv(text[i + j])] - plm1 + i;
+ bcShift = bmBc[(uint) likeconv(cs, text[i + j])] - plm1 + i;
shift = max(turboShift, bcShift);
shift = max(shift, bmGs[i]);
if (shift == bmGs[i])
@@ -1825,3 +2197,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 f7ade97940c..b9d8615beb4 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -21,6 +21,59 @@
#pragma interface /* gcc class implementation */
#endif
+extern Item_result item_cmp_type(Item_result a,Item_result b);
+class Item_bool_func2;
+class Arg_comparator;
+
+typedef int (Arg_comparator::*arg_cmp_func)();
+
+class Arg_comparator: public Sql_alloc
+{
+ Item **a, **b;
+ arg_cmp_func func;
+ Item_bool_func2 *owner;
+ Arg_comparator *comparators; // used only for compare_row()
+
+public:
+ Arg_comparator() {};
+ Arg_comparator(Item **a1, Item **a2): a(a1), b(a2) {};
+
+ int set_compare_func(Item_bool_func2 *owner, Item_result type);
+ inline int set_compare_func(Item_bool_func2 *owner)
+ {
+ return set_compare_func(owner, item_cmp_type((*a)->result_type(),
+ (*b)->result_type()));
+ }
+ inline int set_cmp_func(Item_bool_func2 *owner,
+ Item **a1, Item **a2,
+ Item_result type)
+ {
+ a= a1;
+ b= a2;
+ return set_compare_func(owner, type);
+ }
+ inline int set_cmp_func(Item_bool_func2 *owner,
+ Item **a1, Item **a2)
+ {
+ return set_cmp_func(owner, a1, a2, item_cmp_type((*a1)->result_type(),
+ (*a2)->result_type()));
+ }
+ inline int compare() { return (this->*func)(); }
+
+ int compare_string(); // compare args[0] & args[1]
+ int compare_real(); // compare args[0] & args[1]
+ int compare_int(); // compare args[0] & args[1]
+ int compare_row(); // compare args[0] & args[1]
+ int compare_e_string(); // compare args[0] & args[1]
+ int compare_e_real(); // compare args[0] & args[1]
+ int compare_e_int(); // compare args[0] & args[1]
+ int compare_e_row(); // compare args[0] & args[1]
+
+ static arg_cmp_func comparator_matrix [4][2];
+
+ friend class Item_func;
+};
+
class Item_bool_func :public Item_int_func
{
public:
@@ -28,29 +81,72 @@ 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_cache;
+class Item_in_optimizer: public Item_bool_func
+{
+protected:
+ Item_cache *cache;
+public:
+ Item_in_optimizer(Item *a, Item_in_subselect *b):
+ Item_bool_func(a, (Item *)b), cache(0) {}
+ // used by row in transformer
+ bool preallocate_row();
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ bool is_null();
+ /*
+ Item_in_optimizer item is special boolean function. On value request
+ (one of val, val_int or val_str methods) it evaluate left expression
+ of IN by storing it value in cache item (one of Item_cache* items),
+ then it test cache is it NULL. If left expression (cache) is NULL then
+ Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
+ */
+ longlong val_int();
+
+ Item_cache **get_cache() { return &cache; }
};
class Item_bool_func2 :public Item_int_func
{ /* Bool with 2 string args */
protected:
+ Arg_comparator cmp;
String tmp_value1,tmp_value2;
+ CHARSET_INFO *cmp_charset;
+
public:
- Item_bool_func2(Item *a,Item *b) :Item_int_func(a,b) {}
+ Item_bool_func2(Item *a,Item *b):
+ Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {}
void fix_length_and_dec();
- void set_cmp_func(Item_result type);
- int (Item_bool_func2::*cmp_func)();
- int compare_string(); /* compare arg[0] & arg[1] */
- int compare_real(); /* compare arg[0] & arg[1] */
- int compare_int(); /* compare arg[0] & arg[1] */
+ void set_cmp_func()
+ {
+ cmp.set_cmp_func(this, tmp_arg, tmp_arg+1);
+ }
optimize_type select_optimize() const { return OPTIMIZE_OP; }
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); }
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
- unsigned int size_of() { return sizeof(*this);}
+ virtual bool binary() const { return test(cmp_charset->state & MY_CS_BINSORT); }
+
+ static Item_bool_func2* eq_creator(Item *a, Item *b);
+ static Item_bool_func2* ne_creator(Item *a, Item *b);
+ static Item_bool_func2* gt_creator(Item *a, Item *b);
+ static Item_bool_func2* lt_creator(Item *a, Item *b);
+ static Item_bool_func2* ge_creator(Item *a, Item *b);
+ static Item_bool_func2* le_creator(Item *a, Item *b);
+
+ friend class Arg_comparator;
};
+class Item_bool_rowready_func2 :public Item_bool_func2
+{
+public:
+ Item_bool_rowready_func2(Item *a,Item *b) :Item_bool_func2(a,b)
+ {
+ allowed_arg_cols= a->cols();
+ }
+};
class Item_func_not :public Item_bool_func
{
@@ -60,10 +156,10 @@ public:
const char *func_name() const { return "not"; }
};
-class Item_func_eq :public Item_bool_func2
+class Item_func_eq :public Item_bool_rowready_func2
{
public:
- Item_func_eq(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_eq(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
longlong val_int();
enum Functype functype() const { return EQ_FUNC; }
enum Functype rev_functype() const { return EQ_FUNC; }
@@ -71,25 +167,23 @@ public:
const char *func_name() const { return "="; }
};
-class Item_func_equal :public Item_bool_func2
+class Item_func_equal :public Item_bool_rowready_func2
{
- Item_result cmp_result_type;
public:
- Item_func_equal(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_equal(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
longlong val_int();
void fix_length_and_dec();
enum Functype functype() const { return EQUAL_FUNC; }
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);}
};
-class Item_func_ge :public Item_bool_func2
+class Item_func_ge :public Item_bool_rowready_func2
{
public:
- Item_func_ge(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_ge(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
longlong val_int();
enum Functype functype() const { return GE_FUNC; }
enum Functype rev_functype() const { return LE_FUNC; }
@@ -98,10 +192,10 @@ public:
};
-class Item_func_gt :public Item_bool_func2
+class Item_func_gt :public Item_bool_rowready_func2
{
public:
- Item_func_gt(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_gt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
longlong val_int();
enum Functype functype() const { return GT_FUNC; }
enum Functype rev_functype() const { return LT_FUNC; }
@@ -110,10 +204,10 @@ public:
};
-class Item_func_le :public Item_bool_func2
+class Item_func_le :public Item_bool_rowready_func2
{
public:
- Item_func_le(Item *a,Item *b) :Item_bool_func2(a,b) { };
+ Item_func_le(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
longlong val_int();
enum Functype functype() const { return LE_FUNC; }
enum Functype rev_functype() const { return GE_FUNC; }
@@ -122,10 +216,10 @@ public:
};
-class Item_func_lt :public Item_bool_func2
+class Item_func_lt :public Item_bool_rowready_func2
{
public:
- Item_func_lt(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ Item_func_lt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}
longlong val_int();
enum Functype functype() const { return LT_FUNC; }
enum Functype rev_functype() const { return GT_FUNC; }
@@ -134,10 +228,10 @@ public:
};
-class Item_func_ne :public Item_bool_func2
+class Item_func_ne :public Item_bool_rowready_func2
{
public:
- Item_func_ne(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ Item_func_ne(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}
longlong val_int();
enum Functype functype() const { return NE_FUNC; }
cond_result eq_cmp_result() const { return COND_FALSE; }
@@ -148,7 +242,7 @@ public:
class Item_func_between :public Item_int_func
{
- int (*string_compare)(const String *x,const String *y);
+ CHARSET_INFO *cmp_charset;
public:
Item_result cmp_type;
String value0,value1,value2;
@@ -166,7 +260,13 @@ class Item_func_strcmp :public Item_bool_func2
public:
Item_func_strcmp(Item *a,Item *b) :Item_bool_func2(a,b) {}
longlong val_int();
- void fix_length_and_dec() { max_length=2; }
+ void fix_length_and_dec()
+ {
+ max_length=2;
+ /* QQ: COERCIBILITY */
+ cmp_charset= args[0]->binary() || args[1]->binary() ?
+ &my_charset_bin : args[0]->charset();
+ }
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "strcmp"; }
};
@@ -174,22 +274,14 @@ public:
class Item_func_interval :public Item_int_func
{
- Item *item;
+ Item_row *row;
double *intervals;
public:
- Item_func_interval(Item *a,List<Item> &list)
- :Item_int_func(list),item(a),intervals(0) {}
+ Item_func_interval(Item_row *a)
+ :Item_int_func(a),row(a),intervals(0) { allowed_arg_cols= a->cols(); }
longlong val_int();
- bool fix_fields(THD *thd,struct st_table_list *tlist)
- {
- return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
- }
- void split_sum_func(List<Item> &fields);
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);}
};
@@ -197,14 +289,15 @@ class Item_func_ifnull :public Item_func
{
enum Item_result cached_result_type;
public:
- Item_func_ifnull(Item *a,Item *b) :Item_func(a,b) { }
+ Item_func_ifnull(Item *a,Item *b)
+ :Item_func(a,b), cached_result_type(INT_RESULT)
+ {}
double val();
longlong val_int();
String *val_str(String *str);
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);}
};
@@ -212,19 +305,20 @@ class Item_func_if :public Item_func
{
enum Item_result cached_result_type;
public:
- Item_func_if(Item *a,Item *b,Item *c) :Item_func(a,b,c) { }
+ Item_func_if(Item *a,Item *b,Item *c)
+ :Item_func(a,b,c), cached_result_type(INT_RESULT)
+ {}
double val();
longlong val_int();
String *val_str(String *str);
enum Item_result result_type () const { return cached_result_type; }
- bool fix_fields(THD *thd,struct st_table_list *tlist)
+ bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
{
args[0]->top_level_item();
- return Item_func::fix_fields(thd,tlist);
+ return Item_func::fix_fields(thd, tlist, ref);
}
void fix_length_and_dec();
const char *func_name() const { return "if"; }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -232,14 +326,15 @@ class Item_func_nullif :public Item_bool_func2
{
enum Item_result cached_result_type;
public:
- Item_func_nullif(Item *a,Item *b) :Item_bool_func2(a,b) { }
+ Item_func_nullif(Item *a,Item *b)
+ :Item_bool_func2(a,b), cached_result_type(INT_RESULT)
+ {}
double val();
longlong val_int();
String *val_str(String *str);
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);}
};
@@ -247,14 +342,15 @@ class Item_func_coalesce :public Item_func
{
enum Item_result cached_result_type;
public:
- Item_func_coalesce(List<Item> &list) :Item_func(list) {}
+ Item_func_coalesce(List<Item> &list)
+ :Item_func(list),cached_result_type(INT_RESULT)
+ {}
double val();
longlong val_int();
String *val_str(String *);
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
@@ -262,9 +358,12 @@ class Item_func_case :public Item_func
Item * first_expr, *else_expr;
enum Item_result cached_result_type;
String tmp_value;
+ bool first_expr_is_binary;
public:
- Item_func_case(List<Item> &list, Item *first_expr_, Item *else_expr_)
- :Item_func(list), first_expr(first_expr_), else_expr(else_expr_) {}
+ Item_func_case(List<Item> &list, Item *first_expr_arg, Item *else_expr_arg)
+ :Item_func(list), first_expr(first_expr_arg), else_expr(else_expr_arg),
+ cached_result_type(INT_RESULT)
+ {}
double val();
longlong val_int();
String *val_str(String *);
@@ -273,10 +372,10 @@ 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);
- void split_sum_func(List<Item> &fields);
+ bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
Item *find_item(String *str);
- unsigned int size_of() { return sizeof(*this);}
+ void set_outer_resolving();
};
@@ -291,6 +390,7 @@ class in_vector :public Sql_alloc
uint count;
public:
uint used_count;
+ in_vector() {}
in_vector(uint elements,uint element_length,qsort_cmp cmp_func)
:base((char*) sql_calloc(elements*element_length)),
size(element_length), compare(cmp_func), count(elements),
@@ -305,7 +405,6 @@ public:
int find(Item *item);
};
-
class in_string :public in_vector
{
char buff[80];
@@ -317,7 +416,6 @@ public:
byte *get_value(Item *item);
};
-
class in_longlong :public in_vector
{
longlong tmp;
@@ -327,7 +425,6 @@ public:
byte *get_value(Item *item);
};
-
class in_double :public in_vector
{
double tmp;
@@ -337,7 +434,6 @@ public:
byte *get_value(Item *item);
};
-
/*
** Classes for easy comparing of non const items
*/
@@ -345,91 +441,188 @@ public:
class cmp_item :public Sql_alloc
{
public:
- cmp_item() {}
+ CHARSET_INFO *cmp_charset;
+ cmp_item() { cmp_charset= &my_charset_bin; }
virtual ~cmp_item() {}
- virtual void store_value(Item *item)=0;
- virtual int cmp(Item *item)=0;
+ virtual void store_value(Item *item)= 0;
+ virtual int cmp(Item *item)= 0;
+ // for optimized IN with row
+ virtual int compare(cmp_item *item)= 0;
+ static cmp_item* get_comparator(Item *);
+ virtual cmp_item *make_same()= 0;
+ virtual void store_value_by_template(cmp_item *tmpl, Item *item)
+ {
+ store_value(item);
+ }
};
-
-class cmp_item_sort_string :public cmp_item {
- protected:
- char value_buff[80];
- String value,*value_res;
+class cmp_item_string :public cmp_item
+{
+protected:
+ String *value_res;
public:
- cmp_item_sort_string() :value(value_buff,sizeof(value_buff)) {}
- void store_value(Item *item)
- {
- value_res=item->val_str(&value);
- }
- int cmp(Item *arg)
- {
- char buff[80];
- String tmp(buff,sizeof(buff)),*res;
- if (!(res=arg->val_str(&tmp)))
- return 1; /* Can't be right */
- return sortcmp(value_res,res);
- }
+ cmp_item_string (CHARSET_INFO *cs) { cmp_charset= cs; }
+ friend class cmp_item_sort_string;
+ friend class cmp_item_sort_string_in_static;
};
-class cmp_item_binary_string :public cmp_item_sort_string {
+class cmp_item_sort_string :public cmp_item_string
+{
+protected:
+ char value_buff[80];
+ String value;
public:
- cmp_item_binary_string() {}
+ cmp_item_sort_string(CHARSET_INFO *cs):
+ cmp_item_string(cs),
+ value(value_buff, sizeof(value_buff), cs) {}
+ void store_value(Item *item)
+ {
+ value_res= item->val_str(&value);
+ }
int cmp(Item *arg)
- {
- char buff[80];
- String tmp(buff,sizeof(buff)),*res;
- if (!(res=arg->val_str(&tmp)))
- return 1; /* Can't be right */
- return stringcmp(value_res,res);
- }
+ {
+ char buff[80];
+ String tmp(buff, sizeof(buff), cmp_charset), *res;
+ if (!(res= arg->val_str(&tmp)))
+ return 1; /* Can't be right */
+ return sortcmp(value_res, res, cmp_charset);
+ }
+ int compare(cmp_item *c)
+ {
+ cmp_item_string *cmp= (cmp_item_string *)c;
+ return sortcmp(value_res, cmp->value_res, cmp_charset);
+ }
+ cmp_item *make_same();
};
-
class cmp_item_int :public cmp_item
{
longlong value;
public:
void store_value(Item *item)
- {
- value=item->val_int();
- }
+ {
+ value= item->val_int();
+ }
int cmp(Item *arg)
- {
- return value != arg->val_int();
- }
+ {
+ return value != arg->val_int();
+ }
+ int compare(cmp_item *c)
+ {
+ cmp_item_int *cmp= (cmp_item_int *)c;
+ return (value < cmp->value) ? -1 : ((value == cmp->value) ? 0 : 1);
+ }
+ cmp_item *make_same();
};
-
class cmp_item_real :public cmp_item
{
double value;
public:
void store_value(Item *item)
- {
- value= item->val();
- }
+ {
+ value= item->val();
+ }
int cmp(Item *arg)
+ {
+ return value != arg->val();
+ }
+ int compare(cmp_item *c)
+ {
+ cmp_item_real *cmp= (cmp_item_real *)c;
+ return (value < cmp->value)? -1 : ((value == cmp->value) ? 0 : 1);
+ }
+ cmp_item *make_same();
+};
+
+class cmp_item_row :public cmp_item
+{
+ cmp_item **comparators;
+ uint n;
+public:
+ cmp_item_row(): comparators(0), n(0) {}
+ ~cmp_item_row()
+ {
+ if (comparators)
{
- return value != arg->val();
+ for (uint i= 0; i < n; i++)
+ {
+ if (comparators[i])
+ delete comparators[i];
+ }
}
+ }
+ void store_value(Item *item);
+ int cmp(Item *arg);
+ int compare(cmp_item *arg);
+ cmp_item *make_same();
+ void store_value_by_template(cmp_item *tmpl, Item *);
};
+class in_row :public in_vector
+{
+ cmp_item_row tmp;
+public:
+ in_row(uint elements, Item *);
+ ~in_row();
+ void set(uint pos,Item *item);
+ byte *get_value(Item *item);
+};
+
+/*
+ cmp_item for optimized IN with row (right part string, which never
+ be changed)
+*/
+
+class cmp_item_sort_string_in_static :public cmp_item_string
+{
+ protected:
+ String value;
+public:
+ cmp_item_sort_string_in_static(CHARSET_INFO *cs):
+ cmp_item_string(cs) {}
+ void store_value(Item *item)
+ {
+ value_res= item->val_str(&value);
+ }
+ int cmp(Item *item)
+ {
+ // Should never be called
+ DBUG_ASSERT(0);
+ return 1;
+ }
+ int compare(cmp_item *c)
+ {
+ cmp_item_string *cmp= (cmp_item_string *)c;
+ return sortcmp(value_res, cmp->value_res, cmp_charset);
+ }
+ cmp_item * make_same()
+ {
+ return new cmp_item_sort_string_in_static(cmp_charset);
+ }
+};
+
class Item_func_in :public Item_int_func
{
Item *item;
in_vector *array;
cmp_item *in_item;
+ bool have_null;
public:
Item_func_in(Item *a,List<Item> &list)
- :Item_int_func(list),item(a),array(0),in_item(0) {}
+ :Item_int_func(list), item(a), array(0), in_item(0), have_null(0)
+ {
+ allowed_arg_cols= item->cols();
+ }
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)
{
- bool res= (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist));
+ // We do not check item->cols(), because allowed_arg_cols assigned from it
+ bool res=(item->fix_fields(thd, tlist, &item) ||
+ Item_func::fix_fields(thd, tlist, ref));
with_sum_func= with_sum_func || item->with_sum_func;
- return res;
+ return res;
}
void fix_length_and_dec();
~Item_func_in() { delete item; delete array; delete in_item; }
@@ -440,12 +633,15 @@ class Item_func_in :public Item_int_func
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
void update_used_tables();
- void split_sum_func(List<Item> &fields);
- unsigned int size_of() { return sizeof(*this);}
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
+ bool nulls_in_row();
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_int_func::set_outer_resolving();
+ }
};
-
-
/* Functions used by where clause */
class Item_func_isnull :public Item_bool_func
@@ -480,7 +676,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
@@ -495,7 +690,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
@@ -527,9 +721,7 @@ public:
optimize_type select_optimize() const;
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
@@ -542,14 +734,14 @@ class Item_func_regex :public Item_bool_func
bool regex_compiled;
bool regex_is_const;
String prev_regexp;
+ bool binary_cmp;
public:
Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b),
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
@@ -579,17 +771,17 @@ 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; }
table_map used_tables() const;
void update_used_tables();
void print(String *str);
- void split_sum_func(List<Item> &fields);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
- unsigned int size_of() { return sizeof(*this);}
void top_level_item() { abort_on_null=1; }
+ void set_outer_resolving();
};
@@ -614,6 +806,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)
@@ -626,15 +829,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 7e082bc174c..d90c708fc0f 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -52,6 +52,13 @@ Item *create_func_ord(Item* a)
return new Item_func_ord(a);
}
+Item *create_func_old_password(Item* a)
+{
+ return new Item_func_old_password(a);
+}
+
+
+
Item *create_func_asin(Item* a)
{
return new Item_func_asin(a);
@@ -76,7 +83,7 @@ Item *create_func_ceiling(Item* a)
Item *create_func_connection_id(void)
{
THD *thd=current_thd;
- thd->safe_to_cache_query=0;
+ thd->lex.safe_to_cache_query=0;
return new Item_int(NullS,(longlong) thd->thread_id,10);
}
@@ -96,6 +103,14 @@ Item *create_func_cot(Item* a)
new Item_func_tan(a));
}
+
+#ifdef HAVE_COMPRESS
+Item *create_func_crc32(Item* a)
+{
+ return new Item_func_crc32(a);
+}
+#endif
+
Item *create_func_date_format(Item* a,Item *b)
{
return new Item_func_date_format(a,b,0);
@@ -144,7 +159,7 @@ Item *create_func_floor(Item* a)
Item *create_func_found_rows(void)
{
THD *thd=current_thd;
- thd->safe_to_cache_query=0;
+ thd->lex.safe_to_cache_query=0;
return new Item_int(NullS,(longlong) thd->found_rows(),21);
}
@@ -155,7 +170,7 @@ Item *create_func_from_days(Item* a)
Item *create_func_get_lock(Item* a, Item *b)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.uncacheable();
return new Item_func_get_lock(a, b);
}
@@ -215,6 +230,11 @@ Item *create_func_bit_length(Item* a)
return new Item_func_bit_length(a);
}
+Item *create_func_coercibility(Item* a)
+{
+ return new Item_func_coercibility(a);
+}
+
Item *create_func_char_length(Item* a)
{
return new Item_func_char_length(a);
@@ -242,7 +262,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)
@@ -299,7 +319,8 @@ Item *create_func_current_user()
length= (uint) (strxmov(buff, thd->priv_user, "@", thd->host_or_ip, NullS) -
buff);
- return new Item_string(NullS, thd->memdup(buff, length), length);
+ return new Item_string(NullS, thd->memdup(buff, length), length,
+ default_charset_info);
}
Item *create_func_quarter(Item* a)
@@ -319,7 +340,7 @@ Item *create_func_radians(Item *a)
Item *create_func_release_lock(Item* a)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.uncacheable();
return new Item_func_release_lock(a);
}
@@ -340,7 +361,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)
@@ -365,7 +386,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)
@@ -410,7 +431,9 @@ Item *create_func_ucase(Item* a)
Item *create_func_version(void)
{
- return new Item_string(NullS,server_version, strlen(server_version));
+ return new Item_string(NullS,server_version,
+ (uint) strlen(server_version),
+ default_charset_info);
}
Item *create_func_weekday(Item* a)
@@ -425,10 +448,11 @@ Item *create_func_year(Item* a)
Item *create_load_file(Item* a)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.uncacheable();
return new Item_load_file(a);
}
+
Item *create_func_cast(Item *a, Item_cast cast_type)
{
Item *res;
@@ -447,7 +471,7 @@ Item *create_func_cast(Item *a, Item_cast cast_type)
Item *create_func_is_free_lock(Item* a)
{
- current_thd->safe_to_cache_query=0;
+ current_thd->lex.uncacheable();
return new Item_func_is_free_lock(a);
}
@@ -455,3 +479,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 5381ad946ae..135bd6b02c4 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -25,12 +25,17 @@ Item *create_func_asin(Item* a);
Item *create_func_bin(Item* a);
Item *create_func_bit_count(Item* a);
Item *create_func_bit_length(Item* a);
+Item *create_func_coercibility(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);
+#ifdef HAVE_COMPRESS
+Item *create_func_crc32(Item* a);
+#endif
Item *create_func_date_format(Item* a,Item *b);
Item *create_func_dayname(Item* a);
Item *create_func_dayofmonth(Item* a);
@@ -64,6 +69,7 @@ Item *create_func_monthname(Item* a);
Item *create_func_nullif(Item* a, Item *b);
Item *create_func_oct(Item *);
Item *create_func_ord(Item* a);
+Item *create_func_old_password(Item* a);
Item *create_func_period_add(Item* a, Item *b);
Item *create_func_period_diff(Item* a, Item *b);
Item *create_func_pi(void);
@@ -95,3 +101,41 @@ Item *create_func_weekday(Item* a);
Item *create_load_file(Item* a);
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 b6a64155ab5..9abbb0e290b 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -22,11 +22,14 @@
#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
+#ifdef HAVE_COMPRESS
+#include <zlib.h>
+#endif
/* return TRUE if item is a constant */
@@ -37,7 +40,8 @@ eval_const_cond(COND *cond)
}
-Item_func::Item_func(List<Item> &list)
+Item_func::Item_func(List<Item> &list):
+ allowed_arg_cols(1)
{
arg_count=list.elements;
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
@@ -55,12 +59,47 @@ 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 any argument is binary, this is set to binary
+
+ 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,35 +107,80 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables)
return 0; // Fatal error if flag is set!
if (arg_count)
{ // Print purify happy
+ bool first_coll= 1;
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) ||
+ (*arg)->check_cols(allowed_arg_cols))
return 1; /* purecov: inspected */
if ((*arg)->maybe_null)
maybe_null=1;
- if ((*arg)->binary)
- binary=1;
+
+ if ((*arg)->result_type() == STRING_RESULT)
+ {
+ /*
+ Set return character set to first argument if we are returning a
+ string.
+ */
+ if (first_coll)
+ {
+ set_charset((*arg)->charset());
+ coercibility= (*args)->coercibility;
+ first_coll= 0;
+ }
+ else if ((*arg)->charset() == &my_charset_bin ||
+ charset() == &my_charset_bin)
+ {
+ set_charset(&my_charset_bin);
+ coercibility= COER_NOCOLL;
+ }
+ else if ((*arg)->coercibility < coercibility)
+ {
+ if (!my_charset_same(charset(),(*arg)->charset()))
+ {
+ set_charset(&my_charset_bin);
+ coercibility= COER_NOCOLL;
+ }
+ else
+ {
+ coercibility= (*arg)->coercibility;
+ set_charset((*arg)->charset());
+ }
+ }
+ }
with_sum_func= with_sum_func || (*arg)->with_sum_func;
used_tables_cache|=(*arg)->used_tables();
const_item_cache&= (*arg)->const_item();
}
}
fix_length_and_dec();
+ fixed= 1;
return 0;
}
+void Item_func::set_outer_resolving()
+{
+ if (arg_count)
+ {
+ Item **arg,**arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ (*arg)->set_outer_resolving();
+ }
+}
-void Item_func::split_sum_func(List<Item> &fields)
+void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
{
- Item **arg,**arg_end;
- for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
+ Item **arg, **arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end ; arg++)
{
if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM)
- (*arg)->split_sum_func(fields);
+ (*arg)->split_sum_func(ref_pointer_array, fields);
else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(*arg);
- *arg=new Item_ref((Item**) fields.head_ref(),0,(*arg)->name);
+ ref_pointer_array[el]= *arg;
+ *arg= new Item_ref(ref_pointer_array + el, 0, (*arg)->name);
}
}
}
@@ -165,14 +249,11 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
return 1;
}
-
Field *Item_func::tmp_table_field(TABLE *t_arg)
{
Field *res;
LINT_INIT(res);
- if (!t_arg)
- return result_field;
switch (result_type()) {
case INT_RESULT:
if (max_length > 11)
@@ -187,9 +268,14 @@ 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;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
break;
}
return res;
@@ -202,7 +288,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,default_charset());
return str;
}
@@ -215,9 +301,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,default_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,default_charset());
}
else
{
@@ -225,7 +311,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,default_charset());
}
return str;
}
@@ -239,15 +325,22 @@ void Item_func::fix_num_length_and_dec()
max_length=float_length(decimals);
}
+Item *Item_func::get_tmp_table_item(THD *thd)
+{
+ if (!with_sum_func && !const_item())
+ return new Item_field(result_field);
+ return copy_or_same(thd);
+}
+
String *Item_int_func::val_str(String *str)
{
longlong nr=val_int();
if (null_value)
return 0;
else if (!unsigned_flag)
- str->set(nr);
+ str->set(nr,default_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,default_charset());
return str;
}
@@ -274,9 +367,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,default_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,default_charset());
}
else
{
@@ -284,7 +377,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,default_charset());
}
return str;
}
@@ -320,7 +413,7 @@ void Item_func_minus::fix_length_and_dec()
{
Item_num_op::fix_length_and_dec();
if (unsigned_flag &&
- (current_thd->sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
+ (current_thd->variables.sql_mode & MODE_NO_UNSIGNED_SUBTRACTION))
unsigned_flag=0;
}
@@ -398,6 +491,28 @@ 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 (unsigned_flag ?
+ (ulonglong) value / (ulonglong) val2 :
+ value / val2);
+}
+
+
+void Item_func_int_div::fix_length_and_dec()
+{
+ find_num_type();
+ 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);
@@ -761,8 +876,8 @@ 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++)
{
if (max_length < args[i]->max_length)
@@ -772,8 +887,10 @@ 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 (i==0)
+ set_charset(args[i]->charset());
+ else if (args[i]->charset() == &my_charset_bin)
+ set_charset(&my_charset_bin);
}
}
@@ -787,9 +904,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,default_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,default_charset());
return str;
}
case REAL_RESULT:
@@ -798,7 +915,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,default_charset());
return str;
}
case STRING_RESULT:
@@ -819,7 +936,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= sortcmp(res,res2,charset());
if ((cmp_sign < 0 ? cmp : -cmp) < 0)
res=res2;
}
@@ -827,6 +944,12 @@ String *Item_func_min_max::val_str(String *str)
}
return res;
}
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
+
}
return 0; // Keep compiler happy
}
@@ -876,6 +999,21 @@ longlong Item_func_min_max::val_int()
}
+#ifdef HAVE_COMPRESS
+longlong Item_func_crc32::val_int()
+{
+ String *res=args[0]->val_str(&value);
+ if (!res)
+ {
+ null_value=1;
+ return 0; /* purecov: inspected */
+ }
+ null_value=0;
+ return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length());
+}
+#endif /* HAVE_COMPRESS */
+
+
longlong Item_func_length::val_int()
{
String *res=args[0]->val_str(&value);
@@ -897,15 +1035,24 @@ 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) res->numchars();
}
+longlong Item_func_coercibility::val_int()
+{
+ if (args[0]->null_value)
+ {
+ null_value= 1;
+ return 0;
+ }
+ null_value= 0;
+ return (longlong) args[0]->coercibility;
+}
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;
if (!a || !b)
{
null_value=1;
@@ -920,10 +1067,10 @@ 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)
+ if (!binary_cmp)
start=a->charpos(start);
}
#endif
@@ -933,7 +1080,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_cmp)
{
const char *ptr=a->ptr()+start;
const char *search=b->ptr();
@@ -952,14 +1099,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_cmp ? a->strstr(*b,start) :
(a->strstr_case(*b,start)))+1;
}
@@ -979,18 +1127,23 @@ longlong Item_func_field::val_int()
return 0;
}
-void Item_func_field::split_sum_func(List<Item> &fields)
+
+void Item_func_field::split_sum_func(Item **ref_pointer_array,
+ List<Item> &fields)
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
- item->split_sum_func(fields);
+ item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(item);
- item= new Item_ref((Item**) fields.head_ref(), 0, item->name);
- }
- Item_func::split_sum_func(fields);
+ ref_pointer_array[el]= item;
+ item= new Item_ref(ref_pointer_array + el, 0, item->name);
+ }
+ Item_func::split_sum_func(ref_pointer_array, fields);
}
+
longlong Item_func_ascii::val_int()
{
String *res=args[0]->val_str(&value);
@@ -1014,12 +1167,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()))
{
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;
@@ -1079,6 +1232,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();
@@ -1092,7 +1246,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++;
@@ -1187,7 +1341,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
@@ -1200,11 +1354,11 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func,
}
else
thd=current_thd; // In WHERE / const clause
- udf_func *tmp_udf=find_udf(u_d->name,(uint) strlen(u_d->name),1);
+ udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1);
if (!tmp_udf)
{
- my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name,
+ my_printf_error(ER_CANT_FIND_UDF,ER(ER_CANT_FIND_UDF),MYF(0),u_d->name.str,
errno);
DBUG_RETURN(1);
}
@@ -1212,7 +1366,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;
@@ -1231,10 +1385,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) || (*arg)->check_cols(1))
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;
@@ -1360,6 +1514,11 @@ bool udf_handler::get_arguments()
to+= ALIGN_SIZE(sizeof(double));
}
break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
}
return 0;
@@ -1397,7 +1556,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, str->charset());
return save_str;
}
@@ -1418,7 +1577,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,default_charset());
return str;
}
@@ -1439,9 +1598,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,default_charset());
else
- str->set((ulonglong) nr);
+ str->set((ulonglong) nr,default_charset());
return str;
}
@@ -1522,7 +1681,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)
@@ -1537,9 +1697,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);
@@ -1561,7 +1721,7 @@ longlong Item_master_pos_wait::val_int()
{
THD* thd = current_thd;
String *log_name = args[0]->val_str(&value);
- int event_count;
+ int event_count= 0;
null_value=0;
if (thd->slave_thread || !log_name || !log_name->length())
@@ -1569,15 +1729,17 @@ longlong Item_master_pos_wait::val_int()
null_value = 1;
return 0;
}
- longlong pos = args[1]->val_int();
+ longlong pos = (ulong)args[1]->val_int();
longlong timeout = (arg_count==3) ? args[2]->val_int() : 0 ;
+#ifdef HAVE_REPLICATION
LOCK_ACTIVE_MI;
- if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
- {
+ if ((event_count = active_mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
+ {
null_value = 1;
event_count=0;
}
UNLOCK_ACTIVE_MI;
+#endif
return event_count;
}
@@ -1798,7 +1960,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), &my_charset_bin);
THD *thd=current_thd;
for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++)
@@ -1813,6 +1975,11 @@ longlong Item_func_benchmark::val_int()
case STRING_RESULT:
(void) args[0]->val_str(&tmp);
break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
}
return 0;
@@ -1841,6 +2008,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
entry->value=0;
entry->length=0;
entry->update_query_id=0;
+ entry->used_query_id=current_thd->query_id;
entry->type=STRING_RESULT;
memcpy(entry->name.str, name.str, name.length+1);
if (hash_insert(hash,(byte*) entry))
@@ -1853,11 +2021,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) ||
+ /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
+ 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;
@@ -1875,7 +2044,9 @@ 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,
+ enum coercion coercibility)
{
if ((null_value=args[0]->null_value))
{
@@ -1884,6 +2055,8 @@ 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;
+ entry->var_coercibility= coercibility;
}
else
{
@@ -1914,11 +2087,13 @@ 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;
+ entry->var_coercibility= coercibility;
}
return;
err:
- current_thd->fatal_error=1; // Probably end of memory
+ current_thd->fatal_error(); // Probably end of memory
null_value=1;
return;
}
@@ -1935,12 +2110,19 @@ Item_func_set_user_var::update()
(void) val_int();
break;
case STRING_RESULT:
+ {
char buffer[MAX_FIELD_WIDTH];
- String tmp(buffer,sizeof(buffer));
+ String tmp(buffer,sizeof(buffer),&my_charset_bin);
(void) val_str(&tmp);
break;
}
- return current_thd->fatal_error;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
+ }
+ return current_thd->is_fatal_error;
}
@@ -1948,7 +2130,8 @@ 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,
+ &my_charset_bin, COER_NOCOLL);
return value;
}
@@ -1956,7 +2139,8 @@ 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,
+ &my_charset_bin, COER_NOCOLL);
return value;
}
@@ -1965,9 +2149,10 @@ 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, &my_charset_bin, COER_NOCOLL);
else
- update_hash(res->c_ptr(),res->length()+1,STRING_RESULT);
+ update_hash((void*) res->ptr(), res->length(), STRING_RESULT,
+ res->charset(), args[0]->coercibility);
return res;
}
@@ -2002,18 +2187,23 @@ 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, &my_charset_bin);
break;
case INT_RESULT:
- str->set(*(longlong*) entry->value);
+ str->set(*(longlong*) entry->value, &my_charset_bin);
break;
case STRING_RESULT:
- if (str->copy(entry->value, entry->length-1))
+ if (str->copy(entry->value, entry->length, entry->var_charset))
{
null_value=1;
return NULL;
}
break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
return str;
}
@@ -2031,6 +2221,11 @@ double Item_func_get_user_var::val()
return (double) *(longlong*) entry->value;
case STRING_RESULT:
return atof(entry->value); // This is null terminated
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
return 0.0; // Impossible
}
@@ -2048,6 +2243,11 @@ longlong Item_func_get_user_var::val_int()
return *(longlong*) entry->value;
case STRING_RESULT:
return strtoull(entry->value,NULL,10); // String is null terminated
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
return LL(0); // Impossible
}
@@ -2055,16 +2255,63 @@ longlong Item_func_get_user_var::val_int()
void Item_func_get_user_var::fix_length_and_dec()
{
+ BINLOG_USER_VAR_EVENT *user_var_event;
THD *thd=current_thd;
maybe_null=1;
decimals=NOT_FIXED_DEC;
max_length=MAX_BLOB_WIDTH;
- var_entry= get_variable(&thd->user_vars, name, 0);
+
+ if ((var_entry= get_variable(&thd->user_vars, name, 0)))
+ {
+ if (opt_bin_log && is_update_query(thd->lex.sql_command) &&
+ var_entry->used_query_id != thd->query_id)
+ {
+ uint size;
+ /*
+ First we need to store value of var_entry, when the next situation
+ appers:
+ > set @a:=1;
+ > insert into t1 values (@a), (@a:=@a+1), (@a:=@a+1);
+ We have to write to binlog value @a= 1;
+ */
+ size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length;
+ if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) thd->alloc(size)))
+ goto err;
+
+ user_var_event->value= (char*) user_var_event +
+ ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT));
+ user_var_event->user_var_event= var_entry;
+ user_var_event->type= var_entry->type;
+ user_var_event->charset_number= var_entry->var_charset->number;
+ if (!var_entry->value)
+ {
+ /* NULL value*/
+ user_var_event->length= 0;
+ user_var_event->value= 0;
+ }
+ else
+ {
+ user_var_event->length= var_entry->length;
+ memcpy(user_var_event->value, var_entry->value,
+ var_entry->length);
+ }
+ var_entry->used_query_id= thd->query_id;
+ if (insert_dynamic(&thd->user_var_events, (gptr) &user_var_event))
+ goto err;
+ }
+ }
+ return;
+
+err:
+ thd->fatal_error();
+ return;
}
bool Item_func_get_user_var::const_item() const
-{ return var_entry && current_thd->query_id != var_entry->update_query_id; }
+{
+ return var_entry && current_thd->query_id != var_entry->update_query_id;
+}
enum Item_result Item_func_get_user_var::result_type() const
@@ -2092,14 +2339,9 @@ bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
if (this == item)
return 1; // Same item is same.
/* Check if other type is also a get_user_var() object */
-#ifdef FIX_THIS
- if (item->eq == &Item_func_get_user_var::eq)
- return 0;
-#else
if (item->type() != FUNC_ITEM ||
((Item_func*) item)->func_name() != func_name())
return 0;
-#endif
Item_func_get_user_var *other=(Item_func_get_user_var*) item;
return (name.length == other->name.length &&
!memcmp(name.str, other->name.str, name.length));
@@ -2114,7 +2356,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),&my_charset_bin);
if (!(s = args[0]->val_str(&tmp))) // If null value
goto err;
null_value=0;
@@ -2153,7 +2395,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)
{
@@ -2164,15 +2408,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,
@@ -2187,7 +2431,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;
@@ -2201,7 +2445,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;
@@ -2209,7 +2453,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()) || item->check_cols(1))
return 1;
if (item->type() == Item::REF_ITEM)
li.replace(item= *((Item_ref *)item)->ref);
@@ -2233,6 +2477,14 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
return 0;
}
+void Item_func_match::set_outer_resolving()
+{
+ Item_real_func::set_outer_resolving();
+ List_iterator<Item> li(fields);
+ Item *item;
+ while ((item= li++))
+ item->set_outer_resolving();
+}
bool Item_func_match::fix_index()
{
@@ -2356,6 +2608,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();
@@ -2372,23 +2625,24 @@ 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)))
return 0; // Impossible
- thd->safe_to_cache_query=0;
+ thd->lex.uncacheable();
buff[0]='@';
buff[1]='@';
pos=buff+2;
@@ -2403,6 +2657,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->lex.uncacheable();
+ item->set_name(item_name); // Will use original name
+ return item;
+}
+
+
/*
Check a user level lock.
@@ -2437,3 +2708,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 68e5335dc7e..860ddbbbadf 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -31,7 +31,8 @@ extern "C" /* Bug in BSDI include file */
class Item_func :public Item_result_field
{
protected:
- Item **args,*tmp_arg[2];
+ Item **args, *tmp_arg[2];
+ uint allowed_arg_cols;
public:
uint arg_count;
table_map used_tables_cache;
@@ -39,63 +40,72 @@ 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; }
- Item_func(void)
+ Item_func(void):
+ allowed_arg_cols(1), arg_count(0)
{
- arg_count=0; with_sum_func=0;
+ with_sum_func= 0;
}
- Item_func(Item *a)
+ Item_func(Item *a):
+ allowed_arg_cols(1), arg_count(1)
{
- arg_count=1;
- args=tmp_arg;
- args[0]=a;
- with_sum_func=a->with_sum_func;
+ args= tmp_arg;
+ args[0]= a;
+ with_sum_func= a->with_sum_func;
}
- Item_func(Item *a,Item *b)
+ Item_func(Item *a,Item *b):
+ allowed_arg_cols(1), arg_count(2)
{
- arg_count=2;
- args=tmp_arg;
- args[0]=a; args[1]=b;
- with_sum_func=a->with_sum_func || b->with_sum_func;
+ args= tmp_arg;
+ args[0]= a; args[1]= b;
+ with_sum_func= a->with_sum_func || b->with_sum_func;
}
- Item_func(Item *a,Item *b,Item *c)
+ Item_func(Item *a,Item *b,Item *c):
+ allowed_arg_cols(1)
{
- arg_count=0;
- if ((args=(Item**) sql_alloc(sizeof(Item*)*3)))
+ arg_count= 0;
+ if ((args= (Item**) sql_alloc(sizeof(Item*)*3)))
{
- arg_count=3;
- args[0]=a; args[1]=b; args[2]=c;
- with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func;
+ arg_count= 3;
+ args[0]= a; args[1]= b; args[2]= c;
+ with_sum_func= a->with_sum_func || b->with_sum_func || c->with_sum_func;
}
}
- Item_func(Item *a,Item *b,Item *c,Item *d)
+ Item_func(Item *a,Item *b,Item *c,Item *d):
+ allowed_arg_cols(1)
{
- arg_count=0;
- if ((args=(Item**) sql_alloc(sizeof(Item*)*4)))
+ arg_count= 0;
+ if ((args= (Item**) sql_alloc(sizeof(Item*)*4)))
{
- arg_count=4;
- args[0]=a; args[1]=b; args[2]=c; args[3]=d;
- with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func ||
- d->with_sum_func;
+ arg_count= 4;
+ args[0]= a; args[1]= b; args[2]= c; args[3]= d;
+ with_sum_func= a->with_sum_func || b->with_sum_func ||
+ c->with_sum_func || d->with_sum_func;
}
}
- Item_func(Item *a,Item *b,Item *c,Item *d,Item* e)
+ Item_func(Item *a,Item *b,Item *c,Item *d,Item* e):
+ allowed_arg_cols(1)
{
- arg_count=5;
- if ((args=(Item**) sql_alloc(sizeof(Item*)*5)))
+ arg_count= 5;
+ if ((args= (Item**) sql_alloc(sizeof(Item*)*5)))
{
- args[0]=a; args[1]=b; args[2]=c; args[3]=d; args[4]=e;
- with_sum_func=a->with_sum_func || b->with_sum_func || c->with_sum_func ||
- d->with_sum_func || e->with_sum_func ;
+ args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e;
+ with_sum_func= a->with_sum_func || b->with_sum_func ||
+ c->with_sum_func || d->with_sum_func || e->with_sum_func ;
}
}
Item_func(List<Item> &list);
~Item_func() {} /* Nothing to do; Items are freed automaticly */
- bool fix_fields(THD *,struct st_table_list *);
- void make_field(Send_field *field);
+ bool fix_fields(THD *,struct st_table_list *, Item **ref);
table_map used_tables() const;
void update_used_tables();
bool eq(const Item *item, bool binary_cmp) const;
@@ -107,7 +117,7 @@ public:
inline Item **arguments() const { return args; }
inline uint argument_count() const { return arg_count; }
inline void remove_arguments() { arg_count=0; }
- virtual void split_sum_func(List<Item> &fields);
+ virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
void print(String *str);
void print_op(String *str);
void fix_num_length_and_dec();
@@ -121,8 +131,10 @@ 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() { return result_field; }
Field *tmp_table_field(TABLE *t_arg);
+ void set_outer_resolving();
+ Item *get_tmp_table_item(THD *thd);
};
@@ -137,7 +149,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 +164,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 +179,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 +260,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:
@@ -495,7 +516,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);}
};
@@ -506,13 +526,12 @@ class Item_func_min_max :public Item_func
int cmp_sign;
public:
Item_func_min_max(List<Item> &list,int cmp_sign_arg) :Item_func(list),
- cmp_sign(cmp_sign_arg) {}
+ cmp_type(INT_RESULT), cmp_sign(cmp_sign_arg) {}
double val();
longlong val_int();
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
@@ -530,6 +549,18 @@ public:
};
+#ifdef HAVE_COMPRESS
+class Item_func_crc32 :public Item_int_func
+{
+ String value;
+public:
+ Item_func_crc32(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "crc32"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+#endif
+
class Item_func_length :public Item_int_func
{
String value;
@@ -538,7 +569,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,19 +587,31 @@ 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_coercibility :public Item_int_func
+{
+public:
+ Item_func_coercibility(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "coercibility"; }
+ void fix_length_and_dec() { max_length=10; }
};
class Item_func_locate :public Item_int_func
{
String value1,value2;
+ bool binary_cmp;
public:
Item_func_locate(Item *a,Item *b) :Item_int_func(a,b) {}
Item_func_locate(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {}
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);}
+ void fix_length_and_dec()
+ {
+ maybe_null=0; max_length=11;
+ binary_cmp = args[0]->binary() || args[1]->binary();
+ }
};
@@ -581,11 +623,12 @@ 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->check_cols(1) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
- void split_sum_func(List<Item> &fields);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
void update_used_tables()
{
item->update_used_tables() ; Item_func::update_used_tables();
@@ -600,7 +643,11 @@ public:
const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
}
- unsigned int size_of() { return sizeof(*this);}
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_int_func::set_outer_resolving();
+ }
};
@@ -612,7 +659,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
@@ -622,7 +668,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
@@ -635,7 +680,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);}
};
@@ -711,7 +755,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);}
};
@@ -728,15 +771,15 @@ 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;
+ fixed= 1;
return res;
}
Item_result result_type () const { return udf.result_type(); }
- unsigned int size_of() { return sizeof(*this);}
};
@@ -779,13 +822,15 @@ public:
String *val_str(String *);
double val()
{
+ int err;
String *res; res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),0,&err) : 0.0;
}
longlong val_int()
{
+ int err;
String *res; res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,(char**) 0,&err) : (longlong) 0;
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
@@ -845,7 +890,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
@@ -856,7 +900,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 */
@@ -870,7 +913,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=21; maybe_null=1;}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -885,18 +927,20 @@ class Item_func_set_user_var :public Item_func
user_var_entry *entry;
public:
- Item_func_set_user_var(LEX_STRING a,Item *b): Item_func(b), name(a) {}
+ Item_func_set_user_var(LEX_STRING a,Item *b)
+ :Item_func(b), cached_result_type(INT_RESULT), name(a)
+ {}
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, enum coercion coercibility);
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);}
};
@@ -915,12 +959,16 @@ public:
void fix_length_and_dec();
void print(String *str);
enum Item_result result_type() const;
+ /*
+ We must always return variables as strings to guard against selects of type
+ select @t1:=1,@t1,@t:="hello",@t from foo where (@t1:= t2.b)
+ */
+ enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
const char *func_name() const { return "get_user_var"; }
bool const_item() const;
table_map used_tables() const
{ return const_item() ? 0 : RAND_TABLE_BIT; }
bool eq(const Item *item, bool binary_cmp) const;
- unsigned int size_of() { return sizeof(*this);}
};
@@ -960,7 +1008,7 @@ public:
{
ft_handler->please->close_search(ft_handler);
ft_handler=0;
- if(join_key)
+ if (join_key)
table->file->ft_handler=0;
table->fulltext_searched=0;
}
@@ -969,14 +1017,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);}
+ void set_outer_resolving();
+};
+
+
+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"; }
};
@@ -999,16 +1131,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_CAST_CHAR
-};
-
-Item *create_func_cast(Item *a, Item_cast cast_type);
-
class Item_func_bit_xor : public Item_int_func
{
@@ -1027,5 +1149,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, ITEM_CAST_CHAR
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
new file mode 100644
index 00000000000..cf745e21e45
--- /dev/null
+++ b/sql/item_row.cc
@@ -0,0 +1,131 @@
+/* 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"
+
+/*
+ Row items used for comparing rows and IN operations on rows:
+
+ (a, b, c) > (10, 10, 30)
+ (a, b, c) = (select c, d, e, from t1 where x=12)
+ (a, b, c) IN ((1,2,2), (3,4,5), (6,7,8)
+ (a, b, c) IN (select c, d, e, from t1)
+*/
+
+Item_row::Item_row(List<Item> &arg):
+ Item(), used_tables_cache(0), array_holder(1), const_item_cache(1), with_null(0)
+{
+
+ //TODO: think placing 2-3 component items in item (as it done for function)
+ if ((arg_count= arg.elements))
+ items= (Item**) sql_alloc(sizeof(Item*)*arg_count);
+ else
+ items= 0;
+ List_iterator<Item> li(arg);
+ uint i= 0;
+ Item *item;
+ while ((item= li++))
+ {
+ items[i]= item;
+ i++;
+ }
+}
+
+void Item_row::illegal_method_call(const char *method)
+{
+ DBUG_ENTER("Item_row::illegal_method_call");
+ DBUG_PRINT("error", ("!!! %s method was called for row item", method));
+ DBUG_ASSERT(0);
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ DBUG_VOID_RETURN;
+}
+
+bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
+{
+ null_value= 0;
+ maybe_null= 0;
+ Item **arg, **arg_end;
+ for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
+ {
+ if ((*arg)->fix_fields(thd, tabl, arg))
+ return 1;
+ used_tables_cache |= (*arg)->used_tables();
+ if (const_item_cache&= (*arg)->const_item() && !with_null)
+ {
+ if ((*arg)->cols() > 1)
+ with_null|= (*arg)->null_inside();
+ else
+ {
+ (*arg)->val_int();
+ with_null|= (*arg)->null_value;
+ }
+ }
+ maybe_null|= (*arg)->maybe_null;
+ with_sum_func= with_sum_func || (*arg)->with_sum_func;
+ }
+ return 0;
+}
+
+void Item_row::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
+{
+ Item **arg, **arg_end;
+ for (arg= items, arg_end= items+arg_count; arg != arg_end ; arg++)
+ {
+ if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM)
+ (*arg)->split_sum_func(ref_pointer_array, fields);
+ else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
+ {
+ uint el= fields.elements;
+ fields.push_front(*arg);
+ ref_pointer_array[el]= *arg;
+ *arg= new Item_ref(ref_pointer_array + el, 0, (*arg)->name);
+ }
+ }
+}
+
+void Item_row::update_used_tables()
+{
+ used_tables_cache= 0;
+ const_item_cache= 1;
+ for (uint i= 0; i < arg_count; i++)
+ {
+ items[i]->update_used_tables();
+ used_tables_cache|= items[i]->used_tables();
+ const_item_cache&= items[i]->const_item();
+ }
+}
+
+bool Item_row::check_cols(uint c)
+{
+ if (c != arg_count)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
+
+void Item_row::bring_value()
+{
+ for (uint i= 0; i < arg_count; i++)
+ items[i]->bring_value();
+}
+
+void Item_row::set_outer_resolving()
+{
+ for (uint i= 0; i < arg_count; i++)
+ items[i]->set_outer_resolving();
+}
diff --git a/sql/item_row.h b/sql/item_row.h
new file mode 100644
index 00000000000..4f674d8a561
--- /dev/null
+++ b/sql/item_row.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+class Item_row: public Item
+{
+ Item **items;
+ table_map used_tables_cache;
+ uint arg_count;
+ bool array_holder;
+ bool const_item_cache;
+ bool with_null;
+public:
+ Item_row(List<Item> &);
+ Item_row(Item_row *item):
+ Item(),
+ items(item->items),
+ used_tables_cache(item->used_tables_cache),
+ arg_count(item->arg_count),
+ array_holder(0),
+ const_item_cache(item->const_item_cache),
+ with_null(0)
+ {}
+
+ ~Item_row()
+ {
+ if (array_holder && items)
+ sql_element_free(items);
+ }
+
+ enum Type type() const { return ROW_ITEM; };
+ void illegal_method_call(const char *);
+ bool is_null() { return null_value; }
+ void make_field(Send_field *)
+ {
+ illegal_method_call((const char*)"make_field");
+ };
+ double val()
+ {
+ illegal_method_call((const char*)"val");
+ return 0;
+ };
+ longlong val_int()
+ {
+ illegal_method_call((const char*)"val_int");
+ return 0;
+ };
+ String *val_str(String *)
+ {
+ illegal_method_call((const char*)"val_str");
+ return 0;
+ };
+ bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
+ table_map used_tables() const { return used_tables_cache; };
+ bool const_item() const { return const_item_cache; };
+ enum Item_result result_type() const { return ROW_RESULT; }
+ void update_used_tables();
+ void set_outer_resolving();
+
+ uint cols() { return arg_count; }
+ Item* el(uint i) { return items[i]; }
+ Item** addr(uint i) { return items + i; }
+ bool check_cols(uint c);
+ bool null_inside() { return with_null; };
+ void bring_value();
+};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index f1e37889d5f..80d85e565e7 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;
@@ -52,16 +52,19 @@ uint nr_of_decimals(const char *str)
double Item_str_func::val()
{
+ int err;
String *res;
res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
+ NULL, &err) : 0.0;
}
longlong Item_str_func::val_int()
{
+ int err;
String *res;
res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),NULL,10) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10,NULL,&err) : (longlong) 0;
}
@@ -124,12 +127,12 @@ String *Item_func_sha::val_str(String *str)
digest[8], digest[9], digest[10], digest[11],
digest[12], digest[13], digest[14], digest[15],
digest[16], digest[17], digest[18], digest[19]);
-
+
str->length((uint) SHA1_HASH_SIZE*2);
null_value=0;
return str;
}
- }
+ }
null_value=1;
return 0;
}
@@ -145,7 +148,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;
@@ -153,13 +156,13 @@ String *Item_func_aes_encrypt::val_str(String *str)
{
null_value=0;
aes_length=my_aes_get_size(sptr->length()); // Calculate result length
-
+
if (!str_value.alloc(aes_length)) // Ensure that memory is free
{
// finally encrypt directly to allocated buffer.
if (my_aes_encrypt(sptr->ptr(),sptr->length(), (char*) str_value.ptr(),
key->ptr(), key->length()) == aes_length)
- {
+ {
// We got the expected result length
str_value.length((uint) aes_length);
return &str_value;
@@ -180,7 +183,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
@@ -196,7 +200,7 @@ String *Item_func_aes_decrypt::val_str(String *str)
(char*) str_value.ptr(),
key->ptr(), key->length());
if (length >= 0) // if we got correct data data
- {
+ {
str_value.length((uint) length);
DBUG_RETURN(&str_value);
}
@@ -231,6 +235,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 +265,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 +277,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 +296,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 +306,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;
}
}
@@ -321,7 +331,7 @@ void Item_func_concat::fix_length_and_dec()
}
}
-/*
+/*
Function des_encrypt() by tonu@spam.ee & monty
Works only if compiled with OpenSSL library support.
This returns a binary string where first character is CHAR(128 | key-number).
@@ -378,10 +388,10 @@ String *Item_func_des_encrypt::val_str(String *str)
des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
}
- /*
+ /*
The problem: DES algorithm requires original data to be in 8-bytes
- chunks. Missing bytes get filled with '*'s and result of encryption
- can be up to 8 bytes longer than original string. When decrypted,
+ chunks. Missing bytes get filled with '*'s and result of encryption
+ can be up to 8 bytes longer than original string. When decrypted,
we do not know the size of original string :(
We add one byte with value 0x1..0x8 as the last byte of the padded
string marking change of string length.
@@ -452,7 +462,7 @@ String *Item_func_des_decrypt::val_str(String *str)
// Here we set all 64-bit keys (56 effective) one by one
des_set_key_unchecked(&keyblock.key1,keyschedule.ks1);
des_set_key_unchecked(&keyblock.key2,keyschedule.ks2);
- des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
+ des_set_key_unchecked(&keyblock.key3,keyschedule.ks3);
}
if (tmp_value.alloc(length-1))
goto error;
@@ -478,7 +488,7 @@ error:
}
-/*
+/*
concat with separator. First arg is the separator
concat_ws takes at least two arguments.
*/
@@ -486,7 +496,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;
@@ -587,16 +597,19 @@ null:
return 0;
}
-void Item_func_concat_ws::split_sum_func(List<Item> &fields)
+void Item_func_concat_ws::split_sum_func(Item **ref_pointer_array,
+ List<Item> &fields)
{
if (separator->with_sum_func && separator->type() != SUM_FUNC_ITEM)
- separator->split_sum_func(fields);
+ separator->split_sum_func(ref_pointer_array, fields);
else if (separator->used_tables() || separator->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(separator);
- separator= new Item_ref((Item**) fields.head_ref(), 0, separator->name);
- }
- Item_str_func::split_sum_func(fields);
+ ref_pointer_array[el]= separator;
+ separator= new Item_ref(ref_pointer_array + el, 0, separator->name);
+ }
+ Item_str_func::split_sum_func(ref_pointer_array, fields);
}
void Item_func_concat_ws::fix_length_and_dec()
@@ -637,7 +650,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()))
{
String tmpstr;
tmpstr.copy(*res);
@@ -645,7 +658,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++;
@@ -688,8 +701,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_cmp;
#endif
null_value=0;
@@ -700,6 +712,10 @@ String *Item_func_replace::val_str(String *str)
if (args[1]->null_value)
goto null;
+#ifdef USE_MB
+ binary_cmp = (args[0]->binary() || args[1]->binary() || !use_mb(res->charset()));
+#endif
+
if (res2->length() == 0)
return res;
#ifndef USE_MB
@@ -707,7 +723,7 @@ String *Item_func_replace::val_str(String *str)
return res;
#else
offset=0;
- if (binary_str && (offset=res->strstr(*res2)) < 0)
+ if (binary_cmp && (offset=res->strstr(*res2)) < 0)
return res;
#endif
if (!(res3=args[2]->val_str(&tmp_value2)))
@@ -716,7 +732,7 @@ String *Item_func_replace::val_str(String *str)
to_length= res3->length();
#ifdef USE_MB
- if (!binary_str)
+ if (!binary_cmp)
{
search=res2->ptr();
search_end=search+from_length;
@@ -746,7 +762,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;
}
}
@@ -804,13 +820,8 @@ String *Item_func_insert::val_str(String *str)
if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
args[3]->null_value)
goto null; /* purecov: inspected */
-#ifdef USE_MB
- if (use_mb(default_charset_info) && !args[0]->binary)
- {
- start=res->charpos(start);
- length=res->charpos(length,start);
- }
-#endif
+ start=res->charpos(start);
+ length=res->charpos(length,start);
if (start > res->length()+1)
return res; // Wrong param; skip insert
if (length > res->length()-start)
@@ -877,15 +888,13 @@ String *Item_func_left::val_str(String *str)
return 0;
if (length <= 0)
return &empty_string;
-#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
- length = res->charpos(length);
-#endif
+ length= res->charpos(length);
if (res->length() > (ulong) length)
{ // Safe even if const arg
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);
@@ -925,19 +934,11 @@ String *Item_func_right::val_str(String *str)
return &empty_string; /* purecov: inspected */
if (res->length() <= (uint) length)
return res; /* purecov: inspected */
-#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
- {
- uint start=res->numchars()-(uint) length;
- if (start<=0) return res;
- start=res->charpos(start);
- tmp_value.set(*res,start,res->length()-start);
- }
- else
-#endif
- {
- tmp_value.set(*res,(res->length()- (uint) length),(uint) length);
- }
+
+ uint start=res->numchars()-(uint) length;
+ if (start<=0) return res;
+ start=res->charpos(start);
+ tmp_value.set(*res,start,res->length()-start);
return &tmp_value;
}
@@ -958,13 +959,8 @@ String *Item_func_substr::val_str(String *str)
if ((null_value=(args[0]->null_value || args[1]->null_value ||
(arg_count == 3 && args[2]->null_value))))
return 0; /* purecov: inspected */
-#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
- {
- start=res->charpos(start);
- length=res->charpos(length,start);
- }
-#endif
+ start=res->charpos(start);
+ length=res->charpos(length,start);
if (start < 0 || (uint) start+1 > res->length() || length <= 0)
return &empty_string;
@@ -1019,7 +1015,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()))
{
const char *ptr=res->ptr();
const char *strend = ptr+res->length();
@@ -1044,7 +1040,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 */
@@ -1116,7 +1112,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);
@@ -1154,7 +1150,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);
@@ -1173,11 +1169,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()))
{
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;
@@ -1190,12 +1186,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()))
{
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))
@@ -1226,7 +1222,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);
@@ -1241,14 +1237,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()))
{
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))
@@ -1272,19 +1268,83 @@ String *Item_func_trim::val_str(String *str)
return &tmp_value;
}
+void Item_func_password::fix_length_and_dec()
+{
+ max_length= get_password_length(use_old_passwords);
+}
+
+/*
+ Password() function has 2 arguments. Second argument can be used
+ to make results repeatable
+*/
String *Item_func_password::val_str(String *str)
{
+ struct rand_struct rand_st; // local structure for 2 param version
+ ulong seed=0; // seed to initialise random generator to
+
+ String *res =args[0]->val_str(str);
+ if ((null_value=args[0]->null_value))
+ return 0;
+
+ if (arg_count == 1)
+ {
+ if (res->length() == 0)
+ return &empty_string;
+ make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
+ &current_thd->rand);
+ str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
+ return str;
+ }
+ else
+ {
+ /* We'll need the buffer to get second parameter */
+ char key_buff[80];
+ String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
+ String *key =args[1]->val_str(&tmp_key_value);
+
+ /* Check second argument for NULL value. First one is already checked */
+ if ((null_value=args[1]->null_value))
+ return 0;
+
+ /* This shall be done after checking for null for proper results */
+ if (res->length() == 0)
+ return &empty_string;
+
+ /* Generate the seed first this allows to avoid double allocation */
+ char* seed_ptr=key->c_ptr();
+ while (*seed_ptr)
+ {
+ seed=(seed*211+*seed_ptr) & 0xffffffffL; /* Use simple hashing */
+ seed_ptr++;
+ }
+
+ /* Use constants which allow nice random values even with small seed */
+ randominit(&rand_st,
+ (ulong) ((ulonglong) seed*111111+33333333L) & (ulong) 0xffffffff,
+ (ulong) ((ulonglong) seed*1111+55555555L) & (ulong) 0xffffffff);
+
+ make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
+ &rand_st);
+ str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
+ return str;
+ }
+}
+
+String *Item_func_old_password::val_str(String *str)
+{
String *res =args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
if (res->length() == 0)
return &empty_string;
- make_scrambled_password(tmp_value,res->c_ptr());
- str->set(tmp_value,16);
+ make_scrambled_password(tmp_value,res->c_ptr(),1,&current_thd->rand);
+ str->set(tmp_value,16,res->charset());
return str;
}
+
+
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
String *Item_func_encrypt::val_str(String *str)
@@ -1315,7 +1375,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;
@@ -1364,20 +1424,30 @@ String *Item_func_decode::val_str(String *str)
String *Item_func_database::val_str(String *str)
{
- if (!current_thd->db)
+ THD *thd= current_thd;
+ if (!thd->db)
str->length(0);
else
- str->set((const char*) current_thd->db,(uint) strlen(current_thd->db));
+ str->copy((const char*) thd->db,(uint) strlen(thd->db),
+ system_charset_info, default_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= default_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;
}
@@ -1398,9 +1468,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)
@@ -1414,6 +1484,8 @@ String *Item_func_soundex::val_str(String *str)
{
String *res =args[0]->val_str(str);
char last_ch,ch;
+ CHARSET_INFO *cs= &my_charset_latin1;
+
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
@@ -1421,22 +1493,23 @@ String *Item_func_soundex::val_str(String *str)
return str; /* purecov: inspected */
char *to= (char *) tmp_value.ptr();
char *from= (char *) res->ptr(), *end=from+res->length();
-
- while (from != end && isspace(*from)) // Skip pre-space
+ tmp_value.set_charset(cs);
+
+ while (from != end && my_isspace(cs,*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(cs,*from); // Copy first letter
+ last_ch = get_scode(cs,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(cs,*from))
continue;
- ch=get_scode(from);
+ ch=get_scode(cs,from);
if ((ch != '0') && (ch != last_ch)) // if not skipped or double
{
*to++ = ch; // letter, copy to output
@@ -1470,7 +1543,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,default_charset());
str_length=str->length();
if (nr < 0)
str_length--; // Don't count sign
@@ -1513,16 +1586,19 @@ void Item_func_elt::fix_length_and_dec()
}
-void Item_func_elt::split_sum_func(List<Item> &fields)
+void Item_func_elt::split_sum_func(Item **ref_pointer_array,
+ List<Item> &fields)
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
- item->split_sum_func(fields);
+ item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(item);
- item= new Item_ref((Item**) fields.head_ref(), 0, item->name);
- }
- Item_str_func::split_sum_func(fields);
+ ref_pointer_array[el]= item;
+ item= new Item_ref(ref_pointer_array + el, 0, item->name);
+ }
+ Item_str_func::split_sum_func(ref_pointer_array, fields);
}
@@ -1572,16 +1648,19 @@ String *Item_func_elt::val_str(String *str)
}
-void Item_func_make_set::split_sum_func(List<Item> &fields)
+void Item_func_make_set::split_sum_func(Item **ref_pointer_array,
+ List<Item> &fields)
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
- item->split_sum_func(fields);
+ item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
+ uint el= fields.elements;
fields.push_front(item);
- item= new Item_ref((Item**) fields.head_ref(), 0, item->name);
- }
- Item_str_func::split_sum_func(fields);
+ ref_pointer_array[el]= item;
+ item= new Item_ref(ref_pointer_array + el, 0, item->name);
+ }
+ Item_str_func::split_sum_func(ref_pointer_array, fields);
}
@@ -1665,7 +1744,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));
@@ -1673,7 +1752,7 @@ String *Item_func_char::val_str(String *str)
} else if (num&0xFF0000L) {
b2: str->append((char)(num>>16));
goto b1;
- } else if (num&0xFF00L) {
+ } else if (num&0xFF00L) {
b1: str->append((char)(num>>8));
}
}
@@ -1913,6 +1992,7 @@ String *Item_func_conv::val_str(String *str)
longlong dec;
int from_base= (int) args[1]->val_int();
int to_base= (int) args[2]->val_int();
+ int err;
if (args[0]->null_value || args[1]->null_value || args[2]->null_value ||
abs(to_base) > 36 || abs(to_base) < 2 ||
@@ -1923,16 +2003,279 @@ String *Item_func_conv::val_str(String *str)
}
null_value=0;
if (from_base < 0)
- dec= strtoll(res->c_ptr(),&endptr,-from_base);
+ dec= my_strntoll(res->charset(),res->ptr(),res->length(),-from_base,&endptr,&err);
else
- dec= (longlong) strtoull(res->c_ptr(),&endptr,from_base);
+ dec= (longlong) my_strntoull(res->charset(),res->ptr(),res->length(),from_base,&endptr,&err);
ptr= longlong2str(dec,ans,to_base);
- if (str->copy(ans,(uint32) (ptr-ans)))
+ if (str->copy(ans,(uint32) (ptr-ans), default_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 (1)
+ {
+ 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;
+ coercibility= COER_IMPLICIT;
+ 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 (1)
+ {
+ 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) || args[0]->check_cols(1))
+ return 1;
+ maybe_null=args[0]->maybe_null;
+ const_item_cache=args[0]->const_item();
+ set_charset(conv_charset);
+ fix_length_and_dec();
+ fixed= 1;
+ return 0;
+}
+
+
+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(charset());
+ return str;
+}
+
+bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables, Item **ref)
+{
+ CHARSET_INFO *set_collation;
+ String tmp, *str;
+ const char *colname;
+ 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) || args[0]->check_cols(1))
+ return 1;
+ if (args[0]->fix_fields(thd, tables, args) || args[0]->check_cols(1))
+ return 2;
+ maybe_null=args[0]->maybe_null || args[1]->maybe_null;
+
+ str= args[1]->val_str(&tmp);
+ colname= str->c_ptr();
+ if (!strncmp(colname,"BINARY",6))
+ set_collation= get_charset_by_csname(args[0]->charset()->csname,
+ MY_CS_BINSORT,MYF(0));
+ else
+ set_collation= get_charset_by_name(colname,MYF(0));
+
+ if (!set_collation)
+ {
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), str->c_ptr());
+ return 1;
+ }
+
+ if (!my_charset_same(args[0]->charset(),set_collation))
+ {
+ my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
+ set_collation->name,args[0]->charset()->csname);
+ return 1;
+ }
+ set_charset(set_collation);
+
+ coercibility= COER_EXPLICIT;
+ 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();
+ fixed= 1;
+ 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 (charset() != item_func_sc->charset())
+ 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()->csname,strlen(res->charset()->csname),
+ &my_charset_latin1, default_charset());
+ return str;
+}
+
+String *Item_func_collation::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, default_charset());
+ return str;
+}
+
+
String *Item_func_hex::val_str(String *str)
{
if (args[0]->result_type() != STRING_RESULT)
@@ -1943,7 +2286,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;
}
@@ -2017,11 +2360,11 @@ err:
String* Item_func_export_set::val_str(String* str)
{
ulonglong the_set = (ulonglong) args[0]->val_int();
- String yes_buf, *yes;
+ String yes_buf, *yes;
yes = args[1]->val_str(&yes_buf);
- String no_buf, *no;
+ String no_buf, *no;
no = args[2]->val_str(&no_buf);
- String *sep = NULL, sep_buf ;
+ String *sep = NULL, sep_buf ;
uint num_set_values = 64;
ulonglong mask = 0x1;
@@ -2052,7 +2395,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;
@@ -2095,7 +2438,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
int4store(buf,n);
/* Now we can assume little endian. */
-
+
num[3]='.';
for (p=buf+4 ; p-- > buf ; )
{
@@ -2116,6 +2459,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.
@@ -2123,7 +2467,7 @@ String* Item_func_inet_ntoa::val_str(String* str)
DESCRIPTION
Adds a \ before all characters that needs to be escaped in a SQL string.
We also escape '^Z' (END-OF-FILE in windows) to avoid probelms when
- running commands from a file in windows.
+ running commands from a file in windows.
This function is very useful when you want to generate SQL statements
@@ -2139,7 +2483,7 @@ String *Item_func_quote::val_str(String *str)
/*
Bit mask that has 1 for set for the position of the following characters:
0, \, ' and ^Z
- */
+ */
static uchar escmask[32]=
{
@@ -2206,3 +2550,342 @@ null:
null_value= 1;
return 0;
}
+
+
+/*******************************************************
+General functions for spatial objects
+********************************************************/
+
+String *Item_func_geometry_from_text::val_str(String *str)
+{
+ Geometry geom;
+ String arg_val;
+ String *wkt = args[0]->val_str(&arg_val);
+ 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 arg_val;
+ String *wkt = args[0]->val_str(&arg_val);
+ 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 *res = args[0]->val_str(str);
+ Geometry geom;
+
+ if ((null_value = args[0]->null_value ||
+ geom.create_from_wkb(res->ptr(),res->length())))
+ return 0;
+
+ res->length(0);
+ return (null_value= geom.envelope(res)) ? 0 : res;
+}
+
+
+String *Item_func_centroid::val_str(String *str)
+{
+ String arg_val;
+ String *wkb = args[0]->val_str(&arg_val);
+ 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 arg_val;
+ String *wkb = args[0]->val_str(&arg_val);
+ Geometry geom;
+
+ if ((null_value = (args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()))))
+ return 0;
+
+ null_value=1;
+ str->length(0);
+ 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 arg_val;
+ String *wkb = args[0]->val_str(&arg_val);
+ 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)
+{
+ double x= args[0]->val();
+ double y= args[1]->val();
+
+ 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(x);
+ str->q_append(y);
+ 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)
+{
+ String arg_value;
+ 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)
+ {
+ String *res = args[i]->val_str(&arg_value);
+ if (args[i]->null_value)
+ goto ret;
+
+ 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 < 4 + 2 * POINT_DATA_SIZE)
+ goto ret;
+
+ uint32 llen=len;
+ const char *ldata=data;
+
+ n_points=uint4korr(data);
+ data+=4;
+ float8get(x1,data);
+ data+=8;
+ float8get(y1,data);
+ data+=8;
+
+ 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 5c9706ed633..8bfa4317698 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -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) ||
+ separator->check_cols(1) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
- void split_sum_func(List<Item> &fields);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
const char *func_name() const { return "concat_ws"; }
+ void set_outer_resolving()
+ {
+ separator->set_outer_resolving();
+ Item_func::set_outer_resolving();
+ }
};
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,21 +245,33 @@ 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);}
};
class Item_func_password :public Item_str_func
{
- char tmp_value[17];
+ char tmp_value[64]; /* This should be enough for new password format */
public:
Item_func_password(Item *a) :Item_str_func(a) {}
+ Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {}
String *val_str(String *);
- void fix_length_and_dec() { max_length = 16; }
+ void fix_length_and_dec();
const char *func_name() const { return "password"; }
- unsigned int size_of() { return sizeof(*this);}
};
+
+class Item_func_old_password :public Item_str_func
+{
+ char tmp_value[17]; /* old password length +1 */
+public:
+ Item_func_old_password(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ void fix_length_and_dec() { max_length = get_password_length(1); }
+ const char *func_name() const { return "old_password"; }
+};
+
+
+
class Item_func_des_encrypt :public Item_str_func
{
String tmp_value;
@@ -275,7 +282,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 +293,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 +303,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 +316,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 +331,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 * default_charset()->mbmaxlen;
+ set_charset(default_charset());
+ }
const char *func_name() const { return "database"; }
};
@@ -337,7 +344,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)*default_charset()->mbmaxlen;
+ set_charset(default_charset());
+ }
const char *func_name() const { return "user"; }
};
@@ -350,7 +361,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,15 +374,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->check_cols(1) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
- void split_sum_func(List<Item> &fields);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "elt"; }
- unsigned int size_of() { return sizeof(*this);}
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_str_func::set_outer_resolving();
+ }
};
@@ -385,15 +401,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->check_cols(1) ||
+ Item_func::fix_fields(thd, tlist, ref));
}
- void split_sum_func(List<Item> &fields);
+ void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "make_set"; }
- unsigned int size_of() { return sizeof(*this);}
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_str_func::set_outer_resolving();
+ }
};
@@ -408,7 +430,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);}
};
@@ -417,7 +438,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"; }
};
@@ -430,7 +451,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);}
};
@@ -443,7 +463,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);}
};
@@ -456,7 +475,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);}
};
@@ -478,7 +496,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,9 +508,14 @@ public:
{
String *tmp=args[0]->val_str(a);
null_value=args[0]->null_value;
+ tmp->set_charset(&my_charset_bin);
return tmp;
- }
- void fix_length_and_dec() { 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); }
};
@@ -506,8 +528,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;
+ }
};
@@ -522,7 +547,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)
@@ -541,3 +566,256 @@ 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
+{
+public:
+ Item_func_set_collation(Item *a, Item *b) :Item_str_func(a,b) {};
+ String *val_str(String *);
+ bool fix_fields(THD *thd,struct st_table_list *tables, Item **ref);
+ 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(default_charset());
+ };
+};
+
+class Item_func_collation :public Item_str_func
+{
+public:
+ Item_func_collation(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ const char *func_name() const { return "collation"; }
+ void fix_length_and_dec()
+ {
+ max_length=40; // should be enough
+ set_charset(default_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..76451680b59
--- /dev/null
+++ b/sql/item_subselect.cc
@@ -0,0 +1,869 @@
+/* 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"
+
+inline Item * and_items(Item* cond, Item *item)
+{
+ return (cond? (new Item_cond_and(cond, item)) : item);
+}
+
+Item_subselect::Item_subselect():
+ Item_result_field(), engine_owner(1), value_assigned(0), substitution(0),
+ have_to_be_excluded(0)
+{
+ reset();
+ /*
+ 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", (ulong) select_lex));
+
+ select_transformer(thd, select_lex->master_unit());
+ 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::select_transformer(THD *thd, st_select_lex_unit *unit)
+{
+ DBUG_ENTER("Item_subselect::select_transformer");
+ DBUG_VOID_RETURN;
+}
+
+
+bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
+{
+ if (substitution)
+ {
+ (*ref)= substitution;
+ substitution->name= name;
+ if (have_to_be_excluded)
+ engine->exclude();
+ substitution= 0;
+ int ret= (*ref)->fix_fields(thd, tables, ref);
+ // We can't substitute aggregate functions (like (SELECT (max(i)))
+ if ((*ref)->with_sum_func)
+ {
+ my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0));
+ return 1;
+ }
+ return ret;
+ }
+
+ char const *save_where= thd->where;
+ int res= engine->prepare();
+ if (!res)
+ {
+ // Is it one field subselect?
+ if (engine->cols() > max_columns)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ return 1;
+ }
+ fix_length_and_dec();
+ }
+ fixed= 1;
+ thd->where= save_where;
+ return res;
+}
+
+Item::Type Item_subselect::type() const
+{
+ return SUBSELECT_ITEM;
+}
+
+void Item_subselect::fix_length_and_dec()
+{
+ engine->fix_length_and_dec(0);
+}
+
+inline table_map Item_subselect::used_tables() const
+{
+ return (table_map) (engine->dependent() ? 1L :
+ (engine->uncacheable() ? RAND_TABLE_BIT : 0L));
+}
+
+Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
+ st_select_lex *select_lex):
+ Item_subselect(), value(0)
+{
+ DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect");
+ init(thd, select_lex, new select_singlerow_subselect(this));
+ max_columns= 1;
+ maybe_null= 1;
+ max_columns= UINT_MAX;
+ DBUG_VOID_RETURN;
+}
+
+void Item_singlerow_subselect::reset()
+{
+ null_value= 1;
+ if (value)
+ value->null_value= 1;
+}
+
+void Item_singlerow_subselect::select_transformer(THD *thd,
+ st_select_lex_unit *unit)
+{
+ SELECT_LEX *select_lex= unit->first_select();
+
+ if (!select_lex->next_select() && !select_lex->table_list.elements &&
+ select_lex->item_list.elements == 1 &&
+ /*
+ We cant change name of Item_field or Item_ref, because it will
+ prevent it's correct resolving, but we should save name of
+ removed item => we do not make optimization if top item of
+ list is field or reference.
+ TODO: solve above problem
+ */
+ !(select_lex->item_list.head()->type() == FIELD_ITEM ||
+ select_lex->item_list.head()->type() == REF_ITEM)
+ )
+ {
+
+ have_to_be_excluded= 1;
+ if (thd->lex.describe)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SELECT_REDUCED, warn_buff);
+ }
+ substitution= select_lex->item_list.head();
+ substitution->set_outer_resolving();
+
+ if (select_lex->where || select_lex->having)
+ {
+ Item *cond;
+ if (!select_lex->having)
+ cond= select_lex->where;
+ else if (!select_lex->where)
+ cond= select_lex->having;
+ else
+ if (!(cond= new Item_cond_and(select_lex->having, select_lex->where)))
+ return;
+ if (!(substitution= new Item_func_if(cond, substitution,
+ new Item_null())))
+ return;
+ }
+ }
+}
+
+void Item_singlerow_subselect::store(uint i, Item *item)
+{
+ row[i]->store(item);
+}
+
+enum Item_result Item_singlerow_subselect::result_type() const
+{
+ return engine->type();
+}
+
+void Item_singlerow_subselect::fix_length_and_dec()
+{
+ if ((max_columns= engine->cols()) == 1)
+ {
+ engine->fix_length_and_dec(row= &value);
+ if (!(value= Item_cache::get_cache(engine->type())))
+ return;
+ }
+ else
+ {
+ THD *thd= current_thd;
+ if (!(row= (Item_cache**)thd->alloc(sizeof(Item_cache*)*max_columns)))
+ return;
+ engine->fix_length_and_dec(row);
+ value= *row;
+ }
+ maybe_null= engine->may_be_null();
+}
+
+uint Item_singlerow_subselect::cols()
+{
+ return engine->cols();
+}
+
+bool Item_singlerow_subselect::check_cols(uint c)
+{
+ if (c != engine->cols())
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), c);
+ return 1;
+ }
+ return 0;
+}
+
+bool Item_singlerow_subselect::null_inside()
+{
+ for (uint i= 0; i < max_columns ; i++)
+ {
+ if (row[i]->null_value)
+ return 1;
+ }
+ return 0;
+}
+
+void Item_singlerow_subselect::bring_value()
+{
+ engine->exec();
+}
+
+double Item_singlerow_subselect::val ()
+{
+ if (!engine->exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val();
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+longlong Item_singlerow_subselect::val_int ()
+{
+ if (!engine->exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val_int();
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+String *Item_singlerow_subselect::val_str (String *str)
+{
+ if (!engine->exec() && !value->null_value)
+ {
+ null_value= 0;
+ return value->val_str(str);
+ }
+ else
+ {
+ reset();
+ return 0;
+ }
+}
+
+Item_exists_subselect::Item_exists_subselect(THD *thd,
+ st_select_lex *select_lex):
+ Item_subselect()
+{
+ DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
+ init(thd, select_lex, new select_exists_subselect(this));
+ max_columns= UINT_MAX;
+ null_value= 0; //can't be NULL
+ maybe_null= 0; //can't be NULL
+ value= 0;
+ // We need only 1 row to determinate existence
+ select_lex->master_unit()->global_parameters->select_limit= 1;
+ DBUG_VOID_RETURN;
+}
+
+Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp,
+ st_select_lex *select_lex):
+ Item_exists_subselect()
+{
+ DBUG_ENTER("Item_in_subselect::Item_in_subselect");
+ left_expr= left_exp;
+ init(thd, select_lex, new select_exists_subselect(this));
+ max_columns= UINT_MAX;
+ maybe_null= 1;
+ reset();
+ // We need only 1 row to determinate existence
+ select_lex->master_unit()->global_parameters->select_limit= 1;
+ DBUG_VOID_RETURN;
+}
+
+Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
+ compare_func_creator f,
+ st_select_lex *select_lex):
+ Item_in_subselect()
+{
+ DBUG_ENTER("Item_in_subselect::Item_in_subselect");
+ left_expr= left_exp;
+ func= f;
+ init(thd, select_lex, new select_exists_subselect(this));
+ max_columns= 1;
+ reset();
+ // We need only 1 row to determinate existence
+ select_lex->master_unit()->global_parameters->select_limit= 1;
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_exists_subselect::fix_length_and_dec()
+{
+ decimals= 0;
+ max_length= 1;
+ max_columns= engine->cols();
+}
+
+double Item_exists_subselect::val ()
+{
+ if (engine->exec())
+ {
+ reset();
+ return 0;
+ }
+ return (double) value;
+}
+
+longlong Item_exists_subselect::val_int ()
+{
+ if (engine->exec())
+ {
+ reset();
+ return 0;
+ }
+ return value;
+}
+
+String *Item_exists_subselect::val_str(String *str)
+{
+ if (engine->exec())
+ {
+ reset();
+ return 0;
+ }
+ str->set(value,default_charset());
+ return str;
+}
+
+double Item_in_subselect::val ()
+{
+ if (engine->exec())
+ {
+ reset();
+ null_value= 1;
+ return 0;
+ }
+ if (was_null && !value)
+ null_value= 1;
+ return (double) value;
+}
+
+longlong Item_in_subselect::val_int ()
+{
+ if (engine->exec())
+ {
+ reset();
+ null_value= 1;
+ return 0;
+ }
+ if (was_null && !value)
+ null_value= 1;
+ return value;
+}
+
+String *Item_in_subselect::val_str(String *str)
+{
+ if (engine->exec())
+ {
+ reset();
+ null_value= 1;
+ return 0;
+ }
+ if (was_null && !value)
+ {
+ null_value= 1;
+ return 0;
+ }
+ str->set(value,default_charset());
+ return str;
+}
+
+Item_in_subselect::Item_in_subselect(Item_in_subselect *item):
+ Item_exists_subselect(item)
+{
+ left_expr= item->left_expr;
+}
+
+Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item):
+ Item_in_subselect(item)
+{
+ func= item->func;
+}
+
+void Item_in_subselect::single_value_transformer(THD *thd,
+ st_select_lex_unit *unit,
+ Item *left_expr,
+ compare_func_creator func)
+{
+ DBUG_ENTER("Item_in_subselect::single_value_transformer");
+
+ if (unit->global_parameters->select_limit != HA_POS_ERROR)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "LIMIT & IN/ALL/ANY/SOME subquery");
+ DBUG_VOID_RETURN;
+ }
+ // no sense in ORDER BY without LIMIT
+ unit->global_parameters->order_list.empty();
+
+ Item_in_optimizer *optimizer;
+ substitution= optimizer= new Item_in_optimizer(left_expr, this);
+ if (!optimizer)
+ DBUG_VOID_RETURN;
+
+ /*
+ As far as Item_ref_in_optimizer do not substitude itself on fix_fields
+ we can use same item for all selects.
+ */
+ Item *expr= new Item_ref((Item**)optimizer->get_cache(),
+ (char *)"<no matter>",
+ (char*)"<left expr>");
+ unit->dependent= 1;
+ for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->select_limit != HA_POS_ERROR)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "LIMIT & IN/ALL/ANY/SOME subquery");
+ DBUG_VOID_RETURN;
+ }
+
+ sl->dependent= 1;
+ Item *item;
+ if (sl->item_list.elements > 1)
+ {
+ my_error(ER_CARDINALITY_COL, MYF(0), 1);
+ DBUG_VOID_RETURN;
+ }
+ else
+ item= (Item*) sl->item_list.pop();
+
+ sl->order_list.empty(); // no sense in ORDER BY without LIMIT
+
+ if (sl->having || sl->with_sum_func || sl->group_list.elements)
+ {
+ sl->item_list.push_back(item);
+ setup_ref_array(thd, &sl->ref_pointer_array,
+ 1 + sl->with_sum_func +
+ sl->order_list.elements + sl->group_list.elements);
+ // To prevent crash on Item_ref_null_helper destruction in case of error
+ sl->ref_pointer_array[0]= 0;
+ item= (*func)(expr, new Item_ref_null_helper(this,
+ sl->ref_pointer_array,
+ (char *)"<ref>",
+ this->full_name()));
+ sl->having= and_items(sl->having, item);
+ }
+ else
+ {
+ sl->item_list.empty();
+ sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21));
+ if (sl->table_list.elements)
+ {
+ item= (*func)(expr, new Item_asterisk_remover(this, item,
+ (char *)"<no matter>",
+ (char*)"<result>"));
+ sl->where= and_items(sl->where, item);
+ }
+ else
+ {
+ if (item->type() == Item::FIELD_ITEM &&
+ ((Item_field*) item)->field_name[0] == '*')
+ {
+ my_error(ER_NO_TABLES_USED, MYF(0));
+ DBUG_VOID_RETURN;
+ }
+ if (unit->first_select()->next_select())
+ {
+ /*
+ It is in union => we should perform it.
+ Item_asterisk_remover used only as wrapper to receine NULL value
+ */
+ sl->having= (*func)(expr,
+ new Item_asterisk_remover(this, item,
+ (char *)"<no matter>",
+ (char*)"<result>"));
+ }
+ else
+ {
+ // it is single select without tables => possible optimization
+ item= (*func)(left_expr, item);
+ substitution= item;
+ have_to_be_excluded= 1;
+ if (thd->lex.describe)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_SELECT_REDUCED), sl->select_number);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SELECT_REDUCED, warn_buff);
+ }
+ }
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+void Item_in_subselect::row_value_transformer(THD *thd,
+ st_select_lex_unit *unit,
+ Item *left_expr)
+{
+ DBUG_ENTER("Item_in_subselect::row_value_transformer");
+ if (unit->global_parameters->select_limit !=
+ HA_POS_ERROR)
+ {
+ /*
+ Because we do the following (not exactly, following is just explenation)
+ transformation
+ SELECT * from t1 WHERE t1.a IN (SELECT t2.a FROM t2)
+ ->
+ SELECT * from t1 WHERE EXISTS(SELECT 1 FROM t2 t1.a = t2.a LIMIT 1)
+
+ it's impossible to support limit in the sub select.
+ */
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "LIMIT & IN/ALL/ANY/SOME subquery");
+ DBUG_VOID_RETURN;
+ }
+ // no sense in ORDER BY without LIMIT
+ unit->global_parameters->order_list.empty();
+
+ Item_in_optimizer *optimizer;
+ substitution= optimizer= new Item_in_optimizer(left_expr, this);
+ if (!optimizer)
+ DBUG_VOID_RETURN;
+
+ unit->dependent= 1;
+ uint n= left_expr->cols();
+ if (optimizer->preallocate_row() || (*optimizer->get_cache())->allocate(n))
+ DBUG_VOID_RETURN;
+ for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->select_limit != HA_POS_ERROR)
+ {
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0),
+ "LIMIT & IN/ALL/ANY/SOME subquery");
+ DBUG_VOID_RETURN;
+ }
+ sl->order_list.empty(); // no sense in ORDER BY without LIMIT
+
+ sl->dependent= 1;
+
+ Item *item= 0;
+ List_iterator_fast<Item> li(sl->item_list);
+ for (uint i= 0; i < n; i++)
+ {
+ Item *func=
+ new Item_ref_on_list_position(this, sl, i,
+ (char *) "<no matter>",
+ (char *) "<list ref>");
+ func=
+ Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())->
+ addr(i),
+ (char *)"<no matter>",
+ (char *)"<left expr>"),
+ func);
+ item= and_items(item, func);
+ }
+
+ if (sl->having || sl->with_sum_func || sl->group_list.first ||
+ !sl->table_list.elements)
+ sl->having= and_items(sl->having, item);
+ else
+ sl->where= and_items(sl->where, item);
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+void Item_in_subselect::select_transformer(THD *thd, st_select_lex_unit *unit)
+{
+ if (left_expr->cols() == 1)
+ single_value_transformer(thd, unit, left_expr,
+ &Item_bool_func2::eq_creator);
+ else
+ row_value_transformer(thd, unit, left_expr);
+}
+
+void Item_allany_subselect::select_transformer(THD *thd,
+ st_select_lex_unit *unit)
+{
+ single_value_transformer(thd, unit, left_expr, func);
+}
+
+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();
+ 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();
+ 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(&select_lex->ref_pointer_array,
+ (TABLE_LIST*) select_lex->table_list.first,
+ select_lex->with_wild,
+ select_lex->where,
+ select_lex->order_list.elements +
+ select_lex->group_list.elements,
+ (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, 0);
+}
+
+static Item_result set_row(SELECT_LEX *select_lex, Item * item,
+ Item_cache **row, bool *maybe_null)
+{
+ Item_result res_type= STRING_RESULT;
+ Item *sel_item;
+ List_iterator_fast<Item> li(select_lex->item_list);
+ for (uint i= 0; (sel_item= li++); i++)
+ {
+ item->max_length= sel_item->max_length;
+ res_type= sel_item->result_type();
+ item->decimals= sel_item->decimals;
+ *maybe_null= sel_item->maybe_null;
+ if (row)
+ {
+ if (!(row[i]= Item_cache::get_cache(res_type)))
+ return STRING_RESULT; // we should return something
+ row[i]->set_len_n_dec(sel_item->max_length, sel_item->decimals);
+ }
+ }
+ if (select_lex->item_list.elements > 1)
+ res_type= ROW_RESULT;
+ return res_type;
+}
+
+void subselect_single_select_engine::fix_length_and_dec(Item_cache **row)
+{
+ DBUG_ASSERT(row || select_lex->item_list.elements==1);
+ res_type= set_row(select_lex, item, row, &maybe_null);
+ if (cols() != 1)
+ maybe_null= 0;
+}
+
+void subselect_union_engine::fix_length_and_dec(Item_cache **row)
+{
+ DBUG_ASSERT(row || unit->first_select()->item_list.elements==1);
+
+ if (unit->first_select()->item_list.elements == 1)
+ {
+ 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)
+ mlen= len;
+ if (!sel_item)
+ sel_item= s_item;
+ maybe_null= s_item->maybe_null;
+ }
+ item->max_length= mlen;
+ res_type= sel_item->result_type();
+ item->decimals= sel_item->decimals;
+ if (row)
+ {
+ if (!(row[0]= Item_cache::get_cache(res_type)))
+ return;
+ row[0]->set_len_n_dec(mlen, sel_item->decimals);
+ }
+ }
+ else
+ {
+ SELECT_LEX *sl= unit->first_select();
+ bool fake= 0;
+ res_type= set_row(sl, item, row, &fake);
+ for (sl= sl->next_select(); sl; sl->next_select())
+ {
+ List_iterator_fast<Item> li(sl->item_list);
+ Item *sel_item;
+ for (uint i= 0; (sel_item= li++); i++)
+ {
+ if (sel_item->max_length > row[i]->max_length)
+ row[i]->max_length= sel_item->max_length;
+ }
+ }
+ }
+}
+
+int subselect_single_select_engine::exec()
+{
+ DBUG_ENTER("subselect_single_select_engine::exec");
+ char const *save_where= join->thd->where;
+ if (!optimized)
+ {
+ optimized=1;
+ if (join->optimize())
+ {
+ join->thd->where= save_where;
+ executed= 1;
+ DBUG_RETURN(join->error?join->error:1);
+ }
+ }
+ if ((select_lex->dependent || select_lex->uncacheable) && executed)
+ {
+ if (join->reinit())
+ {
+ join->thd->where= save_where;
+ DBUG_RETURN(1);
+ }
+ item->reset();
+ 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;
+ join->thd->where= save_where;
+ DBUG_RETURN(join->error||thd->is_fatal_error);
+ }
+ join->thd->where= save_where;
+ DBUG_RETURN(0);
+}
+
+int subselect_union_engine::exec()
+{
+ char const *save_where= unit->thd->where;
+ int res= unit->exec();
+ unit->thd->where= save_where;
+ return res;
+}
+
+uint subselect_single_select_engine::cols()
+{
+ return select_lex->item_list.elements;
+}
+
+uint subselect_union_engine::cols()
+{
+ return unit->first_select()->item_list.elements;
+}
+
+bool subselect_single_select_engine::dependent()
+{
+ return select_lex->dependent;
+}
+
+bool subselect_union_engine::dependent()
+{
+ return unit->dependent;
+}
+
+bool subselect_single_select_engine::uncacheable()
+{
+ return select_lex->uncacheable;
+}
+
+bool subselect_union_engine::uncacheable()
+{
+ return unit->uncacheable;
+}
+
+void subselect_single_select_engine::exclude()
+{
+ select_lex->master_unit()->exclude_level();
+}
+
+void subselect_union_engine::exclude()
+{
+ unit->exclude_level();
+}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
new file mode 100644
index 00000000000..351c4af7f33
--- /dev/null
+++ b/sql/item_subselect.h
@@ -0,0 +1,267 @@
+/* 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;
+class Item_bool_func2;
+
+typedef Item_bool_func2* (*compare_func_creator)(Item*, Item*);
+
+/* 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:
+ /* substitution instead of subselect in case of optimization */
+ Item *substitution;
+ /* engine that perform execution of subselect (single select or union) */
+ subselect_engine *engine;
+ /* allowed number of columns (1 for single value subqueries) */
+ uint max_columns;
+ /* work with 'substitution' */
+ bool have_to_be_excluded;
+
+public:
+ Item_subselect();
+ Item_subselect(Item_subselect *item)
+ {
+ substitution= item->substitution;
+ 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.
+ */
+ virtual void init (THD *thd, st_select_lex *select_lex,
+ select_subselect *result);
+
+ ~Item_subselect();
+ virtual void reset()
+ {
+ null_value= 1;
+ }
+ virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
+ bool assigned() { return value_assigned; }
+ void assigned(bool a) { value_assigned= a; }
+ enum Type type() const;
+ bool is_null()
+ {
+ val_int();
+ return null_value;
+ }
+ bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
+ virtual void fix_length_and_dec();
+ table_map used_tables() const;
+
+ friend class select_subselect;
+ friend class Item_in_optimizer;
+};
+
+/* single value subselect */
+
+class Item_cache;
+class Item_singlerow_subselect :public Item_subselect
+{
+protected:
+ Item_cache *value, **row;
+public:
+ Item_singlerow_subselect(THD *thd, st_select_lex *select_lex);
+ Item_singlerow_subselect(Item_singlerow_subselect *item):
+ Item_subselect(item)
+ {
+ value= item->value;
+ max_length= item->max_length;
+ decimals= item->decimals;
+ }
+ void reset();
+ void select_transformer(THD *thd, st_select_lex_unit *unit);
+ void store(uint i, Item* item);
+ double val();
+ longlong val_int ();
+ String *val_str (String *);
+ Item *new_item() { return new Item_singlerow_subselect(this); }
+ enum Item_result result_type() const;
+ void fix_length_and_dec();
+
+ uint cols();
+ Item* el(uint i) { return (Item*)row[i]; }
+ Item** addr(uint i) { return (Item**)row + i; }
+ bool check_cols(uint c);
+ bool null_inside();
+ void bring_value();
+
+ friend class select_singlerow_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;
+ }
+ Item_exists_subselect(): Item_subselect() {}
+
+ void reset()
+ {
+ 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;
+};
+
+/* IN subselect */
+
+class Item_in_subselect :public Item_exists_subselect
+{
+protected:
+ Item * left_expr;
+ bool was_null;
+public:
+ Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
+ Item_in_subselect(Item_in_subselect *item);
+ Item_in_subselect(): Item_exists_subselect() {}
+ void reset()
+ {
+ value= 0;
+ null_value= 0;
+ was_null= 0;
+ }
+ virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
+ void single_value_transformer(THD *thd, st_select_lex_unit *unit,
+ Item *left_expr, compare_func_creator func);
+ void row_value_transformer(THD *thd, st_select_lex_unit *unit,
+ Item *left_expr);
+ longlong val_int();
+ double val();
+ String *val_str(String*);
+
+ friend class Item_asterisk_remover;
+ friend class Item_ref_null_helper;
+};
+
+/* ALL/ANY/SOME subselect */
+class Item_allany_subselect :public Item_in_subselect
+{
+protected:
+ compare_func_creator func;
+
+public:
+ Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f,
+ st_select_lex *select_lex);
+ Item_allany_subselect(Item_allany_subselect *item);
+ virtual void select_transformer(THD *thd, st_select_lex_unit *unit);
+};
+
+class subselect_engine: public Sql_alloc
+{
+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 */
+ bool maybe_null; /* may be null (first item in select) */
+public:
+
+ subselect_engine(THD *thd, Item_subselect *si, select_subselect *res)
+ {
+ result= res;
+ item= si;
+ this->thd= thd;
+ res_type= STRING_RESULT;
+ maybe_null= 0;
+ }
+ virtual ~subselect_engine() {}; // to satisfy compiler
+
+ virtual int prepare()= 0;
+ virtual void fix_length_and_dec(Item_cache** row)= 0;
+ virtual int exec()= 0;
+ virtual uint cols()= 0; /* return number of columnss in select */
+ virtual bool dependent()= 0; /* depended from outer select */
+ virtual bool uncacheable()= 0; /* query is uncacheable */
+ enum Item_result type() { return res_type; }
+ virtual void exclude()= 0;
+ bool may_be_null() { return maybe_null; };
+};
+
+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(Item_cache** row);
+ int exec();
+ uint cols();
+ bool dependent();
+ bool uncacheable();
+ void exclude();
+};
+
+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(Item_cache** row);
+ int exec();
+ uint cols();
+ bool dependent();
+ bool uncacheable();
+ void exclude();
+};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index b6bbc12efd6..e303c26262e 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -23,7 +23,6 @@
#include "mysql_priv.h"
-
Item_sum::Item_sum(List<Item> &list)
{
arg_count=list.elements;
@@ -38,32 +37,45 @@ Item_sum::Item_sum(List<Item> &list)
args[i++]= item;
}
}
- with_sum_func=1;
+ mark_as_sum_func();
list.empty(); // Fields are used
}
+// Constructor used in processing select with temporary tebles
+Item_sum::Item_sum(THD *thd, Item_sum &item):
+ Item_result_field(thd, item), quick_group(item.quick_group)
+{
+ arg_count= item.arg_count;
+ if (arg_count <= 2)
+ args=tmp_args;
+ else
+ if (!(args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
+ return;
+ for (uint i= 0; i < arg_count; i++)
+ args[i]= item.args[i];
+}
+
+void Item_sum::mark_as_sum_func()
+{
+ current_thd->lex.current_select->with_sum_func++;
+ with_sum_func= 1;
+}
+
void Item_sum::make_field(Send_field *tmp_field)
{
if (args[0]->type() == Item::FIELD_ITEM && keep_field_type())
- ((Item_field*) args[0])->field->make_field(tmp_field);
- else
{
- tmp_field->flags=0;
- if (!maybe_null)
- tmp_field->flags|= NOT_NULL_FLAG;
- if (unsigned_flag)
- tmp_field->flags |= UNSIGNED_FLAG;
- tmp_field->length=max_length;
- tmp_field->decimals=decimals;
- tmp_field->type=(result_type() == INT_RESULT ? FIELD_TYPE_LONG :
- result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE :
- FIELD_TYPE_VAR_STRING);
+ ((Item_field*) args[0])->field->make_field(tmp_field);
+ tmp_field->db_name=(char*)"";
+ tmp_field->org_table_name=tmp_field->table_name=(char*)"";
+ tmp_field->org_col_name=tmp_field->col_name=name;
}
- tmp_field->table_name=(char*)"";
- tmp_field->col_name=name;
+ else
+ init_make_field(tmp_field, field_type());
}
+
void Item_sum::print(String *str)
{
str->append(func_name());
@@ -85,6 +97,26 @@ void Item_sum::fix_num_length_and_dec()
max_length=float_length(decimals);
}
+Item *Item_sum::get_tmp_table_item(THD *thd)
+{
+ Item_sum* sum_item= (Item_sum *) copy_or_same(thd);
+ if (sum_item && sum_item->result_field) // If not a const sum func
+ {
+ Field *result_field= sum_item->result_field;
+ for (uint i=0 ; i < sum_item->arg_count ; i++)
+ {
+ Item *arg= sum_item->args[i];
+ if (!arg->const_item())
+ {
+ if (arg->type() == Item::FIELD_ITEM)
+ ((Item_field*) arg)->field= result_field++;
+ else
+ sum_item->args[i]= new Item_field(result_field++);
+ }
+ }
+ }
+ return sum_item;
+}
String *
Item_sum_num::val_str(String *str)
@@ -92,7 +124,7 @@ Item_sum_num::val_str(String *str)
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals);
+ str->set(nr,decimals,default_charset());
return str;
}
@@ -103,15 +135,13 @@ Item_sum_int::val_str(String *str)
longlong nr=val_int();
if (null_value)
return 0;
- char buff[21];
- uint length= (uint) (longlong10_to_str(nr,buff,-10)-buff);
- str->copy(buff,length);
+ str->set(nr,default_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 +153,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) || args[i]->check_cols(1))
return 1;
if (decimals < args[i]->decimals)
decimals=args[i]->decimals;
@@ -134,12 +164,13 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables)
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
+ fixed= 1;
return 0;
}
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,23 +179,36 @@ 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) || item->check_cols(1))
return 1;
hybrid_type=item->result_type();
if (hybrid_type == INT_RESULT)
+ {
+ cmp_charset= &my_charset_bin;
max_length=20;
+ }
else if (hybrid_type == REAL_RESULT)
+ {
+ cmp_charset= &my_charset_bin;
max_length=float_length(decimals);
- else
+ }else
+ {
+ cmp_charset= item->charset();
max_length=item->max_length;
+ }
decimals=item->decimals;
maybe_null=item->maybe_null;
- binary=item->binary;
unsigned_flag=item->unsigned_flag;
+ set_charset(item->charset());
result_field=0;
null_value=1;
fix_length_and_dec();
thd->allow_sum_func=1; // Allow group functions
+ if (item->type() == Item::FIELD_ITEM)
+ hybrid_field_type= ((Item_field*) item)->field->type();
+ else
+ hybrid_field_type= Item::field_type();
+ fixed= 1;
return 0;
}
@@ -249,12 +293,24 @@ double Item_sum_avg::val()
** Standard deviation
*/
-void Item_sum_std::reset()
+double Item_sum_std::val()
{
- sum=sum_sqr=0.0; count=0; (void) Item_sum_std::add();
+ double tmp= Item_sum_variance::val();
+ return tmp <= 0.0 ? 0.0 : sqrt(tmp);
}
-bool Item_sum_std::add()
+/*
+** variance
+*/
+
+void Item_sum_variance::reset()
+{
+ sum=sum_sqr=0.0;
+ count=0;
+ (void) Item_sum_variance::add();
+}
+
+bool Item_sum_variance::add()
{
double nr=args[0]->val();
if (!args[0]->null_value)
@@ -266,7 +322,7 @@ bool Item_sum_std::add()
return 0;
}
-double Item_sum_std::val()
+double Item_sum_variance::val()
{
if (!count)
{
@@ -277,11 +333,10 @@ double Item_sum_std::val()
/* Avoid problems when the precision isn't good enough */
double tmp=ulonglong2double(count);
double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
- return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2);
+ return tmp2 <= 0.0 ? 0.0 : tmp2;
}
-
-void Item_sum_std::reset_field()
+void Item_sum_variance::reset_field()
{
double nr=args[0]->val();
char *res=result_field->ptr;
@@ -298,7 +353,7 @@ void Item_sum_std::reset_field()
}
}
-void Item_sum_std::update_field(int offset)
+void Item_sum_variance::update_field(int offset)
{
double nr,old_nr,old_sqr;
longlong field_count;
@@ -324,18 +379,25 @@ void Item_sum_std::update_field(int offset)
double Item_sum_hybrid::val()
{
+ int err;
if (null_value)
return 0.0;
switch (hybrid_type) {
case STRING_RESULT:
String *res; res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return (res ? my_strntod(res->charset(), (char*) res->ptr(),res->length(),
+ (char**) 0, &err) : 0.0);
case INT_RESULT:
if (unsigned_flag)
return ulonglong2double(sum_int);
return (double) sum_int;
case REAL_RESULT:
return sum;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
return 0; // Keep compiler happy
}
@@ -359,13 +421,18 @@ Item_sum_hybrid::val_str(String *str)
case STRING_RESULT:
return &value;
case REAL_RESULT:
- str->set(sum,decimals);
+ str->set(sum,decimals,default_charset());
break;
case INT_RESULT:
if (unsigned_flag)
- str->set((ulonglong) sum_int);
+ str->set((ulonglong) sum_int,default_charset());
else
- str->set((longlong) sum_int);
+ str->set((longlong) sum_int,default_charset());
+ break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
break;
}
return str; // Keep compiler happy
@@ -378,8 +445,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))
+ (null_value || sortcmp(&value,result,cmp_charset) > 0))
{
value.copy(*result);
null_value=0;
@@ -409,6 +475,11 @@ bool Item_sum_min::add()
}
}
break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
return 0;
}
@@ -421,8 +492,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))
+ (null_value || sortcmp(&value,result,cmp_charset) < 0))
{
value.copy(*result);
null_value=0;
@@ -452,6 +522,11 @@ bool Item_sum_max::add()
}
}
break;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ break;
}
return 0;
}
@@ -513,7 +588,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),result_field->charset()),*res;
res=args[0]->val_str(&tmp);
if (args[0]->null_value)
@@ -524,7 +599,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 +767,8 @@ 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) :
- sortcmp(res_str,&tmp_value)) < 0))
- result_field->store(res_str->ptr(),res_str->length());
+ (cmp_sign * sortcmp(res_str,&tmp_value,cmp_charset)) < 0)
+ result_field->store(res_str->ptr(),res_str->length(),res_str->charset());
else
{ // Use old value
char *res=result_field->ptr;
@@ -810,11 +884,22 @@ 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,default_charset());
return str;
}
Item_std_field::Item_std_field(Item_sum_std *item)
+ : Item_variance_field(item)
+{
+}
+
+double Item_std_field::val()
+{
+ double tmp= Item_variance_field::val();
+ return tmp <= 0.0 ? 0.0 : sqrt(tmp);
+}
+
+Item_variance_field::Item_variance_field(Item_sum_variance *item)
{
name=item->name;
decimals=item->decimals;
@@ -823,7 +908,7 @@ Item_std_field::Item_std_field(Item_sum_std *item)
maybe_null=1;
}
-double Item_std_field::val()
+double Item_variance_field::val()
{
double sum,sum_sqr;
longlong count;
@@ -839,15 +924,15 @@ double Item_std_field::val()
null_value=0;
double tmp= (double) count;
double tmp2=(sum_sqr - sum*sum/tmp)/tmp;
- return tmp2 <= 0.0 ? 0.0 : sqrt(tmp2);
+ return tmp2 <= 0.0 ? 0.0 : tmp2;
}
-String *Item_std_field::val_str(String *str)
+String *Item_variance_field::val_str(String *str)
{
double nr=val();
if (null_value)
return 0;
- str->set(nr,decimals);
+ str->set(nr,decimals,default_charset());
return str;
}
@@ -857,14 +942,17 @@ String *Item_std_field::val_str(String *str)
#include "sql_select.h"
-static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
+int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
{
return memcmp(key1, key2, *(uint*) arg);
}
-static int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
+int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
- return my_sortcmp((char*) key1, (char*) key2, *(uint*) arg);
+ Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
+ CHARSET_INFO *cs=item->key_charset;
+ uint len=item->key_length;
+ return my_strnncoll(cs, (const uchar*) key1, len, (const uchar*) key2, len);
}
/*
@@ -907,7 +995,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
The first item->rec_offset bytes are taken care of with
restore_record(table,2) in setup()
*/
- memcpy(buf + item->rec_offset, key, item->tree.size_of_element);
+ memcpy(buf + item->rec_offset, key, item->tree->size_of_element);
if ((error = item->table->file->write_row(buf)))
{
if (error != HA_ERR_FOUND_DUPP_KEY &&
@@ -920,16 +1008,24 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
Item_sum_count_distinct::~Item_sum_count_distinct()
{
- if (table)
- free_tmp_table(current_thd, table);
- delete tmp_table_param;
- if (use_tree)
- delete_tree(&tree);
+ /*
+ Free table and tree if they belong to this item (if item have not pointer
+ to original item from which was made copy => it own its objects )
+ */
+ if (!original)
+ {
+ if (table)
+ free_tmp_table(current_thd, table);
+ delete tmp_table_param;
+ if (use_tree)
+ delete_tree(tree);
+ }
}
-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;
@@ -938,6 +1034,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++)
{
@@ -959,9 +1059,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,
+ select_lex->options | thd->options,
+ HA_POS_ERROR)))
return 1;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
@@ -987,14 +1088,22 @@ bool Item_sum_count_distinct::setup(THD *thd)
Field* field = table->field[0];
switch(field->type())
{
- /*
- If we have a string, we must take care of charsets and case
- sensitivity
- */
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
- compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
- simple_str_key_cmp);
+ if (field->binary())
+ {
+ compare_key = (qsort_cmp2)simple_raw_key_cmp;
+ cmp_arg = (void*) &key_length;
+ }
+ else
+ {
+ /*
+ If we have a string, we must take care of charsets and case
+ sensitivity
+ */
+ compare_key = (qsort_cmp2)simple_str_key_cmp;
+ cmp_arg = (void*) this;
+ }
break;
default:
/*
@@ -1002,11 +1111,12 @@ bool Item_sum_count_distinct::setup(THD *thd)
be compared with memcmp
*/
compare_key = (qsort_cmp2)simple_raw_key_cmp;
+ cmp_arg = (void*) &key_length;
break;
}
- key_length = field->pack_length();
- cmp_arg = (void*) &key_length;
- rec_offset = 1;
+ key_charset = field->charset();
+ key_length = field->pack_length();
+ rec_offset = 1;
}
else // too bad, cannot cheat - there is more than one field
{
@@ -1039,8 +1149,8 @@ bool Item_sum_count_distinct::setup(THD *thd)
}
}
- init_tree(&tree, min(thd->variables.max_heap_table_size,
- thd->variables.sortbuff_size/16), 0,
+ init_tree(tree, min(thd->variables.max_heap_table_size,
+ thd->variables.sortbuff_size/16), 0,
key_length, compare_key, 0, NULL, cmp_arg);
use_tree = 1;
@@ -1052,6 +1162,12 @@ bool Item_sum_count_distinct::setup(THD *thd)
*/
max_elements_in_tree = ((key_length) ?
thd->variables.max_heap_table_size/key_length : 1);
+
+ }
+ if (original)
+ {
+ original->table= table;
+ original->use_tree= use_tree;
}
return 0;
}
@@ -1059,12 +1175,12 @@ bool Item_sum_count_distinct::setup(THD *thd)
int Item_sum_count_distinct::tree_to_myisam()
{
- if (create_myisam_from_heap(table, tmp_table_param,
+ if (create_myisam_from_heap(current_thd, table, tmp_table_param,
HA_ERR_RECORD_FILE_FULL, 1) ||
- tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
+ tree_walk(tree, (tree_walk_action)&dump_leaf, (void*)this,
left_root_right))
return 1;
- delete_tree(&tree);
+ delete_tree(tree);
use_tree = 0;
return 0;
}
@@ -1072,7 +1188,7 @@ int Item_sum_count_distinct::tree_to_myisam()
void Item_sum_count_distinct::reset()
{
if (use_tree)
- reset_tree(&tree);
+ reset_tree(tree);
else if (table)
{
table->file->extra(HA_EXTRA_NO_CACHE);
@@ -1100,12 +1216,13 @@ bool Item_sum_count_distinct::add()
If the tree got too big, convert to MyISAM, otherwise insert into the
tree.
*/
- if (tree.elements_in_tree > max_elements_in_tree)
+ if (tree->elements_in_tree > max_elements_in_tree)
{
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])))
@@ -1113,19 +1230,21 @@ bool Item_sum_count_distinct::add()
if (error != HA_ERR_FOUND_DUPP_KEY &&
error != HA_ERR_FOUND_DUPP_UNIQUE)
{
- if (create_myisam_from_heap(table, tmp_table_param, error,1))
+ if (create_myisam_from_heap(current_thd, table, tmp_table_param, error,
+ 1))
return 1; // Not a table_is_full error
}
}
return 0;
}
+
longlong Item_sum_count_distinct::val_int()
{
if (!table) // Empty query
return LL(0);
if (use_tree)
- return tree.elements_in_tree;
+ return tree->elements_in_tree;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
return table->file->records;
}
@@ -1167,7 +1286,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,default_charset());
return str;
}
@@ -1186,7 +1305,7 @@ String *Item_sum_udf_int::val_str(String *str)
if (null_value)
return 0;
else
- str->set(nr);
+ str->set(nr,default_charset());
return str;
}
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 29ac1f1d1b1..74c7b11a7ba 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -27,30 +27,37 @@ class Item_sum :public Item_result_field
{
public:
enum Sumfunctype {COUNT_FUNC,COUNT_DISTINCT_FUNC,SUM_FUNC,AVG_FUNC,MIN_FUNC,
- MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,SUM_BIT_FUNC,
+ MAX_FUNC, UNIQUE_USERS_FUNC,STD_FUNC,VARIANCE_FUNC,SUM_BIT_FUNC,
UDF_SUM_FUNC };
Item **args,*tmp_args[2];
uint arg_count;
bool quick_group; /* If incremental update of fields */
- Item_sum() : arg_count(0),quick_group(1) { with_sum_func=1; }
+ void mark_as_sum_func();
+ Item_sum() : arg_count(0),quick_group(1)
+ {
+ mark_as_sum_func();
+ }
Item_sum(Item *a) :quick_group(1)
{
arg_count=1;
args=tmp_args;
args[0]=a;
- with_sum_func = 1;
+ mark_as_sum_func();
}
Item_sum( Item *a, Item *b ) :quick_group(1)
{
arg_count=2;
args=tmp_args;
args[0]=a; args[1]=b;
- with_sum_func=1;
+ mark_as_sum_func();
}
Item_sum(List<Item> &list);
+ //Copy constructor, need to perform subselects with temporary tables
+ Item_sum(THD *thd, Item_sum &item);
~Item_sum() { result_field=0; }
+
enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0;
virtual void reset()=0;
@@ -71,7 +78,7 @@ public:
void fix_num_length_and_dec();
void no_rows_in_result() { reset(); }
virtual bool setup(THD *thd) {return 0;}
- unsigned int size_of() { return sizeof(*this);}
+ Item *get_tmp_table_item(THD *thd);
};
@@ -82,11 +89,11 @@ 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 *);
+ Item_sum_num(THD *thd, Item_sum_num &item) :Item_sum(thd, item) {}
+ 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);}
};
@@ -98,10 +105,10 @@ class Item_sum_int :public Item_sum_num
public:
Item_sum_int(Item *item_par) :Item_sum_num(item_par) {}
Item_sum_int(List<Item> &list) :Item_sum_num(list) {}
+ Item_sum_int(THD *thd, Item_sum_int &item) :Item_sum_num(thd, item) {}
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);}
};
@@ -112,6 +119,8 @@ class Item_sum_sum :public Item_sum_num
public:
Item_sum_sum(Item *item_par) :Item_sum_num(item_par),sum(0.0) {}
+ Item_sum_sum(THD *thd, Item_sum_sum &item)
+ :Item_sum_num(thd, item), sum(item.sum) {}
enum Sumfunctype sum_func () const {return SUM_FUNC;}
void reset();
bool add();
@@ -119,7 +128,7 @@ 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);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_sum(thd, *this); }
};
@@ -132,6 +141,10 @@ class Item_sum_count :public Item_sum_int
Item_sum_count(Item *item_par)
:Item_sum_int(item_par),count(0),used_table_cache(~(table_map) 0)
{}
+ Item_sum_count(THD *thd, Item_sum_count &item)
+ :Item_sum_int(thd, item), count(item.count),
+ used_table_cache(item.used_table_cache)
+ {}
table_map used_tables() const { return used_table_cache; }
bool const_item() const { return !used_table_cache; }
enum Sumfunctype sum_func () const { return COUNT_FUNC; }
@@ -143,7 +156,7 @@ 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);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_count(thd, *this); }
};
@@ -153,12 +166,20 @@ 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;
- uint key_length;
+ TREE tree_base;
+ TREE *tree;
+ /*
+ Following is 0 normal object and pointer to original one for copy
+ (to correctly free resources)
+ */
+ Item_sum_count_distinct *original;
+ uint key_length;
+ CHARSET_INFO *key_charset;
+
// calculated based on max_heap_table_size. If reached,
// walk the tree and dump it into MyISAM table
uint max_elements_in_tree;
@@ -177,14 +198,26 @@ class Item_sum_count_distinct :public Item_sum_int
int tree_to_myisam();
friend int composite_key_cmp(void* arg, byte* key1, byte* key2);
+ friend int simple_str_key_cmp(void* arg, byte* key1, byte* key2);
+ friend int simple_raw_key_cmp(void* arg, byte* key1, byte* key2);
friend int dump_leaf(byte* key, uint32 count __attribute__((unused)),
Item_sum_count_distinct* item);
public:
Item_sum_count_distinct(List<Item> &list)
- :Item_sum_int(list),table(0),used_table_cache(~(table_map) 0),
- tmp_table_param(0),use_tree(0),always_null(0)
- { quick_group=0; }
+ :Item_sum_int(list), table(0), used_table_cache(~(table_map) 0),
+ tmp_table_param(0), tree(&tree_base), original(0), use_tree(0),
+ always_null(0)
+ { quick_group= 0; }
+ Item_sum_count_distinct(THD *thd, Item_sum_count_distinct &item)
+ :Item_sum_int(thd, item), table(item.table),
+ used_table_cache(item.used_table_cache),
+ field_lengths(item.field_lengths), tmp_table_param(item.tmp_table_param),
+ tree(item.tree), original(&item), key_length(item.key_length),
+ max_elements_in_tree(item.max_elements_in_tree),
+ rec_offset(item.rec_offset), use_tree(item.use_tree),
+ always_null(item.always_null)
+ {}
~Item_sum_count_distinct();
table_map used_tables() const { return used_table_cache; }
@@ -196,8 +229,11 @@ 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);
+ Item *copy_or_same(THD* thd)
+ {
+ return new Item_sum_count_distinct(thd, *this);
+ }
void no_rows_in_result() {}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -215,9 +251,8 @@ public:
longlong val_int() { return (longlong) val(); }
bool is_null() { (void) val_int(); return null_value; }
String *val_str(String*);
- void make_field(Send_field *field);
+ enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
void fix_length_and_dec() {}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -230,6 +265,8 @@ class Item_sum_avg :public Item_sum_num
public:
Item_sum_avg(Item *item_par) :Item_sum_num(item_par),count(0) {}
+ Item_sum_avg(THD *thd, Item_sum_avg &item)
+ :Item_sum_num(thd, item), sum(item.sum), count(item.count) {}
enum Sumfunctype sum_func () const {return AVG_FUNC;}
void reset();
bool add();
@@ -239,47 +276,86 @@ 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);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_avg(thd, *this); }
};
-class Item_sum_std;
+class Item_sum_variance;
-class Item_std_field :public Item_result_field
+class Item_variance_field :public Item_result_field
{
public:
Field *field;
- Item_std_field(Item_sum_std *item);
- enum Type type() const { return FIELD_STD_ITEM; }
+ Item_variance_field(Item_sum_variance *item);
+ enum Type type() const {return FIELD_VARIANCE_ITEM; }
double val();
longlong val_int() { return (longlong) val(); }
String *val_str(String*);
bool is_null() { (void) val_int(); return null_value; }
- void make_field(Send_field *field);
+ enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
void fix_length_and_dec() {}
- unsigned int size_of() { return sizeof(*this);}
};
-class Item_sum_std :public Item_sum_num
+/*
+
+variance(a) =
+
+= sum (ai - avg(a))^2 / count(a) )
+= sum (ai^2 - 2*ai*avg(a) + avg(a)^2) / count(a)
+= (sum(ai^2) - sum(2*ai*avg(a)) + sum(avg(a)^2))/count(a) =
+= (sum(ai^2) - 2*avg(a)*sum(a) + count(a)*avg(a)^2)/count(a) =
+= (sum(ai^2) - 2*sum(a)*sum(a)/count(a) + count(a)*sum(a)^2/count(a)^2 )/count(a) =
+= (sum(ai^2) - 2*sum(a)^2/count(a) + sum(a)^2/count(a) )/count(a) =
+= (sum(ai^2) - sum(a)^2/count(a))/count(a)
+
+*/
+
+class Item_sum_variance : public Item_sum_num
{
- double sum;
- double sum_sqr;
+ double sum, sum_sqr;
ulonglong count;
void fix_length_and_dec() { decimals+=4; maybe_null=1; }
public:
- Item_sum_std(Item *item_par) :Item_sum_num(item_par),count(0) {}
- enum Sumfunctype sum_func () const { return STD_FUNC; }
+ Item_sum_variance(Item *item_par) :Item_sum_num(item_par),count(0) {}
+ Item_sum_variance(THD *thd, Item_sum_variance &item):
+ Item_sum_num(thd, item), sum(item.sum), sum_sqr(item.sum_sqr),
+ count(item.count) {}
+ enum Sumfunctype sum_func () const { return VARIANCE_FUNC; }
void reset();
bool add();
double val();
void reset_field();
void update_field(int offset);
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);}
+ { return new Item_variance_field(this); }
+ const char *func_name() const { return "variance"; }
+ Item *copy_or_same(THD* thd) { return new Item_sum_variance(thd, *this); }
+};
+
+class Item_sum_std;
+
+class Item_std_field :public Item_variance_field
+{
+public:
+ Item_std_field(Item_sum_std *item);
+ enum Type type() const { return FIELD_STD_ITEM; }
+ double val();
};
+/*
+ standard_deviation(a) = sqrt(variance(a))
+*/
+
+class Item_sum_std :public Item_sum_variance
+{
+ public:
+ Item_sum_std(Item *item_par) :Item_sum_variance(item_par){}
+ enum Sumfunctype sum_func () const { return STD_FUNC; }
+ double val();
+ Item *result_item(Field *field)
+ { return new Item_std_field(this); }
+ const char *func_name() const { return "std"; }
+};
// This class is a string or number function depending on num_func
@@ -290,14 +366,23 @@ class Item_sum_hybrid :public Item_sum
double sum;
longlong sum_int;
Item_result hybrid_type;
+ enum_field_types hybrid_field_type;
int cmp_sign;
table_map used_table_cache;
+ CHARSET_INFO *cmp_charset;
public:
- Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par),cmp_sign(sign),
- used_table_cache(~(table_map) 0)
+ Item_sum_hybrid(Item *item_par,int sign)
+ :Item_sum(item_par), hybrid_type(INT_RESULT), cmp_sign(sign),
+ used_table_cache(~(table_map) 0),
+ cmp_charset(&my_charset_bin)
{}
- bool fix_fields(THD *,struct st_table_list *);
+ Item_sum_hybrid(THD *thd, Item_sum_hybrid &item):
+ Item_sum(thd, item), value(item.value), tmp_value(item.tmp_value),
+ sum(item.sum), sum_int(item.sum_int), hybrid_type(item.hybrid_type),
+ cmp_sign(item.cmp_sign), used_table_cache(used_table_cache),
+ cmp_charset(item.cmp_charset) {}
+ 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,11 +401,11 @@ class Item_sum_hybrid :public Item_sum
void make_const() { used_table_cache=0; }
bool keep_field_type(void) const { return 1; }
enum Item_result result_type () const { return hybrid_type; }
+ enum enum_field_types field_type() const { return hybrid_field_type; }
void update_field(int offset);
void min_max_update_str_field(int offset);
void min_max_update_real_field(int offset);
void min_max_update_int_field(int offset);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -328,11 +413,12 @@ class Item_sum_min :public Item_sum_hybrid
{
public:
Item_sum_min(Item *item_par) :Item_sum_hybrid(item_par,1) {}
+ Item_sum_min(THD *thd, Item_sum_min &item) :Item_sum_hybrid(thd, item) {}
enum Sumfunctype sum_func () const {return MIN_FUNC;}
bool add();
const char *func_name() const { return "min"; }
- unsigned int size_of() { return sizeof(*this);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_min(thd, *this); }
};
@@ -340,11 +426,12 @@ class Item_sum_max :public Item_sum_hybrid
{
public:
Item_sum_max(Item *item_par) :Item_sum_hybrid(item_par,-1) {}
+ Item_sum_max(THD *thd, Item_sum_max &item) :Item_sum_hybrid(thd, item) {}
enum Sumfunctype sum_func () const {return MAX_FUNC;}
bool add();
const char *func_name() const { return "max"; }
- unsigned int size_of() { return sizeof(*this);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_max(thd, *this); }
};
@@ -356,11 +443,12 @@ class Item_sum_bit :public Item_sum_int
public:
Item_sum_bit(Item *item_par,ulonglong reset_arg)
:Item_sum_int(item_par),reset_bits(reset_arg),bits(reset_arg) {}
+ Item_sum_bit(THD *thd, Item_sum_bit &item):
+ Item_sum_int(thd, item), reset_bits(item.reset_bits), bits(item.bits) {}
enum Sumfunctype sum_func () const {return SUM_BIT_FUNC;}
void reset();
longlong val_int();
void reset_field();
- unsigned int size_of() { return sizeof(*this);}
};
@@ -368,10 +456,11 @@ class Item_sum_or :public Item_sum_bit
{
public:
Item_sum_or(Item *item_par) :Item_sum_bit(item_par,LL(0)) {}
+ Item_sum_or(THD *thd, Item_sum_or &item) :Item_sum_bit(thd, item) {}
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_or"; }
- unsigned int size_of() { return sizeof(*this);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_or(thd, *this); }
};
@@ -379,10 +468,11 @@ class Item_sum_and :public Item_sum_bit
{
public:
Item_sum_and(Item *item_par) :Item_sum_bit(item_par, ~(ulonglong) LL(0)) {}
+ Item_sum_and(THD *thd, Item_sum_and &item) :Item_sum_bit(thd, item) {}
bool add();
void update_field(int offset);
const char *func_name() const { return "bit_and"; }
- unsigned int size_of() { return sizeof(*this);}
+ Item *copy_or_same(THD* thd) { return new Item_sum_and(thd, *this); }
};
/*
@@ -400,10 +490,13 @@ public:
Item_udf_sum( udf_func *udf_arg, List<Item> &list )
:Item_sum( list ), udf(udf_arg)
{ quick_group=0;}
+ Item_udf_sum(THD *thd, Item_udf_sum &item)
+ :Item_sum(thd, item), udf(item.udf) {}
~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)
{
+ fixed= 1;
return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
@@ -413,7 +506,6 @@ public:
bool add();
void reset_field() {};
void update_field(int offset_arg) {};
- unsigned int size_of() { return sizeof(*this);}
};
@@ -423,11 +515,14 @@ class Item_sum_udf_float :public Item_udf_sum
Item_sum_udf_float(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
Item_sum_udf_float(udf_func *udf_arg, List<Item> &list)
:Item_udf_sum(udf_arg,list) {}
+ Item_sum_udf_float(THD *thd, Item_sum_udf_float &item)
+ :Item_udf_sum(thd, item) {}
~Item_sum_udf_float() {}
longlong val_int() { return (longlong) Item_sum_udf_float::val(); }
double val();
String *val_str(String*str);
void fix_length_and_dec() { fix_num_length_and_dec(); }
+ Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); }
};
@@ -437,12 +532,15 @@ public:
Item_sum_udf_int(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
Item_sum_udf_int(udf_func *udf_arg, List<Item> &list)
:Item_udf_sum(udf_arg,list) {}
+ Item_sum_udf_int(THD *thd, Item_sum_udf_int &item)
+ :Item_udf_sum(thd, item) {}
~Item_sum_udf_int() {}
longlong val_int();
double val() { return (double) Item_sum_udf_int::val_int(); }
String *val_str(String*str);
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() { decimals=0; max_length=21; }
+ Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); }
};
@@ -452,20 +550,26 @@ public:
Item_sum_udf_str(udf_func *udf_arg) :Item_udf_sum(udf_arg) {}
Item_sum_udf_str(udf_func *udf_arg, List<Item> &list)
:Item_udf_sum(udf_arg,list) {}
+ Item_sum_udf_str(THD *thd, Item_sum_udf_str &item)
+ :Item_udf_sum(thd, item) {}
~Item_sum_udf_str() {}
String *val_str(String *);
double val()
{
+ int err;
String *res; res=val_str(&str_value);
- return res ? atof(res->c_ptr()) : 0.0;
+ return res ? my_strntod(res->charset(),(char*) res->ptr(),res->length(),
+ (char**) 0, &err) : 0.0;
}
longlong val_int()
{
+ int err;
String *res; res=val_str(&str_value);
- return res ? strtoll(res->c_ptr(),(char**) 0,10) : (longlong) 0;
+ return res ? my_strntoll(res->charset(),res->ptr(),res->length(),10, (char**) 0, &err) : (longlong) 0;
}
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec();
+ Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); }
};
#else /* Dummy functions to get sql_yacc.cc compiled */
@@ -475,12 +579,15 @@ class Item_sum_udf_float :public Item_sum_num
public:
Item_sum_udf_float(udf_func *udf_arg) :Item_sum_num() {}
Item_sum_udf_float(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ Item_sum_udf_float(THD *thd, Item_sum_udf_float &item)
+ :Item_sum_num(thd, item) {}
~Item_sum_udf_float() {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
double val() { return 0.0; }
void reset() {}
bool add() { return 0; }
void update_field(int offset) {}
+ Item *copy_or_same(THD* thd) { return new Item_sum_udf_float(thd, *this); }
};
@@ -489,6 +596,8 @@ class Item_sum_udf_int :public Item_sum_num
public:
Item_sum_udf_int(udf_func *udf_arg) :Item_sum_num() {}
Item_sum_udf_int(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ Item_sum_udf_int(THD *thd, Item_sum_udf_int &item)
+ :Item_sum_num(thd, item) {}
~Item_sum_udf_int() {}
enum Sumfunctype sum_func () const { return UDF_SUM_FUNC; }
longlong val_int() { return 0; }
@@ -496,6 +605,7 @@ public:
void reset() {}
bool add() { return 0; }
void update_field(int offset) {}
+ Item *copy_or_same(THD* thd) { return new Item_sum_udf_int(thd, *this); }
};
@@ -504,6 +614,8 @@ class Item_sum_udf_str :public Item_sum_num
public:
Item_sum_udf_str(udf_func *udf_arg) :Item_sum_num() {}
Item_sum_udf_str(udf_func *udf_arg, List<Item> &list) :Item_sum_num() {}
+ Item_sum_udf_str(THD *thd, Item_sum_udf_str &item)
+ :Item_sum_num(thd, item) {}
~Item_sum_udf_str() {}
String *val_str(String *) { null_value=1; return 0; }
double val() { null_value=1; return 0.0; }
@@ -514,6 +626,7 @@ public:
void reset() {}
bool add() { return 0; }
void update_field(int offset) {}
+ Item *copy_or_same(THD* thd) { return new Item_sum_udf_str(thd, *this); }
};
#endif /* HAVE_DLOPEN */
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 6a95c15a226..997247b6141 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.
@@ -44,21 +64,21 @@ static String day_names[] = { "Monday", "Tuesday", "Wednesday",
** DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
*/
-bool get_interval_info(const char *str,uint length,uint count,
- long *values)
+bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
+ uint count, long *values)
{
const char *end=str+length;
uint i;
- while (str != end && !isdigit(*str))
+ while (str != end && !my_isdigit(cs,*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(cs,*str) ; str++)
value=value*10L + (long) (*str - '0');
values[i]= value;
- while (str != end && !isdigit(*str))
+ while (str != end && !my_isdigit(cs,*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(), default_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(), default_charset());
+ return str;
}
@@ -269,8 +295,8 @@ longlong Item_func_time_to_sec::val_int()
/*
-** Convert a string to a interval value
-** To make code easy, allow interval objects without separators.
+ Convert a string to a interval value
+ To make code easy, allow interval objects without separators.
*/
static bool get_interval_value(Item *args,interval_type int_type,
@@ -280,6 +306,7 @@ static bool get_interval_value(Item *args,interval_type int_type,
const char *str;
uint32 length;
LINT_INIT(value); LINT_INIT(str); LINT_INIT(length);
+ CHARSET_INFO *cs=str_value->charset();
bzero((char*) t,sizeof(*t));
if ((int) int_type <= INTERVAL_SECOND)
@@ -302,7 +329,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(cs,*str))
str++;
if (str != end && *str == '-')
{
@@ -332,26 +359,26 @@ static bool get_interval_value(Item *args,interval_type int_type,
t->second=value;
break;
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
- if (get_interval_info(str,length,2,array))
+ if (get_interval_info(str,length,cs,2,array))
return (1);
t->year=array[0];
t->month=array[1];
break;
case INTERVAL_DAY_HOUR:
- if (get_interval_info(str,length,2,array))
+ if (get_interval_info(str,length,cs,2,array))
return (1);
t->day=array[0];
t->hour=array[1];
break;
case INTERVAL_DAY_MINUTE:
- if (get_interval_info(str,length,3,array))
+ if (get_interval_info(str,length,cs,3,array))
return (1);
t->day=array[0];
t->hour=array[1];
t->minute=array[2];
break;
case INTERVAL_DAY_SECOND:
- if (get_interval_info(str,length,4,array))
+ if (get_interval_info(str,length,cs,4,array))
return (1);
t->day=array[0];
t->hour=array[1];
@@ -359,20 +386,20 @@ static bool get_interval_value(Item *args,interval_type int_type,
t->second=array[3];
break;
case INTERVAL_HOUR_MINUTE:
- if (get_interval_info(str,length,2,array))
+ if (get_interval_info(str,length,cs,2,array))
return (1);
t->hour=array[0];
t->minute=array[1];
break;
case INTERVAL_HOUR_SECOND:
- if (get_interval_info(str,length,3,array))
+ if (get_interval_info(str,length,cs,3,array))
return (1);
t->hour=array[0];
t->minute=array[1];
t->second=array[2];
break;
case INTERVAL_MINUTE_SECOND:
- if (get_interval_info(str,length,2,array))
+ if (get_interval_info(str,length,cs,2,array))
return (1);
t->minute=array[0];
t->second=array[1];
@@ -389,21 +416,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,default_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,default_charset());
return str;
}
-bool Item_date::save_in_field(Field *field, bool no_conversions)
+int Item_date::save_in_field(Field *field, bool no_conversions)
{
TIME ltime;
timestamp_type t_type=TIMESTAMP_FULL;
@@ -435,7 +462,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(default_charset());
+ decimals=0;
+ max_length=10*default_charset()->mbmaxlen;
localtime_r(&query_start,&tm_tmp);
start=&tm_tmp;
value=(longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
@@ -460,28 +490,50 @@ bool Item_func_curdate::get_date(TIME *res,
return 0;
}
+String *Item_func_curtime::val_str(String *str)
+{
+ str_value.set(buff,buff_length,default_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=default_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,default_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= &my_charset_bin;
+
+ 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 +542,15 @@ 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 +571,7 @@ bool Item_func_now::get_date(TIME *res,
}
-bool Item_func_now::save_in_field(Field *to, bool no_conversions)
+int Item_func_now::save_in_field(Field *to, bool no_conversions)
{
to->set_notnull();
to->store_time(&ltime,TIMESTAMP_FULL);
@@ -528,9 +581,10 @@ bool Item_func_now::save_in_field(Field *to, bool no_conversions)
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 +593,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, default_charset());
return str;
}
@@ -651,6 +705,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 +798,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 +838,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 +846,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 +866,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 +877,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 +891,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 +900,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 +908,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 +917,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 +939,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=default_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;
}
@@ -938,7 +999,42 @@ bool Item_func_from_unixtime::get_date(TIME *ltime,
return 0;
}
- /* Here arg[1] is a Item_interval object */
+
+void Item_date_add_interval::fix_length_and_dec()
+{
+ enum_field_types arg0_field_type;
+ set_charset(default_charset());
+ maybe_null=1;
+ max_length=19*default_charset()->mbmaxlen;
+ value.alloc(32);
+
+ /*
+ The field type for the result of an Item_date function is defined as
+ follows:
+
+ - If first arg is a MYSQL_TYPE_DATETIME result is MYSQL_TYPE_DATETIME
+ - If first arg is a MYSQL_TYPE_DATE and the interval type uses hours,
+ minutes or seconds then type is MYSQL_TYPE_DATETIME.
+ - Otherwise the result is MYSQL_TYPE_STRING
+ (This is because you can't know if the string contains a DATE, TIME or
+ DATETIME argument)
+ */
+ cached_field_type= MYSQL_TYPE_STRING;
+ arg0_field_type= args[0]->field_type();
+ if (arg0_field_type == MYSQL_TYPE_DATETIME ||
+ arg0_field_type == MYSQL_TYPE_TIMESTAMP)
+ cached_field_type= MYSQL_TYPE_DATETIME;
+ else if (arg0_field_type == MYSQL_TYPE_DATE)
+ {
+ if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH)
+ cached_field_type= arg0_field_type;
+ else
+ cached_field_type= MYSQL_TYPE_DATETIME;
+ }
+}
+
+
+/* Here arg[1] is a Item_interval object */
bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date)
{
@@ -1028,26 +1124,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=default_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 0ca2a36609d..2ed126b58e5 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*default_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*default_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*default_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*default_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(), default_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(default_charset());
+ decimals=0;
+ max_length=2*default_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(default_charset());
+ decimals=0;
+ max_length=10*default_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*default_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*default_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*default_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*default_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*default_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*default_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*default_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*default_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(), default_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(default_charset());
+ decimals=0;
+ max_length=1*default_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(default_charset());
+ decimals=0;
+ max_length=9*default_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*default_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*default_charset()->mbmaxlen;
}
};
@@ -227,20 +316,22 @@ public:
Item_date() :Item_func() {}
Item_date(Item *a) :Item_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
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, bool no_conversions);
- void make_field(Send_field *tmp_field)
- {
- init_make_field(tmp_field,FIELD_TYPE_DATE);
+ void fix_length_and_dec()
+ {
+ set_charset(default_charset());
+ decimals=0;
+ max_length=10*default_charset()->mbmaxlen;
}
+ int save_in_field(Field *to, bool no_conversions);
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg);
+ return (new Field_date(maybe_null, name, t_arg, default_charset()));
}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -250,43 +341,35 @@ public:
Item_date_func() :Item_str_func() {}
Item_date_func(Item *a) :Item_str_func(a) {}
Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
- void make_field(Send_field *tmp_field)
- {
- init_make_field(tmp_field,FIELD_TYPE_DATETIME);
- }
+ enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
- t_arg);
+ return (new Field_datetime(maybe_null, name, t_arg, default_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() {}
Item_func_curtime(Item *a) :Item_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; }
+ enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
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)
- {
- init_make_field(tmp_field,FIELD_TYPE_TIME);
- }
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg);
+ return (new Field_time(maybe_null, name, t_arg, default_charset()));
}
- unsigned int size_of() { return sizeof(*this);}
};
@@ -300,14 +383,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 +398,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, bool no_conversions);
- String *val_str(String *str)
- { str_value.set(buff,buff_length); return &str_value; }
+ int save_in_field(Field *to, bool no_conversions);
+ String *val_str(String *str);
const char *func_name() const { return "now"; }
void fix_length_and_dec();
bool get_date(TIME *res,bool fuzzy_date);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -347,7 +427,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,8 +438,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; }
-// enum Item_result result_type () const { return STRING_RESULT; }
+ void fix_length_and_dec()
+ {
+ set_charset(default_charset());
+ decimals=0;
+ max_length=19*default_charset()->mbmaxlen;
+ }
bool get_date(TIME *res,bool fuzzy_date);
};
@@ -372,42 +455,52 @@ 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; }
- const char *func_name() const { return "sec_to_time"; }
- void make_field(Send_field *tmp_field)
- {
- init_make_field(tmp_field,FIELD_TYPE_TIME);
+ void fix_length_and_dec()
+ {
+ set_charset(default_charset());
+ maybe_null=1;
+ max_length=13*default_charset()->mbmaxlen;
}
+ enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
+ const char *func_name() const { return "sec_to_time"; }
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg);
+ return (new Field_time(maybe_null, name, t_arg, default_charset()));
}
};
+/*
+ The following must be sorted so that simple intervals comes first.
+ (get_interval_value() depends on this)
+*/
+
+enum interval_type
+{
+ INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, INTERVAL_HOUR, INTERVAL_MINUTE,
+ INTERVAL_SECOND, INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR, INTERVAL_DAY_MINUTE,
+ INTERVAL_DAY_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
+ INTERVAL_MINUTE_SECOND
+};
-enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
- INTERVAL_HOUR, INTERVAL_MINUTE, INTERVAL_SECOND,
- INTERVAL_YEAR_MONTH, INTERVAL_DAY_HOUR,
- INTERVAL_DAY_MINUTE, INTERVAL_DAY_SECOND,
- INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
- INTERVAL_MINUTE_SECOND};
class Item_date_add_interval :public Item_date_func
{
const interval_type int_type;
String value;
const bool date_sub_interval;
+ enum_field_types cached_field_type;
public:
Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg)
: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();
+ enum_field_types field_type() const { return cached_field_type; }
double val() { return (double) val_int(); }
longlong val_int();
bool get_date(TIME *res,bool fuzzy_date);
- unsigned int size_of() { return sizeof(*this);}
};
@@ -422,7 +515,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);}
};
@@ -432,8 +524,17 @@ public:
Item_typecast(Item *a) :Item_str_func(a) {}
const char *func_name() const { return "char"; }
String *val_str(String *a)
- { a=args[0]->val_str(a); null_value=args[0]->null_value; return a; }
- void fix_length_and_dec() { max_length=args[0]->max_length; }
+ {
+ String *tmp=args[0]->val_str(a);
+ null_value=args[0]->null_value;
+ tmp->set_charset(charset());
+ return tmp;
+ }
+ void fix_length_and_dec()
+ {
+ set_charset(default_charset());
+ max_length=args[0]->max_length;
+ }
void print(String *str);
};
@@ -442,7 +543,11 @@ class Item_char_typecast :public Item_typecast
{
public:
Item_char_typecast(Item *a) :Item_typecast(a) {}
- void fix_length_and_dec() { binary=0; max_length=args[0]->max_length; }
+ void fix_length_and_dec()
+ {
+ set_charset(default_charset());
+ max_length=args[0]->max_length;
+ }
};
@@ -451,13 +556,11 @@ class Item_date_typecast :public Item_typecast
public:
Item_date_typecast(Item *a) :Item_typecast(a) {}
const char *func_name() const { return "date"; }
- void make_field(Send_field *tmp_field)
- {
- init_make_field(tmp_field,FIELD_TYPE_DATE);
- }
+ enum_field_types field_type() const { return MYSQL_TYPE_DATE; }
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg);
+ return (new Field_date(maybe_null, name, t_arg, default_charset()));
}
};
@@ -467,13 +570,11 @@ class Item_time_typecast :public Item_typecast
public:
Item_time_typecast(Item *a) :Item_typecast(a) {}
const char *func_name() const { return "time"; }
- void make_field(Send_field *tmp_field)
- {
- init_make_field(tmp_field,FIELD_TYPE_TIME);
- }
+ enum_field_types field_type() const { return MYSQL_TYPE_TIME; }
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg);
+ return (new Field_time(maybe_null, name, t_arg, default_charset()));
}
};
@@ -483,13 +584,10 @@ class Item_datetime_typecast :public Item_typecast
public:
Item_datetime_typecast(Item *a) :Item_typecast(a) {}
const char *func_name() const { return "datetime"; }
- void make_field(Send_field *tmp_field)
- {
- init_make_field(tmp_field,FIELD_TYPE_DATETIME);
- }
+ enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; }
+ Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
- return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
- t_arg);
+ return (new Field_datetime(maybe_null, name, t_arg, default_charset()));
}
};
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index cc087832f49..5ffd10be7a5 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -29,20 +29,29 @@ 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:
Item_sum_unique_users(Item *name_arg,int start,int end,Item *item_arg)
:Item_sum_num(item_arg) {}
+ Item_sum_unique_users(THD *thd, Item_sum_unique_users &item)
+ :Item_sum_num(thd, item) {}
double val() { return 0.0; }
enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
void reset() {}
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)
+ {
+ fixed= 1;
+ return 0;
+ }
+ Item *copy_or_same(THD* thd)
+ {
+ return new Item_sum_unique_users(thd, *this);
+ }
};
diff --git a/sql/key.cc b/sql/key.cc
index 809c5a164b9..37ef6339f20 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -67,7 +67,7 @@ int find_ref_key(TABLE *table,Field *field, uint *key_length)
/* Copy a key from record to some buffer */
- /* if length == 0 then copy hole key */
+ /* if length == 0 then copy whole key */
void key_copy(byte *key,TABLE *table,uint idx,uint key_length)
{
@@ -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))
+ if (my_strnncoll(key_part->field->charset(),
+ (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 d9a84dd25b4..5b1cbb58c1e 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
@@ -56,12 +56,15 @@ static SYMBOL symbols[] = {
{ "AGAINST", SYM(AGAINST),0,0},
{ "ANALYZE", SYM(ANALYZE_SYM),0,0},
{ "AND", SYM(AND),0,0},
+ { "ANY", SYM(ANY_SYM),0,0},
{ "AS", SYM(AS),0,0},
{ "ASC", SYM(ASC),0,0},
+ { "ASCII", SYM(ASCII_SYM),0,0},
{ "AVG", SYM(AVG_SYM),0,0},
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
{ "BACKUP", SYM(BACKUP_SYM),0,0},
+ { "BEFORE", SYM(BEFORE_SYM),0,0},
{ "BEGIN", SYM(BEGIN_SYM),0,0},
{ "BERKELEYDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BDB", SYM(BERKELEY_DB_SYM),0,0},
@@ -74,7 +77,9 @@ 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},
@@ -88,6 +93,8 @@ 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},
+ { "COLLATION", SYM(COLLATION_SYM),0,0},
{ "COLUMN", SYM(COLUMN_SYM),0,0},
{ "COLUMNS", SYM(COLUMNS),0,0},
{ "COMMENT", SYM(COMMENT_SYM),0,0},
@@ -124,11 +131,15 @@ static SYMBOL symbols[] = {
{ "DISABLE", SYM(DISABLE_SYM),0,0},
{ "DISTINCT", SYM(DISTINCT),0,0},
{ "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */
+ { "DIV", SYM(DIV_SYM),0,0},
{ "DO", SYM(DO_SYM),0,0},
{ "DOUBLE", SYM(DOUBLE_SYM),0,0},
+ { "DUAL", SYM(DUAL_SYM),0,0},
{ "DROP", SYM(DROP),0,0},
{ "DUMPFILE", SYM(DUMPFILE),0,0},
{ "DYNAMIC", SYM(DYNAMIC_SYM),0,0},
+ { "DUPLICATE", SYM(DUPLICATE_SYM),0,0},
+ { "ERRORS", SYM(ERRORS),0,0},
{ "END", SYM(END),0,0},
{ "ELSE", SYM(ELSE),0,0},
{ "ESCAPE", SYM(ESCAPE_SYM),0,0},
@@ -150,6 +161,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},
{ "FORCE", SYM(FORCE_SYM),0,0},
{ "RAID_TYPE", SYM(RAID_TYPE),0,0},
@@ -161,13 +173,17 @@ 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},
+ { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),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_SYM),0,0},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
{ "HOUR", SYM(HOUR_SYM),0,0},
{ "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0},
@@ -209,6 +225,7 @@ static SYMBOL symbols[] = {
{ "LEVEL", SYM(LEVEL_SYM),0,0},
{ "LIKE", SYM(LIKE),0,0},
{ "LINES", SYM(LINES),0,0},
+ { "LINESTRING", SYM(LINESTRING),0,0},
{ "LIMIT", SYM(LIMIT),0,0},
{ "LOAD", SYM(LOAD),0,0},
{ "LOCAL", SYM(LOCAL_SYM),0,0},
@@ -245,11 +262,16 @@ 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},
+ { "MULTILINESTRING", SYM(MULTILINESTRING),0,0},
+ { "MULTIPOINT", SYM(MULTIPOINT),0,0},
+ { "MULTIPOLYGON", SYM(MULTIPOLYGON),0,0},
{ "MRG_MYISAM", SYM(MERGE_SYM),0,0},
{ "MYISAM", SYM(MYISAM_SYM),0,0},
+ { "NAMES", SYM(NAMES_SYM),0,0},
{ "NATURAL", SYM(NATURAL),0,0},
{ "NATIONAL", SYM(NATIONAL_SYM),0,0},
{ "NEXT", SYM(NEXT_SYM),0,0},
@@ -273,6 +295,8 @@ static SYMBOL symbols[] = {
{ "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
{ "PARTIAL", SYM(PARTIAL),0,0},
{ "PASSWORD", SYM(PASSWORD),0,0},
+ { "POINT", SYM(POINT_SYM),0,0},
+ { "POLYGON", SYM(POLYGON),0,0},
{ "PURGE", SYM(PURGE),0,0},
{ "PRECISION", SYM(PRECISION),0,0},
{ "PREV", SYM(PREV_SYM),0,0},
@@ -309,25 +333,31 @@ 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},
+ { "SOME", SYM(ANY_SYM),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
+ { "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
{ "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0},
{ "SQL_CALC_FOUND_ROWS", SYM(SQL_CALC_FOUND_ROWS),0,0},
{ "SQL_NO_CACHE", SYM(SQL_NO_CACHE_SYM), 0, 0},
{ "SQL_SMALL_RESULT", SYM(SQL_SMALL_RESULT),0,0},
- { "SQL_THREAD", SYM(SQL_THREAD),0,0},
+ { "SQL_THREAD", SYM(SQL_THREAD),0,0},
+ { "SOUNDS", SYM(SOUNDS_SYM),0,0},
{ "SSL", SYM(SSL_SYM),0,0},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN),0,0},
{ "START", SYM(START_SYM),0,0},
@@ -352,9 +382,12 @@ 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},
+ { "UNICODE", SYM(UNICODE_SYM),0,0},
{ "UNION", SYM(UNION_SYM),0,0},
{ "UNIQUE", SYM(UNIQUE_SYM),0,0},
{ "UNLOCK", SYM(UNLOCK_SYM),0,0},
@@ -364,11 +397,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},
@@ -389,8 +425,9 @@ 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)},
- { "ASCII", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ascii)},
+ { "AREA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_area)},
{ "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},
@@ -403,17 +440,24 @@ static SYMBOL sql_functions[] = {
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
{ "CURRENT_USER", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_current_user)},
{ "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},
+ { "COERCIBILITY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_coercibility)},
{ "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)},
+#ifdef HAVE_COMPRESS
+ { "CRC32", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_crc32)},
+#endif
+ { "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)},
{ "CURDATE", SYM(CURDATE),0,0},
{ "CURTIME", SYM(CURTIME),0,0},
{ "DATE_ADD", SYM(DATE_ADD_INTERVAL),0,0},
@@ -427,9 +471,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},
@@ -441,6 +491,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)},
+ { "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},
+ { "GEOMETRYFROMTEXT", 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)},
@@ -448,13 +504,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},
+ { "LINESTRINGFROMTEXT",SYM(LINEFROMTEXT),0,0},
{ "LOAD_FILE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_load_file)},
{ "LOCATE", SYM(LOCATE),0,0},
{ "LOG", SYM(LOG_SYM),0,0},
@@ -469,17 +532,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},
{ "MONTHNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_monthname)},
+ { "MULTILINESTRINGFROMTEXT",SYM(MLINEFROMTEXT),0,0},
+ { "MULTIPOINTFROMTEXT",SYM(MPOINTFROMTEXT),0,0},
+ { "MULTIPOLYGONFROMTEXT",SYM(MPOLYFROMTEXT),0,0},
{ "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)},
+ { "NUMINTERIORRINGS", 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)},
- { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_password)},
+ { "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)},
{ "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
+ { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
{ "PERIOD_DIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_diff)},
{ "PI", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_pi)},
+ { "POINTFROMTEXT", SYM(POINTFROMTEXT),0,0},
+ { "POINTN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pointn)},
+ { "POLYFROMTEXT", SYM(POLYFROMTEXT),0,0},
+ { "POLYGONFROMTEXT", SYM(POLYFROMTEXT),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)},
@@ -503,6 +579,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)},
@@ -515,14 +592,19 @@ 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},
{ "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP),0,0},
{ "UPPER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "USER", SYM(USER),0,0},
+ { "VARIANCE", SYM(VARIANCE_SYM),0,0},
{ "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 41a76007289..82004298453 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -68,7 +68,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 +161,7 @@ retry:
sql_lock=0;
}
}
+
thd->lock_time();
DBUG_RETURN (sql_lock);
}
@@ -431,8 +437,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 9befcaefb01..00bd44274f9 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -29,7 +29,6 @@
#include <my_dir.h>
#include <stdarg.h>
#include <m_ctype.h> // For test_if_number
-#include <assert.h>
MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log;
extern I_List<i_string> binlog_do_db, binlog_ignore_db;
@@ -45,16 +44,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 +77,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);
}
@@ -204,7 +206,9 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
case LOG_NORMAL:
{
char *end;
-#ifdef __NT__
+#ifdef EMBEDDED_LIBRARY
+ sprintf(buff, "%s, Version: %s, embedded library\n", my_progname, server_version);
+#elif __NT__
sprintf(buff, "%s, Version: %s, started with:\nTCP Port: %d, Named Pipe: %s\n", my_progname, server_version, mysql_port, mysql_unix_port);
#else
sprintf(buff, "%s, Version: %s, started with:\nTcp port: %d Unix socket: %s\n", my_progname,server_version,mysql_port,mysql_unix_port);
@@ -220,15 +224,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;
@@ -611,6 +618,8 @@ err:
LOG_INFO_IO Got IO error while reading file
*/
+#ifdef HAVE_REPLICATION
+
int MYSQL_LOG::purge_first_log(struct st_relay_log_info* rli)
{
int error;
@@ -680,6 +689,19 @@ err:
DBUG_RETURN(error);
}
+/*
+ Update log index_file
+*/
+
+int MYSQL_LOG::update_log_index(LOG_INFO* log_info)
+{
+ if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
+ return LOG_INFO_IO;
+
+ // now update offsets in index file for running threads
+ adjust_linfo_offsets(log_info->index_file_start_offset);
+ return 0;
+}
/*
Remove all logs before the given log from disk and from the index file.
@@ -732,15 +754,69 @@ int MYSQL_LOG::purge_logs(THD* thd, const char* to_log)
If we get killed -9 here, the sysadmin would have to edit
the log index file after restart - otherwise, this should be safe
*/
+ error= update_log_index(&log_info);
- if (copy_up_file_and_fill(&index_file, log_info.index_file_start_offset))
- {
- error= LOG_INFO_IO;
+err:
+ pthread_mutex_unlock(&LOCK_index);
+ DBUG_RETURN(error);
+}
+
+/*
+ Remove all logs before the given file date from disk and from the
+ index file.
+
+ SYNOPSIS
+ purge_logs_before_date()
+ thd Thread pointer
+ before_date Delete all log files before given date.
+
+ NOTES
+ If any of the logs before the deleted one is in use,
+ only purge logs up to this one.
+
+ RETURN VALUES
+ 0 ok
+ LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
+*/
+
+int MYSQL_LOG::purge_logs_before_date(THD* thd, time_t purge_time)
+{
+ int error;
+ LOG_INFO log_info;
+ MY_STAT stat_area;
+
+ DBUG_ENTER("purge_logs_before_date");
+
+ if (no_rotate)
+ DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE);
+
+ pthread_mutex_lock(&LOCK_index);
+
+ /*
+ Delete until we find curren file
+ or a file that is used or a file
+ that is older than purge_time.
+ */
+ if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
+
+ while (strcmp(log_file_name, log_info.log_file_name) &&
+ !log_in_use(log_info.log_file_name))
+ {
+ /* It's not fatal even if we can't delete a log file */
+ if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)) ||
+ stat_area.st_mtime >= purge_time)
+ break;
+ my_delete(log_info.log_file_name, MYF(0));
+ if (find_next_log(&log_info, 0))
+ break;
}
- // now update offsets in index file for running threads
- adjust_linfo_offsets(log_info.index_file_start_offset);
+ /*
+ If we get killed -9 here, the sysadmin would have to edit
+ the log index file after restart - otherwise, this should be safe
+ */
+ error= update_log_index(&log_info);
err:
pthread_mutex_unlock(&LOCK_index);
@@ -748,6 +824,9 @@ err:
}
+#endif /* HAVE_REPLICATION */
+
+
/*
Create a new log file name
@@ -949,7 +1028,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 */
@@ -998,8 +1078,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)
{
@@ -1031,6 +1113,7 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command,
bool MYSQL_LOG::write(Log_event* event_info)
{
bool error=0;
+ bool should_rotate = 0;
DBUG_ENTER("MYSQL_LOG::write(event)");
if (!inited) // Can't use mutex if not init
@@ -1043,7 +1126,6 @@ bool MYSQL_LOG::write(Log_event* event_info)
/* In most cases this is only called if 'is_open()' is true */
if (is_open())
{
- bool should_rotate = 0;
THD *thd=event_info->thd;
const char *local_db = event_info->get_db();
#ifdef USING_TRANSACTIONS
@@ -1053,6 +1135,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
#else
IO_CACHE *file = &log_file;
#endif
+#ifdef HAVE_REPLICATION
if ((thd && !(thd->options & OPTION_BIN_LOG) &&
(thd->master_access & SUPER_ACL)) ||
(local_db && !db_ok(local_db, binlog_do_db, binlog_ignore_db)))
@@ -1061,6 +1144,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
DBUG_PRINT("error",("!db_ok"));
DBUG_RETURN(0);
}
+#endif /* HAVE_REPLICATION */
error=1;
/*
@@ -1095,6 +1179,23 @@ bool MYSQL_LOG::write(Log_event* event_info)
if (e.write(file))
goto err;
}
+ if (thd->user_var_events.elements)
+ {
+ for (uint i= 0; i < thd->user_var_events.elements; i++)
+ {
+ BINLOG_USER_VAR_EVENT *user_var_event;
+ get_dynamic(&thd->user_var_events,(gptr) &user_var_event, i);
+ User_var_log_event e(thd, user_var_event->user_var_event->name.str,
+ user_var_event->user_var_event->name.length,
+ user_var_event->value,
+ user_var_event->length,
+ user_var_event->type,
+ user_var_event->charset_number);
+ e.set_log_pos(this);
+ if (e.write(file))
+ goto err;
+ }
+ }
if (thd->variables.convert_set)
{
char buf[256], *p;
@@ -1161,6 +1262,15 @@ err:
}
pthread_mutex_unlock(&LOCK_log);
+#ifdef HAVE_REPLICATION
+ if (should_rotate && expire_logs_days)
+ {
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ error= purge_logs_before_date(current_thd, purge_time);
+ }
+
+#endif
DBUG_RETURN(error);
}
@@ -1281,11 +1391,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,
@@ -1460,6 +1566,7 @@ void MYSQL_LOG::close(bool exiting)
DBUG_PRINT("enter",("exiting: %d", (int) exiting));
if (is_open())
{
+#ifdef HAVE_REPLICATION
if (log_type == LOG_BIN && !no_auto_events && exiting)
{
Stop_log_event s;
@@ -1467,6 +1574,7 @@ void MYSQL_LOG::close(bool exiting)
s.write(&log_file);
signal_update();
}
+#endif /* HAVE_REPLICATION */
end_io_cache(&log_file);
if (my_close(log_file.file,MYF(0)) < 0 && ! write_error)
{
@@ -1524,8 +1632,8 @@ static bool test_if_number(register const char *str,
while (*str++ == ' ') ;
if (*--str == '-' || *str == '+')
str++;
- while (isdigit(*str) || (allow_wildcards &&
- (*str == wild_many || *str == wild_one)))
+ while (my_isdigit(files_charset_info,*str) ||
+ (allow_wildcards && (*str == wild_many || *str == wild_one)))
{
flag=1;
str++;
@@ -1533,7 +1641,7 @@ static bool test_if_number(register const char *str,
if (*str == '.')
{
for (str++ ;
- isdigit(*str) ||
+ my_isdigit(files_charset_info,*str) ||
(allow_wildcards && (*str == wild_many || *str == wild_one)) ;
str++, flag=1) ;
}
@@ -1636,3 +1744,6 @@ bool flush_error_log()
}
return result;
}
+
+
+
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 78470a2b198..b57a691c267 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -24,8 +24,13 @@
#include <my_dir.h>
#endif /* MYSQL_CLIENT */
-#include <assert.h>
+#define log_cs &my_charset_latin1
+/*****************************************************************************
+
+ 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,40 +73,58 @@ static void pretty_print_str(FILE* file, char* str, int len)
}
fputc('\'', file);
}
-#endif
+#endif // MYSQL_CLIENT
-#ifndef MYSQL_CLIENT
+/*****************************************************************************
+
+ ignored_error_code()
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
inline int ignored_error_code(int err_code)
{
return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
}
+#endif
+
+/*****************************************************************************
+ pretty_print_str()
-static void pretty_print_str(String* packet, char* str, int len)
+ ****************************************************************************/
+#ifndef MYSQL_CLIENT
+static char* pretty_print_str(char* packet, char* str, int len)
{
char* end = str + len;
- packet->append('\'');
+ char* pos= packet;
+ *pos++= '\'';
while (str < end)
{
char c;
switch ((c=*str++)) {
- case '\n': packet->append( "\\n"); break;
- case '\r': packet->append( "\\r"); break;
- case '\\': packet->append( "\\\\"); break;
- case '\b': packet->append( "\\b"); break;
- case '\t': packet->append( "\\t"); break;
- case '\'': packet->append( "\\'"); break;
- case 0 : packet->append( "\\0"); break;
+ case '\n': pos= strmov(pos, "\\n"); break;
+ case '\r': pos= strmov(pos, "\\r"); break;
+ case '\\': pos= strmov(pos, "\\\\"); break;
+ case '\b': pos= strmov(pos, "\\b"); break;
+ case '\t': pos= strmov(pos, "\\t"); break;
+ case '\'': pos= strmov(pos, "\\'"); break;
+ case 0 : pos= strmov(pos, "\\0"); break;
default:
- packet->append((char)c);
+ *pos++= (char)c;
break;
}
}
- packet->append('\'');
+ *pos++= '\'';
+ return pos;
}
+#endif // !MYSQL_CLIENT
+/*****************************************************************************
+ slave_load_file_stem()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
static inline char* slave_load_file_stem(char*buf, uint file_id,
int event_server_id)
{
@@ -108,9 +136,81 @@ static inline char* slave_load_file_stem(char*buf, uint file_id,
*buf++ = '-';
return int10_to_str(file_id, buf, 10);
}
+#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.
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(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
+/*****************************************************************************
+
+ 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 +226,27 @@ 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";
+ case USER_VAR_EVENT: return "User var";
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 +254,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)
{
@@ -203,7 +287,13 @@ Log_event::Log_event(const char* buf, bool old_format)
#ifndef MYSQL_CLIENT
+#ifdef HAVE_REPLICATION
+/*****************************************************************************
+
+ Log_event::exec_event()
+
+ ****************************************************************************/
int Log_event::exec_event(struct st_relay_log_info* rli)
{
/*
@@ -231,217 +321,79 @@ 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());
-}
+ Log_event::pack_info()
-void Start_log_event::pack_info(String* packet)
+ ****************************************************************************/
+void Log_event::pack_info(Protocol *protocol)
{
- 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());
+ protocol->store("",0);
}
-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());
-}
+ Log_event::net_send()
-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());
-}
+ Only called by SHOW BINLOG EVENTS
-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());
-}
+ ****************************************************************************/
-void Rand_log_event::pack_info(String* packet)
+int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos)
{
- 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));
+ const char *p= strrchr(log_name, FN_LIBCHAR);
+ const char *event_type;
+ if (p)
+ log_name = p + 1;
+
+ protocol->prepare_for_resend();
+ protocol->store(log_name, system_charset_info);
+ protocol->store((ulonglong) pos);
+ event_type = get_type_str();
+ protocol->store(event_type, strlen(event_type), system_charset_info);
+ protocol->store((uint32) server_id);
+ protocol->store((ulonglong) log_pos);
+ pack_info(protocol);
+ return protocol->write();
}
+#endif /* HAVE_REPLICATION */
-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));
- field_list->push_back(new Item_empty_string("Pos", 20));
+ field_list->push_back(new Item_return_int("Pos", 11,
+ MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Event_type", 20));
- field_list->push_back(new Item_empty_string("Server_id", 20));
- field_list->push_back(new Item_empty_string("Orig_log_pos", 20));
+ field_list->push_back(new Item_return_int("Server_id", 10,
+ MYSQL_TYPE_LONG));
+ field_list->push_back(new Item_return_int("Orig_log_pos", 11,
+ MYSQL_TYPE_LONGLONG));
field_list->push_back(new Item_empty_string("Info", 20));
}
-/*
- * 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;
- if (p)
- log_name = p + 1;
-
- packet->length(0);
- net_store_data(packet, log_name, strlen(log_name));
- net_store_data(packet, (longlong) pos);
- event_type = get_type_str();
- net_store_data(packet, event_type, strlen(event_type));
- net_store_data(packet, server_id);
- net_store_data(packet, (longlong) log_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];
@@ -461,8 +413,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)
{
@@ -517,8 +474,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);
@@ -529,7 +485,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,
@@ -601,7 +563,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)
{
@@ -619,7 +585,7 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
ev = new Query_log_event(buf, event_len, old_format);
break;
case LOAD_EVENT:
- ev = new Create_file_log_event(buf, event_len, old_format);
+ ev = new Load_log_event(buf, event_len, old_format);
break;
case NEW_LOAD_EVENT:
ev = new Load_log_event(buf, event_len, old_format);
@@ -627,9 +593,11 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
case ROTATE_EVENT:
ev = new Rotate_log_event(buf, event_len, old_format);
break;
+#ifdef HAVE_REPLICATION
case SLAVE_EVENT:
ev = new Slave_log_event(buf, event_len);
break;
+#endif /* HAVE_REPLICATION */
case CREATE_FILE_EVENT:
ev = new Create_file_log_event(buf, event_len, old_format);
break;
@@ -645,15 +613,20 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
case START_EVENT:
ev = new Start_log_event(buf, old_format);
break;
+#ifdef HAVE_REPLICATION
case STOP_EVENT:
ev = new Stop_log_event(buf, old_format);
break;
+#endif /* HAVE_REPLICATION */
case INTVAR_EVENT:
ev = new Intvar_log_event(buf, old_format);
break;
case RAND_EVENT:
ev = new Rand_log_event(buf, old_format);
break;
+ case USER_VAR_EVENT:
+ ev = new User_var_log_event(buf, old_format);
+ break;
default:
break;
}
@@ -667,8 +640,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];
@@ -678,6 +656,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;
@@ -699,117 +682,102 @@ 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);
-}
+#if defined(HAVE_REPLICATION) && !defined(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(Protocol *protocol)
{
- // 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)
+ char *buf, *pos;
+ if (!(buf= my_malloc(9 + db_len + q_len, MYF(MY_WME))))
return;
- buf += header_size;
- if (old_format)
+ pos= buf;
+ if (db && db_len)
{
- ident_len = (uint)(event_len - OLD_HEADER_LEN);
- pos = 4;
- ident_offset = 0;
+ pos= strmov(buf, "use `");
+ memcpy(pos, db, db_len);
+ pos+= db_len;
+ pos= strmov(pos, "`; ");
}
- else
+ if (query && q_len)
{
- ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD);
- pos = uint8korr(buf + R_POS_OFFSET);
- ident_offset = ROTATE_HEADER_LEN;
+ memcpy(pos, query, q_len);
+ pos+= q_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;
+ protocol->store(buf, pos-buf, system_charset_info);
+ my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
+#endif
+/*****************************************************************************
-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)
- :Log_event(thd_arg, 0, using_trans), data_buf(0), query(query_arg),
+ :Log_event(thd_arg, !thd_arg->tmp_table_used ?
+ 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans),
+ data_buf(0), query(query_arg),
db(thd_arg->db), q_len((uint32) query_length),
error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN: thd_arg->net.last_errno),
thread_id(thd_arg->thread_id)
@@ -819,8 +787,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)
@@ -856,9 +829,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
@@ -883,116 +859,357 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
*end++=';';
*end++='\n';
my_fwrite(file, (byte*) buff, (uint) (end-buff),MYF(MY_NABP | MY_WME));
+ if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
+ fprintf(file,"SET @@session.pseudo_thread_id=%lu;\n",(ulong)thread_id);
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)
+ Query_log_event::exec_event()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int Query_log_event::exec_event(struct st_relay_log_info* rli)
{
- 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);
+ int expected_error,actual_error = 0;
+ thd->db = rewrite_db((char*)db);
- 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;
-}
+ /*
+ 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();
-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);
-}
+ if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
+ {
+ thd->set_time((time_t)when);
+ thd->current_tablenr = 0;
+ thd->query_length= q_len;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query = (char*)query;
+ thd->query_id = query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->query_error= 0; // clear error
+ thd->clear_error();
+
+ thd->variables.pseudo_thread_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);
-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";
+ /*
+ Set a flag if we are inside an transaction so that we can restart
+ the transaction from the start if we are killed
+
+ This will only be done if we are supporting transactional tables
+ in the slave.
+ */
+ if (!strcmp(thd->query,"BEGIN"))
+ rli->inside_transaction= opt_using_transactions;
+ else if (!strcmp(thd->query,"COMMIT"))
+ rli->inside_transaction=0;
+
+ 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
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->db = thd->query = 0;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ 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
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query= 0; // just to be sure
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ // assume no convert for next query unless set explictly
+ thd->variables.convert_set = 0;
+ close_thread_tables(thd);
+
+ if (thd->query_error || thd->is_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
-int Intvar_log_event::write_data(IO_CACHE* file)
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Start_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Start_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Start_log_event::pack_info(Protocol *protocol)
{
- 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 buf[12 + ST_SERVER_VER_LEN + 14 + 22], *pos;
+ pos= strmov(buf, "Server ver: ");
+ pos= strmov(pos, server_version);
+ pos= strmov(pos, ", Binlog ver: ");
+ pos=int10_to_str(binlog_version, pos, 10);
+ protocol->store(buf, pos-buf, system_charset_info);
}
+#endif
+/*****************************************************************************
+
+ 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.
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int Start_log_event::exec_event(struct st_relay_log_info* rli)
{
- char llbuff[22],llbuff2[22];
- if (!short_form)
+ DBUG_ENTER("Start_log_event::exec_event");
+ /* 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();
+ DBUG_RETURN(Log_event::exec_event(rli));
+}
+#endif
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ Load_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Load_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Load_log_event::pack_info(Protocol *protocol)
+{
+ char *buf, *pos;
+ uint buf_len;
+
+ buf_len=
+ 5 + db_len + 3 + // "use DB; "
+ 18 + fname_len + 2 + // "LOAD DATA INFILE 'file''"
+ 9 + // " REPLACE or IGNORE "
+ 11 + table_name_len + // "INTO TABLE table"
+ 21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'"
+ 23 + sql_ex.enclosed_len*4 + 2 + // " OPTIONALLY ENCLOSED BY 'str'"
+ 12 + sql_ex.escaped_len*4 + 2 + // " ESCAPED BY 'str'"
+ 21 + sql_ex.line_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'"
+ 19 + sql_ex.line_start_len*4 + 2 + // " LINES STARTING BY 'str'"
+ 15 + 22 + // " IGNORE xxx LINES"
+ 3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)"
+
+ buf= my_malloc(buf_len, MYF(MY_WME));
+ if (!buf)
+ return;
+ pos= buf;
+ if (db && db_len)
{
- print_header(file);
- fprintf(file, "\tRand\n");
+ pos= strmov(pos, "use `");
+ memcpy(pos, db, db_len);
+ pos+= db_len;
+ pos= strmov(pos, "`; ");
}
- fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n",
- llstr(seed1, llbuff),llstr(seed2, llbuff2));
- fflush(file);
+
+ pos= strmov(pos, "LOAD DATA INFILE '");
+ memcpy(pos, fname, fname_len);
+ pos+= fname_len;
+ pos= strmov(pos, "' ");
+
+ if (sql_ex.opt_flags && REPLACE_FLAG )
+ pos= strmov(pos, " REPLACE ");
+ else if (sql_ex.opt_flags && IGNORE_FLAG )
+ pos= strmov(pos, " IGNORE ");
+
+ pos= strmov(pos ,"INTO TABLE ");
+ memcpy(pos, table_name, table_name_len);
+ pos+= table_name_len;
+
+ if (sql_ex.field_term_len)
+ {
+ pos= strmov(pos, " FIELDS TERMINATED BY ");
+ pos= pretty_print_str(pos, sql_ex.field_term, sql_ex.field_term_len);
+ }
+
+ if (sql_ex.enclosed_len)
+ {
+ if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG )
+ pos= strmov(pos, " OPTIONALLY ");
+ pos= strmov(pos, " ENCLOSED BY ");
+ pos= pretty_print_str(pos, sql_ex.enclosed, sql_ex.enclosed_len);
+ }
+
+ if (sql_ex.escaped_len)
+ {
+ pos= strmov(pos, " ESCAPED BY ");
+ pos= pretty_print_str(pos, sql_ex.escaped, sql_ex.escaped_len);
+ }
+
+ if (sql_ex.line_term_len)
+ {
+ pos= strmov(pos, " LINES TERMINATED BY ");
+ pos= pretty_print_str(pos, sql_ex.line_term, sql_ex.line_term_len);
+ }
+
+ if (sql_ex.line_start_len)
+ {
+ pos= strmov(pos, " LINES STARTING BY ");
+ pos= pretty_print_str(pos, sql_ex.line_start, sql_ex.line_start_len);
+ }
+
+ if ((int)skip_lines > 0)
+ {
+ pos= strmov(pos, " IGNORE ");
+ pos= longlong10_to_str((long) skip_lines, pos, 10);
+ pos= strmov(pos," LINES ");
+ }
+
+ if (num_fields)
+ {
+ uint i;
+ const char* field = fields;
+ pos= strmov(pos, " (");
+ for (i = 0; i < num_fields; i++)
+ {
+ if (i)
+ pos= strmov(pos, " ,");
+ memcpy(pos, field, field_lens[i]);
+ pos+= field_lens[i];
+ field += field_lens[i] + 1;
+ }
+ *pos++= ')';
+ }
+
+ protocol->store(buf, pos-buf, system_charset_info);
+ my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
#endif
+/*****************************************************************************
+
+ Load_log_event::write_data_header()
+
+ ****************************************************************************/
int Load_log_event::write_data_header(IO_CACHE* file)
{
char buf[LOAD_HEADER_LEN];
@@ -1005,6 +1222,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))
@@ -1020,110 +1242,21 @@ 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,
+Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
+ const char *db_arg, const char *table_name_arg,
+ List<Item> &fields_arg,
enum enum_duplicates handle_dup,
bool using_trans)
- :Log_event(thd_arg, 0, using_trans),thread_id(thd_arg->thread_id),
- num_fields(0),fields(0),
- field_lens(0),field_block_len(0),
- table_name(table_name_arg ? table_name_arg : ""),
- db(db_arg), fname(ex->file_name)
+ :Log_event(thd_arg, 0, using_trans), thread_id(thd_arg->thread_id),
+ num_fields(0), fields(0), field_lens(0),field_block_len(0),
+ table_name(table_name_arg ? table_name_arg : ""),
+ db(db_arg), fname(ex->file_name)
{
time_t end_time;
time(&end_time);
@@ -1153,9 +1286,15 @@ Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex,
sql_ex.empty_flags = 0;
switch (handle_dup) {
- case DUP_IGNORE: sql_ex.opt_flags |= IGNORE_FLAG; break;
- case DUP_REPLACE: sql_ex.opt_flags |= REPLACE_FLAG; break;
- case DUP_ERROR: break;
+ case DUP_IGNORE:
+ sql_ex.opt_flags |= IGNORE_FLAG;
+ break;
+ case DUP_REPLACE:
+ sql_ex.opt_flags |= REPLACE_FLAG;
+ break;
+ case DUP_UPDATE: // Impossible here
+ case DUP_ERROR:
+ break;
}
if (!ex->field_term->length())
@@ -1187,25 +1326,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)
{
@@ -1250,8 +1396,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)
@@ -1271,7 +1421,10 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db)
if (db && db[0] && !same_db)
fprintf(file, "use %s;\n", db);
- fprintf(file, "LOAD DATA INFILE '%-*s' ", fname_len, fname);
+ fprintf(file, "LOAD ");
+ if (check_fname_outside_temp_buf())
+ fprintf(file, "LOCAL ");
+ fprintf(file, "DATA INFILE '%-*s' ", fname_len, fname);
if (sql_ex.opt_flags && REPLACE_FLAG )
fprintf(file," REPLACE ");
@@ -1332,473 +1485,27 @@ 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
-
-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)
-{
- DBUG_ENTER("Slave_log_event");
- if (!rli->inited) // QQ When can this happen ?
- DBUG_VOID_RETURN;
-
- MASTER_INFO* mi = rli->mi;
- // TODO: re-write this better without holding both locks at the same time
- pthread_mutex_lock(&mi->data_lock);
- pthread_mutex_lock(&rli->data_lock);
- master_host_len = strlen(mi->host);
- master_log_len = strlen(rli->master_log_name);
- // on OOM, just do not initialize the structure and print the error
- if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
- MYF(MY_WME))))
- {
- master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
- memcpy(master_host, mi->host, master_host_len + 1);
- master_log = master_host + master_host_len + 1;
- memcpy(master_log, rli->master_log_name, master_log_len + 1);
- master_port = mi->port;
- master_pos = rli->master_log_pos;
- DBUG_PRINT("info", ("master_log: %s pos: %d", master_log,
- (ulong) master_pos));
- }
- else
- sql_print_error("Out of memory while recording slave event");
- pthread_mutex_unlock(&rli->data_lock);
- pthread_mutex_unlock(&mi->data_lock);
- DBUG_VOID_RETURN;
-}
-
-#endif /* ! MYSQL_CLIENT */
-
-
-Slave_log_event::~Slave_log_event()
-{
- my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
-}
-
-#ifdef MYSQL_CLIENT
-
-void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
-{
- char llbuff[22];
- if (short_form)
- return;
- print_header(file);
- fputc('\n', file);
- fprintf(file, "Slave: master_host: '%s' master_port: %d \
-master_log: '%s' master_pos: %s\n",
- master_host, master_port, master_log, llstr(master_pos, llbuff));
-}
-
-#endif /* MYSQL_CLIENT */
-
-int Slave_log_event::get_data_size()
-{
- return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
-}
-
-int Slave_log_event::write_data(IO_CACHE* file)
-{
- int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
- int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port);
- // log and host are already there
- return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
-}
-
-
-void Slave_log_event::init_from_mem_pool(int data_size)
-{
- master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET);
- master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET);
- master_host = mem_pool + SL_MASTER_HOST_OFFSET;
- master_host_len = strlen(master_host);
- // safety
- master_log = master_host + master_host_len + 1;
- if (master_log > mem_pool + data_size)
- {
- master_host = 0;
- return;
- }
- master_log_len = strlen(master_log);
-}
-
-Slave_log_event::Slave_log_event(const char* buf, int event_len)
- :Log_event(buf,0),mem_pool(0),master_host(0)
-{
- event_len -= LOG_EVENT_HEADER_LEN;
- if (event_len < 0)
- return;
- if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME))))
- return;
- memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len);
- mem_pool[event_len] = 0;
- init_from_mem_pool(event_len);
-}
-
-#ifndef MYSQL_CLIENT
-Create_file_log_event::
-Create_file_log_event(THD* thd_arg, sql_exchange* ex,
- const char* db_arg, const char* table_name_arg,
- List<Item>& fields_arg, enum enum_duplicates handle_dup,
- char* block_arg, uint block_len_arg, bool using_trans)
- :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup,
- using_trans),
- fake_base(0),block(block_arg),block_len(block_len_arg),
- file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
-{
- sql_ex.force_new_format();
-}
-#endif
-
-int Create_file_log_event::write_data_body(IO_CACHE* file)
-{
- int res;
- if ((res = Load_log_event::write_data_body(file)) || fake_base)
- return res;
- return (my_b_safe_write(file, (byte*) "", 1) ||
- my_b_safe_write(file, (byte*) block, block_len));
-}
-
-int Create_file_log_event::write_data_header(IO_CACHE* file)
-{
- int res;
- if ((res = Load_log_event::write_data_header(file)) || fake_base)
- return res;
- byte buf[CREATE_FILE_HEADER_LEN];
- int4store(buf + CF_FILE_ID_OFFSET, file_id);
- return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN);
-}
-
-int Create_file_log_event::write_base(IO_CACHE* file)
-{
- int res;
- fake_base = 1; // pretend we are Load event
- res = write(file);
- fake_base = 0;
- return res;
-}
-
-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)
-{
- int block_offset;
- if (copy_log_event(buf,len,old_format))
- return;
- if (!old_format)
- {
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
- + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
- // + 1 for \0 terminating fname
- block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
- CREATE_FILE_HEADER_LEN + 1);
- if (len < block_offset)
- return;
- block = (char*)buf + block_offset;
- block_len = len - block_offset;
- }
- else
- {
- sql_ex.force_new_format();
- inited_from_old = 1;
- }
-}
-
-
-#ifdef MYSQL_CLIENT
-void Create_file_log_event::print(FILE* file, bool short_form,
- char* last_db)
-{
- if (short_form)
- return;
- Load_log_event::print(file, 1, last_db);
- fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len);
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-void Create_file_log_event::pack_info(String* packet)
-{
- char buf1[256],buf[22], *end;
- String tmp(buf1, sizeof(buf1));
- tmp.length(0);
- tmp.append("db=");
- tmp.append(db, db_len);
- tmp.append(";table=");
- tmp.append(table_name, table_name_len);
- tmp.append(";file_id=");
- end= int10_to_str((long) file_id, buf, 10);
- tmp.append(buf, (uint32) (end-buf));
- tmp.append(";block_len=");
- end= int10_to_str((long) block_len, buf, 10);
- tmp.append(buf, (uint32) (end-buf));
- net_store_data(packet, (char*) tmp.ptr(), tmp.length());
-}
-#endif
-
-#ifndef MYSQL_CLIENT
-Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
- uint block_len_arg,
- bool using_trans)
- :Log_event(thd_arg,0, using_trans), block(block_arg),
- block_len(block_len_arg), file_id(thd_arg->file_id)
-{
-}
-#endif
-
-Append_block_log_event::Append_block_log_event(const char* buf, int len)
- :Log_event(buf, 0),block(0)
-{
- if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
- return;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
- block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD;
- block_len = len - APPEND_BLOCK_EVENT_OVERHEAD;
-}
-
-int Append_block_log_event::write_data(IO_CACHE* file)
-{
- byte buf[APPEND_BLOCK_HEADER_LEN];
- int4store(buf + AB_FILE_ID_OFFSET, file_id);
- return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
- my_b_safe_write(file, (byte*) block, block_len));
-}
-
-#ifdef MYSQL_CLIENT
-void Append_block_log_event::print(FILE* file, bool short_form,
- char* last_db)
-{
- if (short_form)
- return;
- print_header(file);
- fputc('\n', file);
- fprintf(file, "#Append_block: file_id: %d block_len: %d\n",
- file_id, block_len);
-}
-#endif
-
-#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);
-}
-
-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
-
-
-Delete_file_log_event::Delete_file_log_event(const char* buf, int len)
- :Log_event(buf, 0),file_id(0)
-{
- if ((uint)len < DELETE_FILE_EVENT_OVERHEAD)
- return;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
-}
-
-
-int Delete_file_log_event::write_data(IO_CACHE* file)
-{
- byte buf[DELETE_FILE_HEADER_LEN];
- int4store(buf + DF_FILE_ID_OFFSET, file_id);
- return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN);
-}
-
-#ifdef MYSQL_CLIENT
-void Delete_file_log_event::print(FILE* file, bool short_form,
- char* last_db)
-{
- if (short_form)
- return;
- print_header(file);
- fputc('\n', file);
- fprintf(file, "#Delete_file: file_id=%u\n", file_id);
-}
-#endif
-
-#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);
-}
-#endif
-
-
-#ifndef MYSQL_CLIENT
-Execute_load_log_event::Execute_load_log_event(THD* thd_arg, bool using_trans)
- :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
-{
-}
-#endif
-
-Execute_load_log_event::Execute_load_log_event(const char* buf, int len)
- :Log_event(buf, 0), file_id(0)
-{
- if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
- return;
- file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET);
-}
-
-int Execute_load_log_event::write_data(IO_CACHE* file)
-{
- byte buf[EXEC_LOAD_HEADER_LEN];
- int4store(buf + EL_FILE_ID_OFFSET, file_id);
- return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN);
-}
-
-#ifdef MYSQL_CLIENT
-void Execute_load_log_event::print(FILE* file, bool short_form,
- char* last_db)
-{
- if (short_form)
- return;
- print_header(file);
- fputc('\n', file);
- 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->set_time((time_t)when);
- thd->current_tablenr = 0;
- thd->query_length= q_len;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query = (char*)query;
- 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);
-
- /*
- Set a flag if we are inside an transaction so that we can restart
- the transaction from the start if we are killed
-
- This will only be done if we are supporting transactional tables
- in the slave.
- */
- if (!strcmp(thd->query,"BEGIN"))
- rli->inside_transaction= opt_using_transactions;
- else if (!strcmp(thd->query,"COMMIT"))
- rli->inside_transaction=0;
-
- 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
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->db = thd->query = 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- 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
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query= 0; // just to be sure
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- // assume no convert for next query unless set explictly
- thd->variables.convert_set = 0;
- 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);
-}
-
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
/*
Does the data loading job when executing a LOAD DATA on the slave
@@ -1828,7 +1535,6 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors)
{
- init_sql_alloc(&thd->mem_root, 8192,0);
thd->db = rewrite_db((char*)db);
DBUG_ASSERT(thd->query == 0);
thd->query = 0; // Should not be needed
@@ -1863,12 +1569,12 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
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);
-
+ String field_term(sql_ex.field_term,sql_ex.field_term_len,log_cs);
+ String enclosed(sql_ex.enclosed,sql_ex.enclosed_len,log_cs);
+ String line_term(sql_ex.line_term,sql_ex.line_term_len,log_cs);
+ String line_start(sql_ex.line_start,sql_ex.line_start_len,log_cs);
+ String escaped(sql_ex.escaped,sql_ex.escaped_len, log_cs);
+
ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG);
if (sql_ex.empty_flags & FIELD_TERM_EMPTY)
ex.field_term->length(0);
@@ -1876,7 +1582,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
ex.skip_lines = skip_lines;
List<Item> field_list;
set_fields(field_list);
- thd->slave_proxy_id = thd->thread_id;
+ thd->variables.pseudo_thread_id= thd->thread_id;
if (net)
{
// mysql_load will use thd->net to read the file
@@ -1890,6 +1596,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
TL_WRITE))
thd->query_error = 1;
if (thd->cuted_fields)
+ {
/*
log_pos is the position of the LOAD
event in the master log
@@ -1897,6 +1604,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
sql_print_error("Slave: load data infile at position %s in log \
'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME,
thd->cuted_fields );
+ }
if (net)
net->pkt_nr= thd->net.pkt_nr;
}
@@ -1929,7 +1637,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
}
free_root(&thd->mem_root,0);
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
{
sql_print_error("Slave: Fatal error running LOAD DATA INFILE ");
return 1;
@@ -1937,65 +1645,118 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) );
}
+#endif
-/*
- 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.
+ Rotate_log_event methods
- 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)
+/*****************************************************************************
+
+ Rotate_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Rotate_log_event::pack_info(Protocol *protocol)
{
- /* 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);
+ char *buf, *b_pos;
+ if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME))))
+ return;
+ b_pos= buf;
+ memcpy(buf, new_log_ident, ident_len);
+ b_pos+= ident_len;
+ b_pos= strmov(b_pos, ";pos=");
+ b_pos=longlong10_to_str(pos, b_pos, 10);
+ if (flags & LOG_EVENT_FORCED_ROTATE_F)
+ b_pos= strmov(b_pos ,"; forced by master");
+ protocol->store(buf, b_pos-buf, system_charset_info);
+ my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
+#endif
+/*****************************************************************************
-/*
- The master stopped. Clean up all temporary tables + locks that the
- master may have set.
+ Rotate_log_event::print()
- TODO
- - Remove all active user locks
-*/
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char buf[22];
+ if (short_form)
+ return;
-int Stop_log_event::exec_event(struct st_relay_log_info* rli)
+ 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)
{
- // do not clean up immediately after rotate event
- if (rli->master_log_pos > BIN_LOG_HEADER_SIZE)
+ // 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)
{
- close_temporary_tables(thd);
- cleanup_load_tmpdir();
+ ident_len = (uint)(event_len - OLD_HEADER_LEN);
+ pos = 4;
+ ident_offset = 0;
}
- /*
- 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;
+ 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
@@ -2007,9 +1768,9 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
RETURN VALUES
0 ok
- */
-
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
{
char* log_name = rli->master_log_name;
@@ -2025,8 +1786,111 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
flush_relay_log_info(rli);
DBUG_RETURN(0);
}
+#endif
+
+
+/*****************************************************************************
+ *****************************************************************************
+ Intvar_log_event methods
+
+ *****************************************************************************
+ ****************************************************************************/
+
+/*****************************************************************************
+
+ Intvar_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Intvar_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64], *pos;
+ pos= strmov(buf, get_var_type_name());
+ *(pos++)='=';
+ pos= longlong10_to_str(val, pos, -10);
+ protocol->store(buf, pos-buf, system_charset_info);
+}
+#endif
+
+/*****************************************************************************
+
+ 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()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
{
switch (type) {
@@ -2041,22 +1905,664 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
rli->inc_pending(get_event_len());
return 0;
}
+#endif
+
+/****************************************************************************
+ Rand_log_event methods
+****************************************************************************/
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Rand_log_event::pack_info(Protocol *protocol)
+{
+ 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);
+ protocol->store(buf1, (uint) (pos-buf1), system_charset_info);
+}
+#endif
+
+
+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);
+}
+
+
+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));
+}
+
+
+#ifdef MYSQL_CLIENT
+void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char llbuff[22],llbuff2[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, llbuff2));
+ fflush(file);
+}
+#endif // MYSQL_CLIENT
+
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Rand_log_event::exec_event(struct st_relay_log_info* rli)
{
- thd->rand.seed1 = (ulong) seed1;
- thd->rand.seed2 = (ulong) seed2;
+ thd->rand.seed1= (ulong) seed1;
+ thd->rand.seed2= (ulong) seed2;
rli->inc_pending(get_event_len());
return 0;
}
+#endif // !MYSQL_CLIENT
+
+
+/***************************************************************************
+ User_var_log_event methods
+***************************************************************************/
+
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void User_var_log_event::pack_info(Protocol* protocol)
+{
+ char *buf= 0;
+ uint val_offset= 2 + name_len;
+ uint event_len= val_offset;
+
+ if (is_null)
+ {
+ buf= my_malloc(val_offset + 5, MYF(MY_WME));
+ strmov(buf + val_offset, "NULL");
+ event_len= val_offset + 4;
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ double real_val;
+ float8get(real_val, val);
+ buf= my_malloc(val_offset + FLOATING_POINT_BUFFER, MYF(MY_WME));
+ event_len+= my_sprintf(buf + val_offset,
+ (buf + val_offset, "%.14g", real_val));
+ break;
+ case INT_RESULT:
+ buf= my_malloc(val_offset + 22, MYF(MY_WME));
+ event_len= longlong10_to_str(uint8korr(val), buf + val_offset,-10)-buf;
+ break;
+ case STRING_RESULT:
+ /*
+ This is correct as pack_info is used for SHOW BINLOG command
+ only. But be carefull this is may be incorrect in other cases as
+ string may contain \ and '.
+ */
+ event_len= val_offset + 2 + val_len;
+ buf= my_malloc(event_len, MYF(MY_WME));
+ buf[val_offset]= '\'';
+ memcpy(buf + val_offset + 1, val, val_len);
+ buf[val_offset + val_len + 1]= '\'';
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(1);
+ return;
+ }
+ }
+ buf[0]= '@';
+ buf[1+name_len]= '=';
+ memcpy(buf+1, name, name_len);
+ protocol->store(buf, event_len, system_charset_info);
+ my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+}
+#endif // !MYSQL_CLIENT
+
+
+User_var_log_event::User_var_log_event(const char* buf, bool old_format)
+ :Log_event(buf, old_format)
+{
+ buf+= (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN;
+ name_len= uint4korr(buf);
+ name= (char *) buf + UV_NAME_LEN_SIZE;
+ buf+= UV_NAME_LEN_SIZE + name_len;
+ is_null= (bool) *buf;
+ if (is_null)
+ {
+ type= STRING_RESULT;
+ charset_number= my_charset_bin.number;
+ val_len= 0;
+ val= 0;
+ }
+ else
+ {
+ type= (Item_result) buf[UV_VAL_IS_NULL];
+ charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE);
+ val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE);
+ val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE);
+ }
+}
+
+
+int User_var_log_event::write_data(IO_CACHE* file)
+{
+ char buf[UV_NAME_LEN_SIZE];
+ char buf1[UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE];
+ char buf2[8], *pos= buf2;
+ uint buf1_length;
+
+ int4store(buf, name_len);
+
+ if ((buf1[0]= is_null))
+ {
+ buf1_length= 1;
+ val_len= 0;
+ }
+ else
+ {
+ buf1[1]= type;
+ int4store(buf1 + 2, charset_number);
+ int4store(buf1 + 2 + UV_CHARSET_NUMBER_SIZE, val_len);
+ buf1_length= 10;
+
+ switch (type) {
+ case REAL_RESULT:
+ float8store(buf2, *(double*) val);
+ break;
+ case INT_RESULT:
+ int8store(buf2, *(longlong*) val);
+ break;
+ case STRING_RESULT:
+ pos= val;
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(1);
+ return 0;
+ }
+ }
+ return (my_b_safe_write(file, (byte*) buf, sizeof(buf)) ||
+ my_b_safe_write(file, (byte*) name, name_len) ||
+ my_b_safe_write(file, (byte*) buf1, buf1_length) ||
+ my_b_safe_write(file, (byte*) pos, val_len));
+}
+
+
+/*****************************************************************************
+
+ User_var_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void User_var_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ if (!short_form)
+ {
+ print_header(file);
+ fprintf(file, "\tUser_var\n");
+ }
+
+ fprintf(file, "SET @");
+ my_fwrite(file, (byte*) name, (uint) (name_len), MYF(MY_NABP | MY_WME));
+
+ if (is_null)
+ {
+ fprintf(file, ":=NULL;\n");
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ double real_val;
+ float8get(real_val, val);
+ fprintf(file, ":=%.14g;\n", real_val);
+ break;
+ case INT_RESULT:
+ char int_buf[22];
+ longlong10_to_str(uint8korr(val), int_buf, -10);
+ fprintf(file, ":=%s;\n", int_buf);
+ break;
+ case STRING_RESULT:
+ fprintf(file, ":='%s';\n", val);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(1);
+ return;
+ }
+ }
+ fflush(file);
+}
+#endif
+
+/*****************************************************************************
+
+ User_var_log_event::exec_event()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+int User_var_log_event::exec_event(struct st_relay_log_info* rli)
+{
+ Item *it= 0;
+ CHARSET_INFO *charset= get_charset(charset_number, MYF(0));
+ LEX_STRING user_var_name;
+ user_var_name.str= name;
+ user_var_name.length= name_len;
+ double real_val;
+ longlong int_val;
+
+ if (is_null)
+ {
+ it= new Item_null();
+ }
+ else
+ {
+ switch (type) {
+ case REAL_RESULT:
+ float8get(real_val, val);
+ it= new Item_real(real_val);
+ val= (char*) &real_val; // Pointer to value in native format
+ val_len= sizeof(real_val);
+ break;
+ case INT_RESULT:
+ int_val= (longlong) uint8korr(val);
+ it= new Item_int(int_val);
+ val= (char*) &int_val; // Pointer to value in native format
+ val_len= sizeof(int_val);
+ break;
+ case STRING_RESULT:
+ it= new Item_string(val, val_len, charset);
+ break;
+ case ROW_RESULT:
+ default:
+ DBUG_ASSERT(1);
+ return 0;
+ }
+ }
+ Item_func_set_user_var e(user_var_name, it);
+ e.fix_fields(thd, 0, 0);
+ e.update_hash(val, val_len, type, charset, Item::COER_NOCOLL);
+ free_root(&thd->mem_root,0);
+
+ rli->inc_pending(get_event_len());
+ return 0;
+}
+#endif // !MYSQL_CLIENT
+
+
+/****************************************************************************
+ Slave_log_event methods
+****************************************************************************/
+#ifdef HAVE_REPLICATION
+
+#ifndef MYSQL_CLIENT
+void Slave_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256], *pos;
+ pos= strmov(buf, "host=");
+ pos= strnmov(pos, master_host, HOSTNAME_LENGTH);
+ pos= strmov(pos, ",port=");
+ pos= int10_to_str((long) master_port, pos, 10);
+ pos= strmov(pos, ",log=");
+ pos= strmov(pos, master_log);
+ pos= strmov(pos, ",pos=");
+ pos= longlong10_to_str(master_pos, pos, 10);
+ protocol->store(buf, pos-buf, system_charset_info);
+}
+#endif // !MYSQL_CLIENT
+
+
+#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)
+{
+ DBUG_ENTER("Slave_log_event");
+ if (!rli->inited) // QQ When can this happen ?
+ DBUG_VOID_RETURN;
+
+ MASTER_INFO* mi = rli->mi;
+ // TODO: re-write this better without holding both locks at the same time
+ pthread_mutex_lock(&mi->data_lock);
+ pthread_mutex_lock(&rli->data_lock);
+ master_host_len = strlen(mi->host);
+ master_log_len = strlen(rli->master_log_name);
+ // on OOM, just do not initialize the structure and print the error
+ if ((mem_pool = (char*)my_malloc(get_data_size() + 1,
+ MYF(MY_WME))))
+ {
+ master_host = mem_pool + SL_MASTER_HOST_OFFSET ;
+ memcpy(master_host, mi->host, master_host_len + 1);
+ master_log = master_host + master_host_len + 1;
+ memcpy(master_log, rli->master_log_name, master_log_len + 1);
+ master_port = mi->port;
+ master_pos = rli->master_log_pos;
+ DBUG_PRINT("info", ("master_log: %s pos: %d", master_log,
+ (ulong) master_pos));
+ }
+ else
+ sql_print_error("Out of memory while recording slave event");
+ pthread_mutex_unlock(&rli->data_lock);
+ pthread_mutex_unlock(&mi->data_lock);
+ DBUG_VOID_RETURN;
+}
+#endif // !MYSQL_CLIENT
+
+
+Slave_log_event::~Slave_log_event()
+{
+ my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR));
+}
+
+
+#ifdef MYSQL_CLIENT
+void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
+{
+ char llbuff[22];
+ if (short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "Slave: master_host: '%s' master_port: %d \
+master_log: '%s' master_pos: %s\n",
+ master_host, master_port, master_log, llstr(master_pos, llbuff));
+}
+#endif // MYSQL_CLIENT
+
+
+int Slave_log_event::get_data_size()
+{
+ return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET;
+}
+
+
+int Slave_log_event::write_data(IO_CACHE* file)
+{
+ int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos);
+ int2store(mem_pool + SL_MASTER_PORT_OFFSET, master_port);
+ // log and host are already there
+ return my_b_safe_write(file, (byte*)mem_pool, get_data_size());
+}
+
+
+void Slave_log_event::init_from_mem_pool(int data_size)
+{
+ master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET);
+ master_port = uint2korr(mem_pool + SL_MASTER_PORT_OFFSET);
+ master_host = mem_pool + SL_MASTER_HOST_OFFSET;
+ master_host_len = strlen(master_host);
+ // safety
+ master_log = master_host + master_host_len + 1;
+ if (master_log > mem_pool + data_size)
+ {
+ master_host = 0;
+ return;
+ }
+ master_log_len = strlen(master_log);
+}
+
+
+Slave_log_event::Slave_log_event(const char* buf, int event_len)
+ :Log_event(buf,0),mem_pool(0),master_host(0)
+{
+ event_len -= LOG_EVENT_HEADER_LEN;
+ if (event_len < 0)
+ return;
+ if (!(mem_pool = (char*) my_malloc(event_len + 1, MYF(MY_WME))))
+ return;
+ memcpy(mem_pool, buf + LOG_EVENT_HEADER_LEN, event_len);
+ mem_pool[event_len] = 0;
+ init_from_mem_pool(event_len);
+}
+
+#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
+#endif /* HAVE_REPLICATION */
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ 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,
+ const char* db_arg, const char* table_name_arg,
+ List<Item>& fields_arg, enum enum_duplicates handle_dup,
+ char* block_arg, uint block_len_arg, bool using_trans)
+ :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup,
+ using_trans),
+ fake_base(0),block(block_arg),block_len(block_len_arg),
+ file_id(thd_arg->file_id = mysql_bin_log.next_file_id())
+{
+ sql_ex.force_new_format();
+}
+#endif // !MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Create_file_log_event::write_data_body()
+
+ ****************************************************************************/
+int Create_file_log_event::write_data_body(IO_CACHE* file)
+{
+ int res;
+ if ((res = Load_log_event::write_data_body(file)) || fake_base)
+ return res;
+ return (my_b_safe_write(file, (byte*) "", 1) ||
+ 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;
+ if ((res = Load_log_event::write_data_header(file)) || fake_base)
+ return res;
+ byte buf[CREATE_FILE_HEADER_LEN];
+ int4store(buf + CF_FILE_ID_OFFSET, file_id);
+ 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;
+ fake_base = 1; // pretend we are Load event
+ res = write(file);
+ fake_base = 0;
+ 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)
+{
+ int block_offset;
+ if (copy_log_event(buf,len,old_format))
+ return;
+ if (!old_format)
+ {
+ file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN +
+ + LOAD_HEADER_LEN + CF_FILE_ID_OFFSET);
+ // + 1 for \0 terminating fname
+ block_offset = (LOG_EVENT_HEADER_LEN + Load_log_event::get_data_size() +
+ CREATE_FILE_HEADER_LEN + 1);
+ if (len < block_offset)
+ return;
+ block = (char*)buf + block_offset;
+ block_len = len - block_offset;
+ }
+ else
+ {
+ sql_ex.force_new_format();
+ inited_from_old = 1;
+ }
+}
+
+/*****************************************************************************
+
+ Create_file_log_event::print()
+
+ ****************************************************************************/
+#ifdef MYSQL_CLIENT
+void Create_file_log_event::print(FILE* file, bool short_form,
+ char* last_db, bool enable_local)
+{
+ if (short_form)
+ {
+ if (enable_local && check_fname_outside_temp_buf())
+ Load_log_event::print(file, 1, last_db);
+ return;
+ }
+
+ if (enable_local)
+ {
+ if (!check_fname_outside_temp_buf())
+ fprintf(file, "#");
+ Load_log_event::print(file, 1, last_db);
+ fprintf(file, "#");
+ }
+
+ fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len);
+}
+void Create_file_log_event::print(FILE* file, bool short_form,
+ char* last_db)
+{
+ print(file,short_form,last_db,0);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Create_file_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Create_file_log_event::pack_info(Protocol *protocol)
+{
+ char buf[NAME_LEN*2 + 30 + 21*2], *pos;
+ pos= strmov(buf, "db=");
+ memcpy(pos, db, db_len);
+ pos+= db_len;
+ pos= strmov(pos, ";table=");
+ memcpy(pos, table_name, table_name_len);
+ pos+= table_name_len;
+ pos= strmov(pos, ";file_id=");
+ pos= int10_to_str((long) file_id, pos, 10);
+ pos= strmov(pos, ";block_len=");
+ pos= int10_to_str((long) block_len, pos, 10);
+ protocol->store(buf, pos-buf, system_charset_info);
+}
+#endif
+
+/*****************************************************************************
+
+ Create_file_log_event::exec_event()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
{
char fname_buf[FN_REFLEN+10];
@@ -2113,20 +2619,101 @@ err:
my_close(fd, MYF(0));
return error ? 1 : Log_event::exec_event(rli);
}
+#endif
-int Delete_file_log_event::exec_event(struct st_relay_log_info* rli)
+
+/*****************************************************************************
+ *****************************************************************************
+
+ 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,
+ bool using_trans)
+ :Log_event(thd_arg,0, using_trans), block(block_arg),
+ block_len(block_len_arg), file_id(thd_arg->file_id)
{
- 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
+
+/*****************************************************************************
+
+ Append_block_log_event ctor
+ ****************************************************************************/
+Append_block_log_event::Append_block_log_event(const char* buf, int len)
+ :Log_event(buf, 0),block(0)
+{
+ if ((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
+ return;
+ file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET);
+ block = (char*)buf + APPEND_BLOCK_EVENT_OVERHEAD;
+ 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];
+ int4store(buf + AB_FILE_ID_OFFSET, file_id);
+ return (my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
+ 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)
+{
+ if (short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "#Append_block: file_id: %d block_len: %d\n",
+ file_id, block_len);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Append_block_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Append_block_log_event::pack_info(Protocol *protocol)
+{
+ char buf[256];
+ uint length;
+ length= (uint) my_sprintf(buf,
+ (buf, ";file_id=%u;block_len=%u", file_id,
+ block_len));
+ protocol->store(buf, (int32) length, system_charset_info);
+}
+#endif
+
+/*****************************************************************************
+
+ Append_block_log_event::exec_event()
+
+ ****************************************************************************/
+#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
{
char fname[FN_REFLEN+10];
@@ -2154,6 +2741,189 @@ err:
my_close(fd, MYF(0));
return error ? error : Log_event::exec_event(rli);
}
+#endif
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ 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)
+{
+ if ((uint)len < DELETE_FILE_EVENT_OVERHEAD)
+ return;
+ 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];
+ int4store(buf + DF_FILE_ID_OFFSET, file_id);
+ 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)
+{
+ if (short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "#Delete_file: file_id=%u\n", file_id);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Delete_file_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Delete_file_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64];
+ uint length;
+ length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id));
+ protocol->store(buf, (int32) length, system_charset_info);
+}
+#endif
+
+/*****************************************************************************
+
+ Delete_file_log_event::exec_event()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(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
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ 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)
+ :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id)
+{
+}
+#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)
+{
+ if ((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
+ return;
+ 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];
+ int4store(buf + EL_FILE_ID_OFFSET, file_id);
+ 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)
+{
+ if (short_form)
+ return;
+ print_header(file);
+ fputc('\n', file);
+ fprintf(file, "#Exec_load: file_id=%d\n",
+ file_id);
+}
+#endif // MYSQL_CLIENT
+
+/*****************************************************************************
+
+ Execute_load_log_event::pack_info()
+
+ ****************************************************************************/
+#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
+void Execute_load_log_event::pack_info(Protocol *protocol)
+{
+ char buf[64];
+ uint length;
+ length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id));
+ protocol->store(buf, (int32) length, system_charset_info);
+}
+
+/*****************************************************************************
+
+ Execute_load_log_event::exec_event()
+
+ ****************************************************************************/
int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
{
@@ -2218,4 +2988,95 @@ err:
return error ? error : Log_event::exec_event(rli);
}
-#endif /* !MYSQL_CLIENT */
+#endif
+
+
+/*****************************************************************************
+ *****************************************************************************
+
+ 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;
+}
+
+
diff --git a/sql/log_event.h b/sql/log_event.h
index 5b9f30b3afd..62b5873fabb 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
@@ -157,6 +173,14 @@ struct sql_ex_info
#define RAND_SEED1_OFFSET 0
#define RAND_SEED2_OFFSET 8
+/* User_var event post-header */
+
+#define UV_VAL_LEN_SIZE 4
+#define UV_VAL_IS_NULL 1
+#define UV_VAL_TYPE_SIZE 1
+#define UV_NAME_LEN_SIZE 4
+#define UV_CHARSET_NUMBER_SIZE 4
+
/* Load event post-header */
#define L_THREAD_ID_OFFSET 0
@@ -196,15 +220,17 @@ struct sql_ex_info
#define BINLOG_MAGIC "\xfe\x62\x69\x6e"
-#define LOG_EVENT_TIME_F 0x1
-#define LOG_EVENT_FORCED_ROTATE_F 0x2
+#define LOG_EVENT_TIME_F 0x1
+#define LOG_EVENT_FORCED_ROTATE_F 0x2
+#define LOG_EVENT_THREAD_SPECIFIC_F 0x4 /* query depends on thread
+ (for example: TEMPORARY TABLE) */
enum Log_event_type
{
START_EVENT = 1, QUERY_EVENT =2, STOP_EVENT=3, ROTATE_EVENT = 4,
INTVAR_EVENT=5, LOAD_EVENT=6, SLAVE_EVENT=7, CREATE_FILE_EVENT=8,
APPEND_BLOCK_EVENT=9, EXEC_LOAD_EVENT=10, DELETE_FILE_EVENT=11,
- NEW_LOAD_EVENT=12, RAND_EVENT=13
+ NEW_LOAD_EVENT=12, RAND_EVENT=13, USER_VAR_EVENT=14
};
enum Int_event_type
@@ -221,6 +247,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:
@@ -244,10 +277,12 @@ public:
static int read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock);
void set_log_pos(MYSQL_LOG* log);
- virtual void pack_info(String* packet);
- int net_send(THD* thd, const char* log_name, my_off_t pos);
static void init_show_field_list(List<Item>* field_list);
+#ifdef HAVE_REPLICATION
+ int net_send(Protocol *protocol, const char* log_name, my_off_t pos);
+ virtual void pack_info(Protocol *protocol);
virtual int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
virtual const char* get_db()
{
return thd ? thd->db : 0;
@@ -304,6 +339,13 @@ public:
};
+/*****************************************************************************
+
+ Query Log Event class
+
+ Logs SQL queries
+
+ ****************************************************************************/
class Query_log_event: public Log_event
{
protected:
@@ -325,8 +367,10 @@ public:
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
bool using_trans);
const char* get_db() { return db; }
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -353,7 +397,13 @@ public:
}
};
+#ifdef HAVE_REPLICATION
+
+/*****************************************************************************
+
+ Slave Log Event class
+ ****************************************************************************/
class Slave_log_event: public Log_event
{
protected:
@@ -369,7 +419,7 @@ public:
#ifndef MYSQL_CLIENT
Slave_log_event(THD* thd_arg, struct st_relay_log_info* rli);
- void pack_info(String* packet);
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
@@ -383,6 +433,14 @@ public:
int write_data(IO_CACHE* file );
};
+#endif /* HAVE_REPLICATION */
+
+
+/*****************************************************************************
+
+ Load Log Event class
+
+ ****************************************************************************/
class Load_log_event: public Log_event
{
protected:
@@ -404,6 +462,13 @@ public:
uint32 skip_lines;
sql_ex_info sql_ex;
+ /* fname doesn't point to memory inside Log_event::temp_buf */
+ void set_fname_outside_temp_buf(const char *afname, uint alen)
+ {fname=afname;fname_len=alen;}
+ /* fname doesn't point to memory inside Log_event::temp_buf */
+ int check_fname_outside_temp_buf()
+ {return fname<temp_buf || fname>temp_buf+cached_event_len;}
+
#ifndef MYSQL_CLIENT
String field_lens_buf;
String fields_buf;
@@ -413,14 +478,16 @@ public:
List<Item>& fields_arg, enum enum_duplicates handle_dup,
bool using_trans);
void set_fields(List<Item> &fields_arg);
- void pack_info(String* packet);
const char* get_db() { return db; }
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli)
{
return exec_event(thd->slave_net,rli,0);
}
int exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -449,6 +516,11 @@ public:
extern char server_version[SERVER_VERSION_LENGTH];
+/*****************************************************************************
+
+ Start Log Event class
+
+ ****************************************************************************/
class Start_log_event: public Log_event
{
public:
@@ -462,8 +534,10 @@ public:
created = (uint32) when;
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
}
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -480,6 +554,13 @@ public:
};
+/*****************************************************************************
+
+ Intvar Log Event class
+
+ Logs special variables such as auto_increment values
+
+ ****************************************************************************/
class Intvar_log_event: public Log_event
{
public:
@@ -490,8 +571,10 @@ public:
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
:Log_event(),val(val_arg),type(type_arg)
{}
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -500,15 +583,17 @@ public:
~Intvar_log_event() {}
Log_event_type get_type_code() { return INTVAR_EVENT;}
const char* get_var_type_name();
- int get_data_size() { return sizeof(type) + sizeof(val);}
+ int get_data_size() { return 9; /* sizeof(type) + sizeof(val) */;}
int write_data(IO_CACHE* file);
bool is_valid() { return 1; }
};
/*****************************************************************************
- *
- * Rand log event class
- *
+
+ Rand Log Event class
+
+ Logs random seed used by the next RAND()
+
****************************************************************************/
class Rand_log_event: public Log_event
{
@@ -520,8 +605,10 @@ class Rand_log_event: public Log_event
Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg)
:Log_event(thd_arg,0,0),seed1(seed1_arg),seed2(seed2_arg)
{}
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -529,16 +616,63 @@ class Rand_log_event: public Log_event
Rand_log_event(const char* buf, bool old_format);
~Rand_log_event() {}
Log_event_type get_type_code() { return RAND_EVENT;}
- int get_data_size() { return sizeof(ulonglong) * 2; }
+ int get_data_size() { return 16; /* sizeof(ulonglong) * 2*/ }
int write_data(IO_CACHE* file);
bool is_valid() { return 1; }
};
+/*****************************************************************************
+
+ User var Log Event class
+
+ ****************************************************************************/
+class User_var_log_event: public Log_event
+{
+public:
+ char *name;
+ uint name_len;
+ char *val;
+ ulong val_len;
+ Item_result type;
+ uint charset_number;
+ bool is_null;
+#ifndef MYSQL_CLIENT
+ User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
+ char *val_arg, ulong val_len_arg, Item_result type_arg,
+ uint charset_number_arg)
+ :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
+ val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
+ { is_null= !val; }
+ void pack_info(Protocol* protocol);
+ int exec_event(struct st_relay_log_info* rli);
+#else
+ void print(FILE* file, bool short_form = 0, char* last_db = 0);
+#endif
+
+ User_var_log_event(const char* buf, bool old_format);
+ ~User_var_log_event() {}
+ Log_event_type get_type_code() { return USER_VAR_EVENT;}
+ int get_data_size()
+ {
+ return (is_null ? UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL :
+ UV_NAME_LEN_SIZE + name_len + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE +
+ UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE + val_len);
+ }
+ int write_data(IO_CACHE* file);
+ bool is_valid() { return 1; }
+};
+
+/*****************************************************************************
+
+ Stop Log Event class
+
+ ****************************************************************************/
+#ifdef HAVE_REPLICATION
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,7 +688,16 @@ public:
bool is_valid() { return 1; }
};
+#endif /* HAVE_REPLICATION */
+
+
+/*****************************************************************************
+
+ Rotate Log Event class
+
+ This will be depricated when we move to using sequence ids.
+ ****************************************************************************/
class Rotate_log_event: public Log_event
{
public:
@@ -570,8 +713,10 @@ public:
pos(pos_arg),ident_len(ident_len_arg ? ident_len_arg :
(uint) strlen(new_log_ident_arg)), alloced(0)
{}
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -590,6 +735,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:
@@ -612,10 +762,13 @@ public:
enum enum_duplicates handle_dup,
char* block_arg, uint block_len_arg,
bool using_trans);
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form, char* last_db, bool enable_local);
#endif
Create_file_log_event(const char* buf, int event_len, bool old_format);
@@ -647,6 +800,11 @@ public:
};
+/*****************************************************************************
+
+ Append Block Log Event class
+
+ ****************************************************************************/
class Append_block_log_event: public Log_event
{
public:
@@ -657,8 +815,10 @@ public:
#ifndef MYSQL_CLIENT
Append_block_log_event(THD* thd, char* block_arg,
uint block_len_arg, bool using_trans);
+#ifdef HAVE_REPLICATION
int exec_event(struct st_relay_log_info* rli);
- void pack_info(String* packet);
+ void pack_info(Protocol* protocol);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -671,7 +831,11 @@ public:
int write_data(IO_CACHE* file);
};
+/*****************************************************************************
+
+ Delete File Log Event class
+ ****************************************************************************/
class Delete_file_log_event: public Log_event
{
public:
@@ -679,8 +843,10 @@ public:
#ifndef MYSQL_CLIENT
Delete_file_log_event(THD* thd, bool using_trans);
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
@@ -693,6 +859,11 @@ public:
int write_data(IO_CACHE* file);
};
+/*****************************************************************************
+
+ Execute Load Log Event class
+
+ ****************************************************************************/
class Execute_load_log_event: public Log_event
{
public:
@@ -700,8 +871,10 @@ public:
#ifndef MYSQL_CLIENT
Execute_load_log_event(THD* thd, bool using_trans);
- void pack_info(String* packet);
+#ifdef HAVE_REPLICATION
+ void pack_info(Protocol* protocol);
int exec_event(struct st_relay_log_info* rli);
+#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif
diff --git a/sql/mf_iocache.cc b/sql/mf_iocache.cc
index c79317cfeb3..b7e2a803e42 100644
--- a/sql/mf_iocache.cc
+++ b/sql/mf_iocache.cc
@@ -32,12 +32,12 @@
#define MAP_TO_USE_RAID
#include "mysql_priv.h"
+#ifdef HAVE_REPLICATION
#ifdef HAVE_AIOWAIT
#include <mysys_err.h>
#include <errno.h>
static void my_aiowait(my_aio_result *result);
#endif
-#include <assert.h>
extern "C" {
@@ -85,3 +85,6 @@ int _my_b_net_read(register IO_CACHE *info, byte *Buffer,
}
} /* extern "C" */
+#endif /* HAVE_REPLICATION */
+
+
diff --git a/sql/mini_client.cc b/sql/mini_client.cc
index 38b3c22b91b..db3a51712f2 100644
--- a/sql/mini_client.cc
+++ b/sql/mini_client.cc
@@ -23,6 +23,8 @@
*/
#include <my_global.h>
+#ifdef HAVE_EXTERNAL_CLIENT
+
/* my_pthread must be included early to be able to fix things */
#if defined(THREAD)
#include <my_pthread.h> /* because of signal() */
@@ -40,6 +42,7 @@
#include "mysql_version.h"
#include "mysqld_error.h"
#include "errmsg.h"
+#include <assert.h>
#if defined( OS2) && defined(MYSQL_SERVER)
#undef ER
@@ -86,7 +89,9 @@ static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields,
-#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
+#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \
+ CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION)
+
#if defined(MSDOS) || defined(__WIN__)
#define perror(A)
@@ -124,7 +129,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));
@@ -325,7 +330,7 @@ static int mc_sock_connect(my_socket s, const struct sockaddr *name,
** or packet is an error message
*****************************************************************************/
-ulong
+ulong
mc_net_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
@@ -430,7 +435,7 @@ my_bool mc_mysql_reconnect(MYSQL *mysql)
-int
+int
mc_simple_command(MYSQL *mysql,enum enum_server_command command,
const char *arg, uint length, my_bool skipp_check)
{
@@ -450,21 +455,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));
@@ -480,13 +485,14 @@ mc_simple_command(MYSQL *mysql,enum enum_server_command command,
}
-MYSQL *
+MYSQL *
mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag,
uint net_read_timeout)
{
char buff[NAME_LEN+USERNAME_LENGTH+100],*end,*host_info;
+ char password_hash[SCRAMBLE41_LENGTH];
my_socket sock;
ulong ip_addr;
struct sockaddr_in sock_addr;
@@ -509,7 +515,6 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
user ? user : "(Null)",
net_read_timeout,
(uint) slave_net_timeout));
-
net->vio = 0; /* If something goes wrong */
mysql->charset=default_charset_info; /* Set character set */
if (!port)
@@ -664,7 +669,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
vio_poll_read(net->vio, mysql->options.connect_timeout))
{
net->last_errno= CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ strmov(net->last_error,ER(net->last_errno));
goto error;
}
if ((pkt_length=mc_net_safe_read(mysql)) == packet_error)
@@ -779,7 +784,7 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ strmov(net->last_error,ER(net->last_errno));
goto error;
}
/* Do the SSL layering. */
@@ -803,22 +808,105 @@ mc_mysql_connect(MYSQL *mysql,const char *host, const char *user,
}
DBUG_PRINT("info",("user: %s",buff+5));
- end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
- (my_bool) (mysql->protocol_version == 9));
- if (db)
+
+ /*
+ We always start with old type handshake the only difference is message sent
+ If server handles secure connection type we'll not send the real scramble
+ */
+ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+ {
+ if (passwd[0])
+ {
+ /* Prepare false scramble */
+ end=strend(buff+5)+1;
+ bfill(end, SCRAMBLE_LENGTH, 'x');
+ end+=SCRAMBLE_LENGTH;
+ *end=0;
+ }
+ else /* For empty password*/
+ {
+ end=strend(buff+5)+1;
+ *end=0; /* Store zero length scramble */
+ }
+ }
+ else
+ {
+ /*
+ Real scramble is only sent to old servers. This can be blocked
+ by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
+ */
+ end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
+ (my_bool) (mysql->protocol_version == 9));
+
+ }
+ /* Add database if needed */
+ if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
end=strmake(end+1,db,NAME_LEN);
mysql->db=my_strdup(db,MYF(MY_WME));
db=0;
}
+ /* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
- strmov(net->last_error,ER(net->last_errno));
+ strmov(net->last_error,ER(net->last_errno));
goto error;
}
- if (mc_net_safe_read(mysql) == packet_error)
+
+ /* We shall only query sever if it expect us to do so */
+
+ if ( (pkt_length=mc_net_safe_read(mysql)) == packet_error)
goto error;
+
+ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
+ {
+ /* This should always happen with new server unless empty password */
+ if (pkt_length==24 && net->read_pos[0])
+ /* OK/Error message has zero as the first character */
+ {
+ /* Old passwords will have zero at the first byte of hash */
+ if (net->read_pos[0] != '*')
+ {
+ /* Build full password hash as it is required to decode scramble */
+ password_hash_stage1(buff, passwd);
+ /* Store copy as we'll need it later */
+ memcpy(password_hash,buff,SCRAMBLE41_LENGTH);
+ /* Finally hash complete password using hash we got from server */
+ password_hash_stage2(password_hash,(char*)net->read_pos);
+ /* Decypt and store scramble 4 = hash for stage2 */
+ password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,
+ SCRAMBLE41_LENGTH);
+ mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
+ /* Encode scramble with password. Recycle buffer */
+ password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
+ }
+ else
+ {
+ /* Create password to decode scramble */
+ create_key_from_old_password(passwd,password_hash);
+ /* Decypt and store scramble 4 = hash for stage2 */
+ password_crypt((char*)net->read_pos+4,mysql->scramble_buff,password_hash,
+ SCRAMBLE41_LENGTH);
+ mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
+ /* Finally scramble decoded scramble with password */
+ scramble(buff, mysql->scramble_buff, passwd,0);
+ }
+ /* Write second package of authentication */
+ if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
+ {
+ net->last_errno= CR_SERVER_LOST;
+ strmov(net->last_error,ER(net->last_errno));
+ goto error;
+ }
+ /* Read What server thinks about out new auth message report */
+ if (mc_net_safe_read(mysql) == packet_error)
+ goto error;
+ }
+ }
+
+ /* End of authentication part of handshake */
+
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
net->compress=1;
DBUG_PRINT("exit",("Mysql handler: %lx",mysql));
@@ -845,7 +933,7 @@ error:
** NB! Errors are not reported until you do mysql_real_connect.
**************************************************************************
*/
-int
+int
mysql_ssl_clear(MYSQL *mysql)
{
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
@@ -870,7 +958,7 @@ mysql_ssl_clear(MYSQL *mysql)
** If handle is alloced by mysql connect free it.
*************************************************************************/
-void
+void
mc_mysql_close(MYSQL *mysql)
{
DBUG_ENTER("mysql_close");
@@ -1032,18 +1120,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;
@@ -1391,3 +1480,5 @@ MYSQL_RES *mc_mysql_store_result(MYSQL *mysql)
mysql->fields=0; /* fields is now in result */
DBUG_RETURN(result); /* Data fetched */
}
+
+#endif /* HAVE_EXTERNAL_CLIENT */
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index c6e205f4729..61c5d308b4e 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -24,6 +24,7 @@
#include <thr_lock.h>
#include <my_base.h> /* Needed by field.h */
#include <my_bitmap.h>
+#include <assert.h>
#ifdef __EMX__
#undef write /* remove pthread.h macro definition for EMX */
@@ -53,12 +54,24 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
#define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1))
#define all_bits_set(A,B) ((A) & (B) != (B))
+#ifndef LL
+#ifdef HAVE_LONG_LONG
+#define LL(A) A ## LL
+#else
+#define LL(A) A ## L
+#endif
+#endif
+
+#define files_charset_info system_charset_info
+
/***************************************************************************
Configuration parameters
****************************************************************************/
#define ACL_CACHE_SIZE 256
-#define HASH_PASSWORD_LENGTH 16
+/* Password lengh for 4.1 version previous versions had 16 bytes password hash */
+#define HASH_PASSWORD_LENGTH 45
+#define HASH_OLD_PASSWORD_LENGTH 16
#define HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32
@@ -192,6 +205,16 @@ 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 MODE_NO_KEY_OPTIONS 4096
+#define MODE_NO_TABLE_OPTIONS 8192
+#define MODE_NO_FIELD_OPTIONS 16384
+#define MODE_MYSQL323 32768
+#define MODE_MYSQL40 65536
#define RAID_BLOCK_SIZE 1024
@@ -270,8 +293,10 @@ inline THD *_current_thd(void)
#include "handler.h"
#include "table.h"
#include "field.h" /* Field definitions */
+#include "protocol.h"
#include "sql_udf.h"
#include "item.h"
+typedef compare_func_creator (*chooser_compare_func_creator)(bool invert);
#include "sql_class.h"
#include "opt_range.h"
@@ -302,22 +327,31 @@ 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);
+int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
+ my_bool drop_temporary);
int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
- bool log_query);
+ bool drop_temporary, bool log_query);
int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
- bool if_exists,
+ bool if_exists, bool drop_temporary,
bool log_query);
int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
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);
+bool is_update_query(enum enum_sql_command command);
+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);
+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);
@@ -326,7 +360,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);
@@ -356,45 +390,38 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt);
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,
- const char *info=0);
-void send_eof(NET *net,bool no_flush=0);
-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);
-char *net_store_data(char *to,int32 from);
-char *net_store_data(char *to,longlong from);
-
-bool net_store_null(String *packet);
-bool net_store_data(String *packet,uint32 from);
-bool net_store_data(String *packet,longlong from);
-bool net_store_data(String *packet,const char *from);
-bool net_store_data(String *packet,const char *from,uint length);
-bool net_store_data(String *packet,struct tm *tmp);
-bool net_store_data(String* packet, I_List<i_string>* str_list);
-bool net_store_data(String *packet,CONVERT *convert, const char *from,
- uint length);
-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_ref_array(THD *thd, Item ***rref_pointer_array, uint elements);
+int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, List <Item> &all_fields, ORDER *order);
+int setup_group(THD *thd, Item **ref_pointer_array, 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);
+int mysql_select(THD *thd, Item ***rref_pointer_array,
+ TABLE_LIST *tables, uint wild_num, List<Item> &list,
+ COND *conds, uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc_param, ulong select_type,
+ select_result *result, SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex, bool tables_and_fields_initied);
+void free_underlaid_joins(THD *thd, SELECT_LEX *select);
+void fix_tables_pointers(SELECT_LEX *select_lex);
+void fix_tables_pointers(SELECT_LEX_UNIT *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,
+ SELECT_LEX_UNIT *unit, bool tables_and_fields_initied);
+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 ***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,
@@ -407,11 +434,14 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
- ORDER *order,
+ uint order_num, ORDER *order,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
- bool simple_alter=0);
+ bool simple_alter=0);
+int mysql_create_like_table(THD *thd, TABLE_LIST *table,
+ HA_CREATE_INFO *create_info,
+ Table_ident *src_table);
bool mysql_rename_table(enum db_type base,
const char *old_db,
const char * old_name,
@@ -422,15 +452,17 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys);
int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &values,COND *conds,
- ORDER *order, ha_rows limit,
+ List<Item> &values,COND *conds,
+ uint order_num, ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates);
int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
List<Item> *fields, List<Item> *values,
COND *conds, ulong options,
- enum enum_duplicates handle_duplicates);
+ enum enum_duplicates handle_duplicates,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex);
int mysql_insert(THD *thd,TABLE_LIST *table,List<Item> &fields,
- List<List_item> &values, enum_duplicates flag);
+ List<List_item> &values, List<Item> &update_fields,
+ List<Item> &update_values, enum_duplicates flag);
void kill_delayed_threads(void);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, ORDER *order,
ha_rows rows, ulong options);
@@ -449,13 +481,15 @@ 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_ident *item, TABLE_LIST *tables,
+ TABLE_LIST **where, bool report_error);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
#ifdef HAVE_OPENSSL
-struct st_des_keyblock
-{
- des_cblock key1, key2, key3;
+struct st_des_keyblock
+{
+ des_cblock key1, key2, key3;
};
struct st_des_keyschedule
{
@@ -472,7 +506,7 @@ void free_des_key_file();
/* 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);
@@ -484,12 +518,36 @@ 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, 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(void *not_used, PREP_STMT *stmt, ulong *key);
+void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used);
+bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length);
+void mysql_stmt_execute(THD *thd, char *packet);
+void mysql_stmt_free(THD *thd, char *packet);
+void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
+int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
+ List<Item> &values, ulong counter);
+
+/* sql_error.cc */
+void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code,
+ const char *msg);
+void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *format, ...);
+void mysql_reset_errors(THD *thd);
+my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show);
/* sql_handler.cc */
int mysql_ha_open(THD *thd, TABLE_LIST *tables);
@@ -500,18 +558,13 @@ int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
/* sql_base.cc */
void set_item_name(Item *item,char *pos,uint length);
-bool add_field_to_list(char *field_name, enum enum_field_types type,
+bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
char *length, char *decimal,
- uint type_modifier, Item *default_value,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,
- ulong table_option,
- 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);
+bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
void add_join_on(TABLE_LIST *b,Item *expr);
void add_join_natural(TABLE_LIST *a,TABLE_LIST *b);
bool add_proc_to_list(THD *thd, Item *item);
@@ -519,17 +572,23 @@ 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);
-bool insert_fields(THD *thd,TABLE_LIST *tables,
+enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
+ IGNORE_ERRORS};
+extern const Item **not_found_item;
+Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
+ 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);
bool setup_tables(TABLE_LIST *tables);
-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_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
+ List<Item> *sum_func_list, uint wild_num);
+int setup_fields(THD *thd, Item** ref_pointer_array, 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);
@@ -537,13 +596,16 @@ int lock_tables(THD *thd,TABLE_LIST *tables);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list);
bool rm_temporary_table(enum db_type base, char *path);
-bool send_fields(THD *thd,List<Item> &item,uint send_field_count);
void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr);
-void close_thread_tables(THD *thd,bool locked=0);
-bool close_thread_table(THD *thd, TABLE **table_ptr);
+void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
void close_temporary_tables(THD *thd);
+TABLE_LIST * find_table_in_list(TABLE_LIST *table,
+ const char *db_name, const char *table_name);
+TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1);
@@ -580,7 +642,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 */
@@ -602,8 +664,6 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
const char *index_file_name,
enum_log_type type, bool read_append = 0,
bool no_auto_events = 0);
-/* mysqld.cc */
-void clear_error_message(THD *thd);
/*
External variables
@@ -611,8 +671,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 */
@@ -652,6 +713,7 @@ extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size;
extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
extern ulong specialflag, current_pid;
+extern ulong expire_logs_days;
extern uint test_flags,select_errors,ha_open_options;
extern uint protocol_version,dropping_tables;
@@ -667,18 +729,21 @@ extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names;
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_enable_named_pipe;
+extern my_bool opt_old_passwords, use_old_passwords;
+extern char *shared_memory_base_name;
+extern bool opt_enable_shared_memory;
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;
@@ -686,6 +751,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;
extern struct rand_struct sql_rand;
@@ -732,7 +801,7 @@ void unlock_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,
@@ -757,6 +826,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time);
longlong str_to_datetime(const char *str,uint length,bool fuzzy_date);
timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,
bool fuzzy_date);
+void localtime_to_TIME(TIME *to, struct tm *from);
int test_if_number(char *str,int *res,bool allow_wildcards);
void change_byte(byte *,uint,char,char);
@@ -765,9 +835,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);
@@ -780,7 +850,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);
@@ -788,12 +858,8 @@ int rename_file_ext(const char * from,const char * to,const char * ext);
bool check_db_name(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);
+char *get_field(MEM_ROOT *mem, Field *field);
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
/* from hostname.cc */
struct in_addr;
@@ -812,31 +878,44 @@ 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);
/* log.cc */
bool flush_error_log(void);
/* Some inline functions for more speed */
-inline bool add_item_to_list(Item *item)
+inline bool add_item_to_list(THD *thd, Item *item)
{
- return current_lex->select->item_list.push_back(item);
+ return thd->lex.current_select->add_item_to_list(thd, item);
}
-inline bool add_value_to_list(Item *value)
+
+inline bool add_value_to_list(THD *thd, Item *value)
{
- return current_lex->value_list.push_back(value);
+ return thd->lex.value_list.push_back(value);
}
-inline bool add_order_to_list(Item *item,bool asc)
+
+inline bool add_order_to_list(THD *thd, Item *item, bool asc)
{
- return add_to_list(current_lex->select->order_list,item,asc);
+ return thd->lex.current_select->add_order_to_list(thd, item, asc);
}
-inline bool add_group_to_list(Item *item,bool asc)
+
+inline bool add_group_to_list(THD *thd, Item *item, bool asc)
{
- return add_to_list(current_lex->select->group_list,item,asc);
+ return thd->lex.current_select->add_group_to_list(thd, item, asc);
}
+
inline void mark_as_null_row(TABLE *table)
{
table->null_row=1;
table->status|=STATUS_NULL_ROW;
bfill(table->null_flags,table->null_bytes,255);
}
+
+compare_func_creator comp_eq_creator(bool invert);
+compare_func_creator comp_ge_creator(bool invert);
+compare_func_creator comp_gt_creator(bool invert);
+compare_func_creator comp_le_creator(bool invert);
+compare_func_creator comp_lt_creator(bool invert);
+compare_func_creator comp_ne_creator(bool invert);
+
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index e22d9b1dc67..e9026eb5b00 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -32,7 +32,8 @@
#include <nisam.h>
#include <thr_alarm.h>
#include <ft_global.h>
-#include <assert.h>
+
+#define mysqld_charset &my_charset_latin1
#ifndef DBUG_OFF
#define ONE_THREAD
@@ -57,7 +58,7 @@ char pstack_file_name[80];
#if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ)
#define HAVE_CLOSE_SERVER_SOCK 1
-#endif
+#endif
extern "C" { // Because of SCO 3.2V4.2
#include <errno.h>
@@ -191,10 +192,10 @@ 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;
#endif
#ifdef __WIN__
+static pthread_cond_t COND_handler_count;
+static uint handler_count;
static bool start_mode=0, use_opt_args;
static int opt_argc;
static char **opt_argv;
@@ -257,6 +258,8 @@ SHOW_COMP_OPTION have_crypt=SHOW_OPTION_YES;
SHOW_COMP_OPTION have_crypt=SHOW_OPTION_NO;
#endif
+const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"};
+
bool opt_large_files= sizeof(my_off_t) > 4;
#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
#define GET_HA_ROWS GET_ULL
@@ -277,7 +280,7 @@ my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted
If set, some standard measures to enforce slave data integrity will not
be performed
*/
-my_bool opt_reckless_slave = 0;
+my_bool opt_reckless_slave = 0;
ulong back_log, connect_timeout, concurrency;
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30];
@@ -305,7 +308,8 @@ static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool lower_case_table_names, opt_old_rpl_compat;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
-my_bool opt_log_slave_updates= 0, opt_console= 0;
+my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
+my_bool opt_console= 0;
volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
@@ -362,6 +366,15 @@ ulong query_cache_size=0;
ulong query_cache_limit=0;
Query_cache query_cache;
#endif
+arg_cmp_func Arg_comparator::comparator_matrix[4][2] =
+{{&Arg_comparator::compare_string, &Arg_comparator::compare_e_string},
+ {&Arg_comparator::compare_real, &Arg_comparator::compare_e_real},
+ {&Arg_comparator::compare_int, &Arg_comparator::compare_e_int},
+ {&Arg_comparator::compare_row, &Arg_comparator::compare_e_row}};
+#ifdef HAVE_SMEM
+char *shared_memory_base_name=default_shared_memory_base_name;
+bool opt_enable_shared_memory = 0;
+#endif
volatile ulong cached_thread_count=0;
@@ -371,7 +384,7 @@ my_string master_user = (char*) "test", master_password = 0, master_host=0,
relay_log_info_file = (char*) "relay-log.info",
master_ssl_key=0, master_ssl_cert=0, master_ssl_capath=0, master_ssl_cipher=0;
my_string report_user = 0, report_password = 0, report_host=0;
-
+
const char *localhost=LOCAL_HOST;
const char *delayed_user="DELAYED";
uint master_port = MYSQL_PORT, master_connect_retry = 60;
@@ -400,7 +413,8 @@ ulong max_connections,max_insert_delayed_threads,max_used_connections,
max_connect_errors, max_user_connections = 0;
ulong thread_id=1L,current_pid;
ulong slow_launch_threads = 0;
-
+ulong expire_logs_days = 0;
+
char mysql_real_data_home[FN_REFLEN],
language[LIBLEN],reg_ext[FN_EXTLEN],
mysql_charsets_dir[FN_REFLEN], *charsets_list,
@@ -423,7 +437,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;
@@ -431,10 +446,14 @@ double log_10[32]; /* 10 potences */
I_List<THD> threads,thread_cache;
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", "DB2", "SAPDB", "NO_KEY_OPTIONS",
+ "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40",
+ NullS
+};
TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"",
sql_mode_names};
@@ -443,15 +462,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;
@@ -477,6 +495,7 @@ static void start_signal_handler(void);
extern "C" pthread_handler_decl(signal_hand, arg);
static void set_options(void);
static void get_options(int argc,char **argv);
+static int init_thread_environment();
static char *get_relative_path(const char *path);
static void fix_paths(void);
extern "C" pthread_handler_decl(handle_connections_sockets,arg);
@@ -487,6 +506,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);
@@ -495,6 +517,7 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib);
static void clean_up(bool print_message);
static void clean_up_mutexes(void);
+#ifndef EMBEDDED_LIBRARY
/****************************************************************************
** Code to end mysqld
****************************************************************************/
@@ -568,7 +591,7 @@ static void close_connections(void)
{
HANDLE temp;
DBUG_PRINT( "quit", ("Closing named pipes") );
-
+
/* Create connection to the handle named pipe handler to break the loop */
if ((temp = CreateFile(szPipeName,
GENERIC_READ | GENERIC_WRITE,
@@ -666,6 +689,7 @@ static void close_connections(void)
DBUG_PRINT("quit",("close_connections thread"));
DBUG_VOID_RETURN;
}
+#endif /*EMBEDDED_LIBRARY*/
static void close_server_sock()
@@ -684,7 +708,7 @@ static void close_server_sock()
The following code is disabled for normal systems as it causes MySQL
to hang on AIX 4.3 during shutdown
*/
- DBUG_PRINT("info",("calling closesocket on TCP/IP socket"));
+ DBUG_PRINT("info",("calling closesocket on TCP/IP socket"));
VOID(closesocket(tmp_sock));
#endif
}
@@ -716,7 +740,7 @@ void kill_mysql(void)
#ifdef SIGNALS_DONT_BREAK_READ
abort_loop=1; // Break connection loops
close_server_sock(); // Force accept to wake up
-#endif
+#endif
#if defined(__WIN__)
#if !defined(EMBEDDED_LIBRARY)
@@ -754,11 +778,10 @@ void kill_mysql(void)
(void*) 0))
sql_print_error("Error: Can't create thread to kill server");
}
-#endif
+#endif
DBUG_VOID_RETURN;
}
-
/* Force server down. kill all connections and threads and exit */
#if defined(OS2) || defined(__NETWARE__)
@@ -774,7 +797,7 @@ static void __cdecl kill_server(int sig_ptr)
{
int sig=(int) (long) sig_ptr; // This is passed a int
DBUG_ENTER("kill_server");
-
+#ifndef EMBEDDED_LIBRARY
// if there is a signal during the kill in progress, ignore the other
if (kill_in_progress) // Safety
RETURN_FROM_KILL_SERVER;
@@ -794,13 +817,13 @@ static void __cdecl kill_server(int sig_ptr)
unireg_abort(1); /* purecov: inspected */
else
unireg_end();
-
#ifdef __NETWARE__
pthread_join(select_thread, NULL); // wait for main thread
#else
pthread_exit(0); /* purecov: deadcode */
#endif /* __NETWARE__ */
+#endif /* EMBEDDED_LIBRARY */
RETURN_FROM_KILL_SERVER;
}
@@ -891,8 +914,10 @@ void clean_up(bool print_message)
mysql_update_log.cleanup();
mysql_bin_log.cleanup();
+#ifdef HAVE_REPLICATION
if (use_slave_mask)
bitmap_free(&slave_error_mask);
+#endif
acl_free(1);
grant_free();
query_cache_destroy();
@@ -913,13 +938,17 @@ 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);
+#ifdef HAVE_REPLICATION
my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR));
+#endif
x_free(opt_bin_logname);
x_free(opt_relay_logname);
bitmap_free(&temp_pool);
free_max_user_conn();
+#ifdef HAVE_REPLICATION
end_slave_list();
+#endif
#ifdef HAVE_OPENSSL
free_des_key_file();
#endif /* HAVE_OPENSSL */
@@ -954,7 +983,7 @@ static void clean_up_mutexes()
{
(void) pthread_mutex_destroy(&LOCK_mysql_create_db);
(void) pthread_mutex_destroy(&LOCK_Acl);
- (void) pthread_mutex_destroy(&LOCK_grant);
+ (void) rwlock_destroy(&LOCK_grant);
(void) pthread_mutex_destroy(&LOCK_open);
(void) pthread_mutex_destroy(&LOCK_thread_count);
(void) pthread_mutex_destroy(&LOCK_mapped_file);
@@ -969,7 +998,10 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_timezone);
(void) pthread_mutex_destroy(&LOCK_user_conn);
+#ifdef HAVE_REPLICATION
(void) pthread_mutex_destroy(&LOCK_rpl_status);
+ (void) pthread_cond_destroy(&COND_rpl_status);
+#endif
(void) pthread_mutex_destroy(&LOCK_active_mi);
(void) pthread_mutex_destroy(&LOCK_global_system_variables);
(void) pthread_cond_destroy(&COND_thread_count);
@@ -977,7 +1009,6 @@ static void clean_up_mutexes()
(void) pthread_cond_destroy(&COND_thread_cache);
(void) pthread_cond_destroy(&COND_flush_thread_cache);
(void) pthread_cond_destroy(&COND_manager);
- (void) pthread_cond_destroy(&COND_rpl_status);
}
/****************************************************************************
@@ -1040,7 +1071,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(mysqld_charset,*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);
@@ -1083,6 +1114,7 @@ static void set_root(const char *path)
#endif
}
+
static void server_init(void)
{
struct sockaddr_in IPaddr;
@@ -1144,7 +1176,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,
@@ -1194,7 +1226,7 @@ static void server_init(void)
{
DBUG_PRINT("general",("UNIX Socket is %s",mysql_unix_port));
- if ((unix_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ if ((unix_sock= socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
{
sql_perror("Can't start server : UNIX Socket "); /* purecov: inspected */
unireg_abort(1); /* purecov: inspected */
@@ -1229,15 +1261,17 @@ 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;
- if (!strcmp(s,"parse error"))
+ THD *thd=current_thd;
+ char *yytext=(char*) thd->lex.tok_start;
+ /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */
+ if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0)
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);
}
+#ifndef EMBEDDED_LIBRARY
void close_connection(NET *net,uint errcode,bool lock)
{
st_vio* vio;
@@ -1250,13 +1284,15 @@ 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)
(void) pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
}
+#endif /* EMBEDDED_LIBRARY */
+
/* Called when a thread is aborted */
/* ARGSUSED */
@@ -1506,7 +1542,7 @@ extern "C" sig_handler handle_segfault(int sig)
fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
exit(1);
}
-
+
segfaulted = 1;
fprintf(stderr,"\
mysqld got signal %d;\n\
@@ -1531,7 +1567,7 @@ bytes of memory\n", ((ulong) keybuff_size +
thd->variables.sortbuff_size) *
max_connections)/ 1024);
fprintf(stderr, "Hope that's ok; if not, decrease some variables in the equation.\n\n");
-
+
#if defined(HAVE_LINUXTHREADS)
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
{
@@ -1661,7 +1697,7 @@ static void start_signal_handler(void)
(void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
if (!(opt_specialflag & SPECIAL_NO_PRIOR))
my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR);
- pthread_attr_setstacksize(&thr_attr,32768);
+ pthread_attr_setstacksize(&thr_attr, 129*1024);
#endif
(void) pthread_mutex_lock(&LOCK_thread_count);
@@ -1718,8 +1754,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));
}
}
@@ -1824,11 +1860,13 @@ static void check_data_home(const char *path)
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);
@@ -1840,17 +1878,6 @@ extern "C" int my_message_sql(uint error, const char *str,
DBUG_RETURN(0);
}
-
-/*
- Forget last error message (if we got one)
-*/
-
-void clear_error_message(THD *thd)
-{
- thd->net.last_error[0]= 0;
-}
-
-
#ifdef __WIN__
struct utsname
@@ -1875,7 +1902,7 @@ extern "C" pthread_handler_decl(handle_shutdown,arg)
PeekMessage(&msg, NULL, 1, 65534,PM_NOREMOVE);
#if !defined(EMBEDDED_LIBRARY)
if (WaitForSingleObject(hEventShutdown,INFINITE)==WAIT_OBJECT_0)
-#endif
+#endif /* EMBEDDED_LIBRARY */
kill_server(MYSQL_KILL_SIGNAL);
return 0;
}
@@ -1892,6 +1919,7 @@ int STDCALL handle_kill(ulong ctrl_type)
}
#endif
+
#ifdef OS2
extern "C" pthread_handler_decl(handle_shutdown,arg)
{
@@ -1955,28 +1983,15 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
}
-
-#ifdef __WIN__
-int win_main(int argc, char **argv)
-#else
-int main(int argc, char **argv)
-#endif
+static int init_common_variables(const char *conf_file_name, int argc,
+ char **argv, const char **groups)
{
- DEBUGGER_OFF;
-
my_umask=0660; // Default umask for new files
my_umask_dir=0700; // Default umask for new directories
- MAIN_THD;
- /*
- Initialize signal_th and shutdown_th to main_th for default value
- as we need to initialize them to something safe. They are used
- when compiled with safemalloc.
- */
- SIGNAL_THD;
- SHUTDOWN_THD;
- MY_INIT(argv[0]); // init my_sys library & pthreads
+ umask(((~my_umask) & 0666));
tzset(); // Set tzname
+ max_system_variables.pseudo_thread_id= (ulong)~0;
start_time=time((time_t*) 0);
#ifdef OS2
@@ -2007,98 +2022,24 @@ int main(int argc, char **argv)
strmov(glob_hostname,"mysql");
strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5);
strmov(fn_ext(pidfile_name),".pid"); // Add proper extension
+
#ifndef DBUG_OFF
strxmov(strend(server_version),MYSQL_SERVER_SUFFIX,"-debug",NullS);
#else
strmov(strend(server_version),MYSQL_SERVER_SUFFIX);
#endif
-#ifdef _CUSTOMSTARTUPCONFIG_
- if (_cust_check_startup())
- {
- /* _cust_check_startup will report startup failure error */
- exit( 1 );
- }
-#endif
- 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 */
+ load_defaults(conf_file_name, groups, &argc, &argv);
+ defaults_argv=argv;
set_options();
get_options(argc,argv);
+ if (init_thread_environment())
+ return 1;
if (opt_log || opt_update_log || opt_slow_log || opt_bin_log)
strcat(server_version,"-log");
DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname,
server_version, SYSTEM_TYPE,MACHINE_TYPE));
- /* These must be set early */
-
- (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);
- (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
- (void) pthread_mutex_init(&LOCK_user_conn, MY_MUTEX_INIT_FAST);
- (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) pthread_cond_init(&COND_thread_count,NULL);
- (void) pthread_cond_init(&COND_refresh,NULL);
- (void) pthread_cond_init(&COND_thread_cache,NULL);
- (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
- (void) pthread_cond_init(&COND_manager,NULL);
- (void) pthread_cond_init(&COND_rpl_status, NULL);
- init_signals();
-
- 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));
-
-#ifdef HAVE_OPENSSL
- if (opt_use_ssl)
- {
- /* having ssl_acceptor_fd != 0 signals the use of SSL */
- ssl_acceptor_fd= new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert,
- opt_ssl_ca, opt_ssl_capath,
- opt_ssl_cipher);
- DBUG_PRINT("info",("ssl_acceptor_fd: %lx", (long) ssl_acceptor_fd));
- if (!ssl_acceptor_fd)
- opt_use_ssl = 0;
- }
-#endif /* HAVE_OPENSSL */
-
-#ifdef HAVE_LIBWRAP
- libwrapName= my_progname+dirname_length(my_progname);
- openlog(libwrapName, LOG_PID, LOG_AUTH);
-#endif
-
- if (!(opt_specialflag & SPECIAL_NO_PRIOR))
- my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
- /* Parameter for threads created for connections */
- (void) pthread_attr_init(&connection_attrib);
- (void) pthread_attr_setdetachstate(&connection_attrib,
- PTHREAD_CREATE_DETACHED);
- pthread_attr_setstacksize(&connection_attrib,thread_stack);
#ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE
{
/* Retrieve used stack size; Needed for checking stack overflows */
@@ -2112,9 +2053,6 @@ int main(int argc, char **argv)
}
}
#endif
- if (!(opt_specialflag & SPECIAL_NO_PRIOR))
- my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
- pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
#if defined( SET_RLIMIT_NOFILE) || defined( OS2)
/* connections and databases needs lots of files */
@@ -2142,26 +2080,88 @@ int main(int argc, char **argv)
set_var_init();
mysys_uses_curses=0;
#ifdef USE_REGEX
- regex_init();
+ regex_init(&my_charset_latin1);
#endif
- select_thread=pthread_self();
- select_thread_in_use=1;
+ if (!(default_charset_info= get_charset_by_name(sys_charset.value, MYF(MY_WME))))
+ return 1;
+ system_charset_info= default_charset_info;
+ charsets_list= list_charsets(MYF(MY_CS_COMPILED | MY_CS_CONFIG));
+
if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
- unireg_abort(1);
+ return 1;
+ return 0;
+}
- /*
- We have enough space for fiddling with the argv, continue
- */
- umask(((~my_umask) & 0666));
- check_data_home(mysql_real_data_home);
- if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
+
+static int init_thread_environment()
+{
+ (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_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);
+ (void) pthread_mutex_init(&LOCK_status,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_error_log,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_delayed_insert,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_delayed_status,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_delayed_create,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_manager,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_crypt,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_bytes_sent,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_bytes_received,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_timezone,MY_MUTEX_INIT_FAST);
+ (void) pthread_mutex_init(&LOCK_user_conn, 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);
+ (void) pthread_cond_init(&COND_flush_thread_cache,NULL);
+ (void) pthread_cond_init(&COND_manager,NULL);
+#ifdef HAVE_REPLICATION
+ (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST);
+ (void) pthread_cond_init(&COND_rpl_status, NULL);
+#endif
+ /* Parameter for threads created for connections */
+ (void) pthread_attr_init(&connection_attrib);
+ (void) pthread_attr_setdetachstate(&connection_attrib,
+ PTHREAD_CREATE_DETACHED);
+ pthread_attr_setscope(&connection_attrib, PTHREAD_SCOPE_SYSTEM);
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_attr_setprio(&connection_attrib,WAIT_PRIOR);
+
+ if (pthread_key_create(&THR_THD,NULL) ||
+ pthread_key_create(&THR_MALLOC,NULL))
{
- unireg_abort(1); /* purecov: inspected */
+ sql_print_error("Can't create thread-keys");
+ return 1;
}
- mysql_data_home= mysql_data_home_buff;
- mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
- mysql_data_home[1]=0;
- server_init();
+ return 0;
+}
+
+
+static void init_ssl()
+{
+#ifdef HAVE_OPENSSL
+ if (opt_use_ssl)
+ {
+ /* having ssl_acceptor_fd != 0 signals the use of SSL */
+ ssl_acceptor_fd= new_VioSSLAcceptorFd(opt_ssl_key, opt_ssl_cert,
+ opt_ssl_ca, opt_ssl_capath,
+ opt_ssl_cipher);
+ DBUG_PRINT("info",("ssl_acceptor_fd: %lx", (long) ssl_acceptor_fd));
+ if (!ssl_acceptor_fd)
+ opt_use_ssl = 0;
+ }
+ if (des_key_file)
+ load_des_key_file(des_key_file);
+#endif /* HAVE_OPENSSL */
+}
+
+
+static int init_server_components()
+{
table_cache_init();
hostname_cache_init();
query_cache_result_size_limit(query_cache_limit);
@@ -2169,12 +2169,9 @@ int main(int argc, char **argv)
randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2);
reset_floating_point_exceptions();
init_thr_lock();
+#ifdef HAVE_REPLICATION
init_slave_list();
-#ifdef HAVE_OPENSSL
- if (des_key_file)
- load_des_key_file(des_key_file);
-#endif /* HAVE_OPENSSL */
-
+#endif
/* Setup log files */
if (opt_log)
open_log(&mysql_log, glob_hostname, opt_logname, ".log", NullS,
@@ -2185,11 +2182,25 @@ int main(int argc, char **argv)
NullS, LOG_NEW);
using_update_log=1;
}
-
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
NullS, LOG_NORMAL);
+ if (opt_bin_log)
+ {
+ open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
+ opt_binlog_index_name,LOG_BIN);
+ using_update_log=1;
+#ifdef HAVE_REPLICATION
+ if (expire_logs_days)
+ {
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ mysql_bin_log.purge_logs_before_date(current_thd, purge_time);
+ }
+#endif
+ }
+
if (opt_error_log)
{
if (!log_error_file_ptr[0])
@@ -2205,14 +2216,16 @@ int main(int argc, char **argv)
freopen(log_error_file, "a+", stderr);
}
}
+
if (ha_init())
{
sql_print_error("Can't init databases");
- if (unix_sock != INVALID_SOCKET)
- unlink(mysql_unix_port);
unireg_abort(1);
}
+ if (opt_myisam_log)
+ (void) mi_log(1);
ha_key_cache();
+
#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
if (locked_in_memory && !geteuid())
{
@@ -2227,13 +2240,194 @@ int main(int argc, char **argv)
locked_in_memory=0;
#endif
- if (opt_myisam_log)
- (void) mi_log(1);
ft_init_stopwords();
+ init_max_user_conn();
+ init_update_queries();
+ return 0;
+}
+
+
+static void create_maintenance_thread()
+{
+ if (
+#ifdef HAVE_BERKELEY_DB
+ !berkeley_skip ||
+#endif
+ (flush_time && flush_time != ~(ulong) 0L))
+ {
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
+ sql_print_error("Warning: Can't create thread to manage maintenance");
+ }
+}
+
+
+static void create_shutdown_thread()
+{
+#if !defined(EMBEDDED_LIBRARY)
+#ifdef __WIN__
+ hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
+ sql_print_error("Warning: Can't create thread to handle shutdown requests");
+
+ // On "Stop Service" we have to do regular shutdown
+ Service.SetShutdownEvent(hEventShutdown);
+#endif
+#ifdef OS2
+ pthread_cond_init(&eventShutdown, NULL);
+ pthread_t hThread;
+ if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
+ sql_print_error("Warning: Can't create thread to handle shutdown requests");
+#endif
+#endif // EMBEDDED_LIBRARY
+}
+
+
+#if defined(__NT__) || defined(HAVE_SMEM)
+static void handle_connections_methods()
+{
+ pthread_t hThread;
+ DBUG_ENTER("handle_connections_methods");
+#ifdef __NT__
+ if (hPipe == INVALID_HANDLE_VALUE &&
+ (!have_tcpip || opt_disable_networking) &&
+ !opt_enable_shared_memory)
+ {
+ sql_print_error("TCP/IP,--shared-memory or --named-pipe should be configured on NT OS");
+ unireg_abort(1); // Will not return
+ }
+#endif
+
+ pthread_mutex_lock(&LOCK_thread_count);
+ (void) pthread_cond_init(&COND_handler_count,NULL);
+ handler_count=0;
+#ifdef __NT__
+ if (hPipe != INVALID_HANDLE_VALUE)
+ {
+ handler_count++;
+ if (pthread_create(&hThread,&connection_attrib,
+ handle_connections_namedpipes, 0))
+ {
+ sql_print_error("Warning: Can't create thread to handle named pipes");
+ handler_count--;
+ }
+ }
+#endif /* __NT__ */
+ 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 TCP/IP");
+ handler_count--;
+ }
+ }
+#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
+
+ while (handler_count > 0)
+ pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ DBUG_VOID_RETURN;
+}
+#endif /* defined(__NT__) || defined(HAVE_SMEM) */
+
+
+#ifndef EMBEDDED_LIBRARY
#ifdef __WIN__
+int win_main(int argc, char **argv)
+#else
+int main(int argc, char **argv)
+#endif
+{
+ DEBUGGER_OFF;
+
+ MY_INIT(argv[0]); // init my_sys library & pthreads
+
+#ifdef _CUSTOMSTARTUPCONFIG_
+ if (_cust_check_startup())
+ {
+ / * _cust_check_startup will report startup failure error * /
+ exit( 1 );
+ }
+#endif
+
+ if (init_common_variables(MYSQL_CONFIG_NAME,
+ argc, argv, load_default_groups))
+ unireg_abort(1); // Will do exit
+
+ init_signals();
+ if (!(opt_specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(),CONNECT_PRIOR);
+ pthread_attr_setstacksize(&connection_attrib,thread_stack);
+ (void) thr_setconcurrency(concurrency); // 10 by default
+
+ select_thread=pthread_self();
+ select_thread_in_use=1;
+ init_ssl();
+
+#ifdef HAVE_LIBWRAP
+ libwrapName= my_progname+dirname_length(my_progname);
+ openlog(libwrapName, LOG_PID, LOG_AUTH);
+#endif
+
+ /*
+ We have enough space for fiddling with the argv, continue
+ */
+ check_data_home(mysql_real_data_home);
+ if (my_setwd(mysql_real_data_home,MYF(MY_WME)))
+ {
+ unireg_abort(1); /* purecov: inspected */
+ }
+ mysql_data_home= mysql_data_home_buff;
+ mysql_data_home[0]=FN_CURLIB; // all paths are relative from here
+ mysql_data_home[1]=0;
+ server_init();
+
+ if (opt_bin_log && !server_id)
+ {
+ server_id= !master_host ? 1 : 2;
+#ifdef EXTRA_DEBUG
+ switch (server_id) {
+ case 1:
+ sql_print_error("\
+Warning: You have enabled the binary log, but you haven't set server-id:\n\
+Updates will be logged to the binary log, but connections to slaves will\n\
+not be accepted.");
+ break;
+ case 2:
+ sql_print_error("\
+Warning: You should set server-id to a non-0 value if master_host is set.\n\
+The server will not act as a slave.");
+ break;
+ }
+#endif
+ }
+
+ if (init_server_components())
+ exit(1);
+
+#ifdef __WIN__
+#define MYSQL_ERR_FILE "mysql.err"
if (!opt_console)
+ {
+ freopen(MYSQL_ERR_FILE,"a+",stdout);
+ freopen(MYSQL_ERR_FILE,"a+",stderr);
FreeConsole(); // Remove window
+ }
#endif
/*
@@ -2241,16 +2435,8 @@ 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) ||
- pthread_key_create(&THR_MALLOC,NULL))
- {
- sql_print_error("Can't create thread-keys");
- if (unix_sock != INVALID_SOCKET)
- unlink(mysql_unix_port);
- unireg_abort(1);
- }
start_signal_handler(); // Creates pidfile
- if (acl_init((THD*) 0, opt_noacl))
+ if (acl_init((THD *)0, opt_noacl))
{
abort_loop=1;
select_thread_in_use=0;
@@ -2263,13 +2449,10 @@ int main(int argc, char **argv)
#endif
if (unix_sock != INVALID_SOCKET)
unlink(mysql_unix_port);
- unireg_abort(1);
+ exit(1);
}
if (!opt_noacl)
- (void) grant_init((THD*) 0);
- init_max_user_conn();
- init_update_queries();
- DBUG_ASSERT(current_thd == 0);
+ (void) grant_init((THD *)0);
#ifdef HAVE_DLOPEN
if (!opt_noacl)
@@ -2278,34 +2461,6 @@ int main(int argc, char **argv)
/* init_slave() must be called after the thread keys are created */
init_slave();
- DBUG_ASSERT(current_thd == 0);
- if (opt_bin_log && !server_id)
- {
- server_id= !master_host ? 1 : 2;
- switch (server_id) {
-#ifdef EXTRA_DEBUG
- case 1:
- sql_print_error("\
-Warning: You have enabled the binary log, but you haven't set server-id:\n\
-Updates will be logged to the binary log, but connections to slaves will\n\
-not be accepted.");
- break;
-#endif
- case 2:
- sql_print_error("\
-Warning: You should set server-id to a non-0 value if master_host is set.\n\
-The server will not act as a slave.");
- break;
- }
- }
- if (opt_bin_log)
- {
- open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
- opt_binlog_index_name,LOG_BIN);
- using_update_log=1;
- }
-
-
if (opt_bootstrap)
{
int error=bootstrap(stdin);
@@ -2320,87 +2475,19 @@ The server will not act as a slave.");
unireg_abort(1);
}
}
- (void) thr_setconcurrency(concurrency); // 10 by default
-#if defined(__WIN__) && !defined(EMBEDDED_LIBRARY) //IRENA
- {
- hEventShutdown=CreateEvent(0, FALSE, FALSE, shutdown_event_name);
- pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
- sql_print_error("Warning: Can't create thread to handle shutdown requests");
- // On "Stop Service" we have to do regular shutdown
- Service.SetShutdownEvent(hEventShutdown);
- }
-#endif
-#ifdef OS2
- {
- pthread_cond_init( &eventShutdown, NULL);
- pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_shutdown,0))
- sql_print_error("Warning: Can't create thread to handle shutdown requests");
- }
-#endif
-
- if (
-#ifdef HAVE_BERKELEY_DB
- !berkeley_skip ||
-#endif
- (flush_time && flush_time != ~(ulong) 0L))
- {
- pthread_t hThread;
- if (pthread_create(&hThread,&connection_attrib,handle_manager,0))
- sql_print_error("Warning: Can't create thread to manage maintenance");
- }
+ create_shutdown_thread();
+ create_maintenance_thread();
printf(ER(ER_READY),my_progname,server_version,
((unix_sock == INVALID_SOCKET) ? (char*) "" : mysql_unix_port),
mysql_port);
fflush(stdout);
-#ifdef __NT__
- if (hPipe == INVALID_HANDLE_VALUE &&
- (!have_tcpip || opt_disable_networking))
- {
- sql_print_error("TCP/IP or --enable-named-pipe should be configured on NT OS");
- unireg_abort(1);
- }
- else
- {
- pthread_mutex_lock(&LOCK_thread_count);
- (void) pthread_cond_init(&COND_handler_count,NULL);
- {
- pthread_t hThread;
- handler_count=0;
- if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe)
- {
- handler_count++;
- if (pthread_create(&hThread,&connection_attrib,
- handle_connections_namedpipes, 0))
- {
- sql_print_error("Warning: Can't create thread to handle named pipes");
- handler_count--;
- }
- }
- 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");
- handler_count--;
- }
- }
- while (handler_count > 0)
- pthread_cond_wait(&COND_handler_count,&LOCK_thread_count);
- }
- pthread_mutex_unlock(&LOCK_thread_count);
- }
+#if defined(__NT__) || defined(HAVE_SMEM)
+ handle_connections_methods();
#else
handle_connections_sockets(0);
-#ifdef EXTRA_DEBUG2
- sql_print_error("Exiting main thread");
-#endif
#endif /* __NT__ */
/* (void) pthread_attr_destroy(&connection_attrib); */
@@ -2458,6 +2545,8 @@ The server will not act as a slave.");
return(0); /* purecov: deadcode */
}
+#endif /* EMBEDDED_LIBRARY */
+
/****************************************************************************
Main and thread entry function for Win32
@@ -2479,7 +2568,7 @@ int mysql_service(void *p)
SYNOPSIS
default_service_handling()
- argv Pointer to argument list
+ argv Pointer to argument list
servicename Internal name of service
displayname Display name of service (in taskbar ?)
file_path Path to this program
@@ -2530,7 +2619,7 @@ int main(int argc, char **argv)
fn_format(file_path,argv[0],file_path,"",1+4+16); /* Force full path */
if (argc == 2)
- {
+ {
if (!default_service_handling(argv,MYSQL_SERVICENAME, MYSQL_SERVICENAME,
file_path))
return 0;
@@ -2599,10 +2688,11 @@ int main(int argc, char **argv)
static int bootstrap(FILE *file)
{
- THD *thd= new THD;
- int error;
+ int error= 0;
DBUG_ENTER("bootstrap");
+#ifndef EMBEDDED_LIBRARY // TODO: Enable this
+ THD *thd= new THD;
thd->bootstrap=1;
thd->client_capabilities=0;
my_net_init(&thd->net,(st_vio*) 0);
@@ -2615,7 +2705,7 @@ static int bootstrap(FILE *file)
if (pthread_create(&thd->real_id,&connection_attrib,handle_bootstrap,
(void*) thd))
{
- sql_print_error("Warning: Can't create thread to handle bootstrap");
+ sql_print_error("Warning: Can't create thread to handle bootstrap");
DBUG_RETURN(-1);
}
/* Wait for thread to die */
@@ -2626,13 +2716,15 @@ static int bootstrap(FILE *file)
DBUG_PRINT("quit",("One thread died (count=%u)",thread_count));
}
(void) pthread_mutex_unlock(&LOCK_thread_count);
- error= thd->fatal_error;
+ error= thd->is_fatal_error;
net_end(&thd->net);
thd->cleanup();
delete thd;
+#endif /* EMBEDDED_LIBRARY */
DBUG_RETURN(error);
}
+
static bool read_init_file(char *file_name)
{
FILE *file;
@@ -2646,6 +2738,7 @@ static bool read_init_file(char *file_name)
}
+#ifndef EMBEDDED_LIBRARY
static void create_new_thread(THD *thd)
{
DBUG_ENTER("create_new_thread");
@@ -2670,6 +2763,9 @@ static void create_new_thread(THD *thd)
for (uint i=0; i < 8 ; i++) // Generate password teststring
thd->scramble[i]= (char) (my_rnd(&sql_rand)*94+33);
thd->scramble[8]=0;
+ // Back it up as old clients may need it
+ memcpy(thd->old_scramble,thd->scramble,9);
+
thd->real_id=pthread_self(); // Keep purify happy
@@ -2709,7 +2805,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;
@@ -2723,6 +2819,8 @@ static void create_new_thread(THD *thd)
DBUG_PRINT("info",("Thread created"));
DBUG_VOID_RETURN;
}
+#endif /* EMBEDDED_LIBRARY */
+
#ifdef SIGNALS_DONT_BREAK_READ
inline void kill_broken_server()
@@ -2749,6 +2847,7 @@ inline void kill_broken_server()
/* Handle new connections and spawn new process to handle them */
+#ifndef EMBEDDED_LIBRARY
extern "C" pthread_handler_decl(handle_connections_sockets,
arg __attribute__((unused)))
{
@@ -3047,31 +3146,250 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg)
#endif /* __NT__ */
-/******************************************************************************
-** handle start options
+/*
+ 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);
+ handler_count--;
+ pthread_mutex_unlock(&LOCK_thread_count);
+ pthread_cond_signal(&COND_handler_count);
+ DBUG_RETURN(0);
+}
+#endif /* HAVE_SMEM */
+#endif /* EMBEDDED_LIBRARY */
+
+
+/****************************************************************************
+ Handle start options
******************************************************************************/
-enum options {
- OPT_ISAM_LOG=256, OPT_SKIP_NEW,
- OPT_SKIP_GRANT, OPT_SKIP_LOCK,
+enum options
+{
+ OPT_ISAM_LOG=256, OPT_SKIP_NEW,
+ OPT_SKIP_GRANT, OPT_SKIP_LOCK,
OPT_ENABLE_LOCK, OPT_USE_LOCKING,
- OPT_SOCKET, OPT_UPDATE_LOG,
- OPT_BIN_LOG, OPT_SKIP_RESOLVE,
+ OPT_SOCKET, OPT_UPDATE_LOG,
+ OPT_BIN_LOG, OPT_SKIP_RESOLVE,
OPT_SKIP_NETWORKING, OPT_BIN_LOG_INDEX,
OPT_BIND_ADDRESS, OPT_PID_FILE,
- OPT_SKIP_PRIOR, OPT_BIG_TABLES,
+ OPT_SKIP_PRIOR, OPT_BIG_TABLES,
OPT_STANDALONE, OPT_ONE_THREAD,
OPT_CONSOLE, OPT_LOW_PRIORITY_UPDATES,
- OPT_SKIP_HOST_CACHE, OPT_LONG_FORMAT,
- OPT_FLUSH, OPT_SAFE,
+ OPT_SKIP_HOST_CACHE, OPT_LONG_FORMAT,
+ OPT_FLUSH, OPT_SAFE,
OPT_BOOTSTRAP, OPT_SKIP_SHOW_DB,
- OPT_TABLE_TYPE, OPT_INIT_FILE,
- OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
+ OPT_TABLE_TYPE, OPT_INIT_FILE,
+ OPT_DELAY_KEY_WRITE_ALL, OPT_SLOW_QUERY_LOG,
OPT_DELAY_KEY_WRITE, OPT_CHARSETS_DIR,
- OPT_BDB_HOME, OPT_BDB_LOG,
+ OPT_BDB_HOME, OPT_BDB_LOG,
OPT_BDB_TMP, OPT_BDB_NOSYNC,
- OPT_BDB_LOCK, OPT_BDB_SKIP,
- OPT_BDB_NO_RECOVER, OPT_BDB_SHARED,
+ OPT_BDB_LOCK, OPT_BDB_SKIP,
+ OPT_BDB_NO_RECOVER, OPT_BDB_SHARED,
OPT_MASTER_HOST, OPT_MASTER_USER,
OPT_MASTER_PASSWORD, OPT_MASTER_PORT,
OPT_MASTER_INFO_FILE, OPT_MASTER_CONNECT_RETRY,
@@ -3079,26 +3397,26 @@ enum options {
OPT_MASTER_SSL, OPT_MASTER_SSL_KEY,
OPT_MASTER_SSL_CERT, OPT_MASTER_SSL_CAPATH,
OPT_MASTER_SSL_CIPHER,
- OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
+ OPT_SQL_BIN_UPDATE_SAME, OPT_REPLICATE_DO_DB,
OPT_REPLICATE_IGNORE_DB, OPT_LOG_SLAVE_UPDATES,
OPT_BINLOG_DO_DB, OPT_BINLOG_IGNORE_DB,
OPT_WANT_CORE, OPT_CONCURRENT_INSERT,
OPT_MEMLOCK, OPT_MYISAM_RECOVER,
- OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
+ OPT_REPLICATE_REWRITE_DB, OPT_SERVER_ID,
OPT_SKIP_SLAVE_START, OPT_SKIP_INNOBASE,
- OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
- OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
- OPT_REPLICATE_WILD_IGNORE_TABLE,
- OPT_DISCONNECT_SLAVE_EVENT_COUNT,
+ OPT_SAFEMALLOC_MEM_LIMIT, OPT_REPLICATE_DO_TABLE,
+ OPT_REPLICATE_IGNORE_TABLE, OPT_REPLICATE_WILD_DO_TABLE,
+ OPT_REPLICATE_WILD_IGNORE_TABLE,
+ OPT_DISCONNECT_SLAVE_EVENT_COUNT,
OPT_ABORT_SLAVE_EVENT_COUNT,
OPT_INNODB_DATA_HOME_DIR,
OPT_INNODB_DATA_FILE_PATH,
- OPT_INNODB_LOG_GROUP_HOME_DIR,
- OPT_INNODB_LOG_ARCH_DIR,
- OPT_INNODB_LOG_ARCHIVE,
- OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
- OPT_INNODB_FLUSH_METHOD,
- OPT_INNODB_FAST_SHUTDOWN,
+ OPT_INNODB_LOG_GROUP_HOME_DIR,
+ OPT_INNODB_LOG_ARCH_DIR,
+ OPT_INNODB_LOG_ARCHIVE,
+ OPT_INNODB_FLUSH_LOG_AT_TRX_COMMIT,
+ OPT_INNODB_FLUSH_METHOD,
+ OPT_INNODB_FAST_SHUTDOWN,
OPT_SAFE_SHOW_DB,
OPT_INNODB_SKIP, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION,
@@ -3130,11 +3448,12 @@ 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,
OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
- OPT_OPEN_FILES_LIMIT,
+ OPT_OPEN_FILES_LIMIT,
OPT_QUERY_CACHE_LIMIT, OPT_QUERY_CACHE_SIZE,
OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT,
@@ -3148,6 +3467,7 @@ enum options {
OPT_INNODB_LOG_FILE_SIZE,
OPT_INNODB_LOG_BUFFER_SIZE,
OPT_INNODB_BUFFER_POOL_SIZE,
+ OPT_INNODB_BUFFER_POOL_AWE_MEM_MB,
OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
OPT_INNODB_FILE_IO_THREADS,
OPT_INNODB_LOCK_WAIT_TIMEOUT,
@@ -3156,7 +3476,12 @@ enum options {
OPT_BDB_CACHE_SIZE,
OPT_BDB_LOG_BUFFER_SIZE,
OPT_BDB_MAX_LOCK,
- OPT_ERROR_LOG_FILE
+ OPT_ERROR_LOG_FILE,
+ OPT_ENABLE_SHARED_MEMORY,
+ OPT_SHARED_MEMORY_BASE_NAME,
+ OPT_OLD_PASSWORDS,
+ OPT_EXPIRE_LOGS_DAYS,
+ OPT_DEFAULT_WEEK_FORMAT
};
@@ -3193,13 +3518,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",
@@ -3235,7 +3560,7 @@ struct my_option my_long_options[] =
#endif
#endif
#ifdef HAVE_OPENSSL
- {"des-key-file", OPT_DES_KEY_FILE,
+ {"des-key-file", OPT_DES_KEY_FILE,
"Load keys for des_encrypt() and des_encrypt from given file",
(gptr*) &des_key_file, (gptr*) &des_key_file, 0, GET_STR, REQUIRED_ARG,
0, 0, 0, 0, 0, 0},
@@ -3263,6 +3588,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,
@@ -3280,7 +3610,7 @@ struct my_option my_long_options[] =
(gptr*) &innobase_data_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0,
0},
{"innodb_log_group_home_dir", OPT_INNODB_LOG_GROUP_HOME_DIR,
- "Path to innodb log files.", (gptr*) &innobase_log_group_home_dir,
+ "Path to innodb log files.", (gptr*) &innobase_log_group_home_dir,
(gptr*) &innobase_log_group_home_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0,
0, 0},
{"innodb_log_arch_dir", OPT_INNODB_LOG_ARCH_DIR,
@@ -3402,6 +3732,7 @@ struct my_option my_long_options[] =
GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"memlock", OPT_MEMLOCK, "Lock mysqld in memory", (gptr*) &locked_in_memory,
(gptr*) &locked_in_memory, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef HAVE_REPLICATION
{"disconnect-slave-event-count", OPT_DISCONNECT_SLAVE_EVENT_COUNT,
"Option used by mysql-test for debugging and testing of replication",
(gptr*) &disconnect_slave_event_count,
@@ -3420,10 +3751,11 @@ struct my_option my_long_options[] =
(gptr*) &opt_sporadic_binlog_dump_fail,
(gptr*) &opt_sporadic_binlog_dump_fail, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
0},
+#endif /* HAVE_REPLICATION */
{"safemalloc-mem-limit", OPT_SAFEMALLOC_MEM_LIMIT,
"Simulate memory shortage when compiled with the --with-debug=full option",
0, 0, 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"new", 'n', "Use some 4.1 features and syntax (4.1 compatibility mode)",
+ {"new", 'n', "Use very new possible 'unsafe' functions",
(gptr*) &global_system_variables.new_mode,
(gptr*) &max_system_variables.new_mode,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
@@ -3500,6 +3832,8 @@ struct my_option my_long_options[] =
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients)",
+ (gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef TO_BE_DELETED
{"safe-show-database", OPT_SAFE_SHOW_DB,
"Deprecated option; One should use GRANT SHOW DATABASES instead...",
@@ -3516,6 +3850,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,
@@ -3560,12 +3899,14 @@ struct my_option my_long_options[] =
{"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE, "Undocumented",
(gptr*) &relay_log_info_file, (gptr*) &relay_log_info_file, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef HAVE_REPLICATION
{"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR, "Undocumented",
(gptr*) &slave_load_tmpdir, (gptr*) &slave_load_tmpdir, 0, GET_STR_ALLOC,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"slave-skip-errors", OPT_SLAVE_SKIP_ERRORS,
"Tells the slave thread to continue replication when a query returns an error from the provided list",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif
{"socket", OPT_SOCKET, "Socket file to use for connection",
(gptr*) &mysql_unix_port, (gptr*) &mysql_unix_port, 0, GET_STR,
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -3580,11 +3921,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,
@@ -3637,7 +3986,7 @@ struct my_option my_long_options[] =
"The size of the cache to hold the SQL statements for the binary log during a transaction. If you often use big, multi-statement transactions you can increase this to get more performance.",
(gptr*) &binlog_cache_size, (gptr*) &binlog_cache_size, 0, GET_ULONG,
REQUIRED_ARG, 32*1024L, IO_SIZE, ~0L, 0, IO_SIZE, 0},
- {"connect_timeout", OPT_CONNECT_TIMEOUT,
+ {"connect_timeout", OPT_CONNECT_TIMEOUT,
"The number of seconds the mysqld server is waiting for a connect packet before responding with Bad handshake",
(gptr*) &connect_timeout, (gptr*) &connect_timeout,
0, GET_ULONG, REQUIRED_ARG, CONNECT_TIMEOUT, 2, LONG_TIMEOUT, 0, 1, 0 },
@@ -3675,7 +4024,7 @@ struct my_option my_long_options[] =
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
#ifdef HAVE_INNOBASE_DB
{"innodb_mirrored_log_groups", OPT_INNODB_MIRRORED_LOG_GROUPS,
- "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
+ "Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
(gptr*) &innobase_mirrored_log_groups,
(gptr*) &innobase_mirrored_log_groups, 0, GET_LONG, REQUIRED_ARG, 1, 1, 10,
0, 1, 0},
@@ -3695,6 +4044,10 @@ struct my_option my_long_options[] =
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
(gptr*) &innobase_buffer_pool_size, (gptr*) &innobase_buffer_pool_size, 0,
GET_LONG, REQUIRED_ARG, 8*1024*1024L, 1024*1024L, ~0L, 0, 1024*1024L, 0},
+ {"innodb_buffer_pool_awe_mem_mb", OPT_INNODB_BUFFER_POOL_AWE_MEM_MB,
+ "If Windows AWE is used, the size of InnoDB buffer pool allocated from the AWE memory.",
+ (gptr*) &innobase_buffer_pool_awe_mem_mb, (gptr*) &innobase_buffer_pool_awe_mem_mb, 0,
+ GET_LONG, REQUIRED_ARG, 0, 0, 63000, 0, 1, 0},
{"innodb_additional_mem_pool_size", OPT_INNODB_ADDITIONAL_MEM_POOL_SIZE,
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
(gptr*) &innobase_additional_mem_pool_size,
@@ -3773,6 +4126,11 @@ struct my_option my_long_options[] =
"Don't start more than this number of threads to handle INSERT DELAYED statements. This option does not yet have effect (on TODO), unless it is set to zero, which means INSERT DELAYED is not used.",
(gptr*) &max_insert_delayed_threads, (gptr*) &max_insert_delayed_threads,
0, GET_ULONG, REQUIRED_ARG, 20, 0, 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,
@@ -3783,6 +4141,11 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.max_join_size,
(gptr*) &max_system_variables.max_join_size, 0, GET_HA_ROWS, 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,
@@ -3829,7 +4192,7 @@ struct my_option my_long_options[] =
(gptr*) &max_system_variables.myisam_sort_buff_size, 0,
GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0},
{"net_buffer_length", OPT_NET_BUFFER_LENGTH,
- "Buffer length for TCP/IP and socket communication.",
+ "Buffer length for TCP/IP and socket communication.",
(gptr*) &global_system_variables.net_buffer_length,
(gptr*) &max_system_variables.net_buffer_length, 0, GET_ULONG,
REQUIRED_ARG, 16384, 1024, 1024*1024L, 0, 1024, 0},
@@ -3885,6 +4248,7 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.read_buff_size,
(gptr*) &max_system_variables.read_buff_size,0, GET_ULONG, REQUIRED_ARG,
128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0},
+#ifdef HAVE_REPLICATION
{"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT,
"Max space to use for all relay logs",
(gptr*) &relay_log_space_limit,
@@ -3899,6 +4263,7 @@ struct my_option my_long_options[] =
"Number of seconds to wait for more data from a master/slave connection before aborting the read.",
(gptr*) &slave_net_timeout, (gptr*) &slave_net_timeout, 0,
GET_ULONG, REQUIRED_ARG, SLAVE_NET_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
+#endif /* HAVE_REPLICATION */
{"slow_launch_time", OPT_SLOW_LAUNCH_TIME,
"If creating the thread takes longer than this value (in seconds), the Slow_launch_threads counter will be incremented.",
(gptr*) &slow_launch_time, (gptr*) &slow_launch_time, 0, GET_ULONG,
@@ -3935,6 +4300,16 @@ struct my_option my_long_options[] =
(gptr*) &global_system_variables.net_wait_timeout,
(gptr*) &max_system_variables.net_wait_timeout, 0, GET_ULONG,
REQUIRED_ARG, NET_WAIT_TIMEOUT, 1, LONG_TIMEOUT, 0, 1, 0},
+ {"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
+ "Logs will be rotated after expire-log-days days. ",
+ (gptr*) &expire_logs_days,
+ (gptr*) &expire_logs_days, 0, GET_ULONG,
+ REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
+ { "default-week-format", OPT_DEFAULT_WEEK_FORMAT,
+ "The default week format used by WEEK() functions.",
+ (gptr*) &global_system_variables.default_week_format,
+ (gptr*) &max_system_variables.default_week_format,
+ 0, GET_ULONG, REQUIRED_ARG, 0, 0, 3L, 0, 1, 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
@@ -3946,6 +4321,7 @@ struct show_var_st status_vars[]= {
{"Bytes_sent", (char*) &bytes_sent, SHOW_LONG},
{"Com_admin_commands", (char*) &com_other, SHOW_LONG},
{"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG},
+ {"Com_alter_db", (char*) (com_stat+(uint) SQLCOM_ALTER_DB),SHOW_LONG},
{"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG},
{"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG},
{"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG},
@@ -3959,6 +4335,7 @@ struct show_var_st status_vars[]= {
{"Com_create_table", (char*) (com_stat+(uint) SQLCOM_CREATE_TABLE),SHOW_LONG},
{"Com_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
{"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),SHOW_LONG},
+ {"Com_do", (char*) (com_stat+(uint) SQLCOM_DO),SHOW_LONG},
{"Com_drop_db", (char*) (com_stat+(uint) SQLCOM_DROP_DB),SHOW_LONG},
{"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG},
{"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
@@ -3968,15 +4345,17 @@ struct show_var_st status_vars[]= {
{"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
{"Com_ha_open", (char*) (com_stat+(uint) SQLCOM_HA_OPEN),SHOW_LONG},
{"Com_ha_read", (char*) (com_stat+(uint) SQLCOM_HA_READ),SHOW_LONG},
+ {"Com_help", (char*) (com_stat+(uint) SQLCOM_HELP),SHOW_LONG},
{"Com_insert", (char*) (com_stat+(uint) SQLCOM_INSERT),SHOW_LONG},
{"Com_insert_select", (char*) (com_stat+(uint) SQLCOM_INSERT_SELECT),SHOW_LONG},
{"Com_kill", (char*) (com_stat+(uint) SQLCOM_KILL),SHOW_LONG},
{"Com_load", (char*) (com_stat+(uint) SQLCOM_LOAD),SHOW_LONG},
- {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
+ {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
{"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG},
{"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG},
{"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG},
{"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG},
+ {"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG},
{"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG},
{"Com_repair", (char*) (com_stat+(uint) SQLCOM_REPAIR),SHOW_LONG},
{"Com_replace", (char*) (com_stat+(uint) SQLCOM_REPLACE),SHOW_LONG},
@@ -3989,8 +4368,12 @@ struct show_var_st status_vars[]= {
{"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG},
{"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
{"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG},
- {"Com_show_create", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
+ {"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),SHOW_LONG},
+ {"Com_show_column_types", (char*) (com_stat+(uint) SQLCOM_SHOW_COLUMN_TYPES),SHOW_LONG},
+ {"Com_show_create_table", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
+ {"Com_show_create_db", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE_DB),SHOW_LONG},
{"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG},
+ {"Com_show_errors", (char*) (com_stat+(uint) SQLCOM_SHOW_ERRORS),SHOW_LONG},
{"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG},
{"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
{"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
@@ -3998,18 +4381,22 @@ struct show_var_st status_vars[]= {
{"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
{"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG},
{"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG},
+ {"Com_show_privileges", (char*) (com_stat+(uint) SQLCOM_SHOW_PRIVILEGES),SHOW_LONG},
{"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
{"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
{"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
{"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
{"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
{"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
+ {"Com_show_table_types", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLE_TYPES),SHOW_LONG},
{"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
+ {"Com_show_warnings", (char*) (com_stat+(uint) SQLCOM_SHOW_WARNS),SHOW_LONG},
{"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
{"Com_slave_stop", (char*) (com_stat+(uint) SQLCOM_SLAVE_STOP),SHOW_LONG},
{"Com_truncate", (char*) (com_stat+(uint) SQLCOM_TRUNCATE),SHOW_LONG},
{"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
{"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
+ {"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
{"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
{"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG},
@@ -4048,7 +4435,7 @@ struct show_var_st status_vars[]= {
{"Qcache_hits", (char*) &query_cache.hits, SHOW_LONG},
{"Qcache_lowmem_prunes", (char*) &query_cache.lowmem_prunes, SHOW_LONG},
{"Qcache_not_cached", (char*) &query_cache.refused, SHOW_LONG},
- {"Qcache_free_memory", (char*) &query_cache.free_memory,
+ {"Qcache_free_memory", (char*) &query_cache.free_memory,
SHOW_LONG_CONST},
{"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
SHOW_LONG_CONST},
@@ -4165,12 +4552,12 @@ static void set_options(void)
sizeof(mysql_real_data_home)-1);
/* 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= HA_POS_ERROR;
- max_system_variables.select_limit= HA_POS_ERROR;
- global_system_variables.max_join_size= HA_POS_ERROR;
- max_system_variables.max_join_size= HA_POS_ERROR;
+ global_system_variables.table_type= DB_TYPE_MYISAM;
+ global_system_variables.tx_isolation= ISO_REPEATABLE_READ;
+ global_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
+ max_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
+ global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
+ max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
#if defined(__WIN__) || defined(__NETWARE__)
/* Allow Win32 and NetWare users to move MySQL anywhere */
@@ -4205,9 +4592,10 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_endinfo=1; /* unireg: memory allocation */
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);
+ global_system_variables.sql_mode=
+ (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT |
+ MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE |
+ MODE_ONLY_FULL_GROUP_BY);
global_system_variables.tx_isolation= ISO_SERIALIZABLE;
break;
case 'b':
@@ -4233,9 +4621,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case 'o':
protocol_version=PROTOCOL_VERSION-1;
break;
+#ifdef HAVE_REPLICATION
case OPT_SLAVE_SKIP_ERRORS:
init_slave_skip_errors(argument);
break;
+#endif
case OPT_SAFEMALLOC_MEM_LIMIT:
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
safemalloc_mem_limit = atoi(argument);
@@ -4278,6 +4668,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int) OPT_ERROR_LOG_FILE:
opt_error_log= 1;
break;
+#ifdef HAVE_REPLICATION
case (int) OPT_INIT_RPL_ROLE:
{
int role;
@@ -4304,7 +4695,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
case (int)OPT_REPLICATE_REWRITE_DB:
{
char* key = argument,*p, *val;
-
+
if (!(p= strstr(argument, "->")))
{
fprintf(stderr,
@@ -4312,7 +4703,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(mysqld_charset, *p) && p > argument)
*p-- = 0;
if (p == argument)
{
@@ -4322,7 +4713,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(mysqld_charset, *val))
*val++;
if (!*val)
{
@@ -4398,13 +4789,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
table_rules_on = 1;
break;
}
- case (int) OPT_SLOW_QUERY_LOG:
- opt_slow_log=1;
- break;
case (int)OPT_RECKLESS_SLAVE:
opt_reckless_slave = 1;
init_slave_skip_errors("all");
break;
+#endif /* HAVE_REPLICATION */
+ case (int) OPT_SLOW_QUERY_LOG:
+ opt_slow_log=1;
+ break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
@@ -4464,7 +4856,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(mysqld_charset, argument[0]))
{
my_bind_addr = (ulong) inet_addr(argument);
}
@@ -4579,8 +4971,12 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
berkeley_lock_type=berkeley_lock_types[type-1];
else
{
- if (test_if_int(argument,(uint) strlen(argument)))
- berkeley_lock_scan_time=atoi(argument);
+ int err;
+ char *end;
+ uint length= strlen(argument);
+ long value= my_strntol(&my_charset_latin1, argument, length, 10, &end, &err);
+ if (test_if_int(argument,(uint) length, end, &my_charset_latin1))
+ berkeley_lock_scan_time= value;
else
{
fprintf(stderr,"Unknown lock type: %s\n",argument);
@@ -4641,16 +5037,17 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
}
case OPT_SQL_MODE:
{
- sql_mode_str = argument;
- if ((opt_sql_mode =
- find_bit_type(argument, &sql_mode_typelib)) == ~(ulong) 0)
+ sql_mode_str= argument;
+ if ((global_system_variables.sql_mode=
+ find_bit_type(argument, &sql_mode_typelib)) == ~(ulong) 0)
{
fprintf(stderr, "Unknown option to sql-mode: %s\n", argument);
exit(1);
}
- global_system_variables.tx_isolation= ((opt_sql_mode & MODE_SERIALIZABLE) ?
- ISO_SERIALIZABLE :
- ISO_REPEATABLE_READ);
+ global_system_variables.tx_isolation=
+ ((global_system_variables.sql_mode & MODE_SERIALIZABLE) ?
+ ISO_SERIALIZABLE :
+ ISO_REPEATABLE_READ);
break;
}
case OPT_MASTER_PASSWORD:
@@ -4700,7 +5097,7 @@ static void get_options(int argc,char **argv)
myisam_max_temp_length=
(my_off_t) min(global_system_variables.myisam_max_sort_file_size,
(ulonglong) MAX_FILE_SIZE);
- myisam_max_extra_temp_length=
+ myisam_max_extra_temp_length=
(my_off_t) min(global_system_variables.myisam_max_extra_sort_file_size,
(ulonglong) MAX_FILE_SIZE);
@@ -4780,15 +5177,15 @@ 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);
+#ifdef HAVE_REPLICATION
if (!slave_load_tmpdir)
{
if (!(slave_load_tmpdir = (char*) my_strdup(mysql_tmpdir, MYF(MY_FAE))))
exit(1);
}
+#endif /* HAVE_REPLICATION */
}
@@ -4883,7 +5280,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(mysqld_charset,*i++) !=
+ my_toupper(mysqld_charset,*j++))
goto skipp;
}
found_int=bit;
diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc
deleted file mode 100644
index 315cad5ca6d..00000000000
--- a/sql/net_pkg.cc
+++ /dev/null
@@ -1,401 +0,0 @@
-/* Copyright (C) 2000-2003 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 <stdarg.h>
-
- /* Send a error string to client */
-
-void send_error(NET *net, uint sql_errno, const char *err)
-{
- uint length;
- char buff[MYSQL_ERRMSG_SIZE+2];
- THD *thd=current_thd;
- DBUG_ENTER("send_error");
- DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno,
- err ? err : net->last_error[0] ?
- net->last_error : "NULL"));
-
- query_cache_abort(net);
- if (thd)
- thd->query_error = 1; // needed to catch query errors during replication
- if (!err)
- {
- if (sql_errno)
- err=ER(sql_errno);
- else
- {
- if ((err=net->last_error)[0])
- sql_errno=net->last_errno;
- else
- {
- sql_errno=ER_UNKNOWN_ERROR;
- err=ER(sql_errno); /* purecov: inspected */
- }
- }
- }
- if (net->vio == 0)
- {
- if (thd && thd->bootstrap)
- {
- /* In bootstrap it's ok to print on stderr */
- fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
- }
- DBUG_VOID_RETURN;
- }
-
- if (net->return_errno)
- { // new client code; Add errno before message
- int2store(buff,sql_errno);
- length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff);
- err=buff;
- }
- else
- {
- length=(uint) strlen(err);
- set_if_smaller(length,MYSQL_ERRMSG_SIZE);
- }
- VOID(net_write_command(net,(uchar) 255,(char*) err,length));
- if (thd)
- thd->fatal_error=0; // Error message is given
- 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.
-*/
-
-void send_warning(NET *net, uint sql_errno, const char *err)
-{
- DBUG_ENTER("send_warning");
- send_error(net,sql_errno,err);
- 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
-*/
-/* VARARGS3 */
-
-void
-net_printf(NET *net, uint errcode, ...)
-{
- va_list args;
- uint length,offset;
- const char *format,*text_pos;
- int head_length= NET_HEADER_SIZE;
- THD *thd=current_thd;
- DBUG_ENTER("net_printf");
- DBUG_PRINT("enter",("message: %u",errcode));
-
- if (thd)
- thd->query_error = 1; // if we are here, something is wrong :-)
- query_cache_abort(net); // Safety
- va_start(args,errcode);
- /*
- The following is needed to make net_printf() work with 0 argument for
- errorcode and use the argument after that as the format string. This
- is useful for rare errors that are not worth the hassle to put in
- errmsg.sys, but at the same time, the message is not fixed text
- */
- if (errcode)
- format= ER(errcode);
- else
- {
- format=va_arg(args,char*);
- errcode= ER_UNKNOWN_ERROR;
- }
- offset= net->return_errno ? 2 : 0;
- text_pos=(char*) net->buff+head_length+offset+1;
- (void) vsprintf(my_const_cast(char*) (text_pos),format,args);
- length=(uint) strlen((char*) text_pos);
- if (length >= sizeof(net->last_error))
- length=sizeof(net->last_error)-1; /* purecov: inspected */
- va_end(args);
-
- if (net->vio == 0)
- {
- if (thd && thd->bootstrap)
- {
- /*
- In bootstrap it's ok to print on stderr
- This may also happen when we get an error from a slave thread
- */
- fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
- thd->fatal_error=1;
- }
- DBUG_VOID_RETURN;
- }
-
- int3store(net->buff,length+1+offset);
- net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
- net->buff[head_length]=(uchar) 255; // Error package
- 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
- DBUG_VOID_RETURN;
-}
-
-
-void
-send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
-{
- if (net->no_send_ok) // hack for re-parsing queries
- return;
-
- char buff[MYSQL_ERRMSG_SIZE+10],*pos;
- DBUG_ENTER("send_ok");
- 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)
- {
- int2store(pos,*net->return_status);
- pos+=2;
- }
- if (message)
- pos=net_store_data((char*) pos,message);
- if (net->vio != 0)
- {
- VOID(my_net_write(net,buff,(uint) (pos-buff)));
- VOID(net_flush(net));
- }
- DBUG_VOID_RETURN;
-}
-
-void
-send_eof(NET *net,bool no_flush)
-{
- static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */
- DBUG_ENTER("send_eof");
- if (net->vio != 0)
- {
- VOID(my_net_write(net,eof_buff,1));
- if (!no_flush)
- VOID(net_flush(net));
- }
- DBUG_VOID_RETURN;
-}
-
-
-/****************************************************************************
-** Store a field length in logical packet
-****************************************************************************/
-
-char *
-net_store_length(char *pkg, ulonglong length)
-{
- uchar *packet=(uchar*) pkg;
- if (length < LL(251))
- {
- *packet=(uchar) length;
- return (char*) packet+1;
- }
- /* 251 is reserved for NULL */
- if (length < LL(65536))
- {
- *packet++=252;
- int2store(packet,(uint) length);
- return (char*) packet+2;
- }
- if (length < LL(16777216))
- {
- *packet++=253;
- int3store(packet,(ulong) length);
- return (char*) packet+3;
- }
- *packet++=254;
- int8store(packet,length);
- return (char*) packet+8;
-}
-
-char *
-net_store_length(char *pkg, uint length)
-{
- uchar *packet=(uchar*) pkg;
- if (length < 251)
- {
- *packet=(uchar) length;
- return (char*) packet+1;
- }
- *packet++=252;
- int2store(packet,(uint) length);
- return (char*) packet+2;
-}
-
-/* The following will only be used for short strings < 65K */
-char *
-net_store_data(char *to,const char *from)
-{
- uint length=(uint) strlen(from);
- to=net_store_length(to,length);
- memcpy(to,from,length);
- return to+length;
-}
-
-
-char *
-net_store_data(char *to,int32 from)
-{
- char buff[20];
- uint length=(uint) (int10_to_str(from,buff,10)-buff);
- to=net_store_length(to,length);
- memcpy(to,buff,length);
- return to+length;
-}
-
-char *
-net_store_data(char *to,longlong from)
-{
- char buff[22];
- uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
- to=net_store_length(to,length);
- memcpy(to,buff,length);
- return to+length;
-}
-
-
-bool net_store_null(String *packet)
-{
- return packet->append((char) 251);
-}
-
-bool
-net_store_data(String *packet,const char *from,uint length)
-{
- ulong packet_length=packet->length();
- if (packet_length+9+length > packet->alloced_length() &&
- packet->realloc(packet_length+9+length))
- return 1;
- char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
- (ulonglong) length);
- memcpy(to,from,length);
- packet->length((uint) (to+length-packet->ptr()));
- return 0;
-}
-
-/* The following is only used at short, null terminated data */
-
-bool
-net_store_data(String *packet,const char *from)
-{
- uint length=(uint) strlen(from);
- uint packet_length=packet->length();
- /*
- 3 is the longest coding for storing a string with the used
- net_store_length() function. We use 5 here 'just in case'
- */
- if (packet_length+5+length > packet->alloced_length() &&
- packet->realloc(packet_length+5+length))
- return 1;
- char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
- length);
- memcpy(to,from,length);
- packet->length((uint) (to+length-packet->ptr()));
- return 0;
-}
-
-
-bool
-net_store_data(String *packet,uint32 from)
-{
- char buff[20];
- return net_store_data(packet,(char*) buff,
- (uint) (int10_to_str(from,buff,10)-buff));
-}
-
-bool
-net_store_data(String *packet, longlong from)
-{
- char buff[22];
- return net_store_data(packet,(char*) buff,
- (uint) (longlong10_to_str(from,buff,10)-buff));
-}
-
-bool
-net_store_data(String *packet,struct tm *tmp)
-{
- char buff[20];
- sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
- ((int) (tmp->tm_year+1900)) % 10000,
- (int) tmp->tm_mon+1,
- (int) tmp->tm_mday,
- (int) tmp->tm_hour,
- (int) tmp->tm_min,
- (int) tmp->tm_sec);
- return net_store_data(packet,(char*) buff,19);
-}
-
-bool net_store_data(String* packet, I_List<i_string>* str_list)
-{
- char buf[256];
- String tmp(buf, sizeof(buf));
- tmp.length(0);
- I_List_iterator<i_string> it(*str_list);
- i_string* s;
-
- while ((s=it++))
- {
- if (tmp.length())
- tmp.append(',');
- tmp.append(s->ptr);
- }
-
- return net_store_data(packet, (char*)tmp.ptr(), tmp.length());
-}
-
-/*
-** translate and store data; These are mainly used by the SHOW functions
-*/
-
-bool
-net_store_data(String *packet,CONVERT *convert, const char *from,uint length)
-{
- if (convert)
- return convert->store(packet, from, length);
- return net_store_data(packet,from,length);
-}
-
-bool
-net_store_data(String *packet, CONVERT *convert, const char *from)
-{
- uint length=(uint) strlen(from);
- if (convert)
- return convert->store(packet, from, length);
- return net_store_data(packet,from,length);
-}
-
-/*
- Function called by my_net_init() to set some check variables
-*/
-
-extern "C" {
-void my_net_local_init(NET *net)
-{
- net->max_packet= (uint) global_system_variables.net_buffer_length;
- net->read_timeout= (uint) global_system_variables.net_read_timeout;
- net->write_timeout=(uint) global_system_variables.net_write_timeout;
- net->retry_count= (uint) global_system_variables.net_retry_count;
- net->max_packet_size= max(global_system_variables.net_buffer_length,
- global_system_variables.max_allowed_packet);
-}
-}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 19f68e0b631..550fb772fce 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -23,6 +23,7 @@
3 byte length & 1 byte package-number.
*/
+#ifndef EMBEDDED_LIBRARY
#ifdef __WIN__
#include <winsock.h>
#endif
@@ -80,7 +81,7 @@ 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 +100,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,7 +129,7 @@ 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;
@@ -138,8 +140,9 @@ static my_bool net_realloc(NET *net, ulong length)
{
DBUG_PRINT("error",("Packet too large. Max sixe: %lu",
net->max_packet_size));
- 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;
DBUG_RETURN(1);
}
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
@@ -151,9 +154,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
DBUG_RETURN(1);
}
@@ -188,14 +192,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 */
@@ -216,7 +220,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];
@@ -247,17 +251,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;
DBUG_ENTER("net_write_command");
@@ -268,25 +293,28 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len)
if (length >= MAX_PACKET_LENGTH)
{
/* Take into account that we have the command in the first header */
- len= MAX_PACKET_LENGTH -1;
+ len= MAX_PACKET_LENGTH - 1 - head_len;
do
{
int3store(buff, MAX_PACKET_LENGTH);
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))
DBUG_RETURN(1);
packet+= len;
length-= MAX_PACKET_LENGTH;
len= MAX_PACKET_LENGTH;
+ head_len= 0;
header_size= NET_HEADER_SIZE;
} while (length >= MAX_PACKET_LENGTH);
len=length; /* Data left to be written */
}
int3store(buff,length);
buff[3]= (uchar) net->pkt_nr++;
- DBUG_RETURN(test(net_write_buff(net,(char*) buff,header_size) ||
- net_write_buff(net,packet,len) || net_flush(net)));
+ DBUG_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)));
}
/*
@@ -402,10 +430,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);
@@ -451,9 +481,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;
@@ -479,7 +510,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);
@@ -652,9 +684,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;
}
@@ -683,7 +716,8 @@ my_real_read(NET *net, ulong *complen)
DBUG_PRINT("error",("Couldn't read packet: remain: %u errno: %d length: %ld",
remain, vio_errno(net->vio), length));
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);
@@ -713,6 +747,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
@@ -890,7 +925,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
@@ -911,12 +947,5 @@ my_net_read(NET *net)
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));
-}
+#endif /* EMBEDDED_LIBRARY */
+
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index b917c91ce15..93bae6f444d 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -431,7 +431,7 @@ BOOL NTService::SeekStatus(LPCSTR szInternName, int OperationType)
if (ret_error == ERROR_ACCESS_DENIED)
{
printf("Install/Remove of the Service Denied!\n");
- if(!is_super_user())
+ if (!is_super_user())
printf("That operation should be made by an user with Administrator privileges!\n");
}
else
@@ -530,13 +530,13 @@ BOOL NTService::is_super_user()
UINT x;
BOOL ret_value=FALSE;
- if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken ))
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,&hAccessToken ))
{
- if(GetLastError() != ERROR_NO_TOKEN)
- return FALSE;
+ if (GetLastError() != ERROR_NO_TOKEN)
+ return FALSE;
- if(!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken))
- return FALSE;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hAccessToken))
+ return FALSE;
}
ret_value= GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
@@ -544,21 +544,21 @@ BOOL NTService::is_super_user()
CloseHandle(hAccessToken);
- if(!ret_value )
- return FALSE;
+ if (!ret_value )
+ return FALSE;
- if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
- SECURITY_BUILTIN_DOMAIN_RID,
- DOMAIN_ALIAS_RID_ADMINS,
- 0, 0, 0, 0, 0, 0,
- &psidAdministrators))
- return FALSE;
+ if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &psidAdministrators))
+ return FALSE;
ret_value = FALSE;
- for(x=0;x<ptgGroups->GroupCount;x++)
+ for (x=0;x<ptgGroups->GroupCount;x++)
{
- if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
+ if ( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) )
{
ret_value = TRUE;
break;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index aeeabb7d29c..92bab76bedd 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -31,8 +31,6 @@
#include <m_ctype.h>
#include <nisam.h>
#include "sql_select.h"
-#include <assert.h>
-
#ifndef EXTRA_DEBUG
#define test_rb_tree(A,B) {}
@@ -172,8 +170,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)
{
@@ -296,9 +295,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,
@@ -662,6 +658,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;
}
@@ -679,6 +677,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++)
@@ -929,10 +928,10 @@ 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),value->charset()),*res;
uint length,offset,min_length,max_length;
- if (!field->optimize_range((uint) key_part->key))
+ if (!field->optimize_range(param->real_keynr[key_part->key]))
DBUG_RETURN(0); // Can't optimize this
if (!(res= value->val_str(&tmp)))
DBUG_RETURN(&null_element);
@@ -970,25 +969,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
@@ -1016,7 +1004,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(tree);
}
- if (!field->optimize_range((uint) key_part->key) &&
+ if (!field->optimize_range(param->real_keynr[key_part->key]) &&
type != Item_func::EQ_FUNC &&
type != Item_func::EQUAL_FUNC)
DBUG_RETURN(0); // Can't optimize this
@@ -1030,7 +1018,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, 1))
+ if (value->save_in_field(field, 1) > 0)
{
/* This happens when we try to insert a NULL field in a not null column */
DBUG_RETURN(&null_element); // cmp with NULL is never true
@@ -1042,7 +1030,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(0);
if (maybe_null)
*str= (char) field->is_real_null(); // Set to 1 if null
- field->get_key_image(str+maybe_null,key_part->part_length);
+ field->get_key_image(str+maybe_null,key_part->part_length,
+ field->charset(),key_part->image_type);
if (!(tree=new SEL_ARG(field,str,str)))
DBUG_RETURN(0);
@@ -1067,73 +1056,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 +2153,31 @@ 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),
+ 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,26 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
}
}
else
- 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;
+ {
+ 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 ((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 +2425,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 +2446,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->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 +2473,15 @@ 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,
- range->min_length,
- ((range->flag & NEAR_MIN) ?
- HA_READ_AFTER_KEY:
- (range->flag & EQ_RANGE) ?
- HA_READ_KEY_EXACT :
- HA_READ_KEY_OR_NEXT))))
+ if ((result = file->index_read(record,
+ (byte*) (range->min_key +
+ test(range->flag & GEOM_FLAG)),
+ range->min_length,
+ (range->flag & NEAR_MIN) ?
+ HA_READ_AFTER_KEY:
+ (range->flag & EQ_RANGE) ?
+ HA_READ_KEY_EXACT :
+ HA_READ_KEY_OR_NEXT)))
{
if (result != HA_ERR_KEY_NOT_FOUND)
@@ -2493,8 +2499,11 @@ int QUICK_SELECT::get_next()
}
}
- /* compare if found key is over max-value */
- /* Returns 0 if key <= range->max_key */
+
+/*
+ Compare if found key is over max-value
+ Returns 0 if key <= range->max_key
+*/
int QUICK_SELECT::cmp_next(QUICK_RANGE *range_arg)
{
@@ -2622,20 +2631,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)
{
@@ -2770,7 +2787,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),&my_charset_bin);
for (uint length=0;
length < used_length ;
@@ -2790,7 +2807,8 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
}
field->set_key_image((char*) key,key_part->part_length -
((field->type() == FIELD_TYPE_BLOB) ?
- HA_KEY_BLOB_LENGTH : 0));
+ HA_KEY_BLOB_LENGTH : 0),
+ field->charset());
field->val_str(&tmp,&tmp);
fwrite(tmp.ptr(),sizeof(char),tmp.length(),DBUG_FILE);
}
diff --git a/sql/opt_range.h b/sql/opt_range.h
index 6a6b5ae3810..bc56fb99b4b 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 aeaf8beef07..1e116518da0 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -15,27 +15,59 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* Optimizing of many different type of queries with GROUP functions */
+/*
+ Optimising of MIN(), MAX() and COUNT(*) queries without 'group by' clause
+ by replacing the aggregate expression with a constant.
+
+ Given a table with a compound key on columns (a,b,c), the following
+ types of queries are optimised (assuming the table handler supports
+ the required methods)
+
+ SELECT COUNT(*) FROM t1[,t2,t3,...]
+ SELECT MIN(b) FROM t1 WHERE a=const
+ SELECT MAX(c) FROM t1 WHERE a=const AND b=const
+ SELECT MAX(b) FROM t1 WHERE a=const AND b<const
+ SELECT MIN(b) FROM t1 WHERE a=const AND b>const
+ SELECT MIN(b) FROM t1 WHERE a=const AND b BETWEEN const AND const
+ SELECT MAX(b) FROM t1 WHERE a=const AND b BETWEEN const AND const
+
+ Instead of '<' one can use '<=', '>', '>=' and '=' as well.
+ Instead of 'a=const' the condition 'a IS NULL' can be used.
+
+ If all selected fields are replaced then we will also remove all
+ involved tables and return the answer without any join. Thus, the
+ following query will be replaced with a row of two constants:
+ SELECT MAX(b), MIN(d) FROM t1,t2
+ WHERE a=const AND b<const AND d>const
+ (assuming a index for column d of table t2 is defined)
+
+*/
#include "mysql_priv.h"
#include "sql_select.h"
-static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond);
+static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
+ Field* field, COND *cond,
+ uint *range_fl, uint *key_prefix_length);
+static int reckey_in_range(bool max_fl, TABLE_REF *ref, Field* field,
+ COND *cond, uint range_fl, uint prefix_len);
+static int maxmin_in_range(bool max_fl, Field* field, COND *cond);
+
/*
Substitutes constants for some COUNT(), MIN() and MAX() functions.
SYNOPSIS
opt_sum_query()
- tables Tables in query
- all_fields All fields to be returned
- conds WHERE clause
+ tables Tables in query
+ all_fields All fields to be returned
+ conds WHERE clause
NOTE:
This function is only called for queries with sum functions and no
GROUP BY part.
- RETURN VALUES
+ RETURN VALUES
0 No errors
1 if all items was resolved
-1 on impossible conditions
@@ -62,13 +94,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
outer_tables|= tl->table->map;
/*
- We can't optimise LEFT JOIN in cases where the WHERE condition
- restricts the table that is used, like in:
+ We can't optimise LEFT JOIN in cases where the WHERE condition
+ restricts the table that is used, like in:
SELECT MAX(t1.a) FROM t1 LEFT JOIN t2 join-condition
- WHERE t2.field IS NULL;
+ WHERE t2.field IS NULL;
*/
if (tl->table->map & where_tables)
- return 0;
+ return 0;
}
else
used_tables|= tl->table->map;
@@ -86,349 +118,644 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
Item_sum *item_sum= (((Item_sum*) item));
switch (item_sum->sum_func()) {
case Item_sum::COUNT_FUNC:
- /*
- If the expr in count(expr) can never be null we can change this
- to the number of rows in the tables
- */
- if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null)
- {
- longlong count=1;
- TABLE_LIST *table;
- for (table=tables; table ; table=table->next)
- {
- if (outer_tables || (table->table->file->table_flags() &
- HA_NOT_EXACT_COUNT))
- {
- const_result=0; // Can't optimize left join
- break;
- }
- tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
- count*= table->table->file->records;
- }
- if (!table)
- {
- ((Item_sum_count*) item)->make_const(count);
- recalc_const_item=1;
- }
- }
- else
- const_result=0;
- break;
+ /*
+ If the expr in count(expr) can never be null we can change this
+ to the number of rows in the tables
+ */
+ if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null)
+ {
+ longlong count= 1;
+ TABLE_LIST *table;
+ for (table=tables ; table ; table=table->next)
+ {
+ if (outer_tables || (table->table->file->table_flags() &
+ HA_NOT_EXACT_COUNT))
+ {
+ const_result= 0; // Can't optimize left join
+ break;
+ }
+ tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
+ count*= table->table->file->records;
+ }
+ if (!table)
+ {
+ ((Item_sum_count*) item)->make_const(count);
+ recalc_const_item= 1;
+ }
+ }
+ else
+ const_result= 0;
+ break;
case Item_sum::MIN_FUNC:
{
- /*
- If MIN(expr) is the first part of a key or if all previous
- parts of the key is found in the COND, then we can use
- indexes to find the key.
- */
- Item *expr=item_sum->args[0];
- if (expr->type() == Item::FIELD_ITEM)
- {
- byte key_buff[MAX_KEY_LENGTH];
- TABLE_REF ref;
- ref.key_buff=key_buff;
- Item_field *item_field= ((Item_field*) expr);
- TABLE *table= item_field->field->table;
-
- if ((outer_tables & table->map) ||
- (!find_range_key(&ref, item_field->field,conds)))
- {
- const_result=0;
- break;
- }
- bool error= table->file->index_init((uint) ref.key);
- enum ha_rkey_function find_flag= HA_READ_KEY_OR_NEXT;
- uint prefix_len= ref.key_length;
- /*
- If we are doing MIN() on a column with NULL fields
- we must read the key after the NULL column
- */
- if (item_field->field->null_bit)
- {
- ref.key_buff[ref.key_length++]=1;
- find_flag= HA_READ_AFTER_KEY;
- }
-
- if (!ref.key_length)
- error=table->file->index_first(table->record[0]) !=0;
- else
- error=table->file->index_read(table->record[0],key_buff,
- ref.key_length,
- find_flag) ||
- key_cmp(table, key_buff, ref.key, prefix_len);
- if (table->key_read)
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
- table->file->index_end();
- if (error)
- return -1; // No rows matching where
- removed_tables|= table->map;
- }
- else if (!expr->const_item()) // This is VERY seldom false
- {
- const_result=0;
- break;
- }
- ((Item_sum_min*) item_sum)->reset();
- ((Item_sum_min*) item_sum)->make_const();
- recalc_const_item=1;
- break;
+ /*
+ If MIN(expr) is the first part of a key or if all previous
+ parts of the key is found in the COND, then we can use
+ indexes to find the key.
+ */
+ Item *expr=item_sum->args[0];
+ if (expr->type() == Item::FIELD_ITEM)
+ {
+ byte key_buff[MAX_KEY_LENGTH];
+ TABLE_REF ref;
+ uint range_fl, prefix_len;
+
+ ref.key_buff= key_buff;
+ Item_field *item_field= ((Item_field*) expr);
+ TABLE *table= item_field->field->table;
+
+ /*
+ Look for a partial key that can be used for optimization.
+ If we succeed, ref.key_length will contain the length of
+ this key, while prefix_len will contain the length of
+ the beginning of this key without field used in MIN().
+ Type of range for the key part for this field will be
+ returned in range_fl.
+ */
+ if ((outer_tables & table->map) ||
+ !find_key_for_maxmin(0, &ref, item_field->field, conds,
+ &range_fl, &prefix_len))
+ {
+ const_result= 0;
+ break;
+ }
+ bool error= table->file->index_init((uint) ref.key);
+
+ if (!ref.key_length)
+ error= table->file->index_first(table->record[0]) != 0;
+ else
+ error= table->file->index_read(table->record[0],key_buff,
+ ref.key_length,
+ range_fl & NEAR_MIN ?
+ HA_READ_AFTER_KEY :
+ HA_READ_KEY_OR_NEXT) ||
+ reckey_in_range(0, &ref, item_field->field,
+ conds, range_fl, prefix_len);
+ if (table->key_read)
+ {
+ table->key_read= 0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ table->file->index_end();
+ if (error)
+ return -1; // No rows matching where
+ removed_tables|= table->map;
+ }
+ else if (!expr->const_item()) // This is VERY seldom false
+ {
+ const_result= 0;
+ break;
+ }
+ ((Item_sum_min*) item_sum)->reset();
+ ((Item_sum_min*) item_sum)->make_const();
+ recalc_const_item= 1;
+ break;
}
case Item_sum::MAX_FUNC:
{
- /*
- If MAX(expr) is the first part of a key or if all previous
- parts of the key is found in the COND, then we can use
- indexes to find the key.
- */
- Item *expr=item_sum->args[0];
- if (expr->type() == Item::FIELD_ITEM)
- {
- byte key_buff[MAX_KEY_LENGTH];
- TABLE_REF ref;
- ref.key_buff=key_buff;
- TABLE *table=((Item_field*) expr)->field->table;
-
- if ((outer_tables & table->map) ||
- !find_range_key(&ref, ((Item_field*) expr)->field,conds))
- {
- const_result=0;
- break;
- }
- if ((table->file->table_flags() & HA_NOT_READ_AFTER_KEY))
- {
- const_result=0;
- break;
- }
- bool error=table->file->index_init((uint) ref.key);
-
- if (!ref.key_length)
- error=table->file->index_last(table->record[0]) !=0;
- else
- {
- error = table->file->index_read(table->record[0], key_buff,
- ref.key_length,
- HA_READ_PREFIX_LAST) ||
- key_cmp(table,key_buff,ref.key,ref.key_length);
- }
- if (table->key_read)
- {
- table->key_read=0;
- table->file->extra(HA_EXTRA_NO_KEYREAD);
- }
- table->file->index_end();
- if (error)
- return -1; // Impossible query
- removed_tables|= table->map;
- }
- else if (!expr->const_item()) // This is VERY seldom false
- {
- const_result=0;
- break;
- }
- ((Item_sum_min*) item_sum)->reset();
- ((Item_sum_min*) item_sum)->make_const();
- recalc_const_item=1;
- break;
+ /*
+ If MAX(expr) is the first part of a key or if all previous
+ parts of the key is found in the COND, then we can use
+ indexes to find the key.
+ */
+ Item *expr=item_sum->args[0];
+ if (expr->type() == Item::FIELD_ITEM)
+ {
+ byte key_buff[MAX_KEY_LENGTH];
+ TABLE_REF ref;
+ uint range_fl, prefix_len;
+
+ ref.key_buff= key_buff;
+ Item_field *item_field= ((Item_field*) expr);
+ TABLE *table= item_field->field->table;
+
+ /*
+ Look for a partial key that can be used for optimization.
+ If we succeed, ref.key_length will contain the length of
+ this key, while prefix_len will contain the length of
+ the beginning of this key without field used in MAX().
+ Type of range for the key part for this field will be
+ returned in range_fl.
+ */
+ if ((outer_tables & table->map) ||
+ !find_key_for_maxmin(1, &ref, item_field->field, conds,
+ &range_fl, &prefix_len))
+ {
+ const_result= 0;
+ break;
+ }
+ if ((table->file->table_flags() & HA_NOT_READ_AFTER_KEY))
+ {
+ const_result= 0;
+ break;
+ }
+ bool error= table->file->index_init((uint) ref.key);
+
+ if (!ref.key_length)
+ error=table->file->index_last(table->record[0]) != 0;
+ else
+ error= table->file->index_read(table->record[0], key_buff,
+ ref.key_length,
+ range_fl & NEAR_MAX ?
+ HA_READ_BEFORE_KEY :
+ HA_READ_PREFIX_LAST_OR_PREV) ||
+ reckey_in_range(1, &ref, item_field->field,
+ conds, range_fl, prefix_len);
+ if (table->key_read)
+ {
+ table->key_read=0;
+ table->file->extra(HA_EXTRA_NO_KEYREAD);
+ }
+ table->file->index_end();
+ if (error)
+ return -1; // Impossible query
+ removed_tables|= table->map;
+ }
+ else if (!expr->const_item()) // This is VERY seldom false
+ {
+ const_result= 0;
+ break;
+ }
+ ((Item_sum_min*) item_sum)->reset();
+ ((Item_sum_min*) item_sum)->make_const();
+ recalc_const_item= 1;
+ break;
}
default:
- const_result=0;
- break;
+ const_result= 0;
+ break;
}
}
else if (const_result)
{
if (recalc_const_item)
- item->update_used_tables();
+ item->update_used_tables();
if (!item->const_item())
- const_result=0;
+ const_result= 0;
}
}
/*
If we have a where clause, we can only ignore searching in the
tables if MIN/MAX optimisation replaced all used tables
- This is to not to use replaced values in case of:
+ We do not use replaced values in case of:
SELECT MIN(key) FROM table_1, empty_table
removed_tables is != 0 if we have used MIN() or MAX().
*/
if (removed_tables && used_tables != removed_tables)
- const_result= 0; // We didn't remove all tables
+ const_result= 0; // We didn't remove all tables
return const_result;
}
-/* Count in how many times table is used (up to MAX_KEY_PARTS+1) */
-uint count_table_entries(COND *cond,TABLE *table)
-{
- if (cond->type() == Item::COND_ITEM)
- {
- if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
- return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
+/*
+ Test if the predicate compares a field with constants
- List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
- Item *item;
- uint count=0;
- while ((item=li++))
+ SYNOPSIS
+ simple_pred()
+ func_item in: Predicate item
+ args out: Here we store the field followed by constants
+ inv_order out: Is set to 1 if the predicate is of the form 'const op field'
+
+ RETURN
+ 0 func_item is a simple predicate: a field is compared with constants
+ 1 Otherwise
+*/
+
+static bool simple_pred(Item_func *func_item, Item **args, bool *inv_order)
+{
+ Item *item;
+ *inv_order= 0;
+ switch (func_item->argument_count()) {
+ case 1:
+ /* field IS NULL */
+ item= func_item->arguments()[0];
+ if (item->type() != Item::FIELD_ITEM)
+ return 0;
+ args[0]= item;
+ break;
+ case 2:
+ /* 'field op const' or 'const op field' */
+ item= func_item->arguments()[0];
+ if (item->type() == Item::FIELD_ITEM)
{
- if ((count+=count_table_entries(item,table)) > MAX_REF_PARTS)
- return MAX_REF_PARTS+1;
+ args[0]= item;
+ item= func_item->arguments()[1];
+ if (!item->const_item())
+ return 0;
+ args[1]= item;
}
- return count;
- }
- if (cond->type() == Item::FUNC_ITEM &&
- (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
- (((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)) &&
- cond->used_tables() == table->map)
- {
- Item *left_item= ((Item_func*) cond)->arguments()[0];
- Item *right_item= ((Item_func*) cond)->arguments()[1];
- if (left_item->type() == Item::FIELD_ITEM)
+ else if (item->const_item())
{
- if (!(((Item_field*) left_item)->field->flags & PART_KEY_FLAG) ||
- !right_item->const_item())
- return MAX_REF_PARTS+1;
- return 1;
+ args[1]= item;
+ item= func_item->arguments()[1];
+ if (item->type() != Item::FIELD_ITEM)
+ return 0;
+ args[0]= item;
+ *inv_order= 1;
}
- if (right_item->type() == Item::FIELD_ITEM)
+ else
+ return 0;
+ break;
+ case 3:
+ /* field BETWEEN const AND const */
+ item= func_item->arguments()[0];
+ if (item->type() == Item::FIELD_ITEM)
{
- if (!(((Item_field*) right_item)->field->flags & PART_KEY_FLAG) ||
- !left_item->const_item())
- return MAX_REF_PARTS+1;
- return 1;
+ args[0]= item;
+ for (int i= 1 ; i <= 2; i++)
+ {
+ item= func_item->arguments()[i];
+ if (!item->const_item())
+ return 0;
+ args[i]= item;
+ }
}
+ else
+ return 0;
}
- return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
+ return 1;
}
-/* check that the field is usable as key part */
+/*
+ Check whether a condition matches a key to get {MAX|MIN}(field):
+
+ SYNOPSIS
+ matching_cond()
+ max_fl in: Set to 1 if we are optimising MAX()
+ ref in/out: Reference to the structure we store the key value
+ keyinfo in Reference to the key info
+ field_part in: Pointer to the key part for the field
+ cond in WHERE condition
+ key_part_used in/out: Map of matchings parts
+ range_fl in/out: Says whether including key will be used
+ prefix_len out: Length of common key part for the range
+ where MAX/MIN is searched for
+
+ DESCRIPTION
+ For the index specified by the keyinfo parameter, index that
+ contains field as its component (field_part), the function
+ checks whether the condition cond is a conjunction and all its
+ conjuncts referring to the columns of the same table as column
+ field are one of the following forms:
+ - f_i= const_i or const_i= f_i or f_i is null,
+ where f_i is part of the index
+ - field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field
+ - field between const1 and const2
+
+ RETURN
+ 0 Index can't be used.
+ 1 We can use index to get MIN/MAX value
+*/
-bool part_of_cond(COND *cond,Field *field)
+static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
+ KEY_PART_INFO *field_part, COND *cond,
+ key_part_map *key_part_used, uint *range_fl,
+ uint *prefix_len)
{
+ if (!cond)
+ return 1;
+ Field *field= field_part->field;
+ if (!(cond->used_tables() & field->table->map))
+ {
+ /* Condition doesn't restrict the used table */
+ return 1;
+ }
if (cond->type() == Item::COND_ITEM)
{
if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
- return 0; // Already checked
+ return 0;
+ /* AND */
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
Item *item;
- while ((item=li++))
+ while ((item= li++))
{
- if (part_of_cond(item,field))
- return 1;
+ if (!matching_cond(max_fl, ref, keyinfo, field_part, item,
+ key_part_used, range_fl, prefix_len))
+ return 0;
}
+ return 1;
+ }
+
+ if (cond->type() != Item::FUNC_ITEM)
+ return 0; // Not operator, can't optimize
+
+ bool eq_type= 0; // =, <=> or IS NULL
+ bool noeq_type= 0; // < or >
+ bool less_fl= 0; // < or <=
+ bool is_null= 0;
+ bool between= 0;
+
+ switch (((Item_func*) cond)->functype()) {
+ case Item_func::ISNULL_FUNC:
+ is_null= 1; /* fall through */
+ case Item_func::EQ_FUNC:
+ case Item_func::EQUAL_FUNC:
+ eq_type= 1;
+ break;
+ case Item_func::LT_FUNC:
+ noeq_type= 1; /* fall through */
+ case Item_func::LE_FUNC:
+ less_fl= 1;
+ break;
+ case Item_func::GT_FUNC:
+ noeq_type= 1; /* fall through */
+ case Item_func::GE_FUNC:
+ break;
+ case Item_func::BETWEEN:
+ between= 1;
+ break;
+ default:
+ return 0; // Can't optimize function
+ }
+
+ Item *args[3];
+ bool inv;
+
+ /* Test if this is a comparison of a field and constant */
+ if (!simple_pred((Item_func*) cond, args, &inv))
+ return 0;
+
+ if (inv && !eq_type)
+ less_fl= 1-less_fl; // Convert '<' -> '>' (etc)
+
+ /* Check if field is part of the tested partial key */
+ byte *key_ptr= ref->key_buff;
+ KEY_PART_INFO *part;
+ for (part= keyinfo->key_part;
+ ;
+ key_ptr+= part++->store_length)
+
+ {
+ if (part > field_part)
+ return 0; // Field is beyond the tested parts
+ if (part->field->eq(((Item_field*) args[0])->field))
+ break; // Found a part od the key for the field
+ }
+
+ bool is_field_part= part == field_part;
+ if (!(is_field_part || eq_type))
return 0;
+
+ key_part_map org_key_part_used= *key_part_used;
+ if (eq_type || between || max_fl == less_fl)
+ {
+ uint length= (key_ptr-ref->key_buff)+part->store_length;
+ if (ref->key_length < length)
+ /* Ultimately ref->key_length will contain the length of the search key */
+ ref->key_length= length;
+ if (!*prefix_len && part+1 == field_part)
+ *prefix_len= length;
+ if (is_field_part && eq_type)
+ *prefix_len= ref->key_length;
+
+ *key_part_used|= (key_part_map) 1 << (part - keyinfo->key_part);
}
- if (cond->type() == Item::FUNC_ITEM &&
- (((Item_func*) cond)->functype() == Item_func::EQ_FUNC ||
- ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC) &&
- cond->used_tables() == field->table->map)
+
+ if (org_key_part_used != *key_part_used ||
+ (is_field_part &&
+ (between || eq_type || max_fl == less_fl) && !cond->val_int()))
{
- Item *left_item= ((Item_func*) cond)->arguments()[0];
- Item *right_item= ((Item_func*) cond)->arguments()[1];
- if (left_item->type() == Item::FIELD_ITEM)
+ /*
+ It's the first predicate for this part or a predicate of the
+ following form that moves upper/lower bounds for max/min values:
+ - field BETWEEN const AND const
+ - field = const
+ - field {<|<=} const, when searching for MAX
+ - field {>|>=} const, when searching for MIN
+ */
+
+ if (is_null)
{
- if (((Item_field*) left_item)->field != field ||
- !right_item->const_item())
- return 0;
+ part->field->set_null();
+ *key_ptr= (byte) 1;
}
- else if (right_item->type() == Item::FIELD_ITEM)
+ else
{
- if (((Item_field*) right_item)->field != field ||
- !left_item->const_item())
- return 0;
- right_item=left_item; // const item in right
+ store_val_in_field(part->field, args[between && max_fl ? 2 : 1]);
+ if (part->null_bit)
+ *key_ptr++= (byte) test(part->field->is_null());
+ part->field->get_key_image((char*) key_ptr, part->length,
+ part->field->charset(), Field::itRAW);
+ }
+ if (is_field_part)
+ {
+ if (between || eq_type)
+ *range_fl&= ~(NO_MAX_RANGE | NO_MIN_RANGE);
+ else
+ {
+ *range_fl&= ~(max_fl ? NO_MAX_RANGE : NO_MIN_RANGE);
+ if (noeq_type)
+ *range_fl|= (max_fl ? NEAR_MAX : NEAR_MIN);
+ else
+ *range_fl&= ~(max_fl ? NEAR_MAX : NEAR_MIN);
+ }
}
- store_val_in_field(field,right_item);
- return 1;
}
- return 0;
+ else if (eq_type)
+ {
+ if (!is_null && !cond->val_int() ||
+ is_null && !test(part->field->is_null()))
+ return 0; // Impossible test
+ }
+ else if (is_field_part)
+ *range_fl&= ~(max_fl ? NO_MIN_RANGE : NO_MAX_RANGE);
+ return 1;
}
-/* Check if we can get value for field by using a key */
+/*
+ Check whether we can get value for {max|min}(field) by using a key.
-static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
+ SYNOPSIS
+ find_key_for_maxmin()
+ max_fl in: 0 for MIN(field) / 1 for MAX(field)
+ ref in/out Reference to the structure we store the key value
+ field in: Field used inside MIN() / MAX()
+ cond in: WHERE condition
+ range_fl out: Bit flags for how to search if key is ok
+ prefix_len out: Length of prefix for the search range
+
+ DESCRIPTION
+ If where condition is not a conjunction of 0 or more conjuct the
+ function returns false, otherwise it checks whether there is an
+ index including field as its k-th component/part such that:
+
+ 1. for each previous component f_i there is one and only one conjunct
+ of the form: f_i= const_i or const_i= f_i or f_i is null
+ 2. references to field occur only in conjucts of the form:
+ field {<|<=|>=|>|=} const or const {<|<=|>=|>|=} field or
+ field BETWEEN const1 AND const2
+ 3. all references to the columns from the same table as column field
+ occur only in conjucts mentioned above.
+
+ If such an index exists the function through the ref parameter
+ returns the key value to find max/min for the field using the index,
+ the length of first (k-1) components of the key and flags saying
+ how to apply the key for the search max/min value.
+ (if we have a condition field = const, prefix_len contains the length
+ of the whole search key)
+
+ RETURN
+ 0 Index can not be used to optimize MIN(field)/MAX(field)
+ 1 Can use key to optimize MIN()/MAX()
+ In this case ref, range_fl and prefix_len are updated
+*/
+
+static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
+ Field* field, COND *cond,
+ uint *range_fl, uint *prefix_len)
{
if (!(field->flags & PART_KEY_FLAG))
- return 0; // Not part of a key. Skip it
+ return 0; // Not key field
+ *prefix_len= 0;
+
+ TABLE *table= field->table;
+ uint idx= 0;
- TABLE *table=field->table;
- uint idx=0;
-
- /* Check if some key has field as first key part */
- if ((field->key_start & field->table->keys_in_use_for_query) &&
- (! cond || ! (cond->used_tables() & table->map)))
- {
- for (key_map key=field->key_start ;;)
- {
- for (; !(key & 1) ; idx++)
- key>>=1;
- if (!(table->file->index_flags(idx) & HA_WRONG_ASCII_ORDER))
- break; // Key is ok
- /* Can't use this key, for looking up min() or max(), end if last one */
- if (key == 1)
- return 0;
- }
- ref->key_length=0;
- ref->key=idx;
- if (field->part_of_key & ((key_map) 1 << idx))
+ KEY *keyinfo,*keyinfo_end;
+ for (keyinfo= table->key_info, keyinfo_end= keyinfo+table->keys ;
+ keyinfo != keyinfo_end;
+ keyinfo++,idx++)
+ {
+ if (table->file->index_flags(idx) & HA_WRONG_ASCII_ORDER)
+ break;
+
+ KEY_PART_INFO *part,*part_end;
+ key_part_map key_part_to_use= 0;
+ for (part= keyinfo->key_part, part_end= part+keyinfo->key_parts ;
+ part != part_end ;
+ part++, key_part_to_use= (key_part_to_use << 1) | 1)
{
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
+ if (field->eq(part->field))
+ {
+ ref->key= idx;
+ ref->key_length= 0;
+ key_part_map key_part_used= 0;
+ *range_fl= NO_MIN_RANGE | NO_MAX_RANGE;
+ if (matching_cond(max_fl, ref, keyinfo, part, cond,
+ &key_part_used, range_fl, prefix_len) &&
+ !(key_part_to_use & ~key_part_used))
+ {
+ if (!max_fl && key_part_used == key_part_to_use && part->null_bit)
+ {
+ /*
+ SELECT MIN(key_part2) FROM t1 WHERE key_part1=const
+ If key_part2 may be NULL, then we want to find the first row
+ that is not null
+ */
+ ref->key_buff[ref->key_length++]= 1;
+ *range_fl&= ~NO_MIN_RANGE;
+ *range_fl|= NEAR_MIN; // > NULL
+ }
+ /*
+ The following test is false when the key in the key tree is
+ converted (for example to upper case)
+ */
+ if (field->part_of_key & ((key_map) 1 << idx))
+ {
+ table->key_read= 1;
+ table->file->extra(HA_EXTRA_KEYREAD);
+ }
+ return 1;
+ }
+ }
}
- return 1; // Ok to use key
}
- /*
- ** Check if WHERE consist of exactly the previous key parts for some key
- */
- if (!cond)
- return 0;
- uint table_entries= count_table_entries(cond,table);
- if (!table_entries || table_entries > MAX_REF_PARTS)
+ return 0;
+}
+
+
+/*
+ Check whether found key is in range specified by conditions
+
+ SYNOPSIS
+ reckey_in_range()
+ max_fl in: 0 for MIN(field) / 1 for MAX(field)
+ ref in: Reference to the key value and info
+ field in: Field used the MIN/MAX expression
+ cond in: WHERE condition
+ range_fl in: Says whether there is a condition to to be checked
+ prefix_len in: Length of the constant part of the key
+
+ RETURN
+ 0 ok
+ 1 WHERE was not true for the found row
+*/
+
+static int reckey_in_range(bool max_fl, TABLE_REF *ref, Field* field,
+ COND *cond, uint range_fl, uint prefix_len)
+{
+ if (key_cmp(field->table, ref->key_buff, ref->key, prefix_len))
+ return 1;
+ if (!cond || (range_fl & (max_fl ? NO_MIN_RANGE : NO_MAX_RANGE)))
return 0;
+ return maxmin_in_range(max_fl, field, cond);
+}
- KEY *keyinfo,*keyinfo_end;
- idx=0;
- for (keyinfo=table->key_info, keyinfo_end=keyinfo+table->keys ;
- keyinfo != keyinfo_end;
- keyinfo++,idx++)
+
+/*
+ Check whether {MAX|MIN}(field) is in range specified by conditions
+ SYNOPSIS
+ maxmin_in_range()
+ max_fl in: 0 for MIN(field) / 1 for MAX(field)
+ field in: Field used the MIN/MAX expression
+ cond in: WHERE condition
+
+ RETURN
+ 0 ok
+ 1 WHERE was not true for the found row
+*/
+
+static int maxmin_in_range(bool max_fl, Field* field, COND *cond)
+{
+ /* If AND/OR condition */
+ if (cond->type() == Item::COND_ITEM)
{
- if (table_entries < keyinfo->key_parts)
+ List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
+ Item *item;
+ while ((item= li++))
{
- byte *key_ptr=ref->key_buff;
- KEY_PART_INFO *part,*part_end;
- int left_length=MAX_KEY_LENGTH;
-
- for (part=keyinfo->key_part, part_end=part+table_entries ;
- part != part_end ;
- part++)
- {
- if (!part_of_cond(cond,part->field) ||
- left_length < part->store_length ||
- (table->file->index_flags(idx) & HA_WRONG_ASCII_ORDER))
- break;
- // 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);
- key_ptr+=part->store_length - test(part->null_bit);
- left_length-=part->store_length;
- }
- if (part == part_end && part->field == field)
- {
- ref->key_length= (uint) (key_ptr-ref->key_buff);
- ref->key=idx;
- if (field->part_of_key & ((key_map) 1 << idx))
- {
- table->key_read=1;
- table->file->extra(HA_EXTRA_KEYREAD);
- }
- return 1; // Ok to use key
- }
+ if (maxmin_in_range(max_fl, field, item))
+ return 1;
}
+ return 0;
}
- return 0; // No possible key
+
+ if (cond->used_tables() != field->table->map)
+ return 0;
+ bool less_fl= 0;
+ switch (((Item_func*) cond)->functype()) {
+ case Item_func::BETWEEN:
+ return cond->val_int() == 0; // Return 1 if WHERE is false
+ case Item_func::LT_FUNC:
+ case Item_func::LE_FUNC:
+ less_fl= 1;
+ case Item_func::GT_FUNC:
+ case Item_func::GE_FUNC:
+ {
+ Item *item= ((Item_func*) cond)->arguments()[1];
+ /* In case of 'const op item' we have to swap the operator */
+ if (!item->const_item())
+ less_fl= 1-less_fl;
+ /*
+ We only have to check the expression if we are using an expression like
+ SELECT MAX(b) FROM t1 WHERE a=const AND b>const
+ not for
+ SELECT MAX(b) FROM t1 WHERE a=const AND b<const
+ */
+ if (max_fl != less_fl)
+ return cond->val_int() == 0; // Return 1 if WHERE is false
+ return 0;
+ }
+ case Item_func::EQ_FUNC:
+ case Item_func::EQUAL_FUNC:
+ break;
+ default: // Keep compiler happy
+ DBUG_ASSERT(1); // Impossible
+ break;
+ }
+ return 0;
}
+
diff --git a/sql/password.c b/sql/password.c
index 575e837ceb8..9752bcc95eb 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -32,14 +32,55 @@
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
+
+
+ New in MySQL 4.1 authentication works even more secure way.
+ At the first step client sends user name to the sever, and password if
+ it is empty. So in case of empty password authentication is as fast as before.
+ At the second stap servers sends scramble to client, which is encoded with
+ password stage2 hash stored in the password database as well as salt, needed
+ for client to build stage2 password to decrypt scramble.
+ Client decrypts the scramble and encrypts it once again with stage1 password.
+ This information is sent to server.
+ Server decrypts the scramble to get stage1 password and hashes it to get
+ stage2 hash. This hash is when compared to hash stored in the database.
+
+ This authentication needs 2 packet round trips instead of one but it is much
+ stronger. Now if one will steal mysql database content he will not be able
+ to break into MySQL.
+
+ New Password handling functions by Peter Zaitsev
+
+
*****************************************************************************/
#include <my_global.h>
#include <my_sys.h>
#include <m_string.h>
+#include <sha1.h>
#include "mysql.h"
+
+/* Character to use as version identifier for version 4.1 */
+#define PVERSION41_CHAR '*'
+
+/* Scramble length for new password version */
+
+
+/*
+ New (MySQL 3.21+) random generation structure initialization
+
+ SYNOPSIS
+ randominit()
+ rand_st OUT Structure to initialize
+ seed1 IN First initialization parameter
+ seed2 IN Second initialization parameter
+
+ RETURN
+ none
+*/
+
void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
{ /* For mysql 3.21.# */
#ifdef HAVE_purify
@@ -51,6 +92,19 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
rand_st->seed2=seed2%rand_st->max_value;
}
+
+/*
+ Old (MySQL 3.20) random generation structure initialization
+
+ SYNOPSIS
+ old_randominit()
+ rand_st OUT Structure to initialize
+ seed1 IN First initialization parameter
+
+ RETURN
+ none
+*/
+
static void old_randominit(struct rand_struct *rand_st,ulong seed1)
{ /* For mysql 3.20.# */
rand_st->max_value= 0x01FFFFFFL;
@@ -59,6 +113,18 @@ static void old_randominit(struct rand_struct *rand_st,ulong seed1)
rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
}
+
+/*
+ Generate Random number
+
+ SYNOPSIS
+ rnd()
+ rand_st INOUT Structure used for number generation
+
+ RETURN
+ Generated pseudo random number
+*/
+
double my_rnd(struct rand_struct *rand_st)
{
rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value;
@@ -66,6 +132,67 @@ double my_rnd(struct rand_struct *rand_st)
return (((double) rand_st->seed1)/rand_st->max_value_dbl);
}
+
+/*
+ Generate String of printable random characters of requested length
+ String will not be zero terminated.
+
+ SYNOPSIS
+ create_random_string()
+ length IN Lenght of
+ rand_st INOUT Structure used for number generation
+ target OUT Buffer for generation
+
+ RETURN
+ none
+*/
+
+void create_random_string(int length,struct rand_struct *rand_st,char *target)
+{
+ char *end=target+length;
+ /* Use pointer arithmetics as it is faster way to do so. */
+ for (; target<end ; target++)
+ *target= (char) (rnd(rand_st)*94+33);
+}
+
+
+/*
+ Encrypt/Decrypt function used for password encryption in authentication
+ Simple XOR is used here but it is OK as we crypt random strings
+
+ SYNOPSIS
+ password_crypt()
+ from IN Data for encryption
+ to OUT Encrypt data to the buffer (may be the same)
+ password IN Password used for encryption (same length)
+ length IN Length of data to encrypt
+
+ RETURN
+ none
+*/
+
+void password_crypt(const char *from,char *to, const char *password,int length)
+{
+ const char *from_end=from+length;
+
+ while (from < from_end)
+ *to++= *(from++) ^* (password++);
+}
+
+
+/*
+ Generate binary hash from raw text password
+ Used for Pre-4.1 Password handling
+
+ SYNOPSIS
+ hash_pasword()
+ result OUT Store hash in this location
+ password IN Plain text password to build hash
+
+ RETURN
+ none
+*/
+
void hash_password(ulong *result, const char *password)
{
register ulong nr=1345345333L, add=7, nr2=0x12345671L;
@@ -84,13 +211,230 @@ void hash_password(ulong *result, const char *password)
return;
}
-void make_scrambled_password(char *to,const char *password)
+
+/*
+ Stage one password hashing.
+ Used in MySQL 4.1 password handling
+
+ SYNOPSIS
+ password_hash_stage1()
+ to OUT Store stage one hash to this location
+ password IN Plain text password to build hash
+
+ RETURN
+ none
+*/
+
+void password_hash_stage1(char *to, const char *password)
{
- ulong hash_res[2];
- hash_password(hash_res,password);
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+ SHA1_CONTEXT context;
+ sha1_reset(&context);
+ for (; *password ; password++)
+ {
+ if (*password == ' ' || *password == '\t')
+ continue;/* skip space in password */
+ sha1_input(&context,(uint8*) &password[0],1);
+ }
+ sha1_result(&context,(uint8*)to);
}
+
+/*
+ Stage two password hashing.
+ Used in MySQL 4.1 password handling
+
+ SYNOPSIS
+ password_hash_stage2()
+ to INOUT Use this as stage one hash and store stage two hash here
+ salt IN Salt used for stage two hashing
+
+ RETURN
+ none
+*/
+
+void password_hash_stage2(char *to, const char *salt)
+{
+ SHA1_CONTEXT context;
+ sha1_reset(&context);
+ sha1_input(&context,(uint8*) salt, 4);
+ sha1_input(&context,(uint8*) to, SHA1_HASH_SIZE);
+ sha1_result(&context,(uint8*) to);
+}
+
+
+/*
+ Create password to be stored in user database from raw string
+ Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords
+
+ SYNOPSIS
+ make_scramble_password()
+ to OUT Store scrambled password here
+ password IN Raw string password
+ force_old_scramle
+ IN Force generation of old scramble variant
+ rand_st INOUT Structure for temporary number generation.
+ RETURN
+ none
+*/
+
+void make_scrambled_password(char *to,const char *password,
+ my_bool force_old_scramble,
+ struct rand_struct *rand_st)
+{
+ ulong hash_res[2]; /* Used for pre 4.1 password hashing */
+ unsigned short salt; /* Salt for 4.1 version password */
+ uint8 digest[SHA1_HASH_SIZE];
+ if (force_old_scramble) /* Pre 4.1 password encryption */
+ {
+ hash_password(hash_res,password);
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+ }
+ else /* New password 4.1 password scrambling */
+ {
+ to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
+ /* Rnd returns number from 0 to 1 so this would be good salt generation.*/
+ salt=(unsigned short) (rnd(rand_st)*65535+1);
+ /* Use only 2 first bytes from it */
+ sprintf(to+1,"%04x",salt);
+ /* First hasing is done without salt */
+ password_hash_stage1((char*) digest, password);
+ /* Second stage is done with salt */
+ password_hash_stage2((char*) digest,(char*)to+1),
+ /* Print resulting hash into the password*/
+ sprintf(to+5,
+ "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],
+ digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],
+ digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]);
+ }
+}
+
+
+/*
+ Convert password from binary string form to salt form
+ Used for MySQL 4.1 password handling
+
+ SYNOPSIS
+ get_salt_from_bin_password()
+ res OUT Store salt form password here
+ password IN Binary password to be converted
+ salt IN hashing-salt to be used for salt form generation
+
+ RETURN
+ none
+*/
+
+void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt)
+{
+ unsigned char *password_end=password+SCRAMBLE41_LENGTH;
+ *res=salt;
+ res++;
+
+ /* Process password of known length*/
+ while (password<password_end)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 4 ; i++)
+ val=(val << 8)+(*password++);
+ *res++=val;
+ }
+}
+
+
+/*
+ Validate password for MySQL 4.1 password handling.
+
+ SYNOPSIS
+ validate_password()
+ password IN Encrypted Scramble which we got from the client
+ message IN Original scramble which we have sent to the client before
+ salt IN Password in the salted form to match to
+
+ RETURN
+ 0 for correct password
+ !0 for invalid password
+*/
+
+my_bool validate_password(const char *password, const char *message,
+ ulong *salt)
+{
+ char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */
+ char tmpsalt[8]; /* Temporary value to convert salt to string form */
+ ulong salt_candidate[6]; /* Computed candidate salt */
+ ulong *sc=salt_candidate; /* we need to be able to increment */
+ ulong *salt_end;
+
+ /* Now we shall get stage1 encrypted password in buffer*/
+ password_crypt(password,buffer,message,SCRAMBLE41_LENGTH);
+
+ /* For compatibility reasons we use ulong to store salt while we need char */
+ sprintf(tmpsalt,"%04x",(unsigned short)salt[0]);
+
+ password_hash_stage2(buffer,tmpsalt);
+ /* Convert password to salt to compare */
+ get_salt_from_bin_password(salt_candidate,(uchar*) buffer,salt[0]);
+
+ /* Now we shall get exactly the same password as we have stored for user */
+ for (salt_end=salt+5 ; salt < salt_end; )
+ if (*++salt != *++sc)
+ return 1;
+
+ /* Or password correct*/
+ return 0;
+}
+
+
+/*
+ Get length of password string which is stored in mysql.user table
+
+ SYNOPSIS
+ get_password_length()
+ force_old_scramble IN If we wish to use pre 4.1 scramble format
+
+ RETURN
+ password length >0
+*/
+
+int get_password_length(my_bool force_old_scramble)
+{
+ return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1;
+}
+
+
+/*
+ Get version of the password based on mysql.user password string
+
+ SYNOPSIS
+ get_password_version()
+ password IN Password string as stored in mysql.user
+
+ RETURN
+ 0 for pre 4.1 passwords
+ !0 password version char for newer passwords
+*/
+
+char get_password_version(const char *password)
+{
+ if (password==NULL) return 0;
+ if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
+ return 0;
+}
+
+
+/*
+ Get integer value of Hex character
+
+ SYNOPSIS
+ char_val()
+ X IN Character to find value for
+
+ RETURN
+ Appropriate integer value
+*/
+
+
+
static inline unsigned int char_val(char X)
{
return (uint) (X >= '0' && X <= '9' ? X-'0' :
@@ -98,16 +442,44 @@ static inline unsigned int char_val(char X)
X-'a'+10);
}
+
/*
-** This code assumes that len(password) is divideable with 8 and that
-** res is big enough (2 in mysql)
+ Get Binary salt from password as in mysql.user format
+
+ SYNOPSIS
+ get_salt_from_password()
+ res OUT Store binary salt here
+ password IN Password string as stored in mysql.user
+
+ RETURN
+ none
+
+ NOTE
+ This function does not have length check for passwords. It will just crash
+ Password hashes in old format must have length divisible by 8
*/
void get_salt_from_password(ulong *res,const char *password)
{
- res[0]=res[1]=0;
- if (password)
+ if (password) /* zero salt corresponds to empty password */
{
+ if (password[0]==PVERSION41_CHAR) /* if new password */
+ {
+ uint val=0;
+ uint i;
+ password++; /* skip version identifier */
+
+ /*get hashing salt from password and store in in the start of array */
+ for (i=0 ; i < 4 ; i++)
+ val=(val << 4)+char_val(*password++);
+ *res++=val;
+ }
+ /* We process old passwords the same way as new ones in other case */
+#ifdef EXTRA_DEBUG
+ if (strlen(password)%8!=0)
+ fprintf(stderr,"Warning: Incorrect password length for salting: %d\n",
+ strlen(password));
+#endif
while (*password)
{
ulong val=0;
@@ -120,33 +492,166 @@ void get_salt_from_password(ulong *res,const char *password)
return;
}
-void make_password_from_salt(char *to, ulong *hash_res)
+
+/*
+ Get string version as stored in mysql.user from salt form
+
+ SYNOPSIS
+ make_password_from_salt()
+ to OUT Store resulting string password here
+ hash_res IN Password in salt format
+ password_version
+ IN According to which version salt should be treated
+
+ RETURN
+ none
+*/
+
+void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version)
{
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+ if (!password_version) /* Handling of old passwords. */
+ sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
+ else
+ if (password_version==PVERSION41_CHAR)
+ sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1],
+ hash_res[2],hash_res[3],hash_res[4],hash_res[5]);
+ else /* Just use empty password if we can't handle it. This should not happen */
+ to[0]='\0';
}
/*
- * Genererate a new message based on message and password
- * The same thing is done in client and server and the results are checked.
- */
+ Convert password in salted form to binary string password and hash-salt
+ For old password this involes one more hashing
+
+ SYNOPSIS
+ get_hash_and_password()
+ salt IN Salt to convert from
+ pversion IN Password version to use
+ hash OUT Store zero ended hash here
+ bin_password OUT Store binary password here (no zero at the end)
+
+ RETURN
+ 0 for pre 4.1 passwords
+ !0 password version char for newer passwords
+*/
+
+void get_hash_and_password(ulong *salt, uint8 pversion, char *hash,
+ unsigned char *bin_password)
+{
+ int t;
+ ulong* salt_end;
+ ulong val;
+ SHA1_CONTEXT context;
+
+ if (pversion) /* New password version assumed */
+ {
+ salt_end=salt+5;
+ sprintf(hash,"%04x",(unsigned short)salt[0]);
+ while (salt<salt_end)
+ {
+ val=*(++salt);
+ for (t=3; t>=0; t--)
+ {
+ bin_password[t]= (char) (val & 255);
+ val>>=8; /* Scroll 8 bits to get next part*/
+ }
+ bin_password+=4; /* Get to next 4 chars*/
+ }
+ }
+ else
+ {
+ unsigned char *bp= bin_password; /* Binary password loop pointer */
+
+ /* Use zero starting hash as an indication of old password */
+ hash[0]=0;
+ salt_end=salt+2;
+ /* Encode salt using SHA1 here */
+ sha1_reset(&context);
+ while (salt<salt_end) /* Iterate over these elements*/
+ {
+ val= *salt;
+ for (t=3;t>=0;t--)
+ {
+ bp[t]= (uchar) (val & 255);
+ val>>=8; /* Scroll 8 bits to get next part*/
+ }
+ bp+= 4; /* Get to next 4 chars*/
+ salt++;
+ }
+ /* Use 8 bytes of binary password for hash */
+ sha1_input(&context,(uint8*)bin_password,8);
+ sha1_result(&context,(uint8*)bin_password);
+ }
+}
+
+
+/*
+ Create key from old password to decode scramble
+ Used in 4.1 authentication with passwords stored old way
+
+ SYNOPSIS
+ create_key_from_old_password()
+ passwd IN Password used for key generation
+ key OUT Created 20 bytes key
+
+ RETURN
+ None
+*/
+
+
+void create_key_from_old_password(const char *passwd, char *key)
+{
+ char buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */
+ ulong salt[6]; /* Salt (large for safety) */
+ /* At first hash password to the string stored in password */
+ make_scrambled_password(buffer,passwd,1,(struct rand_struct *)NULL);
+ /* Now convert it to the salt form */
+ get_salt_from_password(salt,buffer);
+ /* Finally get hash and bin password from salt */
+ get_hash_and_password(salt,0,buffer,(unsigned char*) key);
+}
+
+
+/*
+ Scramble string with password
+ Used at pre 4.1 authentication phase.
+
+ SYNOPSIS
+ scramble()
+ to OUT Store scrambled message here
+ message IN Message to scramble
+ password IN Password to use while scrambling
+ old_ver IN Forse old version random number generator
+
+ RETURN
+ End of scrambled string
+*/
char *scramble(char *to,const char *message,const char *password,
my_bool old_ver)
{
struct rand_struct rand_st;
ulong hash_pass[2],hash_message[2];
+ char message_buffer[9]; /* Real message buffer */
+ char *msg=message_buffer;
+
+ /* We use special message buffer now as new server can provide longer hash */
+
+ memcpy(message_buffer,message,8);
+ message_buffer[8]=0;
+
if (password && password[0])
{
char *to_start=to;
hash_password(hash_pass,password);
- hash_password(hash_message,message);
+ hash_password(hash_message,message_buffer);
if (old_ver)
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
else
randominit(&rand_st,hash_pass[0] ^ hash_message[0],
hash_pass[1] ^ hash_message[1]);
- while (*message++)
+ while (*msg++)
*to++= (char) (floor(my_rnd(&rand_st)*31)+64);
if (!old_ver)
{ /* Make it harder to break */
@@ -160,15 +665,45 @@ char *scramble(char *to,const char *message,const char *password,
}
+/*
+ Check scrambled message
+ Used for pre 4.1 password handling
+
+ SYNOPSIS
+ scramble()
+ scrambled IN Scrambled message to check
+ message IN Original message which was scramble
+ hash_pass IN Password which should be used for scrambling
+ old_ver IN Forse old version random number generator
+
+ RETURN
+ 0 Password correct
+ !0 Password invalid
+*/
+
my_bool check_scramble(const char *scrambled, const char *message,
ulong *hash_pass, my_bool old_ver)
{
struct rand_struct rand_st;
ulong hash_message[2];
- char buff[16],*to,extra; /* Big enough for check */
+ char buff[16],*to,extra; /* Big enough for check */
const char *pos;
+ char message_buffer[SCRAMBLE_LENGTH+1]; /* Copy of message */
+
+ /* We need to copy the message as this function can be called for MySQL 4.1
+ scramble which is not zero ended and can have zeroes inside
+ We could just write zero to proper place in original message but
+ this would make it harder to understand code for next generations
+ */
+
+ memcpy(message_buffer,message,SCRAMBLE_LENGTH); /* Ignore the rest */
+ message_buffer[SCRAMBLE_LENGTH]=0;
+
+ /* Check if this exactly N bytes. Overwise this is something fishy */
+ if (strlen(message_buffer)!=SCRAMBLE_LENGTH)
+ return 1; /* Wrong password */
- hash_password(hash_message,message);
+ hash_password(hash_message,message_buffer);
if (old_ver)
old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
else
diff --git a/sql/procedure.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..5365b2e1102 100644
--- a/sql/procedure.h
+++ b/sql/procedure.h
@@ -35,10 +35,10 @@ public:
}
enum Type type() const { return Item::PROC_ITEM; }
virtual void set(double nr)=0;
- virtual void set(const char *str,uint length)=0;
+ virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
virtual void set(longlong nr)=0;
virtual enum_field_types field_type() const=0;
- void set(const char *str) { set(str,(uint) strlen(str)); }
+ void set(const char *str) { set(str,(uint) strlen(str), default_charset()); }
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,field_type());
@@ -55,14 +55,14 @@ public:
decimals=dec; max_length=float_length(dec);
}
enum Item_result result_type () const { return REAL_RESULT; }
- enum_field_types field_type() const { return FIELD_TYPE_DOUBLE; }
+ enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
void set(double nr) { value=nr; }
void set(longlong nr) { value=(double) nr; }
- void set(const char *str,uint length __attribute__((unused)))
- { value=atof(str); }
+ void set(const char *str,uint length,CHARSET_INFO *cs)
+ { int err; value=my_strntod(cs,(char*) str,length,(char**)0,&err); }
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,default_charset()); return s; }
unsigned int size_of() { return sizeof(*this);}
};
@@ -73,14 +73,14 @@ public:
Item_proc_int(const char *name_par) :Item_proc(name_par)
{ max_length=11; }
enum Item_result result_type () const { return INT_RESULT; }
- enum_field_types field_type() const { return FIELD_TYPE_LONG; }
+ enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; }
void set(double nr) { value=(longlong) nr; }
void set(longlong nr) { value=nr; }
- void set(const char *str,uint length __attribute__((unused)))
- { value=strtoll(str,NULL,10); }
+ void set(const char *str,uint length, CHARSET_INFO *cs)
+ { int err; value=my_strntoll(cs,str,length,10,NULL,&err); }
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, default_charset()); return s; }
unsigned int size_of() { return sizeof(*this);}
};
@@ -91,12 +91,24 @@ public:
Item_proc_string(const char *name_par,uint length) :Item_proc(name_par)
{ 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); }
- double val() { return atof(str_value.ptr()); }
- longlong val_int() { return strtoll(str_value.ptr(),NULL,10); }
+ enum_field_types field_type() const { return MYSQL_TYPE_STRING; }
+ void set(double nr) { str_value.set(nr, 2, default_charset()); }
+ void set(longlong nr) { str_value.set(nr, default_charset()); }
+ void set(const char *str, uint length, CHARSET_INFO *cs)
+ { str_value.copy(str,length,cs); }
+ double val()
+ {
+ int err;
+ CHARSET_INFO *cs=str_value.charset();
+ return my_strntod(cs, (char*) str_value.ptr(), str_value.length(),
+ (char**) 0, &err);
+ }
+ longlong val_int()
+ {
+ int err;
+ CHARSET_INFO *cs=str_value.charset();
+ return my_strntoll(cs,str_value.ptr(),str_value.length(),10,NULL,&err);
+ }
String *val_str(String*)
{
return null_value ? (String*) 0 : (String*) &str_value;
diff --git a/sql/protocol.cc b/sql/protocol.cc
new file mode 100644
index 00000000000..c7ce38eadac
--- /dev/null
+++ b/sql/protocol.cc
@@ -0,0 +1,1109 @@
+/* Copyright (C) 2000-2003 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 */
+
+/*
+ Low level functions for storing data to be send to the MySQL client
+ The actual communction is handled by the net_xxx functions in net_serv.cc
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include <stdarg.h>
+
+#ifndef EMBEDDED_LIBRARY
+bool Protocol::net_store_data(const char *from, uint length)
+{
+ ulong packet_length=packet->length();
+ /*
+ The +9 comes from that strings of length longer than 16M require
+ 9 bytes to be stored (see net_store_length).
+ */
+ if (packet_length+9+length > packet->alloced_length() &&
+ packet->realloc(packet_length+9+length))
+ return 1;
+ char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
+ (ulonglong) length);
+ memcpy(to,from,length);
+ packet->length((uint) (to+length-packet->ptr()));
+ return 0;
+}
+
+inline bool Protocol::convert_str(const char *from, uint length)
+{
+ return convert->store(packet, from, length);
+}
+#endif
+
+
+ /* Send a error string to client */
+
+void send_error(THD *thd, uint sql_errno, const char *err)
+{
+#ifndef EMBEDDED_LIBRARY
+ uint length;
+ char buff[MYSQL_ERRMSG_SIZE+2];
+#endif
+ 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"));
+
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
+ query_cache_abort(net);
+#endif
+ thd->query_error= 1; // needed to catch query errors during replication
+ if (!err)
+ {
+ if (sql_errno)
+ err=ER(sql_errno);
+ else
+ {
+ if ((err=net->last_error)[0])
+ sql_errno=net->last_errno;
+ else
+ {
+ sql_errno=ER_UNKNOWN_ERROR;
+ err=ER(sql_errno); /* purecov: inspected */
+ }
+ }
+ }
+
+#ifdef EMBEDDED_LIBRARY
+ net->last_errno= sql_errno;
+ strmake(net->last_error, err, sizeof(net->last_error)-1);
+#else
+
+ if (net->vio == 0)
+ {
+ if (thd->bootstrap)
+ {
+ /* In bootstrap it's ok to print on stderr */
+ fprintf(stderr,"ERROR: %d %s\n",sql_errno,err);
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ if (net->return_errno)
+ { // new client code; Add errno before message
+ int2store(buff,sql_errno);
+ length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff);
+ err=buff;
+ }
+ else
+ {
+ length=(uint) strlen(err);
+ set_if_smaller(length,MYSQL_ERRMSG_SIZE-1);
+ }
+ VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length));
+#endif /* EMBEDDED_LIBRARY*/
+ thd->is_fatal_error=0; // Error message is given
+ thd->net.report_error= 0;
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Send an error to the client when a connection is forced close
+ This is used by mysqld.cc, which doesn't have a THD
+*/
+
+#ifndef EMBEDDED_LIBRARY
+void net_send_error(NET *net, uint sql_errno, const char *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;
+}
+#endif
+
+
+/*
+ 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 use another buffer for
+ this
+*/
+
+void
+net_printf(THD *thd, uint errcode, ...)
+{
+ va_list args;
+ uint length,offset;
+ const char *format;
+#ifndef EMBEDDED_LIBRARY
+ const char *text_pos;
+#else
+ char text_pos[500];
+#endif
+ int head_length= NET_HEADER_SIZE;
+ NET *net= &thd->net;
+
+ DBUG_ENTER("net_printf");
+ DBUG_PRINT("enter",("message: %u",errcode));
+
+ thd->query_error= 1; // needed to catch query errors during replication
+#ifndef EMBEDDED_LIBRARY
+ query_cache_abort(net); // Safety
+#endif
+ va_start(args,errcode);
+ /*
+ The following is needed to make net_printf() work with 0 argument for
+ errorcode and use the argument after that as the format string. This
+ is useful for rare errors that are not worth the hassle to put in
+ errmsg.sys, but at the same time, the message is not fixed text
+ */
+ if (errcode)
+ format= ER(errcode);
+ else
+ {
+ format=va_arg(args,char*);
+ errcode= ER_UNKNOWN_ERROR;
+ }
+ offset= net->return_errno ? 2 : 0;
+#ifndef EMBEDDED_LIBRARY
+ text_pos=(char*) net->buff+head_length+offset+1;
+#endif
+ (void) vsprintf(my_const_cast(char*) (text_pos),format,args);
+ length=(uint) strlen((char*) text_pos);
+ if (length >= sizeof(net->last_error))
+ length=sizeof(net->last_error)-1; /* purecov: inspected */
+ va_end(args);
+
+#ifndef EMBEDDED_LIBRARY
+ if (net->vio == 0)
+ {
+ if (thd->bootstrap)
+ {
+ /*
+ In bootstrap it's ok to print on stderr
+ This may also happen when we get an error from a slave thread
+ */
+ fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos);
+ thd->fatal_error();
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ int3store(net->buff,length+1+offset);
+ net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
+ net->buff[head_length]=(uchar) 255; // Error package
+ if (offset)
+ int2store(text_pos-2, errcode);
+ VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
+#else
+ net->last_errno= errcode;
+ strmake(net->last_error, text_pos, length);
+#endif
+ thd->is_fatal_error=0; // Error message is given
+ DBUG_VOID_RETURN;
+}
+
+/*
+ Function called by my_net_init() to set some check variables
+*/
+
+#ifndef EMBEDDED_LIBRARY
+extern "C" {
+void my_net_local_init(NET *net)
+{
+ net->max_packet= (uint) global_system_variables.net_buffer_length;
+ net->read_timeout= (uint) global_system_variables.net_read_timeout;
+ net->write_timeout=(uint) global_system_variables.net_write_timeout;
+ net->retry_count= (uint) global_system_variables.net_retry_count;
+ net->max_packet_size= max(global_system_variables.net_buffer_length,
+ global_system_variables.max_allowed_packet);
+}
+}
+
+#else /* EMBEDDED_LIBRARY */
+void my_net_local_init(NET *net __attribute__(unused))
+{
+}
+#endif /* EMBEDDED_LIBRARY */
+
+/*
+ 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
+*/
+
+#ifndef EMBEDDED_LIBRARY
+void
+send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message)
+{
+ NET *net= &thd->net;
+ char buff[MYSQL_ERRMSG_SIZE+10],*pos;
+ DBUG_ENTER("send_ok");
+
+ if (net->no_send_ok || !net->vio) // hack for re-parsing queries
+ DBUG_VOID_RETURN;
+
+ buff[0]=0; // No fields
+ pos=net_store_length(buff+1,(ulonglong) affected_rows);
+ pos=net_store_length(pos, (ulonglong) id);
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ 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;
+ }
+ else if (net->return_status) // For 4.0 protocol
+ {
+ int2store(pos,thd->server_status);
+ pos+=2;
+ }
+ if (message)
+ pos=net_store_data((char*) pos, message, strlen(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(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)
+ {
+ 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;
+}
+#endif /* EMBEDDED_LIBRARY */
+
+
+/****************************************************************************
+ Store a field length in logical packet
+ This is used to code the string length for normal protocol
+****************************************************************************/
+
+char *
+net_store_length(char *pkg, ulonglong length)
+{
+ uchar *packet=(uchar*) pkg;
+ if (length < LL(251))
+ {
+ *packet=(uchar) length;
+ return (char*) packet+1;
+ }
+ /* 251 is reserved for NULL */
+ if (length < LL(65536))
+ {
+ *packet++=252;
+ int2store(packet,(uint) length);
+ return (char*) packet+2;
+ }
+ if (length < LL(16777216))
+ {
+ *packet++=253;
+ int3store(packet,(ulong) length);
+ return (char*) packet+3;
+ }
+ *packet++=254;
+ int8store(packet,length);
+ return (char*) packet+8;
+}
+
+
+/*
+ Faster net_store_length when we know length is a 32 bit integer
+*/
+
+char *net_store_length(char *pkg, uint length)
+{
+ uchar *packet=(uchar*) pkg;
+ if (length < 251)
+ {
+ *packet=(uchar) length;
+ return (char*) packet+1;
+ }
+ *packet++=252;
+ int2store(packet,(uint) length);
+ return (char*) packet+2;
+}
+
+
+/****************************************************************************
+ Functions used by the protocol functions (like send_ok) to store strings
+ and numbers in the header result packet.
+****************************************************************************/
+
+/* The following will only be used for short strings < 65K */
+
+char *net_store_data(char *to,const char *from, uint length)
+{
+ to=net_store_length(to,length);
+ memcpy(to,from,length);
+ return to+length;
+}
+
+char *net_store_data(char *to,int32 from)
+{
+ char buff[20];
+ uint length=(uint) (int10_to_str(from,buff,10)-buff);
+ to=net_store_length(to,length);
+ memcpy(to,buff,length);
+ return to+length;
+}
+
+char *net_store_data(char *to,longlong from)
+{
+ char buff[22];
+ uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
+ to=net_store_length(to,length);
+ memcpy(to,buff,length);
+ return to+length;
+}
+
+
+/*****************************************************************************
+ Default Protocol functions
+*****************************************************************************/
+
+void Protocol::init(THD *thd_arg)
+{
+ thd=thd_arg;
+ convert=thd->variables.convert_set;
+ packet= &thd->packet;
+#ifndef DEBUG_OFF
+ field_types= 0;
+#endif
+}
+
+
+/*
+ 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
+
+ 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)
+*/
+
+#ifndef EMBEDDED_LIBRARY
+bool Protocol::send_fields(List<Item> *list, uint flag)
+{
+ List_iterator_fast<Item> it(*list);
+ Item *item;
+ char buff[80];
+ String tmp((char*) buff,sizeof(buff),&my_charset_bin);
+ Protocol_simple prot(thd);
+ String *packet= prot.storage_packet();
+ DBUG_ENTER("send_fields");
+
+ 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));
+ }
+
+#ifndef DEBUG_OFF
+ field_types= (enum_field_types*) thd->alloc(sizeof(field_types) *
+ list->elements);
+ uint count= 0;
+#endif
+
+ while ((item=it++))
+ {
+ char *pos;
+ CHARSET_INFO *cs= system_charset_info;
+ Send_field field;
+ item->make_field(&field);
+ prot.prepare_for_resend();
+
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ if (prot.store(field.db_name, (uint) strlen(field.db_name), cs) ||
+ prot.store(field.table_name, (uint) strlen(field.table_name), cs) ||
+ prot.store(field.org_table_name,
+ (uint) strlen(field.org_table_name), cs) ||
+ prot.store(field.col_name, (uint) strlen(field.col_name), cs) ||
+ prot.store(field.org_col_name,
+ (uint) strlen(field.org_col_name), cs) ||
+ packet->realloc(packet->length()+12))
+ goto err;
+ /* Store fixed length fields */
+ pos= (char*) packet->ptr()+packet->length();
+ *pos++= 11; // Length of packed fields
+ int2store(pos, field.charsetnr);
+ int3store(pos+2, field.length);
+ pos[5]= field.type;
+ int2store(pos+6,field.flags);
+ pos[8]= (char) field.decimals;
+ pos[9]= 0; // For the future
+ pos[10]= 0; // For the future
+ pos+= 11;
+ }
+ else
+ {
+ if (prot.store(field.table_name, (uint) strlen(field.table_name), cs) ||
+ prot.store(field.col_name, (uint) strlen(field.col_name), cs) ||
+ packet->realloc(packet->length()+10))
+ goto err;
+ pos= (char*) packet->ptr()+packet->length();
+
+#ifdef TO_BE_DELETED_IN_6
+ if (!(thd->client_capabilities & CLIENT_LONG_FLAG))
+ {
+ 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;
+ pos+= 9;
+ }
+ else
+#endif
+ {
+ 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;
+ pos+= 10;
+ }
+ }
+ packet->length((uint) (pos - packet->ptr()));
+ if (flag & 2)
+ item->send(&prot, &tmp); // Send default value
+ if (prot.write())
+ break; /* purecov: inspected */
+#ifndef DEBUG_OFF
+ field_types[count++]= field.type;
+#endif
+ }
+
+ send_eof(thd);
+ DBUG_RETURN(prepare_for_send(list));
+
+err:
+ send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
+}
+
+
+bool Protocol::send_records_num(List<Item> *list, ulonglong records)
+{
+ char *pos;
+ char buff[20];
+ pos=net_store_length(buff, (uint) list->elements);
+ pos=net_store_length(pos, records);
+ return my_net_write(&thd->net, buff,(uint) (pos-buff));
+}
+
+
+bool Protocol::write()
+{
+ DBUG_ENTER("Protocol::write");
+ DBUG_RETURN(my_net_write(&thd->net, packet->ptr(), packet->length()));
+}
+#endif /* EMBEDDED_LIBRARY */
+
+
+/*
+ Send \0 end terminated string
+
+ SYNOPSIS
+ store()
+ from NullS or \0 terminated string
+
+ NOTES
+ In most cases one should use store(from, length) instead of this function
+
+ RETURN VALUES
+ 0 ok
+ 1 error
+*/
+
+bool Protocol::store(const char *from, CHARSET_INFO *cs)
+{
+ if (!from)
+ return store_null();
+ uint length= strlen(from);
+ return store(from, length, cs);
+}
+
+
+/*
+ Send a set of strings as one long string with ',' in between
+*/
+
+bool Protocol::store(I_List<i_string>* str_list)
+{
+ char buf[256];
+ String tmp(buf, sizeof(buf), &my_charset_bin);
+ uint32 len;
+ I_List_iterator<i_string> it(*str_list);
+ i_string* s;
+
+ tmp.length(0);
+ while ((s=it++))
+ {
+ tmp.append(s->ptr);
+ tmp.append(',');
+ }
+ if ((len= tmp.length()))
+ len--; // Remove last ','
+ return store((char*) tmp.ptr(), len, tmp.charset());
+}
+
+
+/****************************************************************************
+ Functions to handle the simple (default) protocol where everything is
+ This protocol is the one that is used by default between the MySQL server
+ and client when you are not using prepared statements.
+
+ All data are sent as 'packed-string-length' followed by 'string-data'
+****************************************************************************/
+
+#ifndef EMBEDDED_LIBRARY
+void Protocol_simple::prepare_for_resend()
+{
+ packet->length(0);
+#ifndef DEBUG_OFF
+ field_pos= 0;
+#endif
+}
+
+bool Protocol_simple::store_null()
+{
+#ifndef DEBUG_OFF
+ field_pos++;
+#endif
+ char buff[1];
+ buff[0]= (char)251;
+ return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC);
+}
+#endif
+
+
+bool Protocol_simple::store(const char *from, uint length, CHARSET_INFO *cs)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
+ (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
+ field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
+ field_pos++;
+#endif
+ if (convert)
+ return convert_str(from, length);
+#if 0
+ if (cs != this->thd->charset())
+ {
+ String tmp;
+ tmp.copy(from, length, cs, this->thd->charset());
+ return net_store_data(tmp.ptr(), tmp.length());
+ }
+ else
+#endif
+ return net_store_data(from, length);
+}
+
+
+bool Protocol_simple::store_tiny(longlong from)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY);
+ field_pos++;
+#endif
+ char buff[20];
+ return net_store_data((char*) buff,
+ (uint) (int10_to_str((int) from,buff, -10)-buff));
+}
+
+
+bool Protocol_simple::store_short(longlong from)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_SHORT);
+ field_pos++;
+#endif
+ char buff[20];
+ return net_store_data((char*) buff,
+ (uint) (int10_to_str((int) from,buff, -10)-buff));
+}
+
+
+bool Protocol_simple::store_long(longlong from)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_INT24 ||
+ field_types[field_pos] == MYSQL_TYPE_LONG);
+ field_pos++;
+#endif
+ char buff[20];
+ return net_store_data((char*) buff,
+ (uint) (int10_to_str((int) from,buff, -10)-buff));
+}
+
+
+bool Protocol_simple::store_longlong(longlong from, bool unsigned_flag)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_LONGLONG);
+ field_pos++;
+#endif
+ char buff[22];
+ return net_store_data((char*) buff,
+ (uint) (longlong10_to_str(from,buff,
+ unsigned_flag ? 10 : -10)-
+ buff));
+}
+
+
+bool Protocol_simple::store(float from, uint32 decimals, String *buffer)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_FLOAT);
+ field_pos++;
+#endif
+ buffer->set((double) from, decimals, thd->variables.thd_charset);
+ return net_store_data((char*) buffer->ptr(), buffer->length());
+}
+
+
+bool Protocol_simple::store(double from, uint32 decimals, String *buffer)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DOUBLE);
+ field_pos++;
+#endif
+ buffer->set(from, decimals, thd->variables.thd_charset);
+ return net_store_data((char*) buffer->ptr(), buffer->length());
+}
+
+
+bool Protocol_simple::store(Field *field)
+{
+ if (field->is_null())
+ return store_null();
+#ifndef DEBUG_OFF
+ field_pos++;
+#endif
+ char buff[MAX_FIELD_WIDTH];
+ String tmp(buff,sizeof(buff), &my_charset_bin);
+ field->val_str(&tmp,&tmp);
+ if (convert)
+ return convert_str(tmp.ptr(), tmp.length());
+ return net_store_data(tmp.ptr(), tmp.length());
+}
+
+
+bool Protocol_simple::store(TIME *tm)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DATETIME ||
+ field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
+ field_pos++;
+#endif
+ char buff[40];
+ uint length;
+ length= my_sprintf(buff,(buff, "%04d-%02d-%02d %02d:%02d:%02d",
+ (int) tm->year,
+ (int) tm->month,
+ (int) tm->day,
+ (int) tm->hour,
+ (int) tm->minute,
+ (int) tm->second));
+ return net_store_data((char*) buff, length);
+}
+
+
+bool Protocol_simple::store_date(TIME *tm)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DATE);
+ field_pos++;
+#endif
+ char buff[40];
+ uint length;
+ length= my_sprintf(buff,(buff, "%04d-%02d-%02d",
+ (int) tm->year,
+ (int) tm->month,
+ (int) tm->day));
+ return net_store_data((char*) buff, length);
+}
+
+
+bool Protocol_simple::store_time(TIME *tm)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_TIME);
+ field_pos++;
+#endif
+ char buff[40];
+ uint length;
+ length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d",
+ tm->neg ? "-" : "",
+ (long) tm->day*3600L+(long) tm->hour,
+ (int) tm->minute,
+ (int) tm->second));
+ return net_store_data((char*) buff, length);
+}
+
+
+/****************************************************************************
+ Functions to handle the binary protocol used with prepared statements
+
+ Data format:
+
+ [ok:1] reserved ok packet
+ [null_field:(field_count+7+2)/8] reserved to send null data. The size is
+ calculated using:
+ bit_fields= (field_count+7+2)/8;
+ 2 bits are reserved for identifying type
+ of package.
+ [[length]data] data field (the length applies only for
+ string/binary/time/timestamp fields and
+ rest of them are not sent as they have
+ the default length that client understands
+ based on the field type
+ [..]..[[length]data] data
+****************************************************************************/
+
+bool Protocol_prep::prepare_for_send(List<Item> *item_list)
+{
+ Protocol::prepare_for_send(item_list);
+ bit_fields= (field_count+9)/8;
+ if (packet->alloc(bit_fields+1))
+ return 1;
+ /* prepare_for_resend will be called after this one */
+ return 0;
+}
+
+
+void Protocol_prep::prepare_for_resend()
+{
+ packet->length(bit_fields+1);
+ bzero((char*) packet->ptr(), 1+bit_fields);
+ field_pos=0;
+}
+
+
+bool Protocol_prep::store(const char *from,uint length, CHARSET_INFO *cs)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DECIMAL ||
+ (field_types[field_pos] >= MYSQL_TYPE_ENUM &&
+ field_types[field_pos] <= MYSQL_TYPE_GEOMETRY));
+#endif
+ field_pos++;
+ if (convert)
+ return convert_str(from, length);
+ return net_store_data(from, length);
+}
+
+bool Protocol_prep::store_null()
+{
+ uint offset= (field_pos+2)/8+1, bit= (1 << ((field_pos+2) & 7));
+ /* Room for this as it's allocated in prepare_for_send */
+ char *to= (char*) packet->ptr()+offset;
+ *to= (char) ((uchar) *to | (uchar) bit);
+ field_pos++;
+ return 0;
+}
+
+
+bool Protocol_prep::store_tiny(longlong from)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_TINY);
+#endif
+ char buff[1];
+ field_pos++;
+ buff[0]= (uchar) from;
+ return packet->append(buff, sizeof(buff), PACKET_BUFFET_EXTRA_ALLOC);
+}
+
+
+bool Protocol_prep::store_short(longlong from)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_SHORT ||
+ field_types[field_pos] == MYSQL_TYPE_YEAR);
+#endif
+ field_pos++;
+ char *to= packet->prep_append(2, PACKET_BUFFET_EXTRA_ALLOC);
+ if (!to)
+ return 1;
+ int2store(to, (int) from);
+ return 0;
+}
+
+
+bool Protocol_prep::store_long(longlong from)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_INT24 ||
+ field_types[field_pos] == MYSQL_TYPE_LONG);
+#endif
+ field_pos++;
+ char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC);
+ if (!to)
+ return 1;
+ int4store(to, from);
+ return 0;
+}
+
+
+bool Protocol_prep::store_longlong(longlong from, bool unsigned_flag)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_LONGLONG);
+#endif
+ field_pos++;
+ char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC);
+ if (!to)
+ return 1;
+ int8store(to, from);
+ return 0;
+}
+
+
+bool Protocol_prep::store(float from, uint32 decimals, String *buffer)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_FLOAT);
+#endif
+ field_pos++;
+ char *to= packet->prep_append(4, PACKET_BUFFET_EXTRA_ALLOC);
+ if (!to)
+ return 1;
+ float4store(to, from);
+ return 0;
+}
+
+
+bool Protocol_prep::store(double from, uint32 decimals, String *buffer)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DOUBLE);
+#endif
+ field_pos++;
+ char *to= packet->prep_append(8, PACKET_BUFFET_EXTRA_ALLOC);
+ if (!to)
+ return 1;
+ float8store(to, from);
+ return 0;
+}
+
+
+bool Protocol_prep::store(Field *field)
+{
+ /*
+ We should not increment field_pos here as send_binary() will call another
+ protocol function to do this for us
+ */
+ if (field->is_null())
+ return store_null();
+ return field->send_binary(this);
+}
+
+
+bool Protocol_prep::store(TIME *tm)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_DATETIME ||
+ field_types[field_pos] == MYSQL_TYPE_DATE ||
+ field_types[field_pos] == MYSQL_TYPE_TIMESTAMP);
+#endif
+ char buff[12],*pos;
+ uint length;
+ field_pos++;
+ pos= buff+1;
+
+ int2store(pos, tm->year);
+ pos[2]= (uchar) tm->month;
+ pos[3]= (uchar) tm->day;
+ pos[4]= (uchar) tm->hour;
+ pos[5]= (uchar) tm->minute;
+ pos[6]= (uchar) tm->second;
+ int4store(pos+7, tm->second_part);
+ if (tm->second_part)
+ length=11;
+ else if (tm->hour || tm->minute || tm->second)
+ length=7;
+ else if (tm->year || tm->month || tm->day)
+ length=4;
+ else
+ length=0;
+ buff[0]=(char) length; // Length is stored first
+ return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
+}
+
+bool Protocol_prep::store_date(TIME *tm)
+{
+ tm->hour= tm->minute= tm->second=0;
+ tm->second_part= 0;
+ return Protocol_prep::store(tm);
+}
+
+
+bool Protocol_prep::store_time(TIME *tm)
+{
+#ifndef DEBUG_OFF
+ DBUG_ASSERT(field_types == 0 ||
+ field_types[field_pos] == MYSQL_TYPE_TIME);
+#endif
+ char buff[15],*pos;
+ uint length;
+ field_pos++;
+ pos= buff+1;
+ pos[0]= tm->neg ? 1 : 0;
+ int4store(pos+1, tm->day);
+ pos[5]= (uchar) tm->hour;
+ pos[6]= (uchar) tm->minute;
+ pos[7]= (uchar) tm->second;
+ int4store(pos+8, tm->second_part);
+ if (tm->second_part)
+ length=11;
+ else if (tm->hour || tm->minute || tm->second || tm->day)
+ length=8;
+ else
+ length=0;
+ buff[0]=(char) length; // Length is stored first
+ return packet->append(buff, length+1, PACKET_BUFFET_EXTRA_ALLOC);
+}
diff --git a/sql/protocol.h b/sql/protocol.h
new file mode 100644
index 00000000000..e9df013e81c
--- /dev/null
+++ b/sql/protocol.h
@@ -0,0 +1,144 @@
+/* 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 */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+#define PACKET_BUFFET_EXTRA_ALLOC 1024
+
+class CONVERT;
+class i_string;
+class THD;
+#ifdef EMBEDDED_LIBRARY
+typedef struct st_mysql_field MYSQL_FIELD;
+#endif
+class Protocol
+{
+protected:
+ THD *thd;
+ String *packet;
+ uint field_pos;
+#ifndef DEBUG_OFF
+ enum enum_field_types *field_types;
+#endif
+ uint field_count;
+ bool net_store_data(const char *from, uint length);
+ bool convert_str(const char *from, uint length);
+#ifdef EMBEDDED_LIBRARY
+ char **next_field;
+ MYSQL_FIELD *next_mysql_field;
+ MEM_ROOT *alloc;
+#endif
+public:
+ CONVERT *convert;
+
+ Protocol() {}
+ Protocol(THD *thd) { init(thd); }
+ void init(THD* thd);
+ bool send_fields(List<Item> *list, uint flag);
+ bool send_records_num(List<Item> *list, ulonglong records);
+ bool store(I_List<i_string> *str_list);
+ bool store(const char *from, CHARSET_INFO *cs);
+ String *storage_packet() { return packet; }
+ inline void free() { packet->free(); }
+ bool write();
+ inline bool store(uint32 from)
+ { return store_long((longlong) from); }
+ inline bool store(longlong from)
+ { return store_longlong((longlong) from, 0); }
+ inline bool store(ulonglong from)
+ { return store_longlong((longlong) from, 1); }
+
+ virtual bool prepare_for_send(List<Item> *item_list)
+ {
+ field_count=item_list->elements;
+ return 0;
+ }
+ virtual void prepare_for_resend()=0;
+
+ virtual bool store_null()=0;
+ virtual bool store_tiny(longlong from)=0;
+ virtual bool store_short(longlong from)=0;
+ virtual bool store_long(longlong from)=0;
+ virtual bool store_longlong(longlong from, bool unsigned_flag)=0;
+ virtual bool store(const char *from, uint length, CHARSET_INFO *cs)=0;
+ virtual bool store(float from, uint32 decimals, String *buffer)=0;
+ virtual bool store(double from, uint32 decimals, String *buffer)=0;
+ virtual bool store(TIME *time)=0;
+ virtual bool store_date(TIME *time)=0;
+ virtual bool store_time(TIME *time)=0;
+ virtual bool store(Field *field)=0;
+};
+
+
+/* Class used for the old (MySQL 4.0 protocol) */
+
+class Protocol_simple :public Protocol
+{
+public:
+ Protocol_simple() {}
+ Protocol_simple(THD *thd) :Protocol(thd) {}
+ virtual void prepare_for_resend();
+ virtual bool store_null();
+ virtual bool store_tiny(longlong from);
+ virtual bool store_short(longlong from);
+ virtual bool store_long(longlong from);
+ virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store(const char *from, uint length, CHARSET_INFO *cs);
+ virtual bool store(TIME *time);
+ virtual bool store_date(TIME *time);
+ virtual bool store_time(TIME *time);
+ virtual bool store(float nr, uint32 decimals, String *buffer);
+ virtual bool store(double from, uint32 decimals, String *buffer);
+ virtual bool store(Field *field);
+};
+
+
+class Protocol_prep :public Protocol
+{
+private:
+ uint bit_fields;
+public:
+ Protocol_prep() {}
+ Protocol_prep(THD *thd) :Protocol(thd) {}
+ virtual bool prepare_for_send(List<Item> *item_list);
+ virtual void prepare_for_resend();
+ virtual bool store_null();
+ virtual bool store_tiny(longlong from);
+ virtual bool store_short(longlong from);
+ virtual bool store_long(longlong from);
+ virtual bool store_longlong(longlong from, bool unsigned_flag);
+ virtual bool store(const char *from,uint length, CHARSET_INFO *cs);
+ virtual bool store(TIME *time);
+ virtual bool store_date(TIME *time);
+ virtual bool store_time(TIME *time);
+ virtual bool store(float nr, uint32 decimals, String *buffer);
+ virtual bool store(double from, uint32 decimals, String *buffer);
+ virtual bool store(Field *field);
+};
+
+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(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, uint length);
+char *net_store_data(char *to,int32 from);
+char *net_store_data(char *to,longlong from);
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 8ed002ca649..82fa87658ed 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -17,6 +17,8 @@
// Sasha Pachev <sasha@mysql.com> is currently in charge of this file
#include "mysql_priv.h"
+#ifdef HAVE_REPLICATION
+
#include "repl_failsafe.h"
#include "sql_repl.h"
#include "slave.h"
@@ -184,7 +186,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 +205,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);
}
@@ -416,6 +418,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
int show_new_master(THD* thd)
{
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("show_new_master");
List<Item> field_list;
char errmsg[SLAVE_ERRMSG_SIZE];
@@ -431,17 +434,17 @@ int show_new_master(THD* thd)
}
else
{
- String* packet = &thd->packet;
field_list.push_back(new Item_empty_string("Log_name", 20));
- field_list.push_back(new Item_empty_string("Log_pos", 20));
- if (send_fields(thd, field_list, 1))
+ field_list.push_back(new Item_return_int("Log_pos", 10,
+ MYSQL_TYPE_LONGLONG));
+ if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
- packet->length(0);
- net_store_data(packet, lex_mi->log_file_name);
- net_store_data(packet, (longlong)lex_mi->pos);
- if (my_net_write(&thd->net, packet->ptr(), packet->length()))
+ protocol->prepare_for_resend();
+ protocol->store(lex_mi->log_file_name, system_charset_info);
+ protocol->store((ulonglong) lex_mi->pos);
+ if (protocol->write())
DBUG_RETURN(-1);
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
}
@@ -481,7 +484,7 @@ int update_slave_list(MYSQL* mysql, MASTER_INFO* mi)
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= mc_mysql_error(mysql);
@@ -608,21 +611,24 @@ int show_slave_hosts(THD* thd)
{
List<Item> field_list;
NET* net = &thd->net;
- String* packet = &thd->packet;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("show_slave_hosts");
- field_list.push_back(new Item_empty_string("Server_id", 20));
+ field_list.push_back(new Item_return_int("Server_id", 10,
+ MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Host", 20));
if (opt_show_slave_auth_info)
{
field_list.push_back(new Item_empty_string("User",20));
field_list.push_back(new Item_empty_string("Password",20));
}
- field_list.push_back(new Item_empty_string("Port",20));
- field_list.push_back(new Item_empty_string("Rpl_recovery_rank", 20));
- field_list.push_back(new Item_empty_string("Master_id", 20));
+ field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Rpl_recovery_rank", 7,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Master_id", 10,
+ MYSQL_TYPE_LONG));
- if (send_fields(thd, field_list, 1))
+ if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
pthread_mutex_lock(&LOCK_slave_list);
@@ -630,25 +636,25 @@ int show_slave_hosts(THD* thd)
for (uint i = 0; i < slave_list.records; ++i)
{
SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i);
- packet->length(0);
- net_store_data(packet, si->server_id);
- net_store_data(packet, si->host);
+ protocol->prepare_for_resend();
+ protocol->store((uint32) si->server_id);
+ protocol->store(si->host, system_charset_info);
if (opt_show_slave_auth_info)
{
- net_store_data(packet, si->user);
- net_store_data(packet, si->password);
+ protocol->store(si->user, system_charset_info);
+ protocol->store(si->password, system_charset_info);
}
- net_store_data(packet, (uint32) si->port);
- net_store_data(packet, si->rpl_recovery_rank);
- net_store_data(packet, si->master_id);
- if (my_net_write(net, (char*)packet->ptr(), packet->length()))
+ protocol->store((uint32) si->port);
+ protocol->store((uint32) si->rpl_recovery_rank);
+ protocol->store((uint32) si->master_id);
+ if (protocol->write())
{
pthread_mutex_unlock(&LOCK_slave_list);
DBUG_RETURN(-1);
}
}
pthread_mutex_unlock(&LOCK_slave_list);
- send_eof(net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -734,7 +740,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;
@@ -742,7 +748,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;
}
@@ -752,10 +758,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;
}
@@ -769,7 +775,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;
}
@@ -779,11 +785,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;
}
@@ -823,16 +829,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;
@@ -873,9 +879,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;
}
@@ -885,7 +891,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;
@@ -913,7 +919,10 @@ 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;
}
+
+#endif /* HAVE_REPLICATION */
+
diff --git a/sql/repl_failsafe.h b/sql/repl_failsafe.h
index ae8bb2bc4d5..a9c504330ab 100644
--- a/sql/repl_failsafe.h
+++ b/sql/repl_failsafe.h
@@ -1,3 +1,4 @@
+#ifdef HAVE_REPLICATION
#ifndef REPL_FAILSAFE_H
#define REPL_FAILSAFE_H
@@ -35,3 +36,4 @@ int register_slave(THD* thd, uchar* packet, uint packet_length);
void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
#endif
+#endif /* HAVE_REPLICATION */
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 9ae813e1c51..4189543e70e 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -21,11 +21,14 @@
- If the variable is thread specific, add it to 'system_variables' struct.
If not, add it to mysqld.cc and an declaration in 'mysql_priv.h'
+ - Don't forget to initialize new fields in global_system_variables and
+ max_system_variables!
- 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
@@ -44,6 +47,7 @@
#endif
#include "mysql_priv.h"
+#include <mysql.h>
#include "slave.h"
#include "sql_acl.h"
#include <my_getopt.h>
@@ -82,6 +86,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
@@ -98,6 +104,7 @@ sys_var_str sys_charset("character_set",
sys_check_charset,
sys_update_charset,
sys_set_default_charset);
+sys_var_client_collation sys_client_collation("client_collation");
sys_var_thd_conv_charset sys_convert_charset("convert_character_set");
sys_var_bool_ptr sys_concurrent_insert("concurrent_insert",
&myisam_concurrent_insert);
@@ -113,6 +120,8 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout",
&delayed_insert_timeout);
sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size",
&delayed_queue_size);
+sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
+ &expire_logs_days);
sys_var_bool_ptr sys_flush("flush", &myisam_flush);
sys_var_long_ptr sys_flush_time("flush_time", &flush_time);
sys_var_thd_ulong sys_interactive_timeout("interactive_timeout",
@@ -147,8 +156,12 @@ 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_pseudo_thread_id("pseudo_thread_id",
+ &SV::pseudo_thread_id);
sys_var_thd_ha_rows sys_max_join_size("max_join_size",
&SV::max_join_size,
fix_max_join_size);
@@ -157,6 +170,8 @@ sys_var_thd_ha_rows 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",
@@ -199,14 +214,18 @@ sys_var_thd_enum sys_query_cache_type("query_cache_type",
sys_var_long_ptr sys_server_id("server_id",&server_id);
sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
&opt_slave_compressed_protocol);
+#ifdef HAVE_REPLICATION
sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout",
&slave_net_timeout);
+#endif
sys_var_long_ptr sys_slow_launch_time("slow_launch_time",
&slow_launch_time);
sys_var_thd_ulong sys_sort_buffer("sort_buffer_size",
&SV::sortbuff_size);
-sys_var_thd_enum sys_table_type("table_type", &SV::table_type,
- &ha_table_typelib);
+sys_var_thd_sql_mode sys_sql_mode("sql_mode",
+ &SV::sql_mode);
+sys_var_thd_enum sys_table_type("table_type", &SV::table_type,
+ &ha_table_typelib);
sys_var_long_ptr sys_table_cache_size("table_cache",
&table_cache_size);
sys_var_long_ptr sys_thread_cache_size("thread_cache_size",
@@ -219,8 +238,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
*/
@@ -282,11 +299,24 @@ 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 */
+#ifdef HAVE_REPLICATION
static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter");
+#endif
static sys_var_rand_seed1 sys_rand_seed1("rand_seed1");
static sys_var_rand_seed2 sys_rand_seed2("rand_seed2");
+static sys_var_thd_ulong sys_default_week_format("default_week_format",
+ &SV::default_week_format);
/*
List of all variables for initialisation and storage in hash
@@ -305,13 +335,17 @@ sys_var *sys_variables[]=
&sys_binlog_cache_size,
&sys_buffer_results,
&sys_bulk_insert_buff_size,
+ &sys_client_collation,
&sys_concurrent_insert,
&sys_connect_timeout,
&sys_convert_charset,
+ &sys_default_week_format,
&sys_delay_key_write,
&sys_delayed_insert_limit,
&sys_delayed_insert_timeout,
&sys_delayed_queue_size,
+ &sys_error_count,
+ &sys_expire_logs_days,
&sys_flush,
&sys_flush_time,
&sys_foreign_key_checks,
@@ -334,8 +368,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,
@@ -349,6 +385,7 @@ sys_var *sys_variables[]=
&sys_net_wait_timeout,
&sys_net_write_timeout,
&sys_new_mode,
+ &sys_pseudo_thread_id,
&sys_query_cache_size,
#ifdef HAVE_QUERY_CACHE
&sys_query_cache_limit,
@@ -363,14 +400,17 @@ sys_var *sys_variables[]=
&sys_safe_updates,
&sys_select_limit,
&sys_server_id,
+#ifdef HAVE_REPLICATION
&sys_slave_compressed_protocol,
&sys_slave_net_timeout,
&sys_slave_skip_counter,
+#endif
&sys_slow_launch_time,
&sys_sort_buffer,
&sys_sql_big_tables,
&sys_sql_low_priority_updates,
&sys_sql_max_join_size,
+ &sys_sql_mode,
&sys_sql_warnings,
&sys_table_cache_size,
&sys_table_type,
@@ -378,7 +418,8 @@ sys_var *sys_variables[]=
&sys_timestamp,
&sys_tmp_table_size,
&sys_tx_isolation,
- &sys_unique_checks
+ &sys_unique_checks,
+ &sys_warning_count
};
@@ -403,14 +444,17 @@ struct show_var_st init_vars[]= {
{sys_bulk_insert_buff_size.name,(char*) &sys_bulk_insert_buff_size,SHOW_SYS},
{sys_charset.name, (char*) &sys_charset, SHOW_SYS},
{"character_sets", (char*) &charsets_list, SHOW_CHAR_PTR},
+ {sys_client_collation.name, (char*) &sys_client_collation, SHOW_SYS},
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{sys_convert_charset.name, (char*) &sys_convert_charset, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR},
+ {"default_week_format", (char*) &sys_default_week_format, SHOW_SYS},
{sys_delay_key_write.name, (char*) &sys_delay_key_write, SHOW_SYS},
{sys_delayed_insert_limit.name, (char*) &sys_delayed_insert_limit,SHOW_SYS},
{sys_delayed_insert_timeout.name, (char*) &sys_delayed_insert_timeout, SHOW_SYS},
{sys_delayed_queue_size.name,(char*) &sys_delayed_queue_size, SHOW_SYS},
+ {sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS},
{sys_flush.name, (char*) &sys_flush, SHOW_SYS},
{sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS},
{"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR},
@@ -430,6 +474,7 @@ struct show_var_st init_vars[]= {
#ifdef HAVE_INNOBASE_DB
{"innodb_additional_mem_pool_size", (char*) &innobase_additional_mem_pool_size, SHOW_LONG },
{"innodb_buffer_pool_size", (char*) &innobase_buffer_pool_size, SHOW_LONG },
+ {"innodb_buffer_pool_awe_mem_mb", (char*) &innobase_buffer_pool_awe_mem_mb, SHOW_LONG },
{"innodb_data_file_path", (char*) &innobase_data_file_path, SHOW_CHAR_PTR},
{"innodb_data_home_dir", (char*) &innobase_data_home_dir, SHOW_CHAR_PTR},
{"innodb_file_io_threads", (char*) &innobase_file_io_threads, SHOW_LONG },
@@ -459,7 +504,9 @@ struct show_var_st init_vars[]= {
{"log", (char*) &opt_log, SHOW_BOOL},
{"log_update", (char*) &opt_update_log, SHOW_BOOL},
{"log_bin", (char*) &opt_bin_log, SHOW_BOOL},
+#ifdef HAVE_REPLICATION
{"log_slave_updates", (char*) &opt_log_slave_updates, SHOW_MY_BOOL},
+#endif
{"log_slow_queries", (char*) &opt_slow_log, SHOW_BOOL},
{sys_log_warnings.name, (char*) &sys_log_warnings, SHOW_SYS},
{sys_long_query_time.name, (char*) &sys_long_query_time, SHOW_SYS},
@@ -470,9 +517,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},
@@ -498,6 +547,7 @@ struct show_var_st init_vars[]= {
{"log_error", (char*) log_error_file, SHOW_CHAR},
{"port", (char*) &mysql_port, SHOW_INT},
{"protocol_version", (char*) &protocol_version, SHOW_INT},
+ {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS},
{sys_read_buff_size.name, (char*) &sys_read_buff_size, SHOW_SYS},
{sys_read_rnd_buff_size.name,(char*) &sys_read_rnd_buff_size, SHOW_SYS},
{sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS},
@@ -506,8 +556,14 @@ 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},
+#ifdef HAVE_REPLICATION
{sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS},
+#endif
{"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL},
{"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL},
{"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL},
@@ -516,7 +572,7 @@ struct show_var_st init_vars[]= {
{"socket", (char*) &mysql_unix_port, SHOW_CHAR_PTR},
#endif
{sys_sort_buffer.name, (char*) &sys_sort_buffer, SHOW_SYS},
- {"sql_mode", (char*) &opt_sql_mode, SHOW_LONG},
+ {sys_sql_mode.name, (char*) &sys_sql_mode, SHOW_SYS},
{"table_cache", (char*) &table_cache_size, SHOW_LONG},
{sys_table_type.name, (char*) &sys_table_type, SHOW_SYS},
{sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS},
@@ -529,7 +585,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}
@@ -607,6 +663,7 @@ static void fix_tx_isolation(THD *thd, enum_var_type type)
If we are changing the thread variable, we have to copy it to NET too
*/
+#ifdef HAVE_REPLICATION
static void fix_net_read_timeout(THD *thd, enum_var_type type)
{
if (type != OPT_GLOBAL)
@@ -625,6 +682,17 @@ static void fix_net_retry_count(THD *thd, enum_var_type type)
if (type != OPT_GLOBAL)
thd->net.retry_count=thd->variables.net_retry_count;
}
+#else /* HAVE_REPLICATION */
+static void fix_net_read_timeout(THD *thd __attribute__(unused),
+ enum_var_type type __attribute__(unused))
+{}
+static void fix_net_write_timeout(THD *thd __attribute__(unused),
+ enum_var_type type __attribute__(unused))
+{}
+static void fix_net_retry_count(THD *thd __attribute__(unused),
+ enum_var_type type __attribute__(unused))
+{}
+#endif /* HAVE_REPLICATION */
static void fix_query_cache_size(THD *thd, enum_var_type type)
@@ -821,7 +889,7 @@ void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type)
if (type == OPT_GLOBAL)
{
pthread_mutex_lock(&LOCK_global_system_variables);
- global_system_variables.*offset= (ulong) option_limits->def_value;
+ global_system_variables.*offset= (ulonglong) option_limits->def_value;
pthread_mutex_unlock(&LOCK_global_system_variables);
}
else
@@ -867,7 +935,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)
{
@@ -898,6 +966,44 @@ err:
return 1;
}
+
+
+bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
+{
+ char buff[80], *error= 0;
+ uint error_len= 0;
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ if (!(res= var->value->val_str(&str)))
+ goto err;
+ var->save_result.ulong_value= (ulong)
+ find_set(enum_names, res->c_ptr(), res->length(), &error, &error_len);
+ if (error_len)
+ {
+ strmake(buff, error, min(sizeof(buff), error_len));
+ goto err;
+ }
+ }
+ else
+ {
+ ulonglong tmp= var->value->val_int();
+ if (tmp >= enum_names->count)
+ {
+ llstr(tmp, buff);
+ goto err;
+ }
+ var->save_result.ulong_value= (ulong) tmp; // Save for update
+ }
+ return 0;
+
+err:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buff);
+ return 1;
+}
+
+
/*
Return an Item for a variable. Used with @@[global.]variable_name
@@ -905,6 +1011,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)
@@ -913,7 +1023,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;
@@ -933,10 +1043,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;
}
@@ -970,6 +1080,40 @@ byte *sys_var_thd_enum::value_ptr(THD *thd, enum_var_type type)
}
+byte *sys_var_thd_sql_mode::value_ptr(THD *thd, enum_var_type type)
+{
+ ulong val;
+ char buff[256];
+ String tmp(buff, sizeof(buff), &my_charset_latin1);
+ my_bool found= 0;
+
+ tmp.length(0);
+ val= ((type == OPT_GLOBAL) ? global_system_variables.*offset :
+ thd->variables.*offset);
+ for (uint i= 0; val; val>>= 1, i++)
+ {
+ if (val & 1)
+ {
+ tmp.append(enum_names->type_names[i]);
+ tmp.append(',');
+ }
+ }
+ if (tmp.length())
+ tmp.length(tmp.length() - 1);
+ return (byte*) thd->strmake(tmp.ptr(), tmp.length());
+}
+
+
+void sys_var_thd_sql_mode::set_default(THD *thd, enum_var_type type)
+{
+ if (type == OPT_GLOBAL)
+ global_system_variables.*offset= 0;
+ else
+ thd->variables.*offset= global_system_variables.*offset;
+}
+
+
+
bool sys_var_thd_bit::update(THD *thd, set_var *var)
{
int res= (*update_func)(thd, var);
@@ -994,7 +1138,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
{
@@ -1021,8 +1165,12 @@ bool sys_var_thd_conv_charset::update(THD *thd, set_var *var)
if (var->type == OPT_GLOBAL)
global_system_variables.convert_set= var->save_result.convert;
else
+ {
thd->lex.convert_set= thd->variables.convert_set=
var->save_result.convert;
+ thd->protocol_simple.init(thd);
+ thd->protocol_prep.init(thd);
+ }
return 0;
}
@@ -1036,6 +1184,55 @@ byte *sys_var_thd_conv_charset::value_ptr(THD *thd, enum_var_type type)
}
+bool sys_var_client_collation::check(THD *thd, set_var *var)
+{
+ CHARSET_INFO *tmp;
+ char buff[80];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+
+ if (!var->value) // Default value
+ {
+ var->save_result.charset= (var->type != OPT_GLOBAL ?
+ global_system_variables.thd_charset
+ : thd->db_charset);
+ return 0;
+ }
+
+ if (!(res=var->value->val_str(&str)))
+ res= &empty_string;
+
+ if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))))
+ {
+ my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr());
+ return 1;
+ }
+ var->save_result.charset= tmp; // Save for update
+ return 0;
+}
+
+bool sys_var_client_collation::update(THD *thd, set_var *var)
+{
+ if (var->type == OPT_GLOBAL)
+ global_system_variables.thd_charset= var->save_result.charset;
+ else
+ {
+ thd->variables.thd_charset= var->save_result.charset;
+ thd->protocol_simple.init(thd);
+ thd->protocol_prep.init(thd);
+ }
+ return 0;
+}
+
+
+byte *sys_var_client_collation::value_ptr(THD *thd, enum_var_type type)
+{
+ CHARSET_INFO *cs= ((type == OPT_GLOBAL) ?
+ global_system_variables.thd_charset :
+ thd->variables.thd_charset);
+ return cs ? (byte*) cs->name : (byte*) "";
+}
+
+
bool sys_var_timestamp::update(THD *thd, set_var *var)
{
@@ -1084,6 +1281,7 @@ byte *sys_var_insert_id::value_ptr(THD *thd, enum_var_type type)
}
+#ifdef HAVE_REPLICATION
bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
{
int result= 0;
@@ -1119,7 +1317,7 @@ bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
UNLOCK_ACTIVE_MI;
return 0;
}
-
+#endif /* HAVE_REPLICATION */
bool sys_var_rand_seed1::update(THD *thd, set_var *var)
{
@@ -1189,6 +1387,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:
@@ -1250,7 +1463,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) ;
@@ -1302,7 +1516,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;
}
@@ -1374,7 +1588,7 @@ int set_var::check(THD *thd)
return 0;
}
- if (value->fix_fields(thd,0))
+ if (value->fix_fields(thd, 0, &value) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
{
@@ -1403,7 +1617,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 c74f1e827bd..b84e0b888e2 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -28,7 +28,7 @@
class sys_var;
class set_var;
typedef struct system_variables SV;
-extern TYPELIB bool_typelib, delay_key_write_typelib;
+extern TYPELIB bool_typelib, delay_key_write_typelib, sql_mode_typelib;
enum enum_var_type
{
@@ -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
{
@@ -55,6 +56,7 @@ public:
virtual ~sys_var() {}
virtual bool check(THD *thd, set_var *var) { return 0; }
bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names);
+ bool check_set(THD *thd, set_var *var, TYPELIB *enum_names);
virtual bool update(THD *thd, set_var *var)=0;
virtual void set_default(THD *thd, enum_var_type type) {}
virtual SHOW_TYPE type() { return SHOW_UNDEF; }
@@ -236,6 +238,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; }
@@ -268,6 +274,7 @@ public:
class sys_var_thd_enum :public sys_var_thd
{
+protected:
ulong SV::*offset;
TYPELIB *enum_names;
public:
@@ -292,6 +299,21 @@ public:
};
+class sys_var_thd_sql_mode :public sys_var_thd_enum
+{
+public:
+ sys_var_thd_sql_mode(const char *name_arg, ulong SV::*offset_arg)
+ :sys_var_thd_enum(name_arg, offset_arg, &sql_mode_typelib)
+ {}
+ bool check(THD *thd, set_var *var)
+ {
+ return check_set(thd, var, enum_names);
+ }
+ void set_default(THD *thd, enum_var_type type);
+ byte *value_ptr(THD *thd, enum_var_type type);
+};
+
+
class sys_var_thd_bit :public sys_var_thd
{
sys_update_func update_func;
@@ -352,6 +374,7 @@ public:
};
+#ifndef EMBEDDED_LIBRARY
class sys_var_slave_skip_counter :public sys_var
{
public:
@@ -364,7 +387,7 @@ public:
type() or value_ptr()
*/
};
-
+#endif
class sys_var_rand_seed1 :public sys_var
{
@@ -400,6 +423,47 @@ public:
bool check_default(enum_var_type type) { return 0; }
};
+class sys_var_client_collation :public sys_var_thd
+{
+public:
+ sys_var_client_collation(const char *name_arg) :sys_var_thd(name_arg)
+ {}
+ bool check(THD *thd, set_var *var);
+ bool update(THD *thd, set_var *var);
+ SHOW_TYPE type() { return SHOW_CHAR; }
+ byte *value_ptr(THD *thd, enum_var_type type);
+ bool check_update_type(Item_result type)
+ {
+ return type != STRING_RESULT; /* Only accept strings */
+ }
+ bool check_default(enum_var_type type) { return 0; }
+};
+
+
+/* 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
@@ -425,6 +489,7 @@ public:
enum_var_type type;
union
{
+ CHARSET_INFO *charset;
CONVERT *convert;
ulong ulong_value;
} save_result;
@@ -439,7 +504,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),
+ item->charset())))
value=value_arg; /* Give error message later */
}
else
diff --git a/sql/share/Makefile.am b/sql/share/Makefile.am
index c70ac9ccf57..35202ff4722 100644
--- a/sql/share/Makefile.am
+++ b/sql/share/Makefile.am
@@ -7,7 +7,7 @@ dist-hook:
done; \
sleep 1 ; touch $(srcdir)/*/errmsg.sys
$(INSTALL_DATA) $(srcdir)/charsets/README $(distdir)/charsets
- $(INSTALL_DATA) $(srcdir)/charsets/Index $(distdir)/charsets
+ $(INSTALL_DATA) $(srcdir)/charsets/Index.xml $(distdir)/charsets
all: @AVAILABLE_LANGUAGES_ERRORS@
@@ -25,8 +25,7 @@ install-data-local:
done
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)/charsets
$(INSTALL_DATA) $(srcdir)/charsets/README $(DESTDIR)$(pkgdatadir)/charsets/README
- $(INSTALL_DATA) $(srcdir)/charsets/Index $(DESTDIR)$(pkgdatadir)/charsets/Index
- $(INSTALL_DATA) $(srcdir)/charsets/*.conf $(DESTDIR)$(pkgdatadir)/charsets
+ $(INSTALL_DATA) $(srcdir)/charsets/*.xml $(DESTDIR)$(pkgdatadir)/charsets
fix_errors:
for lang in @AVAILABLE_LANGUAGES@; \
diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index
deleted file mode 100644
index 5cf30682cc0..00000000000
--- a/sql/share/charsets/Index
+++ /dev/null
@@ -1,38 +0,0 @@
-# sql/share/charsets/Index
-#
-# This file lists all of the available character sets. Please keep this
-# file sorted by character set number.
-
-
-big5 1
-czech 2
-dec8 3
-dos 4
-german1 5
-hp8 6
-koi8_ru 7
-latin1 8
-latin2 9
-swe7 10
-usa7 11
-ujis 12
-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 23
-gb2312 24
-greek 25
-win1250 26
-croat 27
-gbk 28
-cp1257 29
-latin5 30
-latin1_de 31
diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml
new file mode 100644
index 00000000000..4d54b8b53ce
--- /dev/null
+++ b/sql/share/charsets/Index.xml
@@ -0,0 +1,497 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets max-id="82">
+
+<description>
+This file lists all of the available character sets.
+To make maintaining easier please:
+ - keep records sorted by collation number.
+ - change charsets.max-id when adding a new collation.
+</description>
+
+<charset name="big5">
+ <family>Traditional Chinese</family>
+ <alias>big-5</alias>
+ <alias>bigfive</alias>
+ <alias>big-five</alias>
+ <alias>cn-big5</alias>
+ <alias>csbig5</alias>
+ <collation name="big5" id="1" order="Chinese">
+ <flag>primary</flag>
+ <flag>compiled"</flag>
+ </collation>
+</charset>
+
+<charset name="latin2">
+ <family>Central European</family>
+ <alias>csisolatin2</alias>
+ <alias>iso-8859-2</alias>
+ <alias>iso-ir-101</alias>
+ <alias>iso_8859-2</alias>
+ <alias>iso_8859-2:1987</alias>
+ <alias>l2</alias>
+ <collation name="czech" id="2" order="Czech" flag="compiled"/>
+ <collation name="latin2" id="9" flag="primary">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+ <collation name="hungarian" id="21" order="Hungarian"/>
+ <collation name="croat" id="27" order="Croatian"/>
+ <collation name="latin2_bin" id="77" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="dec8">
+ <family>Western</family>
+ <collation name="dec_bin" id="69" order="Binary" flag="binary"/>
+ <collation name="dec8" id="3" flag="primary">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+</charset>
+
+<charset name="pclatin1">
+ <family>Western</family>
+ <alias>850</alias>
+ <alias>cp850</alias>
+ <alias>cspc850multilingual</alias>
+ <alias>ibm850</alias>
+ <collation name="pclatin1" id="4" flag="primary">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+ <collation name="pclatin1_bin" id="80" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="latin1">
+ <family>Western</family>
+ <alias>csisolatin1</alias>
+ <alias>iso-8859-1</alias>
+ <alias>iso-ir-100</alias>
+ <alias>iso_8859-1</alias>
+ <alias>iso_8859-1:1987</alias>
+ <alias>l1</alias>
+ <alias>latin1</alias>
+ <collation name="german1" id="5" order="German Duden"/>
+ <collation name="latin1" id="8" order="Finnish, Swedish" flag="primary"/>
+ <collation name="danish" id="15" order="Danish"/>
+ <collation name="latin1_de" id="31" order="German DIN" flag="compiled"/>
+ <collation name="latin1_bin" id="47" order="Binary" flag="binary"/>
+ <collation name="latin1_ci_as" id="48">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+ <collation name="latin1_cs_as" id="49">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+</charset>
+
+<charset name="hp8">
+ <family>Western</family>
+ <alias>hproman8</alias>
+ <collation name="hp8_bin" id="72" order="Binary" flag="binary"/>
+ <collation name="hp8" id="6" flag="primary">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+</charset>
+
+<charset name="koi8r">
+ <family>Cyrillic</family>
+ <alias>koi8-r</alias>
+ <alias>cskoi8r</alias>
+ <collation name="koi8r" id="7" order="Russian" flag="primary"/>
+ <collation name="koi8r_bin" id="74" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="swe7">
+ <family>Western</family>
+ <alias>iso-646-se</alias>
+ <collation name="swe7" id="10" order="Swedish" flag="primary"/>
+ <collation name="swe7_bin" id="82" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="ascii">
+ <family>Western</family>
+ <alias>us</alias>
+ <alias>us-ascii</alias>
+ <alias>csascii</alias>
+ <alias>iso-ir-6</alias>
+ <alias>iso646-us</alias>
+ <collation name="ascii" id="11" order="English" flag="primary"/>
+ <collation name="ascii_bin" id="65" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="ujis">
+ <family>Japanese</family>
+ <alias>euc-jp</alias>
+ <collation name="ujis" id="12" order="Japanese" flag="primary"/>
+</charset>
+
+<charset name="sjis">
+ <family>Japanese</family>
+ <alias>s-jis</alias>
+ <alias>shift-jis</alias>
+ <alias>x-sjis</alias>
+ <collation name="sjis" id="13" order="Japanese" flag="primary"/>
+</charset>
+
+<charset name="cp1251">
+ <family>Cyrillic</family>
+ <alias>windows-1251</alias>
+ <alias>ms-cyr</alias>
+ <alias>ms-cyrillic</alias>
+ <collation name="cp1251" id="14" flag="primary">
+ <order>Belarusian</order>
+ <order>Bulgarian</order>
+ <order>Macedonian</order>
+ <order>Russian</order>
+ <order>Serbian</order>
+ <order>Mongolian</order>
+ <order>Ukrainian</order>
+ </collation>
+ <collation name="win1251ukr" id="23" order="Depreciated"/>
+ <collation name="cp1251_bin" id="50" order="Binary" flag="binary"/>
+ <collation name="cp1251_ci_as" id="51">
+ <order>Belarusian</order>
+ <order>Bulgarian</order>
+ <order>Macedonian</order>
+ <order>Russian</order>
+ <order>Serbian</order>
+ <order>Mongolian</order>
+ <order>Ukrainian</order>
+ </collation>
+ <collation name="cp1251_cs_as" id="52">
+ <order>Belarusian</order>
+ <order>Bulgarian</order>
+ <order>Macedonian</order>
+ <order>Russian</order>
+ <order>Serbian</order>
+ <order>Mongolian</order>
+ <order>Ukrainian</order>
+ </collation>
+</charset>
+
+<charset name="hebrew">
+ <family>Hebrew</family>
+ <alias>csisolatinhebrew</alias>
+ <alias>iso-8859-8</alias>
+ <alias>iso-ir-138</alias>
+ <collation name="hebrew" id="16" order="Hebrew" flag="primary"/>
+ <collation name="hebrew_bin" id="71" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="tis620">
+ <family>Thai</family>
+ <alias>tis-620</alias>
+ <collation name="tis620" id="18" order="Thai">
+ <flag>primary</flag>
+ <flag>compiled</flag>
+ </collation>
+</charset>
+
+<charset name="euckr">
+ <family>Korean</family>
+ <alias>euc_kr</alias>
+ <alias>euc-kr</alias>
+ <collation name="euckr" id="19" order="Korean">
+ <flag>primary</flag>
+ <flag>compiled"</flag>
+ </collation>
+</charset>
+
+<charset name="latin7">
+ <family>Baltic</family>
+ <alias>BalticRim</alias>
+ <alias>iso-8859-13</alias>
+ <alias>l7</alias>
+ <collation name="estonia" id="20" order="Estonian" flag="primary"/>
+ <collation name="latvian" id="41" order="Latvian"/>
+ <collation name="latvian1" id="42" order="Latvian"/>
+ <collation name="latin7_bin" id="79" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="koi8u">
+ <family>Cyrillic</family>
+ <alias>koi8-u</alias>
+ <collation name="koi8u" id="22" order="Ukranian" flag="primary"/>
+ <collation name="koi8u_bin" id="75" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="gb2312">
+ <family>Simplified Chinese</family>
+ <alias>chinese</alias>
+ <alias>iso-ir-58</alias>
+ <collation name="gb2312" id="24" order="Chinese">
+ <flag>primary</flag>
+ <flag>compiled"</flag>
+ </collation>
+</charset>
+
+<charset name="greek">
+ <family>Greek</family>
+ <alias>csisolatingreek</alias>
+ <alias>ecma-118</alias>
+ <alias>greek8</alias>
+ <alias>iso-8859-7</alias>
+ <alias>iso-ir-126</alias>
+ <collation name="greek" id="25" order="Greek" flag="primary"/>
+ <collation name="greek_bin" id="70" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="cp1250">
+ <family>Central European</family>
+ <alias>ms-ce</alias>
+ <alias>windows-1250</alias>
+ <collation name="cp1250" id="26" flag="primary">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+ <collation name="cp1250_czech" id="34" order="Czech"/>
+ <collation name="cp1250_bin" id="66" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="gbk">
+ <family>East Asian</family>
+ <alias>cp936</alias>
+ <collation name="gbk" id="28" order="Chinese">
+ <flag>primary</flag>
+ <flag>compiled</flag>
+ </collation>
+</charset>
+
+<charset name="cp1257">
+ <family>Baltic</family>
+ <alias>WinBaltRim</alias>
+ <alias>windows-1257</alias>
+ <collation name="cp1257" id="29" order="Depreciated"/>
+ <collation name="cp1257_bin" id="58" order="Binary" flag="binary"/>
+ <collation name="cp1257_ci_ai" id="59" flag="primary">
+ <order>Latvian</order>
+ <order>Lithuanian</order>
+ </collation>
+ <collation name="cp1257_ci_as" id="60">
+ <order>Latvian</order>
+ <order>Lithuanian</order>
+ </collation>
+ <collation name="cp1257_cs_as" id="61">
+ <order>Latvian</order>
+ <order>Lithuanian</order>
+ </collation>
+</charset>
+
+<charset name="latin5">
+ <family>South Asian</family>
+ <alias>csisolatin5</alias>
+ <alias>iso-8859-9</alias>
+ <alias>iso-ir-148</alias>
+ <alias>l5</alias>
+ <alias>latin5</alias>
+ <alias>turkish</alias>
+ <collation name="latin5" id="30" order="Turkish" flag="primary"/>
+ <collation name="latin5_bin" id="78" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="armscii8">
+ <family>South Asian</family>
+ <alias>armscii-8</alias>
+ <collation name="armscii8" id="32" order="Armenian" flag="primary"/>
+ <collation name="armscii_bin" id="64" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="utf8">
+ <family>Unicode</family>
+ <alias>utf-8</alias>
+ <collation name="utf8" id="33" flag="primary"/>
+</charset>
+
+<charset name="ucs2">
+ <family>Unicode</family>
+ <collation name="ucs2" id="35" flag="primary"/>
+</charset>
+
+<charset name="cp866">
+ <family>Cyrillic</family>
+ <alias>866</alias>
+ <alias>csibm866</alias>
+ <alias>ibm866</alias>
+ <alias>DOSCyrillicRussian</alias>
+ <collation name="cp866" id="36" order="Russian" flag="primary"/>
+ <collation name="cp866_bin" id="68" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="keybcs2">
+ <family>Central European</family>
+ <collation name="keybcs2" id="37" order="Czech" flag="primary"/>
+ <collation name="keybcs2_bin" id="73" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="MacCE">
+ <family>Central European</family>
+ <alias>MacCentralEurope</alias>
+ <collation name="macce" id="38" flag="primary">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+ <collation name="macce_bin" id="43" order="Binary" flag="binary"/>
+ <collation name="macce_ci_ai" id="44">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+ <collation name="macce_ci_as" id="45">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+ <collation name="macce_cs_as" id="46">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+</charset>
+
+<charset name="MacRoman">
+ <family>Western</family>
+ <alias>Mac</alias>
+ <alias>Macintosh</alias>
+ <alias>csmacintosh</alias>
+ <collation name="macroman" id="39" flag="primary">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+ <collation name="macroman_bin" id="53" order="Binary" flag="binary"/>
+ <collation name="macroman_ci_as" id="54">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+ <collation name="macroman_ci_ai" id="55">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+ <collation name="macroman_cs_as" id="56">
+ <order>Dutch</order>
+ <order>English</order>
+ <order>French</order>
+ <order>German Duden</order>
+ <order>Italian</order>
+ <order>Latin</order>
+ <order>Pogtuguese</order>
+ <order>Spanish</order>
+ </collation>
+</charset>
+
+<charset name="pclatin2">
+ <family>Central European</family>
+ <alias>852</alias>
+ <alias>cp852</alias>
+ <alias>ibm852</alias>
+ <collation name="pclatin2" id="40" flag="primary">
+ <order>Hungarian</order>
+ <order>Polish</order>
+ <order>Romanian</order>
+ <order>Croatian</order>
+ <order>Slovak</order>
+ <order>Slovenian</order>
+ <order>Sorbian</order>
+ </collation>
+ <collation name="pclatin2_bin" id="81" order="Binary" flag="binary"/>
+</charset>
+
+<charset name="cp1256">
+ <family>Arabic</family>
+ <alias>ms-arab</alias>
+ <alias>windows-1256</alias>
+ <collation name="cp1256_bin" id="67" order="Binary" flag="binary"/>
+ <collation name="cp1256" id="57" order="Arabic" flag="primary">
+ <order>Arabic</order>
+ <order>Persian</order>
+ <order>Pakistani</order>
+ <order>Urdu</order>
+ </collation>
+</charset>
+
+<charset name="binary">
+ <collation name="binary" id="63" order="Binary">
+ <flag>primary</flag>
+ <flag>compiled</flag>
+ </collation>
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/MacCE.xml b/sql/share/charsets/MacCE.xml
new file mode 100644
index 00000000000..9a6a392b426
--- /dev/null
+++ b/sql/share/charsets/MacCE.xml
@@ -0,0 +1,189 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="MacCE">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="macce">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="macce_bin" flag="binary"/>
+
+<collation name="macce_ci_ai">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="macce_ci_as">
+<map>
+ 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
+
+</map>
+</collation>
+
+
+<collation name="macce_cs_as">
+<map>
+ 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
+</map>
+</collation>
+
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/MacRoman.xml b/sql/share/charsets/MacRoman.xml
new file mode 100644
index 00000000000..9dc4d73b3ef
--- /dev/null
+++ b/sql/share/charsets/MacRoman.xml
@@ -0,0 +1,182 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="MacRoman">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+<collation name="macroman">
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="macroman_bin" flag="binary"/>
+
+<collation name="macroman_ci_ai">
+<map>
+ 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
+
+</map>
+</collation>
+
+<collation name="macroman_ci_as">
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="macroman_cs_as">
+<map>
+ 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
+</map>
+</collation>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/armscii8.xml b/sql/share/charsets/armscii8.xml
new file mode 100644
index 00000000000..5012a3d84a9
--- /dev/null
+++ b/sql/share/charsets/armscii8.xml
@@ -0,0 +1,121 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="armscii8">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="armscii8">
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="armscii_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/ascii.xml b/sql/share/charsets/ascii.xml
new file mode 100644
index 00000000000..c94901b1ae7
--- /dev/null
+++ b/sql/share/charsets/ascii.xml
@@ -0,0 +1,121 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="ascii">
+
+<ctype>
+<map>
+ 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
+ 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 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="ascii">
+<map>
+ 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 5C 5D 5B 5E 5F
+ 45 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 59 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
+</map>
+</collation>
+
+<collation name="ascii_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/win1250.conf b/sql/share/charsets/cp1250.xml
index 31d253d7381..b858fbff2a0 100644
--- a/sql/share/charsets/win1250.conf
+++ b/sql/share/charsets/cp1250.xml
@@ -1,6 +1,11 @@
-# Configuration file for the win1250 character set.
+<?xml version='1.0' encoding="utf-8"?>
-# The ctype array must have 257 elements.
+<charsets>
+
+<charset name="cp1250">
+
+<ctype>
+<map>
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
@@ -18,8 +23,12 @@
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
+</map>
+</ctype>
+
-# The to_lower array must have 256 elements.
+<lower>
+<map>
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
@@ -36,8 +45,12 @@
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
+</map>
+</lower>
-# The to_upper array must have 256 elements.
+
+<upper>
+<map>
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
@@ -54,8 +67,34 @@
D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE A7
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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
-# The sort_order array must have 256 elements.
+
+<collation name="cp1250">
+<map>
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
@@ -72,3 +111,13 @@
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
+</map>
+</collation>
+
+<collation name="cp1250_czech"/>
+
+<collation name="cp1250_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/cp1251.conf b/sql/share/charsets/cp1251.conf
deleted file mode 100644
index 6af97c891b8..00000000000
--- a/sql/share/charsets/cp1251.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the cp1251 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 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 00 00 00 00 00 00
- 00 00 00 00 00 00 00 00 02 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 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 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 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 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 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 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 D7 D8 D9 DA DB DC DD DE DF
-
-# 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 7C 7D 7E 7F 80
- 81 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 82 83 84 85 FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF 61 FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF 61 FF FF FF FF FF FF FF
- 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
- 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
diff --git a/sql/share/charsets/cp1251.xml b/sql/share/charsets/cp1251.xml
new file mode 100644
index 00000000000..79b71df9baf
--- /dev/null
+++ b/sql/share/charsets/cp1251.xml
@@ -0,0 +1,197 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="cp1251">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+
+</map>
+</unicode>
+
+
+<collation name="cp1251">
+<map>
+ 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 7C 7D 7E 7F 80
+ 81 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 82 83 84 85 FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF 61 FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF 61 FF FF FF FF FF FF FF
+ 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
+ 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
+</map>
+</collation>
+
+
+<collation name="cp1251_bin" flag="binary"/>
+
+
+<collation name="cp1251_ci_as">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="cp1251_cs_as">
+<!--
+# 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.
+-->
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="win1251ukr">
+<map>
+ 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
+ 20 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
+ 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 84 CA CB 88 CC 87 CD CE CF D0 8D
+ D1 D2 8C 8C 84 D3 D4 D5 88 D6 87 D7 D8 D9 DA 8D
+ 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
+ 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
+</map>
+</collation>
+
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/cp1256.xml b/sql/share/charsets/cp1256.xml
new file mode 100644
index 00000000000..a747c7c3a93
--- /dev/null
+++ b/sql/share/charsets/cp1256.xml
@@ -0,0 +1,124 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<!-- Arabic, Persian, Pakistani, Urdu -->
+
+<charsets>
+
+<charset name="cp1256">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="cp1256">
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="cp1256_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/cp1257.conf b/sql/share/charsets/cp1257.conf
deleted file mode 100644
index 610ed5a646f..00000000000
--- a/sql/share/charsets/cp1257.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the cp1257 character set.
-
-# 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 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 00 00 00 00 00 00 00 00 00 00 00 00 00
- 01 01 00 00 00 00 01 00 01 00 00 01 00 00 00 00
- 01 00 00 00 00 00 00 00 01 00 00 01 00 00 01 00
- 02 02 00 00 00 00 02 00 02 00 00 02 00 00 00 00
- 02 00 00 00 00 00 00 00 02 00 00 02 00 00 02 00
-
-# 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 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 C2 C3 C4 C5 E6 C7 E8 C9 CA EB CC CD CE CF
- F0 D1 D2 D3 D4 D5 D6 D7 F8 D9 DA FB DC DD 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 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 E2 E3 E4 E5 C6 E7 C8 E9 EA CB EC ED EE EF
- D0 F1 F2 F3 F4 F5 F6 F7 D8 F9 FA DB FC FD 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
- 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 44 46 47 4A 4B 4C 4D 50 51 52 53 54 55
- 56 57 58 59 5B 5C 5F 60 61 4E FF 62 63 64 65 66
- 67 41 43 44 46 47 4A 4B 4C 4D 50 51 52 53 54 55
- 56 57 58 59 5B 5C 5F 60 61 4E FF 68 69 6A 6B FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- 42 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
- 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
diff --git a/sql/share/charsets/cp1257.xml b/sql/share/charsets/cp1257.xml
new file mode 100644
index 00000000000..7f1f8293aae
--- /dev/null
+++ b/sql/share/charsets/cp1257.xml
@@ -0,0 +1,210 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="cp1257">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="cp1257">
+<map>
+ 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 44 46 47 4A 4B 4C 4D 50 51 52 53 54 55
+ 56 57 58 59 5B 5C 5F 60 61 4E FF 62 63 64 65 66
+ 67 41 43 44 46 47 4A 4B 4C 4D 50 51 52 53 54 55
+ 56 57 58 59 5B 5C 5F 60 61 4E FF 68 69 6A 6B FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ 42 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
+ 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
+</map>
+</collation>
+
+
+<collation name="cp1257_bin" flag="binary"/>
+
+
+<collation name="cp1257_ci_ai">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="cp1257_ci_as">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="cp1257_cs_as">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="cp1257ltlv">
+<map>
+ 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 49 4D 4F 57 59 5D 5F 65 67 6B 6F 71 75
+ 79 7B 7D 81 85 87 8D 8F 91 93 95 FF FF FF FF FF
+ FF 42 48 4A 4E 50 58 5A 5E 60 66 68 6C 70 72 76
+ 7A 7C 7E 82 86 88 8E 90 92 94 96 FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF 7F FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF 80 FF FF FF FF FF
+ 45 63 43 FF FF FF 53 51 4B FF FF 55 5B 69 61 6D
+ 83 FF 73 FF 77 FF FF FF 8B FF FF 89 FF 99 97 FF
+ 46 64 44 FF FF FF 54 52 4C FF FF 56 5C 6A 62 6E
+ 84 FF 74 FF 78 FF FF FF 8C FF FF 8A FF 9A 98 FF
+</map>
+</collation>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/cp866.xml b/sql/share/charsets/cp866.xml
new file mode 100644
index 00000000000..43bab971bb3
--- /dev/null
+++ b/sql/share/charsets/cp866.xml
@@ -0,0 +1,124 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="cp866">
+<!-- cp866_DOSCyrillicRussian -->
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="cp866">
+<!-- Case insensitive, accent sensitive -->
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="cp866_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/croat.conf b/sql/share/charsets/croat.conf
deleted file mode 100644
index fbbe3328547..00000000000
--- a/sql/share/charsets/croat.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the croat 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 01 00 00 00 01 00 00
- 00 00 00 00 00 00 00 00 00 02 00 00 00 02 00 00
- 48 10 10 10 10 10 10 10 10 10 10 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 02
-
-# 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 9A 8B 8C 8D 9E 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 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 8A 9B 9C 9D 8E 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 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 46 48 49 4A 4B 4C 4D 4E 4F 50 51 52
- 53 54 55 56 58 59 5A 5B 5C 5D 5E 5B 5C 5D 5E 5F
- 60 41 42 43 46 48 49 4A 4B 4C 4D 4E 4F 50 51 52
- 53 54 55 56 58 59 5A 5B 5C 5D 5E 7B 7C 7D 7E 7F
- 80 81 82 83 84 85 86 87 88 89 57 8B 8C 8D 5F 8F
- 90 91 92 93 94 95 96 97 98 99 57 9B 9C 9D 5F 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
- 41 41 41 41 5C 5B 45 43 44 45 45 45 49 49 49 49
- 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
diff --git a/sql/share/charsets/danish.conf b/sql/share/charsets/danish.conf
deleted file mode 100644
index f99590ed6f3..00000000000
--- a/sql/share/charsets/danish.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the danish 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 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 02
-
-# 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 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 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
- 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 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
- 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
- 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
diff --git a/sql/share/charsets/dec8.conf b/sql/share/charsets/dec8.conf
deleted file mode 100644
index a4849aaa04c..00000000000
--- a/sql/share/charsets/dec8.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the dec8 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 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 02
-
-# 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 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 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
- 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 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
- 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
- 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
diff --git a/sql/share/charsets/latin1.conf b/sql/share/charsets/dec8.xml
index cf974aefa14..7b40041ec53 100644
--- a/sql/share/charsets/latin1.conf
+++ b/sql/share/charsets/dec8.xml
@@ -1,6 +1,11 @@
-# Configuration file for the latin1 character set
+<?xml version='1.0' encoding="utf-8"?>
-# ctype array (must have 257 elements)
+<charsets>
+
+<charset name="dec8">
+
+<ctype>
+<map>
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
@@ -18,8 +23,12 @@
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 02
+</map>
+</ctype>
+
-# to_lower array (must have 256 elements)
+<lower>
+<map>
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
@@ -36,8 +45,12 @@
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
+</map>
+</lower>
-# to_upper array (must have 256 elements)
+
+<upper>
+<map>
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
@@ -54,8 +67,34 @@
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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
-# sort_order array (must have 256 elements)
+
+<collation name="dec8">
+<map>
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
@@ -72,3 +111,12 @@
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
+</map>
+</collation>
+
+<collation name="dec_bin" flag="binary"/>
+
+</charset>
+
+
+</charsets>
diff --git a/sql/share/charsets/dos.conf b/sql/share/charsets/dos.conf
deleted file mode 100644
index dda86d0f3e8..00000000000
--- a/sql/share/charsets/dos.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the dos character set
-
-# ctype array (must have 257 elements)
- 00
- 20 30 30 30 30 30 30 20 20 28 28 28 28 28 30 30
- 30 30 30 30 30 30 30 30 30 30 20 30 30 30 30 30
- 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 30
- 02 02 02 02 02 02 02 02 02 02 02 02 02 02 01 01
- 01 02 01 02 02 02 02 02 02 01 01 10 10 10 10 10
- 02 02 02 02 02 01 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 20
-
-# 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
- 87 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 84 86
- 82 91 91 93 94 95 96 97 98 94 81 9B 9C 9D 9E 9F
- A0 A1 A2 A3 A4 A4 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 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 9A 90 41 8E 41 8F 80 45 45 45 49 49 49 8E 8F
- 90 92 92 4F 99 4F 55 55 59 99 9A 9B 9C 9D 9E 9F
- 41 49 4F 55 A5 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 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
- 43 59 45 41 5C 41 5B 43 45 45 45 49 49 49 5C 5B
- 45 5C 5C 4F 5D 4F 55 55 59 5D 59 24 24 24 24 24
- 41 49 4F 55 4E 4E A6 A7 3F A9 AA AB AC 21 22 22
- 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
diff --git a/sql/share/charsets/estonia.conf b/sql/share/charsets/estonia.conf
deleted file mode 100644
index 76bbc021b0c..00000000000
--- a/sql/share/charsets/estonia.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the estonia character set.
-
-# 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
- 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 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 02
-
-# 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 02 03 04 05 06 07 08 09 2E 2F 30 31 32 0A 0B
- 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B
- 2C 33 34 35 36 37 38 27 39 3A 3B 5D 3C 28 3D 3E
- 76 7A 7C 7E 80 81 82 83 84 85 3F 40 5E 5F 60 41
- 42 86 90 92 98 9A A4 A6 AA AC B2 B4 B8 BE C0 C6
- CE D0 D2 D6 E5 E8 EE F0 FA FC DD 43 44 45 46 47
- 48 87 91 93 99 9B A5 A7 AB AD B3 B5 B9 BF C1 C7
- CF D1 D3 D7 E6 E9 EF F1 FB FD DE 49 4A 4B 4C 1C
- 01 1D 57 1E 5A 74 71 72 1F 75 20 5B 21 4E 52 51
- 22 55 56 58 59 73 2A 2B 23 E7 24 5C 25 4F 54 26
- 2D FE 66 67 68 FF 4D 69 CC 6A D4 62 6B 29 6C 8E
- 6D 61 7D 7F 50 6E 6F 70 CD 7B D5 63 77 78 79 8F
- 8C B0 88 94 F4 8A A2 A0 96 9C DF 9E A8 B6 AE BA
- 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
diff --git a/sql/share/charsets/german1.conf b/sql/share/charsets/german1.conf
deleted file mode 100644
index 3090c921ebe..00000000000
--- a/sql/share/charsets/german1.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the german1 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 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 02
-
-# 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 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 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
- 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 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
- 41 41 41 41 41 41 41 43 45 45 45 45 49 49 49 49
- 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
diff --git a/sql/share/charsets/greek.conf b/sql/share/charsets/greek.conf
deleted file mode 100644
index 73d67d6ee71..00000000000
--- a/sql/share/charsets/greek.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the greek 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 00 00 10 10 10 10 00 10 10 10 00 10
- 10 10 10 10 10 10 01 10 01 01 01 10 01 10 01 01
- 02 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 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 02 02 02 00
-
-# 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 A8 A9 AA AB AC AD AE AF
- B0 B1 B2 B3 B4 B5 DC B7 DD DE DF BB FC BD FD FE
- C0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
- F0 F1 D2 F3 F4 F5 F6 F7 F8 F9 FA FB 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 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
- DA 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 C1 C5 C7 C9
- DB 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 DA DB CF D5 D9 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 C1 B7 C5 C7 C9 BB CF BD D5 D9
- C9 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 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
diff --git a/sql/share/charsets/greek.xml b/sql/share/charsets/greek.xml
new file mode 100644
index 00000000000..1ad3d1bc9d2
--- /dev/null
+++ b/sql/share/charsets/greek.xml
@@ -0,0 +1,122 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="greek">
+
+<ctype>
+<map>
+ 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 00 00 10 10 10 10 00 10 10 10 00 10
+ 10 10 10 10 10 10 01 10 01 01 01 10 01 10 01 01
+ 02 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 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 02 02 02 00
+ </map>
+</ctype>
+
+
+<lower>
+<map>
+ 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 DC B7 DD DE DF BB FC BD FD FE
+ C0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 D2 F3 F4 F5 F6 F7 F8 F9 FA FB 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+ DA 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 C1 C5 C7 C9
+ DB 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 DA DB CF D5 D9 FF
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="greek">
+<map>
+ 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 C1 B7 C5 C7 C9 BB CF BD D5 D9
+ C9 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 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
+</map>
+</collation>
+
+<collation name="greek_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/hebrew.conf b/sql/share/charsets/hebrew.conf
deleted file mode 100644
index 6a5f88eb228..00000000000
--- a/sql/share/charsets/hebrew.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the hebrew 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 10 10 10 10 10 10 10 10 10 10 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
- 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 00 00 00 00 00
-
-# 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 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 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
-
-# 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 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
diff --git a/sql/share/charsets/hebrew.xml b/sql/share/charsets/hebrew.xml
new file mode 100644
index 00000000000..fbd4ea0c1d2
--- /dev/null
+++ b/sql/share/charsets/hebrew.xml
@@ -0,0 +1,122 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="hebrew">
+
+<ctype>
+<map>
+ 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 10 10 10 10 10 10 10 10 10 10 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
+ 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 00 00 00 00 00
+ </map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="hebrew">
+<map>
+ 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 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
+</map>
+</collation>
+
+<collation name="hebrew_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/hp8.conf b/sql/share/charsets/hp8.conf
deleted file mode 100644
index e9fadacbf76..00000000000
--- a/sql/share/charsets/hp8.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the hp8 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
- 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 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 20 20 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 02 10 10 10 10 10 10 02 10 02 02
- 01 10 10 01 02 10 10 02 01 10 01 01 01 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 20 20 20 20 10 10 10 10 10 10 10 10 10 20
-
-# 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 C8 C0 C9 C1 CD D1 DD A8 A9 AA AB AC CB C3 AF
- B0 B2 B2 B3 B5 B5 B7 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
- D4 D1 D6 D7 D4 D5 D6 D7 CC D9 CE CF C5 DD DE C2
- C4 E2 E2 E4 E4 D5 D9 C6 CA EA EA EC EC C7 EF EF
- F1 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC 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 B1 B3 B4 B4 B6 B6 B8 B9 BA BB BC BD BE BF
- A2 A4 DF AE E0 DC E7 ED A1 A3 E8 AD D8 A5 DA DB
- D0 A6 D2 D3 D0 E5 D2 D3 D8 E6 DA DB DC A7 DE DF
- E0 E1 E1 E3 E3 E5 E6 E7 E8 E9 E9 EB EB ED EE EE
- F0 F0 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD 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 5C 5D 5B 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
diff --git a/sql/share/charsets/hp8.xml b/sql/share/charsets/hp8.xml
new file mode 100644
index 00000000000..619297fa988
--- /dev/null
+++ b/sql/share/charsets/hp8.xml
@@ -0,0 +1,122 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="hp8">
+
+<ctype>
+<map>
+ 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
+ 20 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 20 20 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 02 10 10 10 10 10 10 02 10 02 02
+ 01 10 10 01 02 10 10 02 01 10 01 01 01 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 20 20 20 20 10 10 10 10 10 10 10 10 10 20
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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 C8 C0 C9 C1 CD D1 DD A8 A9 AA AB AC CB C3 AF
+ B0 B2 B2 B3 B5 B5 B7 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
+ D4 D1 D6 D7 D4 D5 D6 D7 CC D9 CE CF C5 DD DE C2
+ C4 E2 E2 E4 E4 D5 D9 C6 CA EA EA EC EC C7 EF EF
+ F1 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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 B1 B3 B4 B4 B6 B6 B8 B9 BA BB BC BD BE BF
+ A2 A4 DF AE E0 DC E7 ED A1 A3 E8 AD D8 A5 DA DB
+ D0 A6 D2 D3 D0 E5 D2 D3 D8 E6 DA DB DC A7 DE DF
+ E0 E1 E1 E3 E3 E5 E6 E7 E8 E9 E9 EB EB ED EE EE
+ F0 F0 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+
+</map>
+</unicode>
+
+
+<collation name="hp8">
+<map>
+ 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 5C 5D 5B 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
+</map>
+</collation>
+
+<collation name="hp8_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/hungarian.conf b/sql/share/charsets/hungarian.conf
deleted file mode 100644
index db58d62575f..00000000000
--- a/sql/share/charsets/hungarian.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the hungarian 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
- 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
- 01 10 01 10 01 01 10 00 00 01 01 01 01 10 01 01
- 10 02 10 02 10 02 02 10 10 02 02 02 02 10 02 02
- 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
- 10 01 01 01 01 01 01 10 01 01 01 01 01 01 01 10
- 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
-
-# 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 8B 8B A1 A1 8E A0
- 82 91 92 93 94 A2 96 A3 96 94 81 9B 9C 9D 9E 9F
- A0 A1 A2 A3 B5 B6 A6 93 A8 B9 BA BB BC AD BE BF
- B0 B1 B2 B3 B4 E1 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
- D0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE DF
- A2 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA 96 EC ED EE EF
- F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC 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 9A 90 83 84 85 86 87 88 89 8A 8A 8C 8D 8E 8F
- 90 91 92 A7 99 95 98 97 98 99 9A 9B 9C 9D 9E 9F
- 8F 8D 95 97 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
- B0 A0 B2 A2 B4 B5 A5 B7 B8 A9 AA AB AC 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 D8 D9 DA DB DC DD DE DF
- E0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA EB CC CD CE CF
- F0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE 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 47 48 4C 4E 53 54 55 56 5A 5B 5C 60 61 64
- 69 6A 6B 6E 72 75 7A 7B 7C 7D 7F 83 84 85 86 87
- 88 41 47 48 4C 4E 53 54 55 56 5A 5B 5C 60 61 64
- 69 6A 6B 6E 72 75 7A 7B 7C 7D 7F 89 8A 8B 8C 00
- 01 78 4E 04 05 06 07 08 09 0A 67 67 56 56 0F 41
- 4E 12 13 67 67 64 78 75 78 67 78 1C 1D 1E 1F FF
- 41 56 64 75 5E 6F FF 67 FF 70 71 73 80 FF 81 82
- FF 42 FF 5D FF 41 6F FF FF 70 71 73 80 FF 81 82
- 6C 41 44 45 46 5F 49 4B 4A 4E 51 52 50 56 57 4D
- 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
diff --git a/sql/share/charsets/keybcs2.xml b/sql/share/charsets/keybcs2.xml
new file mode 100644
index 00000000000..e509207c1c5
--- /dev/null
+++ b/sql/share/charsets/keybcs2.xml
@@ -0,0 +1,122 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="keybcs2">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="keybcs2">
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="keybcs2_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/koi8_ru.conf b/sql/share/charsets/koi8_ru.conf
deleted file mode 100644
index 4cfee67a236..00000000000
--- a/sql/share/charsets/koi8_ru.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the koi8_ru 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
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 02 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 01 10 10 10 10 10 10 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 02 02 02 02 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
-
-# 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 A8 A9 AA AB AC AD AE AF
- B0 B1 B2 A3 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 D7 D8 D9 DA DB DC DD DE DF
-
-# 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 B3 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 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
-
-# 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 E5 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE
- AF B0 B1 E5 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD
- 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
- 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
diff --git a/sql/share/charsets/koi8r.xml b/sql/share/charsets/koi8r.xml
new file mode 100644
index 00000000000..c5aeea23997
--- /dev/null
+++ b/sql/share/charsets/koi8r.xml
@@ -0,0 +1,121 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="koi8r">
+
+<ctype>
+<map>
+ 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
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 02 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 01 10 10 10 10 10 10 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 02 02 02 02 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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 A3 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 D7 D8 D9 DA DB DC DD DE DF
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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 B3 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 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="koi8r">
+<map>
+ 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 E5 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE
+ AF B0 B1 E5 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD
+ 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
+ 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
+</map>
+</collation>
+
+<collation name="koi8r_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/koi8_ukr.conf b/sql/share/charsets/koi8u.xml
index 3e2c8e27325..fd963ff0da5 100644
--- a/sql/share/charsets/koi8_ukr.conf
+++ b/sql/share/charsets/koi8u.xml
@@ -1,6 +1,11 @@
-# Configuration file for the koi8_ukr character set
+<?xml version='1.0' encoding="utf-8"?>
-# ctype array (must have 257 elements)
+<charsets>
+
+<charset name="koi8u">
+
+<ctype>
+<map>
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
@@ -18,8 +23,12 @@
02 02 02 02 02 02 02 02 02 02 02 02 02 02 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
+</map>
+</ctype>
+
-# to_lower array (must have 256 elements)
+<lower>
+<map>
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
@@ -36,8 +45,12 @@
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
+</map>
+</lower>
-# to_upper array (must have 256 elements)
+
+<upper>
+<map>
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
@@ -54,8 +67,34 @@
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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
-# sort_order array (must have 256 elements)
+
+<collation name="koi8u">
+<map>
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
@@ -72,3 +111,12 @@
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
+</map>
+</collation>
+
+<collation name="koi8u_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
diff --git a/sql/share/charsets/latin1.xml b/sql/share/charsets/latin1.xml
new file mode 100644
index 00000000000..87abbe06f77
--- /dev/null
+++ b/sql/share/charsets/latin1.xml
@@ -0,0 +1,214 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="latin1">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="latin1">
+<map>
+ 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
+ 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49
+ 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
+</map>
+</collation>
+
+
+<collation name="german1">
+<map>
+ 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
+ 41 41 41 41 41 41 41 43 45 45 45 45 49 49 49 49
+ 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
+</map>
+</collation>
+
+
+<collation name="danish">
+<map>
+ 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
+ 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49
+ 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
+</map>
+</collation>
+
+
+<collation name="latin1_de"/>
+
+
+<collation name="latin1_bin" flag="binary"/>
+
+
+<collation name="latin1_ci_as">
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="latin1_cs_as">
+<map>
+ 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
+</map>
+</collation>
+
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/latin2.conf b/sql/share/charsets/latin2.conf
deleted file mode 100644
index cc18c22c0a2..00000000000
--- a/sql/share/charsets/latin2.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the latin2 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 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
- 48 01 10 01 10 01 01 10 10 01 01 01 01 10 01 01
- 10 02 10 02 10 02 02 10 10 02 02 02 02 10 02 02
- 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
- 10 01 01 01 01 01 01 10 01 01 01 01 01 01 01 10
- 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
-
-# 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 B1 A2 B3 A4 B5 B6 A7 A8 B9 BA BB BC AD BE 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
- D0 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 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 A1 B2 A3 B4 A5 A6 B7 B8 A9 AA AB AC 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 D8 D9 DA DB DC DD DE DF
- C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
- F0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE 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 44 45 48 49 4B 4C 4D 4E 4F 50 51 53 54 56
- 58 59 5A 5B 5E 5F 60 61 62 63 64 68 69 6A 6B 6C
- 6D 41 44 45 48 49 4B 4C 4D 4E 4F 50 51 53 54 56
- 58 59 5A 5B 5E 5F 60 61 62 63 64 6E 6F 70 71 FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
- FF 42 FF 52 FF 51 5C FF FF 5D 5B 5E 65 FF 67 66
- FF 42 FF 52 FF 51 5C FF FF 5D 5B 5E 65 FF 67 66
- 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
- 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
diff --git a/sql/share/charsets/latin2.xml b/sql/share/charsets/latin2.xml
new file mode 100644
index 00000000000..9be39dee47d
--- /dev/null
+++ b/sql/share/charsets/latin2.xml
@@ -0,0 +1,168 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="latin2">
+
+<ctype>
+<map>
+ 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
+ 48 01 10 01 10 01 01 10 10 01 01 01 01 10 01 01
+ 10 02 10 02 10 02 02 10 10 02 02 02 02 10 02 02
+ 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
+ 10 01 01 01 01 01 01 10 01 01 01 01 01 01 01 10
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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 B1 A2 B3 A4 B5 B6 A7 A8 B9 BA BB BC AD BE 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
+ D0 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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 A1 B2 A3 B4 A5 A6 B7 B8 A9 AA AB AC 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 D8 D9 DA DB DC DD DE DF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ F0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="latin2">
+<map>
+ 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 48 49 4B 4C 4D 4E 4F 50 51 53 54 56
+ 58 59 5A 5B 5E 5F 60 61 62 63 64 68 69 6A 6B 6C
+ 6D 41 44 45 48 49 4B 4C 4D 4E 4F 50 51 53 54 56
+ 58 59 5A 5B 5E 5F 60 61 62 63 64 6E 6F 70 71 FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+ FF 42 FF 52 FF 51 5C FF FF 5D 5B 5E 65 FF 67 66
+ FF 42 FF 52 FF 51 5C FF FF 5D 5B 5E 65 FF 67 66
+ 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
+ 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
+</map>
+</collation>
+
+
+<collation name="croat">
+<map>
+ 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 46 48 49 4A 4B 4C 4D 4E 4F 50 51 52
+ 53 54 55 56 58 59 5A 5B 5C 5D 5E 5B 5C 5D 5E 5F
+ 60 41 42 43 46 48 49 4A 4B 4C 4D 4E 4F 50 51 52
+ 53 54 55 56 58 59 5A 5B 5C 5D 5E 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 57 8B 8C 8D 5F 8F
+ 90 91 92 93 94 95 96 97 98 99 57 9B 9C 9D 5F 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
+ 41 41 41 41 5C 5B 45 43 44 45 45 45 49 49 49 49
+ 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
+</map>
+</collation>
+
+
+<collation name="czech"/>
+
+
+<collation name="hungarian">
+<map>
+ 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 4E 53 54 55 56 5A 5B 5C 60 61 64
+ 69 6A 6B 6E 72 75 7A 7B 7C 7D 7F 83 84 85 86 87
+ 88 41 47 48 4C 4E 53 54 55 56 5A 5B 5C 60 61 64
+ 69 6A 6B 6E 72 75 7A 7B 7C 7D 7F 89 8A 8B 8C 00
+ 01 78 4E 04 05 06 07 08 09 0A 67 67 56 56 0F 41
+ 4E 12 13 67 67 64 78 75 78 67 78 1C 1D 1E 1F FF
+ 41 56 64 75 5E 6F FF 67 FF 70 71 73 80 FF 81 82
+ FF 42 FF 5D FF 41 6F FF FF 70 71 73 80 FF 81 82
+ 6C 41 44 45 46 5F 49 4B 4A 4E 51 52 50 56 57 4D
+ 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
+</map>
+</collation>
+
+<collation name="latin2_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/latin5.conf b/sql/share/charsets/latin5.conf
deleted file mode 100644
index 92fbd2299bb..00000000000
--- a/sql/share/charsets/latin5.conf
+++ /dev/null
@@ -1,78 +0,0 @@
-# Configuration file for the latin5 (turkish) character set
-
-# Note: all accented characters are compared separately (this
-# is different from the default latin1 character set, where
-# e.g. a = ä = á, etc.).
-
-# 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 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 02
-
-# 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 FD 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 69 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 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 DD 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 49 DE 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 45 46 47 48 4A 4B 4D 4E 4F 50 51 52
- 54 55 56 57 59 5A 5C 5D 5E 5F 60 61 62 63 64 65
- 66 41 42 43 45 46 47 48 4A 4C 4D 4E 4F 50 51 52
- 54 55 56 57 59 5A 5C 5D 5E 5F 60 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 44 D3 D4 D5 D6 D7 D8 D9 DA
- 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
diff --git a/sql/share/charsets/latin5.xml b/sql/share/charsets/latin5.xml
new file mode 100644
index 00000000000..c73cc645d42
--- /dev/null
+++ b/sql/share/charsets/latin5.xml
@@ -0,0 +1,126 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="latin5">
+
+<ctype>
+<map>
+ 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 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 02
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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 FD 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 69 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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 DD 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 49 DE FF
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="latin5">
+<!--
+# Note: all accented characters are compared separately (this
+# is different from the default latin1 character set, where
+# e.g. a = ä = á, etc.).
+-->
+<map>
+ 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 45 46 47 48 4A 4B 4D 4E 4F 50 51 52
+ 54 55 56 57 59 5A 5C 5D 5E 5F 60 61 62 63 64 65
+ 66 41 42 43 45 46 47 48 4A 4C 4D 4E 4F 50 51 52
+ 54 55 56 57 59 5A 5C 5D 5E 5F 60 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 44 D3 D4 D5 D6 D7 D8 D9 DA
+ 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
+</map>
+</collation>
+
+<collation name="latin5_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml
new file mode 100644
index 00000000000..89c14a3acd8
--- /dev/null
+++ b/sql/share/charsets/latin7.xml
@@ -0,0 +1,169 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="latin7">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="estonia">
+<map>
+ 00 02 03 04 05 06 07 08 09 2E 2F 30 31 32 0A 0B
+ 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B
+ 2C 33 34 35 36 37 38 27 39 3A 3B 5D 3C 28 3D 3E
+ 76 7A 7C 7E 80 81 82 83 84 85 3F 40 5E 5F 60 41
+ 42 86 90 92 98 9A A4 A6 AA AC B2 B4 B8 BE C0 C6
+ CE D0 D2 D6 E5 E8 EE F0 FA FC DD 43 44 45 46 47
+ 48 87 91 93 99 9B A5 A7 AB AD B3 B5 B9 BF C1 C7
+ CF D1 D3 D7 E6 E9 EF F1 FB FD DE 49 4A 4B 4C 1C
+ 01 1D 57 1E 5A 74 71 72 1F 75 20 5B 21 4E 52 51
+ 22 55 56 58 59 73 2A 2B 23 E7 24 5C 25 4F 54 26
+ 2D FE 66 67 68 FF 4D 69 CC 6A D4 62 6B 29 6C 8E
+ 6D 61 7D 7F 50 6E 6F 70 CD 7B D5 63 77 78 79 8F
+ 8C B0 88 94 F4 8A A2 A0 96 9C DF 9E A8 B6 AE BA
+ 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
+</map>
+</collation>
+
+
+<collation name="latvian">
+<!-- Created for case-sensitive record search -->
+<!-- by Andis Grasis & Rihards Grasis e-mail:andis@cata.lv -->
+<map>
+ 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
+</map>
+</collation>
+
+
+<collation name="latvian1">
+<!-- Created for case-insensitive record search -->
+<!-- Created by Andis & Rihards -->
+<map>
+ 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
+</map>
+</collation>
+
+<collation name="latin7_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/pclatin1.xml b/sql/share/charsets/pclatin1.xml
new file mode 100644
index 00000000000..da4b6d2ac92
--- /dev/null
+++ b/sql/share/charsets/pclatin1.xml
@@ -0,0 +1,121 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="pclatin1">
+
+<ctype>
+<map>
+ 00
+ 20 30 30 30 30 30 30 20 20 28 28 28 28 28 30 30
+ 30 30 30 30 30 30 30 30 30 30 20 30 30 30 30 30
+ 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 30
+ 02 02 02 02 02 02 02 02 02 02 02 02 02 02 01 01
+ 01 02 01 02 02 02 02 02 02 01 01 10 10 10 10 10
+ 02 02 02 02 02 01 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 20
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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 8A 8B 8C 8D 84 86
+ 82 91 91 93 94 95 96 97 98 94 81 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A4 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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 41 8E 41 8F 80 45 45 45 49 49 49 8E 8F
+ 90 92 92 4F 99 4F 55 55 59 99 9A 9B 9C 9D 9E 9F
+ 41 49 4F 55 A5 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
+
+
+<collation name="pclatin1">
+<map>
+ 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
+ 43 59 45 41 5C 41 5B 43 45 45 45 49 49 49 5C 5B
+ 45 5C 5C 4F 5D 4F 55 55 59 5D 59 24 24 24 24 24
+ 41 49 4F 55 4E 4E A6 A7 3F A9 AA AB AC 21 22 22
+ 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
+</map>
+</collation>
+
+<collation name="pclatin1_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/pclatin2.xml b/sql/share/charsets/pclatin2.xml
new file mode 100644
index 00000000000..4402edcd847
--- /dev/null
+++ b/sql/share/charsets/pclatin2.xml
@@ -0,0 +1,119 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="pclatin2">
+
+<ctype>
+<map>
+ 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
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 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
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+ 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
+</map>
+</unicode>
+
+
+<collation name="pclatin2">
+<map>
+ 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
+</map>
+</collation>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/charsets/swe7.conf b/sql/share/charsets/swe7.xml
index d2de48b4d1c..2768768cd9b 100644
--- a/sql/share/charsets/swe7.conf
+++ b/sql/share/charsets/swe7.xml
@@ -1,6 +1,11 @@
-# Configuration file for the swe7 character set
+<?xml version='1.0' encoding="utf-8"?>
-# ctype array (must have 257 elements)
+<charsets>
+
+<charset name="swe7">
+
+<ctype>
+<map>
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
@@ -18,8 +23,12 @@
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
+</map>
+</ctype>
+
-# to_lower array (must have 256 elements)
+<lower>
+<map>
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
@@ -36,8 +45,12 @@
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
+</map>
+</lower>
-# to_upper array (must have 256 elements)
+
+<upper>
+<map>
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
@@ -54,8 +67,34 @@
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
+</map>
+</upper>
+
+
+<unicode>
+<map>
+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
+</map>
+</unicode>
-# sort_order array (must have 256 elements)
+
+<collation name="swe7">
+<map>
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
@@ -72,3 +111,13 @@
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
+</map>
+</collation>
+
+<collation name="swe7_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
+
+
diff --git a/sql/share/charsets/usa7.conf b/sql/share/charsets/usa7.conf
deleted file mode 100644
index b9e7a44c894..00000000000
--- a/sql/share/charsets/usa7.conf
+++ /dev/null
@@ -1,74 +0,0 @@
-# Configuration file for the usa7 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
- 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 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
-
-# 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 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 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
-
-# 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 5C 5D 5B 5E 5F
- 45 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 59 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
diff --git a/sql/share/charsets/win1251.conf b/sql/share/charsets/win1251.conf
deleted file mode 100644
index a5ccc3190ad..00000000000
--- a/sql/share/charsets/win1251.conf
+++ /dev/null
@@ -1,82 +0,0 @@
-# Configuration file for the win1251 character set
-
-# NOTE: this character set is deprecated. Please don't use it
-# unless you must because of old tables.
-#
-# If you want to convert your files to charset cp1251, you can do:
-#
-# myisamchk -rq --set-character-set-name=cp1251 *.MYI
-
-
-# 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
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 01 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 02 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 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 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 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 F5 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 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 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 D5 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 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 C6 A9 AA AB AC AD AE AF
- B0 B1 B2 B3 B4 B5 B6 B7 C6 B9 BA BB BC BD BE BF
- 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
- 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
diff --git a/sql/share/charsets/win1251ukr.conf b/sql/share/charsets/win1251ukr.conf
deleted file mode 100644
index e693958910e..00000000000
--- a/sql/share/charsets/win1251ukr.conf
+++ /dev/null
@@ -1,77 +0,0 @@
-# Configuration file for the win1251ukr character set
-
-# it's really, just a cp1251 charset with Ukranian letter
-# marked as "letters"
-
-# 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
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
- 10 10 10 10 10 10 10 10 01 10 01 10 10 10 10 01
- 10 10 01 02 10 10 10 10 02 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 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 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
- 20 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
- 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 20 20 20 20 A5 20 20 A8 20 AA 20 20 20 20 AF
- 20 20 B2 B2 A5 20 20 20 A8 20 AA 20 20 20 20 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
-
-# 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
- 20 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
- 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 20 20 20 20 B4 20 20 B8 20 BA 20 20 20 20 BF
- 20 20 B3 B3 B4 20 20 20 B8 20 BA 20 20 20 20 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
-
-# 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
- 20 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
- 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 84 CA CB 88 CC 87 CD CE CF D0 8D
- D1 D2 8C 8C 84 D3 D4 D5 88 D6 87 D7 D8 D9 DA 8D
- 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
- 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
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index f169d6f85f1..169595c34c5 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -1,4 +1,4 @@
-/*
+v/*
Modifikoval Petr -B©najdr, snajdr@pvt.net, snajdr@cpress.cz v.0.01
ISO LATIN-8852-2
Dal-B¹í verze Jan Pazdziora, adelton@fi.muni.cz
@@ -103,7 +103,7 @@
"Nen-Bí mo¾né vymazat v¹echny polo¾ky s ALTER TABLE. Pou¾ijte DROP TABLE",
"Nemohu zru-B¹it '%-.64s' (provést DROP). Zkontrolujte, zda neexistují záznamy/klíèe",
"Z-Báznamù: %ld Zdvojených: %ld Varování: %ld",
-"INSERT TABLE '%-.64s' nen-Bí dovoleno v seznamu tabulek FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Nezn-Bámá identifikace threadu: %lu",
"Nejste vlastn-Bíkem threadu %lu",
"Nejsou pou-B¾ity ¾ádné tabulky",
@@ -206,10 +206,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -247,3 +247,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 06c63e47a73..ff58079f4c8 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -97,7 +97,7 @@
"Man kan ikke slette alle felter med ALTER TABLE. Brug DROP TABLE i stedet.",
"Kan ikke udføre DROP '%-.64s'. Undersøg om feltet/nøglen eksisterer.",
"Poster: %ld Ens: %ld Advarsler: %ld",
-"INSERT TABLE '%-.64s' er ikke tilladt i FROM tabel liste",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ukendt tråd id: %lu",
"Du er ikke ejer af tråden %lu",
"Ingen tabeller i brug",
@@ -202,8 +202,8 @@
"Tabellen '%-.64s' er markeret med fejl og sidste (automatiske?) REPAIR fejlede",
"Advarsel: Visse data i tabeller der ikke understøtter transaktioner kunne ikke tilbagestilles",
"Fler-udtryks transaktion krævede mere plads en 'max_binlog_cache_size' bytes. Forhøj værdien af denne variabel og prøv igen",
-"Denne handling kunne ikke udføres med kørende slave, brug først kommandoen SLAVE STOP",
-"Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen SLAVE START",
+"Denne handling kunne ikke udføres med kørende slave, brug først kommandoen STOP SLAVE",
+"Denne handling kræver en kørende slave. Konfigurer en slave og brug kommandoen START SLAVE",
"Denne server er ikke konfigureret som slave. Ret in config-filen eller brug kommandoen CHANGE MASTER TO",
"Kunne ikke initialisere master info-struktur. Check om rettigheder i master.info",
"Kunne ikke danne en slave-tråd. Check systemressourcerne",
@@ -241,3 +241,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 452a330b61b..a0a6755c693 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -105,7 +105,7 @@
"Het is niet mogelijk alle velden te verwijderen met ALTER TABLE. Gebruik a.u.b. DROP TABLE hiervoor!",
"Kan '%-.64s' niet weggooien. Controleer of het veld of de zoeksleutel daadwerkelijk bestaat.",
"Records: %ld Dubbel: %ld Waarschuwing: %ld",
-"INSERT TABLE '%-.64s' is niet toegestaan in de FROM tabel-lijst",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Onbekend thread id: %lu",
"U bent geen bezitter van thread %lu",
"Geen tabellen gebruikt.",
@@ -210,8 +210,8 @@
"Tabel '%-.64s' staat als gecrashed gemarkeerd en de laatste (automatische?) reparatie poging mislukte",
"Waarschuwing: Roll back mislukt voor sommige buiten transacties gewijzigde tabellen",
"Multi-statement transactie vereist meer dan 'max_binlog_cache_size' bytes opslag. Verhoog deze mysqld variabele en probeer opnieuw",
-"Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst SLAVE STOP",
-"Deze operatie vereist een actieve slave, configureer slave en doe dan SLAVE START",
+"Deze operatie kan niet worden uitgevoerd met een actieve slave, doe eerst STOP SLAVE",
+"Deze operatie vereist een actieve slave, configureer slave en doe dan START SLAVE",
"De server is niet geconfigureerd als slave, fix in configuratie bestand of met CHANGE MASTER TO",
"Kon master info structuur niet initialiseren, controleer permissies in master.info",
"Kon slave thread niet aanmaken, controleer systeem resources",
@@ -249,3 +249,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 023cd7bc73e..0f48416d6db 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -94,7 +94,7 @@
"You can't delete all columns with ALTER TABLE. Use DROP TABLE instead",
"Can't DROP '%-.64s'. Check that column/key exists",
"Records: %ld Duplicates: %ld Warnings: %ld",
-"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Unknown thread id: %lu",
"You are not owner of thread %lu",
"No tables used",
@@ -197,10 +197,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -238,3 +238,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias",
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index d0a30b2f434..4503f011692 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -99,7 +99,7 @@
"ALTER TABLE kasutades ei saa kustutada kõiki tulpasid. Kustuta tabel DROP TABLE abil",
"Ei suuda kustutada '%-.64s'. Kontrolli kas tulp/võti eksisteerib",
"Kirjeid: %ld Kattuvaid: %ld Hoiatusi: %ld",
-"INSERT TABLE '%-.64s' ei ole lubatud FROM tabelite nimekirjas",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Tundmatu lõim: %lu",
"Ei ole lõime %lu omanik",
"Ühtegi tabelit pole kasutusel",
@@ -204,8 +204,8 @@
"Tabel '%-.64s' on märgitud vigaseks ja viimane (automaatne?) parandus ebaõnnestus",
"Hoiatus: mõnesid transaktsioone mittetoetavaid tabeleid ei suudetud tagasi kerida",
"Mitme lausendiga transaktsioon nõudis rohkem ruumi kui lubatud 'max_binlog_cache_size' muutujaga. Suurenda muutuja väärtust ja proovi uuesti",
-"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -243,3 +243,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 08aa5760d6c..9474d67f2f2 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -94,7 +94,7 @@
"Vous ne pouvez effacer tous les champs avec ALTER TABLE. Utilisez DROP TABLE",
"Ne peut effacer (DROP) '%-.64s'. Vérifiez s'il existe",
"Enregistrements: %ld Doublons: %ld Avertissements: %ld",
-"INSERT TABLE '%-.64s' n'est pas permis dans FROM liste des tables",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Numéro de tâche inconnu: %lu",
"Vous n'êtes pas propriétaire de la tâche no: %lu",
"Aucune table utilisée",
@@ -199,8 +199,8 @@
"La table '%-.64s' est marquée 'crashed' et le dernier 'repair' a échoué",
"Attention: certaines tables ne supportant pas les transactions ont été changées et elles ne pourront pas être restituées",
"Cette transaction à commandes multiples nécessite plus de 'max_binlog_cache_size' octets de stockage, augmentez cette variable de mysqld et réessayez",
-"Cette opération ne peut être réalisée avec un esclave actif, faites SLAVE STOP d'abord",
-"Cette opération nécessite un esclave actif, configurez les esclaves et faites SLAVE START",
+"Cette opération ne peut être réalisée avec un esclave actif, faites STOP SLAVE d'abord",
+"Cette opération nécessite un esclave actif, configurez les esclaves et faites START SLAVE",
"Le server n'est pas configuré comme un esclave, changez le fichier de configuration ou utilisez CHANGE MASTER TO",
"Impossible d'initialiser les structures d'information de maître, vérifiez les permissions sur master.info",
"Impossible de créer une tâche esclave, vérifiez les ressources système",
@@ -238,3 +238,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 42e8c6f069b..ef4110a6b93 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -2,7 +2,13 @@
This file is public domain and comes with NO WARRANTY of any kind
Dirk Munzinger (dmun@4t2.com)
- Version: 07.06.2001 */
+ Version: 07.06.2001
+
+ Georg Richter (georg@php.net)
+ fixed typos and translation
+ translated new error messages
+ 2002-12-11
+ */
"hashchk",
"isamchk",
@@ -13,41 +19,41 @@
"Kann Datenbank '%-.64s' nicht erzeugen. (Fehler: %d)",
"Kann Datenbank '%-.64s' nicht erzeugen. Datenbank '%-.64s' existiert bereits.",
"Kann Datenbank '%-.64s' nicht löschen. Keine Datenbank '%-.64s' vorhanden.",
-"Fehler beim Löschen der Datenbank. ('%-.64s' kann nicht gelöscht werden, Fehler %d)",
-"Fehler beim Löschen der Datenbank. (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehler %d)",
+"Fehler beim Löschen der Datenbank. ('%-.64s' kann nicht gelöscht werden, Fehlernuumer: %d)",
+"Fehler beim Löschen der Datenbank. (Verzeichnis '%-.64s' kann nicht gelöscht werden, Fehlernummer: %d)",
"Fehler beim Löschen von '%-.64s'. (Fehler: %d)",
"Datensatz in der Systemtabelle nicht lesbar.",
-"Kann Status von '%-.64s' nicht erhalten. (Fehler: %d)",
-"Kann Arbeitsverzeichnis nicht erhalten. (Fehler: %d)",
-"File nicht sperrbar. (Fehler: %d)",
+"Kann Status von '%-.64s' nicht ermitteln. (Fehler: %d)",
+"Kann Arbeitsverzeichnis nicht ermitteln. (Fehler: %d)",
+"Datei nicht sperrbar. (Fehler: %d)",
"Kann Datei '%-.64s' nicht öffnen. (Fehler: %d)",
"Kann Datei '%-.64s' nicht finden. (Fehler: %d)",
"Verzeichnis von '%-.64s' nicht lesbar. (Fehler: %d)",
-"Verzeichnis kann nicht nach '%-.64s' gewechselt werden. (Fehler: %d)",
+"Kann nicht in das Verzeichnis '%-.64s' wechseln. (Fehler: %d)",
"Datensatz hat sich seit dem letzten Zugriff auf Tabelle '%-.64s' geändert.",
"Festplatte voll (%-.64s). Warte bis jemand Platz schafft ...",
"Kann nicht speichern, doppelter Schlüssel in Tabelle '%-.64s'.",
"Fehler beim Schließen von '%-.64s'. (Fehler: %d)",
"Fehler beim Lesen der Datei '%-.64s'. (Fehler: %d)",
-"Fehler beim Umbennenen von '%-.64s' nach '%-.64s'. (Fehler: %d)",
+"Fehler beim Umbenennen von '%-.64s' nach '%-.64s'. (Fehler: %d)",
"Fehler beim Speichern der Datei '%-.64s'. (Fehler: %d)",
"'%-.64s' ist für Veränderungen gesperrt.",
"Sortieren abgebrochen.",
"View '%-.64s' existiert für '%-.64s' nicht.",
-"Fehler %d. (table handler)",
-"Diese Option gibt es nicht. (table handler)",
+"Fehler %d. (Tabellenhandler)",
+"Diese Option gibt es nicht. (Tabellenhandler)",
"Kann Datensatz nicht finden.",
"Falsche Information in Datei: '%-.64s'",
"Falsche Schlüssel-Datei für Tabelle '%-.64s'. Versuche zu reparieren!",
"Alte Schlüssel-Datei für Tabelle '%-.64s'. Repariere!",
"'%-.64s' ist nur lesbar.",
-"Kein Speicher (benötigt %d bytes). Server neu starten.",
-"Kein Speicher zum Sortieren. Server Sortier-Buffer erhöhen.",
-"Unerwartetes EOF beim Lesen der Datei '%-.64s'. (Fehler: %d)",
+"Kein Speicher vorhanden (benötigt %d bytes). Server neu starten.",
+"Kein Speicher zum Sortieren. sort_buffer_size sollte erhöht werden.",
+"Unerwartetes Ende beim Lesen der Datei '%-.64s'. (Fehler: %d)",
"Zu viele Verbindungen.",
"Zuwenig Speicher.",
"Kann Hostname für diese Adresse nicht erhalten.",
-"Schlechter handshake.",
+"Schlechter Handshake.",
"Keine Zugriffsberechtigung für Benutzer: '%-.32s@%-.64s' für Datenbank '%-.64s'.",
"Keine Zugriffsberechtigung für Benutzer: '%-.32s@%-.64s'. (Verwendetes Passwort: %-.64s)",
"Keine Datenbank ausgewählt.",
@@ -61,16 +67,16 @@
"Unbekanntes Tabellenfeld '%-.64s' in %-.64s.",
"'%-.64s' ist nicht in GROUP BY.",
"Gruppierung nicht möglich bei '%-.64s'.",
-"Im Statement wurden sowohl sum-Funktionen als auch Spalten verwendet. Nicht möglich.",
+"Die Verwendung von sum-Funktionen und Spalten ist nicht möglich.",
"Spaltenzähler entspricht nicht dem Wertzähler.",
-"Name des Identifizierers '%-.64s' ist zu lang.",
+"Name des Bezeichners '%-.64s' ist zu lang.",
"Doppelter Spaltenname vorhanden: '%-.64s'",
"Doppelter Name für Schlüssel (Key) vorhanden: '%-.64s'",
"Doppelter Eintrag '%-.64s' für Schlüssel %d.",
"Falsche Spalten-Spezifizierung für Spalte '%-.64s'.",
"%-.64s bei '%-.64s' in Zeile %d.",
"Leere Abfrage.",
-"Keine eindeutige(n) Tabelle/Alias: '%-.64s'",
+"Keine eindeutiger Tabellenname/Alias: '%-.64s'",
"Fehlerhafter Vorgabewert (Default-Wert): '%-.64s'",
"Mehrfacher Primärschlüssel (Primary Key) definiert.",
"Zuviele Schlüssel definiert. Maximal %d Schlüssel erlaubt.",
@@ -78,37 +84,37 @@
"Schlüssel ist zu lang. Die maximale Schlüssellänge beträgt %d.",
"In der Tabelle gibt es keine Schlüsselspalte '%-.64s'.",
"BLOB-Feld '%-.64s' kann nicht als Schlüssel verwendet werden.",
-"Feldlänge für Feld '%-.64s' zu groß (max = %d). BLOB-Feld verwenden!",
+"Feldlänge für Feld '%-.64s' zu groß (max. = %d). BLOB-Feld verwenden!",
"Nur ein Auto-Feld möglich, welches als Schlüssel definiert werden muß.",
-"%-.64s: Warten auf Verbindungen.\n",
+"%-.64s: Warte auf Verbindungen.\n",
"%-.64s: Normal beendet.\n",
"%-.64s: Signal %d erhalten. Abbruch!\n",
"%-.64s: Shutdown ausgeführt.\n",
-"%-.64s: Beendigung des Thread %ld veranlaßt. Benutzer: '%-.64s'\n",
+"%-.64s: Beendigung des Thread %ld veranlasst. Benutzer: '%-.64s'\n",
"Kann IP-Socket nicht erstellen.",
-"Tabelle '%-.64s' hat keinen solchen Index wie in CREATE INDEX verwendet. Index neu anlegen.",
-"Feld-Separator Argument ist nicht in der Form wie erwartet. Bitte im Manual nachlesen.",
+"Tabelle '%-.64s' besitzt keinen wie in CREATE INDEX verwendeten Index. Index neu anlegen.",
+"Feldbegrenzer Argument ist nicht in der Form wie erwartet. Bitte im Manual nachlesen.",
"Eine feste Reihenlänge kann für BLOBs nicht verwendet werden. Verwende 'fields terminated by' stattdessen.",
-"Feld '%-.64s' muß im Datenbank-Directory vorhanden und lesbar für alle sein.",
-"File '%-.64s' bereits vorhanden.",
+"Feld '%-.64s' muß im Datenbank-Verzeichnis vorhanden und lesbar für alle sein.",
+"Datei '%-.64s' bereits vorhanden.",
"Datensätze: %ld Gelöscht: %ld Ausgelassen: %ld Warnungen: %ld",
"Datensätze: %ld Duplikate: %ld",
-"Falscher Subteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String oder die verwendete Länge ist länger als der Teilschlüssel.",
+"Falscher Unterteilschlüssel. Der verwendete Schlüsselteil ist entweder kein String, die verwendete Länge ist länger als der Teilschlüssel oder der Tabellenhandler unterstützt keine Unterteilschlüssel.",
"Mit ALTER TABLE können nicht alle Felder auf einmal gelöscht werden. Verwende DROP TABLE stattdessen.",
"Kann '%-.64s' nicht löschen (DROP). Existiert das Feld/der Schlüssel?",
"Datensätze: %ld Duplikate: %ld Warnungen: %ld",
-"INSERT TABLE '%-.64s' nicht erlaubt im FROM Abschnitt.",
+"Die Verwendung der Zieltabelle '%-.64s' ist bei Update in FROM Teil nicht zulässig.",
"Unbekannte Thread-ID: %lu",
-"Nicht Besitzer des Threads %lu.",
+"Threads %lu. ist einem anderen Besitzer zugeordnet.",
"Keine Tabellen in Verwendung.",
-"Zuviele Strings für Spalte %-.64s und SET.",
-"Kann keinen eindeutigen Log-Filenamen erstellen %-.64s.(1-999)\n",
-"Tabelle '%-.64s' mit Lese-Sperre versehen und kann nicht upgedated werden.",
+"Zuviele Angaben für Spalte %-.64s und SET.",
+"Kann keinen eindeutigen Dateinamen für die Logdatei ermitteln %-.64s.(1-999)\n",
+"Tabelle '%-.64s' mit Lese-Sperre versehen und kann nicht aktualisiert werden.",
"Tabelle '%-.64s' wurde nicht mittels LOCK TABLES gesperrt.",
"BLOB-Feld '%-.64s' kann keinen Vorgabewert (Default-Value) besitzen.",
"Unerlaubter Datenbankname '%-.64s'.",
"Unerlaubter Tabellenname '%-.64s'.",
-"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange daueren. Bitte WHERE überprüfen und SET OPTION SQL_BIG_SELECTS=1 verwenden, sofern SELECT ok ist.",
+"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange daueren. Bitte WHERE überprüfen oder gegebenenfalls SET OPTION SQL_BIG_SELECTS=1 verwenden.",
"Unbekannter Fehler.",
"Unbekannte Procedure %-.64s.",
"Falsche Parameterzahl für Procedure %-.64s.",
@@ -135,51 +141,51 @@
"Funktion '%-.64s' ist nicht definiert.",
"Host blockiert wegen zu vieler Verbindungsfehler. Aufheben der Blockierung mit 'mysqladmin flush-hosts'.",
"Host hat keine Berechtigung, eine Verbindung zu diesem MySQL Server herzustellen.",
-"Sie benutzen MySQL als anonymer User; diese User dürfen keine Passwörter ändern.",
-"Sie müssen autorisiert sein zum UPDATE von Tabellen in der mysql Datenbank, um für andere Benutzer Passwörter ändern zu können.",
-"Kann keinen passenden Datensatz in der User-Tabelle finden.",
+"Sie benutzen MySQL als anonymer Benutzer und dürfen daher keine Passwörter ändern.",
+"Sie müssen autorisiert sein zum Aktualisieren von Tabellen in der mysql Datenbank, um für andere Benutzer Passwörter ändern zu können.",
+"Kann keinen passenden Datensatz in der Benutzer-Tabelle finden.",
"Datensätze gefunden: %ld Geändert: %ld Warnungen: %ld",
-"Kann keinen neuen Thread erzeugen (errno %d). Sollte nicht die Speichergrenze erreicht sein, bitte im Manual nach vorhanden OS-Abhängigen Fehlern nachschauen.",
+"Kann keinen neuen Thread erzeugen (Fehler: %d). Sollte die Speichergrenze nicht erreicht sein, bitte in der Dokumentation nach evtl. Betriebssystem abhängigen Fehlern nachlesen.",
"Spaltenzahl stimmt nicht mit der Anzahl der Werte überein in Reihe%ld",
"Kann Tabelle'%-.64s' nicht wieder öffnen",
"Unerlaubte Verwendung eines NULL-Wertes",
"Fehler '%-.64s' von regexp",
"Das Vermischen von GROUP Spalten (MIN(),MAX(),COUNT()...) mit Nicht-GROUP Spalten ist nicht erlaubt, sofern keine GROUP BY Klausel vorhanden ist.",
"Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s'",
-"%-.16s Kommando abgelehnt für User: '%-.32s@%-.64s' für Tabelle '%-.64s'",
-"%-.16s Kommando abgelehnt für User: '%-.32s@%-.64s' in Spalte '%-.64s' in Tabelle '%-.64s'",
-"Unzulässiges GRANT/REVOKE Kommando. Weiteres zum Thema Berechtigungen im Manual.",
+"%-.16s Befehl nicht erlaubt für User: '%-.32s@%-.64s' für Tabelle '%-.64s'",
+"%-.16s Befehl nicht erlaubt für User: '%-.32s@%-.64s' in Spalte '%-.64s' in Tabelle '%-.64s'",
+"Unzulässiger GRANT/REVOKE Befehl. Weiteres zum Thema Berechtigungen im Manual.",
"Das Host oder User Argument für GRANT ist zu lang",
"Tabelle '%-.64s.%-.64s' existiert nicht",
"Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s' an Tabelle '%-.64s'",
-"Das used Kommando ist mit dieser MySQL Version nicht erlaubt",
+"Der used Befehl ist mit dieser MySQL Version nicht erlaubt",
"Fehler in der Syntax",
-"Verzögerter Einfüge-Thread konnte den angeforderten Lock für Tabelle %-.64s nicht bekommen",
+"Verzögerter Einfüge-Thread konnte den angeforderten Lock für Tabelle %-.64s nicht erhalten",
"Zu viele Delayed Threads in Verwendung",
"Abbruch der Verbindung %ld zur Datenbank: '%-.64s' User: '%-.64s' (%-.64s)",
"Empfangenes Paket ist größer als 'max_allowed_packet'",
"Lese-Fehler bei einer Kommunikations-Pipe",
"Fehler von fcntl()",
"Empfangenes Paket ist nicht in Reihenfolge",
-"Communikation-Packet läßt sich nicht entpacken",
-"Fehler beim Lesen eines Communication-Packets",
-"Timeout beim Lesen eines Communication-Packets",
-"Fehler beim Schreiben eines Communication-Packets",
-"Timeout beim Schreiben eines Communication-Packets",
-"Ergebnisstring ist länger als max_allowed_packet",
+"Kommunikationspaket läßt sich nicht entpacken",
+"Fehler beim Lesen eines Kommunikationspakets",
+"Zeitüberschreitung beim Lesen eines Kommunikationspakets.",
+"Fehler beim Schreiben eines Kommunikationspakets.",
+"Zeitüberschreitung beim Schreiben eines Kommunikationspakets.",
+"Ergebnis ist länger als max_allowed_packet",
"Der verwendete Tabellentyp unterstützt keine BLOB/TEXT Spalten",
"Der verwendete Tabellentyp unterstützt keine AUTO_INCREMENT Spalte",
"INSERT DELAYED kann nicht auf Tabelle '%-.64s' angewendet werden, da diese mit LOCK TABLES gesperrt ist",
"Falscher Spaltenname '%-.100s'",
"Der verwendete Tabellen-Handler kann die Spalte '%-.64s' nicht indizieren",
-"Alle Tabelle in der MERGE-Tabelle sind nicht gleich definiert",
+"Alle Tabellen in der MERGE-Tabelle sind nicht gleich definiert",
"Schreiben in Tabelle '%-.64s' nicht möglich wegen eines Unique Constraint",
"BLOB Spalte '%-.64s' wird in der Key-Definition ohne Längenangabe verwendet",
"Alle Teile eines PRIMARY KEY müssen als NOT NULL definiert sein; Wenn NULL benötigt wird sollte ein UNIQUE Key verwendet werden",
"Ergebnis besteht aus mehr als einer Reihe",
"Dieser Tabellentyp verlangt nach einem PRIMARY KEY",
"Diese MySQL-Version ist nicht mit RAID-Unterstützung kompiliert",
-"Unter Verwendung des Sicheren Updatemodes wurde versucht eine Tabelle zu updaten ohne eine KEY-Spalte in der WHERE-Klausel",
+"Unter Verwendung des sicheren Aktualisierungsmodus wurde versucht eine Tabelle zu aktualisieren ohne eine KEY-Spalte in der WHERE-Klausel",
"Schlüssel '%-.64s' existiert nicht in der Tabelle '%-.64s'",
"Kann Tabelle nicht öffnen",
"Der Tabellen-Handler für diese Tabelle unterstützt kein %s",
@@ -191,53 +197,71 @@
"Verbindungsabbruch %ld zu db: '%-.64s' user: '%-.32s' host: `%-.64s' (%-.64s)",
"Der Tabellenhandler für die Tabelle unterstützt kein Binary Tabellendump",
"Binlog wurde beendet wärend FLUSH MASTER",
-"Neubau des Index der gedumpten Tabelle '%-.64s' fehlgeschlagen",
+"Neuerstellung des Index der gedumpten Tabelle '%-.64s' fehlgeschlagen",
"Fehler vom Master: '%-.64s'",
"Netzfehler beim Lesen vom Master",
"Netzfehler beim Schreiben zum Master",
-"Kann keinen FULLTEXT-Index finden der der Spaltenliste entspricht",
+"Kann keinen FULLTEXT-Index finden, der der Spaltenliste entspricht",
"Kann das aktuelle Kommando wegen aktiver Tabellensperre oder aktiver Transaktion nicht ausführen",
-"Unbekannte System-Variabel '%-.64s'",
+"Unbekannte Systemvariable '%-.64s'",
"Tabelle '%-.64s' ist als defekt makiert und sollte repariert werden",
"Tabelle '%-.64s' ist als defekt makiert und der letzte (automatische) Reparaturversuch schlug fehl.",
"Warnung: Das Rollback konnte bei einigen Tabellen, die nicht mittels Transaktionen geändert wurden, nicht ausgeführt werden.",
-"Multi-Statement Transaktionen benötigen mehr als 'max_binlog_cache_size' Bytes An Speicher. Diese mysqld-Variabel vergrössern und nochmal versuchen.",
-"Diese Operation kann nicht bei einem aktiven Slave durchgeführt werden. Das Kommand SLAVE STOP muss zuerst ausgeführt werden.",
-"Diese Operationbenötigt einen aktiven Slave. Slave konfigurieren und mittels SLAVE START aktivieren.",
+"Multi-Statement Transaktionen benötigen mehr als 'max_binlog_cache_size' Bytes An Speicher. Diese mysqld-Variable vergrössern und erneut versuchen.",
+"Diese Operation kann nicht bei einem aktiven Slave durchgeführt werden. Das Kommand STOP SLAVE muss zuerst ausgeführt werden.",
+"Diese Operation benötigt einen aktiven Slave. Slave konfigurieren und mittels START SLAVE aktivieren.",
"Der Server ist nicht als Slave konfigiriert. Im Konfigurations-File oder mittel CHANGE MASTER TO beheben.",
"Konnte Master-Info-Struktur nicht initialisieren; Berechtigungen von master.info prüfen.",
"Konnte keinen Slave-Thread starten. System-Resourcen überprüfen.",
"Benutzer %-.64s hat mehr als 'max_user_connections' aktive Verbindungen",
-"Bei der Verwendung mit SET dürfen nur Constante Ausdrücke verwendet werden",
-"Lock wait timeout exceeded",
-"The total number of locks exceeds the lock table size",
-"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
-"DROP DATABASE not allowed while thread is holding global read lock",
-"CREATE DATABASE not allowed while thread is holding global read lock",
-"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
-"Incorrect table definition; All MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; Try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
-"Error connecting to master: %-.128s",
-"Error running query on master: %-.128s",
-"Error when executing command %s: %-.128s",
-"Wrong usage of %s and %s",
-"The used SELECT statements have a different number of columns",
-"Can't execute the query because you have a conflicting read lock",
-"Mixing of transactional and non-transactional tables is disabled",
-"Option '%s' used twice in statement",
-"User '%-.64s' has exceeded the '%s' resource (current value: %ld)",
-"Access denied. You need the %-.128s privilege for this operation",
-"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL",
-"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL",
-"Variable '%-.64s' doesn't have a default value",
-"Variable '%-.64s' can't be set to the value of '%-.64s'",
-"Wrong argument type to variable '%-.64s'",
-"Variable '%-.64s' can only be set, not read",
-"Wrong usage/placement of '%s'",
-"This version of MySQL doesn't yet support '%s'",
-"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Bei der Verwendung mit SET dürfen nur konstante Ausdrücke verwendet werden",
+"Beim Warten auf einen LOCK wurde die zulässige Wartezeit überschritten.",
+"Die Gesamtanzahl der LOCKS überschreitet die Grösse der Locktabelle.",
+"Während einer READ UNCOMMITED Transaktion kann keine Update LOCK angefordert werden.",
+"Solange ein globaler Read LOCK gesetzt ist, ist DROP DATABASE nicht zulässig.",
+"Solange ein globaler Read LOCK gesetzt ist, ist CREATE DATABASE nicht zulässig.",
+"Falsche Argumente für %s",
+"%-.32s@%-.64s is nicht berechtigt neue Benutzer hinzuzufügen.",
+"Falsche Tabellendefinition: Sämtliche MERGE-Tabellen müssen in derselben Datenbank sein.",
+"Beim Versuch einen Lock anzufordern ist ein Deadlock aufgetreten. Es wird versucht die Transaktion erneut zu starten.",
+"Der verwendete Tabellentyp unterstützt keinen FULLTEXT-Index.",
+"Foreign_Key Beschränkung konnte nicht hinzugefügt werden.",
+"Hinzufügen eines Kind-Datensatzes schlug aufgrund einer Foreign-Key Beschränkung fehl.",
+"Löschen eines Eltern-Datensatzes schlug aufgrund einer Foreign-Key Beschränkung fehl.",
+"Datensatz kann aufgrund einer Foreign-Key Beschränkung nicht gelöscht werden.",
+"Fehler bei der Verbindung zum Master: %-.128s",
+"Beim Ausführen einer Abfrage auf dem Master trat ein Fehler auf: %-.128s.",
+"Fehler beim Ausführen des Befehls %s: %-.128s.",
+"Falsche Verwendung von %s und %s.",
+"Die verwendeten SELECTs liefern eine unterschiedliche Anzahl von Spalten zurück.",
+"Augrund eines READ LOCK Konflikts kann die Abfrage nicht ausgeführt werden.",
+"Die Verwendung von transaktions- und nicht transaktionsaktionsunterstützenden Tabellen ist deaktiviert.",
+"Option '%s' wird im Befehl zweimal verwendet.",
+"Benutzer '%-.64s' hat Limit '%s' überschritten. (Momentaner Wert: %ld)",
+"Befehl nicht zulässig. Hierfür wird die Berechtigung %-.128s benötigt.",
+"Variable '%-.64s' ist eine lokale Variable und kann nicht mit SET GLOBAL verändert werden.",
+"Variable '%-.64s' ist eine globale Variable und muss mit SET GLOBAL verändert werden.",
+"Variable '%-.64s' besitzt keinen vorgegebenen Wert.",
+"Der Variablen '%-.64s' kann nicht der Wert '%-.64s' zugewiesen werden.",
+"Falscher Typ für Variable '%-.64s'",
+"Variable '%-.64s' kann nur verändert, nicht aber gelesen werden.",
+"Falsche Verwendung oder Platzierung von '%s'",
+"Diese MySQL-Version unterstützt momentan nicht '%s'.",
+"Schwerer Fehler %d: '%-.128s vom Master beim Lesen des Binary Logs.",
+"Falsche Foreign-Key Definition für '%-64s': %s",
+"Schlüssel- und Tabellenreferenz passen nicht zueinander.",
+"Kardinalitäts-Fehler (mehr/oder weniger als %d Spalten).",
+"Unterabfrage lieferte mehr als einen Datensatz zurück.",
+"Unbekannter prepared statement handler (%ld) für %s angegeben.",
+"Die Hilfedatenbank ist beschädigt oder existiert nicht.",
+"Zyklische Referenz in den Unterabfragen.",
+"Spalte '%s' wird von %s nach %s umgewandelt",
+"Referenz '%-.64s' wird nicht unterstützt (%s)",
+"Für jede abgeleitete Tabelle muss ein eigener Alias angegeben werden.",
+"Select %u wurde während der Optimierung reduziert.",
+"Tabelle '%-.64s', die in einem der SELECT-Befehle verwendet wurde kann nicht in %-.32s verwendet werden",
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client",
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index c212c5b5703..3f54e7740bd 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -94,7 +94,7 @@
"Äåí åßíáé äõíáôÞ ç äéáãñáöÞ üëùí ôùí ðåäßùí ìå ALTER TABLE. Ðáñáêáëþ ÷ñçóéìïðïéåßóôå DROP TABLE",
"Áäýíáôç ç äéáãñáöÞ (DROP) '%-.64s'. Ðáñáêáëþ åëÝãîôå áí ôï ðåäßï/êëåéäß õðÜñ÷åé",
"ÅããñáöÝò: %ld ÅðáíáëÞøåéò: %ld ÐñïåéäïðïéÞóåéò: %ld",
-"INSERT TABLE '%-.64s' äåí åðéôñÝðåôáé óôï FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Áãíùóôï thread id: %lu",
"Äåí åßóèå owner ôïõ thread %lu",
"Äåí ÷ñçóéìïðïéÞèçêáí ðßíáêåò",
@@ -197,10 +197,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -238,3 +238,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 5e8affe32b7..7519448ef33 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -96,7 +96,7 @@
"Az osszes mezo nem torolheto az ALTER TABLE-lel. Hasznalja a DROP TABLE-t helyette",
"A DROP '%-.64s' nem lehetseges. Ellenorizze, hogy a mezo/kulcs letezik-e",
"Rekordok: %ld Duplikalva: %ld Warnings: %ld",
-"INSERT TABLE '%-.64s' nem engedelyezett a FROM table listabol",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ervenytelen szal (thread) id: %lu",
"A %lu thread-nek mas a tulajdonosa",
"Nincs hasznalt tabla",
@@ -199,10 +199,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -240,3 +240,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 3fdea588bf3..71a02896c01 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -94,7 +94,7 @@
"Non si possono cancellare tutti i campi con una ALTER TABLE. Utilizzare DROP TABLE",
"Impossibile cancellare '%-.64s'. Controllare che il campo chiave esista",
"Records: %ld Duplicati: %ld Avvertimenti: %ld",
-"INSERT TABLE '%-.64s' non e` permesso nella FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Thread id: %lu sconosciuto",
"Utente non proprietario del thread %lu",
"Nessuna tabella usata",
@@ -199,8 +199,8 @@
"La tabella '%-.64s' e` segnalata come corrotta e l'ultima ricostruzione (automatica?) e` fallita",
"Attenzione: Alcune delle modifiche alle tabelle non transazionali non possono essere ripristinate (roll back impossibile)",
"La transazione a comandi multipli (multi-statement) ha richiesto piu` di 'max_binlog_cache_size' bytes di disco: aumentare questa variabile di mysqld e riprovare",
-"Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima SLAVE STOP",
-"Questa operaione richiede un database 'slave', configurarlo ed eseguire SLAVE START",
+"Questa operazione non puo' essere eseguita con un database 'slave' che gira, lanciare prima STOP SLAVE",
+"Questa operaione richiede un database 'slave', configurarlo ed eseguire START SLAVE",
"Il server non e' configurato come 'slave', correggere il file di configurazione cambiando CHANGE MASTER TO",
"Impossibile inizializzare la struttura 'master info', controllare i permessi sul file master.info",
"Impossibile creare il thread 'slave', controllare le risorse di sistema",
@@ -238,3 +238,20 @@
"Uso/posizione di '%s' sbagliato",
"Questa versione di MySQL non supporta ancora '%s'",
"Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario",
+"Wrong foreign key definition for '%-.64s': %s",
+"Key reference and table reference doesn't match",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"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",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index f9c1645419d..b10ddb1d1d2 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -96,7 +96,7 @@
"ALTER TABLE ¤ÇÁ´¤Æ¤Î column ¤Ïºï½ü¤Ç¤­¤Þ¤»¤ó. DROP TABLE ¤ò»ÈÍѤ·¤Æ¤¯¤À¤µ¤¤",
"'%-.64s' ¤òÇË´þ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿. Check that column/key exists",
"¥ì¥³¡¼¥É¿ô: %ld ½ÅÊ£¿ô: %ld Warnings: %ld",
-"INSERT TABLE '%-.64s' isn't allowed in FROM table list",
+"You can't specify target table '%-.64s' for update in FROM clause",
"thread id: %lu ¤Ï¤¢¤ê¤Þ¤»¤ó",
"thread %lu ¤Î¥ª¡¼¥Ê¡¼¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó",
"No tables used",
@@ -199,10 +199,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -240,3 +240,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 82d5a5ecfbe..be1e85ad33c 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -94,7 +94,7 @@
"ALTER TABLE ¸í·ÉÀ¸·Î´Â ¸ðµç Ä®·³À» Áö¿ï ¼ö ¾ø½À´Ï´Ù. DROP TABLE ¸í·ÉÀ» ÀÌ¿ëÇϼ¼¿ä.",
"'%-.64s'¸¦ DROPÇÒ ¼ö ¾ø½À´Ï´Ù. Ä®·³À̳ª Å°°¡ Á¸ÀçÇÏ´ÂÁö äũÇϼ¼¿ä.",
"·¹ÄÚµå: %ld°³ Áߺ¹: %ld°³ °æ°í: %ld°³",
-"INSERT TABLE '%-.64s' ´Â FROM Å×À̺í list¿¡¼­ Çã°¡µÇÁö ¾Ê¾Ò½À´Ï´Ù.",
+"You can't specify target table '%-.64s' for update in FROM clause",
"¾Ë¼ö ¾ø´Â ¾²·¹µå id: %lu",
"¾²·¹µå(Thread) %luÀÇ ¼ÒÀ¯ÀÚ°¡ ¾Æ´Õ´Ï´Ù.",
"¾î¶² Å×ÀÌºíµµ »ç¿ëµÇÁö ¾Ê¾Ò½À´Ï´Ù.",
@@ -197,10 +197,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -238,3 +238,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index a218d5873b0..84c96a0540e 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -96,7 +96,7 @@
"Ein kan ikkje slette alle felt med ALTER TABLE. Bruk DROP TABLE istadenfor.",
"Kan ikkje DROP '%-.64s'. Undersøk om felt/nøkkel eksisterar.",
"Postar: %ld Like: %ld Åtvaringar: %ld",
-"INSERT TABLE '%-.64s' er ikkje tillate i FROM tabell liste",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ukjent tråd id: %lu",
"Du er ikkje eigar av tråd %lu",
"Ingen tabellar i bruk",
@@ -199,10 +199,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -240,3 +240,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 9ed50b4a00b..b57eb19906d 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -96,7 +96,7 @@
"En kan ikke slette alle felt med ALTER TABLE. Bruk DROP TABLE isteden.",
"Kan ikke DROP '%-.64s'. Undersøk om felt/nøkkel eksisterer.",
"Poster: %ld Like: %ld Advarsler: %ld",
-"INSERT TABLE '%-.64s' er ikke tillatt i FROM tabell liste",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Ukjent tråd id: %lu",
"Du er ikke eier av tråden %lu",
"Ingen tabeller i bruk",
@@ -199,10 +199,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -240,3 +240,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index e5bede3b48c..2d07b362257 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -98,7 +98,7 @@
"Nie mo¿na usun?æ wszystkich pól wykorzystuj?c ALTER TABLE. W zamian u¿yj DROP TABLE",
"Nie mo¿na wykonaæ operacji DROP '%-.64s'. Sprawd¥, czy to pole/klucz istnieje",
"Rekordów: %ld Duplikatów: %ld Ostrze¿eñ: %ld",
-"Operacja INSERT TABLE '%-.64s' nie jest dozwolona w li?cie tabel w FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Nieznany identyfikator w?tku: %lu",
"Nie jeste? w³a?cicielem w?tku %lu",
"Nie ma ¿adej u¿ytej tabeli",
@@ -201,10 +201,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -242,3 +242,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 0badf76c13d..8db48115c49 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -94,7 +94,7 @@
"Você não pode deletar todas as colunas com ALTER TABLE. Use DROP TABLE em seu lugar",
"Não se pode fazer DROP '%-.64s'. Confira se esta coluna/chave existe",
"Registros: %ld - Duplicados: %ld - Avisos: %ld",
-"INSERT TABLE '%-.64s' não é permitido na lista de tabelas contidas em FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"'Id' de 'thread' %lu desconhecido",
"Você não é proprietário da 'thread' %lu",
"Nenhuma tabela usada",
@@ -199,8 +199,8 @@
"Tabela '%-.64s' está marcada como danificada e a última reparação (automática?) falhou",
"Aviso: Algumas tabelas não-transacionais alteradas não puderam ser reconstituídas (rolled back)",
"Transações multi-declaradas (multi-statement transactions) requeriram mais do que o valor limite (max_binlog_cache_size) de bytes para armazenagem. Aumente o valor desta variável do mysqld e tente novamente",
-"Esta operação não pode ser realizada com um 'slave' em execução. Execute SLAVE STOP primeiro",
-"Esta operação requer um 'slave' em execução. Configure o 'slave' e execute SLAVE START",
+"Esta operação não pode ser realizada com um 'slave' em execução. Execute STOP SLAVE primeiro",
+"Esta operação requer um 'slave' em execução. Configure o 'slave' e execute START SLAVE",
"O servidor não está configurado como 'slave'. Acerte o arquivo de configuração ou use CHANGE MASTER TO",
"Não pode inicializar a estrutura de informação do 'master'. Verifique as permissões em 'master.info'",
"Não conseguiu criar 'thread' de 'slave'. Verifique os recursos do sistema",
@@ -238,3 +238,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 1b036481538..337cfd0963e 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -98,7 +98,7 @@
"Nu poti sterge toate coloanele cu ALTER TABLE. Foloseste DROP TABLE in schimb",
"Nu pot sa DROP '%-.64s'. Verifica daca coloana/cheia exista",
"Recorduri: %ld Duplicate: %ld Atentionari (warnings): %ld",
-"INSERT TABLE '%-.64s' nu este permis in lista FROM de tabele",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Id-ul: %lu thread-ului este necunoscut",
"Nu sinteti proprietarul threadului %lu",
"Nici o tabela folosita",
@@ -201,10 +201,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -242,3 +242,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s"
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 8858090e8db..b5d1a0a7e07 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -1,4 +1,4 @@
-/* Copyright 2003 MySQL AB;
+/* Copyright 2003 MySQL AB
Translation done in 2003 by Egor Egorov; Ensita.NET, http://www.ensita.net/
This file is public domain and comes with NO WARRANTY of any kind */
/* charset: KOI8-R */
@@ -237,6 +237,23 @@
"ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÎÅ ÍÏÖÅÔ ÂÙÔØ ÕÓÔÁÎÏ×ÌÅÎÁ × ÚÎÁÞÅÎÉÅ '%-.64s'",
"îÅ×ÅÒÎÙÊ ÔÉÐ ÁÒÇÕÍÅÎÔÁ ÄÌÑ ÐÅÒÅÍÅÎÎÏÊ '%-.64s'",
"ðÅÒÅÍÅÎÎÁÑ '%-.64s' ÍÏÖÅÔ ÂÙÔØ ÔÏÌØËÏ ÕÓÔÁÎÏ×ÌÅÎÁ, ÎÏ ÎÅ ÓÞÉÔÁÎÁ",
-"îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'",
+"îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'",
"üÔÁ ×ÅÒÓÉÑ MySQL ÐÏËÁ ÅÝÅ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ '%s'",
"ðÏÌÕÞÅÎÁ ÎÅÉÓÐÒÁ×ÉÍÁÑ ÏÛÉÂËÁ %d: '%-.128s' ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ × ÐÒÏÃÅÓÓÅ ×ÙÂÏÒËÉ ÄÁÎÎÙÈ ÉÚ Ä×ÏÉÞÎÏÇÏ ÖÕÒÎÁÌÁ",
+"Wrong foreign key definition for '%-.64s': %s",
+"Key reference and table reference doesn't match",
+"ïÛÉÂËÁ ÍÏÝØÎÏÓÔÉ ÍÎÏÖÅÓÔ×Á (ÂÏÌØÛÅ/ÍÅÎØÛÅ %d ËÏÌÏÎÏË)",
+"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ",
+"ðÒÅÏÂÒÁÚÏ×ÁÎÉÅ ÐÏÌÑ '%s' ÉÚ %s × %s",
+"óÓÙÌËÁ '%-.64s' ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔÓÑ (%s)",
+"Every derived table must have it's own alias"
+"Select %u ÂÙÌ ÕÐÒÁÚÄÎÅÎ × ÐÒÏÃÅÓÓÅ ÏÐÔÉÍÉÚÁÃÉÉ",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
new file mode 100644
index 00000000000..d6883efc96b
--- /dev/null
+++ b/sql/share/serbian/errmsg.txt
@@ -0,0 +1,253 @@
+/* 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",
+"You can't specify target table '%-.64s' for update in FROM clause",
+"Nepoznat thread identifikator: %lu",
+"Vi niste vlasnik thread-a %lu",
+"Nema upotrebljenih tabela",
+"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 'STOP SLAVE' 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 'START SLAVE'",
+"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 6424dcec6ee..ee7d1e9c4fb 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -102,7 +102,7 @@
"One nemô¾em zmaza» all fields with ALTER TABLE. Use DROP TABLE instead",
"Nemô¾em zru¹i» (DROP) '%-.64s'. Skontrolujte, èi neexistujú záznamy/kµúèe",
"Záznamov: %ld Opakovaných: %ld Varovania: %ld",
-"INSERT TABLE '%-.64s' nie je dovolené v zozname tabuliek FROM",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Neznáma identifikácia vlákna: %lu",
"Nie ste vlastníkom vlákna %lu",
"Nie je pou¾itá ¾iadna tabuµka",
@@ -205,10 +205,10 @@
"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",
+"This operation cannot be performed with a running slave, run STOP SLAVE first",
+"This operation requires a running slave, configure slave and do START SLAVE",
"The server is not configured as slave, fix in config file or with CHANGE MASTER TO",
"Could not initialize master info structure, check permisions on master.info",
"Could not create slave thread, check system resources",
@@ -246,3 +246,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index df95a02a7aa..2dfdc7573fa 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -95,7 +95,7 @@
"No puede borrar todos los campos con ALTER TABLE. Usa DROP TABLE para hacerlo",
"No puedo ELIMINAR '%-.64s'. compuebe que el campo/clave existe",
"Registros: %ld Duplicados: %ld Peligros: %ld",
-"INSERT TABLE '%-.64s' no esta permitido en FROM tabla lista",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Identificador del thread: %lu desconocido",
"Tu no eres el propietario del thread%lu",
"No ha tablas usadas",
@@ -200,8 +200,8 @@
"Tabla '%-.64s' está marcada como crashed y la última reparación (automactica?) falló",
"Aviso: Algunas tablas no transancionales no pueden tener rolled back",
"Multipla transición necesita mas que 'max_binlog_cache_size' bytes de almacenamiento. Aumente esta variable mysqld y tente de nuevo",
-"Esta operación no puede ser hecha con el esclavo funcionando, primero use SLAVE STOP",
-"Esta operación necesita el esclavo funcionando, configure esclavo y haga el SLAVE START",
+"Esta operación no puede ser hecha con el esclavo funcionando, primero use STOP SLAVE",
+"Esta operación necesita el esclavo funcionando, configure esclavo y haga el START SLAVE",
"El servidor no está configurado como esclavo, edite el archivo config file o con CHANGE MASTER TO",
"No puedo inicializar la estructura info del master, verifique permisiones en el master.info",
"No puedo crear el thread esclavo, verifique recursos del sistema",
@@ -239,3 +239,20 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returns more than 1 record",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"Cyclic reference on subqueries",
+"Converting column '%s' from %s to %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index e0da1bfb4c1..517232fe2a9 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -94,7 +94,7 @@
"Man kan inte radera alla fält med ALTER TABLE. Använd DROP TABLE istället",
"Kan inte ta bort '%-.64s'. Kontrollera att fältet/nyckel finns",
"Rader: %ld Dubletter: %ld Varningar: %ld",
-"INSERT table '%-.64s' får inte finnas i FROM tabell-listan",
+"You can't specify target table '%-.64s' for update in FROM clause",
"Finns inget thread med id %lu",
"Du är inte ägare till thread %lu",
"Inga tabeller angivna",
@@ -197,10 +197,10 @@
"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",
+"Denna operation kan inte göras under replikering; Gör STOP SLAVE först",
+"Denna operation kan endast göras under replikering; Konfigurera slaven och gör START SLAVE",
"Servern är inte konfigurerade som en replikations slav. Ändra konfigurationsfilen eller gör CHANGE MASTER TO",
"Kunde inte initializera replications-strukturerna. Kontrollera privilegerna för 'master.info'",
"Kunde inte starta en tråd för replikering",
@@ -229,12 +229,29 @@
"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",
+"Cardinality error (more/less than %d columns)",
+"Subselect returnerade mer än 1 rad",
+"Okänd PREPARED STATEMENT id (%ld) var given till %s",
+"Hjälp databasen finns inte eller är skadad",
+"Syklisk referens i subselect",
+"Konvertar kolumn '%s' från %s till %s",
+"Reference '%-.64s' not supported (%s)",
+"Every derived table must have it's own alias"
+"Select %u was reduced during optimisation",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index c1d98e83f7d..be8fe2afea5 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -99,7 +99,7 @@
"îÅ ÍÏÖÌÉ×Ï ×ÉÄÁÌÉÔÉ ×Ó¦ ÓÔÏ×Âæ ÚÁ ÄÏÐÏÍÏÇÏÀ ALTER TABLE. äÌÑ ÃØÏÇÏ ÓËÏÒÉÓÔÁÊÔÅÓÑ DROP TABLE",
"îÅ ÍÏÖÕ DROP '%-.64s'. ðÅÒÅצÒÔÅ, ÞÉ ÃÅÊ ÓÔÏ×ÂÅÃØ/ËÌÀÞ ¦ÓÎÕ¤",
"úÁÐÉÓ¦×: %ld äÕÂ̦ËÁÔ¦×: %ld úÁÓÔÅÒÅÖÅÎØ: %ld",
-"INSERT TABLE '%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ Õ ÐÅÒÅ̦ËÕ FROM TABLE",
+"ôÁÂÌÉÃÑ '%-.64s' ÝÏ ÚͦÎÀ¤ÔØÓÑ ÎÅ ÄÏÚ×ÏÌÅÎÁ Õ ÐÅÒÅ̦ËÕ ÔÁÂÌÉÃØ FROM",
"îÅצÄÏÍÉÊ ¦ÄÅÎÔÉƦËÁÔÏÒ Ç¦ÌËÉ: %lu",
"÷É ÎÅ ×ÏÌÏÄÁÒ Ç¦ÌËÉ %lu",
"îÅ ×ÉËÏÒÉÓÔÁÎÏ ÔÁÂÌÉÃØ",
@@ -204,8 +204,8 @@
"ôÁÂÌÉÃÀ '%-.64s' ÍÁÒËÏ×ÁÎÏ ÑË Ú¦ÐÓÏ×ÁÎÕ ÔÁ ÏÓÔÁÎΤ (Á×ÔÏÍÁÔÉÞÎÅ?) צÄÎÏ×ÌÅÎÎÑ ÎÅ ×ÄÁÌÏÓÑ",
"úÁÓÔÅÒÅÖÅÎÎÑ: äÅÑ˦ ÎÅÔÒÁÎÚÁËæÊΦ ÚͦÎÉ ÔÁÂÌÉÃØ ÎÅ ÍÏÖÎÁ ÂÕÄÅ ÐÏ×ÅÒÎÕÔÉ",
"ôÒÁÎÚÁËÃ¦Ñ Ú ÂÁÇÁÔØÍÁ ×ÉÒÁÚÁÍÉ ×ÉÍÁÇÁ¤ ¦ÌØÛÅ Î¦Ö 'max_binlog_cache_size' ÂÁÊÔ¦× ÄÌÑ ÚÂÅÒ¦ÇÁÎÎÑ. ú¦ÌØÛÔÅ ÃÀ ÚͦÎÎÕ mysqld ÔÁ ÓÐÒÏÂÕÊÔÅ ÚÎÏ×Õ",
-"ïÐÅÒÁÃ¦Ñ ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÎÁÎÁ Ú ÚÁÐÕÝÅÎÉÍ Ð¦ÄÌÅÇÌÉÍ, ÓÐÏÞÁÔËÕ ×ÉËÏÎÁÊÔÅ SLAVE STOP",
-"ïÐÅÒÁÃ¦Ñ ×ÉÍÁÇÁ¤ ÚÁÐÕÝÅÎÏÇÏ Ð¦ÄÌÅÇÌÏÇÏ, ÚËÏÎƦÇÕÒÕÊÔŠЦÄÌÅÇÌÏÇÏ ÔÁ ×ÉËÏÎÁÊÔÅ SLAVE START",
+"ïÐÅÒÁÃ¦Ñ ÎÅ ÍÏÖÅ ÂÕÔÉ ×ÉËÏÎÁÎÁ Ú ÚÁÐÕÝÅÎÉÍ Ð¦ÄÌÅÇÌÉÍ, ÓÐÏÞÁÔËÕ ×ÉËÏÎÁÊÔÅ STOP SLAVE",
+"ïÐÅÒÁÃ¦Ñ ×ÉÍÁÇÁ¤ ÚÁÐÕÝÅÎÏÇÏ Ð¦ÄÌÅÇÌÏÇÏ, ÚËÏÎƦÇÕÒÕÊÔŠЦÄÌÅÇÌÏÇÏ ÔÁ ×ÉËÏÎÁÊÔÅ START SLAVE",
"óÅÒ×ÅÒ ÎÅ ÚËÏÎƦÇÕÒÏ×ÁÎÏ ÑË Ð¦ÄÌÅÇÌÉÊ, ×ÉÐÒÁ×ÔÅ ÃÅ Õ ÆÁÊ̦ ËÏÎƦÇÕÒÁæ§ ÁÂÏ Ú CHANGE MASTER TO",
"îÅ ÍÏÖÕ ¦Î¦Ã¦Á̦ÚÕ×ÁÔÉ ÓÔÒÕËÔÕÒÕ ÉÎÆÏÒÍÁæ§ ÇÏÌÏ×ÎÏÇÏ, ÐÅÒÅצÒÔÅ ÐÒÁ×Á ÄÏÓÔÕÐÕ ÎÁ master.info",
"îÅ ÍÏÖÕ ÓÔ×ÏÒÉÔÉ Ð¦ÄÌÅÇÌÕ Ç¦ÌËÕ, ÐÅÒÅצÒÔÅ ÓÉÓÔÅÍΦ ÒÅÓÕÒÓÉ",
@@ -243,3 +243,20 @@
"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",
+"Cardinality error (¦ÌØÛÅ/ÍÅÎØÛÅ Î¦Ö %d ÓÔÏ×Âæ×)",
+"ð¦ÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ¦ÌØÛ ÎiÖ 1 ÚÁÐÉÓ",
+"Unknown prepared statement handler (%ld) given to %s",
+"Help database is corrupt or does not exist",
+"ãÉË̦ÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ЦÄÚÁÐÉÔ",
+"ðÅÒÅÔ×ÏÒÅÎÎÑ ÓÔÏ×ÂÃÁ '%s' Ú %s Õ %s",
+"ðÏÓÉÌÁÎÎÑ '%-.64s' ÎÅ ÐiÄÔÒÉÍÕÅÔÓÑ (%s)",
+"Every derived table must have it's own alias"
+"Select %u was ÓËÁÓÏ×ÁÎÏ ÐÒÉ ÏÐÔÉÍiÚÁÃii",
+"Table '%-.64s' from one of SELECT's can not be used in %-.32s"
+"Client does not support authentication protocol requested by server. Consider upgrading MySQL client"
+"All parts of a SPATIAL KEY must be NOT NULL"
+"COLLATION '%s' is not valid for CHARACTER SET '%s'"
+"The slave was already running"
+"The slave was already stopped"
diff --git a/sql/slave.cc b/sql/slave.cc
index 771317f9431..c66f5c307d4 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -14,8 +14,10 @@
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"
+
+#ifdef HAVE_REPLICATION
+
#include <mysql.h>
#include <myisam.h>
#include "mini_client.h"
@@ -24,7 +26,6 @@
#include "repl_failsafe.h"
#include <thr_alarm.h>
#include <my_dir.h>
-#include <assert.h>
bool use_slave_mask = 0;
MY_BITMAP slave_error_mask;
@@ -55,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,8 +78,21 @@ char* rewrite_db(char* db);
/*
- Get a bit mask for which threads are running so that we later can
- restart these threads
+ Find out which replications threads are running
+
+ SYNOPSIS
+ init_thread_mask()
+ mask Return value here
+ mi master_info for slave
+ inverse If set, returns which threads are not running
+
+ IMPLEMENTATION
+ Get a bit mask for which threads are running so that we can later restart
+ these threads.
+
+ RETURN
+ mask If inverse == 0, running threads
+ If inverse == 1, stopped threads
*/
void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
@@ -96,6 +109,10 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse)
}
+/*
+ lock_slave_threads()
+*/
+
void lock_slave_threads(MASTER_INFO* mi)
{
//TODO: see if we can do this without dual mutex
@@ -103,6 +120,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,6 +133,8 @@ void unlock_slave_threads(MASTER_INFO* mi)
}
+/* Initialize slave structures */
+
int init_slave()
{
DBUG_ENTER("init_slave");
@@ -166,6 +190,7 @@ static void free_table_ent(TABLE_RULE_ENT* e)
my_free((gptr) e, MYF(0));
}
+
static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
my_bool not_used __attribute__((unused)))
{
@@ -287,7 +312,16 @@ err:
}
-/* called from get_options() in mysqld.cc on start-up */
+/*
+ Init functio to set up array for errors that should be skipped for slave
+
+ SYNOPSIS
+ init_slave_skip_errors()
+ arg List of errors numbers to skip, separated with ','
+
+ NOTES
+ Called from get_options() in mysqld.cc on start-up
+*/
void init_slave_skip_errors(const char* arg)
{
@@ -298,9 +332,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;
@@ -312,15 +346,17 @@ 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()
+
+ NOTES
+ 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,
@@ -472,7 +508,8 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
pthread_cond_t *start_cond,
volatile bool *slave_running,
volatile ulong *slave_run_id,
- MASTER_INFO* mi)
+ MASTER_INFO* mi,
+ bool high_priority)
{
pthread_t th;
ulong start_id;
@@ -501,6 +538,8 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
}
start_id= *slave_run_id;
DBUG_PRINT("info",("Creating new slave thread"));
+ if (high_priority)
+ my_pthread_attr_setprio(&connection_attrib,CONNECT_PRIOR);
if (pthread_create(&th, &connection_attrib, h_func, (void*)mi))
{
if (start_lock)
@@ -531,9 +570,12 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock,
/*
- 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
- started the threads that were not previously running
+ start_slave_threads()
+
+ NOTES
+ 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
+ started the threads that were not previously running
*/
int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
@@ -562,13 +604,13 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
error=start_slave_thread(handle_slave_io,lock_io,lock_cond_io,
cond_io,
&mi->slave_running, &mi->slave_run_id,
- mi);
+ mi, 1); //high priority, to read the most possible
if (!error && (thread_mask & SLAVE_SQL))
{
error=start_slave_thread(handle_slave_sql,lock_sql,lock_cond_sql,
cond_sql,
&mi->rli.slave_running, &mi->rli.slave_run_id,
- mi);
+ mi, 0);
if (error)
terminate_slave_threads(mi, thread_mask & SLAVE_IO, 0);
}
@@ -578,12 +620,13 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
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;
}
+
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
{
my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE,
@@ -591,6 +634,7 @@ void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited)
*a_inited = 1;
}
+
static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
uint i;
@@ -600,8 +644,10 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
TABLE_RULE_ENT* e ;
get_dynamic(a, (gptr)&e, i);
- if (!wild_case_compare(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;
}
@@ -740,6 +786,11 @@ int add_table_rule(HASH* h, const char* table_spec)
return 0;
}
+
+/*
+ Add table expression with wildcards to dynamic array
+*/
+
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
{
const char* dot = strchr(table_spec, '.');
@@ -756,6 +807,7 @@ int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec)
return 0;
}
+
static void free_string_array(DYNAMIC_ARRAY *a)
{
uint i;
@@ -768,8 +820,8 @@ static void free_string_array(DYNAMIC_ARRAY *a)
delete_dynamic(a);
}
-#ifdef NOT_USED_YET
+#ifdef NOT_USED_YET
static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
{
end_master_info(mi);
@@ -778,6 +830,13 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/)
#endif
+/*
+ Free all resources used by slave
+
+ SYNOPSIS
+ end_slave()
+*/
+
void end_slave()
{
if (active_mi)
@@ -830,13 +889,25 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
rli->last_slave_errno = err_code;
}
+/*
+ skip_load_data_infile()
+
+ NOTES
+ 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
+}
+
-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));
}
@@ -998,13 +1069,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;
@@ -1012,7 +1083,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
if (!(query = sql_alloc(packet_len + 1)))
{
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(query, net->read_pos, packet_len);
@@ -1050,7 +1121,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;
}
@@ -1059,7 +1130,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;
@@ -1078,7 +1149,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);
@@ -1086,6 +1157,7 @@ err:
return error;
}
+
int fetch_master_table(THD *thd, const char *db_name, const char *table_name,
MASTER_INFO *mi, MYSQL *mysql)
{
@@ -1100,12 +1172,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);
}
@@ -1129,7 +1201,7 @@ 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
}
@@ -1314,9 +1386,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)) &&
!rli->ignore_log_space_limit)
@@ -1468,109 +1542,115 @@ err:
int register_slave_on_master(MYSQL* mysql)
{
- String packet;
- char buf[4];
+ char buf[1024], *pos= buf;
+ uint report_host_len, report_user_len=0, report_password_len=0;
if (!report_host)
return 0;
-
- int4store(buf, server_id);
- packet.append(buf, 4);
-
- net_store_data(&packet, report_host);
+ report_host_len= strlen(report_host);
if (report_user)
- net_store_data(&packet, report_user);
- else
- packet.append((char)0);
-
+ report_user_len= strlen(report_user);
if (report_password)
- net_store_data(&packet, report_user);
- else
- packet.append((char)0);
-
- int2store(buf, (uint16)report_port);
- packet.append(buf, 2);
- int4store(buf, rpl_recovery_rank);
- packet.append(buf, 4);
- int4store(buf, 0); /* tell the master will fill in master_id */
- packet.append(buf, 4);
-
- if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*)packet.ptr(),
- packet.length(), 0))
+ report_password_len= strlen(report_password);
+ /* 30 is a good safety margin */
+ if (report_host_len + report_user_len + report_password_len + 30 >
+ sizeof(buf))
+ return 0; // safety
+
+ int4store(pos, server_id); pos+= 4;
+ pos= net_store_data(pos, report_host, report_host_len);
+ pos= net_store_data(pos, report_user, report_user_len);
+ pos= net_store_data(pos, report_password, report_password_len);
+ int2store(pos, (uint16) report_port); pos+= 2;
+ int4store(pos, rpl_recovery_rank); pos+= 4;
+ /* The master will fill in master_id */
+ int4store(pos, 0); pos+= 4;
+
+ if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf,
+ (uint) (pos- buf), 0))
{
sql_print_error("Error on COM_REGISTER_SLAVE: %d '%s'",
mc_mysql_errno(mysql),
mc_mysql_error(mysql));
return 1;
}
-
return 0;
}
+
int show_master_info(THD* thd, MASTER_INFO* mi)
{
// TODO: fix this for multi-master
- DBUG_ENTER("show_master_info");
List<Item> field_list;
+ Protocol *protocol= thd->protocol;
+ DBUG_ENTER("show_master_info");
+
field_list.push_back(new Item_empty_string("Master_Host",
sizeof(mi->host)));
field_list.push_back(new Item_empty_string("Master_User",
sizeof(mi->user)));
- field_list.push_back(new Item_empty_string("Master_Port", 6));
- field_list.push_back(new Item_empty_string("Connect_retry", 6));
+ field_list.push_back(new Item_return_int("Master_Port", 7,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Connect_retry", 10,
+ MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Master_Log_File",
- FN_REFLEN));
- field_list.push_back(new Item_empty_string("Read_Master_Log_Pos", 12));
+ FN_REFLEN));
+ field_list.push_back(new Item_return_int("Read_Master_Log_Pos", 10,
+ MYSQL_TYPE_LONGLONG));
field_list.push_back(new Item_empty_string("Relay_Log_File",
- FN_REFLEN));
- field_list.push_back(new Item_empty_string("Relay_Log_Pos", 12));
+ FN_REFLEN));
+ field_list.push_back(new Item_return_int("Relay_Log_Pos", 10,
+ MYSQL_TYPE_LONGLONG));
field_list.push_back(new Item_empty_string("Relay_Master_Log_File",
- FN_REFLEN));
+ FN_REFLEN));
field_list.push_back(new Item_empty_string("Slave_IO_Running", 3));
field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3));
field_list.push_back(new Item_empty_string("Replicate_do_db", 20));
field_list.push_back(new Item_empty_string("Replicate_ignore_db", 20));
- field_list.push_back(new Item_empty_string("Last_errno", 4));
+ field_list.push_back(new Item_return_int("Last_errno", 4, MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Last_error", 20));
- field_list.push_back(new Item_empty_string("Skip_counter", 12));
- field_list.push_back(new Item_empty_string("Exec_master_log_pos", 12));
- field_list.push_back(new Item_empty_string("Relay_log_space", 12));
- if (send_fields(thd, field_list, 1))
+ field_list.push_back(new Item_return_int("Skip_counter", 10,
+ MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_return_int("Exec_master_log_pos", 10,
+ MYSQL_TYPE_LONGLONG));
+ field_list.push_back(new Item_return_int("Relay_log_space", 10,
+ MYSQL_TYPE_LONGLONG));
+ if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
if (mi->host[0])
{
String *packet= &thd->packet;
- packet->length(0);
+ protocol->prepare_for_resend();
pthread_mutex_lock(&mi->data_lock);
pthread_mutex_lock(&mi->rli.data_lock);
- net_store_data(packet, mi->host);
- net_store_data(packet, mi->user);
- net_store_data(packet, (uint32) mi->port);
- net_store_data(packet, (uint32) mi->connect_retry);
- net_store_data(packet, mi->master_log_name);
- net_store_data(packet, (longlong) mi->master_log_pos);
- net_store_data(packet, mi->rli.relay_log_name +
- dirname_length(mi->rli.relay_log_name));
- net_store_data(packet, (longlong) mi->rli.relay_log_pos);
- net_store_data(packet, mi->rli.master_log_name);
- net_store_data(packet, mi->slave_running ? "Yes":"No");
- net_store_data(packet, mi->rli.slave_running ? "Yes":"No");
- net_store_data(packet, &replicate_do_db);
- net_store_data(packet, &replicate_ignore_db);
- net_store_data(packet, (uint32)mi->rli.last_slave_errno);
- net_store_data(packet, mi->rli.last_slave_error);
- net_store_data(packet, mi->rli.slave_skip_counter);
- net_store_data(packet, (longlong) mi->rli.master_log_pos);
- net_store_data(packet, (longlong) mi->rli.log_space_total);
+ protocol->store(mi->host, system_charset_info);
+ protocol->store(mi->user, system_charset_info);
+ protocol->store((uint32) mi->port);
+ protocol->store((uint32) mi->connect_retry);
+ protocol->store(mi->master_log_name, system_charset_info);
+ protocol->store((ulonglong) mi->master_log_pos);
+ protocol->store(mi->rli.relay_log_name +
+ dirname_length(mi->rli.relay_log_name), system_charset_info);
+ protocol->store((ulonglong) mi->rli.relay_log_pos);
+ protocol->store(mi->rli.master_log_name, system_charset_info);
+ protocol->store(mi->slave_running ? "Yes":"No", system_charset_info);
+ protocol->store(mi->rli.slave_running ? "Yes":"No", system_charset_info);
+ protocol->store(&replicate_do_db);
+ protocol->store(&replicate_ignore_db);
+ protocol->store((uint32) mi->rli.last_slave_errno);
+ protocol->store(mi->rli.last_slave_error, system_charset_info);
+ protocol->store((uint32) mi->rli.slave_skip_counter);
+ protocol->store((ulonglong) mi->rli.master_log_pos);
+ protocol->store((ulonglong) mi->rli.log_space_total);
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
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);
}
@@ -1586,8 +1666,7 @@ bool flush_master_info(MASTER_INFO* mi)
my_b_printf(file, "%s\n%s\n%s\n%s\n%s\n%d\n%d\n",
mi->master_log_name, llstr(mi->master_log_pos, lbuf),
mi->host, mi->user,
- mi->password, mi->port, mi->connect_retry
- );
+ mi->password, mi->port, mi->connect_retry);
flush_io_cache(file);
DBUG_RETURN(0);
}
@@ -1796,6 +1875,10 @@ improper_arguments: %d timed_out: %d",
}
+/*
+ init_slave_thread()
+*/
+
static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{
DBUG_ENTER("init_slave_thread");
@@ -1934,7 +2017,7 @@ command");
/*
- read one event from the master
+ Read one event from the master
SYNOPSIS
read_event()
@@ -1948,7 +2031,6 @@ command");
RETURN VALUES
'packet_error' Error
number Length of packet
-
*/
static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings)
@@ -2024,7 +2106,6 @@ point. If you are sure that your master is ok, run this query manually on the\
static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
{
- DBUG_ASSERT(rli->sql_thd==thd);
Log_event * ev = next_event(rli);
DBUG_ASSERT(rli->sql_thd==thd);
if (sql_slave_killed(thd,rli))
@@ -2087,7 +2168,8 @@ This may also be a network problem, or just a bug in the master or slave code.\
}
-/* slave I/O thread */
+/* Slave I/O Thread entry point */
+
extern "C" pthread_handler_decl(handle_slave_io,arg)
{
THD *thd; // needs to be first for thread_stack
@@ -2362,7 +2444,7 @@ err:
}
-/* slave SQL logic thread */
+/* Slave SQL Thread entry point */
extern "C" pthread_handler_decl(handle_slave_sql,arg)
{
@@ -2388,7 +2470,8 @@ slave_begin:
#endif
thd = new THD; // note that contructor of THD uses DBUG_ !
- THD_CHECK_SENTRY(thd);
+ thd->thread_stack = (char*)&thd; // remember where our stack is
+
/* Inform waiting threads that slave has started */
rli->slave_run_id++;
@@ -2404,9 +2487,9 @@ slave_begin:
sql_print_error("Failed during slave thread initialization");
goto err;
}
+ thd->init_for_queries();
rli->sql_thd= thd;
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
- thd->thread_stack = (char*)&thd; // remember where our stack is
pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd);
pthread_mutex_unlock(&LOCK_thread_count);
@@ -2499,7 +2582,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
if (abort_slave_event_count && !rli->events_till_abort)
goto slave_begin;
#endif
- my_thread_end(); // clean-up before broadcasting termination
+ my_thread_end();
#ifndef __NETWARE__
pthread_exit(0);
#endif /* __NETWARE__ */
@@ -2507,13 +2590,17 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
}
+/*
+ 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()))
@@ -2527,7 +2614,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;
@@ -2557,7 +2643,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)))
@@ -2603,6 +2689,7 @@ err:
DBUG_RETURN(error);
}
+
/*
Start using a new binary log on the master
@@ -2621,6 +2708,7 @@ err:
RETURN VALUES
0 ok
1 Log event is illegal
+
*/
static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
@@ -2647,7 +2735,10 @@ 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
@@ -2740,7 +2831,10 @@ 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
*/
@@ -2821,7 +2915,20 @@ void end_relay_log_info(RELAY_LOG_INFO* rli)
DBUG_VOID_RETURN;
}
-/* try to connect until successful or slave killed */
+/*
+ Try to connect until successful or slave killed
+
+ SYNPOSIS
+ safe_connect()
+ thd Thread handler for slave
+ mysql MySQL connection handle
+ mi Replication handle
+
+ RETURN
+ 0 ok
+ # Error
+*/
+
static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
{
return connect_to_master(thd, mysql, mi, 0, 0);
@@ -2829,8 +2936,12 @@ static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
/*
- Try to connect until successful or slave killed or we have retried
- master_retry_count times
+ SYNPOSIS
+ connect_to_master()
+
+ IMPLEMENTATION
+ 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,
@@ -2913,8 +3024,11 @@ replication resumed in log '%s' at position %s", mi->user,
/*
- Try to connect until successful or slave killed or we have retried
- master_retry_count times
+ safe_reconnect()
+
+ IMPLEMENTATION
+ 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,
@@ -2983,8 +3097,7 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli)
/*
- This function is called when we notice that the current "hot" log
- got rotated under our feet.
+ 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)
@@ -3244,3 +3357,5 @@ err:
template class I_List_iterator<i_string>;
template class I_List_iterator<i_string_pair>;
#endif
+
+#endif /* HAVE_REPLICATION */
diff --git a/sql/slave.h b/sql/slave.h
index 8832302056d..a4db7388be5 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -1,3 +1,5 @@
+#ifdef HAVE_REPLICATION
+
#ifndef SLAVE_H
#define SLAVE_H
@@ -7,22 +9,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 +56,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 +79,8 @@ struct st_master_info;
master_log_pos
To clean up, call end_relay_log_info()
- */
+
+*****************************************************************************/
typedef struct st_relay_log_info
{
@@ -128,13 +142,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;
@@ -214,10 +233,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
@@ -239,9 +263,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];
@@ -350,7 +374,8 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t* start_lock,
pthread_cond_t* start_cond,
volatile bool *slave_running,
volatile ulong *slave_run_id,
- MASTER_INFO* mi);
+ MASTER_INFO* mi,
+ bool high_priority);
/* If fd is -1, dump to NET */
int mysql_table_dump(THD* thd, const char* db,
@@ -424,3 +449,7 @@ extern I_List<i_string_pair> replicate_rewrite_db;
extern I_List<THD> threads;
#endif
+#else
+#define SLAVE_IO 1
+#define SLAVE_SQL 2
+#endif /* HAVE_REPLICATION */
diff --git a/sql/spatial.cc b/sql/spatial.cc
new file mode 100644
index 00000000000..3345c2756e7
--- /dev/null
+++ b/sql/spatial.cc
@@ -0,0 +1,1570 @@
+#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)/sizeof(ci_collection[0]);
+
+/***************************** 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) &&
+ (my_strncasecmp(&my_charset_latin1, 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);
+ double d;
+ float8get(d, data);
+ result->q_append(d);
+ float8get(d, data + 8);
+ result->q_append(d);
+
+ 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);
+ double d;
+ float8get(d, data);
+ result->q_append(d);
+ float8get(d, data + 8);
+ result->q_append(d);
+
+ 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) // 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);
+ double d;
+ float8get(d, data);
+ result->q_append(d);
+ float8get(d, data + 8);
+ result->q_append(d);
+
+ 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)
+ {
+ double d;
+ float8get(d, data);
+ txt->qs_append(d);
+ txt->qs_append(' ');
+ float8get(d, data + 8);
+ txt->qs_append(d);
+ 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)
+ {
+ double d;
+ float8get(d, data + WKB_HEADER_SIZE);
+ txt->qs_append(d);
+ txt->qs_append(' ');
+ float8get(d, data + WKB_HEADER_SIZE + 8);
+ txt->qs_append(d);
+ txt->qs_append(',');
+ data+= WKB_HEADER_SIZE + 8 + 8;
+ }
+ 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;
+}
+
+int GMultiPoint::num_geometries(uint32 *num) const
+{
+ *num = uint4korr(m_data);
+ return 0;
+}
+
+int GMultiPoint::geometry_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);
+ data+= 4;
+ if ((num > n_points) || (num < 1))
+ return -1;
+ data+= (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE);
+ if (result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE))
+ return 1;
+ result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_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)
+ {
+ double d;
+ float8get(d, data);
+ txt->qs_append(d);
+ txt->qs_append(' ');
+ float8get(d, data + 8);
+ txt->qs_append(d);
+ 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::num_geometries(uint32 *num) const
+{
+ *num = uint4korr(m_data);
+ return 0;
+}
+
+int GMultiLineString::geometry_n(uint32 num, String *result) const
+{
+ uint32 n_line_strings;
+ const char *data= m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_line_strings= uint4korr(data);
+ data+= 4;
+
+ if ((num > n_line_strings) || (num < 1))
+ return -1;
+
+ for (; num > 0; --num)
+ {
+ if (no_data(data, WKB_HEADER_SIZE + 4))
+ return 1;
+ uint32 n_points= uint4korr(data + WKB_HEADER_SIZE);
+ if (num == 1)
+ {
+ if (result->reserve(WKB_HEADER_SIZE + 4 + POINT_DATA_SIZE * n_points))
+ return 1;
+ result->q_append(data, WKB_HEADER_SIZE + 4 + POINT_DATA_SIZE *n_points);
+ break;
+ }
+ else
+ {
+ data+= WKB_HEADER_SIZE + 4 + POINT_DATA_SIZE * n_points;
+ }
+ }
+ 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)
+ {
+ double d;
+ float8get(d, data);
+ txt->qs_append(d);
+ txt->qs_append(' ');
+ float8get(d, data + 8);
+ txt->qs_append(d);
+ 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::num_geometries(uint32 *num) const
+{
+ *num = uint4korr(m_data);
+ return 0;
+}
+
+int GMultiPolygon::geometry_n(uint32 num, String *result) const
+{
+ uint32 n_polygons;
+ const char *data= m_data, *polygon_n;
+ LINT_INIT(polygon_n);
+ if (no_data(data, 4))
+ return 1;
+ n_polygons= uint4korr(data);
+ data+= 4;
+
+ if ((num > n_polygons) || (num < 1))
+ return -1;
+
+ for (; num > 0; --num)
+ {
+ if (no_data(data, WKB_HEADER_SIZE + 4))
+ return 1;
+ uint32 n_linear_rings= uint4korr(data + WKB_HEADER_SIZE);
+
+ if (num == 1)
+ polygon_n= data;
+ 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 + POINT_DATA_SIZE * n_points;
+ }
+ if (num == 1)
+ {
+ if (result->reserve(data - polygon_n))
+ return -1;
+ result->q_append(polygon_n, data - polygon_n);
+ break;
+ }
+ }
+ 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..15e4f7353ed
--- /dev/null
+++ b/sql/spatial.h
@@ -0,0 +1,501 @@
+/* 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; }
+};
+
+/***************************** 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; }
+};
+
+/***************************** 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 num_geometries(uint32 *num) const;
+ int geometry_n(uint32 num, String *result) 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 num_geometries(uint32 *num) const;
+ int geometry_n(uint32 num, String *result) 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 num_geometries(uint32 *num) const;
+ int geometry_n(uint32 num, String *result) const;
+ int area(double *ar) const;
+ int centroid(String *result) const;
+ int dimension(uint32 *dim) const { *dim = 2; return 0; }
+};
+
+/***************************** 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 ee9d3f1c1ea..5f8f71e1bd4 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -29,53 +29,8 @@
#include "sql_acl.h"
#include "hash_filo.h"
#include <m_ctype.h>
-#include <assert.h>
#include <stdarg.h>
-struct acl_host_and_ip
-{
- char *hostname;
- long ip,ip_mask; // Used with masked ip:s
-};
-
-
-class ACL_ACCESS {
-public:
- ulong sort;
- ulong access;
-};
-
-
-/* ACL_HOST is used if no host is specified */
-
-class ACL_HOST :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *db;
-};
-
-
-class ACL_USER :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- uint hostname_length;
- USER_RESOURCES user_resource;
- char *user,*password;
- ulong salt[2];
- enum SSL_type ssl_type;
- const char *ssl_cipher, *x509_issuer, *x509_subject;
-};
-
-
-class ACL_DB :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *user,*db;
-};
-
class acl_entry :public hash_filo_element
{
@@ -99,10 +54,11 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
-static HASH acl_check_hosts, hash_tables;
+static HASH acl_check_hosts, column_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
static uint grant_version=0;
+static uint priv_version=0; /* Version of priv tables. incremented by acl_init */
static ulong get_access(TABLE *form,uint fieldnr);
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
@@ -141,9 +97,13 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (!acl_cache)
acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0,
(hash_get_key) acl_entry_get_key,
- (hash_free_key) free);
+ (hash_free_key) free, system_charset_info);
if (dont_read_acl_tables)
+ {
DBUG_RETURN(0); /* purecov: tested */
+ }
+
+ priv_version++; /* Privileges updated */
/*
To be able to run this from boot, we allocate a temporary THD
@@ -151,6 +111,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (!(thd=new THD))
DBUG_RETURN(1); /* purecov: inspected */
thd->store_globals();
+ /* Use passwords according to command line option */
+ use_old_passwords= opt_old_passwords;
acl_cache->clear(1); // Clear locked hostname cache
thd->db= my_strdup("mysql",MYF(0));
@@ -186,8 +148,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_HOST host;
- update_hostname(&host.host,get_field(&mem, table,0));
- host.db= get_field(&mem, table,1);
+ update_hostname(&host.host,get_field(&mem, table->field[0]));
+ host.db= get_field(&mem, table->field[1]);
host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access);
host.sort= get_sort(2,host.host.hostname,host.db);
@@ -215,15 +177,22 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
protocol_version=9; /* purecov: tested */
}
- DBUG_PRINT("info",("user table fields: %d",table->fields));
+ DBUG_PRINT("info",("user table fields: %d, password length: %d",
+ table->fields, table->field[2]->field_length));
+ if (table->field[2]->field_length < 45 && !use_old_passwords)
+ {
+ sql_print_error("mysql.user table is not updated to new password format; Disabling new password usage until mysql_fix_privilege_tables is run");
+ use_old_passwords= 1;
+ }
+
allow_all_hosts=0;
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_USER user;
uint length=0;
- update_hostname(&user.host,get_field(&mem, table,0));
- user.user=get_field(&mem, table,1);
- user.password=get_field(&mem, table,2);
+ update_hostname(&user.host,get_field(&mem, table->field[0]));
+ user.user=get_field(&mem, table->field[1]);
+ user.password=get_field(&mem, table->field[2]);
if (user.password && (length=(uint) strlen(user.password)) == 8 &&
protocol_version == PROTOCOL_VERSION)
{
@@ -231,13 +200,18 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
"Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)",
user.user ? user.user : ""); /* purecov: tested */
}
- else if (length % 8) // This holds true for passwords
+ else /* non empty and not short passwords */
{
- sql_print_error(
- "Found invalid password for user: '%s@%s'; Ignoring user",
- user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
- continue; /* purecov: tested */
+ user.pversion=get_password_version(user.password);
+ /* Only passwords of specific lengths depending on version are allowed */
+ if ( (!user.pversion && length % 8) || (user.pversion && length!=45 ))
+ {
+ sql_print_error(
+ "Found invalid password for user: '%s@%s'; Ignoring user",
+ user.user ? user.user : "",
+ user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
+ continue; /* purecov: tested */
+ }
}
get_salt_from_password(user.salt,user.password);
user.access=get_access(table,3) & GLOBAL_ACLS;
@@ -246,7 +220,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
(uint) strlen(user.host.hostname) : 0);
if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
{
- char *ssl_type=get_field(&mem, table, 24);
+ char *ssl_type=get_field(&mem, table->field[24]);
if (!ssl_type)
user.ssl_type=SSL_TYPE_NONE;
else if (!strcmp(ssl_type, "ANY"))
@@ -256,15 +230,15 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
else /* !strcmp(ssl_type, "SPECIFIED") */
user.ssl_type=SSL_TYPE_SPECIFIED;
- user.ssl_cipher= get_field(&mem, table, 25);
- user.x509_issuer= get_field(&mem, table, 26);
- user.x509_subject= get_field(&mem, table, 27);
+ user.ssl_cipher= get_field(&mem, table->field[25]);
+ user.x509_issuer= get_field(&mem, table->field[26]);
+ user.x509_subject= get_field(&mem, table->field[27]);
- char *ptr = get_field(&mem, table, 28);
+ char *ptr = get_field(&mem, table->field[28]);
user.user_resource.questions=atoi(ptr);
- ptr = get_field(&mem, table, 29);
+ ptr = get_field(&mem, table->field[29]);
user.user_resource.updates=atoi(ptr);
- ptr = get_field(&mem, table, 30);
+ ptr = get_field(&mem, table->field[30]);
user.user_resource.connections=atoi(ptr);
if (user.user_resource.questions || user.user_resource.updates ||
user.user_resource.connections)
@@ -303,14 +277,14 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_DB db;
- update_hostname(&db.host,get_field(&mem, table,0));
- db.db=get_field(&mem, table,1);
+ update_hostname(&db.host,get_field(&mem, table->field[0]));
+ db.db=get_field(&mem, table->field[1]);
if (!db.db)
{
sql_print_error("Found an entry in the 'db' table with empty database name; Skipped");
continue;
}
- db.user=get_field(&mem, table,2);
+ db.user=get_field(&mem, table->field[2]);
db.access=get_access(table,3);
db.access=fix_rights_for_db(db.access);
db.sort=get_sort(3,db.host.hostname,db.db,db.user);
@@ -392,6 +366,7 @@ void acl_reload(THD *thd)
if (acl_init(thd, 0))
{ // Error. Revert to old list
+ DBUG_PRINT("error",("Reverting to old privileges"));
acl_free(); /* purecov: inspected */
acl_hosts=old_acl_hosts;
acl_users=old_acl_users;
@@ -422,7 +397,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),&my_charset_latin1);
Field **pos;
for (pos=form->field+fieldnr, bit=1;
@@ -431,7 +406,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(&my_charset_latin1, res[0]) == 'Y')
access_bits|= bit;
}
return access_bits;
@@ -484,16 +459,48 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/*
+ Prepare crypted scramble to be sent to the client
+*/
+
+void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble)
+{
+ /* Binary password format to be used for generation*/
+ char bin_password[SCRAMBLE41_LENGTH];
+ /* Generate new long scramble for the thread */
+ create_random_string(SCRAMBLE41_LENGTH,&thd->rand,thd->scramble);
+ thd->scramble[SCRAMBLE41_LENGTH]=0;
+ /* Get binary form, First 4 bytes of prepared scramble is salt */
+ get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble,
+ (unsigned char*) bin_password);
+ /* Store "*" as identifier for old passwords */
+ if (!acl_user->pversion)
+ prepared_scramble[0]='*';
+ /* Finally encrypt password to get prepared scramble */
+ password_crypt(thd->scramble, prepared_scramble+4, bin_password,
+ SCRAMBLE41_LENGTH);
+}
+
+
+/*
Get master privilges for user (priviliges for all tables).
Required before connecting to MySQL
+
+ As we have 2 stage handshake now we cache user not to lookup
+ it second time. At the second stage we do not lookup user in case
+ we already know it;
+
*/
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
- bool old_ver, USER_RESOURCES *mqh)
+ bool old_ver, USER_RESOURCES *mqh, char *prepared_scramble,
+ uint *cur_priv_version, ACL_USER **cached_user)
{
ulong user_access=NO_ACCESS;
- *priv_user=(char*) user;
+ *priv_user= (char*) user;
+ bool password_correct= 0;
+ int stage= (*cached_user != NULL); /* NULL passed as first stage */
+ ACL_USER *acl_user= NULL;
DBUG_ENTER("acl_getroot");
bzero(mqh,sizeof(USER_RESOURCES));
@@ -507,123 +514,172 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
/*
Get possible access from user_list. This is or'ed to others not
fully specified
+
+ If we have cached user use it, in other case look it up.
*/
- for (uint i=0 ; i < acl_users.elements ; i++)
+
+ if (stage && (*cur_priv_version == priv_version))
+ acl_user= *cached_user;
+ else
{
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user->user || !strcmp(user,acl_user->user))
+ for (uint i=0 ; i < acl_users.elements ; i++)
{
- if (compare_hostname(&acl_user->host,host,ip))
+ ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*);
+ if (!acl_user_search->user || !strcmp(user,acl_user_search->user))
+ {
+ if (compare_hostname(&acl_user_search->host,host,ip))
+ {
+ /* Found mathing user */
+ acl_user= acl_user_search;
+ /* Store it as a cache */
+ *cached_user= acl_user;
+ *cur_priv_version= priv_version;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Now we have acl_user found and may start our checks */
+
+ if (acl_user)
+ {
+ /* Password should present for both or absend for both */
+ if (!acl_user->password && !*password)
+ password_correct=1;
+ else if (!acl_user->password || !*password)
+ {
+ *cached_user= 0; // Impossible to connect
+ }
+ else
+ {
+ /* New version password is checked differently */
+ if (acl_user->pversion)
+ {
+ if (stage) /* We check password only on the second stage */
+ {
+ if (!validate_password(password,message,acl_user->salt))
+ password_correct=1;
+ }
+ else /* First stage - just prepare scramble */
+ prepare_scramble(thd,acl_user,prepared_scramble);
+ }
+ /* Old way to check password */
+ else
{
- if (!acl_user->password && !*password ||
- (acl_user->password && *password &&
- !check_scramble(password,message,acl_user->salt,
- (my_bool) old_ver)))
+ /* Checking the scramble at any stage. First - old clients */
+ if (!check_scramble(password,message,acl_user->salt,
+ (my_bool) old_ver))
+ password_correct=1;
+ else if (!stage) /* Here if password incorrect */
{
+ /* At the first stage - prepare scramble */
+ prepare_scramble(thd,acl_user,prepared_scramble);
+ }
+ }
+ }
+ }
+
+ /* If user not found password_correct will also be zero */
+ if (!password_correct)
+ goto unlock_and_exit;
+
+ /* OK. User found and password checked continue validation */
+
#ifdef HAVE_OPENSSL
- Vio *vio=thd->net.vio;
- /*
- In this point we know that user is allowed to connect
- from given host by given username/password pair. Now
- we check if SSL is required, if user is using SSL and
- if X509 certificate attributes are OK
- */
- switch (acl_user->ssl_type) {
- case SSL_TYPE_NOT_SPECIFIED: // Impossible
- case SSL_TYPE_NONE: /* SSL is not required to connect */
- user_access=acl_user->access;
- break;
- case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
- if (vio_type(vio) == VIO_TYPE_SSL)
- user_access=acl_user->access;
- break;
- case SSL_TYPE_X509: /* Client should have any valid certificate. */
- /*
- Connections with non-valid certificates are dropped already
- in sslaccept() anyway, so we do not check validity here.
- */
- if (SSL_get_peer_certificate(vio->ssl_))
- user_access=acl_user->access;
- break;
- case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
- /*
- We do not check for absence of SSL because without SSL it does
- not pass all checks here anyway.
- If cipher name is specified, we compare it to actual cipher in
- use.
- */
- if (acl_user->ssl_cipher)
- {
- DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,
- SSL_get_cipher(vio->ssl_)));
- if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
- user_access=acl_user->access;
- else
- {
- user_access=NO_ACCESS;
- break;
- }
- }
- /* Prepare certificate (if exists) */
- DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(vio->ssl_);
- DBUG_PRINT("info",("checkpoint 2"));
- /* If X509 issuer is speified, we check it... */
- if (acl_user->x509_issuer)
- {
- DBUG_PRINT("info",("checkpoint 3"));
- char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
- acl_user->x509_issuer, ptr));
- if (strcmp(acl_user->x509_issuer, ptr))
- {
- user_access=NO_ACCESS;
- free(ptr);
- break;
- }
- user_access=acl_user->access;
- free(ptr);
- }
- DBUG_PRINT("info",("checkpoint 4"));
- /* X509 subject is specified, we check it .. */
- if (acl_user->x509_subject)
- {
- char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
- acl_user->x509_subject, ptr));
- if (strcmp(acl_user->x509_subject,ptr))
- user_access=NO_ACCESS;
- else
- user_access=acl_user->access;
- free(ptr);
- }
- break;
- }
-#else /* HAVE_OPENSSL */
+ {
+ Vio *vio=thd->net.vio;
+ /*
+ In this point we know that user is allowed to connect
+ from given host by given username/password pair. Now
+ we check if SSL is required, if user is using SSL and
+ if X509 certificate attributes are OK
+ */
+ switch (acl_user->ssl_type) {
+ case SSL_TYPE_NOT_SPECIFIED: // Impossible
+ case SSL_TYPE_NONE: /* SSL is not required to connect */
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ if (vio_type(vio) == VIO_TYPE_SSL)
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_X509: /* Client should have any valid certificate. */
+ /*
+ Connections with non-valid certificates are dropped already
+ in sslaccept() anyway, so we do not check validity here.
+ */
+ if (SSL_get_peer_certificate(vio->ssl_))
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ /*
+ We do not check for absence of SSL because without SSL it does
+ not pass all checks here anyway.
+ If cipher name is specified, we compare it to actual cipher in
+ use.
+ */
+ if (acl_user->ssl_cipher)
+ {
+ DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
+ if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
user_access=acl_user->access;
-#endif /* HAVE_OPENSSL */
- *mqh=acl_user->user_resource;
- if (!acl_user->user)
- *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+ else
+ {
+ user_access=NO_ACCESS;
break;
}
-#ifndef ALLOW_DOWNGRADE_OF_USERS
- break; // Wrong password breaks loop /* purecov: inspected */
-#endif
}
+ /* Prepare certificate (if exists) */
+ DBUG_PRINT("info",("checkpoint 1"));
+ X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ DBUG_PRINT("info",("checkpoint 2"));
+ /* If X509 issuer is speified, we check it... */
+ if (acl_user->x509_issuer)
+ {
+ DBUG_PRINT("info",("checkpoint 3"));
+ char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
+ acl_user->x509_issuer, ptr));
+ if (strcmp(acl_user->x509_issuer, ptr))
+ {
+ user_access=NO_ACCESS;
+ free(ptr);
+ break;
+ }
+ user_access=acl_user->access;
+ free(ptr);
+ }
+ DBUG_PRINT("info",("checkpoint 4"));
+ /* X509 subject is specified, we check it .. */
+ if (acl_user->x509_subject)
+ {
+ char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
+ acl_user->x509_subject, ptr));
+ if (strcmp(acl_user->x509_subject,ptr))
+ user_access=NO_ACCESS;
+ else
+ user_access=acl_user->access;
+ free(ptr);
+ }
+ break;
}
}
+#else /* HAVE_OPENSSL */
+ user_access=acl_user->access;
+#endif /* HAVE_OPENSSL */
+ *mqh=acl_user->user_resource;
+ if (!acl_user->user)
+ *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+
+unlock_and_exit:
VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(user_access);
}
-/*
-** Functions to add and change user and database privileges when one
-** changes things with GRANT
-*/
-
static byte* check_get_key(ACL_USER *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
@@ -632,12 +688,12 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
}
static void acl_update_user(const char *user, const char *host,
- const char *password,
+ const char *password,
enum SSL_type ssl_type,
const char *ssl_cipher,
const char *x509_issuer,
const char *x509_subject,
- USER_RESOURCES *mqh,
+ USER_RESOURCES *mqh,
ulong privileges)
{
for (uint i=0 ; i < acl_users.elements ; i++)
@@ -649,7 +705,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(&my_charset_latin1, host, acl_user->host.hostname))
{
acl_user->access=privileges;
if (mqh->bits & 1)
@@ -670,12 +726,16 @@ static void acl_update_user(const char *user, const char *host,
}
if (password)
{
- if (!password[0])
+ if (!password[0]) /* If password is empty set it to null */
+ {
acl_user->password=0;
+ acl_user->pversion=0; // just initialize
+ }
else
{
acl_user->password=(char*) ""; // Just point at something
get_salt_from_password(acl_user->salt,password);
+ acl_user->pversion=get_password_version(acl_user->password);
}
}
break;
@@ -686,7 +746,7 @@ static void acl_update_user(const char *user, const char *host,
static void acl_insert_user(const char *user, const char *host,
- const char *password,
+ const char *password,
enum SSL_type ssl_type,
const char *ssl_cipher,
const char *x509_issuer,
@@ -711,6 +771,7 @@ static void acl_insert_user(const char *user, const char *host,
{
acl_user.password=(char*) ""; // Just point at something
get_salt_from_password(acl_user.salt,password);
+ acl_user.pversion=get_password_version(password);
}
VOID(push_dynamic(&acl_users,(gptr) &acl_user));
@@ -738,7 +799,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(&my_charset_latin1, host, acl_db->host.hostname))
{
if (!acl_db->db && !db[0] ||
acl_db->db && !strcmp(db,acl_db->db))
@@ -802,7 +864,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(&my_charset_latin1, tmp_db);
db=tmp_db;
}
key_length=(uint) (end-key);
@@ -866,7 +928,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 +939,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 +958,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 +982,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,&my_charset_latin1,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,HASH_CASE_INSENSITIVE));
if (!allow_all_hosts)
{
@@ -935,7 +998,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(&my_charset_latin1,
+ acl_user->host.hostname, acl->hostname))
break; // already stored
}
if (j == acl_wild_hosts.elements) // If new
@@ -1008,19 +1072,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(&my_charset_latin1, 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);
@@ -1040,7 +1104,7 @@ bool check_change_password(THD *thd, const char *host, const char *user)
RETURN VALUES
0 ok
1 ERROR; In this case the error is sent to the client.
-*/
+*/
bool change_password(THD *thd, const char *host, const char *user,
char *new_password)
@@ -1054,15 +1118,20 @@ bool change_password(THD *thd, const char *host, const char *user,
if (check_change_password(thd, host, user))
DBUG_RETURN(1);
- /* password should always be 0 or 16 chars; simple hack to avoid cracking */
+ /*
+ password should always be 0,16 or 45 chars;
+ Simple hack to avoid cracking
+ */
length=(uint) strlen(new_password);
- new_password[length & 16]=0;
+
+ if (length!=45)
+ new_password[length & 16]=0;
VOID(pthread_mutex_lock(&acl_cache->lock));
ACL_USER *acl_user;
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,18 +1141,20 @@ 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);
+ acl_user->pversion=get_password_version(new_password);
if (!new_password[0])
acl_user->password=0;
else
acl_user->password=(char*) ""; // Point at something
+
acl_cache->clear(1); // Clear locked hostname cache
VOID(pthread_mutex_unlock(&acl_cache->lock));
- char buff[460];
+ char buff[512]; /* Extend with extended password length*/
ulong query_length=
my_sprintf(buff,
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
@@ -1173,7 +1244,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(&my_charset_latin1,
+ hostname,host->hostname)) ||
(ip && !wild_compare(ip,host->hostname)));
}
@@ -1196,8 +1268,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), &my_charset_latin1);
+ table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1);
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,0,
@@ -1207,7 +1279,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), &my_charset_latin1);
if ((error=table->file->update_row(table->record[1],table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
@@ -1265,7 +1337,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (combo.password.str && combo.password.str[0])
{
- if (combo.password.length != HASH_PASSWORD_LENGTH)
+ if ((combo.password.length != HASH_PASSWORD_LENGTH)
+ && combo.password.length != HASH_OLD_PASSWORD_LENGTH)
{
my_printf_error(ER_PASSWORD_NO_MATCH,
"Password hash should be a %d-digit hexadecimal number",
@@ -1275,8 +1348,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, &my_charset_latin1);
+ table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->file->index_init(0);
if (table->file->index_read(table->record[0],
(byte*) table->field[0]->ptr,0,
@@ -1296,17 +1369,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, &my_charset_latin1);
+ table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
}
else
{
old_row_exists = 1;
store_record(table,1); // Save copy for update
if (combo.password.str) // If password given
- table->field[2]->store(password,(uint) strlen(password));
+ table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
}
/* Update table columns with new privileges */
@@ -1319,7 +1392,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, &my_charset_latin1);
}
rights=get_access(table,3);
DBUG_PRINT("info",("table->fields: %d",table->fields));
@@ -1328,39 +1401,39 @@ 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, &my_charset_latin1);
+ table->field[25]->store("", 0, &my_charset_latin1);
+ table->field[26]->store("", 0, &my_charset_latin1);
+ table->field[27]->store("", 0, &my_charset_latin1);
break;
case SSL_TYPE_X509:
- table->field[24]->store("X509",4);
- table->field[25]->store("",0);
- table->field[26]->store("",0);
- table->field[27]->store("",0);
+ table->field[24]->store("X509",4, &my_charset_latin1);
+ table->field[25]->store("", 0, &my_charset_latin1);
+ table->field[26]->store("", 0, &my_charset_latin1);
+ table->field[27]->store("", 0, &my_charset_latin1);
break;
case SSL_TYPE_SPECIFIED:
- table->field[24]->store("SPECIFIED",9);
- table->field[25]->store("",0);
- table->field[26]->store("",0);
- table->field[27]->store("",0);
+ table->field[24]->store("SPECIFIED",9, &my_charset_latin1);
+ table->field[25]->store("", 0, &my_charset_latin1);
+ table->field[26]->store("", 0, &my_charset_latin1);
+ table->field[27]->store("", 0, &my_charset_latin1);
if (thd->lex.ssl_cipher)
table->field[25]->store(thd->lex.ssl_cipher,
- strlen(thd->lex.ssl_cipher));
+ strlen(thd->lex.ssl_cipher), &my_charset_latin1);
if (thd->lex.x509_issuer)
table->field[26]->store(thd->lex.x509_issuer,
- strlen(thd->lex.x509_issuer));
+ strlen(thd->lex.x509_issuer), &my_charset_latin1);
if (thd->lex.x509_subject)
table->field[27]->store(thd->lex.x509_subject,
- strlen(thd->lex.x509_subject));
+ strlen(thd->lex.x509_subject), &my_charset_latin1);
break;
case SSL_TYPE_NOT_SPECIFIED:
break;
case SSL_TYPE_NONE:
- table->field[24]->store("",0);
- table->field[25]->store("",0);
- table->field[26]->store("",0);
- table->field[27]->store("",0);
+ table->field[24]->store("", 0, &my_charset_latin1);
+ table->field[25]->store("", 0, &my_charset_latin1);
+ table->field[26]->store("", 0, &my_charset_latin1);
+ table->field[27]->store("", 0, &my_charset_latin1);
break;
}
@@ -1449,9 +1522,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, &my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->file->index_init(0);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
HA_READ_KEY_EXACT))
@@ -1464,9 +1537,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, &my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
}
else
{
@@ -1478,7 +1551,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, &my_charset_latin1);// set requested privileges
}
rights=get_access(table,3);
rights=fix_rights_for_db(rights);
@@ -1559,13 +1632,14 @@ public:
tname= strdup_root(&memex,t);
if (lower_case_table_names)
{
- casedn_str(db);
- casedn_str(tname);
+ my_casedn_str(&my_charset_latin1, db);
+ my_casedn_str(&my_charset_latin1, tname);
}
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
- (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
+ (void) hash_init(&hash_columns,&my_charset_latin1,
+ 0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
}
@@ -1573,12 +1647,12 @@ public:
{
byte key[MAX_KEY_LENGTH];
- host = get_field(&memex,form,0);
- db = get_field(&memex,form,1);
- user = get_field(&memex,form,2);
+ host = get_field(&memex,form->field[0]);
+ db = get_field(&memex,form->field[1]);
+ user = get_field(&memex,form->field[2]);
if (!user)
user=(char*) "";
- tname = get_field(&memex,form,3);
+ tname = get_field(&memex,form->field[3]);
if (!host || !db || !tname)
{
/* Wrong table row; Ignore it */
@@ -1587,8 +1661,8 @@ public:
}
if (lower_case_table_names)
{
- casedn_str(db);
- casedn_str(tname);
+ my_casedn_str(&my_charset_latin1, db);
+ my_casedn_str(&my_charset_latin1, tname);
}
key_length = ((uint) strlen(db) + (uint) strlen(user) +
(uint) strlen(tname) + 3);
@@ -1599,21 +1673,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,&my_charset_latin1,
+ 0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
if (cols)
{
int key_len;
- col_privs->field[0]->store(host,(uint) strlen(host));
- 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), &my_charset_latin1);
+ col_privs->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
+ col_privs->field[2]->store(user,(uint) strlen(user), &my_charset_latin1);
+ col_privs->field[3]->store(tname,(uint) strlen(tname), &my_charset_latin1);
key_len=(col_privs->field[0]->pack_length()+
col_privs->field[1]->pack_length()+
col_privs->field[2]->pack_length()+
col_privs->field[3]->pack_length());
key_copy(key,col_privs,0,key_len);
- col_privs->field[4]->store("",0);
+ col_privs->field[4]->store("",0, &my_charset_latin1);
col_privs->file->index_init(0);
if (col_privs->file->index_read(col_privs->record[0],
(byte*) col_privs->field[0]->ptr,
@@ -1669,24 +1744,28 @@ 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,
+ for (grant_table=(GRANT_TABLE*) hash_search(&column_priv_hash,
+ (byte*) helping,
len) ;
grant_table ;
- grant_table= (GRANT_TABLE*) hash_next(&hash_tables,(byte*) helping,len))
+ grant_table= (GRANT_TABLE*) hash_next(&column_priv_hash,(byte*) helping,
+ len))
{
if (exact)
{
- if ((host && !my_strcasecmp(host,grant_table->host)) ||
+ if ((host &&
+ !my_strcasecmp(&my_charset_latin1, host, grant_table->host)) ||
(ip && !strcmp(ip,grant_table->host)))
return grant_table;
}
else
{
- if ((host && !wild_case_compare(host,grant_table->host)) ||
- (ip && !wild_case_compare(ip,grant_table->host)))
+ if ((host && !wild_case_compare(&my_charset_latin1,
+ host,grant_table->host)) ||
+ (ip && !wild_case_compare(&my_charset_latin1,
+ ip,grant_table->host)))
found=grant_table; // Host ok
}
}
@@ -1713,10 +1792,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, &my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+
table->field[2]->pack_length()+ table->field[3]->pack_length());
key_copy(key,table,0,key_length);
@@ -1733,7 +1812,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(),&my_charset_latin1);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
@@ -1747,9 +1826,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(), &my_charset_latin1);
}
else
{
@@ -1821,7 +1900,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),&my_charset_latin1);
privileges&= ~rights;
table->field[6]->store((longlong)
@@ -1877,7 +1956,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);
@@ -1892,10 +1970,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, &my_charset_latin1);
+ table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
+ table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+ table->field[3]->store(table_name,(uint) strlen(table_name), &my_charset_latin1);
store_record(table,1); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
@@ -1940,7 +2018,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), &my_charset_latin1);
table->field[6]->store((longlong) store_table_rights);
table->field[7]->store((longlong) store_col_rights);
rights=fix_rights_for_table(store_table_rights);
@@ -1970,7 +2048,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
else
{
- hash_delete(&hash_tables,(byte*) grant_table);
+ hash_delete(&column_priv_hash,(byte*) grant_table);
}
DBUG_RETURN(0);
@@ -1995,7 +2073,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)
@@ -2061,7 +2139,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);
@@ -2116,7 +2194,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
result= -1; /* purecov: deadcode */
continue; /* purecov: deadcode */
}
- hash_insert(&hash_tables,(byte*) grant_table);
+ hash_insert(&column_priv_hash,(byte*) grant_table);
}
/* If revoke_grant, calculate the new column privilege for tables_priv */
@@ -2174,9 +2252,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);
}
@@ -2191,17 +2269,16 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
bool create_new_users=0;
TABLE_LIST tables[2];
DBUG_ENTER("mysql_grant");
-
if (!initialized)
{
- send_error(&(thd->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(&my_charset_latin1, tmp_db);
db=tmp_db;
}
@@ -2224,7 +2301,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++;
@@ -2257,11 +2334,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);
}
@@ -2272,7 +2349,7 @@ void grant_free(void)
{
DBUG_ENTER("grant_free");
grant_option = FALSE;
- hash_free(&hash_tables);
+ hash_free(&column_priv_hash);
free_root(&memex,MYF(0));
DBUG_VOID_RETURN;
}
@@ -2290,7 +2367,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(&column_priv_hash,&my_charset_latin1,
+ 0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
init_sql_alloc(&memex,1024,0);
@@ -2336,7 +2414,7 @@ my_bool grant_init(THD *org_thd)
{
GRANT_TABLE *mem_check;
if (!(mem_check=new GRANT_TABLE(t_table,c_table)) ||
- mem_check->ok() && hash_insert(&hash_tables,(byte*) mem_check))
+ mem_check->ok() && hash_insert(&column_priv_hash,(byte*) mem_check))
{
/* This could only happen if we are out memory */
grant_option = FALSE; /* purecov: deadcode */
@@ -2365,35 +2443,37 @@ end:
}
-/* Reload grant array if possible */
+/* Reload grant array (table and column privileges) if possible */
void grant_reload(THD *thd)
{
- HASH old_hash_tables;bool old_grant_option;
+ HASH old_column_priv_hash;
+ bool old_grant_option;
MEM_ROOT old_mem;
DBUG_ENTER("grant_reload");
// 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_column_priv_hash= column_priv_hash;
old_grant_option = grant_option;
old_mem = memex;
if (grant_init(thd))
{ // Error. Revert to old hash
+ DBUG_PRINT("error",("Reverting to old privileges"));
grant_free(); /* purecov: deadcode */
- hash_tables=old_hash_tables; /* purecov: deadcode */
+ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
grant_option = old_grant_option; /* purecov: deadcode */
memex = old_mem; /* purecov: deadcode */
}
else
{
- hash_free(&old_hash_tables);
+ hash_free(&old_column_priv_hash);
free_root(&old_mem,MYF(0));
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
DBUG_VOID_RETURN;
}
@@ -2413,7 +2493,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))
@@ -2447,11 +2527,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="";
@@ -2473,7 +2553,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,
@@ -2493,7 +2573,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
@@ -2511,20 +2591,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];
@@ -2552,7 +2632,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
@@ -2575,12 +2655,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)
@@ -2612,21 +2692,24 @@ 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++)
+ for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
{
- GRANT_TABLE *grant_table = (GRANT_TABLE*) hash_element(&hash_tables,idx);
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ 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(&my_charset_latin1,
+ thd->host,grant_table->host) ||
+ (thd->ip && !wild_case_compare(&my_charset_latin1,
+ thd->ip,grant_table->host))))
{
error=0; // Found match
break;
}
}
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return error;
}
@@ -2636,20 +2719,24 @@ 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);
+#ifdef EMBEDDED_LIBRARY
+ grant_table= NULL;
+#else
grant_table = table_hash_search(thd->host,thd->ip,db,user,
table->real_name,0);
+#endif
table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version;
if (grant_table)
table->grant.privilege|= grant_table->privs;
privilege= table->grant.privilege;
- pthread_mutex_unlock(&LOCK_grant);
+ rw_unlock(&LOCK_grant);
return privilege;
}
@@ -2660,7 +2747,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)
{
@@ -2682,7 +2769,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;
}
@@ -2705,19 +2792,20 @@ static uint command_lengths[]=
};
-int mysql_show_grants(THD *thd,LEX_USER *lex_user)
+int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
ulong want_access;
uint counter,index;
int error = 0;
ACL_USER *acl_user; ACL_DB *acl_db;
char buff[1024];
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysql_show_grants");
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)
@@ -2741,33 +2829,33 @@ 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(&my_charset_latin1, lex_user->host.str, host))
break;
}
- if (counter == acl_users.elements)
+ if (counter == acl_users.elements)
{
my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
MYF(0),lex_user->user.str,lex_user->host.str);
DBUG_RETURN(-1);
}
- Item_string *field=new Item_string("",0);
+ Item_string *field=new Item_string("",0,&my_charset_latin1);
List<Item> field_list;
field->name=buff;
field->max_length=1024;
strxmov(buff,"Grants for ",lex_user->user.str,"@",
lex_user->host.str,NullS);
field_list.push_back(field);
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&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 */
{
want_access=acl_user->access;
- String global(buff,sizeof(buff));
+ String global(buff,sizeof(buff),&my_charset_latin1);
global.length(0);
global.append("GRANT ",6);
@@ -2775,13 +2863,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append("ALL PRIVILEGES",14);
else if (!(want_access & ~GRANT_ACL))
global.append("USAGE",5);
- else
+ else
{
bool found=0;
ulong j,test_access= want_access & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
{
- if (test_access & j)
+ if (test_access & j)
{
if (found)
global.append(", ",2);
@@ -2791,14 +2879,14 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
global.append (" ON *.* TO '",12);
- global.append(lex_user->user.str,lex_user->user.length);
+ global.append(lex_user->user.str,lex_user->user.length);
global.append ("'@'",3);
global.append(lex_user->host.str,lex_user->host.length);
global.append ('\'');
if (acl_user->password)
{
char passd_buff[HASH_PASSWORD_LENGTH+1];
- make_password_from_salt(passd_buff,acl_user->salt);
+ make_password_from_salt(passd_buff,acl_user->salt,acl_user->pversion);
global.append(" IDENTIFIED BY PASSWORD '",25);
global.append(passd_buff);
global.append('\'');
@@ -2840,9 +2928,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
(acl_user->user_resource.questions | acl_user->user_resource.updates |
acl_user->user_resource.connections))
{
- global.append(" WITH",5);
+ global.append(" WITH",5);
if (want_access & GRANT_ACL)
- global.append(" GRANT OPTION",13);
+ global.append(" GRANT OPTION",13);
if (acl_user->user_resource.questions)
{
char buff[22], *p; // just as in int2str
@@ -2865,12 +2953,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(buff,p-buff);
}
}
- thd->packet.length(0);
- net_store_data(&thd->packet,global.ptr(),global.length());
- if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
- thd->packet.length()))
+ protocol->prepare_for_resend();
+ protocol->store(global.ptr(),global.length(),global.charset());
+ if (protocol->write())
{
- error=-1; goto end;
+ error=-1;
+ goto end;
}
}
@@ -2886,12 +2974,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(&my_charset_latin1, lex_user->host.str, host))
{
want_access=acl_db->access;
- if (want_access)
+ if (want_access)
{
- String db(buff,sizeof(buff));
+ String db(buff,sizeof(buff),&my_charset_latin1);
db.length(0);
db.append("GRANT ",6);
@@ -2917,16 +3005,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
db.append (" ON `",5);
db.append(acl_db->db);
db.append ("`.* TO '",8);
- db.append(lex_user->user.str,lex_user->user.length);
+ db.append(lex_user->user.str,lex_user->user.length);
db.append ("'@'",3);
db.append(lex_user->host.str, lex_user->host.length);
- db.append ('\'');
+ db.append ('\'');
if (want_access & GRANT_ACL)
db.append(" WITH GRANT OPTION",18);
- thd->packet.length(0);
- net_store_data(&thd->packet,db.ptr(),db.length());
- if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
- thd->packet.length()))
+ protocol->prepare_for_resend();
+ protocol->store(db.ptr(),db.length(),db.charset());
+ if (protocol->write())
{
error=-1;
goto end;
@@ -2936,10 +3023,11 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
/* Add column access */
- for (index=0 ; index < hash_tables.records ; index++)
+ for (index=0 ; index < column_priv_hash.records ; index++)
{
const char *user,*host;
- GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index);
+ GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
+ index);
if (!(user=grant_table->user))
user="";
@@ -2947,32 +3035,32 @@ 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(&my_charset_latin1, lex_user->host.str, host))
{
want_access=grant_table->privs;
if ((want_access | grant_table->cols) != 0)
{
- String global(buff,sizeof(buff));
+ String global(buff,sizeof(buff),&my_charset_latin1);
global.length(0);
global.append("GRANT ",6);
if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14);
- else
+ else
{
int found=0;
ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1)
{
- if (test_access & j)
+ if (test_access & j)
{
if (found)
global.append(", ",2);
found = 1;
global.append(command_array[counter],command_lengths[counter]);
- if (grant_table->cols)
+ if (grant_table->cols)
{
uint found_col=0;
for (uint col_index=0 ;
@@ -2981,9 +3069,9 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
hash_element(&grant_table->hash_columns,col_index);
- if (grant_column->rights & j)
+ if (grant_column->rights & j)
{
- if (!found_col)
+ if (!found_col)
{
global.append(" (",2);
found_col=1;
@@ -3005,29 +3093,27 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(".",1);
global.append(grant_table->tname);
global.append(" TO '",5);
- global.append(lex_user->user.str,lex_user->user.length);
+ global.append(lex_user->user.str,lex_user->user.length);
global.append("'@'",3);
- global.append(lex_user->host.str,lex_user->host.length);
+ global.append(lex_user->host.str,lex_user->host.length);
global.append('\'');
if (want_access & GRANT_ACL)
- global.append(" WITH GRANT OPTION",18);
- thd->packet.length(0);
- net_store_data(&thd->packet,global.ptr(),global.length());
- if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
- thd->packet.length()))
+ global.append(" WITH GRANT OPTION",18);
+ protocol->prepare_for_resend();
+ protocol->store(global.ptr(),global.length(),global.charset());
+ if (protocol->write())
{
- 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_acl.h b/sql/sql_acl.h
index 6925b6b406c..ceb866d809f 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -79,6 +79,55 @@
#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7))
#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7))
+/* Classes */
+
+struct acl_host_and_ip
+{
+ char *hostname;
+ long ip,ip_mask; // Used with masked ip:s
+};
+
+
+class ACL_ACCESS {
+public:
+ ulong sort;
+ ulong access;
+};
+
+
+/* ACL_HOST is used if no host is specified */
+
+class ACL_HOST :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *db;
+};
+
+
+class ACL_USER :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ uint hostname_length;
+ USER_RESOURCES user_resource;
+ char *user,*password;
+ ulong salt[6]; // New password has longer length
+ uint8 pversion; // password version
+ enum SSL_type ssl_type;
+ const char *ssl_cipher, *x509_issuer, *x509_subject;
+};
+
+
+class ACL_DB :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *user,*db;
+};
+
+
+
/* prototypes */
my_bool acl_init(THD *thd, bool dont_read_acl_tables);
@@ -88,7 +137,8 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db);
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user,
- bool old_ver, USER_RESOURCES *max);
+ bool old_ver, USER_RESOURCES *max,char* prepared_scramble,
+ uint *cur_priv_version, ACL_USER **cached_user);
bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user);
bool change_password(THD *thd, const char *host, const char *user,
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 5d3f9a0595c..9bcfff62ba0 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -41,13 +41,13 @@
int sortcmp2(void* cmp_arg __attribute__((unused)),
const String *a,const String *b)
{
- return sortcmp(a,b);
+ return sortcmp(a,b,a->charset());
}
int stringcmp2(void* cmp_arg __attribute__((unused)),
const String *a,const String *b)
{
- return stringcmp(a,b);
+ return sortcmp(a,b,&my_charset_bin);
}
int compare_double2(void* cmp_arg __attribute__((unused)),
@@ -90,15 +90,14 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
(*param->item)->val() < 0)
{
delete pc;
- net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
pc->max_tree_elements = (uint) (*param->item)->val_int();
param = param->next;
if (param->next) // no third parameter possible
{
- delete pc;
- net_printf(&thd->net, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMCOUNT_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
// second parameter
@@ -106,7 +105,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
(*param->item)->val() < 0)
{
delete pc;
- net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
pc->max_treemem = (uint) (*param->item)->val_int();
@@ -115,7 +114,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
(*param->item)->val() < 0)
{
delete pc;
- net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name);
+ my_error(ER_WRONG_PARAMETERS_TO_PROCEDURE, MYF(0), proc_name);
DBUG_RETURN(0);
}
// if only one parameter was given, it will be the value of max_tree_elements
@@ -172,7 +171,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;
@@ -185,10 +184,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++;
}
@@ -214,7 +213,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
@@ -229,7 +228,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)
{
@@ -282,7 +281,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),&my_charset_bin), *res;
ulong length;
TREE_ELEMENT *element;
@@ -318,6 +317,7 @@ void field_str::add()
was_maybe_zerofill = num_info.maybe_zerofill;
}
+ /* Update min and max arguments */
if (!found)
{
found = 1;
@@ -333,30 +333,20 @@ void field_str::add()
if (length > max_length)
max_length = length;
- if (item->binary)
- {
- if (stringcmp(res, &min_arg) < 0)
- min_arg.copy(*res);
- if (stringcmp(res, &max_arg) > 0)
- max_arg.copy(*res);
- }
- else
- {
- if (sortcmp(res, &min_arg) < 0)
- min_arg.copy(*res);
- if (sortcmp(res, &max_arg) > 0)
- max_arg.copy(*res);
- }
+ if (sortcmp(res, &min_arg,item->charset()) < 0)
+ min_arg.copy(*res);
+ if (sortcmp(res, &max_arg,item->charset()) > 0)
+ max_arg.copy(*res);
}
if (room_in_tree)
{
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);
@@ -396,8 +386,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;
}
@@ -406,12 +395,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;
@@ -425,7 +413,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);
@@ -481,7 +469,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);
@@ -537,7 +525,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);
@@ -594,8 +582,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),&my_charset_bin),
+ s_max(buff, sizeof(buff),&my_charset_bin),
+ ans(buff, sizeof(buff),&my_charset_bin);
for (; f != f_end; f++)
{
@@ -609,23 +598,23 @@ bool analyse::end_of_records()
{
func_items[1]->null_value = 0;
res = (*f)->get_min_arg(&s_min);
- func_items[1]->set(res->ptr(), res->length());
+ func_items[1]->set(res->ptr(), res->length(), res->charset());
func_items[2]->null_value = 0;
res = (*f)->get_max_arg(&s_max);
- func_items[2]->set(res->ptr(), res->length());
+ func_items[2]->set(res->ptr(), res->length(), res->charset());
}
func_items[3]->set((longlong) (*f)->min_length);
func_items[4]->set((longlong) (*f)->max_length);
func_items[5]->set((longlong) (*f)->empty);
func_items[6]->set((longlong) (*f)->nulls);
res = (*f)->avg(&s_max, rows);
- func_items[7]->set(res->ptr(), res->length());
+ func_items[7]->set(res->ptr(), res->length(), res->charset());
func_items[8]->null_value = 0;
res = (*f)->std(&s_max, rows);
if (!res)
func_items[8]->null_value = 1;
else
- func_items[8]->set(res->ptr(), res->length());
+ func_items[8]->set(res->ptr(), res->length(), res->charset());
/*
count the dots, quotas, etc. in (ENUM("a","b","c"...))
If tree has been removed, don't suggest ENUM.
@@ -643,14 +632,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),&my_charset_bin);
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,&my_charset_bin);
tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
left_root_right);
tmp_str.append(')');
@@ -658,7 +647,7 @@ bool analyse::end_of_records()
if (!(*f)->nulls)
tmp_str.append(" NOT NULL");
output_str_length = tmp_str.length();
- func_items[9]->set(tmp_str.ptr(), tmp_str.length());
+ func_items[9]->set(tmp_str.ptr(), tmp_str.length(), tmp_str.charset());
if (result->send_data(result_fields))
return -1;
continue;
@@ -703,7 +692,7 @@ bool analyse::end_of_records()
}
if (!(*f)->nulls)
ans.append(" NOT NULL");
- func_items[9]->set(ans.ptr(), ans.length());
+ func_items[9]->set(ans.ptr(), ans.length(), ans.charset());
if (result->send_data(result_fields))
return -1;
}
@@ -754,7 +743,7 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows)
{
if (must_be_blob)
{
- if (item->binary)
+ if (item->charset() == &my_charset_bin)
answer->append("TINYBLOB", 8);
else
answer->append("TINYTEXT", 8);
@@ -772,21 +761,21 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows)
}
else if (max_length < (1L << 16))
{
- if (item->binary)
+ if (item->charset() == &my_charset_bin)
answer->append("BLOB", 4);
else
answer->append("TEXT", 4);
}
else if (max_length < (1L << 24))
{
- if (item->binary)
+ if (item->charset() == &my_charset_bin)
answer->append("MEDIUMBLOB", 10);
else
answer->append("MEDIUMTEXT", 10);
}
else
{
- if (item->binary)
+ if (item->charset() == &my_charset_bin)
answer->append("LONGBLOB", 8);
else
answer->append("LONGTEXT", 8);
@@ -912,14 +901,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->variables.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->variables.thd_charset);
info->str->append(s);
info->str->append('\'');
return 0;
@@ -931,14 +920,14 @@ int collect_longlong(longlong *element,
TREE_INFO *info)
{
char buff[MAX_FIELD_WIDTH];
- String s(buff, sizeof(buff));
+ String s(buff, sizeof(buff),&my_charset_bin);
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
- s.set(*element);
+ s.set(*element, current_thd->variables.thd_charset);
info->str->append(s);
info->str->append('\'');
return 0;
@@ -950,14 +939,14 @@ int collect_ulonglong(ulonglong *element,
TREE_INFO *info)
{
char buff[MAX_FIELD_WIDTH];
- String s(buff, sizeof(buff));
+ String s(buff, sizeof(buff),&my_charset_bin);
if (info->found)
info->str->append(',');
else
info->found = 1;
info->str->append('\'');
- s.set(*element);
+ s.set(*element, current_thd->variables.thd_charset);
info->str->append(s);
info->str->append('\'');
return 0;
diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h
index aa6d0dbb2d1..2087e6b2b75 100644
--- a/sql/sql_analyse.h
+++ b/sql/sql_analyse.h
@@ -21,6 +21,8 @@
#pragma interface /* gcc class implementation */
#endif
+#define my_thd_charset default_charset_info
+
#define DEC_IN_AVG 4
typedef struct st_number_info
@@ -110,11 +112,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 +130,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 +162,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 +216,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 +260,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 e27ccf55543..2063e8b3f08 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -19,11 +19,11 @@
#include "mysql_priv.h"
#include "sql_acl.h"
+#include "sql_select.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
#include <nisam.h>
-#include <assert.h>
#ifdef __WIN__
#include <io.h>
#endif
@@ -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();
}
@@ -194,92 +195,6 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
DBUG_RETURN(open_list);
}
-
-/******************************************************************************
-** 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
-******************************************************************************/
-
-bool
-send_fields(THD *thd,List<Item> &list,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;
-
- 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;
- Send_field field;
- item->make_field(&field);
- packet->length(0);
-
- if (convert)
- {
- 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))
- {
- 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))
- goto err;
- }
- else if (net_store_data(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 */
- DBUG_RETURN(1); /* purecov: inspected */
-}
-
-
/*****************************************************************************
* Functions to free open table cache
****************************************************************************/
@@ -325,6 +240,7 @@ static void free_cache_entry(TABLE *table)
DBUG_VOID_RETURN;
}
+/* Free resources allocated by filesort() and read_record() */
void free_io_cache(TABLE *table)
{
@@ -391,7 +307,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
close_old_data_files(thd,thd->open_tables,1,1);
bool found=1;
/* Wait until all threads has closed all the tables we had locked */
- DBUG_PRINT("info", ("Waiting for others threads to close their open tables"));
+ DBUG_PRINT("info",
+ ("Waiting for others threads to close their open tables"));
while (found && ! thd->killed)
{
found=0;
@@ -432,12 +349,40 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
}
-/* Put all tables used by thread in free list */
+/*
+ Close all tables used by thread
+
+ SYNOPSIS
+ close_thread_tables()
+ thd Thread handler
+ lock_in_use Set to 1 (0 = default) if caller has a lock on
+ LOCK_open
+ skip_derived Set to 1 (0 = default) if we should not free derived
+ tables.
+
+ IMPLEMENTATION
+ Unlocks tables and frees derived tables.
+ Put all normal tables used by thread in free list.
+*/
-void close_thread_tables(THD *thd, bool locked)
+void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived)
{
DBUG_ENTER("close_thread_tables");
+ if (thd->derived_tables && !skip_derived)
+ {
+ TABLE *table, *next;
+ /*
+ Close all derived tables generated from questions like
+ SELECT * from (select * from t1))
+ */
+ for (table= thd->derived_tables ; table ; table= next)
+ {
+ next= table->next;
+ free_tmp_table(thd, table);
+ }
+ thd->derived_tables= 0;
+ }
if (thd->locked_tables)
{
ha_commit_stmt(thd); // If select statement
@@ -448,10 +393,11 @@ void close_thread_tables(THD *thd, bool locked)
if (thd->lock)
{
- mysql_unlock_tables(thd, thd->lock); thd->lock=0;
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock=0;
}
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->block_signals,NULL)); */
- if (!locked)
+ if (!lock_in_use)
VOID(pthread_mutex_lock(&LOCK_open));
safe_mutex_assert_owner(&LOCK_open);
@@ -470,7 +416,7 @@ void close_thread_tables(THD *thd, bool locked)
/* Tell threads waiting for refresh that something has happened */
VOID(pthread_cond_broadcast(&COND_refresh));
}
- if (!locked)
+ if (!lock_in_use)
VOID(pthread_mutex_unlock(&LOCK_open));
/* VOID(pthread_sigmask(SIG_SETMASK,&thd->signals,NULL)); */
DBUG_VOID_RETURN;
@@ -583,6 +529,54 @@ void close_temporary_tables(THD *thd)
thd->temporary_tables=0;
}
+/*
+ Find first suitable table by alias in given list.
+
+ SYNOPSIS
+ find_table_in_list()
+ table - pointer to table list
+ db_name - data base name or 0 for any
+ table_name - table name or 0 for any
+
+ RETURN VALUES
+ NULL Table not found
+ # Pointer to found table.
+*/
+
+TABLE_LIST * find_table_in_list(TABLE_LIST *table,
+ const char *db_name, const char *table_name)
+{
+ for (; table; table= table->next)
+ if ((!db_name || !strcmp(table->db, db_name)) &&
+ (!table_name || !strcmp(table->alias, table_name)))
+ break;
+ return table;
+}
+
+/*
+ Find real table in given list.
+
+ SYNOPSIS
+ find_table_in_list()
+ table - pointer to table list
+ db_name - data base name
+ table_name - table name
+
+ RETURN VALUES
+ NULL Table not found
+ # Pointer to found table.
+*/
+
+TABLE_LIST * find_real_table_in_list(TABLE_LIST *table,
+ const char *db_name,
+ const char *table_name)
+{
+ for (; table; table= table->next)
+ if (!strcmp(table->db, db_name) &&
+ !strcmp(table->real_name, table_name))
+ break;
+ return table;
+}
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
{
@@ -590,7 +584,7 @@ TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
uint key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
TABLE *table,**prev;
- int4store(key+key_length,thd->slave_proxy_id);
+ int4store(key+key_length,thd->variables.pseudo_thread_id);
key_length += 4;
prev= &thd->temporary_tables;
@@ -630,7 +624,7 @@ bool rename_temporary_table(THD* thd, TABLE *table, const char *db,
(strmov((table->real_name=strmov(table->table_cache_key=key,
db)+1),
table_name) - table->table_cache_key)+1;
- int4store(key+table->key_length,thd->slave_proxy_id);
+ int4store(key+table->key_length,thd->variables.pseudo_thread_id);
table->key_length += 4;
return 0;
}
@@ -784,7 +778,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
if (thd->killed)
DBUG_RETURN(0);
key_length= (uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
- int4store(key + key_length, thd->slave_proxy_id);
+ int4store(key + key_length, thd->variables.pseudo_thread_id);
for (table=thd->temporary_tables; table ; table=table->next)
{
@@ -798,6 +792,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
DBUG_RETURN(0);
}
table->query_id=thd->query_id;
+ thd->tmp_table_used= 1;
goto reset;
}
}
@@ -808,7 +803,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);
@@ -1320,9 +1315,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),
@@ -1332,8 +1326,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)
@@ -1342,8 +1335,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);
@@ -1488,6 +1480,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
while (!(table=open_table(thd,table_list->db,
table_list->real_name,table_list->alias,
&refresh)) && refresh) ;
+
if (table)
{
#if defined( __WIN__) || defined(OS2)
@@ -1507,6 +1500,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
}
else
{
+ DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
if (!(thd->lock=mysql_lock_tables(thd,&table_list->table,1)))
table= 0;
@@ -1538,6 +1532,11 @@ int open_and_lock_tables(THD *thd,TABLE_LIST *tables)
thd Thread handler
tables Tables to lock
+ NOTES
+ You can't call lock_tables twice, as this would break the dead-lock-free
+ handling thr_lock gives us. You most always get all needed locks at
+ once.
+
RETURN VALUES
0 ok
-1 Error
@@ -1551,6 +1550,7 @@ int lock_tables(THD *thd,TABLE_LIST *tables)
if (!thd->locked_tables)
{
+ DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
uint count=0;
for (table = tables ; table ; table=table->next)
count++;
@@ -1620,7 +1620,7 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
+1), table_name)
- tmp_table->table_cache_key)+1;
int4store(tmp_table->table_cache_key + tmp_table->key_length,
- thd->slave_proxy_id);
+ thd->variables.pseudo_thread_id);
tmp_table->key_length += 4;
if (link_in_list)
@@ -1637,6 +1637,8 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
bool rm_temporary_table(enum db_type base, char *path)
{
bool error=0;
+ DBUG_ENTER("rm_temporary_table");
+
fn_format(path, path,"",reg_ext,4);
unpack_filename(path,path);
if (my_delete(path,MYF(0)))
@@ -1646,7 +1648,7 @@ bool rm_temporary_table(enum db_type base, char *path)
if (file && file->delete_table(path))
error=1;
delete file;
- return error;
+ DBUG_RETURN(error);
}
@@ -1669,14 +1671,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;
@@ -1699,8 +1704,33 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
}
+/*
+ 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
+ where Table where field found will be returned via
+ this parameter
+ 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 was not found. no error message reported.
+ found field
+*/
+
+// Special Field pointer for find_field_in_tables returning
+const Field *not_found_field= (Field*) 0x1;
+
Field *
-find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
+find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
+ TABLE_LIST **where, bool report_error)
{
Field *found=0;
const char *db=item->db_name;
@@ -1708,13 +1738,13 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
const char *name=item->field_name;
uint length=(uint) strlen(name);
- if (table_name)
+ if (table_name && table_name[0])
{ /* Qualified field */
bool found_table=0;
for (; tables ; tables=tables->next)
{
if (!strcmp(tables->alias,table_name) &&
- (!db || !strcmp(db,tables->db)))
+ (!db || !tables->db || !tables->db[0] || !strcmp(db,tables->db)))
{
found_table=1;
Field *find=find_field_in_table(thd,tables->table,name,length,
@@ -1723,6 +1753,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
1);
if (find)
{
+ (*where)= tables;
if (find == WRONG_GRANT)
return (Field*) 0;
if (db || !thd->where)
@@ -1739,25 +1770,41 @@ 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)
+ if (db && db[0])
{
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
for (; tables ; tables=tables->next)
{
+ if (!tables->table)
+ {
+ if (report_error)
+ my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
+ item->full_name(),thd->where);
+ return (Field*) not_found_field;
+ }
+
Field *field=find_field_in_table(thd,tables->table,name,length,
grant_option &&
tables->table->grant.want_privilege,
@@ -1766,6 +1813,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
{
if (field == WRONG_GRANT)
return (Field*) 0;
+ (*where)= tables;
if (found)
{
if (!thd->where) // Returns first found
@@ -1779,13 +1827,49 @@ 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;
}
+
+/*
+ Find Item in list of items (find_field_in_tables analog)
+
+ TODO
+ is it better return only counter?
+
+ SYNOPSIS
+ find_item_in_list()
+ find Item to find
+ items List of items
+ counter To return number of found item
+ 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 was not found. No error message was reported
+ found field
+*/
+
+// Special Item pointer for find_item_in_list returning
+const Item **not_found_item= (const Item**) 0x1;
+
+
Item **
-find_item_in_list(Item *find,List<Item> &items)
+find_item_in_list(Item *find, List<Item> &items, uint *counter,
+ find_item_error_report_type report_error)
{
List_iterator<Item> li(items);
Item **found=0,*item;
@@ -1797,11 +1881,12 @@ find_item_in_list(Item *find,List<Item> &items)
table_name= ((Item_ident*) find)->table_name;
}
- while ((item=li++))
+ for (uint i= 0; (item=li++); i++)
{
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)
{
@@ -1809,59 +1894,66 @@ 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;
}
- found=li.ref();
+ found= li.ref();
+ *counter= i;
}
else if (!strcmp(((Item_field*) item)->table_name,table_name))
{
- found=li.ref();
+ found= li.ref();
+ *counter= i;
break;
}
}
}
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();
+ found= li.ref();
+ *counter= i;
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;
}
/****************************************************************************
-** Check that all given fields exists and fill struct with current data
+** Expand all '*' in given fields
****************************************************************************/
-int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
- bool set_query_id, List<Item> *sum_func_list,
- bool allow_sum_func)
+int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
+ List<Item> *sum_func_list,
+ uint wild_num)
{
+ if (!wild_num)
+ return 0;
reg2 Item *item;
List_iterator<Item> it(fields);
- DBUG_ENTER("setup_fields");
-
- thd->set_query_id=set_query_id;
- thd->allow_sum_func= allow_sum_func;
- thd->where="field list";
-
- while ((item=it++))
- {
- if (item->type() == Item::FIELD_ITEM &&
+ while ( wild_num && (item= it++))
+ {
+ if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*')
{
- uint elem=fields.elements;
+ uint elem= fields.elements;
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
- ((Item_field*) item)->table_name,&it))
- DBUG_RETURN(-1); /* purecov: inspected */
+ ((Item_field*) item)->table_name, &it))
+ return (-1);
if (sum_func_list)
{
/*
@@ -1871,25 +1963,52 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
sum_func_list->elements+= fields.elements - elem;
}
- }
- else
- {
- if (item->fix_fields(thd,tables))
- DBUG_RETURN(-1); /* purecov: inspected */
- if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
- sum_func_list)
- item->split_sum_func(*sum_func_list);
- thd->used_tables|=item->used_tables();
+ wild_num--;
}
}
- DBUG_RETURN(test(thd->fatal_error));
+ return 0;
}
+/****************************************************************************
+** Check that all given fields exists and fill struct with current data
+****************************************************************************/
+
+int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, bool set_query_id,
+ List<Item> *sum_func_list, bool allow_sum_func)
+{
+ reg2 Item *item;
+ List_iterator<Item> it(fields);
+ DBUG_ENTER("setup_fields");
+
+ thd->set_query_id=set_query_id;
+ thd->allow_sum_func= allow_sum_func;
+ thd->where="field list";
+
+ Item **ref= ref_pointer_array;
+ while ((item= it++))
+ {
+ if (item->fix_fields(thd, tables, it.ref()) ||
+ item->check_cols(1))
+ DBUG_RETURN(-1); /* purecov: inspected */
+ item= *(it.ref()); //Item can be changed in fix fields
+ if (ref)
+ *(ref++)= item;
+ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
+ sum_func_list)
+ item->split_sum_func(ref_pointer_array, *sum_func_list);
+ thd->used_tables|=item->used_tables();
+ }
+ DBUG_RETURN(test(thd->net.report_error));
+}
/*
Remap table numbers if INSERT ... SELECT
Check also that the 'used keys' and 'ignored keys' exists and set up the
table structure accordingly
+
+ This has to be called for all tables that are used by items, as otherwise
+ table->map is not set and all Item_field will be regarded as const items.
*/
bool setup_tables(TABLE_LIST *tables)
@@ -2028,12 +2147,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
- thd->cond_count=0;
- thd->allow_sum_func=0;
+
+ thd->cond_count= 0;
if (*conds)
{
thd->where="where clause";
- if ((*conds)->fix_fields(thd,tables))
+ if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1))
DBUG_RETURN(1);
}
@@ -2044,7 +2163,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
/* Make a join an a expression */
thd->where="on clause";
- if (table->on_expr->fix_fields(thd,tables))
+ if (table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
+ table->on_expr->check_cols(1))
DBUG_RETURN(1);
thd->cond_count++;
@@ -2072,7 +2192,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]),
@@ -2101,7 +2222,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
table->on_expr=and_conds(table->on_expr,cond_and);
}
}
- DBUG_RETURN(test(thd->fatal_error));
+ DBUG_RETURN(test(thd->net.report_error));
}
@@ -2121,7 +2242,7 @@ fill_record(List<Item> &fields,List<Item> &values)
while ((field=(Item_field*) f++))
{
value=v++;
- if (value->save_in_field(field->field, 0))
+ if (value->save_in_field(field->field, 0) > 0)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2139,7 +2260,7 @@ fill_record(Field **ptr,List<Item> &values)
while ((field = *ptr++))
{
value=v++;
- if (value->save_in_field(field, 0))
+ if (value->save_in_field(field, 0) == 1)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2148,39 +2269,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)
@@ -2192,9 +2315,10 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
DBUG_ENTER("mysql_create_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
+ create_info.table_charset= thd->db_charset;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
- fields, keys, drop, alter, (ORDER*)0, FALSE,
+ fields, keys, drop, alter, 0, (ORDER*)0, FALSE,
DUP_ERROR));
}
@@ -2208,9 +2332,10 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
DBUG_ENTER("mysql_drop_index");
bzero((char*) &create_info,sizeof(create_info));
create_info.db_type=DB_TYPE_DEFAULT;
+ create_info.table_charset= thd->db_charset;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
- fields, keys, drop, alter, (ORDER*)0, FALSE,
+ fields, keys, drop, alter, 0, (ORDER*)0, FALSE,
DUP_ERROR));
}
@@ -2318,10 +2443,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++))
@@ -2340,11 +2465,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..90fd61ebeb7 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->lex.safe_to_cache_query to 0
+ in 'get_lock_data' if any of the tables was a tmp table or a
+ MRG_ISAM table.
+ (This could be done with almost no speed penalty)
*/
#include "mysql_priv.h"
@@ -292,7 +307,6 @@ TODO list:
#else
#include "../myisammrg/myrg_def.h"
#endif
-#include <assert.h>
#if defined(EXTRA_DEBUG) && !defined(DBUG_OFF)
#define MUTEX_LOCK(M) { DBUG_PRINT("lock", ("mutex lock 0x%lx", (ulong)(M))); \
@@ -342,12 +356,6 @@ TODO list:
#define DUMP(C)
#endif
-#ifdef FN_NO_CASE_SENCE
-#define DB_NAME_PREPROCESS(C) tolower(C)
-#else
-#define DB_NAME_PREPROCESS(C) (C)
-#endif
-
const char *query_cache_type_names[]= { "OFF", "ON", "DEMAND",NullS };
TYPELIB query_cache_type_typelib=
{
@@ -746,7 +754,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
if ((local_tables = is_cacheable(thd, thd->query_length,
thd->query, &thd->lex, tables_used)))
{
- NET *net = &thd->net;
+ NET *net= &thd->net;
byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
STRUCT_LOCK(&structure_guard_mutex);
@@ -849,6 +857,7 @@ end:
DBUG_VOID_RETURN;
}
+
/*
Check if the query is in the cache. If it was cached, send it
to the user.
@@ -859,8 +868,6 @@ end:
-1 The query was cached but we didn't have rights to use it.
No error is sent to the client yet.
*/
-
-
int
Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
@@ -885,7 +892,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
/* Check that we haven't forgot to reset the query cache variables */
DBUG_ASSERT(thd->net.query_cache_query == 0);
- if (!thd->safe_to_cache_query)
+ if (!thd->lex.safe_to_cache_query)
{
DBUG_PRINT("qcache", ("SELECT is non-cacheable"));
goto err;
@@ -895,8 +902,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;
@@ -978,7 +986,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
table_list.db, table_list.alias));
refused++; // This is actually a hit
STRUCT_UNLOCK(&structure_guard_mutex);
- thd->safe_to_cache_query=0; // Don't try to cache this
+ thd->lex.safe_to_cache_query=0; // Don't try to cache this
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(-1); // Privilege error
}
@@ -987,7 +995,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
DBUG_PRINT("qcache", ("Need to check column privileges for %s.%s",
table_list.db, table_list.alias));
BLOCK_UNLOCK_RD(query_block);
- thd->safe_to_cache_query=0; // Don't try to cache this
+ thd->lex.safe_to_cache_query=0; // Don't try to cache this
goto err_unlock; // Parse query
}
}
@@ -1006,11 +1014,13 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
ALIGN_SIZE(sizeof(Query_cache_result))));
Query_cache_result *result = result_block->result();
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
if (net_real_write(&thd->net, result->data(),
result_block->used -
result_block->headers_len() -
ALIGN_SIZE(sizeof(Query_cache_result))))
break; // Client aborted
+#endif
result_block = result_block->next;
} while (result_block != first_result_block);
@@ -1046,6 +1056,8 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
for (; tables_used; tables_used=tables_used->next)
{
DBUG_ASSERT(!using_transactions || tables_used->table!=0);
+ if (tables_used->derived)
+ continue;
if (using_transactions &&
tables_used->table->file->has_transactions())
/*
@@ -1383,16 +1395,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 +2451,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)
+ lex->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)
@@ -2460,12 +2472,20 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
if (tables_used->table->db_type == DB_TYPE_MRG_ISAM ||
tables_used->table->tmp_table != NO_TMP_TABLE ||
- (tables_used->db_length == 5 &&
- DB_NAME_PREPROCESS(tables_used->db[0])=='m' &&
- DB_NAME_PREPROCESS(tables_used->db[1])=='y' &&
- DB_NAME_PREPROCESS(tables_used->db[2])=='s' &&
- DB_NAME_PREPROCESS(tables_used->db[3])=='q' &&
- DB_NAME_PREPROCESS(tables_used->db[4])=='l'))
+ (tables_used->db_length == 5 &&
+#ifdef FN_NO_CASE_SENCE
+ // TODO: latin1 charset should be replaced with system charset
+ my_strncasecmp(&my_charset_latin1,
+ tables_used->db,
+ "mysql",5) == 0
+#else
+ tables_used->db[0]=='m' &&
+ tables_used->db[1]=='y' &&
+ tables_used->db[2]=='s' &&
+ tables_used->db[3]=='q' &&
+ tables_used->db[4]=='l'
+#endif
+ ))
{
DBUG_PRINT("qcache",
("select not cacheable: used MRG_ISAM, temporary or system table(s)"));
@@ -2493,7 +2513,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 dc687e483e8..3a66e906837 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -35,7 +35,6 @@
#include <io.h>
#endif
#include <mysys_err.h>
-#include <assert.h>
/*****************************************************************************
@@ -78,35 +77,40 @@ 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), is_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= "connecting host";
locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password=
- query_start_used=safe_to_cache_query=0;
+ query_start_used=prepare_command=0;
db_length=query_length=col_access=0;
- query_error=0;
+ query_error= tmp_table_used= 0;
next_insert_id=last_insert_id=0;
- open_tables=temporary_tables=handler_tables=0;
+ open_tables= temporary_tables= handler_tables= derived_tables= 0;
current_tablenr=0;
handler_items=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;
+ variables.pseudo_thread_id= 0;
file_id = 0;
cond_count=0;
+ warn_id= 0;
+ db_charset=default_charset_info;
mysys_var=0;
#ifndef DBUG_OFF
dbug_sentry=THD_SENTRY_MAGIC;
-#endif
+#endif
+#ifndef EMBEDDED_LIBRARY
net.vio=0;
+#endif
net.last_error[0]=0; // If error on boot
ull=0;
system_thread=cleanup_done=0;
@@ -134,10 +138,36 @@ 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);
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);
+
+ /* For user vars replication*/
+ if (opt_bin_log)
+ my_init_dynamic_array(&user_var_events,
+ sizeof(BINLOG_USER_VAR_EVENT *),
+ 16,
+ 16);
+ else
+ bzero((char*) &user_var_events, sizeof(user_var_events));
+
+
+
+ /* 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);
+
+ /* Protocol */
+ protocol= &protocol_simple; // Default protocol
+ protocol_simple.init(this);
+ protocol_prep.init(this);
+
#ifdef USING_TRANSACTIONS
bzero((char*) &transaction,sizeof(transaction));
if (opt_using_transactions)
@@ -171,17 +201,35 @@ void THD::init(void)
{
pthread_mutex_lock(&LOCK_global_system_variables);
variables= global_system_variables;
+ variables.thd_charset=default_charset_info;
pthread_mutex_unlock(&LOCK_global_system_variables);
server_status= SERVER_STATUS_AUTOCOMMIT;
options= thd_startup_options;
- sql_mode=(uint) opt_sql_mode;
open_options=ha_open_options;
update_lock_default= (variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY :
TL_WRITE);
session_tx_isolation= (enum_tx_isolation) variables.tx_isolation;
+ warn_list.empty();
+ bzero((char*) warn_count, sizeof(warn_count));
+ total_warn_count= 0;
}
+
+/*
+ Init THD for query processing
+
+ This has to be called once before we call mysql_parse()
+*/
+
+void THD::init_for_queries()
+{
+ init_sql_alloc(&mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
+ init_sql_alloc(&transaction.mem_root,
+ TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
+}
+
+
/*
Do what's needed when one invokes change user
@@ -196,11 +244,11 @@ void THD::init(void)
void THD::change_user(void)
{
cleanup();
- cleanup_done=0;
+ cleanup_done= 0;
init();
- 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);
+ (hash_free_key) free_user_var, 0);
}
@@ -210,6 +258,7 @@ void THD::cleanup(void)
{
DBUG_ENTER("THD::cleanup");
ha_rollback(this);
+ delete_tree(&prepared_statements);
if (locked_tables)
{
lock=locked_tables; locked_tables=0;
@@ -221,6 +270,7 @@ void THD::cleanup(void)
close_thread_tables(this);
}
close_temporary_tables(this);
+ delete_dynamic(&user_var_events);
hash_free(&user_vars);
if (global_read_lock)
unlock_global_read_lock(this);
@@ -245,11 +295,13 @@ THD::~THD()
pthread_mutex_unlock(&LOCK_delete);
/* Close connection */
+#ifndef EMBEDDED_LIBRARY
if (net.vio)
{
vio_delete(net.vio);
net_end(&net);
}
+#endif
if (!cleanup_done)
cleanup();
#ifdef USING_TRANSACTIONS
@@ -268,6 +320,8 @@ 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));
mysys_var=0; // Safety (shouldn't be needed)
pthread_mutex_destroy(&LOCK_delete);
@@ -318,8 +372,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();
@@ -415,21 +468,47 @@ 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_return_int("id",3, MYSQL_TYPE_LONGLONG));
+ 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_return_int("key_len",3,
+ MYSQL_TYPE_LONGLONG));
+ 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_return_int("rows",10, MYSQL_TYPE_LONGLONG));
+ 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()
{
DBUG_ENTER("close_active_vio");
safe_mutex_assert_owner(&LOCK_delete);
+#ifndef EMBEDDED_LIBRARY
if (active_vio)
{
vio_close(active_vio);
active_vio = 0;
}
+#endif
DBUG_VOID_RETURN;
}
#endif
+
/*****************************************************************************
** Functions to provide a interface to select results
*****************************************************************************/
@@ -439,8 +518,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)
@@ -453,45 +534,50 @@ sql_exchange::sql_exchange(char *name,bool flag)
bool select_send::send_fields(List<Item> &list,uint flag)
{
- return ::send_fields(thd,list,flag);
+ return thd->protocol->send_fields(&list,flag);
}
-
/* Send data to client. Returns 0 if ok */
bool select_send::send_data(List<Item> &items)
{
- List_iterator_fast<Item> li(items);
- String *packet= &thd->packet;
- DBUG_ENTER("send_data");
+ if (unit->offset_limit_cnt)
+ { // using limit offset,count
+ unit->offset_limit_cnt--;
+ return 0;
+ }
#ifdef HAVE_INNOBASE_DB
- /* We may be passing the control from mysqld to the client: release the
- InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
- by thd */
+ /*
+ We may be passing the control from mysqld to the client: release the
+ InnoDB adaptive hash S-latch to avoid thread deadlocks if it was reserved
+ by thd
+ */
if (thd->transaction.all.innobase_tid)
ha_release_temporary_latches(thd);
#endif
- if (thd->offset_limit)
- { // using limit offset,count
- thd->offset_limit--;
- DBUG_RETURN(0);
- }
- packet->length(0); // Reset packet
+ List_iterator_fast<Item> li(items);
+ Protocol *protocol= thd->protocol;
+ char buff[MAX_FIELD_WIDTH];
+ String buffer(buff, sizeof(buff), &my_charset_bin);
+ DBUG_ENTER("send_data");
+
+ protocol->prepare_for_resend();
Item *item;
while ((item=li++))
{
- if (item->send(thd, packet))
+ if (item->send(protocol, &buffer))
{
- packet->free(); // Free used
- my_error(ER_OUT_OF_RESOURCES,MYF(0));
- DBUG_RETURN(1);
+ protocol->free(); // Free used buffer
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ break;
}
}
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(protocol->write());
+ DBUG_RETURN(1);
}
bool select_send::send_eof()
@@ -509,8 +595,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;
}
@@ -531,11 +622,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
@@ -545,7 +637,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 */
@@ -599,12 +691,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),&my_charset_bin),*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++;
@@ -660,10 +752,11 @@ bool select_export::send_data(List<Item> &items)
pos++)
{
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ CHARSET_INFO *res_charset=res->charset();
+ if (use_mb(res_charset))
{
int l;
- if ((l=my_ismbchar(default_charset_info, pos, end)))
+ if ((l=my_ismbchar(res_charset, pos, end)))
{
pos += l-1;
continue;
@@ -731,9 +824,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;
@@ -745,10 +838,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;
}
@@ -770,9 +861,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
@@ -806,19 +899,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),&my_charset_bin),*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++))
@@ -843,23 +936,122 @@ 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_singlerow_subselect::send_data(List<Item> &items)
+{
+ DBUG_ENTER("select_singlerow_subselect::send_data");
+ Item_singlerow_subselect *it= (Item_singlerow_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;
+ for (uint i= 0; (val_item= li++); i++)
+ it->store(i, val_item);
+ 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;
+ }
+ unit=u;
+ while ((item=li++))
+ {
+ ls= gl++;
+ Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item);
+ xx->fix_fields(thd,(TABLE_LIST*) 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 (unit->offset_limit_cnt)
+ { // Using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
+ 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 ad0540de18c..af60ea6d466 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -29,12 +29,12 @@ class Slave_log_event;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
-enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE };
+enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE, DUP_UPDATE };
enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL };
-// log info errors
+// log info errors
#define LOG_INFO_EOF -1
#define LOG_INFO_IO -2
#define LOG_INFO_INVALID -3
@@ -57,6 +57,15 @@ typedef struct st_log_info
~st_log_info() { pthread_mutex_destroy(&lock);}
} LOG_INFO;
+typedef struct st_user_var_events
+{
+ user_var_entry *user_var_event;
+ char *value;
+ ulong length;
+ Item_result type;
+ uint charset_number;
+} BINLOG_USER_VAR_EVENT;
+
class Log_event;
class MYSQL_LOG {
@@ -73,14 +82,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
@@ -134,7 +143,9 @@ public:
int generate_new_name(char *new_name,const char *old_name);
void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name);
+ int update_log_index(LOG_INFO* linfo);
int purge_logs(THD* thd, const char* to_log);
+ int purge_logs_before_date(THD* thd, time_t purge_time);
int purge_first_log(struct st_relay_log_info* rli);
bool reset_logs(THD* thd);
// if we are exiting, we also want to close the index file
@@ -178,6 +189,12 @@ public:
{
convert_array(from_map, (uchar*) a,length);
}
+ char *store_dest(char *to, const char *from, uint length)
+ {
+ for (const char *end=from+length ; from != end ; from++)
+ *to++= to_map[(uchar) *from];
+ return to;
+ }
bool store(String *, const char *,uint);
inline uint number() { return numb; }
};
@@ -189,6 +206,9 @@ typedef struct st_copy_info {
ha_rows error_count;
enum enum_duplicates handle_duplicates;
int escape_char, last_errno;
+/* for INSERT ... UPDATE */
+ List<Item> *update_fields;
+ List<Item> *update_values;
} COPY_INFO;
@@ -221,19 +241,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
{
@@ -253,8 +294,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:
@@ -263,7 +304,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:
@@ -274,7 +315,44 @@ 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;
+ LEX lex;
+ 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
@@ -291,32 +369,43 @@ struct system_variables
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_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 sortbuff_size;
+ ulong table_type;
ulong tmp_table_size;
ulong tx_isolation;
- ulong table_type;
+ ulong sql_mode;
+ ulong default_week_format;
+
+ /*
+ In slave thread we need to know in behalf of which
+ thread the query is being run to replicate temp tables properly
+ */
+ ulong pseudo_thread_id;
my_bool log_warnings;
my_bool low_priority_updates;
my_bool new_mode;
- CONVERT *convert_set;
+ CONVERT *convert_set;
+ CHARSET_INFO *thd_charset;
};
-
+void free_tmp_table(THD *thd, TABLE *entry);
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -325,10 +414,19 @@ struct system_variables
class THD :public ilink
{
public:
+#ifdef EMBEDDED_LIBRARY
+ struct st_mysql *mysql;
+#endif
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
+ Protocol *protocol; // Current protocol
+ Protocol_simple protocol_simple; // Normal protocol
+ Protocol_prep protocol_prep; // Binary protocol
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
@@ -346,8 +444,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
*/
@@ -359,24 +456,24 @@ public:
/* points to host if host is available, otherwise points to ip */
const char *host_or_ip;
- uint client_capabilities; /* What the client supports */
+ ulong client_capabilities; /* What the client supports */
/* Determines if which non-standard SQL behaviour should be enabled */
- uint sql_mode;
ulong max_client_packet_length;
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
handler_tables - list of tables that were opened with HANDLER OPEN
and are still in use by this thread
*/
- TABLE *open_tables,*temporary_tables, *handler_tables;
+ TABLE *open_tables,*temporary_tables, *handler_tables, *derived_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
@@ -422,7 +519,13 @@ 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;
+ List<TABLE> temporary_tables_should_be_free; // list of temporary tables
+ 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;
@@ -430,32 +533,34 @@ public:
uint server_status,open_options;
uint32 query_length;
uint32 db_length;
+ uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
enum_tx_isolation session_tx_isolation;
- char scramble[9];
+ /* for user variables replication*/
+ DYNAMIC_ARRAY user_var_events;
+ // extend scramble to handle new auth
+ char scramble[SCRAMBLE41_LENGTH+1];
+ // old scramble is needed to handle old clients
+ char old_scramble[SCRAMBLE_LENGTH+1];
uint8 query_cache_type; // type of query cache processing
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
- bool no_errors, allow_sum_func, password, fatal_error;
+ bool no_errors, allow_sum_func, password, is_fatal_error;
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
bool system_thread,in_lock_tables,global_read_lock;
bool query_error, bootstrap, cleanup_done;
- bool safe_to_cache_query;
bool volatile killed;
+ bool prepare_command;
+ bool tmp_table_used;
+
/*
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
each thread that is using LOG_INFO needs to adjust the pointer to it
*/
LOG_INFO* current_linfo;
- /*
- In slave thread we need to know in behalf of which
- thread the query is being run to replicate temp tables properly
- */
- 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
{
@@ -465,8 +570,10 @@ public:
THD();
~THD();
+
void init(void);
void change_user(void);
+ void init_for_queries();
void cleanup(void);
bool store_globals();
#ifdef SIGNAL_WITH_VIO_CLOSE
@@ -559,6 +666,24 @@ 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);
+#ifndef EMBEDDED_LIBRARY
+ inline void clear_error()
+ {
+ net.last_error[0]= 0;
+ net.last_errno= 0;
+ net.report_error= 0;
+ }
+#else
+ void clear_error();
+#endif
+ inline void fatal_error()
+ {
+ is_fatal_error= 1;
+ net.report_error= 1;
+ DBUG_PRINT("error",("Fatal error set"));
+ }
+ inline CHARSET_INFO *charset() { return variables.thd_charset; }
};
/*
@@ -580,26 +705,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 bool initialize_tables (JOIN *join=0) { return 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() {}
@@ -626,7 +756,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);
@@ -645,7 +775,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);
@@ -668,7 +798,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);
@@ -697,7 +827,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();
@@ -712,7 +842,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);
@@ -720,14 +850,45 @@ 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_singlerow_subselect :public select_subselect
+{
+public:
+ select_singlerow_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 {
Field *field; /* Field to sort */
Item *item; /* Item if not sorting fields */
uint length; /* Length of sort field */
- my_bool reverse; /* if descending sort */
Item_result result_type; /* Type of item */
+ bool reverse; /* if descending sort */
+ bool need_strxnfrm; /* If we have to use strxnfrm() */
} SORT_FIELD;
@@ -742,21 +903,35 @@ typedef struct st_sort_buffer {
/* Structure for db & table in sql_yacc */
-class Table_ident :public Sql_alloc {
+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(THD *thd, 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))
+ if (!force && (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)
+ {
+ /* We must have a table name here as this is used with add_table_to_list */
+ db.str=0; table.str=(char *)"*"; table.length=1;
+ }
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
@@ -765,8 +940,10 @@ class user_var_entry
public:
LEX_STRING name;
char *value;
- ulong length, update_query_id;
+ ulong length, update_query_id, used_query_id;
Item_result type;
+ CHARSET_INFO *var_charset;
+ enum Item::coercion var_coercibility;
};
/* Class for unique (removing of duplicates) */
@@ -789,7 +966,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);
@@ -798,26 +975,28 @@ public:
friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique);
};
- class multi_delete : public select_result {
- TABLE_LIST *delete_tables, *table_being_deleted;
- Unique **tempfiles;
- THD *thd;
- ha_rows deleted;
- uint num_of_tables;
- int error;
- bool do_delete, transactional_tables, log_delayed, normal_tables;
- public:
- multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
- ~multi_delete();
- int prepare(List<Item> &list);
- bool send_fields(List<Item> &list,
+class multi_delete : public select_result
+{
+ TABLE_LIST *delete_tables, *table_being_deleted;
+ Unique **tempfiles;
+ THD *thd;
+ ha_rows deleted;
+ uint num_of_tables;
+ int error;
+ bool do_delete, transactional_tables, log_delayed, normal_tables;
+public:
+ multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables);
+ ~multi_delete();
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
+ bool send_fields(List<Item> &list,
uint flag) { return 0; }
- bool send_data(List<Item> &items);
- bool initialize_tables (JOIN *join);
- void send_error(uint errcode,const char *err);
- int do_deletes (bool from_send_error);
- bool send_eof();
- };
+ bool send_data(List<Item> &items);
+ bool initialize_tables (JOIN *join);
+ void send_error(uint errcode,const char *err);
+ int do_deletes (bool from_send_error);
+ bool send_eof();
+};
+
class multi_update : public select_result
{
@@ -837,7 +1016,7 @@ public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> *fields,
List<Item> *values, enum_duplicates handle_duplicates);
~multi_update();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list, uint flag) { return 0; }
bool send_data(List<Item> &items);
bool initialize_tables (JOIN *join);
@@ -846,3 +1025,16 @@ 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 900c87d83a5..03ccf88316c 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -25,20 +25,142 @@
#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;
+ CHARSET_INFO *cs= (create && create->table_charset) ?
+ create->table_charset : default_charset_info;
+ length= my_sprintf(buf,(buf, "default-character-set=%s\n", cs->name));
+
+ /* 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));
+ create->table_charset= default_charset_info;
+ 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(&my_charset_latin1, pos[-1]))
+ pos--;
+ *pos=0;
+ if ((pos= strchr(buf, '=')))
+ {
+ if (!strncmp(buf,"default-character-set", (pos-buf)))
+ {
+ if (strcmp(pos+1,"DEFAULT"))
+ {
+ 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
-int mysql_create_db(THD *thd, char *db, uint create_options, bool silent)
+ 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, 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,30 +195,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_length= (uint) (strxmov(path,"create database `", db, "`",
- NullS) - path);
- thd->query= 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())
{
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query= 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ Query_log_event qinfo(thd, query, query_length, 0);
+ mysql_bin_log.write(&qinfo);
}
- send_ok(&thd->net, result);
+ send_ok(thd, result);
}
exit:
@@ -106,14 +247,57 @@ 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) ?
+ create_info->table_charset : default_charset_info;
+ }
+
+ mysql_update_log.write(thd,thd->query, thd->query_length);
+ if (mysql_bin_log.is_open())
+ {
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ 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,8 +335,13 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
error= -1;
my_error(ER_DB_DROP_EXISTS,MYF(0),db);
}
- else if (!silent)
- send_ok(&thd->net,0);
+ else
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_DB_DROP_EXISTS, ER(ER_DB_DROP_EXISTS), db);
+ if (!silent)
+ send_ok(thd,0);
+ }
goto exit;
}
pthread_mutex_lock(&LOCK_open);
@@ -166,26 +355,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_length= (uint) (strxmov(path,"drop database `", db, "`",
- NullS)-
- path);
- thd->query= 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())
{
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query= 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ 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;
}
@@ -224,7 +414,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(&my_charset_latin1,file->name[0]) &&
+ my_isdigit(&my_charset_latin1,file->name[1]) &&
!file->name[2] && !level)
{
char newpath[FN_REFLEN];
@@ -249,7 +440,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(&my_charset_latin1,
+ fn_ext(file->name), reg_ext))
{
/* Drop the table nicely */
*fn_ext(file->name)=0; // Remove extension
@@ -281,7 +473,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
my_dirend(dirp);
if (thd->killed ||
- (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 1)))
+ (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1)))
DBUG_RETURN(-1);
/*
@@ -331,23 +523,42 @@ 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);
}
@@ -360,7 +571,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);
@@ -378,14 +589,106 @@ 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);
- 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 ? create.table_charset : default_charset_info;
+ thd->variables.thd_charset=thd->db_charset ? thd->db_charset : default_charset_info;
+ DBUG_RETURN(0);
+}
+
+
+int mysqld_show_create_db(THD *thd, 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;
+ Protocol *protocol=thd->protocol;
+ 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 (protocol->send_fields(&field_list,1))
+ DBUG_RETURN(1);
+
+ protocol->prepare_for_resend();
+ protocol->store(dbname, strlen(dbname), system_charset_info);
+ 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)
+ {
+ int cl= (create.table_charset->state & MY_CS_PRIMARY) ? 0 : 1;
+ to= strxmov(to," /*!40100"
+ " DEFAULT CHARACTER SET ",create.table_charset->csname,
+ cl ? " COLLATE " : "", cl ? create.table_charset->name : "",
+ " */",NullS);
+ }
+ protocol->store(path, (uint) (to-path), system_charset_info);
+
+ if (protocol->write())
+ DBUG_RETURN(1);
+ send_eof(thd);
DBUG_RETURN(0);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 1507d49ebd6..05f84616a4c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -35,27 +35,40 @@ 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 transactional_table, log_delayed, safe_update, const_cond;
ha_rows deleted;
+ TABLE_LIST *delete_table_list= (TABLE_LIST*)
+ thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_delete");
- if (((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)))
+ if ((open_and_lock_tables(thd, table_list)))
DBUG_RETURN(-1);
+ fix_tables_pointers(thd->lex.all_selects_list);
+ table= table_list->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
table->map=1;
- if (setup_conds(thd,table_list,&conds) || setup_ftfuncs(thd))
+ if (setup_conds(thd, delete_table_list, &conds) ||
+ setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(-1);
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
+ DBUG_RETURN(-1);
+ }
+
+ const_cond= (!conds || conds->const_item());
+ safe_update=test(thd->options & OPTION_SAFE_UPDATES);
+ if (safe_update && const_cond)
+ {
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ DBUG_RETURN(1);
+ }
/* Test if the user wants to delete all rows */
- if (!using_limit && (!conds || conds->const_item()) &&
- !(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 +89,11 @@ 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);
+ free_underlaid_joins(thd, &thd->lex.select_lex);
+ send_ok(thd,0L);
DBUG_RETURN(0); // Nothing to delete
}
@@ -92,7 +104,8 @@ 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);
+ free_underlaid_joins(thd, &thd->lex.select_lex);
+ send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
}
@@ -113,25 +126,28 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (setup_order(thd, &tables, fields, all_fields, order) ||
+ if (setup_order(thd, 0, &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)
{
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1); // This will force out message
}
}
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)
+ while (!(error=info.read_record(&info)) && !thd->killed &&
+ !thd->net.report_error)
{
- if (!(select && select->skipp_record()))
+ // thd->net.report_error is tested to disallow delete row on error
+ if (!(select && select->skipp_record())&& !thd->net.report_error )
{
if (!(error=table->file->delete_row(table->record[0])))
{
@@ -194,11 +210,12 @@ cleanup:
thd->lock=0;
}
delete select;
- if (error >= 0) // Fatal error
- send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0);
+ free_underlaid_joins(thd, &thd->lex.select_lex);
+ if (error >= 0 || thd->net.report_error)
+ 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);
@@ -228,9 +245,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= 1;
thd->proc_info="deleting from main table";
DBUG_RETURN(0);
@@ -282,8 +300,8 @@ multi_delete::initialize_tables(JOIN *join)
table->file->ref_length,
MEM_STRIP_BUF_SIZE);
}
- init_ftfuncs(thd,1);
- DBUG_RETURN(thd->fatal_error != 0);
+ init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1);
+ DBUG_RETURN(thd->is_fatal_error != 0);
}
@@ -353,7 +371,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)
@@ -459,6 +477,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
@@ -487,9 +506,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;
}
@@ -527,8 +546,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=table->table_charset;
+ db_type table_type=table->db_type;
strmov(path,table->path);
*table_ptr= table->next; // Unlink table from list
close_temporary(table,0);
@@ -539,8 +559,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;
}
@@ -570,6 +590,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=table_list->table->table_charset;
+
*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);
@@ -586,7 +608,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..ca761140955
--- /dev/null
+++ b/sql/sql_derived.cc
@@ -0,0 +1,226 @@
+/* Copyright (C) 2002-2003 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 Sinisa <sinisa@mysql.com>
+*/
+
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include "sql_acl.h"
+
+extern const char *any_db; // Special symbol for check_access
+
+/*
+ Resolve derived tables in all queries
+
+ SYNOPSIS
+ mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
+ thd Thread handle
+ lex LEX for this thread
+ unit node that contains all SELECT's for derived tables
+ t TABLE_LIST for the upper SELECT
+
+ IMPLEMENTATION
+ Derived table is resolved with temporary table. It is created based on the
+ queries defined. After temporary table is created, if this is not EXPLAIN,
+ then the entire unit / node is deleted. unit is deleted if UNION is used
+ for derived table and node is deleted is it is a simple SELECT.
+
+ After table creation, the above TABLE_LIST is updated with a new table.
+
+ This function is called before any command containing derived table
+ is executed.
+
+ Derived tables is stored in thd->derived_tables and freed in
+ close_thread_tables()
+
+ TODO
+ Move creation of derived tables in open_and_lock_tables()
+
+ RETURN
+ 0 ok
+ 1 Error
+ -1 Error and error message given
+*/
+
+
+int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
+ TABLE_LIST *org_table_list)
+{
+ SELECT_LEX *select_cursor= unit->first_select();
+ List<Item> item_list;
+ TABLE *table;
+ int res;
+ select_union *derived_result;
+ TABLE_LIST *tables= (TABLE_LIST *)select_cursor->table_list.first;
+ TMP_TABLE_PARAM tmp_table_param;
+ bool is_union= select_cursor->next_select() &&
+ select_cursor->next_select()->linkage == UNION_TYPE;
+ bool is_subsel= select_cursor->first_inner_unit() ? 1: 0;
+ SELECT_LEX_NODE *save_current_select= lex->current_select;
+ DBUG_ENTER("mysql_derived");
+
+ /*
+ In create_total_list, derived tables have to be treated in case of
+ EXPLAIN, This is because unit/node is not deleted in that
+ case. Current code in this function has to be improved to
+ recognize better when this function is called from derived tables
+ and when from other functions.
+ */
+ if ((is_union || is_subsel) && unit->create_total_list(thd, lex, &tables, 1))
+ DBUG_RETURN(-1);
+
+ /*
+ We have to do access checks here as this code is executed before any
+ sql command is started to execute.
+ */
+ if (tables)
+ res= check_table_access(thd,SELECT_ACL, tables);
+ else
+ res= check_access(thd, SELECT_ACL, any_db);
+ if (res)
+ DBUG_RETURN(-1);
+
+ if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ if (is_union || is_subsel)
+ {
+ /*
+ The following code is a re-do of fix_tables_pointers() found
+ in sql_select.cc for UNION's within derived tables. The only
+ difference is in navigation, as in derived tables we care for
+ this level only.
+
+ */
+ fix_tables_pointers(unit);
+ }
+
+ lex->current_select= select_cursor;
+ TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first;
+ /* Setting up. A must if a join or IGNORE, USE or similar are utilised */
+ if (setup_tables(first_table) ||
+ setup_wild(thd, first_table, select_cursor->item_list, 0, select_cursor->with_wild))
+ {
+ res= -1;
+ goto exit;
+ }
+
+ item_list= select_cursor->item_list;
+ select_cursor->with_wild= 0;
+ if (setup_ref_array(thd, &select_cursor->ref_pointer_array,
+ (item_list.elements + select_cursor->with_sum_func +
+ select_cursor->order_list.elements +
+ select_cursor->group_list.elements)) ||
+ setup_fields(thd, select_cursor->ref_pointer_array, first_table, 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;
+ /* temp table is created so that it hounours if UNION without ALL is to be
+ processed */
+ if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
+ (ORDER*) 0,
+ is_union && !unit->union_option, 1,
+ (select_cursor->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ HA_POS_ERROR)))
+ {
+ res= -1;
+ goto exit;
+ }
+
+ if ((derived_result=new select_union(table)))
+ {
+ derived_result->tmp_table_param=&tmp_table_param;
+ unit->offset_limit_cnt= select_cursor->offset_limit;
+ unit->select_limit_cnt= select_cursor->select_limit+
+ select_cursor->offset_limit;
+ if (unit->select_limit_cnt < select_cursor->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR;
+ if (unit->select_limit_cnt == HA_POS_ERROR)
+ select_cursor->options&= ~OPTION_FOUND_ROWS;
+
+ if (is_union)
+ res= mysql_union(thd, lex, derived_result, unit, 1);
+ else
+ res= mysql_select(thd, &select_cursor->ref_pointer_array,
+ (TABLE_LIST*) select_cursor->table_list.first,
+ select_cursor->with_wild,
+ select_cursor->item_list, select_cursor->where,
+ (select_cursor->order_list.elements+
+ select_cursor->group_list.elements),
+ (ORDER *) select_cursor->order_list.first,
+ (ORDER *) select_cursor->group_list.first,
+ select_cursor->having, (ORDER*) NULL,
+ (select_cursor->options | thd->options |
+ SELECT_NO_UNLOCK),
+ derived_result, unit, select_cursor, 1);
+
+ 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
+ {
+ org_table_list->real_name=table->real_name;
+ org_table_list->table=table;
+ table->derived_select_number= select_cursor->select_number;
+ table->tmp_table= TMP_TABLE;
+ if (lex->describe)
+ {
+ // to fix a problem in EXPLAIN
+ if (tables)
+ tables->table_list->table=tables->table;
+ }
+ else
+ unit->exclude_level();
+ org_table_list->db= (char *)"";
+#ifndef DBUG_OFF
+ /* Try to catch errors if this is accessed */
+ org_table_list->derived=(SELECT_LEX_UNIT *) 1;
+#endif
+// This line is required to force read of table stats in the optimizer
+ table->file->info(HA_STATUS_VARIABLE);
+ }
+ }
+ delete derived_result;
+ }
+ if (res)
+ free_tmp_table(thd, table);
+ else
+ {
+ /* Add new temporary table to list of open derived tables */
+ table->next= thd->derived_tables;
+ thd->derived_tables= table;
+ }
+
+exit:
+ lex->current_select= save_current_select;
+ close_thread_tables(thd, 0, 1);
+ }
+ DBUG_RETURN(res);
+}
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index 70124c2d796..f25c4632e1e 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -25,10 +25,10 @@ int mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
- if (setup_fields(thd,0, values, 0, 0, 0))
+ if (setup_fields(thd, 0, 0, values, 0, 0, 0))
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..8d3bb3ca49b
--- /dev/null
+++ b/sql/sql_error.cc
@@ -0,0 +1,195 @@
+/* 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)
+{
+ DBUG_ENTER("mysql_reset_errors");
+ 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();
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ 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++;
+}
+
+/*
+ Push the warning/error to error list if there is still room in the list
+
+ SYNOPSIS
+ push_warning_printf()
+ thd Thread handle
+ level Severity of warning (note, warning, error ...)
+ code Error number
+ msg Clear error message
+*/
+
+void push_warning_printf(THD *thd, MYSQL_ERROR::enum_warning_level level,
+ uint code, const char *format, ...)
+{
+ va_list args;
+ char warning[ERRMSGSIZE+20];
+ DBUG_ENTER("push_warning_printf");
+ DBUG_PRINT("enter",("warning: %u", code));
+
+ va_start(args,format);
+ my_vsnprintf(warning, sizeof(warning), format, args);
+ va_end(args);
+ push_warning(thd, level, code, warning);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ 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", "?"};
+static int warning_level_length[]= { 4, 7, 5, 1 };
+
+my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
+{
+ List<Item> field_list;
+ DBUG_ENTER("mysqld_show_warnings");
+
+ field_list.push_back(new Item_empty_string("Level", 7));
+ field_list.push_back(new Item_return_int("Code",4, MYSQL_TYPE_LONG));
+ field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE));
+
+ if (thd->protocol->send_fields(&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;
+ Protocol *protocol=thd->protocol;
+
+ 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;
+ }
+ protocol->prepare_for_resend();
+ protocol->store(warning_level_names[err->level],
+ warning_level_length[err->level], system_charset_info);
+ protocol->store((uint32) err->code);
+ protocol->store(err->msg, strlen(err->msg), system_charset_info);
+ if (protocol->write())
+ 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 a98b6c13a00..7c07c08bcac 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 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
@@ -19,7 +19,6 @@
#include "mysql_priv.h"
#include "sql_select.h"
-#include <assert.h>
/* TODO:
HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
@@ -62,7 +61,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
return -1;
}
- send_ok(&thd->net);
+ send_ok(thd);
return 0;
}
@@ -83,7 +82,7 @@ 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;
}
@@ -96,7 +95,7 @@ int mysql_ha_closeall(THD *thd, TABLE_LIST *tables)
}
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,
@@ -114,10 +113,12 @@ 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) || cond->check_cols(1)))
return -1;
- table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
+ /* InnoDB needs to know that this table handle is used in the HANDLER */
+
+ table->file->init_table_handle_for_HANDLER();
if (keyname)
{
@@ -133,13 +134,16 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
List<Item> list;
list.push_front(new Item_field(NULL,NULL,"*"));
List_iterator<Item> it(list);
+ Protocol *protocol= thd->protocol;
+ char buff[MAX_FIELD_WIDTH];
+ String buffer(buff, sizeof(buff), system_charset_info);
uint num_rows;
it++;
insert_fields(thd,tables,tables->db,tables->alias,&it);
select_limit+=offset_limit;
- send_fields(thd,list,1);
+ protocol->send_fields(&list,1);
HANDLER_TABLES_HACK(thd);
MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1);
@@ -147,11 +151,17 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (!lock)
goto err0; // mysql_lock_tables() printed error message already
- table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
+ /*
+ In ::external_lock InnoDB resets the fields which tell it that
+ the handle is used in the HANDLER interface. Tell it again that
+ we are using it for HANDLER.
+ */
+
+ table->file->init_table_handle_for_HANDLER();
for (num_rows=0; num_rows < select_limit; )
{
- switch(mode) {
+ switch (mode) {
case RFIRST:
if (keyname)
err=table->file->index_first(table->record[0]);
@@ -193,12 +203,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, 1);
+ (void) item->save_in_field(key_part->field, 1);
key_len+=key_part->store_length;
}
if (!(key= (byte*) thd->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);
@@ -208,7 +218,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;
}
@@ -229,31 +239,31 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
if (!cond->val_int())
continue;
}
- if (num_rows>=offset_limit)
+ if (num_rows >= offset_limit)
{
if (!err)
{
String *packet = &thd->packet;
Item *item;
- packet->length(0);
+ protocol->prepare_for_resend();
it.rewind();
while ((item=it++))
{
- if (item->send(thd,packet))
+ if (item->send(thd->protocol, &buffer))
{
- packet->free(); // Free used
+ protocol->free(); // Free used
my_error(ER_OUT_OF_RESOURCES,MYF(0));
goto err;
}
}
- my_net_write(&thd->net, (char*)packet->ptr(), packet->length());
+ protocol->write();
}
}
num_rows++;
}
ok:
mysql_unlock_tables(thd,lock);
- send_eof(&thd->net);
+ send_eof(thd);
return 0;
err:
mysql_unlock_tables(thd,lock);
@@ -261,6 +271,7 @@ err0:
return -1;
}
+
static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
const char *table_name, bool is_alias)
{
@@ -270,15 +281,16 @@ static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
if (!db || ! *db)
db= thd->db ? thd->db : "";
dblen=strlen(db)+1;
- ptr=&(thd->handler_tables);
+ ptr= &(thd->handler_tables);
- for (TABLE *table=*ptr; table ; table=*ptr)
+ for (TABLE *table= *ptr; table ; table= *ptr)
{
if (!memcmp(table->table_cache_key, db, dblen) &&
- !my_strcasecmp((is_alias ? table->table_name : table->real_name),table_name))
+ !my_strcasecmp(system_charset_info,
+ (is_alias ? table->table_name : table->real_name),
+ table_name))
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..36c7ef87b17
--- /dev/null
+++ b/sql/sql_help.cc
@@ -0,0 +1,519 @@
+/* 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"
+
+struct st_find_field
+{
+ const char *table_name, *field_name;
+ Field *field;
+};
+
+/* Used fields */
+
+static struct st_find_field init_used_fields[]=
+{
+ { "help_topic", "name", 0},
+ { "help_topic","description", 0},
+ { "help_topic","example", 0},
+ { "help_topic", "help_topic_id", 0},
+ { "help_category","name", 0},
+ { "help_category","help_category_id", 0},
+ { "help_relation","help_topic_id", 0},
+ { "help_relation","help_category_id", 0}
+};
+
+enum enum_used_fields
+{
+ help_topic_name=0, help_topic_description, help_topic_example,
+ help_topic_help_topic_id,
+ help_category_name, help_category_help_category_id,
+ help_relation_help_topic_id, help_relation_help_category_id
+};
+
+/*
+ Fill local used field structure with pointer to fields */
+
+static bool init_fields(THD *thd, TABLE_LIST *tables,
+ struct st_find_field *find_field,
+ uint count)
+{
+ for (; count-- ; find_field++)
+ {
+ TABLE_LIST *not_used;
+ /* We have to use 'new' here as field will be re_linked on free */
+ Item_field *field= new Item_field("mysql", find_field->table_name,
+ find_field->field_name);
+ if (!(find_field->field= find_field_in_tables(thd, field, tables,
+ &not_used,
+ TRUE)))
+ return 1;
+ }
+ return 0;
+}
+
+
+#define help_charset &my_charset_latin1
+
+/*
+ Look for topics by mask
+
+ SYNOPSIS
+ search_topics()
+ thd Thread handler
+ topics Table of topic
+ select Function to test for if matching help topic.
+ Normally 'help_topic.name like 'bit%'
+ pfname Pointer to Field structure for field "name"
+ names List of founded topic's names (out)
+ name Name of founded topic (out),
+ Only set if founded exactly one topic)
+ description Description of founded topic (out)
+ Only set if founded exactly one topic.
+ example Example for founded topic (out)
+ Only if founded exactly one topic.
+ RETURN VALUES
+ # number of topics founded
+*/
+
+int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_field,
+ SQL_SELECT *select, List<char> *names,
+ char **name, char **description, char **example)
+{
+ DBUG_ENTER("search_functions");
+ int count= 0;
+
+ READ_RECORD read_record_info;
+ init_read_record(&read_record_info, thd, topics, select,1,0);
+ while (!read_record_info.read_record(&read_record_info))
+ {
+ if (!select->cond->val_int()) // Dosn't match like
+ continue;
+
+ char *lname= get_field(&thd->mem_root, find_field[help_topic_name].field);
+ count++;
+ if (count > 2)
+ {
+ names->push_back(lname);
+ }
+ else if (count == 1)
+ {
+ *description= get_field(&thd->mem_root,
+ find_field[help_topic_description].field);
+ *example= get_field(&thd->mem_root,
+ find_field[help_topic_example].field);
+ *name= lname;
+ }
+ else
+ {
+ names->push_back(*name);
+ names->push_back(lname);
+ *name= 0;
+ *description= 0;
+ *example= 0;
+ }
+ }
+ end_read_record(&read_record_info);
+ DBUG_RETURN(count);
+}
+
+/*
+ Look for categories by mask
+
+ SYNOPSIS
+ search_categories()
+ thd THD for init_read_record
+ categories Table of categories
+ select Function to test for if matching help topic.
+ Normally 'help_topic.name like 'bit%'
+ names List of founded topic's names (out)
+ res_id Primary index of founded category (only if
+ founded exactly one category)
+
+ RETURN VALUES
+ # Number of categories founded
+*/
+
+int search_categories(THD *thd, TABLE *categories,
+ struct st_find_field *find_fields,
+ SQL_SELECT *select, List<char> *names, int16 *res_id)
+{
+ Field *pfname= find_fields[help_category_name].field;
+ DBUG_ENTER("search_categories");
+ int count= 0;
+
+ READ_RECORD read_record_info;
+ init_read_record(&read_record_info, thd, categories, select,1,0);
+ while (!read_record_info.read_record(&read_record_info))
+ {
+ if (select && !select->cond->val_int())
+ continue;
+ char *lname= get_field(&thd->mem_root,pfname);
+ if (++count == 1 && res_id)
+ {
+ Field *pcat_id= find_fields[help_category_help_category_id].field;
+ *res_id= (int16) pcat_id->val_int();
+ }
+ names->push_back(lname);
+ }
+ end_read_record(&read_record_info);
+
+ DBUG_RETURN(count);
+}
+
+
+/*
+ Send to client rows in format:
+ column1 : <name>
+ column2 : <is_it_category>
+
+ SYNOPSIS
+ send_variant_2_list()
+ protocol Protocol for sending
+ names List of names
+ cat Value of the column <is_it_category>
+
+ RETURN VALUES
+ -1 Writing fail
+ 0 Data was successefully send
+*/
+
+int send_variant_2_list(Protocol *protocol, List<char> *names,
+ const char *cat)
+{
+ DBUG_ENTER("send_names");
+
+ List_iterator<char> it(*names);
+ const char *cur_name;
+ while ((cur_name= it++))
+ {
+ protocol->prepare_for_resend();
+ protocol->store(cur_name, system_charset_info);
+ protocol->store(cat, system_charset_info);
+ if (protocol->write())
+ DBUG_RETURN(-1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Look for all topics of category
+
+ SYNOPSIS
+ get_all_topics_for_category()
+ thd Thread handler
+ topics Table of topics
+ relations Table of m:m relation "topic/category"
+ cat_id Primary index looked for category
+ res List of founded topic's names (out)
+
+ RETURN VALUES
+ -1 corrupt database
+ 0 succesefull
+*/
+
+int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations,
+ struct st_find_field *find_fields,
+ int16 cat_id, List<char> *res)
+{
+ char buff[8]; // Max int length
+ DBUG_ENTER("get_all_topics_for_category");
+
+ int iindex_topic, iindex_relations;
+ Field *rtopic_id, *rcat_id;
+
+ if ((iindex_topic= find_type((char*) "PRIMARY",
+ &topics->keynames, 1+2)-1)<0 ||
+ (iindex_relations= find_type((char*) "PRIMARY",
+ &relations->keynames, 1+2)-1)<0)
+ {
+ send_error(thd,ER_CORRUPT_HELP_DB);
+ DBUG_RETURN(-1);
+ }
+ rtopic_id= find_fields[help_relation_help_topic_id].field;
+ rcat_id= find_fields[help_relation_help_category_id].field;
+
+ topics->file->index_init(iindex_topic);
+ relations->file->index_init(iindex_relations);
+
+ rcat_id->store((longlong) cat_id);
+ rcat_id->get_key_image(buff, rcat_id->pack_length(), help_charset,
+ Field::itRAW);
+ int key_res= relations->file->index_read(relations->record[0],
+ (byte *)buff, rcat_id->pack_length(),
+ HA_READ_KEY_EXACT);
+
+ for ( ; !key_res && cat_id == (int16) rcat_id->val_int() ;
+ key_res= relations->file->index_next(relations->record[0]))
+ {
+ char topic_id_buff[8];
+ longlong topic_id= rtopic_id->val_int();
+ Field *field= find_fields[help_topic_help_topic_id].field;
+ field->store((longlong) topic_id);
+ field->get_key_image(topic_id_buff, field->pack_length(), help_charset,
+ Field::itRAW);
+
+ if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff,
+ field->pack_length(),
+ HA_READ_KEY_EXACT))
+ res->push_back(get_field(&thd->mem_root,
+ find_fields[help_topic_name].field));
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Send to client answer for help request
+
+ SYNOPSIS
+ send_answer_1()
+ protocol - protocol for sending
+ s1 - value of column "Name"
+ s2 - value of column "Category"
+ s3 - value of column "Description"
+ s4 - value of column "Example"
+
+ IMPLEMENTATION
+ Format used:
+ +----------+---------+------------+------------+
+ |Name: |Category |Description |Example |
+ +----------+---------+------------+------------+
+ |String(64)|String(1)|String(1000)|String(1000)|
+ +----------+---------+------------+------------+
+ with exactly one row!
+
+ RETURN VALUES
+ 1 Writing of head failed
+ -1 Writing of row failed
+ 0 Successeful send
+*/
+
+int send_answer_1(Protocol *protocol, 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("Category",1));
+ field_list.push_back(new Item_empty_string("Description",1000));
+ field_list.push_back(new Item_empty_string("Example",1000));
+
+ if (protocol->send_fields(&field_list,1))
+ DBUG_RETURN(1);
+
+ protocol->prepare_for_resend();
+ protocol->store(s1, system_charset_info);
+ protocol->store(s2, system_charset_info);
+ protocol->store(s3, system_charset_info);
+ protocol->store(s4, system_charset_info);
+ if (protocol->write())
+ DBUG_RETURN(-1);
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Send to client help header
+
+ SYNOPSIS
+ send_header_2()
+ protocol - protocol for sending
+
+ IMPLEMENTATION
+ +----------+---------+
+ |Name: |Category |
+ +----------+---------+
+ |String(64)|String(1)|
+ +----------+---------+
+
+ RETURN VALUES
+ result of protocol->send_fields
+*/
+
+int send_header_2(Protocol *protocol)
+{
+ 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("Category",1));
+ DBUG_RETURN(protocol->send_fields(&field_list,1));
+}
+
+
+/*
+ Server-side function 'help'
+
+ SYNOPSIS
+ mysqld_help()
+ thd Thread handler
+
+ RETURN VALUES
+ 0 Success
+ 1 Error and send_error already commited
+ -1 error && send_error should be issued (normal case)
+*/
+
+int mysqld_help(THD *thd, const char *mask)
+{
+ Protocol *protocol= thd->protocol;
+ SQL_SELECT *select= 0, *select_cat= 0;
+ Item *cond_topic, *cond_cat;
+ st_find_field used_fields[array_elements(init_used_fields)];
+ DBUG_ENTER("mysqld_help");
+
+ TABLE_LIST tables[3];
+ bzero((gptr)tables,sizeof(tables));
+ tables[0].alias= tables[0].real_name= (char*) "help_topic";
+ tables[0].lock_type= TL_READ;
+ tables[0].db= (char*) "mysql";
+ tables[0].next= &tables[1];
+ tables[1].alias= tables[1].real_name= (char*) "help_category";
+ tables[1].lock_type= TL_READ;
+ tables[1].db= (char*) "mysql";
+ tables[1].next= &tables[2];
+ tables[2].alias= tables[2].real_name= (char*) "help_relation";
+ tables[2].lock_type= TL_READ;
+ tables[2].db= (char*) "mysql";
+ tables[2].next= 0;
+
+ List<char> function_list, categories_list;
+ char *name, *description, *example;
+ int res, count_topics, count_categories, error;
+
+ if (open_and_lock_tables(thd, tables))
+ {
+ res= -1;
+ goto end;
+ }
+ /* Init tables and fields to be usable from items */
+ setup_tables(tables);
+ memcpy((char*) used_fields, (char*) init_used_fields, sizeof(used_fields));
+ if (init_fields(thd, tables, used_fields, array_elements(used_fields)))
+ {
+ res= -1;
+ goto end;
+ }
+
+ /* TODO: Find out why these are needed (should not be) */
+ tables[0].table->file->init_table_handle_for_HANDLER();
+ tables[1].table->file->init_table_handle_for_HANDLER();
+ tables[2].table->file->init_table_handle_for_HANDLER();
+
+ cond_topic= new Item_func_like(new Item_field(used_fields[help_topic_name].
+ field),
+ new Item_string(mask, strlen(mask),
+ help_charset),
+ (char*) "\\");
+ cond_topic->fix_fields(thd, tables, &cond_topic); // can never fail
+ select= make_select(tables[0].table,0,0,cond_topic,&error);
+ if (error || (select && select->check_quick(0, HA_POS_ERROR)))
+ {
+ res= -1;
+ goto end;
+ }
+
+ cond_cat= new Item_func_like(new Item_field(used_fields[help_category_name].
+ field),
+ new Item_string(mask, strlen(mask),
+ help_charset),
+ (char*) "\\");
+ cond_cat->fix_fields(thd, tables, &cond_topic); // can never fail
+ select_cat= make_select(tables[1].table,0,0,cond_cat,&error);
+ if (error || (select_cat && select_cat->check_quick(0, HA_POS_ERROR)))
+ {
+ res= -1;
+ goto end;
+ }
+
+ res= 1;
+ count_topics= search_topics(thd,tables[0].table, used_fields, select,
+ &function_list, &name, &description, &example);
+ if (count_topics == 0)
+ {
+ int16 category_id;
+ Item *cond=
+ new Item_func_like(new
+ Item_field(used_fields[help_category_name].field),
+ new Item_string(mask, strlen(mask),
+ help_charset),
+ (char*) "\\");
+ (void) cond->fix_fields(thd, tables, &cond); // can never fail
+
+ count_categories= search_categories(thd, tables[1].table, used_fields,
+ select_cat, &categories_list,
+ &category_id);
+ if (count_categories == 1)
+ {
+ if (get_all_topics_for_category(thd,tables[0].table,
+ tables[2].table, used_fields,
+ category_id, &function_list))
+ {
+ res= -1;
+ goto end;
+ }
+ List_iterator<char> it(function_list);
+ char *cur_topic;
+ char buff[1024];
+ String example(buff, sizeof(buff), help_charset);
+ example.length(0);
+
+ while ((cur_topic= it++))
+ {
+ example.append(cur_topic);
+ example.append("\n",1);
+ }
+ if ((send_answer_1(protocol, categories_list.head(),
+ "Y","",example.ptr())))
+ goto end;
+ }
+ else
+ {
+ if (send_header_2(protocol))
+ goto end;
+ if (count_categories == 0)
+ search_categories(thd,tables[1].table, used_fields, (SQL_SELECT *) 0,
+ &categories_list, 0);
+ if (send_variant_2_list(protocol,&categories_list,"Y"))
+ goto end;
+ }
+ }
+ else if (count_topics == 1)
+ {
+ if (send_answer_1(protocol,name,"N",description, example))
+ goto end;
+ }
+ else
+ {
+ /* First send header and functions */
+ if (send_header_2(protocol) ||
+ send_variant_2_list(protocol, &function_list, "N"))
+ goto end;
+ search_categories(thd, tables[1].table, used_fields, select_cat,
+ &categories_list, 0);
+ /* Then send categories */
+ if (send_variant_2_list(protocol, &categories_list, "Y"))
+ goto end;
+ }
+ res= 0;
+
+ send_eof(thd);
+end:
+ delete select;
+ delete select_cat;
+ DBUG_RETURN(res);
+}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ace15771449..dcb39f8526f 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -47,7 +47,7 @@ static void unlink_blobs(register TABLE *table);
if timestamp should be updated or not.
*/
-static int
+int
check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
List<Item> &values, ulong counter)
{
@@ -83,7 +83,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
thd->dupp_field=0;
if (setup_tables(&table_list) ||
- setup_fields(thd,&table_list,fields,1,0,0))
+ setup_fields(thd, 0, &table_list,fields,1,0,0))
return -1;
if (thd->dupp_field)
{
@@ -101,8 +101,12 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
}
-int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
- List<List_item> &values_list,enum_duplicates duplic)
+int mysql_insert(THD *thd,TABLE_LIST *table_list,
+ List<Item> &fields,
+ List<List_item> &values_list,
+ List<Item> &update_fields,
+ List<Item> &update_values,
+ enum_duplicates duplic)
{
int error;
/*
@@ -122,6 +126,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
List_item *values;
char *query=thd->query;
thr_lock_type lock_type = table_list->lock_type;
+ TABLE_LIST *insert_table_list= (TABLE_LIST*)
+ thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_insert");
if (thd->master_access & SUPER_ACL)
@@ -140,9 +146,12 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if ((lock_type == TL_WRITE_DELAYED &&
((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
thd->slave_thread || !max_insert_delayed_threads)) ||
- (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE))
+ (lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) ||
+ (duplic == DUP_UPDATE))
lock_type=TL_WRITE;
+ table_list->lock_type= lock_type;
+ int res;
if (lock_type == TL_WRITE_DELAYED)
{
if (thd->locked_tables)
@@ -157,21 +166,40 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
DBUG_RETURN(-1);
}
}
- if (!(table = delayed_get_table(thd,table_list)) && !thd->fatal_error)
- table = open_ltable(thd,table_list,lock_type=thd->update_lock_default);
+ if ((table= delayed_get_table(thd,table_list)) && !thd->is_fatal_error)
+ if (table_list->next && table)
+ res= open_and_lock_tables(thd, table_list->next);
+ else
+ res= (table == 0);
+ else
+ res= open_and_lock_tables(thd, table_list);
}
else
- table = open_ltable(thd,table_list,lock_type);
- if (!table)
+ res= open_and_lock_tables(thd, table_list);
+ if (res)
DBUG_RETURN(-1);
+ fix_tables_pointers(thd->lex.all_selects_list);
+
+ table= table_list->table;
thd->proc_info="init";
thd->used_tables=0;
values= its++;
if (check_insert_fields(thd,table,fields,*values,1) ||
- setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0))
+ setup_tables(insert_table_list) ||
+ setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
+ (duplic == DUP_UPDATE &&
+ (setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) ||
+ setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0))))
+ goto abort;
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
goto abort;
+ }
+
value_count= values->elements;
- while ((values = its++))
+ while ((values= its++))
{
counter++;
if (values->elements != value_count)
@@ -181,7 +209,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
MYF(0),counter);
goto abort;
}
- if (setup_fields(thd,table_list,*values,0,0,0))
+ if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0))
goto abort;
}
its.rewind ();
@@ -191,6 +219,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
info.records=info.deleted=info.copied=0;
info.handle_duplicates=duplic;
+ info.update_fields=&update_fields;
+ info.update_values=&update_values;
// Don't count warnings for simple inserts
if (values_list.elements > 1 || (thd->options & OPTION_WARNINGS))
thd->count_cuted_fields = 1;
@@ -200,7 +230,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
error=0;
id=0;
thd->proc_info="update";
- if (duplic == DUP_IGNORE || duplic == DUP_REPLACE)
+ if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if ((lock_type != TL_WRITE_DELAYED && !(specialflag & SPECIAL_SAFE_MODE)) &&
values_list.elements >= MIN_ROWS_TO_USE_BULK_INSERT)
@@ -219,9 +249,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
if (fields.elements || !value_count)
{
restore_record(table,2); // Get empty record
- if (fill_record(fields,*values) || check_null_fields(thd,table))
+ if (fill_record(fields,*values)|| thd->net.report_error ||
+ check_null_fields(thd,table))
{
- if (values_list.elements != 1)
+ if (values_list.elements != 1 && !thd->net.report_error)
{
info.records++;
continue;
@@ -236,9 +267,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
restore_record(table,2); // Get empty record
else
table->record[0][0]=table->record[2][0]; // Fix delete marker
- if (fill_record(table->field,*values))
+ if (fill_record(table->field,*values) || thd->net.report_error)
{
- if (values_list.elements != 1)
+ if (values_list.elements != 1 && ! thd->net.report_error)
{
info.records++;
continue;
@@ -339,14 +370,14 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
table->next_number_field=0;
thd->count_cuted_fields=0;
thd->next_insert_id=0; // Reset this if wrongly used
- if (duplic == DUP_IGNORE || duplic == DUP_REPLACE)
+ if (duplic != DUP_ERROR)
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
if (error)
goto abort;
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];
@@ -358,13 +389,15 @@ 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);
}
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(0);
abort:
if (lock_type == TL_WRITE_DELAYED)
end_delayed_insert(thd);
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
@@ -391,7 +424,8 @@ int write_record(TABLE *table,COPY_INFO *info)
char *key=0;
info->records++;
- if (info->handle_duplicates == DUP_REPLACE)
+ if (info->handle_duplicates == DUP_REPLACE ||
+ info->handle_duplicates == DUP_UPDATE)
{
while ((error=table->file->write_row(table->record[0])))
{
@@ -408,7 +442,9 @@ int write_record(TABLE *table,COPY_INFO *info)
was used. This ensures that we don't get a problem when the
whole range of the key has been used.
*/
- if (table->next_number_field && key_nr == table->next_number_index &&
+ if (info->handle_duplicates == DUP_REPLACE &&
+ table->next_number_field &&
+ key_nr == table->next_number_index &&
table->file->auto_increment_column_changed)
goto err;
if (table->file->table_flags() & HA_DUPP_POS)
@@ -440,16 +476,33 @@ int write_record(TABLE *table,COPY_INFO *info)
HA_READ_KEY_EXACT))))
goto err;
}
- if (last_uniq_key(table,key_nr))
+ if (info->handle_duplicates == DUP_UPDATE)
{
- if ((error=table->file->update_row(table->record[1],table->record[0])))
- goto err;
- info->deleted++;
- break; /* Update logfile and count */
+ /* we don't check for other UNIQUE keys - the first row
+ that matches, is updated. If update causes a conflict again,
+ an error is returned
+ */
+ restore_record(table,1);
+ if (fill_record(*info->update_fields,*info->update_values))
+ goto err;
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto err;
+ info->deleted++;
+ break;
+ }
+ else /* DUP_REPLACE */
+ {
+ if (last_uniq_key(table,key_nr))
+ {
+ if ((error=table->file->update_row(table->record[1],table->record[0])))
+ goto err;
+ info->deleted++;
+ break; /* Update logfile and count */
+ }
+ else if ((error=table->file->delete_row(table->record[1])))
+ goto err;
+ info->deleted++;
}
- else if ((error=table->file->delete_row(table->record[1])))
- goto err;
- info->deleted++;
}
info->copied++;
}
@@ -649,7 +702,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
{
if (!(tmp=new delayed_insert()))
{
- thd->fatal_error=1;
+ thd->fatal_error();
my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert));
pthread_mutex_unlock(&LOCK_delayed_create);
DBUG_RETURN(0);
@@ -661,7 +714,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
!(tmp->thd.query=my_strdup(table_list->real_name,MYF(MY_WME))))
{
delete tmp;
- thd->fatal_error=1;
+ thd->fatal_error();
my_error(ER_OUT_OF_RESOURCES,MYF(0));
pthread_mutex_unlock(&LOCK_delayed_create);
DBUG_RETURN(0);
@@ -680,9 +733,9 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
pthread_mutex_unlock(&tmp->mutex);
tmp->unlock();
delete tmp;
- thd->fatal_error=1;
+ thd->fatal_error();
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);
}
@@ -696,10 +749,10 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
thd->proc_info="got old table";
if (tmp->thd.killed)
{
- if (tmp->thd.fatal_error)
+ if (tmp->thd.is_fatal_error)
{
/* Copy error message and abort */
- thd->fatal_error=1;
+ thd->fatal_error();
strmov(thd->net.last_error,tmp->thd.net.last_error);
thd->net.last_errno=tmp->thd.net.last_errno;
}
@@ -723,8 +776,8 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
tmp->unlock();
if (table)
thd->di=tmp;
- else if (tmp->thd.fatal_error)
- thd->fatal_error=1;
+ else if (tmp->thd.is_fatal_error)
+ thd->fatal_error();
DBUG_RETURN((table_list->table=table));
}
@@ -952,7 +1005,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
DBUG_ENTER("handle_delayed_insert");
if (init_thr_lock() || thd->store_globals())
{
- thd->fatal_error=1;
+ thd->fatal_error();
strmov(thd->net.last_error,ER(thd->net.last_errno=ER_OUT_OF_RESOURCES));
goto end;
}
@@ -966,12 +1019,12 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
if (!(di->table=open_ltable(thd,&di->table_list,TL_WRITE_DELAYED)))
{
- thd->fatal_error=1; // Abort waiting inserts
+ thd->fatal_error(); // Abort waiting inserts
goto end;
}
if (di->table->file->has_transactions())
{
- thd->fatal_error=1;
+ thd->fatal_error();
my_error(ER_ILLEGAL_HA, MYF(0), di->table_list.real_name);
goto end;
}
@@ -1193,7 +1246,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
@@ -1288,10 +1341,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;
if (check_insert_fields(thd,table,*fields,values,1))
DBUG_RETURN(1);
@@ -1321,16 +1375,16 @@ 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)
fill_record(*fields,values);
else
fill_record(table->field,values);
- if (write_record(table,&info))
+ if (thd->net.report_error || write_record(table,&info))
return 1;
if (table->next_number_field) // Clear for next record
{
@@ -1344,7 +1398,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);
@@ -1378,7 +1433,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
@@ -1392,7 +1448,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);
return 0;
}
@@ -1404,10 +1460,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,13 +1493,13 @@ 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);
- if (write_record(table,&info))
+ if (thd->net.report_error ||write_record(table,&info))
return 1;
if (table->next_number_field) // Clear for next record
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index d5a225d95dd..378aa380a3c 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -75,8 +75,6 @@ inline int lex_casecmp(const char *s, const char *t, uint len)
#include "lex_hash.h"
-static uchar state_map[256];
-
void lex_init(void)
{
@@ -89,42 +87,6 @@ void lex_init(void)
VOID(pthread_key_create(&THR_LEX,NULL));
- /* Fill state_map with states to get a faster parser */
- for (i=0; i < 256 ; i++)
- {
- if (isalpha(i))
- state_map[i]=(uchar) STATE_IDENT;
- else if (isdigit(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))
- state_map[i]=(uchar) STATE_IDENT;
-#endif
- else if (!isgraph(i))
- state_map[i]=(uchar) STATE_SKIP;
- else
- state_map[i]=(uchar) STATE_CHAR;
- }
- state_map[(uchar)'_']=state_map[(uchar)'$']=(uchar) STATE_IDENT;
- state_map[(uchar)'\'']=state_map[(uchar)'"']=(uchar) STATE_STRING;
- state_map[(uchar)'-']=state_map[(uchar)'+']=(uchar) STATE_SIGNED_NUMBER;
- state_map[(uchar)'.']=(uchar) STATE_REAL_OR_POINT;
- state_map[(uchar)'>']=state_map[(uchar)'=']=state_map[(uchar)'!']= (uchar) STATE_CMP_OP;
- state_map[(uchar)'<']= (uchar) STATE_LONG_CMP_OP;
- state_map[(uchar)'&']=state_map[(uchar)'|']=(uchar) STATE_BOOL;
- state_map[(uchar)'#']=(uchar) STATE_COMMENT;
- state_map[(uchar)';']=(uchar) STATE_COLON;
- state_map[(uchar)':']=(uchar) STATE_SET_VAR;
- state_map[0]=(uchar) STATE_EOL;
- state_map[(uchar)'\\']= (uchar) STATE_ESCAPE;
- state_map[(uchar)'/']= (uchar) STATE_LONG_COMMENT;
- state_map[(uchar)'*']= (uchar) STATE_END_LONG_COMMENT;
- state_map[(uchar)'@']= (uchar) STATE_USER_END;
- state_map[(uchar) '`']= (uchar) STATE_USER_VARIABLE_DELIMITER;
- if (opt_sql_mode & MODE_ANSI_QUOTES)
- {
- state_map[(uchar) '"'] = STATE_USER_VARIABLE_DELIMITER;
- }
DBUG_VOID_RETURN;
}
@@ -136,29 +98,36 @@ void lex_free(void)
}
+/*
+ This is called before every query that is to be parsed.
+ Because of this, it's critical to not do too much things here.
+ (We already do too much here)
+*/
+
LEX *lex_start(THD *thd, uchar *buf,uint length)
{
LEX *lex= &thd->lex;
- lex->next_state=STATE_START;
+ lex->next_state=MY_LEX_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->current_select= &lex->select_lex;
+ lex->convert_set= (lex->thd= thd)->variables.convert_set;
+ lex->thd_charset= lex->thd->variables.thd_charset;
lex->yacc_yyss=lex->yacc_yyvs=0;
- lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE);
- lex->slave_thd_opt=0;
+ lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
lex->sql_command=SQLCOM_END;
- bzero(&lex->mi,sizeof(lex->mi));
return lex;
}
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);
}
@@ -180,7 +149,7 @@ static int find_keyword(LEX *lex, uint len, bool function)
udf_func *udf;
if (function && using_udf_functions && (udf=find_udf((char*) tok, len)))
{
- lex->thd->safe_to_cache_query=0;
+ lex->safe_to_cache_query=0;
lex->yylval->udf=udf;
switch (udf->returns) {
case STRING_RESULT:
@@ -189,6 +158,11 @@ static int find_keyword(LEX *lex, uint len, bool function)
return (udf->type == UDFTYPE_FUNCTION) ? UDF_FLOAT_FUNC : UDA_FLOAT_SUM;
case INT_RESULT:
return (udf->type == UDFTYPE_FUNCTION) ? UDF_INT_FUNC : UDA_INT_SUM;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
}
#endif
@@ -198,7 +172,7 @@ static int find_keyword(LEX *lex, uint len, bool function)
/* make a copy of token before ptr and set yytoklen */
-LEX_STRING get_token(LEX *lex,uint length)
+static LEX_STRING get_token(LEX *lex,uint length)
{
LEX_STRING tmp;
yyUnget(); // ptr points now after last token char
@@ -207,13 +181,35 @@ LEX_STRING get_token(LEX *lex,uint length)
return tmp;
}
-/* Return an unescaped text literal without quotes */
-/* Fix sometimes to do only one scan of the string */
+static LEX_STRING get_quoted_token(LEX *lex,uint length, char quote)
+{
+ LEX_STRING tmp;
+ byte *from, *to, *end;
+ yyUnget(); // ptr points now after last token char
+ tmp.length=lex->yytoklen=length;
+ tmp.str=(char*) lex->thd->alloc(tmp.length+1);
+ for (from= (byte*) lex->tok_start, to= (byte*) tmp.str, end= to+length ;
+ to != end ;
+ )
+ {
+ if ((*to++= *from++) == quote)
+ from++; // Skip double quotes
+ }
+ *to= 0; // End null for safety
+ return tmp;
+}
+
+
+/*
+ Return an unescaped text literal without quotes
+ Fix sometimes to do only one scan of the string
+*/
static char *get_text(LEX *lex)
{
reg1 uchar c,sep;
uint found_escape=0;
+ CHARSET_INFO *cs= lex->thd->variables.thd_charset;
sep= yyGetLast(); // String should end with this
//lex->tok_start=lex->ptr-1; // Remember '
@@ -222,8 +218,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(cs) &&
+ (l = my_ismbchar(cs,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query))) {
lex->ptr += l-1;
@@ -267,8 +263,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(cs) &&
+ (l = my_ismbchar(cs,
(const char *)str, (const char *)end))) {
while (l--)
*to++ = *str++;
@@ -315,8 +311,6 @@ static char *get_text(LEX *lex)
*to=0;
lex->yytoklen=(uint) (to-start);
}
- if (lex->convert_set)
- lex->convert_set->convert((char*) start,lex->yytoklen);
return (char*) start;
}
}
@@ -416,83 +410,88 @@ inline static uint int_token(const char *str,uint length)
// yylex remember the following states from the following yylex()
-// STATE_EOQ ; found end of query
-// STATE_OPERATOR_OR_IDENT ; last state was an ident, text or number
+// MY_LEX_EOQ ; found end of query
+// MY_LEX_OPERATOR_OR_IDENT ; last state was an ident, text or number
// (which can't be followed by a signed number)
-int yylex(void *arg)
+int yylex(void *arg, void *yythd)
{
reg1 uchar c;
int tokval;
uint length;
- enum lex_states state,prev_state;
- LEX *lex=current_lex;
+ enum my_lex_states state,prev_state;
+ LEX *lex= &(((THD *)yythd)->lex);
YYSTYPE *yylval=(YYSTYPE*) arg;
+ CHARSET_INFO *cs= ((THD *) yythd)->variables.thd_charset;
+ uchar *state_map= cs->state_map;
+ uchar *ident_map= cs->ident_map;
lex->yylval=yylval; // The global state
lex->tok_start=lex->tok_end=lex->ptr;
prev_state=state=lex->next_state;
- lex->next_state=STATE_OPERATOR_OR_IDENT;
+ lex->next_state=MY_LEX_OPERATOR_OR_IDENT;
LINT_INIT(c);
for (;;)
{
- switch(state) {
- case STATE_OPERATOR_OR_IDENT: // Next is operator or keyword
- case STATE_START: // Start of token
+ switch (state) {
+ case MY_LEX_OPERATOR_OR_IDENT: // Next is operator or keyword
+ case MY_LEX_START: // Start of token
// Skip startspace
- for (c=yyGet() ; (state_map[c] == STATE_SKIP) ; c= yyGet())
+ for (c=yyGet() ; (state_map[c] == MY_LEX_SKIP) ; c= yyGet())
{
if (c == '\n')
lex->yylineno++;
}
lex->tok_start=lex->ptr-1; // Start of real token
- state= (enum lex_states) state_map[c];
+ state= (enum my_lex_states) state_map[c];
break;
- case STATE_ESCAPE:
+ case MY_LEX_ESCAPE:
if (yyGet() == 'N')
{ // Allow \N as shortcut for NULL
yylval->lex_str.str=(char*) "\\N";
yylval->lex_str.length=2;
return NULL_SYM;
}
- case STATE_CHAR: // Unknown or single char token
- case STATE_SKIP: // This should not happen
- yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first char
+ case MY_LEX_CHAR: // Unknown or single char token
+ case MY_LEX_SKIP: // This should not happen
+ yylval->lex_str.str=(char*) (lex->ptr=lex->tok_start);// Set to first chr
yylval->lex_str.length=1;
c=yyGet();
if (c != ')')
- lex->next_state= STATE_START; // Allow signed numbers
+ lex->next_state= MY_LEX_START; // Allow signed numbers
if (c == ',')
lex->tok_start=lex->ptr; // Let tok_start point at next item
return((int) c);
- case STATE_IDENT: // Incomplete keyword or ident
- if ((c == 'x' || c == 'X') && yyPeek() == '\'')
+ case MY_LEX_IDENT_OR_HEX:
+ if (yyPeek() == '\'')
{ // Found x'hex-number'
- state=STATE_HEX_NUMBER;
+ state= MY_LEX_HEX_NUMBER;
break;
}
+ /* Fall through */
+ case MY_LEX_IDENT_OR_BIN: // TODO: Add binary string handling
+ case MY_LEX_IDENT:
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(cs))
{
- if (my_ismbhead(default_charset_info, yyGetLast()))
+ if (my_ismbhead(cs, yyGetLast()))
{
- int l = my_ismbchar(default_charset_info,
+ int l = my_ismbchar(cs,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query);
if (l == 0) {
- state = STATE_CHAR;
+ state = MY_LEX_CHAR;
continue;
}
lex->ptr += l - 1;
}
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT)
+ while (ident_map[c=yyGet()])
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(cs, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(cs,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -502,22 +501,20 @@ int yylex(void *arg)
}
else
#endif
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT) ;
+ while (ident_map[c=yyGet()]) ;
length= (uint) (lex->ptr - lex->tok_start)-1;
if (lex->ignore_space)
{
- for (; state_map[c] == STATE_SKIP ; c= yyGet());
+ for (; state_map[c] == MY_LEX_SKIP ; c= yyGet());
}
- if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
- state_map[yyPeek()] == STATE_NUMBER_IDENT))
- lex->next_state=STATE_IDENT_SEP;
+ if (c == '.' && ident_map[yyPeek()])
+ lex->next_state=MY_LEX_IDENT_SEP;
else
{ // '(' must follow directly if function
yyUnget();
if ((tokval = find_keyword(lex,length,c == '(')))
{
- lex->next_state= STATE_START; // Allow signed numbers
+ lex->next_state= MY_LEX_START; // Allow signed numbers
return(tokval); // Was keyword
}
yySkip(); // next state does a unget
@@ -525,31 +522,45 @@ 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);
- case STATE_IDENT_SEP: // Found ident and now '.'
- lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
+ /*
+ 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_csname(yylval->lex_str.str+1,
+ MY_CS_PRIMARY,MYF(0))))
+ return(UNDERSCORE_CHARSET);
+ else
+ return(IDENT);
+
+ case MY_LEX_IDENT_SEP: // Found ident and now '.'
+ lex->next_state=MY_LEX_IDENT_START;// Next is an ident (not a keyword)
yylval->lex_str.str=(char*) lex->ptr;
yylval->lex_str.length=1;
c=yyGet(); // should be '.'
return((int) c);
- case STATE_NUMBER_IDENT: // number or ident which num-start
- while (isdigit((c = yyGet()))) ;
- if (state_map[c] != STATE_IDENT)
+ case MY_LEX_NUMBER_IDENT: // number or ident which num-start
+ while (my_isdigit(cs,(c = yyGet()))) ;
+ if (!ident_map[c])
{ // Can't be identifier
- state=STATE_INT_OR_REAL;
+ state=MY_LEX_INT_OR_REAL;
break;
}
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(cs,yyPeek()) ||
+ (c=(yyGet())) == '+' || c == '-')
{ // Allow 1E+10
- if (isdigit(yyPeek())) // Number must have digit after sign
+ if (my_isdigit(cs,yyPeek())) // Number must have digit after sign
{
yySkip();
- while (isdigit(yyGet())) ;
+ while (my_isdigit(cs,yyGet())) ;
yylval->lex_str=get_token(lex,yyLength());
return(FLOAT_NUM);
}
@@ -559,8 +570,8 @@ int yylex(void *arg)
else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
lex->tok_start[0] == '0' )
{ // Varbinary
- while (isxdigit((c = yyGet()))) ;
- if ((lex->ptr - lex->tok_start) >= 4 && state_map[c] != STATE_IDENT)
+ while (my_isxdigit(cs,(c = yyGet()))) ;
+ if ((lex->ptr - lex->tok_start) >= 4 && !ident_map[c])
{
yylval->lex_str=get_token(lex,yyLength());
yylval->lex_str.str+=2; // Skip 0x
@@ -571,29 +582,28 @@ int yylex(void *arg)
yyUnget();
}
// fall through
- case STATE_IDENT_START: // Incomplete ident
+ case MY_LEX_IDENT_START: // Incomplete ident
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(cs))
{
- if (my_ismbhead(default_charset_info, yyGetLast()))
+ if (my_ismbhead(cs, yyGetLast()))
{
- int l = my_ismbchar(default_charset_info,
+ int l = my_ismbchar(cs,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query);
if (l == 0)
{
- state = STATE_CHAR;
+ state = MY_LEX_CHAR;
continue;
}
lex->ptr += l - 1;
}
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT)
+ while (ident_map[c=yyGet()])
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(cs, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(cs,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -603,112 +613,130 @@ int yylex(void *arg)
}
else
#endif
- while (state_map[c = yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT) ;
+ while (ident_map[c = yyGet()]) ;
- if (c == '.' && (state_map[yyPeek()] == STATE_IDENT ||
- state_map[yyPeek()] == STATE_NUMBER_IDENT))
- lex->next_state=STATE_IDENT_SEP;// Next is '.'
+ if (c == '.' && ident_map[yyPeek()])
+ lex->next_state=MY_LEX_IDENT_SEP;// Next is '.'
// fall through
- case STATE_FOUND_IDENT: // Complete ident
+ case MY_LEX_FOUND_IDENT: // Complete ident
yylval->lex_str=get_token(lex,yyLength());
if (lex->convert_set)
lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(IDENT);
- case STATE_USER_VARIABLE_DELIMITER:
+ case MY_LEX_USER_VARIABLE_DELIMITER:
+ {
+ char delim= c; // Used char
lex->tok_start=lex->ptr; // Skip first `
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ if (use_mb(cs))
{
- while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
- c != (uchar) NAMES_SEP_CHAR)
+ while ((c=yyGet()) && c != delim && c != (uchar) NAMES_SEP_CHAR)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(cs, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(cs,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
lex->ptr += l-1;
}
}
+ yylval->lex_str=get_token(lex,yyLength());
}
else
#endif
{
- while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
- c != (uchar) NAMES_SEP_CHAR) ;
+ uint double_quotes= 0;
+ char quote_char= c;
+ while ((c=yyGet()))
+ {
+ if (c == quote_char)
+ {
+ if (yyPeek() != quote_char)
+ break;
+ c=yyGet();
+ double_quotes++;
+ continue;
+ }
+ if (c == (uchar) NAMES_SEP_CHAR)
+ break;
+ }
+ if (double_quotes)
+ yylval->lex_str=get_quoted_token(lex,yyLength() - double_quotes,
+ quote_char);
+ else
+ yylval->lex_str=get_token(lex,yyLength());
}
- yylval->lex_str=get_token(lex,yyLength());
if (lex->convert_set)
lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
- if (state_map[c] == STATE_USER_VARIABLE_DELIMITER)
+ if (c == delim)
yySkip(); // Skip end `
return(IDENT);
-
- case STATE_SIGNED_NUMBER: // Incomplete signed number
- if (prev_state == STATE_OPERATOR_OR_IDENT)
+ }
+ case MY_LEX_SIGNED_NUMBER: // Incomplete signed number
+ if (prev_state == MY_LEX_OPERATOR_OR_IDENT)
{
if (c == '-' && yyPeek() == '-' &&
- (isspace(yyPeek2()) || iscntrl(yyPeek2())))
- state=STATE_COMMENT;
+ (my_isspace(cs,yyPeek2()) ||
+ my_iscntrl(cs,yyPeek2())))
+ state=MY_LEX_COMMENT;
else
- state= STATE_CHAR; // Must be operator
+ state= MY_LEX_CHAR; // Must be operator
break;
}
- if (!isdigit(c=yyGet()) || yyPeek() == 'x')
+ if (!my_isdigit(cs,c=yyGet()) || yyPeek() == 'x')
{
if (c != '.')
{
- if (c == '-' && isspace(yyPeek()))
- state=STATE_COMMENT;
+ if (c == '-' && my_isspace(cs,yyPeek()))
+ state=MY_LEX_COMMENT;
else
- state = STATE_CHAR; // Return sign as single char
+ state = MY_LEX_CHAR; // Return sign as single char
break;
}
yyUnget(); // Fix for next loop
}
- while (isdigit(c=yyGet())) ; // Incomplete real or int number
+ while (my_isdigit(cs,c=yyGet())) ; // Incomplete real or int number
if ((c == 'e' || c == 'E') &&
- (yyPeek() == '+' || yyPeek() == '-' || isdigit(yyPeek())))
+ (yyPeek() == '+' || yyPeek() == '-' || my_isdigit(cs,yyPeek())))
{ // Real number
yyUnget();
c= '.'; // Fool next test
}
// fall through
- case STATE_INT_OR_REAL: // Compleat int or incompleat real
+ case MY_LEX_INT_OR_REAL: // Compleat int or incompleat real
if (c != '.')
{ // Found complete integer number.
yylval->lex_str=get_token(lex,yyLength());
return int_token(yylval->lex_str.str,yylval->lex_str.length);
}
// fall through
- case STATE_REAL: // Incomplete real number
- while (isdigit(c = yyGet())) ;
+ case MY_LEX_REAL: // Incomplete real number
+ while (my_isdigit(cs,c = yyGet())) ;
if (c == 'e' || c == 'E')
{
c = yyGet();
if (c == '-' || c == '+')
c = yyGet(); // Skip sign
- if (!isdigit(c))
+ if (!my_isdigit(cs,c))
{ // No digit after sign
- state= STATE_CHAR;
+ state= MY_LEX_CHAR;
break;
}
- while (isdigit(yyGet())) ;
+ while (my_isdigit(cs,yyGet())) ;
yylval->lex_str=get_token(lex,yyLength());
return(FLOAT_NUM);
}
yylval->lex_str=get_token(lex,yyLength());
return(REAL_NUM);
- case STATE_HEX_NUMBER: // Found x'hexstring'
+ case MY_LEX_HEX_NUMBER: // Found x'hexstring'
yyGet(); // Skip '
- while (isxdigit((c = yyGet()))) ;
+ while (my_isxdigit(cs,(c = yyGet()))) ;
length=(lex->ptr - lex->tok_start); // Length of hexnum+3
if (!(length & 1) || c != '\'')
{
@@ -721,64 +749,73 @@ int yylex(void *arg)
lex->yytoklen-=3;
return (HEX_NUM);
- case STATE_CMP_OP: // Incomplete comparison operator
- if (state_map[yyPeek()] == STATE_CMP_OP ||
- state_map[yyPeek()] == STATE_LONG_CMP_OP)
+ case MY_LEX_CMP_OP: // Incomplete comparison operator
+ if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
+ state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
yySkip();
if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
{
- lex->next_state= STATE_START; // Allow signed numbers
+ lex->next_state= MY_LEX_START; // Allow signed numbers
return(tokval);
}
- state = STATE_CHAR; // Something fishy found
+ state = MY_LEX_CHAR; // Something fishy found
break;
- case STATE_LONG_CMP_OP: // Incomplete comparison operator
- if (state_map[yyPeek()] == STATE_CMP_OP ||
- state_map[yyPeek()] == STATE_LONG_CMP_OP)
+ case MY_LEX_LONG_CMP_OP: // Incomplete comparison operator
+ if (state_map[yyPeek()] == MY_LEX_CMP_OP ||
+ state_map[yyPeek()] == MY_LEX_LONG_CMP_OP)
{
yySkip();
- if (state_map[yyPeek()] == STATE_CMP_OP)
+ if (state_map[yyPeek()] == MY_LEX_CMP_OP)
yySkip();
}
if ((tokval = find_keyword(lex,(uint) (lex->ptr - lex->tok_start),0)))
{
- lex->next_state= STATE_START; // Found long op
+ lex->next_state= MY_LEX_START; // Found long op
return(tokval);
}
- state = STATE_CHAR; // Something fishy found
+ state = MY_LEX_CHAR; // Something fishy found
break;
- case STATE_BOOL:
+ case MY_LEX_BOOL:
if (c != yyPeek())
{
- state=STATE_CHAR;
+ state=MY_LEX_CHAR;
break;
}
yySkip();
tokval = find_keyword(lex,2,0); // Is a bool operator
- lex->next_state= STATE_START; // Allow signed numbers
+ lex->next_state= MY_LEX_START; // Allow signed numbers
return(tokval);
- case STATE_STRING: // Incomplete text string
+ case MY_LEX_STRING_OR_DELIMITER:
+ if (((THD *) yythd)->variables.sql_mode & MODE_ANSI_QUOTES)
+ {
+ state= MY_LEX_USER_VARIABLE_DELIMITER;
+ break;
+ }
+ /* " used for strings */
+ case MY_LEX_STRING: // Incomplete text string
if (!(yylval->lex_str.str = get_text(lex)))
{
- state= STATE_CHAR; // Read char by char
+ state= MY_LEX_CHAR; // Read char by char
break;
}
yylval->lex_str.length=lex->yytoklen;
+ if (lex->convert_set)
+ lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen);
return(TEXT_STRING);
- case STATE_COMMENT: // Comment
+ case MY_LEX_COMMENT: // Comment
lex->select_lex.options|= OPTION_FOUND_COMMENT;
while ((c = yyGet()) != '\n' && c) ;
yyUnget(); // Safety against eof
- state = STATE_START; // Try again
+ state = MY_LEX_START; // Try again
break;
- case STATE_LONG_COMMENT: /* Long C comment? */
+ case MY_LEX_LONG_COMMENT: /* Long C comment? */
if (yyPeek() != '*')
{
- state=STATE_CHAR; // Probable division
+ state=MY_LEX_CHAR; // Probable division
break;
}
yySkip(); // Skip '*'
@@ -787,8 +824,8 @@ int yylex(void *arg)
{
ulong version=MYSQL_VERSION_ID;
yySkip();
- state=STATE_START;
- if (isdigit(yyPeek()))
+ state=MY_LEX_START;
+ if (my_isdigit(cs,yyPeek()))
{ // Version number
version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
}
@@ -806,89 +843,96 @@ int yylex(void *arg)
}
if (lex->ptr != lex->end_of_query)
yySkip(); // remove last '/'
- state = STATE_START; // Try again
+ state = MY_LEX_START; // Try again
break;
- case STATE_END_LONG_COMMENT:
+ case MY_LEX_END_LONG_COMMENT:
if (lex->in_comment && yyPeek() == '/')
{
yySkip();
lex->in_comment=0;
- state=STATE_START;
+ state=MY_LEX_START;
}
else
- state=STATE_CHAR; // Return '*'
+ state=MY_LEX_CHAR; // Return '*'
break;
- case STATE_SET_VAR: // Check if ':='
+ case MY_LEX_SET_VAR: // Check if ':='
if (yyPeek() != '=')
{
- state=STATE_CHAR; // Return ':'
+ state=MY_LEX_CHAR; // Return ':'
break;
}
yySkip();
return (SET_VAR);
- case STATE_COLON: // optional line terminator
+ case MY_LEX_COLON: // optional line terminator
if (yyPeek())
{
- state=STATE_CHAR; // Return ';'
+ if (((THD *)yythd)->client_capabilities & CLIENT_MULTI_QUERIES)
+ {
+ lex->found_colon=(char*)lex->ptr;
+ ((THD *)yythd)->server_status |= SERVER_MORE_RESULTS_EXISTS;
+ lex->next_state=MY_LEX_END;
+ return(END_OF_INPUT);
+ }
+ else
+ state=MY_LEX_CHAR; // Return ';'
break;
}
/* fall true */
- case STATE_EOL:
- lex->next_state=STATE_END; // Mark for next loop
+ case MY_LEX_EOL:
+ lex->next_state=MY_LEX_END; // Mark for next loop
return(END_OF_INPUT);
- case STATE_END:
- lex->next_state=STATE_END;
+ case MY_LEX_END:
+ lex->next_state=MY_LEX_END;
return(0); // We found end of input last time
-
- // Actually real shouldn't start
- // with . but allow them anyhow
- case STATE_REAL_OR_POINT:
- if (isdigit(yyPeek()))
- state = STATE_REAL; // Real
+
+ /* Actually real shouldn't start with . but allow them anyhow */
+ case MY_LEX_REAL_OR_POINT:
+ if (my_isdigit(cs,yyPeek()))
+ state = MY_LEX_REAL; // Real
else
{
- state = STATE_CHAR; // return '.'
- lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword)
+ state = MY_LEX_CHAR; // return '.'
+ lex->next_state=MY_LEX_IDENT_START;// Next is an ident (not a keyword)
}
break;
- case STATE_USER_END: // end '@' of user@hostname
+ case MY_LEX_USER_END: // end '@' of user@hostname
switch (state_map[yyPeek()]) {
- case STATE_STRING:
- case STATE_USER_VARIABLE_DELIMITER:
+ case MY_LEX_STRING:
+ case MY_LEX_USER_VARIABLE_DELIMITER:
+ case MY_LEX_STRING_OR_DELIMITER:
break;
- case STATE_USER_END:
- lex->next_state=STATE_SYSTEM_VAR;
+ case MY_LEX_USER_END:
+ lex->next_state=MY_LEX_SYSTEM_VAR;
break;
default:
- lex->next_state=STATE_HOSTNAME;
+ lex->next_state=MY_LEX_HOSTNAME;
break;
}
yylval->lex_str.str=(char*) lex->ptr;
yylval->lex_str.length=1;
return((int) '@');
- case STATE_HOSTNAME: // end '@' of user@hostname
- for (c=yyGet() ;
- isalnum(c) || c == '.' || c == '_' || c == '$';
+ case MY_LEX_HOSTNAME: // end '@' of user@hostname
+ for (c=yyGet() ;
+ my_isalnum(cs,c) || c == '.' || c == '_' || c == '$';
c= yyGet()) ;
yylval->lex_str=get_token(lex,yyLength());
return(LEX_HOSTNAME);
- case STATE_SYSTEM_VAR:
+ case MY_LEX_SYSTEM_VAR:
yylval->lex_str.str=(char*) lex->ptr;
yylval->lex_str.length=1;
- lex->next_state=STATE_IDENT_OR_KEYWORD;
+ lex->next_state=MY_LEX_IDENT_OR_KEYWORD;
yySkip(); // Skip '@'
return((int) '@');
- case STATE_IDENT_OR_KEYWORD:
+ case MY_LEX_IDENT_OR_KEYWORD:
/*
We come here when we have found two '@' in a row.
We should now be able to handle:
[(global | local | session) .]variable_name
*/
- while (state_map[c=yyGet()] == STATE_IDENT ||
- state_map[c] == STATE_NUMBER_IDENT) ;
+ while (ident_map[c=yyGet()]) ;
if (c == '.')
- lex->next_state=STATE_IDENT_SEP;
+ lex->next_state=MY_LEX_IDENT_SEP;
length= (uint) (lex->ptr - lex->tok_start)-1;
if ((tokval= find_keyword(lex,length,0)))
{
@@ -902,3 +946,417 @@ int yylex(void *arg)
}
}
}
+
+/*
+ st_select_lex structures initialisations
+*/
+
+void st_select_lex_node::init_query()
+{
+ no_table_names_allowed= uncacheable= dependent= 0;
+ ref_pointer_array= 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;
+ with_sum_func= 0;
+ create_refs= 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;
+ union_result= 0;
+ table= 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;
+ having_fix_field= 0;
+ with_wild= 0;
+}
+
+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;
+}
+
+/*
+ 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;
+ slave= 0;
+}
+
+/* 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;
+ slave= 0;
+}
+
+/* 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;
+ */
+}
+
+void st_select_lex_unit::exclude_level()
+{
+ SELECT_LEX_UNIT *units= 0, **units_last= &units;
+ for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
+ {
+ if (sl->link_prev && (*sl->link_prev= sl->link_next))
+ sl->link_next->link_prev= sl->link_prev;
+ SELECT_LEX_UNIT **last= 0;
+ for (SELECT_LEX_UNIT *u= sl->first_inner_unit(); u; u= u->next_unit())
+ {
+ u->master= master;
+ last= (SELECT_LEX_UNIT**)&(u->next);
+ }
+ if (last)
+ {
+ (*units_last)= sl->first_inner_unit();
+ units_last= last;
+ }
+ }
+ if (units)
+ {
+ (*prev)= units;
+ (*units_last)= (SELECT_LEX_UNIT*)next;
+ }
+ else
+ (*prev)= next;
+}
+
+st_select_lex* st_select_lex_node::select_lex()
+{
+ DBUG_ENTER("st_select_lex_node::select_lex (never should be called)");
+ DBUG_ASSERT(0);
+ DBUG_RETURN(0);
+}
+
+bool st_select_lex_node::add_item_to_list(THD *thd, Item *item)
+{
+ return 1;
+}
+
+bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc)
+{
+ return 1;
+}
+
+bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc)
+{
+ return add_to_list(thd, 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(THD *thd, Table_ident *table,
+ LEX_STRING *alias,
+ ulong table_join_options,
+ thr_lock_type flags,
+ List<String> *use_index,
+ List<String> *ignore_index)
+{
+ return 0;
+}
+ulong st_select_lex_node::get_table_join_options() { 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,
+ bool check_derived)
+{
+ *result= 0;
+ return create_total_list_n_last_return(thd, lex, &result, check_derived);
+}
+
+// list creator
+bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
+ TABLE_LIST ***result,
+ bool check_derived)
+{
+ 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;
+ }
+ if (sl->linkage == DERIVED_TABLE_TYPE && !check_derived)
+ continue;
+ 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, 0))
+ 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 */
+ 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(THD *thd, Item *item)
+{
+ return item_list.push_back(item);
+}
+
+bool st_select_lex::add_group_to_list(THD *thd, Item *item, bool asc)
+{
+ return add_to_list(thd, 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;
+}
+
+ulong st_select_lex::get_table_join_options()
+{
+ return table_join_options;
+}
+
+/*
+ There are st_select_lex::add_table_to_list &
+ st_select_lex::set_lock_for_tables in sql_parse.cc
+*/
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index a905871e629..7c45e9e5619 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -37,6 +37,11 @@ class LEX_COLUMN;
#define LEX_YYSTYPE YYSTYPE *
#endif
+/*
+ When a command is added here, be sure it's also added in mysqld.cc
+ in "struct show_var_st status_vars[]= {" ...
+*/
+
enum enum_sql_command {
SQLCOM_SELECT, SQLCOM_CREATE_TABLE, SQLCOM_CREATE_INDEX, SQLCOM_ALTER_TABLE,
SQLCOM_UPDATE, SQLCOM_INSERT, SQLCOM_INSERT_SELECT,
@@ -46,37 +51,32 @@ 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_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT,
+ 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,
SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
- SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS,
+ SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS,
SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
- SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE,
+ SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_UPDATE_MULTI,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO,
- SQLCOM_EMPTY_QUERY,
+ SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS,
+ SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES,
+ SQLCOM_HELP,
+
+ /* This should be the last !!! */
SQLCOM_END
};
-enum lex_states
-{
- STATE_START, STATE_CHAR, STATE_IDENT, STATE_IDENT_SEP, STATE_IDENT_START,
- STATE_FOUND_IDENT, STATE_SIGNED_NUMBER, STATE_REAL, STATE_HEX_NUMBER,
- STATE_CMP_OP, STATE_LONG_CMP_OP, STATE_STRING, STATE_COMMENT, STATE_END,
- STATE_OPERATOR_OR_IDENT, STATE_NUMBER_IDENT, STATE_INT_OR_REAL,
- STATE_REAL_OR_POINT, STATE_BOOL, STATE_EOL, STATE_ESCAPE, STATE_LONG_COMMENT,
- STATE_END_LONG_COMMENT, STATE_COLON, STATE_SET_VAR, STATE_USER_END,
- STATE_HOSTNAME, STATE_SKIP, STATE_USER_VARIABLE_DELIMITER, STATE_SYSTEM_VAR,
- STATE_IDENT_OR_KEYWORD
-};
typedef List<Item> List_item;
@@ -93,7 +93,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 +102,309 @@ 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
-{
+ 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)
+*/
+struct st_lex;
+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;
- enum olap_type olap;
- char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
- Item *where,*having;
- ha_rows select_limit,offset_limit;
- ulong options, table_join_options;
+ 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 */
+ // Arrays of pointers to top elements of all_fields list
+ Item **ref_pointer_array;
+
+ uint with_sum_func; /* sum function indicator and number of it */
+ bool create_refs;
+ bool dependent; /* dependent from outer select subselect */
+ bool uncacheable; /* result of this query can't be cached */
+ bool no_table_names_allowed; /* used for global order by */
+
+ static void *operator new(size_t size)
+ {
+ // TODO: Change to alloc() and explicitely clear elements in constructors
+ return (void*) sql_calloc((uint) size);
+ }
+ static void operator delete(void *ptr,size_t size) {}
+ st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {}
+ 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(THD *thd, Item *item);
+ bool add_order_to_list(THD *thd, Item *item, bool asc);
+ virtual bool add_group_to_list(THD *thd, Item *item, bool asc);
+ virtual bool add_ftfunc_to_list(Item_func_match *func);
+
+ virtual st_select_lex_unit* master_unit()= 0;
+ 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 ulong get_table_join_options();
+ virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table,
+ LEX_STRING *alias,
+ ulong table_options,
+ thr_lock_type flags= TL_UNLOCK,
+ List<String> *use_index= 0,
+ List<String> *ignore_index= 0);
+ virtual void set_lock_for_tables(thr_lock_type lock_type) {}
+ void mark_as_dependent(st_select_lex *last);
+
+ friend class st_select_lex_unit;
+ friend bool mysql_new_select(struct st_lex *lex, bool move_down);
+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;
+ TABLE_LIST result_table_list;
+ select_union *union_result;
+ TABLE *table; /* temporary table using for appending UNION results */
+
+ 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
+ t_and_f; // used for transferring tables_and_fields_initied UNIT:: methods
+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;
+ THD *thd;
+
+ uint union_option;
+
+ void init_query();
+ bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result,
+ bool check_current_derived);
+ st_select_lex_unit* master_unit();
+ st_select_lex* outer_select();
+ st_select_lex* first_select() { return (st_select_lex*) slave; }
+ st_select_lex* first_select_in_union()
+ {
+ return (slave && slave->linkage == GLOBAL_OPTIONS_TYPE) ?
+ (st_select_lex*) slave->next : (st_select_lex*) slave;
+ }
+ st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; }
+ void exclude_level();
+
+ /* UNION methods */
+ int prepare(THD *thd, select_result *result, bool tables_and_fields_initied);
+ int exec();
+ int cleanup();
+
+ friend void mysql_init_query(THD *thd);
+ friend int subselect_union_engine::exec();
+private:
+ bool create_total_list_n_last_return(THD *thd, st_lex *lex,
+ TABLE_LIST ***result,
+ bool check_current_derived);
+};
+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 */
+ ulong table_join_options;
+ uint in_sum_expr;
+ uint select_number; /* number of select (used for EXPLAIN) */
+ uint with_wild; /* item list contain '*' */
+ 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(THD *thd, Item *item);
+ bool add_group_to_list(THD *thd, Item *item, bool asc);
+ bool add_ftfunc_to_list(Item_func_match *func);
+
+ TABLE_LIST* get_table_list();
+ List<Item>* get_item_list();
+ List<String>* get_use_index();
+ List<String>* get_ignore_index();
+ ulong get_table_join_options();
+ TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table,
+ LEX_STRING *alias,
+ ulong table_options,
+ thr_lock_type flags= TL_UNLOCK,
+ List<String> *use_index= 0,
+ List<String> *ignore_index= 0);
+ void set_lock_for_tables(thr_lock_type lock_type);
+ inline void init_order()
+ {
+ order_list.elements= 0;
+ order_list.first= 0;
+ order_list.next= (byte**) &order_list.first;
+ }
+
+ friend void mysql_init_query(THD *thd);
+ void make_empty_select(st_select_lex *last_select)
+ {
+ select_number=INT_MAX;
+ init_query();
+ init_select();
+ include_neighbour(last_select);
+ }
+};
+typedef class st_select_lex SELECT_LEX;
/* The state of the lex parsing. This is saved in the THD struct */
@@ -130,17 +413,26 @@ 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;
+ /* list of all SELECT_LEX */
+ SELECT_LEX *all_selects_list;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */
char* to_log; /* For PURGE MASTER LOGS TO */
+ time_t purge_time; /* For PURGE MASTER LOGS BEFORE */
char* x509_subject,*x509_issuer,*ssl_cipher;
+ char* found_colon; /* For multi queries - next query */
enum SSL_type ssl_type; /* defined in violite.h */
String *wild;
sql_exchange *exchange;
+ select_result *result;
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,12 +443,13 @@ 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
+ CHARSET_INFO *thd_charset;
LEX_USER *grant_user;
gptr yacc_yyss,yacc_yyvs;
THD *thd;
@@ -167,18 +460,43 @@ typedef struct st_lex
USER_RESOURCES mqh;
ulong thread_id,type;
enum_sql_command sql_command;
- enum lex_states next_state;
+ thr_lock_type lock_option;
+ enum my_lex_states next_state;
enum enum_duplicates duplicates;
enum enum_tx_isolation tx_isolation;
enum enum_ha_read_modes ha_read_mode;
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;
+ bool safe_to_cache_query;
uint slave_thd_opt;
+ CHARSET_INFO *charset;
+ char *help_arg;
+
+ inline void uncacheable()
+ {
+ safe_to_cache_query= 0;
+
+ /*
+ There are no sense to mark select_lex and union fields of LEX,
+ but we should merk all subselects as uncacheable from current till
+ most upper
+ */
+ SELECT_LEX_NODE *sl;
+ SELECT_LEX_UNIT *un;
+ for (sl= current_select, un= sl->master_unit();
+ un != &unit;
+ sl= sl->outer_select(), un= sl->master_unit())
+ {
+ sl->uncacheable = un->uncacheable= 1;
+ }
+ }
} LEX;
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 542eef623f0..505ea994d42 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -25,8 +25,16 @@
class Sql_alloc
{
public:
- static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
+ static void *operator new(size_t size)
+ {
+ return (void*) sql_alloc((uint) size);
+ }
+ static void *operator new[](size_t size)
+ {
+ return (void*) sql_alloc((uint) size);
+ }
static void operator delete(void *ptr, size_t size) {} /*lint -e715 */
+ static void operator delete[](void *ptr, size_t size) {}
#ifdef HAVE_purify
bool dummy;
inline Sql_alloc() :dummy(0) {}
@@ -82,6 +90,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 +131,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)
@@ -142,12 +155,20 @@ protected:
class base_list_iterator
{
+protected:
base_list *list;
list_node **el,**prev,*current;
+ void sublist(base_list &ls, uint elm)
+ {
+ ls.first= *el;
+ ls.last= list->last;
+ ls.elements= elm;
+ }
public:
- base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first),
- prev(0),current(0)
+ base_list_iterator(base_list &list_par)
+ :list(&list_par), el(&list_par.first), prev(0), current(0)
{}
+
inline void *next(void)
{
prev=el;
@@ -204,9 +225,9 @@ public:
{
return el == &list->last_ref()->next;
}
+ friend class error_list_iterator;
};
-
template <class T> class List :public base_list
{
public:
@@ -254,6 +275,10 @@ public:
List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
inline void rewind(void) { base_list_iterator::rewind(); }
+ void sublist(List<T> &list, uint el)
+ {
+ base_list_iterator::sublist(list, el);
+ }
};
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 62ed0fc5bed..4f5b19e6f49 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -41,8 +41,9 @@ public:
bool error,line_cuted,found_null,enclosed;
byte *row_start, /* Found row starts here */
*row_end; /* Found row ends here */
+ CHARSET_INFO *read_charset;
- READ_INFO(File file,uint tot_length,
+ READ_INFO(File file,uint tot_length,CHARSET_INFO *cs,
String &field_term,String &line_start,String &line_term,
String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
~READ_INFO();
@@ -77,6 +78,8 @@ static int read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
String &enclosed);
+#ifndef EMBEDDED_LIBRARY
+
int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
List<Item> &fields, enum enum_duplicates handle_duplicates,
bool read_file_from_client,thr_lock_type lock_type)
@@ -119,7 +122,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else
{ // Part field list
thd->dupp_field=0;
- if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0))
+ if (setup_tables(table_list) ||
+ setup_fields(thd, 0, table_list, fields, 1, 0, 0))
DBUG_RETURN(-1);
if (thd->dupp_field)
{
@@ -158,12 +162,14 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
if (read_file_from_client && handle_duplicates == DUP_ERROR)
handle_duplicates=DUP_IGNORE;
+#ifndef EMBEDDED_LIBRARY
if (read_file_from_client)
{
(void)net_request_file(&thd->net,ex->file_name);
file = -1;
}
else
+#endif
{
read_file_from_client=0;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
@@ -209,8 +215,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
info.handle_duplicates=handle_duplicates;
info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX;
- READ_INFO read_info(file,tot_length,*field_term,
- *ex->line_start, *ex->line_term, *enclosed,
+ READ_INFO read_info(file,tot_length,thd->db_charset,
+ *field_term,*ex->line_start, *ex->line_term, *enclosed,
info.escape_char, read_file_from_client, is_fifo);
if (read_info.error)
{
@@ -308,7 +314,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);
@@ -349,6 +355,7 @@ err:
DBUG_RETURN(error);
}
+#endif /* EMBEDDED_LIBRARY */
/****************************************************************************
** Read of rows of fixed size + optional garage + optonal newline
@@ -396,7 +403,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,read_info.read_charset);
pos[length]=save_chr;
if ((pos+=length) > read_info.row_end)
pos= read_info.row_end; /* Fills rest with space */
@@ -477,7 +484,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,read_info.read_charset);
}
if (read_info.error)
break;
@@ -541,12 +548,13 @@ READ_INFO::unescape(char chr)
*/
-READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term,
- String &line_start, String &line_term,
+READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
+ String &field_term, String &line_start, String &line_term,
String &enclosed_par, int escape, bool get_it_from_net,
bool is_fifo)
:file(file_par),escape_char(escape)
{
+ read_charset= cs;
field_term_ptr=(char*) field_term.ptr();
field_term_length= field_term.length();
line_term_ptr=(char*) line_term.ptr();
@@ -607,9 +615,11 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, String &field_term,
cache.read_function = _my_b_net_read;
need_end_io_cache = 1;
+#ifndef EMBEDDED_LIBRARY
if (!opt_old_rpl_compat && mysql_bin_log.is_open())
cache.pre_read = cache.pre_close =
(IO_CACHE_CALLBACK) log_loaded_block;
+#endif
}
}
}
@@ -691,13 +701,13 @@ int READ_INFO::read_field()
{
chr = GET;
#ifdef USE_MB
- if (use_mb(default_charset_info) &&
- my_ismbhead(default_charset_info, chr) &&
- to+my_mbcharlen(default_charset_info, chr) <= end_of_buff)
+ if (use_mb(read_charset) &&
+ my_ismbhead(read_charset, chr) &&
+ to+my_mbcharlen(read_charset, chr) <= end_of_buff)
{
uchar* p = (uchar*)to;
*to++ = chr;
- int ml = my_mbcharlen(default_charset_info, chr);
+ int ml = my_mbcharlen(read_charset, chr);
int i;
for (i=1; i<ml; i++) {
chr = GET;
@@ -705,7 +715,7 @@ int READ_INFO::read_field()
goto found_eof;
*to++ = chr;
}
- if (my_ismbchar(default_charset_info,
+ if (my_ismbchar(read_charset,
(const char *)p,
(const char *)to))
continue;
@@ -874,10 +884,10 @@ int READ_INFO::next_line()
{
int chr = GET;
#ifdef USE_MB
- if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, chr))
+ if (use_mb(read_charset) && my_ismbhead(read_charset, chr))
{
for (int i=1;
- chr != my_b_EOF && i<my_mbcharlen(default_charset_info, chr);
+ chr != my_b_EOF && i<my_mbcharlen(read_charset, chr);
i++)
chr = GET;
if (chr == escape_char)
diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc
index 6eb4fbcaaf6..a5f164e1e38 100644
--- a/sql/sql_olap.cc
+++ b/sql/sql_olap.cc
@@ -62,7 +62,7 @@ static int make_new_olap_select(LEX *lex, SELECT_LEX *select_lex, List<Item> new
List_iterator<Item> list_it(select_lex->item_list);
List_iterator<Item> new_it(new_fields);
- while((item=list_it++))
+ while ((item=list_it++))
{
bool not_found=true;
if (item->type()==Item::FIELD_ITEM)
@@ -109,15 +109,15 @@ static int olap_combos(List<Item> old_fields, List<Item> new_fields, Item *item
int num_new_fields)
{
int sl_return = 0;
- if(position == num_new_fields)
+ if (position == num_new_fields)
{
- if(item)
+ if (item)
new_fields.push_front(item);
sl_return = make_new_olap_select(lex, select_lex, new_fields);
}
else
{
- if(item)
+ if (item)
new_fields.push_front(item);
while ((num_fields - num_new_fields >= selection - position) && !sl_return)
{
@@ -164,18 +164,20 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
if (setup_tables((TABLE_LIST *)select_lex->table_list.first) ||
- setup_fields(lex->thd,(TABLE_LIST *)select_lex->table_list.first,select_lex->item_list,1,&all_fields,1) ||
- setup_fields(lex->thd,(TABLE_LIST *)select_lex->table_list.first,item_list_copy,1,&all_fields,1))
+ setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
+ select_lex->item_list, 1, &all_fields,1) ||
+ setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
+ item_list_copy, 1, &all_fields, 1))
return -1;
if (select_lex->olap == CUBE_TYPE)
{
- for( int i=count-1; i>=0 && !sl_return; i--)
+ for ( int i=count-1; i>=0 && !sl_return; i--)
sl_return=olap_combos(item_list_copy, new_item_list, (Item *)0, lex, select_lex, 0, 0, count, i);
}
else if (select_lex->olap == ROLLUP_TYPE)
{
- for( int i=count-1; i>=0 && !sl_return; i--)
+ for ( int i=count-1; i>=0 && !sl_return; i--)
{
Item *item;
item_list_copy.pop();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 8439db0be6b..8ca5bf2f12d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -21,7 +21,6 @@
#include <m_ctype.h>
#include <myisam.h>
#include <my_dir.h>
-#include <assert.h>
#ifdef HAVE_INNOBASE_DB
#include "ha_innodb.h"
@@ -44,30 +43,21 @@
#else
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL */
-#define SCRAMBLE_LENGTH 8
-#define MEM_ROOT_BLOCK_SIZE 8192
-#define MEM_ROOT_PREALLOC 8192
-#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
-#define TRANS_MEM_ROOT_PREALLOC 4096
-
-extern int yyparse(void);
+extern int yyparse(void *thd);
extern "C" pthread_mutex_t THR_LOCK_keycache;
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
#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
@@ -76,10 +66,11 @@ const char *command_name[]={
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
"Binlog Dump","Table Dump", "Connect Out", "Register Slave",
+ "Prepare", "Prepare Execute", "Long Data", "Close stmt",
"Error" // Last command number
};
-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)
@@ -130,7 +121,7 @@ extern pthread_mutex_t LOCK_user_conn;
static int get_or_create_user_conn(THD *thd, const char *user,
const char *host,
- USER_RESOURCES *mqh)
+ USER_RESOURCES *mqh)
{
int return_val=0;
uint temp_len, user_len, host_len;
@@ -152,7 +143,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;
}
@@ -164,13 +155,13 @@ static int get_or_create_user_conn(THD *thd, const char *user,
uc->connections = 1;
uc->questions=uc->updates=uc->conn_per_hour=0;
uc->user_resources=*mqh;
- if (max_user_connections && mqh->connections > max_user_connections)
+ if (max_user_connections && mqh->connections > max_user_connections)
uc->user_resources.connections = max_user_connections;
uc->intime=thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc))
{
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;
}
@@ -179,54 +170,107 @@ static int get_or_create_user_conn(THD *thd, const char *user,
end:
(void) pthread_mutex_unlock(&LOCK_user_conn);
return return_val;
-
+
}
/*
Check if user is ok
- Updates:
- thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
+
+ SYNOPSIS
+ check_user()
+ thd Thread handle
+ command Command for connection (for log)
+ user Name of user trying to connect
+ passwd Scrambled password sent from client
+ db Database to connect to
+ check_count If set to 1, don't allow too many connection
+ simple_connect If 1 then client is of old type and we should connect
+ using the old method (no challange)
+ do_send_error Set to 1 if we should send error to user
+ prepared_scramble Buffer to store hash password of new connection
+ had_password Set to 1 if the user gave a password
+ cur_priv_version Check flag to know if someone flushed the privileges
+ since last code
+ hint_user Pointer used by acl_getroot() to remmeber user for
+ next call
+
+ RETURN
+ 0 ok
+ thd->user, thd->master_access, thd->priv_user, thd->db and
+ thd->db_access are updated
+ 1 Access denied; Error sent to client
+ -1 If do_send_error == 1: Failed connect, error sent to client
+ If do_send_error == 0: Prepare for stage of connect
*/
-static bool check_user(THD *thd,enum_server_command command, const char *user,
- const char *passwd, const char *db, bool check_count)
+static int check_user(THD *thd,enum_server_command command, const char *user,
+ const char *passwd, const char *db, bool check_count,
+ bool simple_connect, bool do_send_error,
+ char *prepared_scramble, bool had_password,
+ uint *cur_priv_version, ACL_USER** hint_user)
{
- NET *net= &thd->net;
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
+ DBUG_ENTER("check_user");
- if (passwd[0] && strlen(passwd) != SCRAMBLE_LENGTH)
- return 1;
- if (!(thd->user = my_strdup(user, MYF(0))))
+ /* We shall avoid dupplicate user allocations here */
+ if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
{
- send_error(net,ER_OUT_OF_RESOURCES);
- return 1;
+ send_error(thd,ER_OUT_OF_RESOURCES);
+ DBUG_RETURN(1);
}
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user,
- protocol_version == 9 ||
- !(thd->client_capabilities &
- CLIENT_LONG_PASSWORD),&ur);
+ (protocol_version == 9 ||
+ !(thd->client_capabilities &
+ CLIENT_LONG_PASSWORD)),
+ &ur,prepared_scramble,
+ cur_priv_version,hint_user);
+
DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length,
thd->host_or_ip, thd->priv_user,
- passwd[0] ? "yes": "no",
+ had_password ? "yes": "no",
thd->master_access, thd->db ? thd->db : "*none*"));
+
+ /*
+ In case we're going to retry we should not send error message at this
+ point
+ */
if (thd->master_access & NO_ACCESS)
{
- net_printf(net, ER_ACCESS_DENIED_ERROR,
- thd->user,
- thd->host_or_ip,
- passwd[0] ? ER(ER_YES) : ER(ER_NO));
- mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
- thd->user,
- thd->host_or_ip,
- passwd[0] ? ER(ER_YES) : ER(ER_NO));
- return(1); // Error already given
+ if (do_send_error || !had_password || !*hint_user)
+ {
+ DBUG_PRINT("info",("Access denied"));
+ /*
+ Old client should get nicer error message if password version is
+ not supported
+ */
+ if (simple_connect && *hint_user && (*hint_user)->pversion)
+ {
+ net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ }
+ else
+ {
+ net_printf(thd, ER_ACCESS_DENIED_ERROR,
+ thd->user,
+ thd->host_or_ip,
+ had_password ? ER(ER_YES) : ER(ER_NO));
+ mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
+ thd->user,
+ thd->host_or_ip,
+ had_password ? ER(ER_YES) : ER(ER_NO));
+ }
+ DBUG_RETURN(1); // Error already given
+ }
+ DBUG_PRINT("info",("Prepare for second part of handshake"));
+ DBUG_RETURN(-1); // no report error in special handshake
}
+
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -235,8 +279,8 @@ 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);
- return(1);
+ send_error(thd, ER_CON_COUNT_ERROR);
+ DBUG_RETURN(1);
}
}
mysql_log.write(thd,command,
@@ -250,20 +294,20 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
/* Don't allow user to connect if he has done too many queries */
if ((ur.questions || ur.updates || ur.connections) &&
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
- return -1;
- if (thd->user_connect && thd->user_connect->user_resources.connections &&
- check_for_max_user_connections(thd->user_connect))
- return -1;
+ DBUG_RETURN(1);
+ if (thd->user_connect && thd->user_connect->user_resources.connections &&
+ check_for_max_user_connections(thd, thd->user_connect))
+ DBUG_RETURN(1);
+
if (db && db[0])
{
- bool error=test(mysql_change_db(thd,db));
+ int error= test(mysql_change_db(thd,db));
if (error && thd->user_connect)
decrease_user_connections(thd->user_connect);
- return error;
+ DBUG_RETURN(error);
}
- else
- send_ok(net); // Ready to handle questions
- return 0; // ok
+ send_ok(thd); // Ready to handle questions
+ DBUG_RETURN(0); // ok
}
@@ -284,35 +328,35 @@ extern "C" void free_user(struct user_conn *uc)
my_free((char*) uc,MYF(0));
}
-void init_max_user_conn(void)
+void init_max_user_conn(void)
{
- (void) hash_init(&hash_user_connections,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");
-
+
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;
}
- uc->connections++;
+ uc->connections++;
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);
@@ -367,9 +411,13 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
uc_update_queries[SQLCOM_DELETE_MULTI]=1;
uc_update_queries[SQLCOM_DROP_INDEX]=1;
- uc_update_queries[SQLCOM_MULTI_UPDATE]=1;
+ uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
}
+bool is_update_query(enum enum_sql_command command)
+{
+ return uc_update_queries[command];
+}
/*
Check if maximum queries per hour limit has been reached
@@ -403,7 +451,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;
@@ -414,7 +462,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;
@@ -429,7 +477,7 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
{
(void) pthread_mutex_lock(&LOCK_user_conn);
- if (lu) // for GRANT
+ if (lu) // for GRANT
{
USER_CONN *uc;
uint temp_len=lu->user.length+lu->host.length+2;
@@ -464,20 +512,35 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
/*
- Check connnetion and get priviliges
- Returns 0 on ok, -1 < if error is given > 0 on error.
+ Check connnectionn and get priviliges
+
+ SYNOPSIS
+ check_connections
+ thd Thread handle
+
+ RETURN
+ 0 ok
+ -1 Error, which is sent to user
+ > 0 Error code (not sent to user)
*/
+#ifndef EMBEDDED_LIBRARY
static int
check_connections(THD *thd)
{
+ int res;
uint connect_errors=0;
+ uint cur_priv_version;
+ bool using_password;
NET *net= &thd->net;
- /* Store the connection details */
- DBUG_PRINT("info", (("check_connections called by thread %d"),
- thd->thread_id));
+ char *end, *user, *passwd, *db;
+ char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */
+ ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
DBUG_PRINT("info",("New connection received on %s",
- vio_description(net->vio)));
+ vio_description(net->vio)));
+
+ /* Remove warning from valgrind. TODO: Fix it in password.c */
+ bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble));
if (!thd->host) // If TCP/IP connection
{
char ip[30];
@@ -493,18 +556,20 @@ check_connections(THD *thd)
thd->host=(char*) localhost;
else
#endif
- if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- vio_in_addr(net->vio,&thd->remote.sin_addr);
- thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
- /* Cut very long hostnames to avoid possible overflows */
- if (thd->host)
+ if (!(specialflag & SPECIAL_NO_RESOLVE))
{
- thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
- thd->host_or_ip= thd->host;
+ vio_in_addr(net->vio,&thd->remote.sin_addr);
+ thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors);
+ /* Cut very long hostnames to avoid possible overflows */
+ if (thd->host)
+ {
+ thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0;
+ thd->host_or_ip= thd->host;
+ }
+ if (connect_errors > max_connect_errors)
+ return(ER_HOST_IS_BLOCKED);
}
- if (connect_errors > max_connect_errors)
- return(ER_HOST_IS_BLOCKED);
}
DBUG_PRINT("info",("Host: %s ip: %s",
thd->host ? thd->host : "unknown host",
@@ -526,8 +591,9 @@ check_connections(THD *thd)
ulong pkt_len=0;
{
/* buff[] needs to big enough to hold the server_version variable */
- char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end;
- int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB;
+ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
+ int client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
+ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
if (opt_using_transactions)
client_flags|=CLIENT_TRANSACTIONS;
@@ -549,9 +615,11 @@ 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,
+
+ // At this point we write connection message and read reply
+ if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
(uint) (end-buff)) ||
- (pkt_len= my_net_read(net)) == packet_error ||
+ (pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
@@ -567,8 +635,20 @@ check_connections(THD *thd)
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
+ {
+ thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
+ thd->max_client_packet_length= uint4korr(net->read_pos+4);
+ end= (char*) net->read_pos+8;
+ }
+ else
+ {
+ thd->max_client_packet_length= uint3korr(net->read_pos+2);
+ end= (char*) net->read_pos+5;
+ }
+
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->sql_mode|= MODE_IGNORE_SPACE;
+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
DBUG_PRINT("info", ("client capabilities: %d", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
@@ -580,7 +660,7 @@ check_connections(THD *thd)
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
pkt_len));
inc_host_errors(&thd->remote.sin_addr);
- return(ER_HANDSHAKE_ERROR);
+ return(ER_HANDSHAKE_ERROR);
}
DBUG_PRINT("info", ("Reading user information over SSL layer"));
if ((pkt_len=my_net_read(net)) == packet_error ||
@@ -592,32 +672,86 @@ check_connections(THD *thd)
return(ER_HANDSHAKE_ERROR);
}
}
- else
+#endif
+
+ if (end >= (char*) net->read_pos+ pkt_len +2)
{
- DBUG_PRINT("info", ("Leaving IO layer intact"));
- if (pkt_len < NORMAL_HANDSHAKE_SIZE)
- {
- inc_host_errors(&thd->remote.sin_addr);
- return ER_HANDSHAKE_ERROR;
- }
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
}
-#endif
- thd->max_client_packet_length=uint3korr(net->read_pos+2);
- char *user= (char*) net->read_pos+5;
- char *passwd= strend(user)+1;
- char *db=0;
+ user= end;
+ passwd= strend(user)+1;
+ db=0;
+ using_password= test(passwd[0]);
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
db=strend(passwd)+1;
+
+ /* We can get only old hash at this point */
+ if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
+ return ER_HANDSHAKE_ERROR;
+
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
- thd->net.return_status= &thd->server_status;
+ net->return_status= &thd->server_status;
net->read_timeout=(uint) thd->variables.net_read_timeout;
- if (check_user(thd,COM_CONNECT, user, passwd, db, 1))
- return (-1);
- thd->password=test(passwd[0]);
+
+ /* Simple connect only for old clients. New clients always use secure auth */
+ bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
+
+ /* Check user permissions. If password failure we'll get scramble back */
+ if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
+ simple_connect, prepared_scramble, using_password,
+ &cur_priv_version,
+ &cached_user)) < 0)
+ {
+ /* Store current used and database as they are erased with next packet */
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+
+ /* If the client is old we just have to return error */
+ if (simple_connect)
+ return -1;
+
+ DBUG_PRINT("info",("password challenge"));
+
+ tmp_user[0]= tmp_db[0]= 0;
+ if (user)
+ strmake(tmp_user,user,USERNAME_LENGTH);
+ if (db)
+ strmake(tmp_db,db,NAME_LEN);
+
+ /* Write hash and encrypted scramble to client */
+ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
+ net_flush(net))
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ /* Reading packet back */
+ if ((pkt_len= my_net_read(net)) == packet_error)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ /* We have to get very specific packet size */
+ if (pkt_len != SCRAMBLE41_LENGTH)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return ER_HANDSHAKE_ERROR;
+ }
+ /* Final attempt to check the user based on reply */
+ if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
+ tmp_db, 1, 0, 1, prepared_scramble, using_password,
+ &cur_priv_version,
+ &cached_user))
+ return -1;
+ }
+ else if (res)
+ return -1; // Error sent from check_user()
+ thd->password=using_password;
return 0;
}
@@ -678,10 +812,10 @@ 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() */
+ my_sleep(1000); /* must wait after eof() */
#endif
statistic_increment(aborted_connects,&LOCK_status);
goto end_thread;
@@ -698,9 +832,7 @@ pthread_handler_decl(handle_one_connection,arg)
thd->command=COM_SLEEP;
thd->version=refresh_version;
thd->set_time();
- init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
- init_sql_alloc(&thd->transaction.mem_root,
- TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
+ thd->init_for_queries();
while (!net->error && net->vio != 0 && !thd->killed)
{
if (do_command(thd))
@@ -709,7 +841,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),
@@ -718,10 +850,10 @@ 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);
}
-
+
end_thread:
close_connection(net);
end_thread(thd,1);
@@ -750,7 +882,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
if (my_thread_init() || thd->store_globals())
{
close_connection(&thd->net,ER_OUT_OF_RESOURCES);
- thd->fatal_error=1;
+ thd->fatal_error();
goto end;
}
DBUG_ENTER("handle_bootstrap");
@@ -771,13 +903,12 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
thd->priv_user=thd->user=(char*) my_strdup("boot", MYF(MY_WME));
buff= (char*) thd->net.buff;
- init_sql_alloc(&thd->mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
- init_sql_alloc(&thd->transaction.mem_root,
- TRANS_MEM_ROOT_BLOCK_SIZE, TRANS_MEM_ROOT_PREALLOC);
+ thd->init_for_queries();
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(thd->charset(), buff[length-1]) ||
+ buff[length-1] == ';'))
length--;
buff[length]=0;
thd->current_tablenr=0;
@@ -794,7 +925,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
}
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
break;
free_root(&thd->mem_root,MYF(MY_KEEP_PREALLOC));
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
@@ -811,11 +942,13 @@ end:
DBUG_RETURN(0); // Never reached
}
+#endif /* EMBEDDED_LIBRARY */
-inline void free_items(THD *thd)
-{
/* This works because items are allocated with sql_alloc() */
- for (Item *item=thd->free_list ; item ; item=item->next)
+
+void free_items(Item *item)
+{
+ for (; item ; item=item->next)
delete item;
}
@@ -835,12 +968,12 @@ 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 (lower_case_table_names)
- casedn_str(tbl_name);
- remove_escape(tbl_name);
+ my_casedn_str(files_charset_info, tbl_name);
+ remove_escape(table_list->real_name);
if (!(table=open_ltable(thd, table_list, TL_READ_NO_INSERT)))
DBUG_RETURN(1);
@@ -855,7 +988,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
thd->query = tbl_name;
if ((error = mysqld_dump_create_info(thd, table, -1)))
{
- my_error(ER_GET_ERRNO, MYF(0));
+ my_error(ER_GET_ERRNO, MYF(0), my_errno);
goto err;
}
net_flush(&thd->net);
@@ -870,6 +1003,7 @@ err:
/* Execute one command from socket (query or simple command) */
+#ifndef EMBEDDED_LIBRARY
bool do_command(THD *thd)
{
char *packet;
@@ -886,8 +1020,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)
@@ -898,7 +1031,7 @@ bool do_command(THD *thd)
/* Check if we can continue without closing the connection */
if (net->error != 3)
DBUG_RETURN(TRUE); // We have to close it.
- send_error(net,net->last_errno,NullS);
+ send_error(thd,net->last_errno,NullS);
net->error= 0;
DBUG_RETURN(FALSE);
}
@@ -915,13 +1048,14 @@ bool do_command(THD *thd)
net->read_timeout=old_timeout; // restore it
DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length));
}
+#endif /* EMBEDDED_LIBRARY */
bool dispatch_command(enum enum_server_command command, THD *thd,
char* packet, uint packet_length)
{
NET *net= &thd->net;
- bool error=0;
+ bool error= 0;
/*
Commands which will always take a long time should be marked with
this so that they will not get logged to the slow query log
@@ -945,12 +1079,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (!mysql_change_db(thd,packet))
mysql_log.write(thd,command,"%s",thd->db);
break;
+#ifndef EMBEDDED_LIBRARY
case COM_REGISTER_SLAVE:
{
if (!register_slave(thd, (uchar*)packet, packet_length))
- send_ok(&thd->net);
+ send_ok(thd);
break;
}
+#endif
case COM_TABLE_DUMP:
{
statistic_increment(com_other, &LOCK_status);
@@ -964,13 +1100,14 @@ 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;
}
+#ifndef EMBEDDED_LIBRARY
case COM_CHANGE_USER:
{
thd->change_user();
- clear_error_message(thd); // If errors from rollback
+ thd->clear_error(); // If errors from rollback
statistic_increment(com_other,&LOCK_status);
char *user= (char*) packet;
@@ -982,63 +1119,160 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint save_db_access= thd->db_access;
uint save_db_length= thd->db_length;
char *save_user= thd->user;
+ thd->user=NULL; /* Needed for check_user to allocate new user */
char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
- thd->user=0;
- USER_CONN *save_uc= thd->user_connect;
+ USER_CONN *save_uc= thd->user_connect;
+ bool simple_connect;
+ bool using_password;
+ char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+ ACL_USER* cached_user ; /* Cached user */
+ uint cur_priv_version; /* Cached grant version */
+ int res;
+ ulong pkt_len= 0; /* Length of reply packet */
+
+ bzero((char*) prepared_scramble, sizeof(prepared_scramble));
+ /* Small check for incomming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
- { // Check if protocol is ok
- send_error(net, ER_UNKNOWN_COM_ERROR);
- break;
- }
- if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0))
- { // Restore old user
- x_free(thd->user);
- thd->master_access=save_master_access;
- thd->db_access=save_db_access;
- thd->db=save_db;
- thd->db_length=save_db_length;
- thd->user=save_user;
- thd->priv_user=save_priv_user;
- break;
+ goto restore_user_err;
+
+ /* Now we shall basically perform authentication again */
+
+ /* We can get only old hash at this point */
+ if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
+ goto restore_user_err;
+
+ cached_user= NULL;
+
+ /* Simple connect only for old clients. New clients always use sec. auth*/
+ simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
+
+ /* Store information if we used password. passwd will be dammaged */
+ using_password=test(passwd[0]);
+
+ if (simple_connect) /* Restore scramble for old clients */
+ memcpy(thd->scramble,thd->old_scramble,9);
+
+ /*
+ Check user permissions. If password failure we'll get scramble back
+ Do not retry if we already have sent error (result>0)
+ */
+ if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0,
+ simple_connect, simple_connect, prepared_scramble,
+ using_password, &cur_priv_version, &cached_user)) < 0)
+ {
+ /* If the client is old we just have to have auth failure */
+ if (simple_connect)
+ goto restore_user; /* Error is already reported */
+
+ /* Store current used and database as they are erased with next packet */
+ tmp_user[0]= tmp_db[0]= 0;
+ if (user)
+ strmake(tmp_user,user,USERNAME_LENGTH);
+ if (db)
+ strmake(tmp_db,db,NAME_LEN);
+
+ /* Write hash and encrypted scramble to client */
+ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
+ net_flush(net))
+ goto restore_user_err;
+
+ /* Reading packet back */
+ if ((pkt_len=my_net_read(net)) == packet_error)
+ goto restore_user_err;
+
+ /* We have to get very specific packet size */
+ if (pkt_len != SCRAMBLE41_LENGTH)
+ goto restore_user;
+
+ /* Final attempt to check the user based on reply */
+ if (check_user(thd,COM_CHANGE_USER, tmp_user, (char*) net->read_pos,
+ tmp_db, 0, 0, 1, prepared_scramble, using_password,
+ &cur_priv_version, &cached_user))
+ goto restore_user;
}
+ else if (res)
+ goto restore_user;
+
+ /* Finally we've authenticated new user */
if (max_connections && save_uc)
decrease_user_connections(save_uc);
x_free((gptr) save_db);
x_free((gptr) save_user);
- thd->password=test(passwd[0]);
+ thd->password=using_password;
break;
- }
+ /* Bad luck we shall restore old user */
+restore_user_err:
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+
+restore_user:
+ x_free(thd->user);
+ thd->master_access=save_master_access;
+ thd->db_access=save_db_access;
+ thd->db=save_db;
+ thd->db_length=save_db_length;
+ thd->user=save_user;
+ thd->priv_user=save_priv_user;
+ break;
+ }
+#endif /* EMBEDDED_LIBRARY */
+ 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_CLOSE_STMT:
+ {
+ mysql_stmt_free(thd, packet);
+ 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",("%-.4096s",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);
+
+ while (!thd->killed && !thd->is_fatal_error && thd->lex.found_colon)
+ {
+ char *packet= thd->lex.found_colon;
+ /*
+ Multiple queries exits, execute them individually
+ */
+ if (thd->lock || thd->open_tables || thd->derived_tables)
+ close_thread_tables(thd);
+
+ ulong length= thd->query_length-(ulong)(thd->lex.found_colon-thd->query);
+
+ /* Remove garbage at start of query */
+ while (my_isspace(thd->charset(), *packet) && length > 0)
+ {
+ packet++;
+ length--;
+ }
+ thd->query_length= length;
+ thd->query= packet;
+ VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->query_id= query_id++;
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ mysql_parse(thd, packet, length);
+ }
+
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR);
DBUG_PRINT("info",("query ready"));
@@ -1046,7 +1280,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
{
@@ -1056,7 +1290,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;
@@ -1067,7 +1301,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
if (lower_case_table_names)
- casedn_str(table_list.real_name);
+ my_casedn_str(files_charset_info, table_list.real_name);
remove_escape(table_list.real_name); // This can't have wildcards
if (check_access(thd,SELECT_ACL,table_list.db,&thd->col_access))
@@ -1076,7 +1310,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
@@ -1094,7 +1328,7 @@ 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 (check_access(thd,CREATE_ACL,db,0,1))
@@ -1110,20 +1344,21 @@ 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 (check_access(thd,DROP_ACL,db,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);
break;
}
mysql_log.write(thd,command,db);
mysql_rm_db(thd,db,0,0);
break;
}
+#ifndef EMBEDDED_LIBRARY
case COM_BINLOG_DUMP:
{
statistic_increment(com_other,&LOCK_status);
@@ -1148,6 +1383,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
net->error = 0;
break;
}
+#endif
case COM_REFRESH:
{
statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
@@ -1159,18 +1395,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
reload_acl_and_cache(thd, options, (TABLE_LIST*) 0) ;
break;
}
+#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
statistic_increment(com_other,&LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
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
@@ -1179,7 +1416,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
kill_mysql();
error=TRUE;
break;
-
+#endif
+#ifndef EMBEDDED_LIBRARY
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
@@ -1201,9 +1439,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(net_flush(net));
break;
}
+#endif
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);
@@ -1226,7 +1465,7 @@ 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
@@ -1234,17 +1473,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_DELAYED_INSERT:
case COM_END:
default:
- send_error(net, ER_UNKNOWN_COM_ERROR);
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
break;
}
- if (thd->lock || thd->open_tables)
+ if (thd->lock || thd->open_tables || thd->derived_tables)
{
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
- if (thd->fatal_error)
- send_error(net,0); // End of memory ?
+ if (thd->is_fatal_error)
+ send_error(thd,0); // End of memory ?
time_t start_of_query=thd->start_time;
thd->end_time(); // Set start time
@@ -1276,24 +1515,84 @@ 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 garbage at start and end of query */
+ while (my_isspace(thd->charset(),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(thd->charset() ,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;
+ 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 != lex->all_selects_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;
+
+#ifndef EMBEDDED_LIBRARY
if (thd->slave_thread)
{
- /*
+ /*
Skip if we are in the slave thread, some table rules have been
given and the table list says the query should not be replicated
*/
@@ -1312,23 +1611,47 @@ mysql_execute_command(void)
}
#endif
}
-
+#endif /* EMBEDDED_LIBRARY */
/*
- 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->all_selects_list;
+ sl;
+ sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *cursor= sl->get_table_list();
+ cursor;
+ cursor= cursor->next)
+ {
+ if (cursor->derived && (res=mysql_derived(thd, lex,
+ 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 != lex->all_selects_list &&
+ lex->unit.create_total_list(thd, lex, &tables, 0))
+#ifdef HAVE_REPLICATION
+ ||
(table_rules_on && tables && thd->slave_thread &&
- !tables_ok(thd,tables)))
+ !tables_ok(thd,tables))
+#endif
+ )
DBUG_VOID_RETURN;
statistic_increment(com_stat[lex->sql_command],&LOCK_status);
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,
@@ -1345,91 +1668,120 @@ 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(lex->all_selects_list);
+ 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()))
+ {
+ 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:
- res=mysql_do(thd, *lex->insert_list);
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ (res= open_and_lock_tables(thd,tables))))
+ break;
+
+ fix_tables_pointers(lex->all_selects_list);
+ res= mysql_do(thd, *lex->insert_list);
+ if (thd->net.report_error)
+ res= -1;
break;
case SQLCOM_EMPTY_QUERY:
- send_ok(&thd->net);
+ send_ok(thd);
break;
+ case SQLCOM_HELP:
+ res= mysqld_help(thd,lex->help_arg);
+ break;
+
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_PURGE:
{
if (check_global_access(thd, SUPER_ACL))
goto error;
+ // PURGE MASTER LOGS TO 'file'
res = purge_master_logs(thd, lex->to_log);
break;
}
+ case SQLCOM_PURGE_BEFORE:
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ goto error;
+ // PURGE MASTER LOGS BEFORE 'data'
+ res = purge_master_logs_before_date(thd, lex->purge_time);
+ break;
+ }
+#endif
+
+ case SQLCOM_SHOW_WARNS:
+ {
+ res= mysqld_show_warnings(thd, (ulong)
+ ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) |
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN) |
+ (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)
+ ));
+ 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);
#endif
break;
}
+
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_SHOW_SLAVE_HOSTS:
{
if (check_global_access(thd, REPL_SLAVE_ACL))
@@ -1444,6 +1796,8 @@ mysql_execute_command(void)
res = show_binlog_events(thd);
break;
}
+#endif
+
case SQLCOM_BACKUP_TABLE:
{
if (check_db_used(thd,tables) ||
@@ -1463,6 +1817,8 @@ mysql_execute_command(void)
res = mysql_restore_table(thd, tables);
break;
}
+
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_CHANGE_MASTER:
{
if (check_global_access(thd, SUPER_ACL))
@@ -1488,7 +1844,7 @@ mysql_execute_command(void)
res = show_binlog_info(thd);
break;
}
-
+
case SQLCOM_LOAD_MASTER_DATA: // sync with master
if (check_global_access(thd, SUPER_ACL))
goto error;
@@ -1497,7 +1853,8 @@ mysql_execute_command(void)
else
res = load_master_data(thd);
break;
-
+#endif /* EMBEDDED_LIBRARY */
+
#ifdef HAVE_INNOBASE_DB
case SQLCOM_SHOW_INNODB_STATUS:
{
@@ -1508,6 +1865,7 @@ mysql_execute_command(void)
}
#endif
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_LOAD_MASTER_TABLE:
{
if (!tables->db)
@@ -1524,16 +1882,23 @@ mysql_execute_command(void)
if (error)
goto error;
}
+ if (strlen(tables->real_name) > NAME_LEN)
+ {
+ net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name);
+ break;
+ }
LOCK_ACTIVE_MI;
// fetch_master_table will send the error to the client on failure
if (!fetch_master_table(thd, tables->db, tables->real_name,
active_mi, 0))
{
- send_ok(&thd->net);
+ send_ok(thd);
}
UNLOCK_ACTIVE_MI;
break;
}
+#endif /* EMBEDDED_LIBRARY */
+
case SQLCOM_CREATE_TABLE:
{
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
@@ -1557,7 +1922,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;
}
@@ -1579,25 +1944,22 @@ mysql_execute_command(void)
select_result *result;
if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- check_dup(tables->db, tables->real_name, tables->next))
+ find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
- net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
if (tables->next)
{
- TABLE_LIST *table;
if (check_table_access(thd, SELECT_ACL, tables->next))
goto error; // Error message is given
- /* TODO: Delete the following loop when locks is set by sql_yacc */
- for (table = tables->next ; table ; table=table->next)
- table->lock_type= lex->lock_option;
}
select_lex->options|= SELECT_NO_UNLOCK;
- 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=
@@ -1616,12 +1978,16 @@ mysql_execute_command(void)
}
else // regular create
{
- 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
+ if (lex->name)
+ res= mysql_create_like_table(thd, tables, &lex->create_info,
+ (Table_ident *)lex->name);
+ else
+ 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,0); // do logging
if (!res)
- send_ok(&thd->net);
+ send_ok(thd);
}
break;
}
@@ -1638,6 +2004,7 @@ mysql_execute_command(void)
res = mysql_create_index(thd, tables, lex->key_list);
break;
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_SLAVE_START:
{
LOCK_ACTIVE_MI;
@@ -1661,7 +2028,7 @@ mysql_execute_command(void)
*/
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;
}
{
@@ -1670,16 +2037,18 @@ mysql_execute_command(void)
UNLOCK_ACTIVE_MI;
break;
}
+#endif
+
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;
}
@@ -1689,7 +2058,7 @@ mysql_execute_command(void)
select_lex->db=tables->db;
if (check_access(thd,ALTER_ACL,tables->db,&tables->grant.privilege) ||
check_access(thd,INSERT_ACL | CREATE_ACL,select_lex->db,&priv) ||
- check_merge_table_access(thd, tables->db,
+ check_merge_table_access(thd, tables->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
goto error; /* purecov: inspected */
@@ -1721,6 +2090,7 @@ mysql_execute_command(void)
&lex->create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
+ select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
lex->alter_keys_onoff, lex->simple_alter);
@@ -1760,9 +2130,10 @@ mysql_execute_command(void)
res= -1;
break;
}
+#ifndef EMBEDDED_LIBRARY
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
{
@@ -1771,10 +2142,11 @@ mysql_execute_command(void)
res = show_binlogs(thd);
break;
}
-#endif
+#endif
+#endif /* EMBEDDED_LIBRARY */
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
{
@@ -1828,11 +2200,12 @@ 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,
- (ORDER *) 0,
- 0,DUP_ERROR);
+ 0, (ORDER *) 0,
+ 0, DUP_ERROR);
}
else
res = mysql_optimize_table(thd, tables, &lex->check_opt);
@@ -1851,31 +2224,40 @@ 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)
+ res= mysql_update(thd,tables,
+ select_lex->item_list,
+ lex->value_list,
+ select_lex->where,
+ select_lex->order_list.elements,
+ (ORDER *) select_lex->order_list.first,
+ select_lex->select_limit,
+ lex->duplicates);
+ if (thd->net.report_error)
+ res= -1;
+ break;
+ case SQLCOM_UPDATE_MULTI:
+ if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
+ goto error;
+ if (grant_option && check_grant(thd,UPDATE_ACL,tables))
+ goto error;
+ if (select_lex->item_list.elements != lex->value_list.elements)
{
- res= mysql_update(thd,tables,
- select_lex->item_list,
- lex->value_list,
- select_lex->where,
- (ORDER *) select_lex->order_list.first,
- select_lex->select_limit,
- lex->duplicates);
+ send_error(thd,ER_WRONG_VALUE_COUNT);
+ DBUG_VOID_RETURN;
}
- else
{
const char *msg= 0;
- lex->sql_command= SQLCOM_MULTI_UPDATE;
if (select_lex->order_list.elements)
- msg="ORDER BY";
+ msg= "ORDER BY";
else if (select_lex->select_limit && select_lex->select_limit !=
HA_POS_ERROR)
- msg="LIMIT";
+ msg= "LIMIT";
if (msg)
{
- net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg);
+ net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
res= 1;
break;
}
@@ -1884,28 +2266,31 @@ mysql_execute_command(void)
&lex->value_list,
select_lex->where,
select_lex->options,
- lex->duplicates);
+ lex->duplicates, unit, select_lex);
}
break;
- case SQLCOM_INSERT:
- if (check_access(thd,INSERT_ACL,tables->db,&tables->grant.privilege))
- goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INSERT_ACL,tables))
- goto error;
- res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- lex->duplicates);
- break;
case SQLCOM_REPLACE:
- if (check_access(thd,INSERT_ACL | DELETE_ACL,
- tables->db,&tables->grant.privilege))
+ case SQLCOM_INSERT:
+ {
+ my_bool update=(lex->value_list.elements ? UPDATE_ACL : 0);
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
+ if (check_access(thd,privilege,tables->db,&tables->grant.privilege))
goto error; /* purecov: inspected */
- if (grant_option && check_grant(thd,INSERT_ACL | DELETE_ACL,
- tables))
-
+ if (grant_option && check_grant(thd,privilege,tables))
goto error;
+ if (select_lex->item_list.elements != lex->value_list.elements)
+ {
+ send_error(thd,ER_WRONG_VALUE_COUNT);
+ DBUG_VOID_RETURN;
+ }
res = mysql_insert(thd,tables,lex->field_list,lex->many_values,
- DUP_REPLACE);
+ select_lex->item_list, lex->value_list,
+ (update ? DUP_UPDATE : lex->duplicates));
+ if (thd->net.report_error)
+ res= -1;
break;
+ }
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
@@ -1915,8 +2300,8 @@ mysql_execute_command(void)
select privileges for the rest
*/
{
- ulong privilege= (lex->sql_command == SQLCOM_INSERT_SELECT ?
- INSERT_ACL : INSERT_ACL | DELETE_ACL);
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
TABLE_LIST *save_next=tables->next;
tables->next=0;
if (check_access(thd, privilege,
@@ -1931,22 +2316,16 @@ mysql_execute_command(void)
select_lex->options|= SELECT_NO_UNLOCK;
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))
+ if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
- net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name);
+ net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
DBUG_VOID_RETURN;
}
- {
- /* TODO: Delete the following loop when locks is set by sql_yacc */
- TABLE_LIST *table;
- for (table = tables->next ; table ; table=table->next)
- table->lock_type= lex->lock_option;
- }
/* Skip first table, which is the table we are inserting in */
lex->select_lex.table_list.first=
@@ -1956,6 +2335,8 @@ mysql_execute_command(void)
if ((result=new select_insert(tables->table,&lex->field_list,
lex->duplicates)))
res=handle_select(thd,lex,result);
+ if (thd->net.report_error)
+ res= -1;
}
else
res= -1;
@@ -1972,7 +2353,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);
@@ -1988,6 +2369,8 @@ mysql_execute_command(void)
res = mysql_delete(thd,tables, select_lex->where,
(ORDER*) select_lex->order_list.first,
select_lex->select_limit, select_lex->options);
+ if (thd->net.report_error)
+ res= -1;
break;
}
case SQLCOM_DELETE_MULTI:
@@ -1999,12 +2382,12 @@ mysql_execute_command(void)
/* sql_yacc guarantees that tables and aux_tables are not zero */
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
- check_table_access(thd,SELECT_ACL, tables) ||
+ check_table_access(thd,SELECT_ACL, tables) ||
check_table_access(thd,DELETE_ACL, aux_tables))
goto error;
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
- {
- send_error(&thd->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)
@@ -2020,36 +2403,52 @@ 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;
- // Store address to table as we need it later
- auxi->table= my_reinterpret_cast(TABLE *) (walk);
+ auxi->table_list= walk; // Remember corresponding table
}
- if (add_item_to_list(new Item_null()))
+ if (add_item_to_list(thd, new Item_null()))
{
res= -1;
break;
}
- 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= (my_reinterpret_cast(TABLE_LIST*) (auxi->table))->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 | SELECT_NO_UNLOCK,
- result);
+ auxi->table= auxi->table_list->table;
+ if (&lex->select_lex != lex->all_selects_list)
+ {
+ for (TABLE_LIST *t= select_lex->get_table_list();
+ t; t= t->next)
+ {
+ if (find_real_table_in_list(t->table_list->next, t->db, t->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), t->real_name);
+ res= -1;
+ break;
+ }
+ }
+ }
+ fix_tables_pointers(lex->all_selects_list);
+ if (!thd->is_fatal_error && (result= new multi_delete(thd,aux_tables,
+ table_count)))
+ {
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
+ select_lex->get_table_list(),
+ select_lex->with_wild,
+ select_lex->item_list,
+ select_lex->where,
+ 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
+ result, unit, select_lex, 0);
+ if (thd->net.report_error)
+ res= -1;
delete result;
}
else
@@ -2059,12 +2458,17 @@ mysql_execute_command(void)
}
case SQLCOM_DROP_TABLE:
{
- if (check_table_access(thd,DROP_ACL,tables))
- goto error; /* purecov: inspected */
- if (end_active_trans(thd))
- res= -1;
- else
- res = mysql_rm_table(thd,tables,lex->drop_if_exists);
+ if (!lex->drop_temporary)
+ {
+ if (check_table_access(thd,DROP_ACL,tables))
+ goto error; /* purecov: inspected */
+ if (end_active_trans(thd))
+ {
+ res= -1;
+ break;
+ }
+ }
+ res= mysql_rm_table(thd,tables,lex->drop_if_exists, lex->drop_temporary);
}
break;
case SQLCOM_DROP_INDEX:
@@ -2081,7 +2485,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) &&
@@ -2096,6 +2500,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);
@@ -2105,27 +2518,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))
@@ -2143,16 +2563,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 '_'
@@ -2170,14 +2593,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 '_'
@@ -2196,10 +2619,11 @@ mysql_execute_command(void)
case SQLCOM_CHANGE_DB:
mysql_change_db(thd,select_lex->db);
break;
+#ifndef EMBEDDED_LIBRARY
case SQLCOM_LOAD:
{
uint privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | UPDATE_ACL | DELETE_ACL : INSERT_ACL);
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
if (!lex->local_file)
{
@@ -2211,7 +2635,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) ||
@@ -2222,10 +2646,18 @@ mysql_execute_command(void)
lex->duplicates, (bool) lex->local_file, lex->lock_option);
break;
}
+#endif /* EMBEDDED_LIBRARY */
case SQLCOM_SET_OPTION:
- if (!(res=sql_set_variables(thd, &lex->var_list)))
- send_ok(&thd->net);
+ if (tables && ((res= check_table_access(thd, SELECT_ACL, tables)) ||
+ (res= open_and_lock_tables(thd,tables))))
+ break;
+ fix_tables_pointers(lex->all_selects_list);
+ if (!(res= sql_set_variables(thd, &lex->var_list)))
+ send_ok(thd);
+ if (thd->net.report_error)
+ res= -1;
break;
+
case SQLCOM_UNLOCK_TABLES:
unlock_locked_tables(thd);
if (thd->options & OPTION_TABLE_LOCK)
@@ -2235,7 +2667,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);
@@ -2249,7 +2681,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);
@@ -2259,7 +2691,7 @@ 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;
}
/*
@@ -2269,21 +2701,22 @@ mysql_execute_command(void)
do_db/ignore_db. And as this query involves no tables, tables_ok()
above was not called. So we have to check rules again here.
*/
+#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
break;
-
+#endif
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;
}
/*
@@ -2293,26 +2726,62 @@ mysql_execute_command(void)
do_db/ignore_db. And as this query involves no tables, tables_ok()
above was not called. So we have to check rules again here.
*/
+#ifdef HAVE_REPLICATION
if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
break;
+#endif
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
@@ -2321,8 +2790,8 @@ mysql_execute_command(void)
if (check_access(thd,DELETE_ACL,"mysql",0,1))
break;
#ifdef HAVE_DLOPEN
- if (!(res = mysql_drop_function(thd,lex->udf.name)))
- send_ok(&thd->net);
+ if (!(res = mysql_drop_function(thd,&lex->udf.name)))
+ send_ok(thd);
#else
res= -1;
#endif
@@ -2350,7 +2819,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(&my_charset_latin1,
+ user->host.str, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
goto error;
@@ -2381,7 +2851,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
@@ -2411,7 +2881,7 @@ mysql_execute_command(void)
if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables))
goto error;
/* error sending is deferred to reload_acl_and_cache */
- reload_acl_and_cache(thd, lex->type, tables) ;
+ reload_acl_and_cache(thd, lex->type, tables);
break;
case SQLCOM_KILL:
kill_one_thread(thd,lex->thread_id);
@@ -2461,7 +2931,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:
@@ -2475,7 +2945,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;
@@ -2486,21 +2956,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;
@@ -2533,7 +3003,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 */
}
@@ -2546,7 +3016,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 */
@@ -2571,7 +3041,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 */
@@ -2587,7 +3057,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;
}
@@ -2607,6 +3077,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;
@@ -2642,7 +3114,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 */
}
}
@@ -2665,7 +3137,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;
}
}
@@ -2694,7 +3166,7 @@ bool check_stack_overrun(THD *thd,char *buf __attribute__((unused)))
{
sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack);
my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0));
- thd->fatal_error=1;
+ thd->fatal_error();
return 1;
}
return 0;
@@ -2733,111 +3205,174 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
/****************************************************************************
- Initialize global thd variables needed for query
+ 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->unit.thd= thd;
+ lex->select_lex.init_query();
+ lex->value_list.empty();
+ lex->param_list.empty();
+ lex->unit.next= lex->unit.master= lex->unit.link_next= 0;
+ lex->unit.prev= lex->unit.link_prev= 0;
+ lex->unit.global_parameters= lex->unit.slave= lex->current_select=
+ lex->all_selects_list= &lex->select_lex;
+ lex->select_lex.master= &lex->unit;
+ lex->select_lex.prev= &lex->unit.slave;
+ lex->select_lex.link_next= lex->select_lex.slave= lex->select_lex.next= 0;
+ lex->select_lex.link_prev= (st_select_lex_node**)&(lex->all_selects_list);
+ lex->describe= 0;
+ lex->derived_tables= FALSE;
+ lex->lock_option= TL_READ;
+ lex->found_colon= 0;
+ lex->safe_to_cache_query= 1;
+ 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->is_fatal_error= thd->rand_used= 0;
+ thd->server_status &= ~SERVER_MORE_RESULTS_EXISTS;
+ thd->tmp_table_used= 0;
+ if (opt_bin_log)
+ reset_dynamic(&thd->user_var_events);
+ thd->clear_error();
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.empty();
- select_lex->group_list.empty();
- select_lex->next = (SELECT_LEX *)NULL;
+ SELECT_LEX *select_lex= lex->current_select->select_lex();
+ select_lex->init_select();
+ select_lex->master_unit()->select_limit= select_lex->select_limit=
+ lex->thd->variables.select_limit;
+ if (select_lex == &lex->select_lex)
+ {
+ 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->thd= lex->thd;
+ unit->include_down(lex->current_select);
+ unit->link_next= 0;
+ unit->link_prev= 0;
+ select_lex->include_down(unit);
+ }
+ else
+ select_lex->include_neighbour(lex->current_select);
+
+ select_lex->master_unit()->global_parameters= select_lex;
+ select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
+ 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(lex->thd, 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");
mysql_init_query(thd);
- thd->query_length = length;
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
LEX *lex=lex_start(thd, (uchar*) inBuf, length);
- if (!yyparse() && ! thd->fatal_error)
+ if (!yyparse((void *)thd) && ! thd->is_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();
- query_cache_end_of_result(&thd->net);
+ if (thd->net.report_error)
+ send_error(thd, 0, NullS);
+ else
+ {
+ mysql_execute_command(thd);
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
+ query_cache_end_of_result(&thd->net);
+#endif
+ }
}
}
else
{
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
- thd->fatal_error));
+ thd->is_fatal_error));
+#ifndef EMBEDDED_LIBRARY /* TODO query cache in embedded library*/
query_cache_abort(&thd->net);
+#endif
}
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;
@@ -2849,33 +3384,34 @@ mysql_parse(THD *thd,char *inBuf,uint length)
** Return 0 if ok
******************************************************************************/
-bool add_field_to_list(char *field_name, enum_field_types type,
+bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
char *length, char *decimals,
- uint type_modifier, Item *default_value,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();
}
@@ -2885,7 +3421,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;
@@ -2905,6 +3441,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 */
@@ -2936,10 +3485,7 @@ 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;
case FIELD_TYPE_DECIMAL:
if (!length)
@@ -2948,17 +3494,43 @@ 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:
+ case FIELD_TYPE_GEOMETRY:
+ 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;
@@ -2978,7 +3550,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)
@@ -3032,7 +3604,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;
@@ -3048,13 +3620,17 @@ bool add_field_to_list(char *field_name, enum_field_types type,
set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
if (default_value)
{
+ char *not_used;
+ uint not_used2;
+
thd->cuted_fields=0;
String str,*res;
res=default_value->val_str(&str);
- (void) find_set(interval,res->ptr(),res->length());
+ (void) find_set(interval, res->ptr(), res->length(), &not_used,
+ &not_used2);
if (thd->cuted_fields)
{
- net_printf(&thd->net,ER_INVALID_DEFAULT,field_name);
+ net_printf(thd,ER_INVALID_DEFAULT,field_name);
DBUG_RETURN(1);
}
}
@@ -3077,7 +3653,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);
}
}
@@ -3087,16 +3663,17 @@ bool add_field_to_list(char *field_name, enum_field_types type,
if (new_field->length >= MAX_FIELD_WIDTH ||
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
- type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING))
+ type != FIELD_TYPE_STRING &&
+ type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
{
- 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)
@@ -3123,7 +3700,7 @@ add_proc_to_list(THD* thd, Item *item)
ORDER *order;
Item **item_ptr;
- if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
return 1;
item_ptr = (Item**) (order+1);
*item_ptr= item;
@@ -3149,8 +3726,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++;
@@ -3170,12 +3747,12 @@ static void remove_escape(char *name)
****************************************************************************/
-bool add_to_list(SQL_LIST &list,Item *item,bool asc)
+bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc)
{
ORDER *order;
Item **item_ptr;
DBUG_ENTER("add_to_list");
- if (!(order = (ORDER *) sql_alloc(sizeof(ORDER)+sizeof(Item*))))
+ if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))
DBUG_RETURN(1);
item_ptr = (Item**) (order+1);
*item_ptr=item;
@@ -3207,14 +3784,15 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc)
# Pointer to TABLE_LIST element added to the total table list
*/
-TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
- ulong table_options,
- thr_lock_type lock_type,
- List<String> *use_index,
- List<String> *ignore_index)
+TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
+ Table_ident *table,
+ LEX_STRING *alias,
+ ulong table_options,
+ thr_lock_type lock_type,
+ List<String> *use_index,
+ List<String> *ignore_index)
{
register TABLE_LIST *ptr;
- THD *thd=current_thd;
char *alias_str;
DBUG_ENTER("add_table_to_list");
@@ -3224,17 +3802,23 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (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);
}
if (!alias) /* Alias is case sensitive */
+ {
+ if (table->sel)
+ {
+ net_printf(thd,ER_DERIVED_MUST_HAVE_ALIAS);
+ DBUG_RETURN(0);
+ }
if (!(alias_str=thd->memdup(alias_str,table->table.length+1)))
DBUG_RETURN(0);
-
+ }
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
- if (table->db.str)
+ if (table->db.str)
{
ptr->db= table->db.str;
ptr->db_length= table->db.length;
@@ -3246,18 +3830,20 @@ 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(table->table.str);
+ if (lower_case_table_names && table->table.length)
+ my_casedn_str(files_charset_info, table->table.str);
ptr->real_name=table->table.str;
ptr->real_name_length=table->table.length;
- ptr->lock_type= lock_type;
+ ptr->lock_type= lock_type;
ptr->updating= test(table_options & TL_OPTION_UPDATING);
ptr->force_index= test(table_options & TL_OPTION_FORCE_INDEX);
+ ptr->derived= table->sel;
if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
sizeof(*use_index));
@@ -3268,21 +3854,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
/* check that used name is unique */
if (lock_type != 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 */
}
}
}
- thd->lex.select->table_list.link_in_list((byte*) ptr,(byte**) &ptr->next);
+ table_list.link_in_list((byte*) ptr, (byte**) &ptr->next);
DBUG_RETURN(ptr);
}
+
/*
Set lock for all tables in current select level
@@ -3296,15 +3883,14 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
query
*/
-void set_lock_for_tables(thr_lock_type lock_type)
+void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
{
- THD *thd=current_thd;
bool for_update= lock_type >= TL_READ_NO_INSERT;
DBUG_ENTER("set_lock_for_tables");
DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
for_update));
- for (TABLE_LIST *tables= (TABLE_LIST*) thd->lex.select->table_list.first ;
+ for (TABLE_LIST *tables= (TABLE_LIST*) table_list.first ;
tables ;
tables=tables->next)
{
@@ -3315,67 +3901,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;
- 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= my_reinterpret_cast(TABLE *) (cursor);
- }
- }
- }
- return 0;
-}
-
-
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (expr)
@@ -3397,16 +3922,6 @@ void add_join_natural(TABLE_LIST *a,TABLE_LIST *b)
b->natural_join=a;
}
- /* Check if name is used in table list */
-
-static bool check_dup(const char *db, const char *name, TABLE_LIST *tables)
-{
- for (; tables ; tables=tables->next)
- if (!strcmp(name,tables->real_name) && !strcmp(db,tables->db))
- return 1;
- return 0;
-}
-
/*
Reload/resets privileges and the different caches
@@ -3429,6 +3944,14 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
mysql_log.new_file(1);
mysql_update_log.new_file(1);
mysql_bin_log.new_file(1);
+#ifdef HAVE_REPLICATION
+ if (expire_logs_days)
+ {
+ long purge_time= time(0) - expire_logs_days*24*60*60;
+ if (purge_time >= 0)
+ mysql_bin_log.purge_logs_before_date(thd, purge_time);
+ }
+#endif
mysql_slow_log.new_file(1);
if (ha_flush_logs())
result=1;
@@ -3461,9 +3984,11 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
refresh_status();
if (options & REFRESH_THREADS)
flush_thread_cache();
+#ifndef EMBEDDED_LIBRARY
if (options & REFRESH_MASTER)
if (reset_master(thd))
result=1;
+#endif
#ifdef OPENSSL
if (options & REFRESH_DES_KEY_FILE)
{
@@ -3471,6 +3996,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
result=load_des_key_file(des_key_file);
}
#endif
+#ifndef EMBEDDED_LIBRARY
if (options & REFRESH_SLAVE)
{
LOCK_ACTIVE_MI;
@@ -3487,15 +4013,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables)
}
UNLOCK_ACTIVE_MI;
}
+#endif
if (options & REFRESH_USER_RESOURCES)
reset_mqh(thd,(LEX_USER *) NULL);
if (thd && !error_already_sent)
{
if (result)
- send_error(&thd->net,0);
+ send_error(thd,0);
else
- send_ok(&thd->net);
+ send_ok(thd);
}
return result;
@@ -3543,9 +4070,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 */
@@ -3603,13 +4130,43 @@ 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;
}
+
+compare_func_creator comp_eq_creator(bool invert)
+{
+ return invert?&Item_bool_func2::ne_creator:&Item_bool_func2::eq_creator;
+}
+
+compare_func_creator comp_ge_creator(bool invert)
+{
+ return invert?&Item_bool_func2::lt_creator:&Item_bool_func2::ge_creator;
+}
+
+compare_func_creator comp_gt_creator(bool invert)
+{
+ return invert?&Item_bool_func2::le_creator:&Item_bool_func2::gt_creator;
+}
+
+compare_func_creator comp_le_creator(bool invert)
+{
+ return invert?&Item_bool_func2::gt_creator:&Item_bool_func2::le_creator;
+}
+
+compare_func_creator comp_lt_creator(bool invert)
+{
+ return invert?&Item_bool_func2::ge_creator:&Item_bool_func2::lt_creator;
+}
+
+compare_func_creator comp_ne_creator(bool invert)
+{
+ return invert?&Item_bool_func2::eq_creator:&Item_bool_func2::ne_creator;
+}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
new file mode 100644
index 00000000000..fc8959c6493
--- /dev/null
+++ b/sql/sql_prepare.cc
@@ -0,0 +1,974 @@
+/* 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';
+ in the following format:
+ [COM_PREPARE:1] [query]
+ - Parse the query and recognize any parameter markers '?' and
+ store its information list in lex->param_list
+ - Allocate a new statement for this prepare; and keep this in
+ 'thd->prepared_statements' pool.
+ - Without executing the query, return back to client the total
+ number of parameters along with result-set metadata information
+ (if any) in the following format:
+ [STMT_ID:4]
+ [Column_count:2]
+ [Param_count:2]
+ [Columns meta info] (if Column_count > 0)
+ [Params meta info] (if Param_count > 0 ) (TODO : 4.1.1)
+
+Prepare-execute:
+
+ - Server gets the command 'COM_EXECUTE' to execute the
+ previously prepared query. If there is any param markers; then client
+ will send the data in the following format:
+ [COM_EXECUTE:1]
+ [STMT_ID:4]
+ [NULL_BITS:(param_count+7)/8)]
+ [TYPES_SUPPLIED_BY_CLIENT(0/1):1]
+ [[length]data]
+ [[length]data] .. [[length]data].
+ (Note: Except for string/binary types; all other types will not be
+ supplied with length field)
+ - Replace the param items with this new data. If it is a first execute
+ or types altered by client; then setup the conversion routines.
+ - Execute the query without re-parsing and send back the results
+ to client
+
+Long data handling:
+
+ - Server gets the long data in pieces with command type 'COM_LONG_DATA'.
+ - The packet recieved will have the format as:
+ [COM_LONG_DATA:1][STMT_ID:4][parameter_number:2][type:2][data]
+ - Checks if the type is specified by client, and if yes reads the type,
+ and stores the data in that format.
+ - It's up to the client to check for read data ended. The server doesn't
+ care; and also server doesn't notify to the client that it got the
+ data or not; if there is any error; then during execute; the error
+ will be returned
+
+***********************************************************************/
+
+#include "mysql_priv.h"
+#include "sql_acl.h"
+#include "sql_select.h" // for JOIN
+#include <m_ctype.h> // for isspace()
+
+#define IS_PARAM_NULL(pos, param_no) pos[param_no/8] & (1 << param_no & 7)
+
+extern int yyparse(void *thd);
+
+/*
+ Find prepared statement in thd
+
+ 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(void *not_used, PREP_STMT *stmt, ulong *key)
+{
+ return (stmt->stmt_id == *key) ? 0 : (stmt->stmt_id < *key) ? -1 : 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)
+{
+ my_free((char *)stmt->param, MYF(MY_ALLOW_ZERO_PTR));
+ free_items(stmt->free_list);
+ free_root(&stmt->mem_root, MYF(0));
+}
+
+/*
+ Send prepared stmt info to client after prepare
+*/
+
+static bool send_prep_stmt(PREP_STMT *stmt, uint columns)
+{
+ NET *net=&stmt->thd->net;
+ char buff[8];
+ int4store(buff, stmt->stmt_id);
+ int2store(buff+4, columns);
+ int2store(buff+6, stmt->param_count);
+#ifndef EMBEDDED_LIBRARY
+ /* This should be fixed to work with prepared statements
+ */
+ return (my_net_write(net, buff, sizeof(buff)) || net_flush(net));
+#else
+ return true;
+#endif
+}
+
+/*
+ Send information about all item parameters
+
+ TODO: Not yet ready
+*/
+
+static bool send_item_params(PREP_STMT *stmt)
+{
+#if 0
+ char buff[1];
+ buff[0]=0;
+ if (my_net_write(&stmt->thd->net, buff, sizeof(buff)))
+ return 1;
+ send_eof(stmt->thd);
+#endif
+ 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);
+}
+ /*
+ Setup param conversion routines
+
+ setup_param_xx()
+ param Parameter Item
+ pos Input data buffer
+
+ All these functions reads the data from pos and sets up that data
+ through 'param' and advances the buffer position to predifined
+ length position.
+
+ Make a note that the NULL handling is examined at first execution
+ (i.e. when input types altered) and for all subsequent executions
+ we don't read any values for this.
+
+ RETURN VALUES
+
+*/
+
+static void setup_param_tiny(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)(**pos));
+ *pos+= 1;
+}
+
+static void setup_param_short(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)sint2korr(*pos));
+ *pos+= 2;
+}
+
+static void setup_param_int32(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)sint4korr(*pos));
+ *pos+= 4;
+}
+
+static void setup_param_int64(Item_param *param, uchar **pos)
+{
+ param->set_int((longlong)sint8korr(*pos));
+ *pos+= 8;
+}
+
+static void setup_param_float(Item_param *param, uchar **pos)
+{
+ float data;
+ float4get(data,*pos);
+ param->set_double((double) data);
+ *pos+= 4;
+}
+
+static void setup_param_double(Item_param *param, uchar **pos)
+{
+ double data;
+ float8get(data,*pos);
+ param->set_double((double) data);
+ *pos+= 8;
+}
+
+static void setup_param_time(Item_param *param, uchar **pos)
+{
+ ulong length;
+
+ if ((length= get_param_length(pos)))
+ {
+ uchar *to= *pos;
+ TIME tm;
+
+ tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0;
+
+ tm.day= (ulong) sint4korr(to+1);
+ tm.hour= (uint) to[5];
+ tm.minute= (uint) to[6];
+ tm.second= (uint) to[7];
+
+ tm.year= tm.month= 0;
+ tm.neg= (bool)to[0];
+
+ param->set_time(&tm, TIMESTAMP_TIME);
+ }
+ *pos+= length;
+}
+
+static void setup_param_datetime(Item_param *param, uchar **pos)
+{
+ uint length= get_param_length(pos);
+
+ if (length)
+ {
+ uchar *to= *pos;
+ TIME tm;
+
+ tm.second_part= (length > 7 ) ? (ulong) sint4korr(to+7): 0;
+
+ if (length > 4)
+ {
+ tm.hour= (uint) to[4];
+ tm.minute= (uint) to[5];
+ tm.second= (uint) to[6];
+ }
+ else
+ tm.hour= tm.minute= tm.second= 0;
+
+ tm.year= (uint) sint2korr(to);
+ tm.month= (uint) to[2];
+ tm.day= (uint) to[3];
+ tm.neg= 0;
+
+ param->set_time(&tm, TIMESTAMP_FULL);
+ }
+ *pos+= length;
+}
+
+static void setup_param_date(Item_param *param, uchar **pos)
+{
+ ulong length;
+
+ if ((length= get_param_length(pos)))
+ {
+ uchar *to= *pos;
+ TIME tm;
+
+ tm.year= (uint) sint2korr(to);
+ tm.month= (uint) to[2];
+ tm.day= (uint) to[3];
+
+ tm.hour= tm.minute= tm.second= 0;
+ tm.second_part= 0;
+ tm.neg= 0;
+
+ param->set_time(&tm, TIMESTAMP_DATE);
+ }
+ *pos+= length;
+}
+
+static void setup_param_str(Item_param *param, uchar **pos)
+{
+ ulong len= get_param_length(pos);
+ param->set_value((const char *)*pos, len);
+ *pos+= len;
+}
+
+static void setup_param_functions(Item_param *param, uchar param_type)
+{
+ switch (param_type) {
+ case FIELD_TYPE_TINY:
+ param->setup_param_func= setup_param_tiny;
+ param->item_result_type= INT_RESULT;
+ break;
+ case FIELD_TYPE_SHORT:
+ param->setup_param_func= setup_param_short;
+ param->item_result_type= INT_RESULT;
+ break;
+ case FIELD_TYPE_LONG:
+ param->setup_param_func= setup_param_int32;
+ param->item_result_type= INT_RESULT;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ param->setup_param_func= setup_param_int64;
+ param->item_result_type= INT_RESULT;
+ break;
+ case FIELD_TYPE_FLOAT:
+ param->setup_param_func= setup_param_float;
+ param->item_result_type= REAL_RESULT;
+ break;
+ case FIELD_TYPE_DOUBLE:
+ param->setup_param_func= setup_param_double;
+ param->item_result_type= REAL_RESULT;
+ break;
+ case FIELD_TYPE_TIME:
+ param->setup_param_func= setup_param_time;
+ param->item_result_type= STRING_RESULT;
+ break;
+ case FIELD_TYPE_DATE:
+ param->setup_param_func= setup_param_date;
+ param->item_result_type= STRING_RESULT;
+ break;
+ case FIELD_TYPE_DATETIME:
+ case FIELD_TYPE_TIMESTAMP:
+ param->setup_param_func= setup_param_datetime;
+ param->item_result_type= STRING_RESULT;
+ break;
+ default:
+ param->setup_param_func= setup_param_str;
+ param->item_result_type= STRING_RESULT;
+ }
+}
+
+/*
+ Update the parameter markers by reading the data
+ from client ..
+*/
+
+static bool setup_params_data(PREP_STMT *stmt)
+{
+ THD *thd= stmt->thd;
+ List<Item> &params= thd->lex.param_list;
+ List_iterator<Item> param_iterator(params);
+ Item_param *param;
+ DBUG_ENTER("setup_params_data");
+
+#ifndef EMBEDDED_LIBRARY
+ uchar *pos=(uchar*) thd->net.read_pos+1+MYSQL_STMT_HEADER; //skip header
+#else
+ uchar *pos= 0; //just to compile TODO code for embedded case
+#endif
+ uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits
+
+ if (*read_pos++) //types supplied / first execute
+ {
+ /*
+ First execute or types altered by the client, setup the
+ conversion routines for all parameters (one time)
+ */
+ while ((param= (Item_param *)param_iterator++))
+ {
+ setup_param_functions(param,*read_pos);
+ read_pos+= 2;
+ }
+ param_iterator.rewind();
+ }
+ ulong param_no= 0;
+ while ((param= (Item_param *)param_iterator++))
+ {
+ if (!param->long_data_supplied)
+ {
+ if (IS_PARAM_NULL(pos,param_no))
+ param->maybe_null= param->null_value= 1;
+ else
+ {
+ param->maybe_null= param->null_value= 0;
+ param->setup_param_func(param,&read_pos);
+ }
+ }
+ param_no++;
+ }
+ DBUG_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)
+{
+ THD *thd= stmt->thd;
+ TABLE *table;
+ List_iterator_fast<List_item> its(values_list);
+ List_item *values;
+ DBUG_ENTER("mysql_test_insert_fields");
+
+ my_bool update=(thd->lex.value_list.elements ? UPDATE_ACL : 0);
+ ulong privilege= (thd->lex.duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
+
+ if (check_access(thd,privilege,table_list->db,
+ &table_list->grant.privilege) ||
+ (grant_option && check_grant(thd,privilege,table_list)) ||
+ open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(1);
+
+ table= table_list->table;
+
+ 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)
+{
+ THD *thd= stmt->thd;
+ DBUG_ENTER("mysql_test_upd_fields");
+
+ if (check_access(thd,UPDATE_ACL,table_list->db,
+ &table_list->grant.privilege) ||
+ (grant_option && check_grant(thd,UPDATE_ACL,table_list)) ||
+ open_and_lock_tables(thd, table_list))
+ DBUG_RETURN(1);
+
+ if (setup_tables(table_list) ||
+ setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
+ setup_conds(thd, table_list, &conds) || thd->net.report_error)
+ 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,
+ uint wild_num,
+ List<Item> &fields, COND *conds,
+ uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc,
+ ulong select_options,
+ SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex)
+{
+ THD *thd= stmt->thd;
+ LEX *lex= &thd->lex;
+ select_result *result= thd->lex.result;
+ DBUG_ENTER("mysql_test_select_fields");
+
+ ulong privilege= lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL;
+ if (tables)
+ {
+ if (check_table_access(thd, privilege, tables))
+ DBUG_RETURN(1);
+ }
+ else if (check_access(thd, privilege, "*any*"))
+ DBUG_RETURN(1);
+
+ if ((&lex->select_lex != lex->all_selects_list &&
+ lex->unit.create_total_list(thd, lex, &tables, 0)))
+ DBUG_RETURN(1);
+
+ if (open_and_lock_tables(thd, tables))
+ DBUG_RETURN(1);
+
+ if (lex->describe)
+ {
+ if (send_prep_stmt(stmt, 0) || send_item_params(stmt))
+ DBUG_RETURN(1);
+ }
+ else
+ {
+ fix_tables_pointers(thd->lex.all_selects_list);
+ if (!result && !(result= new select_send()))
+ {
+ delete select_lex->having;
+ delete select_lex->where;
+ send_error(thd, ER_OUT_OF_RESOURCES);
+ DBUG_RETURN(1);
+ }
+
+ JOIN *join= new JOIN(thd, fields, select_options, result);
+ thd->used_tables= 0; // Updated by setup_fields
+
+ if (join->prepare(&select_lex->ref_pointer_array, tables,
+ wild_num, conds, og_num, order, group, having, proc,
+ select_lex, unit, 0))
+ DBUG_RETURN(1);
+ if (send_prep_stmt(stmt, fields.elements) ||
+ thd->protocol_simple.send_fields(&fields, 0) ||
+ send_item_params(stmt))
+ DBUG_RETURN(1);
+ join->cleanup(thd);
+ }
+ DBUG_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))
+ goto abort;
+ break;
+
+ case SQLCOM_UPDATE:
+ if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
+ lex->value_list, select_lex->where))
+ goto abort;
+ break;
+
+ case SQLCOM_DELETE:
+ if (mysql_test_upd_fields(stmt, tables, select_lex->item_list,
+ lex->value_list, select_lex->where))
+ goto abort;
+ break;
+
+ case SQLCOM_SELECT:
+ if (mysql_test_select_fields(stmt, tables, select_lex->with_wild,
+ select_lex->item_list,
+ select_lex->where,
+ select_lex->order_list.elements +
+ select_lex->group_list.elements,
+ (ORDER*) select_lex->order_list.first,
+ (ORDER*) select_lex->group_list.first,
+ select_lex->having,
+ (ORDER*)lex->proc_list.first,
+ select_lex->options | thd->options,
+ &(lex->unit), select_lex))
+ goto abort;
+ break;
+
+ default:
+ {
+ /*
+ Rest fall through to default category, no parsing
+ for non-DML statements
+ */
+ if (send_prep_stmt(stmt, 0))
+ goto abort;
+ }
+ }
+ 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);
+ LEX *lex=lex_start(thd, (uchar*) packet, length);
+ lex->safe_to_cache_query= 0;
+ thd->prepare_command= TRUE;
+ thd->lex.param_count= 0;
+ if (!yyparse((void *)thd) && !thd->is_fatal_error)
+ error= send_prepare_results(stmt);
+ lex_end(lex);
+ DBUG_RETURN(error);
+}
+
+/*
+ Initialize parameter items in statement
+*/
+
+static bool init_param_items(PREP_STMT *stmt)
+{
+ List<Item> &params= stmt->thd->lex.param_list;
+ Item_param **to;
+
+ stmt->lex= stmt->thd->lex;
+ if (!stmt->param_count)
+ stmt->param= (Item_param **)0;
+ else
+ {
+ if (!(stmt->param= to= (Item_param **)
+ my_malloc(sizeof(Item_param *)*(stmt->param_count+1),
+ MYF(MY_WME))))
+ return 1;
+ List_iterator<Item> param_iterator(params);
+ while ((*(to++)= (Item_param *)param_iterator++));
+ }
+ return 0;
+}
+
+/*
+ Initialize stmt execution
+*/
+
+static void init_stmt_execute(PREP_STMT *stmt)
+{
+ THD *thd= stmt->thd;
+ TABLE_LIST *tables= (TABLE_LIST*) thd->lex.select_lex.table_list.first;
+
+ /*
+ TODO: When the new table structure is ready, then have a status bit
+ to indicate the table is altered, and re-do the setup_*
+ and open the tables back.
+ */
+ for (; tables ; tables= tables->next)
+ tables->table= 0; //safety - nasty init
+}
+
+/*
+ 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.stmt_id= ++thd->current_stmt_id;
+ init_sql_alloc(&stmt.mem_root, 8192, 8192);
+
+ stmt.thd= thd;
+ stmt.thd->mem_root= stmt.mem_root;
+
+ if (alloc_query(stmt.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);
+
+ if (init_param_items(&stmt))
+ goto err;
+
+ stmt.mem_root= stmt.thd->mem_root;
+ tree_insert(&thd->prepared_statements, (void *)&stmt, 0, (void *)0);
+ thd->mem_root= thd_root; // restore main mem_root
+ DBUG_RETURN(0);
+
+err:
+ stmt.mem_root= stmt.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, stmt->last_errno, stmt->last_error);
+ DBUG_VOID_RETURN;
+ }
+
+ LEX thd_lex= thd->lex;
+ thd->lex= stmt->lex;
+ init_stmt_execute(stmt);
+
+ if (stmt->param_count && setup_params_data(stmt))
+ DBUG_VOID_RETURN;
+
+ 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 ..
+ */
+ thd->protocol= &thd->protocol_prep; // Switch to binary protocol
+ mysql_execute_command(thd);
+ thd->protocol= &thd->protocol_simple; // Use normal protocol
+
+ if (!(specialflag & SPECIAL_NO_PRIOR))
+ my_pthread_setprio(pthread_self(), WAIT_PRIOR);
+
+ thd->lex= thd_lex;
+ 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_free(THD *thd, char *packet)
+{
+ ulong stmt_id= uint4korr(packet);
+ PREP_STMT *stmt;
+ DBUG_ENTER("mysql_stmt_free");
+
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "close")))
+ {
+ send_error(thd); // Not seen by the client
+ DBUG_VOID_RETURN;
+ }
+ tree_delete(&thd->prepared_statements, (void*) &stmt_id, (void *)0);
+ thd->last_prepared_stmt= (PREP_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 < MYSQL_LONG_DATA_HEADER+1)
+ {
+ my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata");
+ DBUG_VOID_RETURN;
+ }
+
+ ulong stmt_id= uint4korr(pos);
+ uint param_number= uint2korr(pos+4);
+ pos+= MYSQL_LONG_DATA_HEADER; // Point to data
+
+ if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata")))
+ {
+ /*
+ 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)
+ {
+ /* Error will be sent in execute call */
+ stmt->error_in_prepare= 1;
+ stmt->last_errno= ER_WRONG_ARGUMENTS;
+ sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata");
+ DBUG_VOID_RETURN;
+ }
+ Item_param *param= *(stmt->param+param_number);
+ param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1);
+ stmt->long_data_used= 1;
+ DBUG_VOID_RETURN;
+}
+
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index d7e998264f3..19b4d299e59 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -85,7 +85,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
mysql_bin_log.write(&qinfo);
}
- send_ok(&thd->net);
+ send_ok(thd);
}
unlock_table_names(thd,table_list);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index d670c673b4a..98bbd8bbb98 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -17,12 +17,13 @@
// Sasha Pachev <sasha@mysql.com> is currently in charge of this file
#include "mysql_priv.h"
+#ifdef HAVE_REPLICATION
+
#include "sql_repl.h"
#include "sql_acl.h"
#include "log_event.h"
#include "mini_client.h"
#include <my_dir.h>
-#include <assert.h>
extern const char* any_db;
@@ -256,15 +257,10 @@ bool log_in_use(const char* log_name)
return result;
}
-
-int purge_master_logs(THD* thd, const char* to_log)
+int purge_error_message(THD* thd, int res)
{
- char search_file_name[FN_REFLEN];
const char* errmsg = 0;
- mysql_bin_log.make_log_name(search_file_name, to_log);
- int res = mysql_bin_log.purge_logs(thd, search_file_name);
-
switch(res) {
case 0: break;
case LOG_INFO_EOF: errmsg = "Target log not found in binlog index"; break;
@@ -283,15 +279,31 @@ 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;
}
+int purge_master_logs(THD* thd, const char* to_log)
+{
+ char search_file_name[FN_REFLEN];
+
+ mysql_bin_log.make_log_name(search_file_name, to_log);
+ int res = mysql_bin_log.purge_logs(thd, search_file_name);
+
+ return purge_error_message(thd, res);
+}
+
+
+int purge_master_logs_before_date(THD* thd, time_t purge_time)
+{
+ int res = mysql_bin_log.purge_logs_before_date(thd, purge_time);
+ return purge_error_message(thd ,res);
+}
+
/*
TODO: Clean up loop to only have one call to send_file()
*/
@@ -372,7 +384,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 +395,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 +430,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 +550,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 +605,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,25 +627,32 @@ 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;
+ int slave_errno;
+ if (!thd)
+ thd = current_thd;
int thread_mask;
DBUG_ENTER("start_slave");
if (check_access(thd, SUPER_ACL, any_db))
DBUG_RETURN(1);
lock_slave_threads(mi); // this allows us to cleanly read slave_running
+ // Get a mask of _stopped_ threads
init_thread_mask(&thread_mask,mi,1 /* inverse */);
+ /*
+ Below we will start all stopped threads.
+ But if the user wants to start only one thread, do as if the other thread
+ was running (as we don't wan't to touch the other thread), so set the
+ bit to 0 for the other thread
+ */
if (thd->lex.slave_thd_opt)
thread_mask &= thd->lex.slave_thd_opt;
- if (thread_mask)
+ if (thread_mask) //some threads are stopped, start them
{
if (init_master_info(mi,master_info_file,relay_log_info_file, 0))
slave_errno=ER_MASTER_INFO;
@@ -647,50 +666,73 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report)
slave_errno = ER_BAD_SLAVE;
}
else
- slave_errno = ER_SLAVE_MUST_STOP;
+ {
+ //no error if all threads are already started, only a warning
+ slave_errno= 0;
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING,
+ ER(ER_SLAVE_WAS_RUNNING));
+ }
unlock_slave_threads(mi);
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;
+ int slave_errno;
+ if (!thd)
+ thd = current_thd;
if (check_access(thd, SUPER_ACL, any_db))
return 1;
thd->proc_info = "Killing slave";
int thread_mask;
lock_slave_threads(mi);
+ // Get a mask of _running_ threads
init_thread_mask(&thread_mask,mi,0 /* not inverse*/);
+ /*
+ Below we will stop all running threads.
+ But if the user wants to stop only one thread, do as if the other thread
+ was stopped (as we don't wan't to touch the other thread), so set the
+ bit to 0 for the other thread
+ */
if (thd->lex.slave_thd_opt)
thread_mask &= thd->lex.slave_thd_opt;
- slave_errno = (thread_mask) ?
- terminate_slave_threads(mi,thread_mask,
- 1 /*skip lock */) : ER_SLAVE_NOT_RUNNING;
+
+ if (thread_mask)
+ {
+ slave_errno= terminate_slave_threads(mi,thread_mask,
+ 1 /*skip lock */);
+ }
+ else
+ {
+ //no error if both threads are already stopped, only a warning
+ slave_errno= 0;
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_NOT_RUNNING,
+ ER(ER_SLAVE_WAS_NOT_RUNNING));
+ }
unlock_slave_threads(mi);
thd->proc_info = 0;
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;
}
@@ -762,7 +804,7 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
err:
unlock_slave_threads(mi);
if (thd && error)
- send_error(&thd->net, sql_errno, errmsg);
+ send_error(thd, sql_errno, errmsg);
DBUG_RETURN(error);
}
@@ -807,7 +849,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
if (thread_mask) // We refuse if any slave thread is running
{
- net_printf(&thd->net,ER_SLAVE_MUST_STOP);
+ net_printf(thd,ER_SLAVE_MUST_STOP);
unlock_slave_threads(mi);
DBUG_RETURN(1);
}
@@ -817,7 +859,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);
}
@@ -878,7 +920,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);
unlock_slave_threads(mi);
DBUG_RETURN(1);
}
@@ -894,7 +936,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);
}
@@ -913,7 +955,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
unlock_slave_threads(mi);
thd->proc_info = 0;
- send_ok(&thd->net);
+ send_ok(thd);
DBUG_RETURN(0);
}
@@ -947,14 +989,15 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
int show_binlog_events(THD* thd)
{
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("show_binlog_events");
List<Item> field_list;
- const char* errmsg = 0;
+ const char *errmsg = 0;
IO_CACHE log;
File file = -1;
Log_event::init_show_field_list(&field_list);
- if (send_fields(thd, field_list, 1))
+ if (protocol-> send_fields(&field_list, 1))
DBUG_RETURN(-1);
if (mysql_bin_log.is_open())
@@ -968,8 +1011,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)
@@ -1002,7 +1045,7 @@ int show_binlog_events(THD* thd)
(ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,0)); )
{
if (event_count >= limit_start &&
- ev->net_send(thd, linfo.log_file_name, pos))
+ ev->net_send(protocol, linfo.log_file_name, pos))
{
errmsg = "Net error";
delete ev;
@@ -1041,38 +1084,39 @@ err:
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
int show_binlog_info(THD* thd)
{
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("show_binlog_info");
List<Item> field_list;
field_list.push_back(new Item_empty_string("File", FN_REFLEN));
- field_list.push_back(new Item_empty_string("Position",20));
- field_list.push_back(new Item_empty_string("Binlog_do_db",20));
- field_list.push_back(new Item_empty_string("Binlog_ignore_db",20));
+ field_list.push_back(new Item_return_int("Position",20,
+ MYSQL_TYPE_LONGLONG));
+ field_list.push_back(new Item_empty_string("Binlog_do_db",255));
+ field_list.push_back(new Item_empty_string("Binlog_ignore_db",255));
- if (send_fields(thd, field_list, 1))
+ if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
- String* packet = &thd->packet;
- packet->length(0);
+ protocol->prepare_for_resend();
if (mysql_bin_log.is_open())
{
LOG_INFO li;
mysql_bin_log.get_current_log(&li);
int dir_len = dirname_length(li.log_file_name);
- net_store_data(packet, li.log_file_name + dir_len);
- net_store_data(packet, (longlong)li.pos);
- net_store_data(packet, &binlog_do_db);
- net_store_data(packet, &binlog_ignore_db);
- if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length()))
+ protocol->store(li.log_file_name + dir_len, system_charset_info);
+ protocol->store((ulonglong) li.pos);
+ protocol->store(&binlog_do_db);
+ protocol->store(&binlog_ignore_db);
+ if (protocol->write())
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -1098,6 +1142,8 @@ int show_binlogs(THD* thd)
List<Item> field_list;
String *packet = &thd->packet;
uint length;
+ Protocol *protocol= thd->protocol;
+ DBUG_ENTER("show_binlogs");
if (!mysql_bin_log.is_open())
{
@@ -1107,8 +1153,8 @@ int show_binlogs(THD* thd)
}
field_list.push_back(new Item_empty_string("Log_name", 255));
- if (send_fields(thd, field_list, 1))
- return 1;
+ if (protocol->send_fields(&field_list, 1))
+ DBUG_RETURN(1);
mysql_bin_log.lock_index();
index_file=mysql_bin_log.get_index_file();
@@ -1117,22 +1163,22 @@ int show_binlogs(THD* thd)
/* The file ends with EOF or empty line */
while ((length=my_b_gets(index_file, fname, sizeof(fname))) > 1)
{
+ protocol->prepare_for_resend();
int dir_len = dirname_length(fname);
- packet->length(0);
/* The -1 is for removing newline from fname */
- net_store_data(packet, fname + dir_len, length-1-dir_len);
- if (my_net_write(net, (char*) packet->ptr(), packet->length()))
+ protocol->store(fname + dir_len, length-1-dir_len, system_charset_info);
+ if (protocol->write())
goto err;
}
mysql_bin_log.unlock_index();
- send_eof(net);
- return 0;
+ send_eof(thd);
+ DBUG_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;
+ DBUG_RETURN(1);
}
@@ -1168,3 +1214,7 @@ int log_loaded_block(IO_CACHE* file)
}
return 0;
}
+
+#endif /* HAVE_REPLICATION */
+
+
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index 15435382b08..e3d600b9798 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -1,3 +1,4 @@
+#ifdef HAVE_REPLICATION
#include "slave.h"
typedef struct st_slave_info
@@ -33,6 +34,7 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
int reset_slave(THD *thd, MASTER_INFO* mi);
int reset_master(THD* thd);
int purge_master_logs(THD* thd, const char* to_log);
+int purge_master_logs_before_date(THD* thd, time_t purge_time);
bool log_in_use(const char* log_name);
void adjust_linfo_offsets(my_off_t purge_offset);
int show_binlogs(THD* thd);
@@ -53,3 +55,6 @@ typedef struct st_load_file_info
} LOAD_FILE_INFO;
int log_loaded_block(IO_CACHE* file);
+
+#endif /* HAVE_REPLICATION */
+
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 96de43ae55c..0126b900b9a 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -29,7 +29,6 @@
#include <m_ctype.h>
#include <hash.h>
#include <ft_global.h>
-#include <assert.h>
const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"MAYBE_REF","ALL","range","index","fulltext" };
@@ -38,7 +37,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,
@@ -56,8 +56,8 @@ static store_key *get_store_key(THD *thd,
static bool make_simple_join(JOIN *join,TABLE *tmp_table);
static bool make_join_select(JOIN *join,SQL_SELECT *select,COND *item);
static void make_join_readinfo(JOIN *join,uint options);
-static void join_free(JOIN *join);
-static bool only_eq_ref_tables(JOIN *join,ORDER *order,table_map tables);
+static void join_free(JOIN *join, bool full);
+static bool only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables);
static void update_depend_map(JOIN *join);
static void update_depend_map(JOIN *join, ORDER *order);
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
@@ -65,7 +65,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 +112,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 +129,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(THD *thd, ORDER *order,
@@ -138,8 +139,16 @@ static TABLE *get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables);
static void calc_group_buffer(JOIN *join,ORDER *group);
static bool alloc_group_fields(JOIN *join,ORDER *group);
static bool make_sum_func_list(JOIN *join,List<Item> &fields);
-static bool change_to_use_tmp_fields(List<Item> &func);
-static bool change_refs_to_tmp_fields(THD *thd, List<Item> &func);
+// Create list for using with tempory table
+static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
+ List<Item> &new_list1,
+ List<Item> &new_list2,
+ uint elements, List<Item> &items);
+// Create list for using with tempory table
+static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
+ List<Item> &new_list1,
+ List<Item> &new_list2,
+ uint elements, List<Item> &items);
static void init_tmptable_sum_functions(Item_sum **func);
static void update_tmptable_sum_func(Item_sum **func,TABLE *tmp_table);
static void copy_sum_funcs(Item_sum **func_ptr);
@@ -148,7 +157,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
@@ -158,100 +167,153 @@ 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)
- res=mysql_union(thd,lex,result);
+ fix_tables_pointers(lex->all_selects_list);
+ if (select_lex->next_select())
+ res=mysql_union(thd, lex, result, &lex->unit, 0);
else
- 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*) lex->proc_list.first,
- select_lex->options | thd->options,
- result);
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
+ (TABLE_LIST*) select_lex->table_list.first,
+ select_lex->with_wild, select_lex->item_list,
+ select_lex->where,
+ select_lex->order_list.elements +
+ select_lex->group_list.elements,
+ (ORDER*) select_lex->order_list.first,
+ (ORDER*) select_lex->group_list.first,
+ select_lex->having,
+ (ORDER*) lex->proc_list.first,
+ select_lex->options | thd->options,
+ 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 relink_tables(SELECT_LEX *select_lex)
+{
+ for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first;
+ cursor;
+ cursor=cursor->next)
+ cursor->table= cursor->table_list->table;
+}
+
+
+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())
+ relink_tables(sl);
+ }
+}
+
+void fix_tables_pointers(SELECT_LEX_UNIT *unit)
+{
+ for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
+ {
+ relink_tables(sl);
+ for (SELECT_LEX_UNIT *un= sl->first_inner_unit(); un; un= un->next_unit())
+ fix_tables_pointers(un);
+ }
+}
+
+
+/*
+ Function to setup clauses without sum functions
+*/
+inline int setup_without_group(THD *thd, Item **ref_pointer_array,
+ TABLE_LIST *tables,
+ List<Item> &fields,
+ List<Item> &all_fields,
+ COND **conds,
+ ORDER *order,
+ ORDER *group, bool *hidden_group_fields)
+{
+ bool save_allow_sum_func= thd->allow_sum_func;
+ thd->allow_sum_func= 0;
+ int res= (setup_conds(thd, tables, conds) ||
+ setup_order(thd, ref_pointer_array, tables, fields, all_fields,
+ order) ||
+ setup_group(thd, ref_pointer_array, tables, fields, all_fields,
+ group, hidden_group_fields));
+ thd->allow_sum_func= save_allow_sum_func;
+ return res;
+}
+
/*****************************************************************************
Check fields, find best join, do the select and output fields.
mysql_select assumes that all tables are already opened
*****************************************************************************/
+/*
+ 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(Item ***rref_pointer_array,
+ TABLE_LIST *tables_init,
+ uint wild_num, COND *conds_init, uint og_num,
+ ORDER *order_init, ORDER *group_init,
+ Item *having_init,
+ ORDER *proc_param_init, SELECT_LEX *select,
+ SELECT_LEX_UNIT *unit,
+ bool tables_and_fields_initied)
+{
+ 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;
+ 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
- /* select_limit is used to decide if we are likely to scan the whole table */
- select_limit= thd->select_limit;
- if (having || (select_options & OPTION_FOUND_ROWS))
- select_limit= HA_POS_ERROR;
-
- 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 ((tables_and_fields_initied ? 0 : (setup_tables(tables_list) ||
+ setup_wild(thd, tables_list,
+ fields_list,
+ &all_fields, wild_num))) ||
+ setup_ref_array(thd, rref_pointer_array, (fields_list.elements +
+ select_lex->with_sum_func +
+ og_num)) ||
+ setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
+ &all_fields, 1) ||
+ setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list,
+ all_fields, &conds, order, group_list,
+ &hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */
+ ref_pointer_array= *rref_pointer_array;
+
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) ||
+ having->check_cols(1));
+ 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);
+ having->split_sum_func(ref_pointer_array, 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
@@ -259,13 +321,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++))
{
@@ -281,22 +341,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 */
@@ -305,7 +366,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;
@@ -321,153 +382,146 @@ 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);
+ /* select_limit is used to decide if we are likely to scan the whole table */
+ select_limit= unit->select_limit_cnt;
+ if (having || (select_options & OPTION_FOUND_ROWS))
+ select_limit= HA_POS_ERROR;
+ do_send_rows = (unit->select_limit_cnt) ? 1 : 0;
+ this->unit= unit;
#ifdef RESTRICTED_GROUP
- 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");
+ // to prevent double initialization on EXPLAIN
+ if (optimized)
+ DBUG_RETURN(0);
+ optimized= 1;
#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->net.report_error)
{
+ // quick abort
delete procedure;
- DBUG_RETURN(0);
- }
- if (cond_value == Item::COND_FALSE || !thd->select_limit)
- { /* 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;
+ error= thd->is_fatal_error ? -1 : 1;
+ DBUG_PRINT("error",("Error from optimize_cond"));
DBUG_RETURN(error);
}
+ if (cond_value == Item::COND_FALSE ||
+ (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
+ { /* Impossible cond */
+ zero_result_cause= "Impossible WHERE";
+ error= 0;
+ 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";
+ error=0;
+ 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)
+ {
+ error= 0;
+ DBUG_RETURN(0);
}
-
- error = -1;
- join.sort_by_table=get_sort_by_table(order,group,tables);
+ error= -1; // Error is sent to client
+ sort_by_table= get_sort_by_table(order, group_list, tables_list);
/* Calculate how to do the join */
- thd->proc_info="statistics";
- if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
- goto err;
+ thd->proc_info= "statistics";
+ if (make_join_statistics(this, tables_list, conds, &keyuse) ||
+ thd->is_fatal_error)
+ {
+ DBUG_PRINT("error",("Error: make_join_statistics() failed"));
+ DBUG_RETURN(1);
+ }
- thd->proc_info="preparing";
- if (result->initialize_tables(&join))
- goto err;
- if (join.const_table_map != join.found_const_table_map &&
+ thd->proc_info= "preparing";
+ if (result->initialize_tables(this))
+ {
+ DBUG_PRINT("error",("Error: initialize_tables() failed"));
+ DBUG_RETURN(1); // error == -1
+ }
+ 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,"no matching row in const table",having,
- procedure);
- goto err;
+ zero_result_cause= "no matching row in const table";
+ DBUG_PRINT("error",("Error: %s", zero_result_cause));
+ select_options= 0; //TODO why option in return_zero_rows was droped
+ error= 0;
+ 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++)
{
@@ -479,28 +533,26 @@ 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 */
+ { /* purecov: inspected */
+ error= -1; /* purecov: inspected */
+ DBUG_PRINT("error",("Error: make_select() failed"));
+ 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 == 0
}
error= -1; /* if goto err */
@@ -508,7 +560,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
/* Optimize distinct away if possible */
{
ORDER *org_order= order;
- order=remove_const(&join,order,conds,&simple_order);
+ order=remove_const(this, order,conds,&simple_order);
/*
If we are using ORDER BY NULL or ORDER BY const_expression,
return result in any order (even if we are using a GROUP BY)
@@ -516,12 +568,13 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (!order && org_order)
skip_sort_order= 1;
}
- 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)
+ else if (select_distinct && tables - const_tables == 1)
{
/*
We are only using one table. In this case we change DISTINCT to a
@@ -538,15 +591,15 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
because in this case we can just create a temporary table that
holds LIMIT rows and stop when this table is full.
*/
- JOIN_TAB *tab= &join.join_tab[join.const_tables];
+ JOIN_TAB *tab= &join_tab[const_tables];
bool all_order_fields_used;
if (order)
skip_sort_order= test_if_skip_sort_order(tab, order, select_limit, 1);
- if ((group=create_distinct_group(thd, order, fields,
- &all_order_fields_used)))
+ if ((group_list=create_distinct_group(thd, order, fields_list,
+ &all_order_fields_used)))
{
bool skip_group= (skip_sort_order &&
- test_if_skip_sort_order(tab, group, select_limit,
+ test_if_skip_sort_order(tab, group_list, select_limit,
1) != 0);
if ((skip_group && all_order_fields_used) ||
select_limit == HA_POS_ERROR ||
@@ -557,37 +610,38 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
no_order= !order;
if (all_order_fields_used)
order=0;
- join.group=1; // For end_write_group
+ group=1; // For end_write_group
}
else
- group= 0;
- } else if (thd->fatal_error) // End of memory
- goto err;
+ group_list= 0;
+ }
+ else if (thd->is_fatal_error) // End of memory
+ 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;
@@ -602,17 +656,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
@@ -622,174 +677,365 @@ 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
}
if (select_options & SELECT_DESCRIBE)
{
- if (!order && !no_order)
- order=group;
- if (order &&
- (join.const_tables == join.tables ||
- ((simple_order || skip_sort_order) &&
- test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
- select_limit, 0))))
- order=0;
- select_describe(&join,need_tmp,
- order != 0 && !skip_sort_order,
- select_distinct);
- error=0;
- goto err;
+ error= 0;
+ DBUG_RETURN(0);
}
+ tmp_having= having;
+ having= 0;
/* 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)
{
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,
+ init_items_ref_array();
+
+ tmp_table_param.hidden_field_count= (all_fields.elements -
+ fields_list.elements);
+ if (!(exec_tmp_table1 =
+ 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,
- (order == 0 || skip_sort_order) &&
- select_limit != HA_POS_ERROR,
- join.select_options)))
- goto err; /* purecov: inspected */
+ group_list : (ORDER*) 0),
+ group_list ? 0 : select_distinct,
+ group_list && simple_group,
+ select_options,
+ (order == 0 || skip_sort_order) ? select_limit :
+ HA_POS_ERROR)))
+ DBUG_RETURN(1);
- if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
- join.having=having;
+ /*
+ We don't have to store rows in temp table that doesn't match HAVING if:
+ - we are sorting the table and writing complete group rows to the
+ temp table.
+ - We are using DISTINCT without resolving the distinct as a GROUP BY
+ on all columns.
+
+ If having is not handled here, it will be checked before the row
+ is sent to the client.
+ */
+ if (having &&
+ (sort_and_group || (exec_tmp_table1->distinct && !group_list)))
+ having= tmp_having;
/* 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_RETURN(1);
+ 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_RETURN(1);
+ if (!group_list && ! exec_tmp_table1->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_RETURN(1);
order=0;
}
}
-
+
/*
Optimize distinct when used on some of the tables
SELECT DISTINCT t1.a FROM t1,t2 WHERE t1.b=t2.b
In this case we can stop scanning t2 when we have found one t1.a
*/
- if (tmp_table->distinct)
+ if (exec_tmp_table1->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)
{
- /* Should always succeed */
- if (test_if_skip_sort_order(&join.join_tab[join.const_tables],
- order, thd->select_limit,0))
+ /* Should always succeed */
+ if (test_if_skip_sort_order(&this->join_tab[const_tables],
+ order, unit->select_limit_cnt, 0))
order=0;
}
}
+
+ if (select_lex != &thd->lex.select_lex &&
+ select_lex->linkage != DERIVED_TABLE_TYPE)
+ {
+ if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN))))
+ DBUG_RETURN(-1);
+ error= 0; // Ensure that tmp_join.error= 0
+ restore_tmp();
+ }
+ }
- /* 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)))
+ error= 0;
+ DBUG_RETURN(0);
+}
+
+/*
+ Restore values in temporary join
+*/
+
+void JOIN::restore_tmp()
+{
+ memcpy(tmp_join, this, (size_t) sizeof(JOIN));
+}
+
+
+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;
+ }
+
+ if (exec_tmp_table1)
+ {
+ exec_tmp_table1->file->extra(HA_EXTRA_RESET_STATE);
+ exec_tmp_table1->file->delete_all_rows();
+ free_io_cache(exec_tmp_table1);
+ }
+ if (exec_tmp_table2)
+ {
+ exec_tmp_table2->file->extra(HA_EXTRA_RESET_STATE);
+ exec_tmp_table2->file->delete_all_rows();
+ free_io_cache(exec_tmp_table2);
+ }
+ if (items0)
+ memcpy(ref_pointer_array, items0, ref_pointer_array_size);
+
+ if (tmp_join)
+ restore_tmp();
+
+ DBUG_RETURN(0);
+}
+
+/*
+ Exec select
+*/
+void
+JOIN::exec()
+{
+ int tmp_error;
+ DBUG_ENTER("JOIN::exec");
+
+ error= 0;
+ if (procedure)
+ {
+ if (procedure->change_columns(fields_list) ||
+ result->prepare(fields_list, unit))
+ DBUG_VOID_RETURN;
+ }
+
+ if (!tables_list)
+ { // Only test of functions
+ if (select_options & SELECT_DESCRIBE)
+ select_describe(this, false, false, false,
+ (zero_result_cause?zero_result_cause:"No tables used"));
+ else
{
- error=tmp_error;
- goto err; /* purecov: inspected */
+ result->send_fields(fields_list,1);
+ if (!having || having->val_int())
+ {
+ if (do_send_rows && (procedure ? (procedure->send_row(fields_list) ||
+ procedure->end_of_records())
+ : result->send_data(fields_list)))
+ error= 1;
+ else
+ {
+ error= (int) result->send_eof();
+ send_records=1;
+ }
+ }
+ else
+ error=(int) result->send_eof();
}
- if (join.having)
- join.having=having=0; // Allready done
+ DBUG_VOID_RETURN;
+ }
+ if (zero_result_cause)
+ {
+ (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;
+ }
+
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (!order && !no_order)
+ order=group_list;
+ if (order &&
+ (const_tables == tables ||
+ ((simple_order || skip_sort_order) &&
+ test_if_skip_sort_order(&join_tab[const_tables], order,
+ select_limit, 0))))
+ order=0;
+ having= tmp_having;
+ select_describe(this, need_tmp,
+ order != 0 && !skip_sort_order,
+ select_distinct);
+ DBUG_VOID_RETURN;
+ }
+
+ /* Perform FULLTEXT search before all regular searches */
+ //init_ftfuncs(thd, select_lex, test(order));
+
+ JOIN *curr_join= this;
+ List<Item> *curr_all_fields= &all_fields;
+ List<Item> *curr_fields_list= &fields_list;
+ TABLE *curr_tmp_table= 0;
+
+ /* Create a tmp table if distinct or if the sort is too complicated */
+ if (need_tmp)
+ {
+ if (tmp_join)
+ curr_join= tmp_join;
+ curr_tmp_table= exec_tmp_table1;
+
+ /* Copy data to the temporary table */
+ thd->proc_info= "Copying to tmp table";
+
+ if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0)))
+ {
+ error= tmp_error;
+ DBUG_VOID_RETURN;
+ }
+ curr_tmp_table->file->info(HA_STATUS_VARIABLE);
+
+ if (curr_join->having)
+ curr_join->having= curr_join->tmp_having= 0; // Allready done
+
/* Change sum_fields reference to calculated fields in tmp_table */
- if (join.sort_and_group || tmp_table->group)
+ curr_join->all_fields= *curr_all_fields;
+ if (!items1)
{
- 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;
+ items1= items0 + all_fields.elements;
+ if (sort_and_group || curr_tmp_table->group)
+ {
+ if (change_to_use_tmp_fields(thd, items1,
+ tmp_fields_list1, tmp_all_fields1,
+ fields_list.elements, all_fields))
+ DBUG_VOID_RETURN;
+ }
+ else
+ {
+ if (change_refs_to_tmp_fields(thd, items1,
+ tmp_fields_list1, tmp_all_fields1,
+ fields_list.elements, all_fields))
+ DBUG_VOID_RETURN;
+ }
+ curr_join->tmp_all_fields1= tmp_all_fields1;
+ curr_join->tmp_fields_list1= tmp_fields_list1;
+ curr_join->items1= items1;
+ }
+ curr_all_fields= &tmp_all_fields1;
+ curr_fields_list= &tmp_fields_list1;
+ memcpy(ref_pointer_array, items1, ref_pointer_array_size);
+
+ if (sort_and_group || curr_tmp_table->group)
+ {
+ curr_join->tmp_table_param.field_count+=
+ curr_join->tmp_table_param.sum_func_count+
+ curr_join->tmp_table_param.func_count;
+ curr_join->tmp_table_param.sum_func_count=
+ curr_join->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;
+ curr_join->tmp_table_param.field_count+=
+ curr_join->tmp_table_param.func_count;
+ curr_join->tmp_table_param.func_count= 0;
}
+
+ // procedure can't be used inside subselect => we do nothing special for it
if (procedure)
procedure->update_refs();
- if (tmp_table->group)
+
+ if (curr_tmp_table->group)
{ // Already grouped
- if (!order && !no_order && !skip_sort_order)
- order=group; /* order by group */
- group=0;
+ if (!curr_join->order && !curr_join->no_order && !skip_sort_order)
+ curr_join->order= curr_join->group_list; /* order by group */
+ curr_join->group_list= 0;
}
-
+
/*
If we have different sort & group then we must sort the data by group
and copy it to another tmp table
@@ -798,181 +1044,342 @@ 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) ||
- (select_distinct &&
- join.tmp_table_param.using_indirect_summary_function))
+ if (curr_join->group_list && (!test_if_subpart(curr_join->group_list,
+ curr_join->order) ||
+ curr_join->select_distinct) ||
+ (curr_join->select_distinct &&
+ curr_join->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);
-
- /* group data to new table */
- if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
- (ORDER*) 0,
- select_distinct && !group,
- 1, 0,
- join.select_options)))
- goto err; /* purecov: inspected */
- if (group)
+ join_free(curr_join, 0);
+ if (make_simple_join(curr_join, curr_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(curr_join, group_list);
+ count_field_types(&curr_join->tmp_table_param, curr_join->tmp_all_fields1,
+ curr_join->select_distinct && !curr_join->group_list);
+ curr_join->tmp_table_param.hidden_field_count=
+ (curr_join->tmp_all_fields1.elements-
+ curr_join->tmp_fields_list1.elements);
+
+
+ if (exec_tmp_table2)
+ curr_tmp_table= exec_tmp_table2;
+ else
+ {
+ /* group data to new table */
+ if (!(curr_tmp_table=
+ exec_tmp_table2= create_tmp_table(thd,
+ &curr_join->tmp_table_param,
+ *curr_all_fields,
+ (ORDER*) 0,
+ curr_join->select_distinct &&
+ !curr_join->group_list,
+ 1, curr_join->select_options,
+ HA_POS_ERROR)))
+ DBUG_VOID_RETURN;
+ curr_join->exec_tmp_table2= exec_tmp_table2;
+ }
+ 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))
+ thd->proc_info= "Creating sort index";
+ if (create_sort_index(thd, curr_join->join_tab, curr_join->group_list,
+ HA_POS_ERROR, HA_POS_ERROR) ||
+ alloc_group_fields(curr_join, curr_join->group_list))
{
- free_tmp_table(thd,tmp_table2); /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- group=0;
+ curr_join->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(curr_join, *curr_all_fields) ||
+ (tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table,
+ 0)))
{
- error=tmp_error;
- free_tmp_table(thd,tmp_table2);
- goto err; /* purecov: inspected */
+ error= tmp_error;
+ 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
-
- 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;
- }
-
- if (tmp_table->distinct)
- select_distinct=0; /* Each row is unique */
-
- join_free(&join); /* Free quick selects */
- if (select_distinct && ! group)
+ end_read_record(&curr_join->join_tab->read_record);
+ curr_join->const_tables= curr_join->tables; // Mark free for join_free()
+ curr_join->join_tab[0].table= 0; // Table is freed
+
+ // No sum funcs anymore
+ if (!items2)
+ {
+ items2= items1 + all_fields.elements;
+ if (change_to_use_tmp_fields(thd, items2,
+ tmp_fields_list2, tmp_all_fields2,
+ fields_list.elements, tmp_all_fields1))
+ DBUG_VOID_RETURN;
+ curr_join->tmp_fields_list2= tmp_fields_list2;
+ curr_join->tmp_all_fields2= tmp_all_fields2;
+ }
+ curr_fields_list= &curr_join->tmp_fields_list2;
+ curr_all_fields= &curr_join->tmp_all_fields2;
+ memcpy(ref_pointer_array, items2, ref_pointer_array_size);
+ curr_join->tmp_table_param.field_count+=
+ curr_join->tmp_table_param.sum_func_count;
+ curr_join->tmp_table_param.sum_func_count= 0;
+ }
+ if (curr_tmp_table->distinct)
+ curr_join->select_distinct=0; /* Each row is unique */
+
+ join_free(curr_join, 0); /* 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;
- 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);
+ if (curr_join->tmp_having)
+ curr_join->tmp_having->update_used_tables();
+ if (remove_duplicates(curr_join, curr_tmp_table,
+ curr_join->fields_list, curr_join->tmp_having))
+ DBUG_VOID_RETURN;
+ curr_join->tmp_having=0;
+ curr_join->select_distinct=0;
+ }
+ curr_tmp_table->reginfo.lock_type= TL_UNLOCK;
+ if (make_simple_join(curr_join, curr_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(curr_join, curr_join->group_list);
+ count_field_types(&curr_join->tmp_table_param, *curr_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);
+ count_field_types(&curr_join->tmp_table_param, *curr_all_fields, 0);
}
- if (join.group || join.tmp_table_param.sum_func_count ||
+
+ if (curr_join->group || curr_join->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(curr_join, curr_join->group_list);
+ if (!items3)
+ {
+ if (!items0)
+ init_items_ref_array();
+ items3= ref_pointer_array + (all_fields.elements*4);
+ setup_copy_fields(thd, &curr_join->tmp_table_param,
+ items3, tmp_fields_list3, tmp_all_fields3,
+ curr_fields_list->elements, *curr_all_fields);
+ tmp_table_param.save_copy_funcs= curr_join->tmp_table_param.copy_funcs;
+ tmp_table_param.save_copy_field= curr_join->tmp_table_param.copy_field;
+ tmp_table_param.save_copy_field_end=
+ curr_join->tmp_table_param.copy_field_end;
+ curr_join->tmp_all_fields3= tmp_all_fields3;
+ curr_join->tmp_fields_list3= tmp_fields_list3;
+ }
+ else
+ {
+ curr_join->tmp_table_param.copy_funcs= tmp_table_param.save_copy_funcs;
+ curr_join->tmp_table_param.copy_field= tmp_table_param.save_copy_field;
+ curr_join->tmp_table_param.copy_field_end=
+ tmp_table_param.save_copy_field_end;
+ }
+ curr_fields_list= &tmp_fields_list3;
+ curr_all_fields= &tmp_all_fields3;
+ memcpy(ref_pointer_array, items3, ref_pointer_array_size);
+
+ if (make_sum_func_list(curr_join, *curr_all_fields) ||
+ thd->is_fatal_error)
+ DBUG_VOID_RETURN;
}
- if (group || order)
+ if (curr_join->group_list || curr_join->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 (curr_join->tmp_having && ! curr_join->group_list &&
+ ! curr_join->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;
+ // Some tables may have been const
+ curr_join->tmp_having->update_used_tables();
+ JOIN_TAB *table= &curr_join->join_tab[const_tables];
+ table_map used_tables= curr_join->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(curr_join->tmp_having,
+ used_tables,
+ used_tables);
if (sort_table_cond)
{
if (!table->select)
- if (!(table->select=new SQL_SELECT))
- goto err;
+ if (!(table->select= new SQL_SELECT))
+ DBUG_VOID_RETURN;
if (!table->select->cond)
- table->select->cond=sort_table_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;
+ if (!(table->select->cond= new Item_cond_and(table->select->cond,
+ sort_table_cond)))
+ DBUG_VOID_RETURN;
table->select_cond=table->select->cond;
table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(table->select->cond,
"select and having"););
- having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
+ curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
+ ~ (table_map) 0,
+ ~used_tables);
DBUG_EXECUTE("where",print_where(conds,"having after sort"););
}
}
- if (group)
- 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++)
+ if (group)
+ curr_join->select_limit= HA_POS_ERROR;
+ else
{
/*
- table->keyuse is set in the case there was an original WHERE clause
- on the table that was optimized away.
- table->on_expr tells us that it was a LEFT JOIN and there will be
- at least one row generated from the table.
+ We can abort sorting after thd->select_limit rows if we there is no
+ WHERE clause for any tables after the sorted one.
*/
- if (table->select_cond || (table->keyuse && !table->on_expr))
+ JOIN_TAB *table= &curr_join->join_tab[const_tables+1];
+ JOIN_TAB *end_table= &curr_join->join_tab[tables];
+ for (; table < end_table ; table++)
{
- /* We have to sort all rows */
- select_limit= HA_POS_ERROR;
- break;
+ /*
+ table->keyuse is set in the case there was an original WHERE clause
+ on the table that was optimized away.
+ table->on_expr tells us that it was a LEFT JOIN and there will be
+ at least one row generated from the table.
+ */
+ if (table->select_cond || (table->keyuse && !table->on_expr))
+ {
+ /* We have to sort all rows */
+ curr_join->select_limit= HA_POS_ERROR;
+ break;
+ }
}
}
+ if (create_sort_index(thd, &curr_join->join_tab[curr_join->const_tables],
+ curr_join->group_list ?
+ curr_join->group_list : curr_join->order,
+ curr_join->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
+ curr_join->having= curr_join->tmp_having;
thd->proc_info="Sending data";
- error=do_select(&join,&fields,NULL,procedure);
+ error= thd->net.report_error ||
+ do_select(curr_join, curr_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");
+ select_lex->join= 0;
+
+ if (tmp_join)
+ {
+ if (join_tab != tmp_join->join_tab)
+ {
+ JOIN_TAB *tab, *end;
+ for (tab= join_tab, end= tab+tables ; tab != end ; tab++)
+ {
+ delete tab->select;
+ delete tab->quick;
+ x_free(tab->cache.buff);
+ }
+ }
+ tmp_join->tmp_join= 0;
+ DBUG_RETURN(tmp_join->cleanup(thd));
+ }
+
+ lock=0; // It's faster to unlock later
+ join_free(this, 1);
+ if (exec_tmp_table1)
+ free_tmp_table(thd, exec_tmp_table1);
+ if (exec_tmp_table2)
+ free_tmp_table(thd, exec_tmp_table2);
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())
+ {
+ error|= unit->cleanup();
+ }
DBUG_RETURN(error);
}
+
+int
+mysql_select(THD *thd, Item ***rref_pointer_array,
+ TABLE_LIST *tables, uint wild_num, List<Item> &fields,
+ COND *conds, uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc_param, ulong select_options,
+ select_result *result, SELECT_LEX_UNIT *unit,
+ SELECT_LEX *select_lex, bool tables_and_fields_initied)
+{
+ int err;
+ bool free_join= 1;
+ DBUG_ENTER("mysql_select");
+
+ JOIN *join;
+ if (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(rref_pointer_array, tables, wild_num,
+ conds, og_num, order, group, having, proc_param,
+ select_lex, unit, tables_and_fields_initied))
+ {
+ DBUG_RETURN(-1);
+ }
+ }
+
+ if ((err= join->optimize()))
+ {
+ if (err == -1)
+ DBUG_RETURN(join->error);
+ DBUG_ASSERT(err == 1);
+ goto err; // 1
+ }
+
+ if (thd->net.report_error)
+ goto err;
+
+ join->exec();
+
+err:
+ if (free_join)
+ {
+ JOIN *curr_join= (join->need_tmp&&join->tmp_join?
+ (join->tmp_join->error=join->error,join->tmp_join):
+ join);
+
+ thd->limit_found_rows= curr_join->send_records;
+ thd->examined_row_count= curr_join->examined_rows;
+ thd->proc_info="end";
+ err= join->cleanup(thd);
+ if (thd->net.report_error)
+ err= -1;
+ delete join;
+ DBUG_RETURN(err);
+ }
+ DBUG_RETURN(join->error);
+}
+
/*****************************************************************************
Create JOIN_TABS, make a guess about the table types,
Approximate how many records will be used in each table
@@ -1008,7 +1415,7 @@ static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
0 ok
1 Fatal error
*/
-
+
static bool
make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse_array)
@@ -1119,8 +1526,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) */
@@ -1317,7 +1724,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
sizeof(POSITION)*join->const_tables);
join->best_read=1.0;
}
- DBUG_RETURN(get_best_combination(join));
+ DBUG_RETURN(join->thd->killed || get_best_combination(join));
}
@@ -1516,9 +1923,10 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
case Item_func::OPTIMIZE_NONE:
break;
case Item_func::OPTIMIZE_KEY:
- if (cond_func->key_item()->type() == Item::FIELD_ITEM)
+ if (cond_func->key_item()->real_item()->type() == Item::FIELD_ITEM)
add_key_field(key_fields,*and_level,
- ((Item_field*) (cond_func->key_item()))->field,
+ ((Item_field*) (cond_func->key_item()->real_item()))
+ ->field,
0,(Item*) 0,usable_tables);
break;
case Item_func::OPTIMIZE_OP:
@@ -1526,18 +1934,20 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
bool equal_func=(cond_func->functype() == Item_func::EQ_FUNC ||
cond_func->functype() == Item_func::EQUAL_FUNC);
- if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{
add_key_field(key_fields,*and_level,
- ((Item_field*) (cond_func->arguments()[0]))->field,
+ ((Item_field*) (cond_func->arguments()[0])->real_item())
+ ->field,
equal_func,
(cond_func->arguments()[1]),usable_tables);
}
- if (cond_func->arguments()[1]->type() == Item::FIELD_ITEM &&
+ if (cond_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM &&
cond_func->functype() != Item_func::LIKE_FUNC)
{
add_key_field(key_fields,*and_level,
- ((Item_field*) (cond_func->arguments()[1]))->field,
+ ((Item_field*) (cond_func->arguments()[1])->real_item())
+ ->field,
equal_func,
(cond_func->arguments()[0]),usable_tables);
}
@@ -1545,10 +1955,11 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
}
case Item_func::OPTIMIZE_NULL:
/* column_name IS [NOT] NULL */
- if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM)
+ if (cond_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM)
{
add_key_field(key_fields,*and_level,
- ((Item_field*) (cond_func->arguments()[0]))->field,
+ ((Item_field*) (cond_func->arguments()[0])->real_item())
+ ->field,
cond_func->functype() == Item_func::ISNULL_FUNC,
new Item_null, usable_tables);
}
@@ -1701,7 +2112,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;
@@ -1729,7 +2141,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);
}
@@ -1829,7 +2241,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)
{
@@ -2118,7 +2530,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
/*
@@ -2141,6 +2553,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
swap(JOIN_TAB*,join->best_ref[idx],*pos);
find_best(join,rest_tables & ~real_table_bit,idx+1,
current_record_count,current_read_time);
+ if (thd->killed)
+ return;
swap(JOIN_TAB*,join->best_ref[idx],*pos);
}
if (join->select_options & SELECT_STRAIGHT_JOIN)
@@ -2364,19 +2778,15 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse,
if (!keyuse->used_tables &&
!(join->select_options & SELECT_DESCRIBE))
{ // Compare against constant
- store_key_item *tmp=new store_key_item(thd,
- keyinfo->key_part[i].field,
- (char*)key_buff +
- maybe_null,
- maybe_null ?
- (char*) key_buff : 0,
- keyinfo->key_part[i].length,
- keyuse->val);
- if (thd->fatal_error)
+ store_key_item tmp(thd, keyinfo->key_part[i].field,
+ (char*)key_buff + maybe_null,
+ maybe_null ? (char*) key_buff : 0,
+ keyinfo->key_part[i].length, keyuse->val);
+ if (thd->is_fatal_error)
{
return TRUE;
}
- tmp->copy();
+ tmp.copy();
}
else
*ref_key++= get_store_key(thd,
@@ -2480,8 +2890,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;
@@ -2604,7 +3014,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 */
@@ -2615,7 +3026,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;
}
@@ -2657,7 +3068,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);
@@ -2838,7 +3249,7 @@ bool error_if_full_join(JOIN *join)
static void
-join_free(JOIN *join)
+join_free(JOIN *join, bool full)
{
JOIN_TAB *tab,*end;
DBUG_ENTER("join_free");
@@ -2851,25 +3262,51 @@ join_free(JOIN *join)
*/
if (join->tables > join->const_tables) // Test for not-const tables
free_io_cache(join->table[join->const_tables]);
- for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ if (join->select_lex->dependent && !full)
{
- 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)
+ 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);
}
- join->table=0;
+ else
+ {
+ for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++)
+ {
+ delete tab->select;
+ delete tab->quick;
+ x_free(tab->cache.buff);
+ tab->cache.buff= 0;
+ 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();
+ /*
+ We need to reset this for next select
+ (Tested in part_of_refkey)
+ */
+ tab->table->reginfo.join_tab= 0;
+ }
+ end_read_record(&tab->read_record);
+ }
+ join->table= 0;
+ }
}
/*
We are not using tables anymore
@@ -2881,9 +3318,12 @@ join_free(JOIN *join)
mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock
join->lock=0;
}
- join->group_fields.delete_elements();
- join->tmp_table_param.copy_funcs.delete_elements();
- join->tmp_table_param.cleanup();
+ if (full)
+ {
+ join->group_fields.delete_elements();
+ join->tmp_table_param.copy_funcs.delete_elements();
+ join->tmp_table_param.cleanup();
+ }
DBUG_VOID_RETURN;
}
@@ -3086,18 +3526,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)
@@ -3205,8 +3647,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
if ((tmp2=new COND_CMP(and_father,func)))
save_list->push_back(tmp2);
}
- func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
- func->arguments()[1]->result_type()));
+ func->set_cmp_func();
}
}
else if (left_item->eq(field,0) && right_item != value)
@@ -3226,8 +3667,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
if ((tmp2=new COND_CMP(and_father,func)))
save_list->push_back(tmp2);
}
- func->set_cmp_func(item_cmp_type(func->arguments()[0]->result_type(),
- func->arguments()[1]->result_type()));
+ func->set_cmp_func();
}
}
}
@@ -3384,7 +3824,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
}
}
if (should_fix_fields)
- cond->fix_fields(current_thd,0);
+ cond->fix_fields(current_thd,0, &cond);
if (!((Item_cond*) cond)->argument_list()->elements ||
*cond_value != Item::COND_OK)
@@ -3419,7 +3859,9 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
(thd->options & OPTION_AUTO_IS_NULL) &&
thd->insert_id())
{
+#ifndef EMBEDDED_LIBRARY
query_cache_abort(&thd->net);
+#endif
COND *new_cond;
if ((new_cond= new Item_func_eq(args[0],
new Item_int("last_insert_id()",
@@ -3427,7 +3869,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
}
@@ -3441,7 +3883,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);
}
}
}
@@ -3567,17 +4009,18 @@ 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 */
+ case Item_sum::VARIANCE_FUNC: /* Place for sum & count */
+ case Item_sum::STD_FUNC:
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);
+ item->name,table,item_sum->decimals);
case Item_sum::UNIQUE_USERS_FUNC:
return new Field_long(9,maybe_null,item->name,table,1);
default:
@@ -3591,12 +4034,17 @@ 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());
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
+ return 0;
}
}
- thd->fatal_error=1;
+ thd->fatal_error();
return 0; // Error
}
case Item::FIELD_ITEM:
@@ -3620,6 +4068,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::PROC_ITEM:
case Item::INT_ITEM:
@@ -3644,10 +4093,15 @@ 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;
+ case ROW_RESULT:
+ default:
+ // This case should never be choosen
+ DBUG_ASSERT(0);
break;
}
if (copy_func && item->is_result_field())
@@ -3672,7 +4126,7 @@ 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)
+ ulong select_options, ha_rows rows_limit)
{
TABLE *table;
uint i,field_count,reclength,null_count,null_pack_length,
@@ -3692,9 +4146,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
uint temp_pool_slot=MY_BIT_NONE;
DBUG_ENTER("create_tmp_table");
- DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d allow_distinct_limit: %d group: %d",
+ DBUG_PRINT("enter",("distinct: %d save_sum_fields: %d rows_limit: %lu group: %d",
(int) distinct, (int) save_sum_fields,
- (int) allow_distinct_limit,test(group)));
+ (ulong) rows_limit,test(group)));
statistic_increment(created_tmp_tables, &LOCK_status);
@@ -3770,6 +4224,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;
@@ -3844,7 +4299,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
not_all_columns || group !=0);
if (!new_field)
{
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
goto err; // Got OOM
continue; // Some kindf of const item
}
@@ -4014,6 +4469,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->usable_key_parts=keyinfo->key_parts= param->group_parts;
keyinfo->key_length=0;
keyinfo->rec_per_key=0;
+ keyinfo->algorithm= HA_KEY_ALG_UNDEF;
for (; group ; group=group->next,key_part_info++)
{
Field *field=(*group->item)->tmp_table_field();
@@ -4068,13 +4524,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
null_pack_length-=hidden_null_pack_length;
keyinfo->key_parts= ((field_count-param->hidden_field_count)+
test(null_pack_length));
- if (allow_distinct_limit)
- {
- set_if_smaller(table->max_rows,thd->select_limit);
- param->end_write_records=thd->select_limit;
- }
- else
- param->end_write_records= HA_POS_ERROR;
+ set_if_smaller(table->max_rows, rows_limit);
+ param->end_write_records= rows_limit;
table->distinct=1;
table->keys=1;
if (blob_count)
@@ -4090,6 +4541,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
keyinfo->flags=HA_NOSAME | HA_NULL_ARE_EQUAL;
keyinfo->key_length=(uint16) reclength;
keyinfo->name=(char*) "tmp";
+ keyinfo->algorithm= HA_KEY_ALG_UNDEF;
if (null_pack_length)
{
key_part_info->null_bit=0;
@@ -4100,7 +4552,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++;
@@ -4121,7 +4573,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
0 : FIELDFLAG_BINARY;
}
}
- if (thd->fatal_error) // If end of memory
+ if (thd->is_fatal_error) // If end of memory
goto err; /* purecov: inspected */
table->db_record_offset=1;
if (table->db_type == DB_TYPE_MYISAM)
@@ -4172,7 +4624,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;
@@ -4209,7 +4661,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)
@@ -4248,6 +4700,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;
@@ -4306,12 +4759,11 @@ free_tmp_table(THD *thd, TABLE *entry)
* If a HEAP table gets full, create a MyISAM table and copy all rows to this
*/
-bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
- bool ignore_last_dupp_key_error)
+bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+ int error, bool ignore_last_dupp_key_error)
{
TABLE new_table;
const char *save_proc_info;
- THD *thd=current_thd;
int write_err;
DBUG_ENTER("create_myisam_from_heap");
@@ -4391,7 +4843,7 @@ bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
static int
do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
{
- int error;
+ int error= 0;
JOIN_TAB *join_tab;
int (*end_select)(JOIN *, struct st_join_table *,bool);
DBUG_ENTER("do_select");
@@ -4407,7 +4859,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 */
@@ -4452,25 +4904,24 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
join->send_records=0;
if (join->tables == join->const_tables)
{
- if (!(error=(*end_select)(join,join_tab,0)) || error == -3)
- error=(*end_select)(join,join_tab,1);
+ if (!join->select_lex->dependent ||
+ ((!join->conds || join->conds->val_int()) &&
+ (!join->having || join->having->val_int())))
+ {
+ if (!(error=(*end_select)(join,join_tab,0)) || error == -3)
+ error=(*end_select)(join,join_tab,1);
+ }
}
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
@@ -4479,7 +4930,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
The following will unlock all cursors if the command wasn't an
update command
*/
- join_free(join);
+ join_free(join, 0); // Unlock all cursors
if (join->result->send_eof())
error= 1; // Don't send error
}
@@ -4490,18 +4941,26 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
int tmp;
if ((tmp=table->file->extra(HA_EXTRA_NO_CACHE)))
{
- my_errno=tmp;
+ DBUG_PRINT("error",("extra(HA_EXTRA_NO_CACHE) failed"));
+ my_errno= tmp;
error= -1;
}
if ((tmp=table->file->index_end()))
{
- my_errno=tmp;
+ DBUG_PRINT("error",("index_end() failed"));
+ my_errno= tmp;
error= -1;
}
if (error == -1)
table->file->print_error(my_errno,MYF(0));
}
- DBUG_RETURN(error);
+#ifndef DBUG_OFF
+ if (error)
+ {
+ DBUG_PRINT("error",("Error: do_select() failed"));
+ }
+#endif
+ DBUG_RETURN(error || join->thd->net.report_error);
}
@@ -5147,7 +5606,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)
@@ -5176,8 +5635,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);
}
}
@@ -5240,14 +5699,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;
}
}
}
@@ -5318,7 +5776,8 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (error == HA_ERR_FOUND_DUPP_KEY ||
error == HA_ERR_FOUND_DUPP_UNIQUE)
goto end;
- if (create_myisam_from_heap(table, &join->tmp_table_param, error,1))
+ if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
+ error,1))
DBUG_RETURN(-1); // Not a table_is_full error
table->uniques=0; // To ensure rows are the same
}
@@ -5328,7 +5787,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);
}
}
@@ -5364,6 +5823,9 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
Item *item= *group->item;
item->save_org_in_field(group->field);
+#ifdef EMBEDDED_LIBRARY
+ join->thd->net.last_errno= 0;
+#endif
/* Store in the used key if the field was 0 */
if (item->maybe_null)
group->buff[-1]=item->null_value ? 1 : 0;
@@ -5395,7 +5857,8 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
copy_funcs(join->tmp_table_param.items_to_copy);
if ((error=table->file->write_row(table->record[0])))
{
- if (create_myisam_from_heap(table, &join->tmp_table_param, error, 0))
+ if (create_myisam_from_heap(join->thd, table, &join->tmp_table_param,
+ error, 0))
DBUG_RETURN(-1); // Not a table_is_full error
/* Change method to update rows */
table->file->index_init(0);
@@ -5489,7 +5952,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{
if ((error=table->file->write_row(table->record[0])))
{
- if (create_myisam_from_heap(table, &join->tmp_table_param,
+ if (create_myisam_from_heap(join->thd, table,
+ &join->tmp_table_param,
error, 0))
DBUG_RETURN(-1); // Not a table_is_full error
}
@@ -5651,6 +6115,9 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
static Item *
part_of_refkey(TABLE *table,Field *field)
{
+ if (!table->reginfo.join_tab)
+ return (Item*) 0; // field from outer non-select (UPDATE,...)
+
uint ref_parts=table->reginfo.join_tab->ref.key_parts;
if (ref_parts)
{
@@ -5729,6 +6196,69 @@ static uint find_shortest_key(TABLE *table, key_map usable_keys)
return best;
}
+/*
+ SYNOPSIS
+ is_subkey()
+ key_part - first key parts
+ ref_key_part - second key parts
+ ref_key_part_end - last+1 part of the second key
+ DESCRIPTION
+ Test if a second key is the subkey of the first one.
+ NOTE
+ Second key MUST be shorter than the first one.
+ RETURN
+ 1 - is the subkey
+ 0 - otherwise
+*/
+
+inline bool
+is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
+ KEY_PART_INFO *ref_key_part_end)
+{
+ for (; ref_key_part < ref_key_part_end; key_part++, ref_key_part++)
+ if (!key_part->field->eq(ref_key_part->field))
+ return 0;
+ return 1;
+}
+
+/*
+ SYNOPSIS
+ test_if_subkey()
+ ref - number of key, used for WHERE clause
+ usable_keys - keys for testing
+ DESCRIPTION
+ Test if we can use one of the 'usable_keys' instead of 'ref' key.
+ RETURN
+ MAX_KEY - if we can't use other key
+ the number of found key - otherwise
+*/
+
+static uint
+test_if_subkey(ORDER *order, TABLE *table, uint ref, key_map usable_keys)
+{
+ uint nr;
+ uint min_length= (uint) ~0;
+ uint best= MAX_KEY;
+ uint not_used;
+ KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
+ uint ref_key_parts= table->key_info[ref].key_parts;
+ KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
+
+ for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
+ {
+ if ((usable_keys & 1) &&
+ table->key_info[nr].key_length < min_length &&
+ table->key_info[nr].key_parts >= ref_key_parts &&
+ is_subkey(table->key_info[nr].key_part, ref_key_part,
+ ref_key_part_end) &&
+ test_if_order_by_key(order, table, nr, &not_used))
+ {
+ min_length= table->key_info[nr].key_length;
+ best= nr;
+ }
+ }
+ return best;
+}
/*
Test if we can skip the ORDER BY by using an index.
@@ -5776,6 +6306,27 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
int order_direction;
uint used_key_parts;
+ if (!(usable_keys & ((key_map) 1 << ref_key)))
+ {
+ /*
+ We come here when ref_key is not among usable_keys
+ */
+ uint a;
+ if ((a= test_if_subkey(order, table, ref_key, usable_keys)) < MAX_KEY)
+ {
+ if (tab->ref.key >= 0)
+ {
+ tab->ref.key= a;
+ table->file->index_init(a);
+ }
+ else
+ {
+ select->quick->index= a;
+ select->quick->init();
+ }
+ ref_key= a;
+ }
+ }
/* Check if we get the rows in requested sorted order by using the key */
if ((usable_keys & ((key_map) 1 << ref_key)) &&
(order_direction = test_if_order_by_key(order,table,ref_key,
@@ -5866,16 +6417,36 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
-/*****************************************************************************
+/*
If not selecting by given key, create an index how records should be read
- return: 0 ok
- -1 some fatal error
- 1 no records
-*****************************************************************************/
+
+ SYNOPSIS
+ create_sort_index()
+ thd Thread handler
+ tab Table to sort (in join structure)
+ order How table should be sorted
+ filesort_limit Max number of rows that needs to be sorted
+ select_limit Max number of rows in final output
+ Used to decide if we should use index or not
+
+
+ IMPLEMENTATION
+ - If there is an index that can be used, 'tab' is modified to use
+ this index.
+ - If no index, create with filesort() an index file that can be used to
+ retrieve rows in order (should be done with 'read_record').
+ The sorted data is stored in tab->table and will be freed when calling
+ free_io_cache(tab->table).
+
+ RETURN VALUES
+ 0 ok
+ -1 Some fatal error
+ 1 No records
+*/
static int
-create_sort_index(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;
@@ -5919,8 +6490,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;
@@ -6019,7 +6590,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;
@@ -6036,7 +6607,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;
@@ -6101,7 +6672,7 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field,
}
if (copy_blobs(first_field))
{
- my_error(ER_OUT_OF_SORTMEMORY,MYF(0));
+ my_error(ER_OUTOFMEMORY,MYF(0));
error=0;
goto err;
}
@@ -6173,8 +6744,9 @@ 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))
+
+ if (hash_init(&hash, &my_charset_bin, (uint) file->records, 0,
+ key_length,(hash_get_key) 0, 0, 0))
{
my_free((char*) key_buffer,MYF(0));
DBUG_RETURN(1);
@@ -6419,12 +6991,14 @@ store_record_in_cache(JOIN_CACHE *cache)
{
if (last_record)
{
- copy->blob_field->get_image((char*) pos,copy->length+sizeof(char*));
+ copy->blob_field->get_image((char*) pos,copy->length+sizeof(char*),
+ copy->blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
{
- copy->blob_field->get_image((char*) pos,copy->length); // blob length
+ copy->blob_field->get_image((char*) pos,copy->length, // blob length
+ copy->blob_field->charset());
memcpy(pos+copy->length,copy->str,copy->blob_length); // Blob data
pos+=copy->length+copy->blob_length;
}
@@ -6481,7 +7055,8 @@ read_cached_record(JOIN_TAB *tab)
{
if (last_record)
{
- copy->blob_field->set_image((char*) pos,copy->length+sizeof(char*));
+ copy->blob_field->set_image((char*) pos,copy->length+sizeof(char*),
+ copy->blob_field->charset());
pos+=copy->length+sizeof(char*);
}
else
@@ -6546,73 +7121,89 @@ cp_buffer_from_ref(TABLE_REF *ref)
*/
static int
-find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
+find_order_in_list(THD *thd, Item **ref_pointer_array,
+ TABLE_LIST *tables,ORDER *order, List<Item> &fields,
List<Item> &all_fields)
{
- if ((*order->item)->type() == Item::INT_ITEM)
+ Item *itemptr=*order->item;
+ if (itemptr->type() == Item::INT_ITEM)
{ /* Order by position */
Item *item=0;
- List_iterator<Item> li(fields);
- for (uint count= (uint) ((Item_int*) (*order->item))->value ;
- count-- && (item=li++) ;) ;
- if (!item)
+ uint count= (uint) ((Item_int*)itemptr)->value;
+ if (!count || count > fields.elements)
{
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
- MYF(0),(*order->item)->full_name(),
+ MYF(0),itemptr->full_name(),
thd->where);
return 1;
}
- order->item=li.ref();
- order->in_field_list=1;
+ order->item= ref_pointer_array + count-1;
+ 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;
+ uint counter;
+ Item **item= find_item_in_list(itemptr, fields, &counter, IGNORE_ERRORS);
if (item)
{
- order->item=item; // use it
+ order->item= ref_pointer_array + counter;
order->in_field_list=1;
return 0;
}
order->in_field_list=0;
- if ((*order->item)->fix_fields(thd,tables) || thd->fatal_error)
+ Item *it= *order->item;
+ if (it->fix_fields(thd, tables, order->item) || it->check_cols(1) ||
+ thd->is_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();
+ uint el= all_fields.elements;
+ all_fields.push_front(it); // Add new field to field list
+ ref_pointer_array[el]= it;
+ order->item= ref_pointer_array + el;
return 0;
}
+/*
+ Allocate array of references to address all_fileds list elements
+*/
+
+int setup_ref_array(THD* thd, Item ***rref_pointer_array, uint elements)
+{
+ if (*rref_pointer_array)
+ return 0;
+
+ return (*rref_pointer_array=
+ (Item **)thd->alloc(sizeof(Item*) * elements * 5)) == 0;
+}
/*
Change order to point at item in select list. If item isn't a number
and doesn't exits in the select list, add it the the field list.
*/
-int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &all_fields, ORDER *order)
+int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, List<Item> &all_fields, ORDER *order)
{
thd->where="order clause";
for (; order; order=order->next)
{
- if (find_order_in_list(thd,tables,order,fields,all_fields))
+ if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
+ all_fields))
return 1;
}
return 0;
}
-static int
-setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
- List<Item> &all_fields, ORDER *order, bool *hidden_group_fields)
+int
+setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+ List<Item> &fields, List<Item> &all_fields, ORDER *order,
+ bool *hidden_group_fields)
{
*hidden_group_fields=0;
if (!order)
return 0; /* Everything is ok */
- if (thd->sql_mode & MODE_ONLY_FULL_GROUP_BY)
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
{
Item *item;
List_iterator<Item> li(fields);
@@ -6624,7 +7215,8 @@ setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
thd->where="group statement";
for (; order; order=order->next)
{
- if (find_order_in_list(thd,tables,order,fields,all_fields))
+ if (find_order_in_list(thd, ref_pointer_array, tables, order, fields,
+ all_fields))
return 1;
(*order->item)->marker=1; /* Mark found */
if ((*order->item)->with_sum_func)
@@ -6634,7 +7226,7 @@ setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
return 1;
}
}
- if (thd->sql_mode & MODE_ONLY_FULL_GROUP_BY)
+ if (thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY)
{
/* Don't allow one to use fields that is not used in GROUP BY */
Item *item;
@@ -6668,17 +7260,17 @@ 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)
+ uint counter;
+ 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, &counter,
+ 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();
}
@@ -6917,47 +7509,77 @@ test_if_group_changed(List<Item_buff> &list)
/*
Setup copy_fields to save fields at start of new group
- Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups.
- Change old item_field to use a new field with points at saved fieldvalue
- This function is only called before use of send_fields
+
+ setup_copy_fields()
+ thd - THD pointer
+ param - temporary table parameters
+ ref_pointer_array - array of pointers to top elements of filed list
+ res_selected_fields - new list of items of select item list
+ res_all_fields - new list of all items
+ elements - number of elements in select item list
+ all_fields - all fields list
+
+ DESCRIPTION
+ Setup copy_fields to save fields at start of new group
+ Only FIELD_ITEM:s and FUNC_ITEM:s needs to be saved between groups.
+ Change old item_field to use a new field with points at saved fieldvalue
+ This function is only called before use of send_fields
+
+ RETURN
+ 0 - ok
+ !=0 - error
*/
bool
-setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
+setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
+ Item **ref_pointer_array,
+ List<Item> &res_selected_fields, List<Item> &res_all_fields,
+ uint elements, List<Item> &all_fields)
{
Item *pos;
- List_iterator<Item> li(fields);
+ List_iterator_fast<Item> li(all_fields);
Copy_field *copy;
DBUG_ENTER("setup_copy_fields");
+ res_selected_fields.empty();
+ res_all_fields.empty();
+ List_iterator_fast<Item> itr(res_all_fields);
+
+ uint i, border= all_fields.elements - elements;
if (!(copy=param->copy_field= new Copy_field[param->field_count]))
goto err2;
param->copy_funcs.empty();
- while ((pos=li++))
+ for (i= 0; (pos= li++); i++)
{
if (pos->type() == Item::FIELD_ITEM)
{
- Item_field *item=(Item_field*) pos;
+ Item_field *item;
+ if (!(item= new Item_field(thd, *((Item_field*) pos))))
+ goto err;
+ pos= item;
if (item->field->flags & BLOB_FLAG)
{
- if (!(pos=new Item_copy_string(pos)))
+ if (!(pos= new Item_copy_string(pos)))
goto err;
- VOID(li.replace(pos));
if (param->copy_funcs.push_back(pos))
goto err;
- continue;
}
-
- /* set up save buffer and change result_field to point at saved value */
- Field *field= item->field;
- item->result_field=field->new_field(&thd->mem_root,field->table);
- char *tmp=(char*) sql_alloc(field->pack_length()+1);
- if (!tmp)
- goto err;
- copy->set(tmp, item->result_field);
- item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
- copy++;
+ else
+ {
+ /*
+ set up save buffer and change result_field to point at
+ saved value
+ */
+ Field *field= item->field;
+ item->result_field=field->new_field(&thd->mem_root,field->table);
+ char *tmp=(char*) sql_alloc(field->pack_length()+1);
+ if (!tmp)
+ goto err;
+ copy->set(tmp, item->result_field);
+ item->result_field->move_field(copy->to_ptr,copy->to_null_ptr,1);
+ copy++;
+ }
}
else if ((pos->type() == Item::FUNC_ITEM ||
pos->type() == Item::COND_ITEM) &&
@@ -6971,12 +7593,18 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields)
*/
if (!(pos=new Item_copy_string(pos)))
goto err;
- VOID(li.replace(pos));
if (param->copy_funcs.push_back(pos))
goto err;
}
+ res_all_fields.push_back(pos);
+ ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
+ pos;
}
param->copy_field_end= copy;
+
+ for (i= 0; i < border; i++)
+ itr++;
+ itr.sublist(res_selected_fields, elements);
DBUG_RETURN(0);
err:
@@ -7041,51 +7669,78 @@ make_sum_func_list(JOIN *join,List<Item> &fields)
/*
- Change all funcs and sum_funcs to fields in tmp table
+ Change all funcs and sum_funcs to fields in tmp table, and create
+ new list of all items.
+
+ change_to_use_tmp_fields()
+ thd - THD pointer
+ ref_pointer_array - array of pointers to top elements of filed list
+ res_selected_fields - new list of items of select item list
+ res_all_fields - new list of all items
+ elements - number of elements in select item list
+ all_fields - all fields list
+
+ RETURN
+ 0 - ok
+ !=0 - error
*/
static bool
-change_to_use_tmp_fields(List<Item> &items)
+change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
+ List<Item> &res_selected_fields,
+ List<Item> &res_all_fields,
+ uint elements, List<Item> &all_fields)
{
- List_iterator<Item> it(items);
+ List_iterator_fast<Item> it(all_fields);
Item *item_field,*item;
+ res_selected_fields.empty();
+ res_all_fields.empty();
- while ((item=it++))
+ uint i, border= all_fields.elements - elements;
+ for (i= 0; (item= it++); i++)
{
Field *field;
+
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
- continue;
- if (item->type() == Item::FIELD_ITEM)
- {
- ((Item_field*) item)->field=
- ((Item_field*) item)->result_field;
- }
- else if ((field=item->tmp_table_field()))
+ item_field= item;
+ else
{
- if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
- item_field=((Item_sum*) item)->result_item(field);
- else
- item_field=(Item*) new Item_field(field);
- if (!item_field)
- return TRUE; // Fatal error
- item_field->name=item->name; /*lint -e613 */
-#ifndef DBUG_OFF
- if (_db_on_ && !item_field->name)
+ if (item->type() == Item::FIELD_ITEM)
{
- char buff[256];
- String str(buff,sizeof(buff));
- str.length(0);
- item->print(&str);
- item_field->name=sql_strmake(str.ptr(),str.length());
+ item_field= item->get_tmp_table_item(thd);
}
+ else if ((field= item->tmp_table_field()))
+ {
+ if (item->type() == Item::SUM_FUNC_ITEM && field->table->group)
+ item_field= ((Item_sum*) item)->result_item(field);
+ else
+ item_field= (Item*) new Item_field(field);
+ if (!item_field)
+ return TRUE; // Fatal error
+ item_field->name= item->name; /*lint -e613 */
+#ifndef DBUG_OFF
+ if (_db_on_ && !item_field->name)
+ {
+ char buff[256];
+ String str(buff,sizeof(buff),&my_charset_bin);
+ str.length(0);
+ item->print(&str);
+ item_field->name= sql_strmake(str.ptr(),str.length());
+ }
#endif
-#ifdef DELETE_ITEMS
- delete it.replace(item_field); /*lint -e613 */
-#else
- (void) it.replace(item_field); /*lint -e613 */
-#endif
+ }
+ else
+ item_field= item;
}
+ res_all_fields.push_back(item_field);
+ ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
+ item_field;
}
+
+ List_iterator_fast<Item> itr(res_all_fields);
+ for (i= 0; i < border; i++)
+ itr++;
+ itr.sublist(res_selected_fields, elements);
return FALSE;
}
@@ -7093,56 +7748,45 @@ change_to_use_tmp_fields(List<Item> &items)
/*
Change all sum_func refs to fields to point at fields in tmp table
Change all funcs to be fields in tmp table
+
+ change_refs_to_tmp_fields()
+ thd - THD pointer
+ ref_pointer_array - array of pointers to top elements of filed list
+ res_selected_fields - new list of items of select item list
+ res_all_fields - new list of all items
+ elements - number of elements in select item list
+ all_fields - all fields list
+
+ RETURN
+ 0 - ok
+ !=0 - error
*/
static bool
-change_refs_to_tmp_fields(THD *thd,List<Item> &items)
+change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
+ List<Item> &res_selected_fields,
+ List<Item> &res_all_fields, uint elements,
+ List<Item> &all_fields)
{
- List_iterator<Item> it(items);
- Item *item;
+ List_iterator_fast<Item> it(all_fields);
+ Item *item, *new_item;
+ res_selected_fields.empty();
+ res_all_fields.empty();
- while ((item= it++))
+ uint i, border= all_fields.elements - elements;
+ for (i= 0; (item= it++); i++)
{
- if (item->type() == Item::SUM_FUNC_ITEM)
- {
- if (!item->const_item())
- {
- Item_sum *sum_item= (Item_sum*) item;
- if (sum_item->result_field) // If not a const sum func
- {
- Field *result_field=sum_item->result_field;
- for (uint i=0 ; i < sum_item->arg_count ; i++)
- {
- Item *arg= sum_item->args[i];
- if (!arg->const_item())
- {
- if (arg->type() == Item::FIELD_ITEM)
- ((Item_field*) arg)->field= result_field++;
- else
- sum_item->args[i]= new Item_field(result_field++);
- }
- }
- }
- }
- }
- else if (item->with_sum_func)
- continue;
- else if ((item->type() == Item::FUNC_ITEM ||
- item->type() == Item::COND_ITEM) &&
- !item->const_item())
- { /* All funcs are stored */
-#ifdef DELETE_ITEMS
- delete it.replace(new Item_field(((Item_func*) item)->result_field));
-#else
- (void) it.replace(new Item_field(((Item_func*) item)->result_field));
-#endif
- }
- else if (item->type() == Item::FIELD_ITEM) /* Change refs */
- {
- ((Item_field*)item)->field=((Item_field*) item)->result_field;
- }
+ res_all_fields.push_back(new_item= item->get_tmp_table_item(thd));
+ ref_pointer_array[((i < border)? all_fields.elements-i-1 : i-border)]=
+ new_item;
}
- return thd->fatal_error;
+
+ List_iterator_fast<Item> itr(res_all_fields);
+ for (i= 0; i < border; i++)
+ itr++;
+ itr.sublist(res_selected_fields, elements);
+
+ return thd->is_fatal_error;
}
@@ -7237,14 +7881,14 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
Item *value=join_tab->ref.items[i];
cond->add(new Item_func_equal(new Item_field(field),value));
}
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(TRUE);
/*
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);
@@ -7264,46 +7908,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();
+ CHARSET_INFO *cs= &my_charset_latin1;
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 *empty= new Item_empty_string("",0);
+ 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), cs));
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(item_null);
+ item_list.push_back(new Item_string(message,strlen(message),cs));
if (result->send_data(item_list))
- result->send_error(0,NullS);
+ join->error= 1;
}
else
{
@@ -7313,19 +7941,35 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
JOIN_TAB *tab=join->join_tab+i;
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));
+ char buff1[512], buff2[512];
+ String tmp1(buff1,sizeof(buff1),cs);
+ String tmp2(buff2,sizeof(buff2),cs);
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),
+ cs));
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)));
+ 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, cs));
+ }
+ else
+ item_list.push_back(new Item_string(table->table_name,
+ strlen(table->table_name),
+ cs));
item_list.push_back(new Item_string(join_type_str[tab->type],
- strlen(join_type_str[tab->type])));
+ strlen(join_type_str[tab->type]),
+ cs));
key_map bits;
uint j;
for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
@@ -7338,14 +7982,15 @@ 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(),cs));
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++)
{
@@ -7353,13 +7998,13 @@ 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(),cs));
}
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),cs));
item_list.push_back(new Item_int((int32) key_info->key_length));
item_list.push_back(item_null);
}
@@ -7367,8 +8012,9 @@ 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),cs));
+ item_list.push_back(new Item_int((int32) tab->select->quick->
+ max_used_key_length));
item_list.push_back(item_null);
}
else
@@ -7377,15 +8023,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(item_null);
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_int((longlong) (ulonglong)
+ join->best_positions[i]. records_read,
+ 21));
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),cs));
else
{
if (tab->select)
@@ -7413,49 +8060,100 @@ 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,
+ cs));
}
// For next iteration
used_tables|=table->map;
if (result->send_data(item_list))
- result->send_error(0,NullS);
+ join->error= 1;
}
}
- 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)?
+ ((thd->lex.all_selects_list != sl)?"PRIMARY":
+ "SIMPLE"):
+ ((sl == first)?
+ ((sl->linkage == DERIVED_TABLE_TYPE) ?
+ "DERIVED":
+ ((sl->dependent)?"DEPENDENT SUBSELECT":
+ (sl->uncacheable?"UNCACHEABLE SUBSELECT":
+ "SUBSELECT"))):
+ ((sl->dependent)?"DEPENDENT UNION":
+ sl->uncacheable?"UNCACHEABLE 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, &select_lex->ref_pointer_array,
+ (TABLE_LIST*) select_lex->table_list.first,
+ select_lex->with_wild, select_lex->item_list,
+ select_lex->where,
+ select_lex->order_list.elements +
+ select_lex->group_list.elements,
+ (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);
+}
+
+/*
+ Free joins of subselect of this select.
+
+ free_underlaid_joins()
+ thd - THD pointer
+ select - pointer to st_select_lex which subselects joins we will free
+*/
+
+void free_underlaid_joins(THD *thd, SELECT_LEX *select)
+{
+ for (SELECT_LEX_UNIT *unit= select->first_inner_unit();
+ unit;
+ unit= unit->next_unit())
+ unit->cleanup();
}
+
+
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 332778aafe6..ffc98548db4 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -119,8 +119,10 @@ class TMP_TABLE_PARAM :public Sql_alloc
{
public:
List<Item> copy_funcs;
+ List<Item> save_copy_funcs;
List_iterator_fast<Item> copy_funcs_it;
Copy_field *copy_field, *copy_field_end;
+ Copy_field *save_copy_field, *save_copy_field_end;
byte *group_buff;
Item **items_to_copy; /* Fields in tmp table */
MI_COLUMNDEF *recinfo,*start_recinfo;
@@ -150,8 +152,8 @@ class TMP_TABLE_PARAM :public Sql_alloc
}
};
-
-class JOIN {
+class JOIN :public Sql_alloc
+{
public:
JOIN_TAB *join_tab,**best_ref,**map2table;
TABLE **table,**all_tables,*sort_by_table;
@@ -160,20 +162,113 @@ class JOIN {
bool sort_and_group,first_record,full_join,group, no_field_update;
bool do_send_rows;
table_map const_table_map,found_const_table_map,outer_join;
- ha_rows send_records,found_records,examined_rows,row_limit;
+ ha_rows send_records,found_records,examined_rows,row_limit, select_limit;
POSITION positions[MAX_TABLES+1],best_positions[MAX_TABLES+1];
double best_read;
List<Item> *fields;
List<Item_buff> group_fields;
TABLE *tmp_table;
+ // used to store 2 possible tmp table of SELECT
+ TABLE *exec_tmp_table1, *exec_tmp_table2;
THD *thd;
Item_sum **sum_funcs;
Procedure *procedure;
Item *having;
+ Item *tmp_having; // To store Having when processed temporary table
uint select_options;
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;
+
+ JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
+
+ 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; // to store all fields that used in query
+ //Above list changed to use temporary table
+ List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
+ //Part, shared with list above, emulate following list
+ List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
+ 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
+ Item **ref_pointer_array; //used pointer reference for this select
+ // Copy of above to be used with different lists
+ Item **items0, **items1, **items2, **items3;
+ uint ref_pointer_array_size; // size of above in bytes
+ const char *zero_result_cause; // not 0 if exec must return zero result
+
+ bool union_part; // this subselect is part of union
+ bool optimized; // flag to avoid double optimization in EXPLAIN
+
+ 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),
+ exec_tmp_table1(0), exec_tmp_table2(0),
+ thd(thd),
+ sum_funcs(0),
+ procedure(0),
+ having(0), tmp_having(0),
+ select_options(select_options),
+ result(result),
+ lock(thd->lock),
+ select_lex(0), //for safety
+ tmp_join(0),
+ 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),
+ ref_pointer_array(0), items0(0), items1(0), items2(0), items3(0),
+ ref_pointer_array_size(0),
+ zero_result_cause(0),
+ optimized(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(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
+ COND *conds, uint og_num, ORDER *order, ORDER *group,
+ Item *having, ORDER *proc_param, SELECT_LEX *select,
+ SELECT_LEX_UNIT *unit, bool tables_and_fields_initied);
+ int optimize();
+ int reinit();
+ void exec();
+ int cleanup(THD *thd);
+ void restore_tmp();
+
+ inline void init_items_ref_array()
+ {
+ items0= ref_pointer_array + all_fields.elements;
+ ref_pointer_array_size= all_fields.elements*sizeof(Item*);
+ memcpy(items0, ref_pointer_array, ref_pointer_array_size);
+ }
};
@@ -188,15 +283,18 @@ 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);
+ ulong select_options, ha_rows rows_limit);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
-bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List<Item> &fields);
+bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
+ Item **ref_pointer_array,
+ List<Item> &new_list1, List<Item> &new_list2,
+ uint elements, List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item **func_ptr);
-bool create_myisam_from_heap(TABLE *table, TMP_TABLE_PARAM *param, int error,
- bool ignore_last_dupp_error);
+bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
+ int error, bool ignore_last_dupp_error);
/* functions from opt_sum.cc */
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
@@ -208,7 +306,6 @@ class store_key :public Sql_alloc
{
protected:
Field *to_field; // Store data here
- Field *key_field; // Copy of key field
char *null_ptr;
char err;
public:
@@ -218,7 +315,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);
@@ -303,3 +400,4 @@ public:
bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
+void relink_tables(SELECT_LEX *select_lex);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 23e5049636a..ba7d7024eaf 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
@@ -53,15 +53,15 @@ extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
** A database is a directory in the mysql_data_home directory
****************************************************************************/
-
int
mysqld_show_dbs(THD *thd,const char *wild)
{
- Item_string *field=new Item_string("",0);
+ Item_string *field=new Item_string("",0,thd->charset());
List<Item> field_list;
char *end;
List<char> files;
char *file_name;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_dbs");
field->name=(char*) thd->alloc(20+ (wild ? (uint) strlen(wild)+4: 0));
@@ -71,11 +71,12 @@ mysqld_show_dbs(THD *thd,const char *wild)
strxmov(end," (",wild,")",NullS);
field_list.push_back(field);
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
DBUG_RETURN(1);
List_iterator_fast<char> it(files);
+
while ((file_name=it++))
{
if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
@@ -83,52 +84,52 @@ 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()))
+ protocol->prepare_for_resend();
+ protocol->store(file_name, system_charset_info);
+ if (protocol->write())
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)
{
List<Item> field_list;
OPEN_TABLE_LIST *open_list;
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_open_tables");
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_int("In_use",0, 4));
- field_list.push_back(new Item_int("Name_locked",0, 4));
+ field_list.push_back(new Item_return_int("In_use", 1, MYSQL_TYPE_TINY));
+ field_list.push_back(new Item_return_int("Name_locked", 4, MYSQL_TYPE_TINY));
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
- if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error)
+ if (!(open_list=list_open_tables(thd,wild)) && thd->is_fatal_error)
DBUG_RETURN(-1);
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()))
+ protocol->prepare_for_resend();
+ protocol->store(open_list->db, system_charset_info);
+ protocol->store(open_list->table, system_charset_info);
+ protocol->store_tiny((longlong) open_list->in_use);
+ protocol->store_tiny((longlong) open_list->locked);
+ if (protocol->write())
{
DBUG_RETURN(-1);
}
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -140,14 +141,16 @@ 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,thd->charset());
List<Item> field_list;
char path[FN_LEN],*end;
List<char> files;
char *file_name;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_tables");
- field->name=(char*) thd->alloc(20+(uint) strlen(db)+(wild ? (uint) strlen(wild)+4:0));
+ field->name=(char*) thd->alloc(20+(uint) strlen(db)+
+ (wild ? (uint) strlen(wild)+4:0));
end=strxmov(field->name,"Tables_in_",db,NullS);
if (wild && wild[0])
strxmov(end," (",wild,")",NullS);
@@ -155,19 +158,233 @@ int mysqld_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(field);
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
if (mysql_find_files(thd,&files,db,path,wild,0))
DBUG_RETURN(-1);
List_iterator_fast<char> it(files);
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()))
+ protocol->prepare_for_resend();
+ protocol->store(file_name, system_charset_info);
+ if (protocol->write())
+ DBUG_RETURN(-1);
+ }
+ 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;
+ Protocol *protocol= thd->protocol;
+ 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 (protocol->send_fields(&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;
+ for (types= sys_table_types; types->type; types++)
+ {
+ protocol->prepare_for_resend();
+ protocol->store(types->type, system_charset_info);
+ 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";
+ protocol->store(option_name, system_charset_info);
+ protocol->store(types->comment, system_charset_info);
+ if (protocol->write())
+ 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;
+ Protocol *protocol= thd->protocol;
+ 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 (protocol->send_fields(&field_list,1))
+ DBUG_RETURN(1);
+
+ show_privileges_st *privilege= sys_privileges;
+ for (privilege= sys_privileges; privilege->privilege ; privilege++)
+ {
+ protocol->prepare_for_resend();
+ protocol->store(privilege->privilege, system_charset_info);
+ protocol->store(privilege->context, system_charset_info);
+ protocol->store(privilege->comment, system_charset_info);
+ if (protocol->write())
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ 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;
+ Protocol *protocol= thd->protocol;
+ 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_return_int("Prec", 4, MYSQL_TYPE_SHORT));
+ field_list.push_back(new Item_return_int("Scale", 4, MYSQL_TYPE_SHORT));
+ 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 (protocol->send_fields(&field_list,1))
+ DBUG_RETURN(1);
+
+ /* TODO: Change the loop to not use 'i' */
+ for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++)
+ {
+ protocol->prepare_for_resend();
+ protocol->store(sys_column_types[i].type, system_charset_info);
+ protocol->store((ulonglong) sys_column_types[i].size);
+ protocol->store(sys_column_types[i].min_value, system_charset_info);
+ protocol->store(sys_column_types[i].max_value, system_charset_info);
+ protocol->store_short((longlong) sys_column_types[i].precision);
+ protocol->store_short((longlong) sys_column_types[i].scale);
+ protocol->store(sys_column_types[i].nullable, system_charset_info);
+ protocol->store(sys_column_types[i].auto_increment, system_charset_info);
+ protocol->store(sys_column_types[i].unsigned_attr, system_charset_info);
+ protocol->store(sys_column_types[i].zerofill, system_charset_info);
+ protocol->store(sys_column_types[i].searchable, system_charset_info);
+ protocol->store(sys_column_types[i].case_sensitivity, system_charset_info);
+ protocol->store(sys_column_types[i].default_value, system_charset_info);
+ protocol->store(sys_column_types[i].comment, system_charset_info);
+ if (protocol->write())
+ DBUG_RETURN(-1);
+ }
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -211,7 +428,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 +436,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 +463,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)
@@ -258,15 +476,13 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
char path[FN_LEN];
char *file_name;
TABLE *table;
- String *packet= &thd->packet;
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
+ TIME time;
DBUG_ENTER("mysqld_extend_show_tables");
(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));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Row_format",10));
@@ -291,11 +507,13 @@ 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));
item->maybe_null=1;
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
if (mysql_find_files(thd,&files,db,path,wild,0))
@@ -305,70 +523,77 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
{
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
- packet->length(0);
- net_store_data(packet,convert, file_name);
+ protocol->prepare_for_resend();
+ protocol->store(file_name, system_charset_info);
table_list.db=(char*) db;
table_list.real_name= table_list.alias= file_name;
if (lower_case_table_names)
- casedn_str(file_name);
+ my_casedn_str(files_charset_info, file_name);
if (!(table = open_ltable(thd, &table_list, TL_READ)))
{
for (uint i=2 ; i < field_list.elements ; i++)
- net_store_null(packet);
- net_store_data(packet,convert, thd->net.last_error);
+ protocol->store_null();
+ // Send error to Comment field
+ protocol->store(thd->net.last_error, system_charset_info);
thd->net.last_error[0]=0;
}
else
{
struct tm tm_tmp;
+ const char *str;
handler *file=table->file;
file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_NO_LOCK);
- net_store_data(packet, convert, file->table_type());
- net_store_data(packet, convert,
- (table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
- "Compressed" :
- (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
- "Dynamic" : "Fixed");
- net_store_data(packet, (longlong) file->records);
- net_store_data(packet, (uint32) file->mean_rec_length);
- net_store_data(packet, (longlong) file->data_file_length);
+ protocol->store(file->table_type(), system_charset_info);
+ str= ((table->db_options_in_use & HA_OPTION_COMPRESS_RECORD) ?
+ "Compressed" :
+ (table->db_options_in_use & HA_OPTION_PACK_RECORD) ?
+ "Dynamic" : "Fixed");
+ protocol->store(str, system_charset_info);
+ protocol->store((ulonglong) file->records);
+ protocol->store((ulonglong) file->mean_rec_length);
+ protocol->store((ulonglong) file->data_file_length);
if (file->max_data_file_length)
- net_store_data(packet, (longlong) file->max_data_file_length);
+ protocol->store((ulonglong) file->max_data_file_length);
else
- net_store_null(packet);
- net_store_data(packet, (longlong) file->index_file_length);
- net_store_data(packet, (longlong) file->delete_length);
+ protocol->store_null();
+ protocol->store((ulonglong) file->index_file_length);
+ protocol->store((ulonglong) file->delete_length);
if (table->found_next_number_field)
{
table->next_number_field=table->found_next_number_field;
table->next_number_field->reset();
file->update_auto_increment();
- net_store_data(packet, table->next_number_field->val_int());
+ protocol->store(table->next_number_field->val_int());
table->next_number_field=0;
}
else
- net_store_null(packet);
+ protocol->store_null();
if (!file->create_time)
- net_store_null(packet);
+ protocol->store_null();
else
{
localtime_r(&file->create_time,&tm_tmp);
- net_store_data(packet, &tm_tmp);
+ localtime_to_TIME(&time, &tm_tmp);
+ protocol->store(&time);
}
if (!file->update_time)
- net_store_null(packet);
+ protocol->store_null();
else
{
localtime_r(&file->update_time,&tm_tmp);
- net_store_data(packet, &tm_tmp);
+ localtime_to_TIME(&time, &tm_tmp);
+ protocol->store(&time);
}
if (!file->check_time)
- net_store_null(packet);
+ protocol->store_null();
else
{
localtime_r(&file->check_time,&tm_tmp);
- net_store_data(packet, &tm_tmp);
+ localtime_to_TIME(&time, &tm_tmp);
+ protocol->store(&time);
}
+ str= (table->table_charset ? table->table_charset->name : "default");
+ protocol->store(str, system_charset_info);
{
char option_buff[350],*ptr;
ptr=option_buff;
@@ -405,27 +630,26 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
ptr=strmov(ptr,buff);
}
- net_store_data(packet, convert, option_buff+1,
- (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1));
+ protocol->store(option_buff+1,
+ (ptr == option_buff ? 0 : (uint) (ptr-option_buff)-1)
+ , system_charset_info);
}
{
char *comment=table->file->update_table_comment(table->comment);
- net_store_data(packet, comment);
+ protocol->store(comment, system_charset_info);
if (comment != table->comment)
my_free(comment,MYF(0));
}
close_thread_tables(thd,0);
}
- if (my_net_write(&thd->net,(char*) packet->ptr(),
- packet->length()))
+ if (protocol->write())
DBUG_RETURN(-1);
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
-
/***************************************************************************
** List all columns in a table_list->real_name
***************************************************************************/
@@ -438,14 +662,14 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
handler *file;
char tmp[MAX_FIELD_WIDTH];
Item *item;
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_fields");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
{
- send_error(&thd->net);
+ send_error(thd);
DBUG_RETURN(1);
}
file=table->file;
@@ -455,23 +679,20 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
List<Item> field_list;
field_list.push_back(new Item_empty_string("Field",NAME_LEN));
field_list.push_back(new Item_empty_string("Type",40));
+ field_list.push_back(new Item_empty_string("Collation",40));
field_list.push_back(new Item_empty_string("Null",1));
field_list.push_back(new Item_empty_string("Key",3));
field_list.push_back(item=new Item_empty_string("Default",NAME_LEN));
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));
-
- // Send first number of fields and records
{
- char *pos;
- pos=net_store_length(tmp, (uint) field_list.elements);
- pos=net_store_length(pos,(ulonglong) file->records);
- (void) my_net_write(&thd->net,tmp,(uint) (pos-tmp));
+ field_list.push_back(new Item_empty_string("Privileges",80));
+ field_list.push_back(new Item_empty_string("Comment",255));
}
-
- if (send_fields(thd,field_list,0))
+ // Send first number of fields and records
+ if (protocol->send_records_num(&field_list, (ulonglong)file->records) ||
+ protocol->send_fields(&field_list,0))
DBUG_RETURN(1);
restore_record(table,2); // Get empty record
@@ -479,7 +700,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 ||
@@ -489,48 +711,49 @@ 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), system_charset_info);
uint col_access;
bool null_default_value=0;
- packet->length(0);
- net_store_data(packet,convert,field->field_name);
+ protocol->prepare_for_resend();
+ protocol->store(field->field_name, system_charset_info);
field->sql_type(type);
- net_store_data(packet,convert,type.ptr(),type.length());
+ protocol->store(type.ptr(), type.length(), system_charset_info);
+ protocol->store(field->charset()->name, system_charset_info);
pos=(byte*) ((flags & NOT_NULL_FLAG) &&
field->type() != FIELD_TYPE_TIMESTAMP ?
"" : "YES");
- net_store_data(packet,convert,(const char*) pos);
+ protocol->store((const char*) pos, system_charset_info);
pos=(byte*) ((field->flags & PRI_KEY_FLAG) ? "PRI" :
(field->flags & UNIQUE_KEY_FLAG) ? "UNI" :
(field->flags & MULTIPLE_KEY_FLAG) ? "MUL":"");
- net_store_data(packet,convert,(char*) pos);
+ protocol->store((char*) pos, system_charset_info);
if (field->type() == FIELD_TYPE_TIMESTAMP ||
field->unireg_check == Field::NEXT_NUMBER)
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),system_charset_info);
field->val_str(&type,&type);
- net_store_data(packet,convert,type.ptr(),type.length());
+ protocol->store(type.ptr(),type.length(),type.charset());
}
else if (field->maybe_null() || null_default_value)
- net_store_null(packet); // Null as default
+ protocol->store_null(); // Null as default
else
- net_store_data(packet,convert,tmp,0);
+ protocol->store("",0, system_charset_info); // empty string
char *end=tmp;
if (field->unireg_check == Field::NEXT_NUMBER)
end=strmov(tmp,"auto_increment");
- net_store_data(packet,convert,tmp,(uint) (end-tmp));
+ protocol->store(tmp,(uint) (end-tmp), system_charset_info);
if (verbose)
{
- /* Add grant options */
- col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
+ /* Add grant options & comments */
end=tmp;
+ col_access= get_column_grant(thd,table_list,field) & COL_ACLS;
for (uint bitnr=0; col_access ; col_access>>=1,bitnr++)
{
if (col_access & 1)
@@ -539,22 +762,28 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
end=strmov(end,grant_types.type_names[bitnr]);
}
}
- net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1));
+ protocol->store(tmp+1,end == tmp ? 0 : (uint) (end-tmp-1),
+ system_charset_info);
+ protocol->store(field->comment.str, field->comment.length,
+ system_charset_info);
}
- if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ if (protocol->write())
DBUG_RETURN(1);
}
}
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
+
int
mysqld_show_create(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
+ char buff[2048];
+ String buffer(buff, sizeof(buff), system_charset_info);
DBUG_ENTER("mysqld_show_create");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
@@ -562,54 +791,25 @@ 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);
}
List<Item> field_list;
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_empty_string("Create Table",1024));
+ field_list.push_back(new Item_empty_string("Create Table", MAX_BLOB_WIDTH));
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(1);
-
- String *packet = &thd->packet;
- {
- packet->length(0);
- net_store_data(packet,convert, table->table_name);
- /*
- A hack - we need to reserve some space for the length before
- we know what it is - let's assume that the length of create table
- statement will fit into 3 bytes ( 16 MB max :-) )
- */
- ulong store_len_offset = packet->length();
- packet->length(store_len_offset + 4);
- if (store_create_info(thd, table, packet))
- DBUG_RETURN(-1);
- ulong create_len = packet->length() - store_len_offset - 4;
- if (create_len > 0x00ffffff) // better readable in HEX ...
- {
- /*
- Just in case somebody manages to create a table
- with *that* much stuff in the definition
- */
- DBUG_RETURN(1);
- }
-
- /*
- Now we have to store the length in three bytes, even if it would fit
- into fewer bytes, so we cannot use net_store_data() anymore,
- and do it ourselves
- */
- char* p = (char*)packet->ptr() + store_len_offset;
- *p++ = (char) 253; // The client the length is stored using 3-bytes
- int3store(p, create_len);
-
- // now we are in business :-)
- if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
- DBUG_RETURN(1);
- }
- send_eof(&thd->net);
+ protocol->prepare_for_resend();
+ protocol->store(table->table_name, system_charset_info);
+ buffer.length(0);
+ if (store_create_info(thd, table, &buffer))
+ DBUG_RETURN(-1);
+ protocol->store(buffer.ptr(), buffer.length(), buffer.charset());
+ if (protocol->write())
+ DBUG_RETURN(1);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -617,22 +817,23 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
int
mysqld_show_logs(THD *thd)
{
+ List<Item> field_list;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_logs");
- List<Item> field_list;
field_list.push_back(new Item_empty_string("File",FN_REFLEN));
field_list.push_back(new Item_empty_string("Type",10));
field_list.push_back(new Item_empty_string("Status",10));
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
#ifdef HAVE_BERKELEY_DB
- if (!berkeley_skip && berkeley_show_logs(thd))
+ if (!berkeley_skip && berkeley_show_logs(protocol))
DBUG_RETURN(-1);
#endif
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
}
@@ -641,30 +842,30 @@ int
mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
{
TABLE *table;
- char buff[256];
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_show_keys");
DBUG_PRINT("enter",("db: %s table: %s",table_list->db,
table_list->real_name));
if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
{
- send_error(&thd->net);
+ send_error(thd);
DBUG_RETURN(1);
}
List<Item> field_list;
Item *item;
field_list.push_back(new Item_empty_string("Table",NAME_LEN));
- field_list.push_back(new Item_int("Non_unique",0,1));
+ field_list.push_back(new Item_return_int("Non_unique",1, MYSQL_TYPE_TINY));
field_list.push_back(new Item_empty_string("Key_name",NAME_LEN));
- field_list.push_back(new Item_int("Seq_in_index",0,2));
+ field_list.push_back(new Item_return_int("Seq_in_index",2, MYSQL_TYPE_TINY));
field_list.push_back(new Item_empty_string("Column_name",NAME_LEN));
field_list.push_back(item=new Item_empty_string("Collation",1));
item->maybe_null=1;
field_list.push_back(item=new Item_int("Cardinality",0,21));
item->maybe_null=1;
- field_list.push_back(item=new Item_int("Sub_part",0,3));
+ field_list.push_back(item=new Item_return_int("Sub_part",3,
+ MYSQL_TYPE_TINY));
item->maybe_null=1;
field_list.push_back(item=new Item_empty_string("Packed",10));
item->maybe_null=1;
@@ -673,7 +874,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
field_list.push_back(new Item_empty_string("Comment",255));
item->maybe_null=1;
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1);
String *packet= &thd->packet;
@@ -682,65 +883,59 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
for (uint i=0 ; i < table->keys ; i++,key_info++)
{
KEY_PART_INFO *key_part= key_info->key_part;
- char *end;
+ const char *str;
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
{
- packet->length(0);
- net_store_data(packet,convert,table->table_name);
- net_store_data(packet,convert,((key_info->flags & HA_NOSAME) ? "0" :"1"), 1);
- net_store_data(packet,convert,key_info->name);
- end=int10_to_str((long) (j+1),(char*) buff,10);
- net_store_data(packet,convert,buff,(uint) (end-buff));
- net_store_data(packet,convert,
- key_part->field ? key_part->field->field_name :
- "?unknown field?");
+ protocol->prepare_for_resend();
+ protocol->store(table->table_name, system_charset_info);
+ protocol->store_tiny((longlong) ((key_info->flags & HA_NOSAME) ? 0 :1));
+ protocol->store(key_info->name, system_charset_info);
+ protocol->store_tiny((longlong) (j+1));
+ str=(key_part->field ? key_part->field->field_name :
+ "?unknown field?");
+ protocol->store(str, system_charset_info);
if (table->file->index_flags(i) & HA_READ_ORDER)
- net_store_data(packet,convert,
- ((key_part->key_part_flag & HA_REVERSE_SORT) ?
- "D" : "A"), 1);
+ protocol->store(((key_part->key_part_flag & HA_REVERSE_SORT) ?
+ "D" : "A"), 1, system_charset_info);
else
- net_store_null(packet); /* purecov: inspected */
+ protocol->store_null(); /* purecov: inspected */
KEY *key=table->key_info+i;
if (key->rec_per_key[j])
{
ha_rows records=(table->file->records / key->rec_per_key[j]);
- end=longlong10_to_str((longlong) records, buff, 10);
- net_store_data(packet,convert,buff,(uint) (end-buff));
+ protocol->store((ulonglong) records);
}
else
- net_store_null(packet);
+ protocol->store_null();
/* Check if we have a key part that only uses part of the field */
if (!key_part->field ||
key_part->length !=
table->field[key_part->fieldnr-1]->key_length())
- {
- end=int10_to_str((long) key_part->length, buff,10); /* purecov: inspected */
- net_store_data(packet,convert,buff,(uint) (end-buff)); /* purecov: inspected */
- }
+ protocol->store_tiny((longlong) key_part->length);
else
- net_store_null(packet);
- net_store_null(packet); // No pack_information yet
+ protocol->store_null();
+ protocol->store_null(); // No pack_information yet
/* Null flag */
uint flags= key_part->field ? key_part->field->flags : 0;
char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES");
- net_store_data(packet,convert,(const char*) pos);
- net_store_data(packet,convert,table->file->index_type(i));
+ protocol->store((const char*) pos, system_charset_info);
+ protocol->store(table->file->index_type(i), system_charset_info);
/* Comment */
- net_store_data(packet,convert,"");
- if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ protocol->store("", 0);
+ if (protocol->write())
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
@@ -752,7 +947,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;
@@ -760,35 +955,37 @@ 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
- if (send_fields(thd,field_list,2))
+ if (thd->protocol->send_fields(&field_list,2))
DBUG_VOID_RETURN;
- VOID(net_flush(&thd->net));
+ net_flush(&thd->net);
DBUG_VOID_RETURN;
}
+
int
mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
{
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
+ String *packet= protocol->storage_packet();
DBUG_ENTER("mysqld_dump_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
- String* packet = &thd->packet;
- packet->length(0);
- if (store_create_info(thd,table,packet))
+ protocol->prepare_for_resend();
+ if (store_create_info(thd, table, packet))
DBUG_RETURN(-1);
- if (convert)
- convert->convert((char*) packet->ptr(), packet->length());
+ if (protocol->convert)
+ protocol->convert->convert((char*) packet->ptr(), packet->length());
if (fd < 0)
{
- if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length()))
+ if (protocol->write())
DBUG_RETURN(-1);
- VOID(net_flush(&thd->net));
+ net_flush(&thd->net);
}
else
{
@@ -799,14 +996,26 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd)
DBUG_RETURN(0);
}
+
static void
append_identifier(THD *thd, String *packet, const char *name)
{
+ char qtype;
+ if ((thd->variables.sql_mode & MODE_ANSI_QUOTES) ||
+ (thd->variables.sql_mode & MODE_POSTGRESQL) ||
+ (thd->variables.sql_mode & MODE_ORACLE) ||
+ (thd->variables.sql_mode & MODE_MSSQL) ||
+ (thd->variables.sql_mode & MODE_DB2) ||
+ (thd->variables.sql_mode & MODE_SAPDB))
+ qtype= '\"';
+ else
+ qtype= '`';
+
if (thd->options & OPTION_QUOTE_SHOW_CREATE)
{
- packet->append("`", 1);
+ packet->append(&qtype, 1);
packet->append(name);
- packet->append("`", 1);
+ packet->append(&qtype, 1);
}
else
{
@@ -814,9 +1023,21 @@ append_identifier(THD *thd, String *packet, const char *name)
}
}
+#define LIST_PROCESS_HOST_LEN 64
+
static int
store_create_info(THD *thd, TABLE *table, String *packet)
{
+ my_bool foreign_db_mode= ((thd->variables.sql_mode & MODE_POSTGRESQL) ||
+ (thd->variables.sql_mode & MODE_ORACLE) ||
+ (thd->variables.sql_mode & MODE_MSSQL) ||
+ (thd->variables.sql_mode & MODE_DB2) ||
+ (thd->variables.sql_mode & MODE_SAPDB));
+ my_bool limited_mysql_mode= ((thd->variables.sql_mode &
+ MODE_NO_FIELD_OPTIONS) ||
+ (thd->variables.sql_mode & MODE_MYSQL323) ||
+ (thd->variables.sql_mode & MODE_MYSQL40));
+
DBUG_ENTER("store_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
@@ -824,7 +1045,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),&my_charset_bin);
if (table->tmp_table)
packet->append("CREATE TEMPORARY TABLE ", 23);
else
@@ -844,7 +1065,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),&my_charset_bin);
field->sql_type(type);
packet->append(type.ptr(),type.length());
@@ -852,6 +1073,17 @@ store_create_info(THD *thd, TABLE *table, String *packet)
bool has_default = (field->type() != FIELD_TYPE_BLOB &&
field->type() != FIELD_TYPE_TIMESTAMP &&
field->unireg_check != Field::NEXT_NUMBER);
+
+ /*
+ For string types dump collation name only if
+ collation is not primary for the given charset
+ */
+ if (!(field->charset()->state & MY_CS_PRIMARY) &&
+ !limited_mysql_mode && !foreign_db_mode)
+ {
+ packet->append(" collate ", 9);
+ packet->append(field->charset()->name);
+ }
if (flags & NOT_NULL_FLAG)
packet->append(" NOT NULL", 9);
@@ -860,12 +1092,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),&my_charset_bin);
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
@@ -873,8 +1105,14 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append(tmp,0);
}
- if (field->unireg_check == Field::NEXT_NUMBER)
- packet->append(" auto_increment", 15 );
+ if (field->unireg_check == Field::NEXT_NUMBER && !foreign_db_mode)
+ 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;
@@ -896,11 +1134,25 @@ 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);
+ append_identifier(thd, packet, key_info->name);
+ if (!(thd->variables.sql_mode & MODE_NO_KEY_OPTIONS) &&
+ !limited_mysql_mode && !foreign_db_mode)
+ {
+ if (table->db_type == DB_TYPE_HEAP &&
+ key_info->algorithm == HA_KEY_ALG_BTREE)
+ packet->append(" TYPE BTREE", 11);
+
+ // +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(" TYPE RTREE", 11);
+ }
packet->append(" (", 2);
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
@@ -939,65 +1191,80 @@ store_create_info(THD *thd, TABLE *table, String *packet)
}
packet->append("\n)", 2);
- packet->append(" TYPE=", 6);
- packet->append(file->table_type());
- char buff[128];
- char* p;
-
- if (table->min_rows)
+ if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
{
- packet->append(" MIN_ROWS=");
- p = longlong10_to_str(table->min_rows, buff, 10);
- packet->append(buff, (uint) (p - buff));
- }
+ packet->append(" TYPE=", 6);
+ packet->append(file->table_type());
+ char buff[128];
+ char* p;
+
+ if (table->table_charset &&
+ !(thd->variables.sql_mode & MODE_MYSQL323) &&
+ !(thd->variables.sql_mode & MODE_MYSQL40))
+ {
+ packet->append(" CHARSET=");
+ packet->append(table->table_charset->csname);
+ if (!(table->table_charset->state & MY_CS_PRIMARY))
+ {
+ packet->append(" COLLATE=");
+ packet->append(table->table_charset->name);
+ }
+ }
- if (table->max_rows)
- {
- packet->append(" MAX_ROWS=");
- p = longlong10_to_str(table->max_rows, buff, 10);
- packet->append(buff, (uint) (p - buff));
- }
- if (table->avg_row_length)
- {
- packet->append(" AVG_ROW_LENGTH=");
- p=longlong10_to_str(table->avg_row_length, buff,10);
- packet->append(buff, (uint) (p - buff));
- }
+ if (table->min_rows)
+ {
+ packet->append(" MIN_ROWS=");
+ p = longlong10_to_str(table->min_rows, buff, 10);
+ packet->append(buff, (uint) (p - buff));
+ }
- if (table->db_create_options & HA_OPTION_PACK_KEYS)
- packet->append(" PACK_KEYS=1", 12);
- if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
- packet->append(" PACK_KEYS=0", 12);
- if (table->db_create_options & HA_OPTION_CHECKSUM)
- packet->append(" CHECKSUM=1", 11);
- if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
- packet->append(" DELAY_KEY_WRITE=1",18);
- if (table->row_type != ROW_TYPE_DEFAULT)
- {
- packet->append(" ROW_FORMAT=",12);
- packet->append(ha_row_type[(uint) table->row_type]);
- }
- table->file->append_create_info(packet);
- if (table->comment && table->comment[0])
- {
- packet->append(" COMMENT='", 10);
- append_unescaped(packet, table->comment);
- packet->append('\'');
- }
- if (file->raid_type)
- {
- char buff[100];
- sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
- my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
- packet->append(buff);
+ if (table->max_rows)
+ {
+ packet->append(" MAX_ROWS=");
+ p = longlong10_to_str(table->max_rows, buff, 10);
+ packet->append(buff, (uint) (p - buff));
+ }
+ if (table->avg_row_length)
+ {
+ packet->append(" AVG_ROW_LENGTH=");
+ p=longlong10_to_str(table->avg_row_length, buff,10);
+ packet->append(buff, (uint) (p - buff));
+ }
+
+ if (table->db_create_options & HA_OPTION_PACK_KEYS)
+ packet->append(" PACK_KEYS=1", 12);
+ if (table->db_create_options & HA_OPTION_NO_PACK_KEYS)
+ packet->append(" PACK_KEYS=0", 12);
+ if (table->db_create_options & HA_OPTION_CHECKSUM)
+ packet->append(" CHECKSUM=1", 11);
+ if (table->db_create_options & HA_OPTION_DELAY_KEY_WRITE)
+ packet->append(" DELAY_KEY_WRITE=1",18);
+ if (table->row_type != ROW_TYPE_DEFAULT)
+ {
+ packet->append(" ROW_FORMAT=",12);
+ packet->append(ha_row_type[(uint) table->row_type]);
+ }
+ table->file->append_create_info(packet);
+ if (table->comment && table->comment[0])
+ {
+ packet->append(" COMMENT=", 9);
+ append_unescaped(packet, table->comment, strlen(table->comment));
+ }
+ if (file->raid_type)
+ {
+ char buff[100];
+ sprintf(buff," RAID_TYPE=%s RAID_CHUNKS=%d RAID_CHUNKSIZE=%ld",
+ my_raid_type(file->raid_type), file->raid_chunks, file->raid_chunksize/RAID_BLOCK_SIZE);
+ packet->append(buff);
+ }
}
DBUG_RETURN(0);
}
/****************************************************************************
-** 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 {
@@ -1017,8 +1284,6 @@ public:
template class I_List<thread_info>;
#endif
-#define LIST_PROCESS_HOST_LEN 64
-
void mysqld_list_processes(THD *thd,const char *user, bool verbose)
{
Item *field;
@@ -1026,21 +1291,21 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
I_List<thread_info> thread_infos;
ulong max_query_length= (verbose ? thd->variables.max_allowed_packet :
PROCESS_LIST_WIDTH);
- CONVERT *convert=thd->variables.convert_set;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysqld_list_processes");
- field_list.push_back(new Item_int("Id",0,7));
+ field_list.push_back(new Item_int("Id",0,11));
field_list.push_back(new Item_empty_string("User",16));
field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
field->maybe_null=1;
field_list.push_back(new Item_empty_string("Command",16));
- field_list.push_back(new Item_empty_string("Time",7));
+ field_list.push_back(new Item_return_int("Time",7, FIELD_TYPE_LONG));
field_list.push_back(field=new Item_empty_string("State",30));
field->maybe_null=1;
field_list.push_back(field=new Item_empty_string("Info",max_query_length));
field->maybe_null=1;
- if (send_fields(thd,field_list,1))
+ if (protocol->send_fields(&field_list,1))
DBUG_VOID_RETURN;
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
@@ -1051,8 +1316,13 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
while ((tmp=it++))
{
struct st_my_thread_var *mysys_var;
+#ifndef EMBEDDED_LIBRARY
if ((tmp->net.vio || tmp->system_thread) &&
(!user || (tmp->user && !strcmp(tmp->user,user))))
+#else
+ if (tmp->system_thread &&
+ (!user || (tmp->user && !strcmp(tmp->user,user))))
+#endif
{
thread_info *thd_info=new thread_info;
@@ -1074,6 +1344,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if ((mysys_var= tmp->mysys_var))
pthread_mutex_lock(&mysys_var->mutex);
thd_info->proc_info= (char*) (tmp->killed ? "Killed" : 0);
+#ifndef EMBEDDED_LIBRARY
thd_info->state_info= (char*) (tmp->locked ? "Locked" :
tmp->net.reading_or_writing ?
(tmp->net.reading_or_writing == 2 ?
@@ -1084,6 +1355,9 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
tmp->mysys_var &&
tmp->mysys_var->current_cond ?
"Waiting on cond" : NullS);
+#else
+ thd_info->state_info= (char*)"Writing to net";
+#endif
if (mysys_var)
pthread_mutex_unlock(&mysys_var->mutex);
@@ -1111,308 +1385,358 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thread_info *thd_info;
- String *packet= &thd->packet;
+ time_t now= time(0);
while ((thd_info=thread_infos.get()))
{
- char buff[20],*end;
- packet->length(0);
- end=int10_to_str((long) thd_info->thread_id, buff,10);
- net_store_data(packet,convert,buff,(uint) (end-buff));
- net_store_data(packet,convert,thd_info->user);
- net_store_data(packet,convert,thd_info->host);
- if (thd_info->db)
- net_store_data(packet,convert,thd_info->db);
- else
- net_store_null(packet);
+ protocol->prepare_for_resend();
+ protocol->store((ulonglong) thd_info->thread_id);
+ protocol->store(thd_info->user, system_charset_info);
+ protocol->store(thd_info->host, system_charset_info);
+ protocol->store(thd_info->db, system_charset_info);
if (thd_info->proc_info)
- net_store_data(packet,convert,thd_info->proc_info);
+ protocol->store(thd_info->proc_info, system_charset_info);
else
- net_store_data(packet,convert,command_name[thd_info->command]);
+ protocol->store(command_name[thd_info->command], system_charset_info);
if (thd_info->start_time)
- net_store_data(packet,
- (uint32) (time((time_t*) 0) - thd_info->start_time));
- else
- net_store_null(packet);
- if (thd_info->state_info)
- net_store_data(packet,convert,thd_info->state_info);
+ protocol->store((uint32) (now - thd_info->start_time));
else
- net_store_null(packet);
- if (thd_info->query)
- net_store_data(packet,convert,thd_info->query);
- else
- net_store_null(packet);
- if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length()))
+ protocol->store_null();
+ protocol->store(thd_info->state_info, system_charset_info);
+ protocol->store(thd_info->query, system_charset_info);
+ if (protocol->write())
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),thd->charset());
+ List<Item> field_list;
+ CHARSET_INFO **cs;
+ Protocol *protocol= thd->protocol;
+ char flags[64];
+
+ DBUG_ENTER("mysqld_show_charsets");
+
+ field_list.push_back(new Item_empty_string("CS_Name",30));
+ field_list.push_back(new Item_empty_string("COL_Name",30));
+ field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT));
+ field_list.push_back(new Item_empty_string("Flags",30));
+ field_list.push_back(new Item_return_int("strx_maxlen",3, FIELD_TYPE_TINY));
+ field_list.push_back(new Item_return_int("mb_maxlen",3, FIELD_TYPE_TINY));
+
+ if (protocol->send_fields(&field_list, 1))
+ DBUG_RETURN(1);
+
+ for (cs=all_charsets ; cs < all_charsets+255 ; cs++ )
+ {
+ if (cs[0] && !(wild && wild[0] &&
+ wild_case_compare(system_charset_info,cs[0]->name,wild)))
+ {
+ protocol->prepare_for_resend();
+ protocol->store(cs[0]->csname, system_charset_info);
+ protocol->store(cs[0]->name, system_charset_info);
+ protocol->store_short((longlong) cs[0]->number);
+ flags[0]='\0';
+ if (cs[0]->state & MY_CS_PRIMARY)
+ strcat(flags,"pri");
+ protocol->store(flags, system_charset_info);
+ protocol->store_tiny((longlong) cs[0]->strxfrm_multiply);
+ protocol->store_tiny((longlong) cs[0]->mbmaxlen);
+ if (protocol->write())
+ 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));
+ char buff[1024];
List<Item> field_list;
- CONVERT *convert=thd->variables.convert_set;
-
+ Protocol *protocol= thd->protocol;
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))
+ if (protocol->send_fields(&field_list,1))
DBUG_RETURN(1); /* purecov: inspected */
/* pthread_mutex_lock(&THR_LOCK_keycache); */
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);
+ protocol->prepare_for_resend();
+ protocol->store(variables->name, system_charset_info);
SHOW_TYPE show_type=variables->type;
char *value=variables->value;
+ const char *pos, *end;
+ long nr;
+
if (show_type == SHOW_SYS)
{
show_type= ((sys_var*) value)->type();
value= (char*) ((sys_var*) value)->value_ptr(thd, value_type);
}
+ pos= end= buff;
switch (show_type) {
case SHOW_LONG:
case SHOW_LONG_CONST:
- net_store_data(&packet2,(uint32) *(ulong*) value);
+ end= int10_to_str(*(long*) value, buff, 10);
break;
case SHOW_LONGLONG:
- net_store_data(&packet2,(longlong) *(longlong*) value);
- break;
+ end= longlong10_to_str(*(longlong*) value, buff, 10);
+ break;
case SHOW_HA_ROWS:
- net_store_data(&packet2,(longlong) *(ha_rows*) value);
+ end= longlong10_to_str((longlong) *(ha_rows*) value, buff, 10);
break;
case SHOW_BOOL:
- net_store_data(&packet2,(ulong) *(bool*) value ? "ON" : "OFF");
+ end= strmov(buff, *(bool*) value ? "ON" : "OFF");
break;
case SHOW_MY_BOOL:
- net_store_data(&packet2,(ulong) *(my_bool*) value ? "ON" : "OFF");
+ end= strmov(buff, *(my_bool*) value ? "ON" : "OFF");
break;
case SHOW_INT_CONST:
case SHOW_INT:
- net_store_data(&packet2,(uint32) *(int*) value);
+ end= int10_to_str((long) *(uint32*) value, buff, 10);
break;
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"));
+ pos= show_comp_option_name[(int) tmp];
+ end= strend(pos);
break;
}
case SHOW_CHAR:
- net_store_data(&packet2,convert, value);
+ pos= value;
+ end= strend(pos);
break;
case SHOW_STARTTIME:
- net_store_data(&packet2,(uint32) (thd->query_start() - start_time));
+ nr= (long) (thd->query_start() - start_time);
+ end= int10_to_str(nr, buff, 10);
break;
case SHOW_QUESTION:
- net_store_data(&packet2,(uint32) thd->query_id);
+ end= int10_to_str((long) thd->query_id, buff, 10);
break;
+#ifndef EMBEDDED_LIBRARY
case SHOW_RPL_STATUS:
- net_store_data(&packet2, rpl_status_type[(int)rpl_status]);
+ end= strmov(buff, rpl_status_type[(int)rpl_status]);
break;
-#ifndef EMBEDDED_LIBRARY
case SHOW_SLAVE_RUNNING:
{
LOCK_ACTIVE_MI;
- net_store_data(&packet2, (active_mi->slave_running &&
- active_mi->rli.slave_running)
- ? "ON" : "OFF");
+ end= strmov(buff, (active_mi->slave_running &&
+ active_mi->rli.slave_running) ? "ON" : "OFF");
UNLOCK_ACTIVE_MI;
break;
}
-#endif
+#endif /* EMBEDDED_LIBRARY */
case SHOW_OPENTABLES:
- net_store_data(&packet2,(uint32) cached_tables());
+ end= int10_to_str((long) cached_tables(), buff, 10);
break;
case SHOW_CHAR_PTR:
{
- value= *(char**) value;
- net_store_data(&packet2,convert, value ? value : "");
+ if (!(pos= *(char**) value))
+ pos= "";
+ end= strend(pos);
break;
}
#ifdef HAVE_OPENSSL
/* First group - functions relying on CTX */
case SHOW_SSL_CTX_SESS_ACCEPT:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_ACCEPT_GOOD:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept_good(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_good(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_CONNECT_GOOD:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect_good(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_good(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_accept_renegotiate(ssl_acceptor_fd->ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_CONNECT_RENEGOTIATE:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect_renegotiate(ssl_acceptor_fd-> ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_CB_HITS:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_cb_hits(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cb_hits(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_HITS:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_hits(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_hits(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_CACHE_FULL:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_cache_full(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_cache_full(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_MISSES:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_misses(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_misses(ssl_acceptor_fd->
+ ssl_context_)),
+ buff, 10);
break;
case SHOW_SSL_CTX_SESS_TIMEOUTS:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_timeouts(ssl_acceptor_fd->ssl_context_)),
+ buff,10);
break;
case SHOW_SSL_CTX_SESS_NUMBER:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_number(ssl_acceptor_fd->ssl_context_)),
+ buff,10);
break;
case SHOW_SSL_CTX_SESS_CONNECT:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_connect(ssl_acceptor_fd->ssl_context_)),
+ buff,10);
break;
case SHOW_SSL_CTX_SESS_GET_CACHE_SIZE:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_sess_get_cache_size(ssl_acceptor_fd->ssl_context_)),
+ buff,10);
break;
case SHOW_SSL_CTX_GET_VERIFY_MODE:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_mode(ssl_acceptor_fd->ssl_context_)),
+ buff,10);
break;
case SHOW_SSL_CTX_GET_VERIFY_DEPTH:
- net_store_data(&packet2,(uint32)
- (!ssl_acceptor_fd ? 0 :
- SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)));
+ end= int10_to_str((long) (!ssl_acceptor_fd ? 0 :
+ SSL_CTX_get_verify_depth(ssl_acceptor_fd->ssl_context_)),
+ buff,10);
break;
case SHOW_SSL_CTX_GET_SESSION_CACHE_MODE:
if (!ssl_acceptor_fd)
{
- net_store_data(&packet2,"NONE" );
+ pos= "NONE";
+ end= pos+4;
break;
}
switch (SSL_CTX_get_session_cache_mode(ssl_acceptor_fd->ssl_context_))
{
case SSL_SESS_CACHE_OFF:
- net_store_data(&packet2,"OFF" );
+ pos= "OFF";
break;
case SSL_SESS_CACHE_CLIENT:
- net_store_data(&packet2,"CLIENT" );
+ pos= "CLIENT";
break;
case SSL_SESS_CACHE_SERVER:
- net_store_data(&packet2,"SERVER" );
+ pos= "SERVER";
break;
case SSL_SESS_CACHE_BOTH:
- net_store_data(&packet2,"BOTH" );
+ pos= "BOTH";
break;
case SSL_SESS_CACHE_NO_AUTO_CLEAR:
- net_store_data(&packet2,"NO_AUTO_CLEAR" );
+ pos= "NO_AUTO_CLEAR";
break;
case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
- net_store_data(&packet2,"NO_INTERNAL_LOOKUP" );
+ pos= "NO_INTERNAL_LOOKUP";
break;
default:
- net_store_data(&packet2,"Unknown");
+ pos= "Unknown";
break;
}
+ end= strend(pos);
break;
/* First group - functions relying on SSL */
case SHOW_SSL_GET_VERSION:
- net_store_data(&packet2, thd->net.vio->ssl_ ?
- SSL_get_version(thd->net.vio->ssl_) : "");
+ pos= thd->net.vio->ssl_ ? SSL_get_version(thd->net.vio->ssl_) : "";
+ end= strend(pos);
break;
case SHOW_SSL_SESSION_REUSED:
- net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
- SSL_session_reused(thd->net.vio->ssl_) : 0));
+ end= int10_to_str((long) (thd->net.vio->ssl_ ?
+ SSL_session_reused(thd->net.vio->ssl_):
+ 0), buff, 10);
break;
case SHOW_SSL_GET_DEFAULT_TIMEOUT:
- net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
- SSL_get_default_timeout(thd->net.vio->ssl_):0));
+ end= int10_to_str((long) (thd->net.vio->ssl_ ?
+ SSL_get_default_timeout(thd->net.vio->ssl_):
+ 0), buff, 10);
break;
case SHOW_SSL_GET_VERIFY_MODE:
- net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
- SSL_get_verify_mode(thd->net.vio->ssl_):0));
+ end= int10_to_str((long) (thd->net.vio->ssl_ ?
+ SSL_get_verify_mode(thd->net.vio->ssl_):
+ 0), buff, 10);
break;
case SHOW_SSL_GET_VERIFY_DEPTH:
- net_store_data(&packet2,(uint32) (thd->net.vio->ssl_ ?
- SSL_get_verify_depth(thd->net.vio->ssl_):0));
+ end= int10_to_str((long) (thd->net.vio->ssl_ ?
+ SSL_get_verify_depth(thd->net.vio->ssl_):
+ 0), buff, 10);
break;
case SHOW_SSL_GET_CIPHER:
- net_store_data(&packet2, thd->net.vio->ssl_ ?
- SSL_get_cipher(thd->net.vio->ssl_) : "");
+ pos= thd->net.vio->ssl_ ? SSL_get_cipher(thd->net.vio->ssl_) : "";
+ end= strend(pos);
break;
case SHOW_SSL_GET_CIPHER_LIST:
if (thd->net.vio->ssl_)
{
- char buf[1024], *pos;
- pos=buf;
+ char *to= buff;
for (int i=0 ; i++ ;)
{
- const char *p=SSL_get_cipher_list(thd->net.vio->ssl_,i);
+ const char *p= SSL_get_cipher_list(thd->net.vio->ssl_,i);
if (p == NULL)
break;
- pos=strmov(pos, p);
- *pos++= ':';
+ to= strmov(to, p);
+ *to++= ':';
}
- if (pos != buf)
- pos--; // Remove last ':'
- *pos=0;
- net_store_data(&packet2, buf);
+ if (to != buff)
+ to--; // Remove last ':'
+ end= to;
}
- else
- net_store_data(&packet2, "");
break;
#endif /* HAVE_OPENSSL */
case SHOW_UNDEF: // Show never happen
case SHOW_SYS:
- net_store_data(&packet2, ""); // Safety
+ break; // Return empty string
+ default:
break;
}
- if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length()))
+ if (protocol->store(pos, (uint32) (end - pos), system_charset_info) ||
+ protocol->write())
goto err; /* purecov: inspected */
}
}
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_sort.h b/sql/sql_sort.h
index 62c5f1cb164..14463a67a28 100644
--- a/sql/sql_sort.h
+++ b/sql/sql_sort.h
@@ -38,9 +38,7 @@ typedef struct st_sort_param {
SORT_FIELD *end;
uchar *unique_buff;
bool not_killable;
-#ifdef USE_STRCOLL
char* tmp_buffer;
-#endif
} SORTPARAM;
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 2dcda2d40c2..d796c53fb52 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -28,8 +28,12 @@
#include <floatingpoint.h>
#endif
+CHARSET_INFO *system_charset_info= &my_charset_latin1;
extern gptr sql_alloc(unsigned size);
extern void sql_element_free(void *ptr);
+static uint32
+copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length, CHARSET_INFO *from_cs);
#include "sql_string.h"
@@ -91,36 +95,44 @@ 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);
+ str_length=(uint32) (cs->longlong10_to_str)(cs,Ptr,l,-10,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);
+ str_length=(uint32) (cs->longlong10_to_str)(cs,Ptr,l,10,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 +140,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 +190,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,19 +212,70 @@ 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_cs, CHARSET_INFO *to_cs)
+{
+ if ((from_cs == &my_charset_bin) || (to_cs == &my_charset_bin))
+ {
+ return copy(str, arg_length, &my_charset_bin);
+ }
+ uint32 new_length= to_cs->mbmaxlen*arg_length;
+ if (alloc(new_length))
+ return TRUE;
+ str_length=copy_and_convert((char*) Ptr, new_length, to_cs,
+ str, arg_length, from_cs);
+ str_charset=to_cs;
return FALSE;
}
+
+/*
+ Set a string to the value of a latin1-string, keeping the original charset
+
+ SYNOPSIS
+ copy_or_set()
+ str String of a simple charset (latin1)
+ arg_length Length of string
+
+ IMPLEMENTATION
+ If string object is of a simple character set, set it to point to the
+ given string.
+ If not, make a copy and convert it to the new character set.
+
+ RETURN
+ 0 ok
+ 1 Could not allocate result buffer
+
+*/
+
+bool String::set_latin1(const char *str, uint32 arg_length)
+{
+ if (str_charset->mbmaxlen == 1)
+ {
+ set(str, arg_length, str_charset);
+ return 0;
+ }
+ return copy(str, arg_length, &my_charset_latin1, str_charset);
+}
+
+
/* This is used by mysql.cc */
bool String::fill(uint32 max_length,char fill_char)
@@ -231,7 +294,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--;
}
@@ -247,11 +310,26 @@ bool String::append(const String &s)
return FALSE;
}
+
+/*
+ Append a latin1 string to the a string of the current character set
+*/
+
+
bool String::append(const char *s,uint32 arg_length)
{
if (!arg_length) // Default argument
if (!(arg_length= (uint32) strlen(s)))
return FALSE;
+ if (str_charset->mbmaxlen > 1)
+ {
+ uint32 add_length=arg_length * str_charset->mbmaxlen;
+ if (realloc(str_length+ add_length))
+ return TRUE;
+ str_length+= copy_and_convert(Ptr+str_length, add_length, str_charset,
+ s, arg_length, &my_charset_latin1);
+ return FALSE;
+ }
if (realloc(str_length+arg_length))
return TRUE;
memcpy(Ptr+str_length,s,arg_length);
@@ -259,6 +337,7 @@ bool String::append(const char *s,uint32 arg_length)
return FALSE;
}
+
#ifdef TO_BE_REMOVED
bool String::append(FILE* file, uint32 arg_length, myf my_flags)
{
@@ -289,46 +368,13 @@ bool String::append(IO_CACHE* file, uint32 arg_length)
uint32 String::numchars()
{
-#ifdef USE_MB
- register uint32 n=0,mblen;
- register const char *mbstr=Ptr;
- register const char *end=mbstr+str_length;
- if (use_mb(default_charset_info))
- {
- while (mbstr < end) {
- if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
- else ++mbstr;
- ++n;
- }
- return n;
- }
- else
-#endif
- return str_length;
+ return str_charset->numchars(str_charset, Ptr, Ptr+str_length);
}
int String::charpos(int i,uint32 offset)
{
-#ifdef USE_MB
- register uint32 mblen;
- register const char *mbstr=Ptr+offset;
- register const char *end=Ptr+str_length;
- if (use_mb(default_charset_info))
- {
- if (i<=0) return i;
- while (i && mbstr < end) {
- if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
- else ++mbstr;
- --i;
- }
- if ( INT_MAX32-i <= (int) (mbstr-Ptr-offset))
- return INT_MAX32;
- else
- return (int) ((mbstr-Ptr-offset)+i);
- }
- else
-#endif
- return i;
+ if (i<0) return i;
+ return str_charset->charpos(str_charset,Ptr+offset,Ptr+str_length,i);
}
int String::strstr(const String &s,uint32 offset)
@@ -377,12 +423,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,76 +504,50 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
return FALSE;
}
-
-int sortcmp(const String *x,const String *y)
+// added by Holyfoot for "geometry" needs
+int String::reserve(uint32 space_needed, uint32 grow_by)
{
- const char *s= x->ptr();
- const char *t= y->ptr();
- uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
-
-#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- {
-#ifndef CMP_ENDSPACE
- while (x_len && isspace(s[x_len-1]))
- x_len--;
- while (y_len && isspace(t[y_len-1]))
- y_len--;
-#endif
- return my_strnncoll(default_charset_info,
- (unsigned char *)s,x_len,(unsigned char *)t,y_len);
- }
- else
+ if (Alloced_length < str_length + space_needed)
{
-#endif /* USE_STRCOLL */
- x_len-=len; // For easy end space test
- y_len-=len;
- while (len--)
- {
- 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]]);
- }
-#ifndef CMP_ENDSPACE
- /* Don't compare end space in strings */
- {
- if (y_len)
- {
- const char *end=t+y_len;
- for (; t != end ; t++)
- if (!isspace(*t))
- return -1;
- }
- else
- {
- const char *end=s+x_len;
- for (; s != end ; s++)
- if (!isspace(*s))
- return 1;
- }
- return 0;
- }
-#else
- return (int) (x_len-y_len);
-#endif /* CMP_ENDSPACE */
-#ifdef USE_STRCOLL
+ if (realloc(Alloced_length + max(space_needed, grow_by) - 1))
+ return TRUE;
}
-#endif
+ 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);
+}
-int stringcmp(const String *x,const String *y)
+void String::qs_append(double *d)
{
- const char *s= x->ptr();
- const char *t= y->ptr();
- uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
+ double ld;
+ float8get(ld, (char*) d);
+ qs_append(ld);
+}
- while (len--)
- {
- if (*s++ != *t++)
- return ((int) (uchar) s[-1] - (int) (uchar) t[-1]);
- }
- return (int) (x_len-y_len);
+void String::qs_append(const char &c)
+{
+ Ptr[str_length] = c;
+ str_length += sizeof(c);
+}
+
+
+int sortcmp(const String *x,const String *y, CHARSET_INFO *cs)
+{
+ return cs->strnncollsp(cs,
+ (unsigned char *) x->ptr(),x->length(),
+ (unsigned char *) y->ptr(),y->length());
}
@@ -542,263 +564,66 @@ 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
+/****************************************************************************
+ Help functions
+****************************************************************************/
/*
-** Compare string against string with wildcard
-** 0 if matched
-** -1 if not matched with wildcard
-** 1 if matched with wildcard
+ copy a string from one character set to another
+
+ SYNOPSIS
+ copy_and_convert()
+ to Store result here
+ to_cs Character set of result string
+ from Copy from here
+ from_length Length of from string
+ from_cs From character set
+
+ NOTES
+ 'to' must be big enough as form_length * to_cs->mbmaxlen
+
+ RETURN
+ length of bytes copied to 'to'
*/
-#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)
+static uint32
+copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
+ const char *from, uint32 from_length, CHARSET_INFO *from_cs)
{
- 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 cnvres;
+ my_wc_t wc;
+ const uchar *from_end= (const uchar*) from+from_length;
+ char *to_start= to;
+ uchar *to_end= (uchar*) to+to_length;
-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 (1)
{
- while (*wildstr != wild_many && *wildstr != wild_one)
+ if ((cnvres=from_cs->mb_wc(from_cs, &wc, (uchar*) from, from_end)) > 0)
+ from+= cnvres;
+ else if (cnvres == MY_CS_ILSEQ)
{
- 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
+ from++;
+ wc= '?';
}
- if (*wildstr == wild_one)
+ else
+ break; // Impossible char.
+
+outp:
+ if ((cnvres= to_cs->wc_mb(to_cs, wc, (uchar*) to, to_end)) > 0)
+ to+= cnvres;
+ else if (cnvres == MY_CS_ILUNI && wc != '?')
{
- 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);
+ wc= '?';
+ goto outp;
}
+ else
+ break;
}
- 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));
+ return (uint32) (to - to_start);
}
diff --git a/sql/sql_string.h b/sql/sql_string.h
index ad7455ecbf1..8e0705844ad 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -25,37 +25,54 @@
#endif
class String;
-int sortcmp(const String *a,const String *b);
-int stringcmp(const String *a,const String *b);
+int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
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= &my_charset_bin;
+ }
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= &my_charset_bin;
+ }
+ 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 +100,32 @@ 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)
+ bool set_latin1(const 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,9 @@ public:
bool copy(); // Alloc string if not alloced
bool copy(const String &s); // Allocate new string
- bool copy(const char *s,uint32 arg_length); // Allocate new string
+ bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string
+ bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom,
+ CHARSET_INFO *csto);
bool append(const String &s);
bool append(const char *s,uint32 arg_length=0);
bool append(IO_CACHE* file, uint32 arg_length);
@@ -179,13 +202,81 @@ 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); }
- friend int sortcmp(const String *a,const String *b);
- friend int stringcmp(const String *a,const String *b);
+ 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, CHARSET_INFO *cs);
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);
+
+ /* Inline (general) functions used by the protocol functions */
+
+ inline char *prep_append(uint32 arg_length, uint32 step_alloc)
+ {
+ uint32 new_length= arg_length + str_length;
+ if (new_length > Alloced_length)
+ {
+ if (realloc(new_length + step_alloc))
+ return 0;
+ }
+ uint32 old_length= str_length;
+ str_length+= arg_length;
+ return Ptr+ old_length; /* Area to use */
+ }
+
+ inline bool append(const char *s, uint32 arg_length, uint32 step_alloc)
+ {
+ uint32 new_length= arg_length + str_length;
+ if (new_length > Alloced_length && realloc(new_length + step_alloc))
+ return TRUE;
+ memcpy(Ptr+str_length, s, arg_length);
+ str_length+= arg_length;
+ return FALSE;
+ }
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 0cdb0a7ff48..f4bcd6bd684 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -23,7 +23,6 @@
#endif
#include <hash.h>
#include <myisam.h>
-#include <assert.h>
#ifdef __WIN__
#include <io.h>
@@ -37,7 +36,7 @@ static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
static int copy_data_between_tables(TABLE *from,TABLE *to,
List<create_field> &create,
enum enum_duplicates handle_duplicates,
- ORDER *order,
+ uint order_num, ORDER *order,
ha_rows *copied,ha_rows *deleted);
/*
@@ -63,7 +62,8 @@ static int copy_data_between_tables(TABLE *from,TABLE *to,
*/
-int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
+int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
+ my_bool drop_temporary)
{
int error= 0;
DBUG_ENTER("mysql_rm_table");
@@ -74,7 +74,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
thd->mysys_var->current_cond= &COND_refresh;
VOID(pthread_mutex_lock(&LOCK_open));
- if (global_read_lock)
+ if (!drop_temporary && global_read_lock)
{
if (thd->global_read_lock)
{
@@ -89,7 +89,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
}
}
- error=mysql_rm_table_part2(thd,tables,if_exists,0);
+ error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary, 0);
err:
pthread_mutex_unlock(&LOCK_open);
@@ -101,7 +101,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);
}
@@ -127,14 +127,15 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists)
int mysql_rm_table_part2_with_lock(THD *thd,
TABLE_LIST *tables, bool if_exists,
- bool dont_log_query)
+ bool drop_temporary, bool dont_log_query)
{
int error;
thd->mysys_var->current_mutex= &LOCK_open;
thd->mysys_var->current_cond= &COND_refresh;
VOID(pthread_mutex_lock(&LOCK_open));
- error=mysql_rm_table_part2(thd,tables, if_exists, dont_log_query);
+ error=mysql_rm_table_part2(thd,tables, if_exists, drop_temporary,
+ dont_log_query);
pthread_mutex_unlock(&LOCK_open);
@@ -147,6 +148,17 @@ int mysql_rm_table_part2_with_lock(THD *thd,
/*
+ Execute the drop of a normal or temporary table
+
+ SYNOPSIS
+ mysql_rm_table_part2()
+ thd Thread handler
+ tables Tables to drop
+ if_exists If set, don't give an error if table doesn't exists.
+ In this case we give an warning of level 'NOTE'
+ drop_temporary Only drop temporary tables
+ dont_log_query Don't log the query
+
TODO:
When logging to the binary log, we should log
tmp_tables and transactional tables as separate statements if we
@@ -156,10 +168,15 @@ int mysql_rm_table_part2_with_lock(THD *thd,
The current code only writes DROP statements that only uses temporary
tables to the cache binary log. This should be ok on most cases, but
not all.
+
+ RETURN
+ 0 ok
+ 1 Error
+ -1 Thread was killed
*/
int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
- bool dont_log_query)
+ bool drop_temporary, bool dont_log_query)
{
TABLE_LIST *table;
char path[FN_REFLEN];
@@ -182,29 +199,35 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
continue; // removed temporary table
}
- abort_locked_tables(thd,db,table->real_name);
- while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed)
- {
- dropping_tables++;
- (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
- dropping_tables--;
- }
- drop_locked_tables(thd,db,table->real_name);
- if (thd->killed)
- DBUG_RETURN(-1);
-
- /* remove form file and isam files */
- strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext,
- NullS);
- (void) unpack_filename(path,path);
error=0;
+ if (!drop_temporary)
+ {
+ abort_locked_tables(thd,db,table->real_name);
+ while (remove_table_from_cache(thd,db,table->real_name) && !thd->killed)
+ {
+ dropping_tables++;
+ (void) pthread_cond_wait(&COND_refresh,&LOCK_open);
+ dropping_tables--;
+ }
+ drop_locked_tables(thd,db,table->real_name);
+ if (thd->killed)
+ DBUG_RETURN(-1);
- table_type=get_table_type(path);
+ /* remove form file and isam files */
+ strxmov(path, mysql_data_home, "/", db, "/", table->real_name, reg_ext,
+ NullS);
+ (void) unpack_filename(path,path);
- if (access(path,F_OK))
+ table_type=get_table_type(path);
+ }
+ if (drop_temporary || access(path,F_OK))
{
- if (!if_exists)
- error=1;
+ if (if_exists)
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
+ table->real_name);
+ else
+ error= 1;
}
else
{
@@ -225,9 +248,10 @@ 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,system_charset_info));
}
}
+ thd->tmp_table_used= tmp_table_deleted;
if (some_tables_deleted || tmp_table_deleted)
{
query_cache_invalidate3(thd, tables, 0);
@@ -280,7 +304,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)
@@ -345,7 +368,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;
@@ -353,14 +377,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)
@@ -369,6 +394,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)
@@ -382,10 +408,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)
@@ -394,17 +419,42 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
if (!(sql_field->flags & NOT_NULL_FLAG))
null_fields++;
+
if (check_column_name(sql_field->field_name))
{
my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name);
DBUG_RETURN(-1);
}
- 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();
@@ -417,6 +467,10 @@ 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;
+
switch (sql_field->sql_type) {
case FIELD_TYPE_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
@@ -425,7 +479,17 @@ 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;
+ blob_columns++;
+ break;
+ case FIELD_TYPE_GEOMETRY:
+ sql_field->pack_flag=FIELDFLAG_GEOM |
+ pack_length_to_packflag(sql_field->pack_length -
+ portable_sizeof_char_ptr);
+ 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;
@@ -434,17 +498,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
@@ -495,35 +563,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);
@@ -532,13 +615,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;
@@ -553,14 +651,46 @@ 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);
+ }
+ /* TODO: To be deleted */
+ my_printf_error(ER_NOT_SUPPORTED_YET, ER(ER_NOT_SUPPORTED_YET),
+ 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)
{
@@ -590,6 +720,17 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
}
}
}
+ if (key->type == Key::SPATIAL)
+ {
+ if (!column->length )
+ {
+ /*
+ BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
+ */
+ column->length=4*sizeof(double);
+ }
+ }
if (!(sql_field->flags & NOT_NULL_FLAG))
{
if (key->type == Key::PRIMARY)
@@ -603,6 +744,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
MYF(0),column->field_name);
DBUG_RETURN(-1);
}
+ if (key->type == Key::SPATIAL)
+ {
+ my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
+ DBUG_RETURN(-1);
+ }
key_info->flags|= HA_NULL_PART_KEY;
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
@@ -625,6 +771,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
}
+ else if (f_is_geom(sql_field->pack_flag))
+ {
+ }
else if (column->length > length ||
((f_is_packed(sql_field->pack_flag) ||
((file->table_flags() & HA_NO_PREFIX_CHAR_KEYS) &&
@@ -672,7 +821,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))
@@ -692,6 +841,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))
@@ -742,7 +892,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); */
@@ -756,6 +906,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
(void) rm_temporary_table(create_info->db_type, path);
goto end;
}
+ thd->tmp_table_used= 1;
}
if (!tmp_table && !no_log)
{
@@ -784,7 +935,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;
}
@@ -820,6 +971,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 */
@@ -851,7 +1003,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)))
{
@@ -952,20 +1104,18 @@ bool close_cached_table(THD *thd,TABLE *table)
DBUG_RETURN(result);
}
-static int send_check_errmsg(THD* thd, TABLE_LIST* table,
+static int send_check_errmsg(THD *thd, TABLE_LIST* table,
const char* operator_name, const char* errmsg)
{
-
- String* packet = &thd->packet;
- packet->length(0);
- net_store_data(packet, table->alias);
- net_store_data(packet, (char*)operator_name);
- net_store_data(packet, "error");
- net_store_data(packet, errmsg);
+ Protocol *protocol= thd->protocol;
+ protocol->prepare_for_resend();
+ protocol->store(table->alias, system_charset_info);
+ protocol->store((char*) operator_name, system_charset_info);
+ protocol->store("error", 5, system_charset_info);
+ protocol->store(errmsg, system_charset_info);
thd->net.last_error[0]=0;
- if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
- packet->length()))
+ if (protocol->write())
return -1;
return 1;
}
@@ -1111,8 +1261,8 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
{
TABLE_LIST *table;
List<Item> field_list;
- Item* item;
- String* packet = &thd->packet;
+ Item *item;
+ Protocol *protocol= thd->protocol;
DBUG_ENTER("mysql_admin_table");
field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
@@ -1123,7 +1273,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
item->maybe_null = 1;
field_list.push_back(item = new Item_empty_string("Msg_text", 255));
item->maybe_null = 1;
- if (send_fields(thd, field_list, 1))
+ if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
for (table = tables; table; table = table->next)
@@ -1135,8 +1285,11 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
thd->open_options|= extra_open_options;
table->table = open_ltable(thd, table, lock_type);
+#ifdef EMBEDDED_LIBRARY
+ thd->net.last_errno= 0; // these errors shouldn't get client
+#endif
thd->open_options&= ~extra_open_options;
- packet->length(0);
+
if (prepare_func)
{
switch ((*prepare_func)(thd, table, check_opt)) {
@@ -1149,30 +1302,30 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (!table->table)
{
const char *err_msg;
- net_store_data(packet, table_name);
- net_store_data(packet, operator_name);
- net_store_data(packet, "error");
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ protocol->store("error",5, system_charset_info);
if (!(err_msg=thd->net.last_error))
err_msg=ER(ER_CHECK_NO_SUCH_TABLE);
- net_store_data(packet, err_msg);
+ protocol->store(err_msg, system_charset_info);
thd->net.last_error[0]=0;
- if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
- packet->length()))
+ if (protocol->write())
goto err;
continue;
}
if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
{
char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
- net_store_data(packet, table_name);
- net_store_data(packet, operator_name);
- net_store_data(packet, "error");
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
+ protocol->store("error", 5, system_charset_info);
sprintf(buff, ER(ER_OPEN_AS_READONLY), table_name);
- net_store_data(packet, buff);
+ protocol->store(buff, system_charset_info);
close_thread_tables(thd);
table->table=0; // For query cache
- if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
- packet->length()))
+ if (protocol->write())
goto err;
continue;
}
@@ -1200,50 +1353,54 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
int result_code = (table->table->file->*operator_func)(thd, check_opt);
- packet->length(0);
- net_store_data(packet, table_name);
- net_store_data(packet, operator_name);
+#ifdef EMBEDDED_LIBRARY
+ thd->net.last_errno= 0; // these errors shouldn't get client
+#endif
+ protocol->prepare_for_resend();
+ protocol->store(table_name, system_charset_info);
+ protocol->store(operator_name, system_charset_info);
switch (result_code) {
case HA_ADMIN_NOT_IMPLEMENTED:
{
char buf[ERRMSGSIZE+20];
- my_snprintf(buf, ERRMSGSIZE,
- ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
- net_store_data(packet, "error");
- net_store_data(packet, buf);
+ uint length=my_snprintf(buf, ERRMSGSIZE,
+ ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
+ protocol->store("error", 5, system_charset_info);
+ protocol->store(buf, length, system_charset_info);
}
break;
case HA_ADMIN_OK:
- net_store_data(packet, "status");
- net_store_data(packet, "OK");
+ protocol->store("status", 6, system_charset_info);
+ protocol->store("OK",2, system_charset_info);
break;
case HA_ADMIN_FAILED:
- net_store_data(packet, "status");
- net_store_data(packet, "Operation failed");
+ protocol->store("status", 6, system_charset_info);
+ protocol->store("Operation failed",16, system_charset_info);
break;
case HA_ADMIN_ALREADY_DONE:
- net_store_data(packet, "status");
- net_store_data(packet, "Table is already up to date");
+ protocol->store("status", 6, system_charset_info);
+ protocol->store("Table is already up to date", 27, system_charset_info);
break;
case HA_ADMIN_CORRUPT:
- net_store_data(packet, "error");
- net_store_data(packet, "Corrupt");
+ protocol->store("error", 5, system_charset_info);
+ protocol->store("Corrupt", 8, system_charset_info);
fatal_error=1;
break;
case HA_ADMIN_INVALID:
- net_store_data(packet, "error");
- net_store_data(packet, "Invalid argument");
+ protocol->store("error", 5, system_charset_info);
+ protocol->store("Invalid argument",16, system_charset_info);
break;
default: // Probably HA_ADMIN_INTERNAL_ERROR
- net_store_data(packet, "error");
- net_store_data(packet, "Unknown - internal error during operation");
+ protocol->store("error", 5, system_charset_info);
+ protocol->store("Unknown - internal error during operation", 41
+ , system_charset_info);
fatal_error=1;
break;
}
@@ -1260,12 +1417,11 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
}
close_thread_tables(thd);
table->table=0; // For query cache
- if (my_net_write(&thd->net, (char*) packet->ptr(),
- packet->length()))
+ if (protocol->write())
goto err;
}
- send_eof(&thd->net);
+ send_eof(thd);
DBUG_RETURN(0);
err:
close_thread_tables(thd); // Shouldn't be needed
@@ -1313,6 +1469,127 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
}
+/*
+ Create a table identical to the specified table
+
+ SYNOPSIS
+ mysql_create_like_table()
+ thd Thread object
+ table Table list (one table only)
+ create_info Create info
+ table_ident Src table_ident
+
+ RETURN VALUES
+ 0 ok
+ -1 error
+*/
+
+int mysql_create_like_table(THD* thd, TABLE_LIST* table,
+ HA_CREATE_INFO *create_info,
+ Table_ident *table_ident)
+{
+ TABLE **tmp_table;
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN];
+ char *db= table->db;
+ char *table_name= table->real_name;
+ char *src_db= thd->db;
+ char *src_table= table_ident->table.str;
+ int err;
+
+ DBUG_ENTER("mysql_create_like_table");
+
+ /*
+ Validate the source table
+ */
+ if (table_ident->table.length > NAME_LEN ||
+ (table_ident->table.length &&
+ check_table_name(src_table,table_ident->table.length)) ||
+ table_ident->db.str && check_db_name((src_db= table_ident->db.str)))
+ {
+ my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table);
+ DBUG_RETURN(-1);
+ }
+
+ if ((tmp_table= find_temporary_table(thd, src_db, src_table)))
+ strxmov(src_path, (*tmp_table)->path, reg_ext, NullS);
+ else
+ {
+ strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table,
+ reg_ext, NullS);
+ if (access(src_path, F_OK))
+ {
+ my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table);
+ DBUG_RETURN(-1);
+ }
+ }
+
+ /*
+ Validate the destination table
+
+ skip the destination table name checking as this is already
+ validated.
+ */
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ if (find_temporary_table(thd, db, table_name))
+ goto table_exists;
+ sprintf(dst_path,"%s%s%lx_%lx_%x%s",mysql_tmpdir,tmp_file_prefix,
+ current_pid, thd->thread_id, thd->tmp_table++,reg_ext);
+ create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
+ }
+ else
+ {
+ strxmov(dst_path, mysql_data_home, "/", db, "/", table_name,
+ reg_ext, NullS);
+ if (!access(dst_path, F_OK))
+ goto table_exists;
+ }
+
+ /*
+ Create a new table by copying from source table
+ */
+ if (my_copy(src_path, dst_path, MYF(MY_WME)))
+ DBUG_RETURN(-1);
+
+ /*
+ As mysql_truncate don't work on a new table at this stage of
+ creation, instead create the table directly (for both normal
+ and temporary tables).
+ */
+ *fn_ext(dst_path)= 0;
+ err= ha_create_table(dst_path, create_info, 1);
+
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ {
+ if (err || !open_temporary_table(thd, dst_path, db, table_name, 1))
+ {
+ (void) rm_temporary_table(create_info->db_type,
+ dst_path); /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ }
+ else if (err)
+ {
+ (void) quick_rm_table(create_info->db_type, db,
+ table_name); /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+ DBUG_RETURN(0);
+
+table_exists:
+ if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff,ER(ER_TABLE_EXISTS_ERROR),table_name);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TABLE_EXISTS_ERROR,warn_buff);
+ DBUG_RETURN(0);
+ }
+ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
+ DBUG_RETURN(-1);
+}
+
+
int mysql_analyze_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
{
#ifdef OS2
@@ -1350,7 +1627,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
- ORDER *order,
+ uint order_num, ORDER *order,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff,
@@ -1385,9 +1662,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
@@ -1471,7 +1748,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);
}
table_list->table=0; // For query cache
query_cache_invalidate3(thd, table_list, 0);
@@ -1487,7 +1764,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;
@@ -1500,7 +1777,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 &&
@@ -1521,7 +1798,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)
@@ -1545,7 +1823,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)
@@ -1579,7 +1857,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)
@@ -1602,8 +1880,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);
@@ -1625,7 +1903,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)
@@ -1647,11 +1925,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
@@ -1668,18 +1948,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)
@@ -1707,6 +1993,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 &
@@ -1774,7 +2062,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)
@@ -1804,7 +2092,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (!new_table->is_view)
error=copy_data_between_tables(table,new_table,create_list,
handle_duplicates,
- order, &copied, &deleted);
+ order_num, order, &copied, &deleted);
thd->last_insert_id=next_insert_id; // Needed for correct log
thd->count_cuted_fields=0; // Don`t calc cuted fields
new_table->time_stamp=save_time_stamp;
@@ -1854,9 +2142,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";
@@ -2001,7 +2289,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);
@@ -2014,7 +2302,7 @@ static int
copy_data_between_tables(TABLE *from,TABLE *to,
List<create_field> &create,
enum enum_duplicates handle_duplicates,
- ORDER *order,
+ uint order_num, ORDER *order,
ha_rows *copied,
ha_rows *deleted)
{
@@ -2062,10 +2350,13 @@ copy_data_between_tables(TABLE *from,TABLE *to,
tables.db = from->table_cache_key;
error=1;
- if (setup_order(thd, &tables, fields, all_fields, order) ||
+ if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
+ order_num)||
+ setup_order(thd, thd->lex.select_lex.ref_pointer_array,
+ &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 6816bb62047..88ed86732f1 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), system_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),system_charset_info);
+ String out(buff2,sizeof(buff2),system_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: %lu\n",(ulong) special);
fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr());
DBUG_UNLOCK_FILE;
DBUG_VOID_RETURN;
@@ -187,6 +202,100 @@ 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");
+
+ unsigned int i;
+ for (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 +361,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 8a1c19568ae..450f1dd09ae 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -33,6 +33,7 @@
#endif
#include "mysql_priv.h"
+#include <my_pthread.h>
#ifdef HAVE_DLOPEN
extern "C"
@@ -70,10 +71,10 @@ extern "C"
static bool initialized = 0;
static MEM_ROOT mem;
static HASH udf_hash;
-static pthread_mutex_t THR_LOCK_udf;
+static rw_lock_t THR_LOCK_udf;
-static udf_func *add_udf(char *name, Item_result ret, char *dl,
+static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
Item_udftype typ);
static void del_udf(udf_func *udf);
static void *find_udf_dl(const char *dl);
@@ -83,8 +84,8 @@ static void init_syms(udf_func *tmp)
{
char nm[MAX_FIELD_NAME+16],*end;
- tmp->func = dlsym(tmp->dlhandle, tmp->name);
- end=strmov(nm,tmp->name);
+ tmp->func = dlsym(tmp->dlhandle, tmp->name.str);
+ end=strmov(nm,tmp->name.str);
(void) strmov(end,"_init");
tmp->func_init = dlsym(tmp->dlhandle, nm);
(void) strmov(end,"_deinit");
@@ -102,8 +103,8 @@ extern "C" byte* get_hash_key(const byte *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
udf_func *udf=(udf_func*) buff;
- *length=(uint) udf->name_length;
- return (byte*) udf->name;
+ *length=(uint) udf->name.length;
+ return (byte*) udf->name.str;
}
/*
@@ -122,12 +123,13 @@ void udf_init()
if (initialized)
DBUG_VOID_RETURN;
- pthread_mutex_init(&THR_LOCK_udf,MY_MUTEX_INIT_SLOW);
-
+ my_rwlock_init(&THR_LOCK_udf,NULL);
+
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);
@@ -159,14 +161,16 @@ void udf_init()
while (!(error = read_record_info.read_record(&read_record_info)))
{
DBUG_PRINT("info",("init udf record"));
- char *name=get_field(&mem, table, 0);
- char *dl_name= get_field(&mem, table, 2);
+ LEX_STRING name;
+ name.str=get_field(&mem, table->field[0]);
+ name.length = strlen(name.str);
+ char *dl_name= get_field(&mem, table->field[2]);
bool new_dl=0;
Item_udftype udftype=UDFTYPE_FUNCTION;
if (table->fields >= 4) // New func table
udftype=(Item_udftype) table->field[3]->val_int();
- if (!(tmp = add_udf(name,(Item_result) table->field[1]->val_int(),
+ if (!(tmp = add_udf(&name,(Item_result) table->field[1]->val_int(),
dl_name, udftype)))
{
sql_print_error("Can't alloc memory for udf function: name");
@@ -232,7 +236,7 @@ void udf_free()
if (initialized)
{
initialized= 0;
- pthread_mutex_destroy(&THR_LOCK_udf);
+ rwlock_destroy(&THR_LOCK_udf);
}
DBUG_VOID_RETURN;
}
@@ -253,10 +257,10 @@ static void del_udf(udf_func *udf)
The functions will be automaticly removed when the least threads
doesn't use it anymore
*/
- char *name= udf->name;
- uint name_length=udf->name_length;
- udf->name=(char*) "*";
- udf->name_length=1;
+ char *name= udf->name.str;
+ uint name_length=udf->name.length;
+ udf->name.str=(char*) "*";
+ udf->name.length=1;
hash_update(&udf_hash,(byte*) udf,(byte*) name,name_length);
}
DBUG_VOID_RETURN;
@@ -266,7 +270,7 @@ static void del_udf(udf_func *udf)
void free_udf(udf_func *udf)
{
DBUG_ENTER("free_udf");
- pthread_mutex_lock(&THR_LOCK_udf);
+ rw_wrlock(&THR_LOCK_udf);
if (!--udf->usage_count)
{
/*
@@ -278,7 +282,7 @@ void free_udf(udf_func *udf)
if (!find_udf_dl(udf->dl))
dlclose(udf->dlhandle);
}
- pthread_mutex_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
DBUG_VOID_RETURN;
}
@@ -291,7 +295,7 @@ udf_func *find_udf(const char *name,uint length,bool mark_used)
DBUG_ENTER("find_udf");
/* TODO: This should be changed to reader locks someday! */
- pthread_mutex_lock(&THR_LOCK_udf);
+ rw_rdlock(&THR_LOCK_udf);
if ((udf=(udf_func*) hash_search(&udf_hash,(byte*) name,
length ? length : (uint) strlen(name))))
{
@@ -300,7 +304,7 @@ udf_func *find_udf(const char *name,uint length,bool mark_used)
else if (mark_used)
udf->usage_count++;
}
- pthread_mutex_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
DBUG_RETURN(udf);
}
@@ -325,7 +329,7 @@ static void *find_udf_dl(const char *dl)
/* Assume that name && dl is already allocated */
-static udf_func *add_udf(char *name, Item_result ret, char *dl,
+static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
Item_udftype type)
{
if (!name || !dl || !(uint) type || (uint) type > (uint) UDFTYPE_AGGREGATE)
@@ -334,8 +338,7 @@ static udf_func *add_udf(char *name, Item_result ret, char *dl,
if (!tmp)
return 0;
bzero((char*) tmp,sizeof(*tmp));
- tmp->name = name;
- tmp->name_length=(uint) strlen(tmp->name);
+ tmp->name = *name; //dup !!
tmp->dl = dl;
tmp->returns = ret;
tmp->type = type;
@@ -359,7 +362,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);
}
@@ -370,19 +373,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)
+ 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)))
+ rw_wrlock(&THR_LOCK_udf);
+ if ((hash_search(&udf_hash,(byte*) udf->name.str, 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)))
@@ -391,7 +394,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;
@@ -401,14 +404,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->name.str=strdup_root(&mem,udf->name.str);
udf->dl=strdup_root(&mem,udf->dl);
- if (!(u_d=add_udf(udf->name,udf->returns,udf->dl,udf->type)))
+ 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;
@@ -428,9 +431,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.str, u_d->name.length, system_charset_info);
table->field[1]->store((longlong) u_d->returns);
- table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl));
+ table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), system_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]);
@@ -438,22 +441,22 @@ 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;
}
- pthread_mutex_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
DBUG_RETURN(0);
err:
if (new_dl)
dlclose(dl);
- pthread_mutex_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
DBUG_RETURN(1);
}
-int mysql_drop_function(THD *thd,const char *udf_name)
+int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
{
TABLE *table;
TABLE_LIST tables;
@@ -461,14 +464,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))))
+ rw_wrlock(&THR_LOCK_udf);
+ if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name->str,
+ (uint) udf_name->length)))
{
- net_printf(&thd->net, ER_FUNCTION_NOT_DEFINED, udf_name);
+ net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name);
goto err;
}
del_udf(udf);
@@ -484,8 +487,8 @@ int mysql_drop_function(THD *thd,const char *udf_name)
tables.real_name= tables.alias= (char*) "func";
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
- if (!table->file->index_read_idx(table->record[0],0,(byte*) udf_name,
- (uint) strlen(udf_name),
+ if (!table->file->index_read_idx(table->record[0],0,(byte*) udf_name->str,
+ (uint) udf_name->length,
HA_READ_KEY_EXACT))
{
int error;
@@ -494,10 +497,10 @@ int mysql_drop_function(THD *thd,const char *udf_name)
}
close_thread_tables(thd);
- pthread_mutex_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
DBUG_RETURN(0);
err:
- pthread_mutex_unlock(&THR_LOCK_udf);
+ rw_unlock(&THR_LOCK_udf);
DBUG_RETURN(1);
}
diff --git a/sql/sql_udf.h b/sql/sql_udf.h
index 1ee9c44ce48..29a351ac52f 100644
--- a/sql/sql_udf.h
+++ b/sql/sql_udf.h
@@ -25,8 +25,7 @@ enum Item_udftype {UDFTYPE_FUNCTION=1,UDFTYPE_AGGREGATE};
typedef struct st_udf_func
{
- char *name;
- int name_length;
+ LEX_STRING name;
Item_result returns;
Item_udftype type;
char *dl;
@@ -61,7 +60,7 @@ class udf_handler :public Sql_alloc
initialized(0)
{}
~udf_handler();
- const char *name() const { return u_d ? u_d->name : "?"; }
+ const char *name() const { return u_d ? u_d->name.str : "?"; }
Item_result result_type () const
{ return u_d ? u_d->returns : STRING_RESULT;}
bool get_arguments();
@@ -140,5 +139,5 @@ void udf_init(void),udf_free(void);
udf_func *find_udf(const char *name, uint len=0,bool mark_used=0);
void free_udf(udf_func *udf);
int mysql_create_function(THD *thd,udf_func *udf);
-int mysql_drop_function(THD *thd,const char *name);
+int mysql_drop_function(THD *thd,const LEX_STRING *name);
#endif
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index faa106d4f42..5f7a1e44bde 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -24,198 +24,14 @@
#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_UNIT *unit, bool tables_and_fields_initied)
{
- 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= 0;
- 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");
-
- /* 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)
- {
- for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
- cursor;
- cursor=cursor->next)
- {
- cursor->table= (my_reinterpret_cast(TABLE_LIST*) (cursor->table))->table;
- }
- }
-
- /* 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
- }
- else if (!last_sl->braces)
- {
- lex_sl= last_sl; // ORDER BY is here
- order= (ORDER *) lex_sl->order_list.first;
- }
- else
- {
- lex_sl=0;
- order=0;
- }
-
- if (describe)
- {
- 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));
- }
- else
- {
- Item *item;
- List_iterator<Item> it(lex->select_lex.item_list);
- TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.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);
- if (setup_fields(thd,first_table,item_list,0,0,1))
- DBUG_RETURN(-1);
- }
-
- 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);
- table->file->extra(HA_EXTRA_WRITE_CACHE);
- table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
- bzero((char*) &result_table_list,sizeof(result_table_list));
- result_table_list.db= (char*) "";
- result_table_list.real_name=result_table_list.alias= (char*) "union";
- result_table_list.table=table;
-
- if (!(union_result=new select_union(table)))
- {
- res= -1;
- goto exit;
- }
- union_result->not_describe= !describe;
- union_result->tmp_table_param=&tmp_table_param;
- for (sl= &lex->select_lex; sl; sl=sl->next)
- {
- 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)
- 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;
- }
- if (union_result->flush())
- {
- res= 1; // Error is already sent
- goto exit;
- }
- delete union_result;
-
- /* Send result to 'result' */
- lex->select = &lex->select_lex;
- res =-1;
- {
- /* Create a list of fields in the temporary table */
- List_iterator<Item> it(item_list);
- Field **field;
-#if 0
- List<Item_func_match> ftfunc_list;
- ftfunc_list.empty();
-#else
- thd->lex.select_lex.ftfunc_list.empty();
-#endif
-
- for (field=table->field ; *field ; field++)
- {
- (void) it++;
- (void) it.replace(new Item_field(*field));
- }
- 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);
- if (found_rows_for_union && !res)
- thd->limit_found_rows = (ulonglong)table->file->records;
- }
- }
-
-exit:
- free_tmp_table(thd,table);
+ int res= 0;
+ if (!(res= unit->prepare(thd, result, tables_and_fields_initied)))
+ res= unit->exec();
+ res|= unit->cleanup();
DBUG_RETURN(res);
}
@@ -232,7 +48,7 @@ select_union::select_union(TABLE *table_par)
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;
+ info.handle_duplicates= DUP_IGNORE;
}
select_union::~select_union()
@@ -240,8 +56,9 @@ select_union::~select_union()
}
-int select_union::prepare(List<Item> &list)
+int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
+ unit= u;
if (not_describe && list.elements != table->fields)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
@@ -253,16 +70,22 @@ int select_union::prepare(List<Item> &list)
bool select_union::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(table->field,values);
- if ((write_record(table,&info)))
+ if (thd->net.report_error || write_record(table,&info))
{
- if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0))
+ if (thd->net.last_errno == ER_RECORD_FILE_FULL)
+ {
+ thd->clear_error(); // do not report user about table overflow
+ if (create_myisam_from_heap(thd, table, tmp_table_param,
+ info.last_errno, 0))
+ return 1;
+ }
+ else
return 1;
}
return 0;
@@ -279,8 +102,279 @@ bool select_union::flush()
if ((error=table->file->extra(HA_EXTRA_NO_CACHE)))
{
table->file->print_error(error,MYF(0));
- ::send_error(&thd->net);
+ ::send_error(thd);
return 1;
}
return 0;
}
+
+int st_select_lex_unit::prepare(THD *thd, select_result *result,
+ bool tables_and_fields_initied)
+{
+ DBUG_ENTER("st_select_lex_unit::prepare");
+
+ if (prepared)
+ DBUG_RETURN(0);
+ prepared= 1;
+ res= 0;
+ found_rows_for_union= 0;
+ TMP_TABLE_PARAM tmp_table_param;
+ this->result= result;
+ t_and_f= tables_and_fields_initied;
+ SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
+ SELECT_LEX *select_cursor;
+
+ thd->lex.current_select= select_cursor= first_select_in_union();
+ /* Global option */
+ if (((void*)(global_parameters)) == ((void*)this))
+ {
+ 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;
+ }
+ if (t_and_f)
+ {
+ // Item list and tables will be initialized by mysql_derived
+ item_list= select_cursor->item_list;
+ }
+ else
+ {
+ item_list.empty();
+ TABLE_LIST *first_table= (TABLE_LIST*) select_cursor->table_list.first;
+
+ if (setup_tables(first_table) ||
+ setup_wild(thd, first_table, select_cursor->item_list, 0, select_cursor->with_wild))
+ goto err;
+ List_iterator<Item> it(select_cursor->item_list);
+ Item *item;
+ while((item=it++))
+ item->maybe_null=1;
+ item_list= select_cursor->item_list;
+ select_cursor->with_wild= 0;
+ if (setup_ref_array(thd, &select_cursor->ref_pointer_array,
+ (item_list.elements + select_cursor->with_sum_func +
+ select_cursor->order_list.elements +
+ select_cursor->group_list.elements)) ||
+ setup_fields(thd, select_cursor->ref_pointer_array, first_table, item_list,
+ 0, 0, 1))
+ goto err;
+ t_and_f= 1;
+ }
+
+ 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, !union_option,
+ 1, (select_cursor->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ HA_POS_ERROR)))
+ goto err;
+ table->file->extra(HA_EXTRA_WRITE_CACHE);
+ table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
+ bzero((char*) &result_table_list,sizeof(result_table_list));
+ result_table_list.db= (char*) "";
+ result_table_list.real_name=result_table_list.alias= (char*) "union";
+ result_table_list.table=table;
+
+ if (!(union_result=new select_union(table)))
+ goto err;
+
+ union_result->not_describe=1;
+ union_result->tmp_table_param=&tmp_table_param;
+
+/*
+ the following piece of code is placed here solely for the purpose of
+ getting correct results with EXPLAIN when UNION is withing a sub-select
+ or derived table ...
+*/
+
+ if (thd->lex.describe)
+ {
+ for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
+ {
+ JOIN *join= new JOIN(thd, sl->item_list,
+ sl->options | thd->options | SELECT_NO_UNLOCK,
+ union_result);
+ 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= join->prepare(&sl->ref_pointer_array,
+ (TABLE_LIST*) sl->table_list.first, sl->with_wild,
+ sl->where,
+ ((sl->braces) ? sl->order_list.elements : 0) +
+ sl->group_list.elements,
+ (sl->braces) ?
+ (ORDER *)sl->order_list.first : (ORDER *) 0,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (ORDER*) NULL,
+ sl, this, t_and_f);
+ t_and_f= 0;
+ if (res | thd->is_fatal_error)
+ goto err;
+ }
+ }
+
+ item_list.empty();
+ thd->lex.current_select= lex_select_save;
+ {
+ List_iterator<Item> it(select_cursor->item_list);
+ Field **field;
+
+ for (field= table->field; *field; field++)
+ {
+ (void) it++;
+ if (item_list.push_back(new Item_field(*field)))
+ DBUG_RETURN(-1);
+ }
+ }
+
+ DBUG_RETURN(res | thd->is_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;
+ SELECT_LEX *select_cursor=first_select_in_union(), *last_select;
+ LINT_INIT(last_select);
+
+ if (executed && !(dependent || uncacheable))
+ DBUG_RETURN(0);
+ executed= 1;
+
+ if ((dependent||uncacheable) || !item || !item->assigned())
+ {
+ if (optimized && item && item->assigned())
+ {
+ item->assigned(0); // We will reinit & rexecute unit
+ item->reset();
+ table->file->delete_all_rows();
+ }
+ for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
+ {
+ last_select=sl;
+ if (optimized)
+ res= sl->join->reinit();
+ else
+ {
+ JOIN *join= new JOIN(thd, sl->item_list,
+ sl->options | thd->options | SELECT_NO_UNLOCK,
+ union_result);
+ 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= join->prepare(&sl->ref_pointer_array,
+ (TABLE_LIST*) sl->table_list.first, sl->with_wild,
+ sl->where,
+ ((sl->braces) ? sl->order_list.elements : 0) +
+ sl->group_list.elements,
+ (sl->braces) ?
+ (ORDER *)sl->order_list.first : (ORDER *) 0,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (ORDER*) NULL,
+ sl, this, t_and_f);
+ t_and_f=0;
+ if (res | thd->is_fatal_error)
+ {
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(res);
+ }
+ res= sl->join->optimize();
+ }
+ if (!res)
+ {
+ sl->join->exec();
+ res= sl->join->error;
+ if (!res && union_result->flush())
+ {
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(1);
+ }
+ }
+ if (res)
+ {
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(res);
+ }
+ }
+ }
+ optimized= 1;
+
+ /* Send result to 'result' */
+
+ // to correct ORDER BY reference resolving
+ thd->lex.current_select = select_cursor;
+ res =-1;
+ {
+ List<Item_func_match> empty_list;
+ empty_list.empty();
+ thd->lex.select_lex.ftfunc_list= &empty_list;
+
+ if (!thd->is_fatal_error) // Check if EOM
+ {
+ SELECT_LEX *fake_select = new SELECT_LEX();
+ fake_select->make_empty_select(last_select);
+ offset_limit_cnt= (select_cursor->braces) ? global_parameters->offset_limit : 0;
+ select_limit_cnt= (select_cursor->braces) ? global_parameters->select_limit+
+ global_parameters->offset_limit : HA_POS_ERROR;
+ 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, &ref_pointer_array, &result_table_list,
+ 0, item_list, NULL,
+ global_parameters->order_list.elements,
+ (ORDER*)global_parameters->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ thd->options, result, this, fake_select, 0);
+ if (found_rows_for_union && !res)
+ thd->limit_found_rows = (ulonglong)table->file->records;
+ fake_select->exclude();
+ delete fake_select;
+ }
+ }
+ thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc;
+ thd->lex.current_select= lex_select_save;
+ DBUG_RETURN(res);
+}
+
+int st_select_lex_unit::cleanup()
+{
+ int error= 0;
+ DBUG_ENTER("st_select_lex_unit::cleanup");
+
+ if (union_result)
+ {
+ delete union_result;
+ if (table)
+ free_tmp_table(thd, table);
+ table= 0; // Safety
+ }
+ for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
+ {
+ JOIN *join;
+ if ((join= sl->join))
+ {
+ error|= sl->join->cleanup(thd);
+ delete join;
+ }
+ }
+ DBUG_RETURN(error);
+}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 709f88726de..e5c9d160725 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -52,7 +52,7 @@ int mysql_update(THD *thd,
List<Item> &fields,
List<Item> &values,
COND *conds,
- ORDER *order,
+ uint order_num, ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates)
{
@@ -66,12 +66,17 @@ int mysql_update(THD *thd,
TABLE *table;
SQL_SELECT *select;
READ_RECORD info;
+ TABLE_LIST *update_table_list= (TABLE_LIST*)
+ thd->lex.select_lex.table_list.first;
DBUG_ENTER("mysql_update");
LINT_INIT(used_index);
LINT_INIT(timestamp_query_id);
- if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
- DBUG_RETURN(-1); /* purecov: inspected */
+ if ((open_and_lock_tables(thd, table_list)))
+ DBUG_RETURN(-1);
+ fix_tables_pointers(thd->lex.all_selects_list);
+ table= table_list->table;
+
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
thd->proc_info="init";
@@ -80,9 +85,17 @@ int mysql_update(THD *thd,
table->quick_keys=0;
want_privilege=table->grant.want_privilege;
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
- if (setup_tables(table_list) || setup_conds(thd,table_list,&conds)
- || setup_ftfuncs(thd))
+ if (setup_tables(update_table_list) ||
+ setup_conds(thd,update_table_list,&conds)
+ || setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(-1); /* purecov: inspected */
+ if (find_real_table_in_list(table_list->next,
+ table_list->db, table_list->real_name))
+ {
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
+ DBUG_RETURN(-1);
+ }
+
old_used_keys=table->used_keys; // Keys used in WHERE
/*
@@ -98,7 +111,7 @@ int mysql_update(THD *thd,
/* Check the fields we are going to modify */
table->grant.want_privilege=want_privilege;
- if (setup_fields(thd,table_list,fields,1,0,0))
+ if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0))
DBUG_RETURN(-1); /* purecov: inspected */
if (table->timestamp_field)
{
@@ -111,8 +124,9 @@ int mysql_update(THD *thd,
/* Check values */
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
- if (setup_fields(thd,table_list,values,0,0,0))
+ if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0))
{
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1); /* purecov: inspected */
}
@@ -123,11 +137,12 @@ int mysql_update(THD *thd,
(select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
if (error)
{
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 */
@@ -137,11 +152,12 @@ int mysql_update(THD *thd,
if (safe_update && !using_limit)
{
delete select;
- send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
+ free_underlaid_joins(thd, &thd->lex.select_lex);
+ 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() &&
@@ -164,6 +180,7 @@ int mysql_update(THD *thd,
DISK_BUFFER_SIZE, MYF(MY_WME)))
{
delete select; /* purecov: inspected */
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
if (old_used_keys & ((key_map) 1 << used_index))
@@ -186,14 +203,18 @@ int mysql_update(THD *thd,
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (setup_order(thd, &tables, fields, all_fields, order) ||
+ if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
+ order_num)||
+ setup_order(thd, thd->lex.select_lex.ref_pointer_array,
+ &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)
{
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
}
@@ -222,6 +243,7 @@ int mysql_update(THD *thd,
}
}
end_read_record(&info);
+
if (table->key_read)
{
table->key_read=0;
@@ -247,6 +269,7 @@ int mysql_update(THD *thd,
if (error >= 0)
{
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
}
@@ -266,7 +289,7 @@ int mysql_update(THD *thd,
if (!(select && select->skipp_record()))
{
store_record(table,1);
- if (fill_record(fields,values))
+ if (fill_record(fields,values) || thd->net.report_error)
break; /* purecov: inspected */
found++;
if (compare_record(table, query_id))
@@ -332,20 +355,22 @@ int mysql_update(THD *thd,
}
delete select;
+ free_underlaid_joins(thd, &thd->lex.select_lex);
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));
}
thd->count_cuted_fields=0; /* calc cuted fields */
free_io_cache(table);
+
DBUG_RETURN(0);
}
@@ -364,7 +389,8 @@ int mysql_multi_update(THD *thd,
List<Item> *values,
COND *conds,
ulong options,
- enum enum_duplicates handle_duplicates)
+ enum enum_duplicates handle_duplicates,
+ SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex)
{
int res;
multi_update *result;
@@ -376,7 +402,7 @@ int mysql_multi_update(THD *thd,
DBUG_RETURN(res);
thd->select_limit=HA_POS_ERROR;
- if (setup_fields(thd, table_list, *fields, 1, 0, 0))
+ if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
DBUG_RETURN(-1);
/*
@@ -399,11 +425,12 @@ int mysql_multi_update(THD *thd,
DBUG_RETURN(-1);
List<Item> total_list;
- res= mysql_select(thd,table_list,total_list,
- conds, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
+ res= mysql_select(thd, &select_lex->ref_pointer_array,
+ table_list, select_lex->with_wild, total_list,
+ conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
(ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
- result);
+ result, unit, select_lex, 0);
delete result;
DBUG_RETURN(res);
}
@@ -423,7 +450,7 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *table_list,
Connect fields with tables and create list of tables that are updated
*/
-int multi_update::prepare(List<Item> &not_used_values)
+int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
{
TABLE_LIST *table_ref;
SQL_LIST update;
@@ -453,7 +480,7 @@ int multi_update::prepare(List<Item> &not_used_values)
reference tables
*/
- if (setup_fields(thd, all_tables, *values, 1,0,0))
+ if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0))
DBUG_RETURN(1);
/*
@@ -489,14 +516,14 @@ int multi_update::prepare(List<Item> &not_used_values)
table_count);
values_for_table= (List_item **) thd->alloc(sizeof(List_item *) *
table_count);
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(1);
for (i=0 ; i < table_count ; i++)
{
fields_for_table[i]= new List_item;
values_for_table[i]= new List_item;
}
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(1);
/* Split fields into fields_for_table[] and values_by_table[] */
@@ -509,7 +536,7 @@ int multi_update::prepare(List<Item> &not_used_values)
fields_for_table[offset]->push_back(item);
values_for_table[offset]->push_back(value);
}
- if (thd->fatal_error)
+ if (thd->is_fatal_error)
DBUG_RETURN(1);
/* Allocate copy fields */
@@ -517,7 +544,7 @@ int multi_update::prepare(List<Item> &not_used_values)
for (i=0 ; i < table_count ; i++)
set_if_bigger(max_fields, fields_for_table[i]->elements);
copy_field= new Copy_field[max_fields];
- DBUG_RETURN(thd->fatal_error != 0);
+ DBUG_RETURN(thd->is_fatal_error != 0);
}
@@ -570,7 +597,7 @@ multi_update::initialize_tables(JOIN *join)
/* ok to be on stack as this is not referenced outside of this func */
Field_string offset(table->file->ref_length, 0, "offset",
- table, 1);
+ table, 1, &my_charset_bin);
if (temp_fields.push_front(new Item_field(((Field *) &offset))))
DBUG_RETURN(1);
@@ -586,8 +613,9 @@ multi_update::initialize_tables(JOIN *join)
if (!(tmp_tables[cnt]=create_tmp_table(thd,
tmp_param,
temp_fields,
- (ORDER*) &group, 0, 0, 0,
- TMP_TABLE_ALL_COLUMNS)))
+ (ORDER*) &group, 0, 0,
+ TMP_TABLE_ALL_COLUMNS,
+ HA_POS_ERROR)))
DBUG_RETURN(1);
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
}
@@ -648,7 +676,6 @@ static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields)
}
-
multi_update::~multi_update()
{
TABLE_LIST *table;
@@ -741,7 +768,8 @@ bool multi_update::send_data(List<Item> &not_used_values)
(error != HA_ERR_FOUND_DUPP_KEY &&
error != HA_ERR_FOUND_DUPP_UNIQUE))
{
- if (create_myisam_from_heap(table, tmp_table_param + offset, error, 1))
+ if (create_myisam_from_heap(thd, table, tmp_table_param + offset,
+ error, 1))
{
do_update=0;
DBUG_RETURN(1); // Not a table_is_full error
@@ -756,7 +784,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
void multi_update::send_error(uint errcode,const char *err)
{
/* First send error what ever it is ... */
- ::send_error(&thd->net,errcode,err);
+ ::send_error(thd,errcode,err);
/* If nothing updated return */
if (!updated)
@@ -927,7 +955,7 @@ bool multi_update::send_eof()
/* Safety: If we haven't got an error before (should not happen) */
my_message(ER_UNKNOWN_ERROR, "An error occured in multi-table update",
MYF(0));
- ::send_error(&thd->net);
+ ::send_error(thd);
return 1;
}
@@ -938,7 +966,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);
return 0;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index b986b72df32..e66e896c590 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -17,26 +17,35 @@
/* sql_yacc.yy */
%{
+/* thd is passed as an arg to yyparse(), and subsequently to yylex().
+** The type will be void*, so it must be cast to (THD*) when used.
+** Use the YYTHD macro for this.
+*/
+#define YYPARSE_PARAM yythd
+#define YYLEX_PARAM yythd
+#define YYTHD ((THD *)yythd)
+
#define MYSQL_YACC
#define YYINITDEPTH 100
#define YYMAXDEPTH 3200 /* Because of 64K stack */
-#define Lex current_lex
-#define Select Lex->select
+#define Lex (&(YYTHD->lex))
+#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>
extern void yyerror(const char*);
-int yylex(void *yylval);
+int yylex(void *yylval, void *yythd);
#define yyoverflow(A,B,C,D,E,F) if (my_yyoverflow((B),(D),(int*) (F))) { yyerror((char*) (A)); return 2; }
-inline Item *or_or_concat(Item* A, Item* B)
+inline Item *or_or_concat(THD *thd, Item* A, Item* B)
{
- return (current_thd->sql_mode & MODE_PIPES_AS_CONCAT ?
+ return (thd->variables.sql_mode & MODE_PIPES_AS_CONCAT ?
(Item*) new Item_func_concat(A,B) : (Item*) new Item_cond_or(A,B));
}
@@ -60,14 +69,18 @@ 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;
+ st_select_lex *select_lex;
+ chooser_compare_func_creator boolfunc2creator;
}
%{
@@ -84,14 +97,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NEXT_SYM
%token PREV_SYM
+%token DIV_SYM
%token EQ
%token EQUAL_SYM
+%token SOUNDS_SYM
%token GE
%token GT_SYM
%token LE
%token LT
%token NE
%token IS
+%token MOD_SYM
%token SHIFT_LEFT
%token SHIFT_RIGHT
%token SET_VAR
@@ -101,6 +117,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token AFTER_SYM
%token ALTER
%token ANALYZE_SYM
+%token ANY_SYM
%token AVG_SYM
%token BEGIN_SYM
%token BINLOG_SYM
@@ -113,11 +130,13 @@ 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
%token EXECUTE_SYM
%token FLUSH_SYM
+%token HELP_SYM
%token INSERT
%token IO_THREAD
%token KILL_SYM
@@ -141,6 +160,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SQL_THREAD
%token START_SYM
%token STD_SYM
+%token VARIANCE_SYM
%token STOP_SYM
%token SUM_SYM
%token SUPER_SYM
@@ -163,7 +183,9 @@ 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
@@ -171,6 +193,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token CHECKSUM_SYM
%token CHECK_SYM
%token COMMITTED_SYM
+%token COLLATE_SYM
+%token COLLATION_SYM
%token COLUMNS
%token COLUMN_SYM
%token CONCURRENT
@@ -186,6 +210,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token DES_KEY_FILE
%token DISABLE_SYM
%token DISTINCT
+%token DUPLICATE_SYM
%token DYNAMIC_SYM
%token ENABLE_SYM
%token ENCLOSED
@@ -194,6 +219,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
@@ -209,6 +235,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
@@ -259,6 +286,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MEMORY_SYM
%token MIN_ROWS
%token MYISAM_SYM
+%token NAMES_SYM
%token NATIONAL_SYM
%token NATURAL
%token NEW_SYM
@@ -305,11 +333,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
@@ -322,7 +354,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
@@ -331,21 +365,28 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token UDF_SONAME_SYM
%token UDF_SYM
%token UNCOMMITTED_SYM
+%token UNDERSCORE_CHARSET
+%token UNICODE_SYM
%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 ASCII_SYM
%token BIGINT
%token BLOB_SYM
%token CHAR_SYM
@@ -358,6 +399,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
@@ -415,6 +457,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
@@ -425,6 +470,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 MASTER_POS_WAIT
@@ -433,8 +480,18 @@ 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 POINT_SYM
+%token POLYFROMTEXT
+%token POLYGON
%token POSITION_SYM
%token PROCEDURE
%token RAND
@@ -476,6 +533,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SUBJECT_SYM
%token CIPHER_SYM
+%token HELP
+%token BEFORE_SYM
%left SET_VAR
%left OR_OR_CONCAT OR
%left AND
@@ -485,13 +544,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 ','
@@ -501,25 +559,26 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_str>
IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME
ULONGLONG_NUM field_ident select_alias ident ident_or_text
+ UNDERSCORE_CHARSET
%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>
- text_string
+ text_string
%type <num>
type int_type real_type order_dir opt_field_spec lock_option
udf_type if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_var_type opt_var_ident_type
- opt_temporary
+ delete_option opt_temporary all_or_any
%type <ulong_num>
ULONG_NUM raid_types merge_insert_types
@@ -534,7 +593,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
literal text_literal insert_ident order_ident
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
+ using_list expr_or_default set_expr_or_default interval_expr
+ param_marker singlerow_subselect singlerow_subselect_init
+ exists_subselect exists_subselect_init
%type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg
@@ -542,6 +603,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
@@ -549,7 +613,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
@@ -573,8 +637,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <lex_user> user grant_user
+%type <charset>
+ opt_collate
+ charset_name
+ charset_name_or_default
+ collation_name
+ collation_name_or_default
+
%type <variable> internal_variable_name
+%type <select_lex> in_subselect in_subselect_init
+
+%type <boolfunc2creator> comp_op
+
%type <NONE>
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
@@ -583,13 +658,13 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
repair restore backup analyze check start
field_list field_list_item field_spec kill column_def key_def
select_item_list select_item values_list no_braces
- limit_clause delete_limit_clause fields opt_values values
+ opt_limit_clause delete_limit_clause fields opt_values values
procedure_list procedure_list2 procedure_item
when_list2 expr_list2 handler
opt_precision opt_ignore opt_column opt_restrict
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
@@ -600,26 +675,29 @@ 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_clause union_list union_option
+ precision subselect_start opt_and charset
+ subselect_end select_var_list select_var_list_init help opt_len
END_OF_INPUT
%type <NONE>
'-' '+' '*' '/' '%' '(' ')'
- ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM THEN_SYM WHEN_SYM
+ ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM
+ THEN_SYM WHEN_SYM DIV_SYM MOD_SYM
%%
query:
END_OF_INPUT
{
- THD *thd=current_thd;
+ THD *thd= YYTHD;
if (!thd->bootstrap &&
(!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT)))
{
- send_error(&current_thd->net,ER_EMPTY_QUERY);
+ send_error(thd,ER_EMPTY_QUERY);
YYABORT;
- }
+ }
else
{
thd->lex.sql_command = SQLCOM_EMPTY_QUERY;
@@ -647,7 +725,7 @@ verb_clause:
| lock
| kill
| optimize
- | purge
+ | purge
| rename
| repair
| replace
@@ -664,7 +742,18 @@ verb_clause:
| handler
| unlock
| update
- | use;
+ | use
+ | help;
+
+/* help */
+
+help:
+ HELP_SYM ident_or_text
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_HELP;
+ lex->help_arg= $2.str;
+ };
/* change master */
@@ -727,7 +816,8 @@ master_def:
RELAY_LOG_POS_SYM EQ ULONG_NUM
{
Lex->mi.relay_log_pos = $3;
- };
+ }
+ ;
/* create a table */
@@ -735,12 +825,18 @@ master_def:
create:
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident
{
+ THD *thd= YYTHD;
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),
- TL_OPTION_UPDATING))
+ if (!lex->select_lex.add_table_to_list(thd,$5,
+ ($2 &
+ HA_LEX_CREATE_TMP_TABLE ?
+ &tmp_table_alias :
+ (LEX_STRING*) 0),
+ TL_OPTION_UPDATING,
+ ((using_update_log)?
+ TL_READ_NO_INSERT:
+ TL_READ)))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
@@ -749,39 +845,44 @@ 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;
+ lex->name=0;
}
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, TL_OPTION_UPDATING))
+ if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL,
+ TL_OPTION_UPDATING))
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
+ { Lex->create_info.table_charset=NULL; }
+ opt_create_database_options
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CREATE_DB;
lex->name=$4.str;
lex->create_info.options=$3;
}
- | CREATE udf_func_type UDF_SYM ident
+ | CREATE udf_func_type UDF_SYM IDENT
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_CREATE_FUNCTION;
- lex->udf.name=$4.str;
- lex->udf.name_length=$4.length;
+ lex->udf.name = $4;
lex->udf.type= $2;
}
UDF_RETURNS_SYM udf_type UDF_SONAME_SYM TEXT_STRING
@@ -789,11 +890,19 @@ 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 {}
+ | LIKE table_ident
+ {
+ LEX *lex=Lex;
+ if (!(lex->name= (char *)$2))
+ YYABORT;
+ }
+ ;
create3:
/* empty */ {}
@@ -803,12 +912,28 @@ 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_clause {}
+ ;
opt_as:
/* empty */ {}
| AS {};
+opt_create_database_options:
+ /* empty */ {}
+ | create_database_options {};
+
+create_database_options:
+ create_database_option {}
+ | create_database_options create_database_option {};
+
+create_database_option:
+ COLLATE_SYM collation_name_or_default
+ { Lex->create_info.table_charset=$2; }
+ | opt_default charset charset_name_or_default
+ { Lex->create_info.table_charset=$3; }
+ ;
+
opt_table_options:
/* empty */ { $$= 0; }
| table_options { $$= $1;};
@@ -828,44 +953,57 @@ 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;
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 opt_equal table_types { Lex->create_info.db_type= $3; }
+ | MAX_ROWS opt_equal ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;}
+ | MIN_ROWS opt_equal ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;}
+ | AVG_ROW_LENGTH opt_equal ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;}
+ | PASSWORD opt_equal TEXT_STRING { Lex->create_info.password=$3.str; }
+ | COMMENT_SYM opt_equal TEXT_STRING { Lex->create_info.comment=$3.str; }
+ | AUTO_INC opt_equal ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;}
+ | PACK_KEYS_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
+ | PACK_KEYS_SYM opt_equal DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;}
+ | CHECKSUM_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; }
+ | DELAY_KEY_WRITE_SYM opt_equal ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; }
+ | ROW_FORMAT_SYM opt_equal row_types { Lex->create_info.row_type= $3; }
+ | RAID_TYPE opt_equal raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKS opt_equal ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | RAID_CHUNKSIZE opt_equal ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;}
+ | UNION_SYM opt_equal '(' table_list ')'
{
/* Move the union list to the merge_list */
LEX *lex=Lex;
- 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;
}
- | CHARSET opt_equal ident {}
- | CHAR_SYM SET opt_equal ident {}
- | 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 opt_equal charset_name_or_default
+ {
+ Lex->create_info.table_charset= $4;
+ Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET;
+ }
+ | COLLATE_SYM opt_equal collation_name_or_default
+ {
+ Lex->create_info.table_charset= $3;
+ Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET;
+ }
+ | INSERT_METHOD opt_equal merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;}
+ | DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING { Lex->create_info.data_file_name= $4.str; }
+ | INDEX DIRECTORY_SYM opt_equal TEXT_STRING { Lex->create_info.index_file_name= $4.str; };
table_types:
ISAM_SYM { $$= DB_TYPE_ISAM; }
@@ -893,7 +1031,8 @@ merge_insert_types:
| LAST_SYM { $$= MERGE_INSERT_TO_LAST; };
opt_select_from:
- /* empty */
+ opt_limit_clause {}
+ | FROM DUAL_SYM {}
| select_from select_lock_type;
udf_func_type:
@@ -911,7 +1050,7 @@ field_list:
field_list_item:
- column_def
+ column_def
| key_def
;
@@ -921,18 +1060,25 @@ column_def:
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
}
- ;
+ ;
key_def:
- 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_constraint
{
@@ -954,77 +1100,112 @@ 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
{
LEX *lex=Lex;
- if (add_field_to_list($1.str,
+ if (add_field_to_list(lex->thd, $1.str,
(enum enum_field_types) $3,
lex->length,lex->dec,lex->type,
- lex->default_value,lex->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;
+ | BOOLEAN_SYM { Lex->length=(char*) "1";
+ $$=FIELD_TYPE_TINY; }
+ | 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;
+ | BINARY '(' NUM ')' { Lex->length=$3.str;
+ 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 (YYTHD->variables.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; }
+ | GEOMETRYCOLLECTION { Lex->charset=&my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | POINT_SYM { Lex->charset=&my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | MULTIPOINT { Lex->charset=&my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | LINESTRING { Lex->charset=&my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | MULTILINESTRING { Lex->charset=&my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | POLYGON { Lex->charset=&my_charset_bin;
+ $$=FIELD_TYPE_GEOMETRY; }
+ | MULTIPOLYGON { 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; }
+ | SERIAL_SYM
+ {
+ $$=FIELD_TYPE_LONGLONG;
+ Lex->type|= (AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNSIGNED_FLAG |
+ UNIQUE_FLAG);
+ }
+ ;
char:
CHAR_SYM {}
@@ -1045,7 +1226,7 @@ int_type:
| BIGINT { $$=FIELD_TYPE_LONGLONG; };
real_type:
- REAL { $$= current_thd->sql_mode & MODE_REAL_AS_FLOAT ?
+ REAL { $$= YYTHD->variables.sql_mode & MODE_REAL_AS_FLOAT ?
FIELD_TYPE_FLOAT : FIELD_TYPE_DOUBLE; }
| DOUBLE_SYM { $$=FIELD_TYPE_DOUBLE; }
| DOUBLE_SYM PRECISION { $$=FIELD_TYPE_DOUBLE; };
@@ -1077,8 +1258,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 */ {}
@@ -1097,23 +1278,109 @@ attribute:
| NOT NULL_SYM { Lex->type|= NOT_NULL_FLAG; }
| DEFAULT literal { Lex->default_value=$2; }
| AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; }
- | PRIMARY_SYM KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; }
+ | SERIAL_SYM DEFAULT VALUE_SYM
+ { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG | UNIQUE_FLAG; }
+ | opt_primary KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; }
| UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; }
| UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; }
- | COMMENT_SYM text_literal {};
+ | COMMENT_SYM text_literal { Lex->comment= $2; }
+ | COLLATE_SYM collation_name
+ {
+ if (Lex->charset && !my_charset_same(Lex->charset,$2))
+ {
+ net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
+ $2->name,Lex->charset->csname);
+ YYABORT;
+ }
+ else
+ {
+ Lex->charset=$2;
+ }
+ }
+ ;
-opt_binary:
+charset:
+ CHAR_SYM SET {}
+ | CHARSET {}
+ ;
+
+charset_name:
+ ident_or_text
+ {
+ if (!($$=get_charset_by_csname($1.str,MY_CS_PRIMARY,MYF(0))))
+ {
+ net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ YYABORT;
+ }
+ };
+
+charset_name_or_default:
+ charset_name { $$=$1; }
+ | DEFAULT { $$=NULL; } ;
+
+collation_name:
+ ident_or_text
+ {
+ if (!($$=get_charset_by_name($1.str,MYF(0))))
+ {
+ net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ YYABORT;
+ }
+ };
+
+opt_collate:
+ /* empty */ { $$=NULL; }
+ | COLLATE_SYM collation_name { $$=$2; }
+ ;
+
+collation_name_or_default:
+ collation_name { $$=$1; }
+ | DEFAULT { $$=NULL; } ;
+
+opt_default:
/* empty */ {}
- | BINARY { Lex->type|=BINARY_FLAG; }
- | CHAR_SYM SET opt_equal ident {}
+ | DEFAULT {};
+
+opt_binary:
+ /* empty */ { Lex->charset=NULL; }
+ | ASCII_SYM { Lex->charset=&my_charset_latin1; }
+ | BYTE_SYM { Lex->charset=&my_charset_bin; }
+ | BINARY { Lex->charset=&my_charset_bin; }
+ | UNICODE_SYM
+ {
+ if (!(Lex->charset=get_charset_by_name("ucs2",MYF(0))))
+ {
+ net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"ucs2");
+ YYABORT;
+ }
+ }
+ | charset charset_name { Lex->charset=$2; } ;
+
+opt_primary:
+ /* empty */
+ | PRIMARY_SYM
;
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 */ {}
@@ -1123,25 +1390,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; };
@@ -1157,7 +1426,17 @@ 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; }
+ | TYPE_SYM 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); }
@@ -1182,10 +1461,12 @@ string_list:
alter:
ALTER opt_ignore TABLE_SYM table_ident
{
- LEX *lex=Lex;
+ THD *thd= YYTHD;
+ LEX *lex=&thd->lex;
lex->sql_command = SQLCOM_ALTER_TABLE;
lex->name=0;
- if (!add_table_to_list($4, NULL, TL_OPTION_UPDATING))
+ if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
+ TL_OPTION_UPDATING))
YYABORT;
lex->drop_primary=0;
lex->create_list.empty();
@@ -1193,20 +1474,25 @@ 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;
- bzero((char*) &lex->create_info,sizeof(lex->create_info));
+ 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;
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_create_database_options
+ {
+ LEX *lex=Lex;
+ lex->sql_command=SQLCOM_ALTER_DB;
+ lex->name=$3.str;
+ };
+
+
alter_list:
| alter_list_item
| alter_list ',' alter_list_item;
@@ -1224,24 +1510,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(lex->thd,$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;
@@ -1276,12 +1562,12 @@ alter_list_item:
lex->simple_alter=0;
}
| 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:
@@ -1309,36 +1595,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;
+ }
+ ;
start:
START_SYM TRANSACTION_SYM { Lex->sql_command = SQLCOM_BEGIN;}
@@ -1346,15 +1619,21 @@ start:
;
slave_thread_opts:
+ { Lex->slave_thd_opt= 0; }
+ slave_thread_opt_list
+ ;
+
+slave_thread_opt_list:
slave_thread_opt
- | slave_thread_opts ',' slave_thread_opt;
+ | slave_thread_opt_list ',' slave_thread_opt
+ ;
slave_thread_opt:
- /*empty*/ {}
+ /*empty*/ {}
| SQL_THREAD { Lex->slave_thd_opt|=SLAVE_SQL; }
| IO_THREAD { Lex->slave_thd_opt|=SLAVE_IO; }
;
-
+
restore:
RESTORE_SYM table_or_tables
{
@@ -1463,10 +1742,14 @@ table_to_table_list:
table_to_table:
table_ident TO_SYM table_ident
{
- if (!add_table_to_list($1, NULL, TL_OPTION_UPDATING, TL_IGNORE) ||
- !add_table_to_list($3, NULL, TL_OPTION_UPDATING, TL_IGNORE))
- YYABORT;
- };
+ LEX *lex=Lex;
+ SELECT_LEX_NODE *sl= lex->current_select;
+ if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
+ TL_IGNORE) ||
+ !sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING,
+ TL_IGNORE))
+ YYABORT;
+ };
/*
Select : retrieve data from table
@@ -1476,29 +1759,74 @@ table_to_table:
select:
select_init { Lex->sql_command=SQLCOM_SELECT; };
+/* Need select_init2 for subselects. */
select_init:
- SELECT_SYM select_part2 { Select->braces= 0; } opt_union
+ SELECT_SYM select_init2
|
- '(' SELECT_SYM select_part2 ')' { Select->braces= 1;} union_opt;
+ '(' SELECT_SYM select_part2 ')'
+ {
+ LEX *lex= Lex;
+ SELECT_LEX * sel= lex->current_select->select_lex();
+ if (sel->set_braces(1))
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ if (sel->linkage == UNION_TYPE &&
+ !sel->master_unit()->first_select()->braces)
+ {
+ 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_init2:
+ select_part2
+ {
+ LEX *lex= Lex;
+ SELECT_LEX * sel= lex->current_select->select_lex();
+ if (lex->current_select->set_braces(0))
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ if (sel->linkage == UNION_TYPE &&
+ sel->master_unit()->first_select()->braces)
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ }
+ union_clause
+ ;
select_part2:
{
LEX *lex=Lex;
- lex->lock_option=TL_READ;
- mysql_init_select(lex);
+ SELECT_LEX * sel= lex->current_select->select_lex();
+ if (lex->current_select == &lex->select_lex)
+ lex->lock_option= TL_READ; /* Only for global SELECT */
+ if (sel->linkage != UNION_TYPE)
+ mysql_init_select(lex);
}
select_options select_item_list select_into select_lock_type;
select_into:
- limit_clause {}
+ opt_limit_clause {}
+ | FROM DUAL_SYM /* oracle compatibility: oracle always requires FROM
+ clause, and DUAL is system table without fields.
+ Is "SELECT 1 FROM DUAL" any better than
+ "SELECT 1" ? Hmmm :) */
+ | into
| select_from
- | opt_into select_from
- | select_from opt_into;
+ | into select_from
+ | select_from into;
select_from:
- FROM join_table_list where_clause group_clause having_clause opt_order_clause limit_clause procedure_clause;
-
+ FROM join_table_list where_clause group_clause having_clause opt_order_clause opt_limit_clause procedure_clause;
select_options:
/* empty*/
@@ -1531,7 +1859,7 @@ select_option:
YYABORT;
Select->options|= OPTION_FOUND_ROWS;
}
- | SQL_NO_CACHE_SYM { current_thd->safe_to_cache_query=0; }
+ | SQL_NO_CACHE_SYM { Lex->uncacheable(); }
| SQL_CACHE_SYM { Select->options|= OPTION_TO_QUERY_CACHE; }
| ALL {}
;
@@ -1541,18 +1869,15 @@ select_lock_type:
| FOR_SYM UPDATE_SYM
{
LEX *lex=Lex;
- if (check_simple_select())
- YYABORT;
- lex->lock_option= TL_WRITE;
- lex->thd->safe_to_cache_query=0;
+ lex->current_select->set_lock_for_tables(TL_WRITE);
+ lex->safe_to_cache_query=0;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
{
LEX *lex=Lex;
- if (check_simple_select())
- YYABORT;
- lex->lock_option= TL_READ_WITH_SHARED_LOCKS;
- lex->thd->safe_to_cache_query=0;
+ lex->current_select->
+ set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
+ lex->safe_to_cache_query=0;
}
;
@@ -1561,15 +1886,17 @@ select_item_list:
| select_item
| '*'
{
- if (add_item_to_list(new Item_field(NULL,NULL,"*")))
+ THD *thd= YYTHD;
+ if (add_item_to_list(thd, new Item_field(NULL, NULL, "*")))
YYABORT;
+ (thd->lex.current_select->select_lex()->with_wild)++;
};
select_item:
remember_name select_item2 remember_end select_alias
{
- if (add_item_to_list($2))
+ if (add_item_to_list(YYTHD, $2))
YYABORT;
if ($4.str)
$2->set_name($4.str);
@@ -1599,50 +1926,83 @@ optional_braces:
| '(' ')' {};
/* all possible expressions */
-expr: expr_expr {$$ = $1; }
- | simple_expr {$$ = $1; };
+expr:
+ expr_expr { $$= $1; }
+ | simple_expr { $$= $1; }
+ ;
+
+comp_op: EQ { $$ = &comp_eq_creator; }
+ | GE { $$ = &comp_ge_creator; }
+ | GT_SYM { $$ = &comp_gt_creator; }
+ | LE { $$ = &comp_le_creator; }
+ | LT { $$ = &comp_lt_creator; }
+ | NE { $$ = &comp_ne_creator; }
+ ;
+
+all_or_any: ALL { $$ = 1; }
+ | ANY_SYM { $$ = 0; }
+ ;
/* expressions that begin with 'expr' */
expr_expr:
- expr IN_SYM '(' expr_list ')'
+ expr IN_SYM '(' expr_list ')'
{ $$= new Item_func_in($1,*$4); }
| expr NOT IN_SYM '(' expr_list ')'
{ $$= new Item_func_not(new Item_func_in($1,*$5)); }
+ | expr IN_SYM in_subselect
+ { $$= new Item_in_subselect(YYTHD, $1, $3); }
+ | expr NOT IN_SYM in_subselect
+ {
+ $$= new Item_func_not(new Item_in_subselect(YYTHD, $1, $4));
+ }
| expr BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_between($1,$3,$5); }
| expr NOT BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
| expr OR expr { $$= new Item_cond_or($1,$3); }
| expr XOR expr { $$= new Item_cond_xor($1,$3); }
| expr AND expr { $$= new Item_cond_and($1,$3); }
+ | expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));}
| expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
| expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5));}
| expr REGEXP expr { $$= new Item_func_regex($1,$3); }
| expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
| expr IS NULL_SYM { $$= new Item_func_isnull($1); }
| expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | expr EQ expr { $$= new Item_func_eq($1,$3); }
| expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | expr GE expr { $$= new Item_func_ge($1,$3); }
- | expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
- | expr LE expr { $$= new Item_func_le($1,$3); }
- | expr LT expr { $$= new Item_func_lt($1,$3); }
- | expr NE expr { $$= new Item_func_ne($1,$3); }
+ | expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); }
+ | expr comp_op all_or_any in_subselect %prec EQ
+ {
+ Item_allany_subselect *it=
+ new Item_allany_subselect(YYTHD, $1, (*$2)($3), $4);
+ if ($3)
+ $$ = new Item_func_not(it); /* ALL */
+ else
+ $$ = it; /* ANY/SOME */
+ }
| expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
| expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
| expr '+' expr { $$= new Item_func_plus($1,$3); }
| expr '-' expr { $$= new Item_func_minus($1,$3); }
| expr '*' expr { $$= new Item_func_mul($1,$3); }
| expr '/' expr { $$= new Item_func_div($1,$3); }
+ | expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
+ | expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
| expr '|' expr { $$= new Item_func_bit_or($1,$3); }
- | expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
+ | expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
| expr '&' expr { $$= new Item_func_bit_and($1,$3); }
| expr '%' expr { $$= new Item_func_mod($1,$3); }
- | expr '+' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,0); }
- | expr '-' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,1); };
+ | expr '+' interval_expr interval
+ { $$= new Item_date_add_interval($1,$3,$4,0); }
+ | expr '-' interval_expr interval
+ { $$= new Item_date_add_interval($1,$3,$4,1); }
+ | expr COLLATE_SYM ident_or_text
+ {
+ $$= new Item_func_set_collation($1,new Item_string($3.str,$3.length,
+ YYTHD->variables.thd_charset));
+ }
+ ;
/* expressions that begin with 'expr' that do NOT follow IN_SYM */
no_in_expr:
@@ -1650,93 +2010,118 @@ no_in_expr:
{ $$= new Item_func_between($1,$3,$5); }
| no_in_expr NOT BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
| no_in_expr OR expr { $$= new Item_cond_or($1,$3); }
| no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); }
| no_in_expr AND expr { $$= new Item_cond_and($1,$3); }
+ | no_in_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));}
| no_in_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
| no_in_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
| no_in_expr REGEXP expr { $$= new Item_func_regex($1,$3); }
| no_in_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
| no_in_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
| no_in_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | no_in_expr EQ expr { $$= new Item_func_eq($1,$3); }
| no_in_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | no_in_expr GE expr { $$= new Item_func_ge($1,$3); }
- | no_in_expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
- | no_in_expr LE expr { $$= new Item_func_le($1,$3); }
- | no_in_expr LT expr { $$= new Item_func_lt($1,$3); }
- | no_in_expr NE expr { $$= new Item_func_ne($1,$3); }
+ | no_in_expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); }
+ | no_in_expr comp_op all_or_any in_subselect %prec EQ
+ {
+ Item_allany_subselect *it=
+ new Item_allany_subselect(YYTHD, $1, (*$2)($3), $4);
+ if ($3)
+ $$ = new Item_func_not(it); /* ALL */
+ else
+ $$ = it; /* ANY/SOME */
+ }
| no_in_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
| no_in_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
| no_in_expr '+' expr { $$= new Item_func_plus($1,$3); }
| no_in_expr '-' expr { $$= new Item_func_minus($1,$3); }
| no_in_expr '*' expr { $$= new Item_func_mul($1,$3); }
| no_in_expr '/' expr { $$= new Item_func_div($1,$3); }
+ | no_in_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
| no_in_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
| no_in_expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
| no_in_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
| no_in_expr '%' expr { $$= new Item_func_mod($1,$3); }
- | no_in_expr '+' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,0); }
- | no_in_expr '-' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,1); }
+ | no_in_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
+ | no_in_expr '+' interval_expr interval
+ { $$= new Item_date_add_interval($1,$3,$4,0); }
+ | no_in_expr '-' interval_expr interval
+ { $$= new Item_date_add_interval($1,$3,$4,1); }
| simple_expr;
/* expressions that begin with 'expr' that does NOT follow AND */
no_and_expr:
- no_and_expr IN_SYM '(' expr_list ')'
- { $$= new Item_func_in($1,*$4); }
+ no_and_expr IN_SYM '(' expr_list ')'
+ { $$= new Item_func_in($1,*$4); }
| no_and_expr NOT IN_SYM '(' expr_list ')'
{ $$= new Item_func_not(new Item_func_in($1,*$5)); }
+ | no_and_expr IN_SYM in_subselect
+ { $$= new Item_in_subselect(YYTHD, $1, $3); }
+ | no_and_expr NOT IN_SYM in_subselect
+ {
+ $$= new Item_func_not(new Item_in_subselect(YYTHD, $1, $4));
+ }
| no_and_expr BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_between($1,$3,$5); }
| no_and_expr NOT BETWEEN_SYM no_and_expr AND expr
{ $$= new Item_func_not(new Item_func_between($1,$4,$6)); }
- | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat($1,$3); }
+ | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); }
| no_and_expr OR expr { $$= new Item_cond_or($1,$3); }
| no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); }
+ | no_and_expr SOUNDS_SYM LIKE expr { $$= Item_bool_func2::eq_creator(new Item_func_soundex($1), new Item_func_soundex($4));}
| no_and_expr LIKE simple_expr opt_escape { $$= new Item_func_like($1,$3,$4); }
| no_and_expr NOT LIKE simple_expr opt_escape { $$= new Item_func_not(new Item_func_like($1,$4,$5)); }
| no_and_expr REGEXP expr { $$= new Item_func_regex($1,$3); }
| no_and_expr NOT REGEXP expr { $$= new Item_func_not(new Item_func_regex($1,$4)); }
| no_and_expr IS NULL_SYM { $$= new Item_func_isnull($1); }
| no_and_expr IS NOT NULL_SYM { $$= new Item_func_isnotnull($1); }
- | no_and_expr EQ expr { $$= new Item_func_eq($1,$3); }
| no_and_expr EQUAL_SYM expr { $$= new Item_func_equal($1,$3); }
- | no_and_expr GE expr { $$= new Item_func_ge($1,$3); }
- | no_and_expr GT_SYM expr { $$= new Item_func_gt($1,$3); }
- | no_and_expr LE expr { $$= new Item_func_le($1,$3); }
- | no_and_expr LT expr { $$= new Item_func_lt($1,$3); }
- | no_and_expr NE expr { $$= new Item_func_ne($1,$3); }
+ | no_and_expr comp_op expr %prec EQ { $$= (*((*$2)(0)))($1,$3); }
+ | no_and_expr comp_op all_or_any in_subselect %prec EQ
+ {
+ Item_allany_subselect *it=
+ new Item_allany_subselect(YYTHD, $1, (*$2)($3), $4);
+ if ($3)
+ $$ = new Item_func_not(it); /* ALL */
+ else
+ $$ = it; /* ANY/SOME */
+ }
| no_and_expr SHIFT_LEFT expr { $$= new Item_func_shift_left($1,$3); }
| no_and_expr SHIFT_RIGHT expr { $$= new Item_func_shift_right($1,$3); }
| no_and_expr '+' expr { $$= new Item_func_plus($1,$3); }
| no_and_expr '-' expr { $$= new Item_func_minus($1,$3); }
| no_and_expr '*' expr { $$= new Item_func_mul($1,$3); }
| no_and_expr '/' expr { $$= new Item_func_div($1,$3); }
+ | no_and_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); }
| no_and_expr '|' expr { $$= new Item_func_bit_or($1,$3); }
| no_and_expr '^' expr { $$= new Item_func_bit_xor($1,$3); }
| no_and_expr '&' expr { $$= new Item_func_bit_and($1,$3); }
| no_and_expr '%' expr { $$= new Item_func_mod($1,$3); }
- | no_and_expr '+' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,0); }
- | no_and_expr '-' INTERVAL_SYM expr interval
- { $$= new Item_date_add_interval($1,$4,$5,1); }
+ | no_and_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); }
+ | no_and_expr '+' interval_expr interval
+ { $$= new Item_date_add_interval($1,$3,$4,0); }
+ | no_and_expr '-' interval_expr interval
+ { $$= new Item_date_add_interval($1,$3,$4,1); }
| simple_expr;
+interval_expr:
+ INTERVAL_SYM expr { $$=$2; }
+ ;
+
simple_expr:
simple_ident
| literal
+ | param_marker
| '@' ident_or_text SET_VAR expr
{
$$= new Item_func_set_user_var($2,$4);
- current_thd->safe_to_cache_query=0;
+ Lex->uncacheable();;
}
- | '@' ident_or_text
+ | '@' ident_or_text
{
$$= new Item_func_get_user_var($2);
- current_thd->safe_to_cache_query=0;
+ Lex->uncacheable();;
}
| '@' '@' opt_var_ident_type ident_or_text
{
@@ -1749,18 +2134,41 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; }
+ | '(' expr ',' expr_list ')'
+ {
+ $4->push_front($2);
+ $$= new Item_row(*$4);
+ }
+ | ROW_SYM '(' expr ',' expr_list ')'
+ {
+ $5->push_front($3);
+ $$= new Item_row(*$5);
+ }
+ | EXISTS exists_subselect { $$= $2; }
+ | singlerow_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); }
+ | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
+ | BINARY expr %prec NEG
+ {
+ $$= new Item_func_set_collation($2,new Item_string("BINARY",6,
+ &my_charset_latin1));
+ }
| 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); }
+ | DEFAULT '(' simple_ident ')'
+ { $$= new Item_default_value($3); }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
| FUNC_ARG1 '(' expr ')'
@@ -1775,29 +2183,33 @@ 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); }
+ | COLLATION_SYM '(' expr ')'
+ { $$= new Item_func_collation($3); }
| CONCAT '(' expr_list ')'
{ $$= new Item_func_concat(* $3); }
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
| CURDATE optional_braces
- { $$= new Item_func_curdate(); current_thd->safe_to_cache_query=0; }
+ { $$= new Item_func_curdate(); Lex->safe_to_cache_query=0; }
| CURTIME optional_braces
- { $$= new Item_func_curtime(); current_thd->safe_to_cache_query=0; }
+ { $$= new Item_func_curtime(); Lex->safe_to_cache_query=0; }
| CURTIME '(' expr ')'
- {
- $$= new Item_func_curtime($3);
- current_thd->safe_to_cache_query=0;
+ {
+ $$= new Item_func_curtime($3);
+ Lex->safe_to_cache_query=0;
}
- | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
- { $$= new Item_date_add_interval($3,$6,$7,0); }
- | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')'
- { $$= new Item_date_add_interval($3,$6,$7,1); }
+ | DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')'
+ { $$= new Item_date_add_interval($3,$5,$6,0); }
+ | DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')'
+ { $$= new Item_date_add_interval($3,$5,$6,1); }
| DATABASE '(' ')'
- {
+ {
$$= new Item_func_database();
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| ELT_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_elt($3, *$5); }
@@ -1806,7 +2218,7 @@ simple_expr:
| ENCRYPT '(' expr ')'
{
$$= new Item_func_encrypt($3);
- current_thd->safe_to_cache_query=0;
+ Lex->uncacheable();;
}
| ENCRYPT '(' expr ',' expr ')' { $$= new Item_func_encrypt($3,$5); }
| DECODE_SYM '(' expr ',' TEXT_STRING ')'
@@ -1827,6 +2239,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 ')'
@@ -1837,70 +2251,132 @@ 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 ')'
{ $$= new Item_func_if($3,$5,$7); }
| INSERT '(' expr ',' expr ',' expr ',' expr ')'
{ $$= new Item_func_insert($3,$5,$7,$9); }
- | INTERVAL_SYM expr interval '+' expr
+ | interval_expr interval '+' expr
/* we cannot put interval before - */
- { $$= new Item_date_add_interval($5,$2,$3,0); }
- | INTERVAL_SYM '(' expr ',' expr_list ')'
- { $$= new Item_func_interval($3,* $5); }
+ { $$= new Item_date_add_interval($4,$1,$2,0); }
+ | interval_expr
+ {
+ if ($1->type() != Item::ROW_ITEM)
+ {
+ send_error(Lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ $$= new Item_func_interval((Item_row *)$1);
+ }
| 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()");
+ Lex->safe_to_cache_query= 0;
}
| LAST_INSERT_ID '(' expr ')'
{
$$= new Item_func_set_last_insert_id($3);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query= 0;
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
+ | LINESTRING '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ 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); }
| MASTER_POS_WAIT '(' expr ',' expr ')'
{
$$= new Item_master_pos_wait($3, $5);
- current_thd->safe_to_cache_query=0;
- }
+ Lex->safe_to_cache_query=0;
+ }
| MASTER_POS_WAIT '(' expr ',' expr ',' expr ')'
{
$$= new Item_master_pos_wait($3, $5, $7);
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| 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;}
+ { $$= new Item_func_now(); Lex->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
- { $$= new Item_func_now($3); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;}
| PASSWORD '(' expr ')'
- {
- $$= new Item_func_password($3);
- }
+ { $$= new Item_func_password($3); }
+ | PASSWORD '(' expr ',' expr ')'
+ { $$= new Item_func_password($3,$5); }
+ | POINT_SYM '(' expr ',' expr ')'
+ { $$= new Item_func_point($3,$5); }
+ | 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 ')'
- { $$= new Item_func_rand($3); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_rand($3); Lex->uncacheable();}
| RAND '(' ')'
- { $$= new Item_func_rand(); current_thd->safe_to_cache_query=0;}
+ { $$= new Item_func_rand(); Lex->uncacheable();}
| REPLACE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_replace($3,$5,$7); }
| RIGHT '(' expr ',' expr ')'
@@ -1921,7 +2397,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 ')'
@@ -1932,6 +2408,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)
@@ -1975,20 +2453,23 @@ simple_expr:
$$ = new Item_func_udf_int($1);
}
| UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' expr_list ')'
- {
+ {
$$= new Item_func_unique_users($3,atoi($5.str),atoi($7.str), * $9);
}
| UNIX_TIMESTAMP '(' ')'
{
$$= new Item_func_unix_timestamp();
- current_thd->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| UNIX_TIMESTAMP '(' expr ')'
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
- { $$= new Item_func_user(); current_thd->safe_to_cache_query=0; }
+ { $$= new Item_func_user(); Lex->safe_to_cache_query=0; }
| WEEK_SYM '(' expr ')'
- { $$= new Item_func_week($3,new Item_int((char*) "0",0,1)); }
+ {
+ $$= new Item_func_week($3,new Item_int((char*) "0",
+ YYTHD->variables.default_week_format,1));
+ }
| WEEK_SYM '(' expr ',' expr ')'
{ $$= new Item_func_week($3,$5); }
| YEAR_SYM '(' expr ')'
@@ -1998,9 +2479,9 @@ simple_expr:
| YEARWEEK '(' expr ',' expr ')'
{ $$= new Item_func_yearweek($3, $5); }
| BENCHMARK_SYM '(' ULONG_NUM ',' expr ')'
- {
+ {
$$=new Item_func_benchmark($3,$5);
- current_thd->safe_to_cache_query=0;
+ Lex->uncacheable();
}
| EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new Item_extract( $3, $5); };
@@ -2030,20 +2511,29 @@ sum_expr:
{ $$=new Item_sum_max($3); }
| STD_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_std($3); }
+ | VARIANCE_SYM '(' in_sum_expr ')'
+ { $$=new Item_sum_variance($3); }
| SUM_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_sum($3); };
in_sum_expr:
opt_all
- { 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--;
- $$=$3;
+ Select->select_lex()->in_sum_expr--;
+ $$= $3;
};
cast_type:
- BINARY { $$=ITEM_CAST_BINARY; }
+ BINARY { $$=ITEM_CAST_BINARY; }
| CHAR_SYM { $$=ITEM_CAST_CHAR; }
| SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; }
| SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
@@ -2092,19 +2582,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:
@@ -2119,7 +2609,7 @@ join_table_list:
| join_table_list normal_join join_table_list
USING
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->db1=$1->db; sel->table1=$1->alias;
sel->db2=$3->db; sel->table2=$3->alias;
}
@@ -2130,7 +2620,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;
}
@@ -2142,7 +2632,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;
}
@@ -2161,20 +2651,54 @@ normal_join:
join_table:
{
- SELECT_LEX *sel=Select;
+ SELECT_LEX *sel= Select->select_lex();
sel->use_index_ptr=sel->ignore_index_ptr=0;
sel->table_join_options= 0;
}
table_ident opt_table_alias opt_key_definition
{
- SELECT_LEX *sel=Select;
- if (!($$=add_table_to_list($2, $3, sel->table_join_options,
- TL_UNLOCK, sel->use_index_ptr,
- sel->ignore_index_ptr)))
+ LEX *lex= Lex;
+ SELECT_LEX_NODE *sel= lex->current_select;
+ if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
+ sel->get_table_join_options(),
+ lex->lock_option,
+ sel->get_use_index(),
+ sel->get_ignore_index())))
YYABORT;
}
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
- { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; };
+ { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+ | '(' SELECT_SYM select_derived ')' opt_table_alias
+ {
+ LEX *lex=Lex;
+ SELECT_LEX_UNIT *unit= lex->current_select->master_unit();
+ lex->current_select= unit->outer_select();
+ if (!($$= lex->current_select->
+ add_table_to_list(lex->thd, new Table_ident(unit), $5, 0,
+ TL_READ,(List<String> *)0,
+ (List<String> *)0)))
+
+ YYABORT;
+ };
+
+select_derived:
+ {
+ LEX *lex= Lex;
+ lex->derived_tables= 1;
+ if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
+ lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL)
+ {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ 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 opt_select_from union_opt
+ ;
opt_outer:
/* empty */ {}
@@ -2184,47 +2708,62 @@ 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;
}
| FORCE_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;
sel->table_join_options|= TL_OPTION_FORCE_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_list_or_empty ')'
+ { $$= &Select->select_lex()->interval_list; }
+ ;
+
+key_list_or_empty:
+ /* empty */ {}
+ | key_usage_list2 {}
+ ;
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;
};
@@ -2260,25 +2799,24 @@ opt_all:
;
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:
@@ -2296,26 +2834,36 @@ group_clause:
group_list:
group_list ',' order_ident order_dir
- { if (add_group_to_list($3,(bool) $4)) YYABORT; }
+ { if (add_group_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
| order_ident order_dir
- { if (add_group_to_list($1,(bool) $2)) YYABORT; };
+ { if (add_group_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
olap_opt:
/* empty */ {}
| WITH CUBE_SYM
{
LEX *lex=Lex;
- lex->olap = true;
- lex->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;
+ 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 */
}
;
@@ -2329,24 +2877,25 @@ opt_order_clause:
| order_clause;
order_clause:
- ORDER_SYM BY
- {
+ 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:
order_list ',' order_ident order_dir
- { if (add_order_to_list($3,(bool) $4)) YYABORT; }
+ { if (add_order_to_list(YYTHD, $3,(bool) $4)) YYABORT; }
| order_ident order_dir
- { if (add_order_to_list($1,(bool) $2)) YYABORT; };
+ { if (add_order_to_list(YYTHD, $1,(bool) $2)) YYABORT; };
order_dir:
/* empty */ { $$ = 1; }
@@ -2354,48 +2903,65 @@ order_dir:
| DESC { $$ =0; };
+opt_limit_clause_init:
+ /* empty */
+ {
+ SELECT_LEX_NODE *sel= Select;
+ sel->offset_limit= 0L;
+ sel->select_limit= Lex->thd->variables.select_limit;
+ }
+ | limit_clause {}
+ ;
+
+opt_limit_clause:
+ /* empty */ {}
+ | limit_clause {}
+ ;
+
limit_clause:
- /* empty */ {}
- | LIMIT
+ 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; };
@@ -2419,12 +2985,19 @@ procedure_clause:
| PROCEDURE ident /* Procedure name */
{
LEX *lex=Lex;
+ if (&lex->select_lex != lex->current_select)
+ {
+ net_printf(lex->thd, ER_WRONG_USAGE,
+ "PROCEDURE",
+ "subquery");
+ YYABORT;
+ }
lex->proc_list.elements=0;
lex->proc_list.first=0;
lex->proc_list.next= (byte**) &lex->proc_list.first;
if (add_proc_to_list(lex->thd, new Item_field(NULL,NULL,$2.str)))
YYABORT;
- current_thd->safe_to_cache_query=0;
+ Lex->uncacheable();
}
'(' procedure_list ')';
@@ -2445,26 +3018,68 @@ 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:
+ 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
+ {
+ Lex->uncacheable();
+ }
+ ;
/*
DO statement
*/
-do: DO_SYM
+do: DO_SYM
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DO;
@@ -2494,7 +3109,8 @@ 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, TL_OPTION_UPDATING))
+ if (!lex->current_select->add_table_to_list(lex->thd, $5, NULL,
+ TL_OPTION_UPDATING))
YYABORT;
}
| DROP DATABASE if_exists ident
@@ -2504,11 +3120,11 @@ drop:
lex->drop_if_exists=$3;
lex->name=$4.str;
}
- | DROP UDF_SYM ident
+ | DROP UDF_SYM IDENT
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_FUNCTION;
- lex->udf.name=$3.str;
+ lex->udf.name = $3;
};
@@ -2518,7 +3134,11 @@ table_list:
table_name:
table_ident
- { if (!add_table_to_list($1,NULL,TL_OPTION_UPDATING)) YYABORT; };
+ {
+ if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING))
+ YYABORT;
+ }
+ ;
if_exists:
/* empty */ { $$= 0; }
@@ -2534,28 +3154,35 @@ opt_temporary:
*/
insert:
- INSERT { Lex->sql_command = SQLCOM_INSERT; } insert_lock_option
- opt_ignore insert2
+ INSERT
+ {
+ LEX *lex= Lex;
+ lex->sql_command = SQLCOM_INSERT;
+ /* for subselects */
+ lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
+ } insert_lock_option
+ opt_ignore insert2
{
- set_lock_for_tables($3);
+ Select->set_lock_for_tables($3);
}
- insert_field_spec
+ insert_field_spec opt_insert_update
{}
;
replace:
REPLACE
{
- LEX *lex=Lex;
+ LEX *lex=Lex;
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
}
replace_lock_option insert2
{
- set_lock_for_tables($3);
+ Select->set_lock_for_tables($3);
}
insert_field_spec
{}
+ {}
;
insert_lock_option:
@@ -2563,7 +3190,7 @@ insert_lock_option:
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; }
| DELAYED_SYM { $$= TL_WRITE_DELAYED; }
| HIGH_PRIORITY { $$= TL_WRITE; }
- ;
+ ;
replace_lock_option:
opt_low_priority { $$= $1; }
@@ -2604,6 +3231,7 @@ fields:
insert_values:
VALUES values_list {}
+ | VALUE_SYM values_list {}
| SELECT_SYM
{
LEX *lex=Lex;
@@ -2612,8 +3240,9 @@ insert_values:
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
mysql_init_select(lex);
}
- select_options select_item_list select_from select_lock_type
- opt_union {};
+ select_options select_item_list opt_select_from select_lock_type
+ union_clause {}
+ ;
values_list:
values_list ',' no_braces
@@ -2673,55 +3302,70 @@ values:
;
expr_or_default:
- expr { $$= $1;}
- | DEFAULT {$$= new Item_default(); }
+ expr { $$= $1;}
+ | DEFAULT {$$= new Item_default_value(); }
;
+opt_insert_update:
+ /* empty */
+ | ON DUPLICATE_SYM
+ { /* for simplisity, let's forget about
+ INSERT ... SELECT ... UPDATE
+ for a moment */
+ if (Lex->sql_command != SQLCOM_INSERT)
+ {
+ send_error(Lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ }
+ KEY_SYM UPDATE_SYM update_list
+ ;
+
/* Update rows in a table */
update:
- UPDATE_SYM
- {
- 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;
+ UPDATE_SYM
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_UPDATE;
+ lex->select_lex.init_order();
}
opt_low_priority opt_ignore join_table_list
SET update_list where_clause opt_order_clause delete_limit_clause
{
- set_lock_for_tables($3);
+ LEX *lex= Lex;
+ Select->set_lock_for_tables($3);
+ if (lex->select_lex.table_list.elements > 1)
+ lex->sql_command=SQLCOM_UPDATE_MULTI;
}
;
update_list:
- update_list ',' simple_ident equal expr
+ update_list ',' simple_ident equal expr_or_default
{
- if (add_item_to_list($3) || add_value_to_list($5))
+ if (add_item_to_list(YYTHD, $3) || add_value_to_list(YYTHD, $5))
YYABORT;
}
- | simple_ident equal expr
+ | simple_ident equal expr_or_default
{
- if (add_item_to_list($1) || add_value_to_list($3))
+ if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3))
YYABORT;
};
opt_low_priority:
- /* empty */ { $$= current_thd->update_lock_default; }
+ /* empty */ { $$= YYTHD->update_lock_default; }
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
/* Delete rows from a table */
delete:
DELETE_SYM
- {
- LEX *lex=Lex;
- lex->sql_command= SQLCOM_DELETE; lex->select->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 {}
;
@@ -2729,8 +3373,8 @@ delete:
single_multi:
FROM table_ident
{
- if (!add_table_to_list($2, NULL, TL_OPTION_UPDATING,
- Lex->lock_option))
+ if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING,
+ Lex->lock_option))
YYABORT;
}
where_clause opt_order_clause
@@ -2749,23 +3393,24 @@ 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,
- TL_OPTION_UPDATING, Lex->lock_option))
- YYABORT;
- }
- | ident '.' ident opt_wild
- {
- if (!add_table_to_list(new Table_ident($1,$3,0), NULL,
- TL_OPTION_UPDATING,
- Lex->lock_option))
+ ident opt_wild opt_table_alias
+ {
+ if (!Select->add_table_to_list(YYTHD, new Table_ident($1), $3,
+ TL_OPTION_UPDATING, Lex->lock_option))
+ YYABORT;
+ }
+ | ident '.' ident opt_wild opt_table_alias
+ {
+ if (!Select->add_table_to_list(YYTHD,
+ new Table_ident(YYTHD, $1, $3, 0),
+ $5, TL_OPTION_UPDATING,
+ Lex->lock_option))
YYABORT;
- }
+ }
;
opt_wild:
- /* empty */ {}
+ /* empty */ {}
| '.' '*' {};
@@ -2780,22 +3425,26 @@ 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();
}
;
opt_table_sym:
/* empty */
| TABLE_SYM;
-
+
/* Show things */
-show: SHOW { Lex->wild=0;} show_param
+show: SHOW
+ {
+ LEX *lex=Lex;
+ lex->wild=0;
+ bzero((char*) &lex->create_info,sizeof(lex->create_info));
+ }
+ show_param
{}
;
@@ -2804,33 +3453,34 @@ show_param:
{ 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(YYTHD, $4, NULL, 0))
YYABORT;
}
- | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
+ | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ
TEXT_STRING AND MASTER_LOG_POS_SYM EQ ulonglong_num
AND MASTER_SERVER_ID_SYM EQ
ULONG_NUM
@@ -2840,7 +3490,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;
}
@@ -2850,19 +3500,40 @@ 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;
- } limit_clause
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS;
+ } opt_limit_clause_init
| 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(YYTHD, $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 opt_limit_clause_init
+ { Lex->sql_command = SQLCOM_SHOW_WARNS;}
+ | ERRORS opt_limit_clause_init
+ { Lex->sql_command = SQLCOM_SHOW_ERRORS;}
| STATUS_SYM wild
{ Lex->sql_command= SQLCOM_SHOW_STATUS; }
| INNOBASE_SYM STATUS_SYM
@@ -2870,11 +3541,13 @@ show_param:
| opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
| opt_var_type VARIABLES wild
- {
- THD *thd= current_thd;
+ {
+ THD *thd= YYTHD;
thd->lex.sql_command= SQLCOM_SHOW_VARIABLES;
thd->lex.option_type= (enum_var_type) $1;
}
+ | charset wild
+ { Lex->sql_command= SQLCOM_SHOW_CHARSETS; }
| LOGS_SYM
{ Lex->sql_command= SQLCOM_SHOW_LOGS; }
| GRANTS FOR_SYM user
@@ -2884,10 +3557,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(YYTHD, $3, NULL,0))
YYABORT;
}
| MASTER_SYM STATUS_SYM
@@ -2932,13 +3611,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(lex->thd, $2, NULL,0))
YYABORT;
}
opt_describe_column {}
- | describe_command select
- { Lex->select_lex.options|= SELECT_DESCRIBE; };
-
+ | describe_command { Lex->describe=1; } select
+ {
+ LEX *lex=Lex;
+ lex->select_lex.options|= SELECT_DESCRIBE;
+ }
+ ;
describe_command:
DESC
@@ -2948,7 +3630,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 */
@@ -3006,13 +3688,34 @@ purge:
PURGE
{
LEX *lex=Lex;
- lex->sql_command = SQLCOM_PURGE;
lex->type=0;
+ } purge_options
+ {}
+ ;
+
+purge_options:
+ LOGS_SYM purge_option
+ | MASTER_SYM LOGS_SYM purge_option
+ ;
+
+purge_option:
+ TO_SYM TEXT_STRING
+ {
+ Lex->sql_command = SQLCOM_PURGE;
+ Lex->to_log = $2.str;
+ }
+ | BEFORE_SYM expr
+ {
+ if ($2->check_cols(1) || $2->fix_fields(Lex->thd, 0, &$2))
+ {
+ net_printf(Lex->thd, ER_WRONG_ARGUMENTS, "PURGE LOGS BEFORE");
+ YYABORT;
+ }
+ Item *tmp= new Item_func_unix_timestamp($2);
+ Lex->sql_command = SQLCOM_PURGE_BEFORE;
+ Lex->purge_time= tmp->val_int();
}
- MASTER_SYM LOGS_SYM TO_SYM TEXT_STRING
- {
- Lex->to_log = $6.str;
- } ;
+ ;
/* kill threads */
@@ -3020,9 +3723,9 @@ kill:
KILL_SYM expr
{
LEX *lex=Lex;
- if ($2->fix_fields(lex->thd,0))
- {
- send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY);
+ if ($2->fix_fields(lex->thd, 0, &$2) || $2->check_cols(1))
+ {
+ send_error(lex->thd, ER_SET_CONSTANTS_ONLY);
YYABORT;
}
lex->sql_command=SQLCOM_KILL;
@@ -3034,7 +3737,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 */
@@ -3052,14 +3756,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, TL_OPTION_UPDATING))
+ if (!Select->add_table_to_list(YYTHD, $11, NULL, TL_OPTION_UPDATING))
YYABORT;
}
|
LOAD TABLE_SYM table_ident FROM MASTER_SYM
{
Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE;
- if (!add_table_to_list($3, NULL, TL_OPTION_UPDATING))
+ if (!Select->add_table_to_list(YYTHD, $3, NULL, TL_OPTION_UPDATING))
YYABORT;
}
@@ -3074,7 +3778,7 @@ opt_local:
| LOCAL_SYM { $$=1;};
load_data_lock:
- /* empty */ { $$= current_thd->update_lock_default; }
+ /* empty */ { $$= YYTHD->update_lock_default; }
| CONCURRENT { $$= TL_WRITE_CONCURRENT_INSERT ; }
| LOW_PRIORITY { $$= TL_WRITE_LOW_PRIORITY; };
@@ -3123,17 +3827,40 @@ 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,
+ YYTHD->variables.thd_charset); }
+ | UNDERSCORE_CHARSET TEXT_STRING
+ { $$ = new Item_string($2.str,$2.length,Lex->charset,Item::COER_IMPLICIT); }
| text_literal TEXT_STRING
- { ((Item_string*) $1)->append($2.str,$2.length); };
+ { ((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,YYTHD->variables.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 (YYTHD->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; }
@@ -3143,7 +3870,7 @@ literal:
| REAL_NUM { $$ = new Item_real($1.str, $1.length); }
| FLOAT_NUM { $$ = new Item_float($1.str, $1.length); }
| NULL_SYM { $$ = new Item_null();
- Lex->next_state=STATE_OPERATOR_OR_IDENT;}
+ Lex->next_state=MY_LEX_OPERATOR_OR_IDENT;}
| HEX_NUM { $$ = new Item_varbinary($1.str,$1.length);}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
@@ -3158,10 +3885,19 @@ insert_ident:
| table_wild { $$=$1; };
table_wild:
- ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); }
+ ident '.' '*'
+ {
+ $$ = new Item_field(NullS,$1.str,"*");
+ Lex->current_select->select_lex()->with_wild++;
+ }
| ident '.' ident '.' '*'
- { $$ = new Item_field((current_thd->client_capabilities &
- CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); };
+ {
+ $$ = new Item_field((YYTHD->client_capabilities &
+ CLIENT_NO_SCHEMA ? NullS : $1.str),
+ $3.str,"*");
+ Lex->current_select->select_lex()->with_wild++;
+ }
+ ;
order_ident:
expr { $$=$1; };
@@ -3169,23 +3905,47 @@ 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);
+ THD *thd= YYTHD;
+ LEX *lex= &thd->lex;
+ SELECT_LEX_NODE *sel= lex->current_select;
+ if (sel->no_table_names_allowed)
+ {
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ ER(ER_TABLENAME_NOT_ALLOWED_HERE),
+ MYF(0), $1.str, thd->where);
+ }
+ $$ = !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);
+ THD *thd= YYTHD;
+ LEX *lex= &thd->lex;
+ SELECT_LEX_NODE *sel= lex->current_select;
+ if (sel->no_table_names_allowed)
+ {
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ ER(ER_TABLENAME_NOT_ALLOWED_HERE),
+ MYF(0), $2.str, thd->where);
+ }
+ $$ = !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);
+ THD *thd= YYTHD;
+ LEX *lex= &thd->lex;
+ SELECT_LEX_NODE *sel= lex->current_select;
+ if (sel->no_table_names_allowed)
+ {
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ ER(ER_TABLENAME_NOT_ALLOWED_HERE),
+ MYF(0), $3.str, thd->where);
+ }
+ $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str);
};
@@ -3196,7 +3956,7 @@ field_ident:
table_ident:
ident { $$=new Table_ident($1); }
- | ident '.' ident { $$=new Table_ident($1,$3,0);}
+ | ident '.' ident { $$=new Table_ident(YYTHD, $1,$3,0);}
| '.' ident { $$=new Table_ident($2);}
/* For Delphi */;
@@ -3207,8 +3967,8 @@ ident:
LEX *lex= Lex;
$$.str= lex->thd->strmake($1.str,$1.length);
$$.length=$1.length;
- if (lex->next_state != STATE_END)
- lex->next_state=STATE_OPERATOR_OR_IDENT;
+ if (lex->next_state != MY_LEX_END)
+ lex->next_state= MY_LEX_OPERATOR_OR_IDENT;
}
;
@@ -3220,13 +3980,15 @@ ident_or_text:
user:
ident_or_text
{
- if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user))))
+ THD *thd= YYTHD;
+ if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
$$->user = $1; $$->host.str=NullS;
}
| ident_or_text '@' ident_or_text
{
- if (!($$=(LEX_USER*) sql_alloc(sizeof(st_lex_user))))
+ THD *thd= YYTHD;
+ if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
$$->user = $1; $$->host=$3;
};
@@ -3238,6 +4000,8 @@ keyword:
| AFTER_SYM {}
| AGAINST {}
| AGGREGATE_SYM {}
+ | ANY_SYM {}
+ | ASCII_SYM {}
| AUTO_INC {}
| AVG_ROW_LENGTH {}
| AVG_SYM {}
@@ -3248,6 +4012,7 @@ keyword:
| BIT_SYM {}
| BOOL_SYM {}
| BOOLEAN_SYM {}
+ | BYTE_SYM {}
| CACHE_SYM {}
| CHANGED {}
| CHARSET {}
@@ -3255,6 +4020,7 @@ keyword:
| CIPHER_SYM {}
| CLIENT_SYM {}
| CLOSE_SYM {}
+ | COLLATION_SYM {}
| COMMENT_SYM {}
| COMMITTED_SYM {}
| COMMIT_SYM {}
@@ -3269,7 +4035,9 @@ keyword:
| DES_KEY_FILE {}
| DIRECTORY_SYM {}
| DO_SYM {}
+ | DUAL_SYM {}
| DUMPFILE {}
+ | DUPLICATE_SYM {}
| DYNAMIC_SYM {}
| END {}
| ENUM {}
@@ -3278,17 +4046,20 @@ 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 {}
+ | GEOMETRY_SYM {}
+ | GEOMETRYCOLLECTION {}
+ | GRANTS {}
| GLOBAL_SYM {}
- | HEAP_SYM {}
| HANDLER_SYM {}
+ | HEAP_SYM {}
+ | HELP_SYM {}
| HOSTS_SYM {}
| HOUR_SYM {}
| IDENTIFIED_SYM {}
@@ -3298,9 +4069,10 @@ keyword:
| ISSUER_SYM {}
| INNOBASE_SYM {}
| INSERT_METHOD {}
- | IO_THREAD {}
+ | IO_THREAD {}
| LAST_SYM {}
| LEVEL_SYM {}
+ | LINESTRING {}
| LOCAL_SYM {}
| LOCKS_SYM {}
| LOGS_SYM {}
@@ -3313,9 +4085,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 {}
| MEMORY_SYM {}
@@ -3324,7 +4096,11 @@ keyword:
| MODIFY_SYM {}
| MODE_SYM {}
| MONTH_SYM {}
+ | MULTILINESTRING {}
+ | MULTIPOINT {}
+ | MULTIPOLYGON {}
| MYISAM_SYM {}
+ | NAMES_SYM {}
| NATIONAL_SYM {}
| NCHAR_SYM {}
| NEXT_SYM {}
@@ -3334,19 +4110,22 @@ keyword:
| OFFSET_SYM {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
+ | PARTIAL {}
| PASSWORD {}
+ | POINT_SYM {}
+ | POLYGON {}
| 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 {}
@@ -3360,16 +4139,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 {}
@@ -3385,10 +4166,14 @@ keyword:
| TYPE_SYM {}
| UDF_SYM {}
| UNCOMMITTED_SYM {}
+ | UNICODE_SYM {}
| USE_FRM {}
| VARIABLES {}
+ | VALUE_SYM {}
| WORK_SYM {}
- | YEAR_SYM {};
+ | YEAR_SYM {}
+ | SOUNDS_SYM {}
+ ;
/* Option functions */
@@ -3421,16 +4206,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:
@@ -3455,18 +4240,67 @@ option_value:
find_sys_var("tx_isolation"),
new Item_int((int32) $4)));
}
- | CHAR_SYM SET opt_equal set_expr_or_default
+ | charset opt_equal set_expr_or_default
{
LEX *lex=Lex;
lex->var_list.push_back(new set_var(lex->option_type,
find_sys_var("convert_character_set"),
- $4));
+ $3));
+ }
+ | NAMES_SYM charset_name_or_default opt_collate
+ {
+ THD* thd= YYTHD;
+ LEX *lex= &thd->lex;
+ CHARSET_INFO *cs= $2 ? $2 : thd->db_charset;
+ CHARSET_INFO *cl= $3 ? $3 : cs;
+
+ if (!my_charset_same(cs,cl))
+ {
+ net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
+ cl->name,cs->csname);
+ YYABORT;
+ }
+ Item_string *csname= new Item_string(cl->name,
+ strlen(cl->name),
+ &my_charset_latin1);
+ lex->var_list.push_back(new set_var(lex->option_type,
+ find_sys_var("client_collation"),
+ csname));
+ }
+ | COLLATION_SYM collation_name_or_default
+ {
+ THD* thd= YYTHD;
+ LEX *lex= &thd->lex;
+ system_variables *vars= &thd->variables;
+ CHARSET_INFO *cs= vars->thd_charset;
+ CHARSET_INFO *cl= $2;
+
+ if (!cl)
+ {
+ if (!(cl=get_charset_by_csname(cs->csname,MY_CS_PRIMARY,MYF(0))))
+ {
+ net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"DEFAULT");
+ YYABORT;
+ }
+ }
+ else if (!my_charset_same(cs,cl))
+ {
+ net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
+ cl->name,cs->csname);
+ YYABORT;
+ }
+ Item_string *csname= new Item_string(cl->name,
+ strlen(cl->name),
+ &my_charset_latin1);
+ lex->var_list.push_back(new set_var(lex->option_type,
+ find_sys_var("client_collation"),
+ csname));
}
| PASSWORD equal text_or_password
{
- THD *thd=current_thd;
+ THD *thd=YYTHD;
LEX_USER *user;
- if (!(user=(LEX_USER*) sql_alloc(sizeof(LEX_USER))))
+ if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
YYABORT;
user->host.str=0;
user->user.str=thd->priv_user;
@@ -3486,7 +4320,7 @@ internal_variable_name:
YYABORT;
$$=tmp;
}
- ;
+ ;
isolation_types:
READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; }
@@ -3503,18 +4337,21 @@ text_or_password:
$$=$3.str;
else
{
- char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
- make_scrambled_password(buff,$3.str);
+ char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
+ make_scrambled_password(buff,$3.str,use_old_passwords,
+ &YYTHD->rand);
$$=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); }
+ | BINARY { $$=new Item_string("binary", 6, system_charset_info); }
;
@@ -3539,16 +4376,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(YYTHD, $1, $2, 0, (thr_lock_type) $3))
+ YYABORT;
+ }
+ ;
lock_option:
READ_SYM { $$=TL_READ_NO_INSERT; }
- | WRITE_SYM { $$=current_thd->update_lock_default; }
+ | WRITE_SYM { $$=YYTHD->update_lock_default; }
| LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; }
- | READ_SYM LOCAL_SYM { $$= TL_READ; };
+ | 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; }
+ ;
/*
@@ -3558,14 +4401,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(lex->thd, $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(lex->thd, $2, 0, 0))
YYABORT;
}
| HANDLER_SYM table_ident READ_SYM
@@ -3573,20 +4418,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(lex->thd, $2, 0, 0))
YYABORT;
}
- handler_read_or_scan where_clause limit_clause { };
+ handler_read_or_scan where_clause opt_limit_clause {}
+ ;
handler_read_or_scan:
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; }
@@ -3600,14 +4448,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 */
@@ -3619,7 +4469,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));
@@ -3636,7 +4486,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));
@@ -3649,7 +4499,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
@@ -3697,7 +4548,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;
@@ -3707,7 +4558,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;
@@ -3717,58 +4568,59 @@ 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;
}
;
-
+
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(lex->thd, $1,NULL,0))
YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = TABLE_ACLS & ~GRANT_ACL;
- };
+ }
+ ;
user_list:
@@ -3787,10 +4639,11 @@ grant_user:
$$=$1; $1->password=$4;
if ($4.length)
{
- char *buff=(char*) sql_alloc(HASH_PASSWORD_LENGTH+1);
+ char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
if (buff)
{
- make_scrambled_password(buff,$4.str);
+ make_scrambled_password(buff,$4.str,use_old_passwords,
+ &YYTHD->rand);
$1->password.str=buff;
$1->password.length=HASH_PASSWORD_LENGTH;
}
@@ -3799,7 +4652,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:
@@ -3817,13 +4671,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;
@@ -3831,11 +4686,12 @@ column_list_id:
point->rights |= lex->which_columns;
else
lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns));
- };
+ }
+ ;
require_clause: /* empty */
- | REQUIRE_SYM require_list
+ | REQUIRE_SYM require_list
{
Lex->ssl_type=SSL_TYPE_SPECIFIED;
}
@@ -3851,7 +4707,7 @@ require_clause: /* empty */
{
Lex->ssl_type=SSL_TYPE_NONE;
}
- ;
+ ;
grant_options:
/* empty */ {}
@@ -3859,7 +4715,8 @@ grant_options:
grant_option_list:
grant_option_list grant_option {}
- | grant_option {};
+ | grant_option {}
+ ;
grant_option:
GRANT OPTION { Lex->grant |= GRANT_ACL;}
@@ -3877,7 +4734,8 @@ grant_option:
{
Lex->mqh.connections=$2;
Lex->mqh.bits |= 4;
- };
+ }
+ ;
begin:
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work {}
@@ -3885,7 +4743,8 @@ begin:
opt_work:
/* empty */ {}
- | WORK_SYM {;};
+ | WORK_SYM {;}
+ ;
commit:
COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;};
@@ -3895,63 +4754,133 @@ rollback:
/*
-** UNIONS : glue selects together
+ UNIONS : glue selects together
*/
-opt_union:
+union_clause:
/* empty */ {}
- | union_list;
+ | 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;
- }
+ mysql_init_select(lex);
+ lex->current_select->linkage=UNION_TYPE;
+ }
select_init {}
;
union_opt:
union_list {}
- | optional_order_or_limit {};
+ | optional_order_or_limit {}
+ ;
optional_order_or_limit:
- /* empty
- intentional reduce/reduce conflict here !!!
- { code } below should not be executed
- when neither ORDER BY nor LIMIT are used */ {}
+ /* Empty */ {}
|
{
- LEX *lex=Lex;
- if (!lex->select->braces)
- {
- send_error(&lex->thd->net, 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;
+ THD *thd= YYTHD;
+ LEX *lex= &thd->lex;
+ DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE);
+ SELECT_LEX *sel= lex->current_select->select_lex();
+ SELECT_LEX_UNIT *unit= sel->master_unit();
+ unit->global_parameters= unit;
+ unit->no_table_names_allowed= 1;
+ lex->current_select= unit;
+ thd->where= "global ORDER clause";
}
- opt_order_clause limit_clause
+ order_or_limit
+ {
+ THD *thd= YYTHD;
+ thd->lex.current_select->no_table_names_allowed= 0;
+ thd->where= "";
+ }
+ ;
+
+order_or_limit:
+ order_clause opt_limit_clause_init
+ | limit_clause
;
union_option:
/* empty */ {}
- | ALL { Lex->union_option=1; }
- ;
+ | ALL {Select->master_unit()->union_option= 1;};
+
+singlerow_subselect:
+ subselect_start singlerow_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+singlerow_subselect_init:
+ select_init2
+ {
+ $$= new Item_singlerow_subselect(YYTHD,
+ Lex->current_select->master_unit()->
+ first_select());
+ };
+
+exists_subselect:
+ subselect_start exists_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+exists_subselect_init:
+ select_init2
+ {
+ $$= new Item_exists_subselect(YYTHD,
+ Lex->current_select->master_unit()->
+ first_select());
+ };
+
+in_subselect:
+ subselect_start in_subselect_init
+ subselect_end
+ {
+ $$= $2;
+ };
+
+in_subselect_init:
+ select_init2
+ {
+ $$= Lex->current_select->master_unit()->first_select();
+ };
+
+subselect_start:
+ '(' SELECT_SYM
+ {
+ LEX *lex=Lex;
+ if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
+ lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) {
+ send_error(lex->thd, ER_SYNTAX_ERROR);
+ YYABORT;
+ }
+ if (mysql_new_select(Lex, 1))
+ YYABORT;
+ };
+
+subselect_end:
+ ')'
+ {
+ LEX *lex=Lex;
+ lex->current_select = lex->current_select->outer_select();
+ };
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index 73a7ecdc7ba..d0478052fb1 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -38,7 +38,7 @@ void safe_print_str(const char* name, const char* val, int max_len)
}
fprintf(stderr, "= ");
- for(; max_len && PTR_SANE(val) && *val; --max_len)
+ for (; max_len && PTR_SANE(val) && *val; --max_len)
fputc(*val++, stderr);
fputc('\n', stderr);
}
@@ -59,7 +59,7 @@ void safe_print_str(const char* name, const char* val, int max_len)
inline uchar** find_prev_fp(uint32* pc, uchar** fp)
{
int i;
- for(i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
+ for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
{
uchar* p = (uchar*)pc;
if (p[2] == 222 && p[3] == 35)
@@ -73,7 +73,7 @@ inline uchar** find_prev_fp(uint32* pc, uchar** fp)
inline uint32* find_prev_pc(uint32* pc, uchar** fp)
{
int i;
- for(i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
+ for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
{
char* p = (char*)pc;
if (p[1] == 0 && p[2] == 94 && p[3] == -73)
diff --git a/sql/structs.h b/sql/structs.h
index 77fed422d21..77c852673d5 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -113,7 +113,8 @@ enum timestamp_type { TIMESTAMP_NONE, TIMESTAMP_DATE, TIMESTAMP_FULL,
TIMESTAMP_TIME };
typedef struct st_time {
- uint year,month,day,hour,minute,second,second_part;
+ uint year,month,day,hour,minute,second;
+ ulong second_part;
bool neg;
timestamp_type time_type;
} TIME;
@@ -148,14 +149,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 a26ab89bd97..b36171cab93 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -37,7 +37,27 @@ static byte* get_field_name(Field *buff,uint *length,
return (byte*) buff->field_name;
}
- /* Open a .frm file */
+/*
+ Open a .frm file
+
+ SYNOPSIS
+ openfrm()
+
+ name path to table-file "db/name"
+ alias alias for table
+ db_stat open flags (for example HA_OPEN_KEYFILE|HA_OPEN_RNDFILE..)
+ can be 0 (example in ha_example_table)
+ prgflag READ_ALL etc..
+ ha_open_flags HA_OPEN_ABORT_IF_LOCKED etc..
+ outparam result table
+
+ RETURN VALUES
+ 0 ok
+ 1 Error (see frm_error)
+ 2 Error (see frm_error)
+ 3 Wrong data in .frm file
+ 4 Error (see frm_error)
+*/
int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam)
@@ -49,7 +69,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 +137,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;
@@ -258,7 +280,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (db_stat & HA_READ_ONLY)
outparam->record[1]=outparam->record[0]; /* purecov: inspected */
}
-
+
VOID(my_seek(file,pos,MY_SEEK_SET,MYF(0)));
if (my_read(file,(byte*) head,288,MYF(MY_NABP))) goto err_not_open;
if (crypted)
@@ -279,7 +301,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 +332,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 +361,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);
@@ -345,6 +370,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{
uint pack_flag, interval_nr, unireg_type, recpos, field_length;
enum_field_types field_type;
+ CHARSET_INFO *charset=NULL;
+ LEX_STRING comment;
if (new_frm_ver == 3)
{
@@ -354,36 +381,58 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
pack_flag= uint2korr(strpos+8);
unireg_type= (uint) strpos[10];
interval_nr= (uint) strpos[12];
- field_type= (enum_field_types) (uint) strpos[13];
+
+ uint comment_length=uint2korr(strpos+15);
+ field_type=(enum_field_types) (uint) strpos[13];
+ if (!(charset=get_charset((uint) strpos[14], 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_length= (uint) strpos[3];
recpos= uint2korr(strpos+4),
pack_flag= uint2korr(strpos+6);
unireg_type= (uint) strpos[8];
interval_nr= (uint) strpos[10];
+
+ /* 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+recpos,
(uint32) field_length,
null_pos,null_bit,
pack_flag,
field_type,
+ charset,
(Field::utype) MTYP_TYPENR(unireg_type),
(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)
@@ -481,13 +530,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)) &&
@@ -977,9 +1026,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' */
@@ -1007,6 +1061,7 @@ void append_unescaped(String *res,const char *pos)
break;
}
}
+ res->append('\'');
}
/* Create a .frm file */
@@ -1030,7 +1085,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+3; // Header
fileinfo[3]= (uchar) ha_checktype(create_info->db_type);
fileinfo[4]=1;
int2store(fileinfo+6,IO_SIZE); /* Next block starts here */
@@ -1046,6 +1101,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;
@@ -1076,6 +1132,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;
}
@@ -1090,15 +1147,22 @@ rename_file_ext(const char * from,const char * to,const char * ext)
/*
- Alloc a value as a string and return it
- If field is empty, return NULL
+ Allocate string field in MEM_ROOT and return it as NULL-terminated string
+
+ SYNOPSIS
+ get_field()
+ mem MEM_ROOT for allocating
+ field Field for retrieving of string
+
+ RETURN VALUES
+ NullS string is empty
+ # pointer to NULL-terminated string value of field
*/
-char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr)
+char *get_field(MEM_ROOT *mem, Field *field)
{
- Field *field=table->field[fieldnr];
char buff[MAX_FIELD_WIDTH];
- String str(buff,sizeof(buff));
+ String str(buff,sizeof(buff),&my_charset_bin);
field->val_str(&str,&str);
uint length=str.length();
if (!length)
@@ -1130,14 +1194,15 @@ bool check_db_name(char *name)
char *start=name;
if (lower_case_table_names)
- casedn_str(name);
+ my_casedn_str(files_charset_info, 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;
@@ -1150,7 +1215,7 @@ bool check_db_name(char *name)
return 1;
name++;
}
- return (uint) (name - start) > NAME_LEN;
+ return (uint) (name - start) > NAME_LEN || name == start;
}
@@ -1170,9 +1235,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;
@@ -1194,9 +1259,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;
diff --git a/sql/table.h b/sql/table.h
index b6935ea6a32..33e2db98d5a 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -19,6 +19,7 @@
class Item; /* Needed by ORDER */
class GRANT_TABLE;
+class st_select_lex_unit;
/* Order clause list element */
@@ -107,6 +108,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;
@@ -118,7 +120,7 @@ struct st_table {
table_map map; /* ID bit of table (1,2,4,8,16...) */
ulong version,flush_version;
uchar *null_flags;
- IO_CACHE *io_cache; /* If sorted trough file*/
+ IO_CACHE *io_cache; /* If sorted trough filebyte */
byte *record_pointers; /* If sorted in memory */
ha_rows found_records; /* How many records in sort */
ORDER *group;
@@ -132,9 +134,11 @@ struct st_table {
uint temp_pool_slot; /* Used by intern temp tables */
struct st_table_list *pos_in_table_list;
};
-
+ /* number of select if it is derived table */
+ uint derived_select_number;
THD *in_use; /* Which thread uses this */
struct st_table *next,*prev;
+ byte *default_values() { return record[2]; }
};
@@ -148,9 +152,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 */
+ };
+ class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */
+ GRANT_INFO grant;
thr_lock_type lock_type;
uint outer_join; /* Which join type */
uint shared; /* Used in union or in multi-upd */
@@ -160,7 +173,6 @@ typedef struct st_table_list
bool force_index; /* Prefer index over table scan */
} TABLE_LIST;
-
typedef struct st_changed_table_list
{
struct st_changed_table_list *next;
@@ -168,7 +180,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/thr_malloc.cc b/sql/thr_malloc.cc
index 8b9baa6f045..57560715fbe 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -24,7 +24,7 @@ extern "C" {
{
THD *thd=current_thd;
if (thd) // QQ; To be removed
- thd->fatal_error=1; /* purecov: inspected */
+ thd->fatal_error(); /* purecov: inspected */
sql_print_error(ER(ER_OUT_OF_RESOURCES));
}
}
diff --git a/sql/time.cc b/sql/time.cc
index 4fe79966404..94f9cb2e5e8 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(my_charset_latin1,*pos))
pos++;
length=(uint) strlen(pos);
for (uint i=0 ; i< 3; i++)
{
start=pos; value=0;
- while (isdigit(pos[0]) &&
+ while (my_isdigit(my_charset_latin1,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(my_charset_latin1,*pos) ||
+ my_isspace(my_charset_latin1,*pos)))
pos++;
}
DBUG_PRINT("exit",("year: %d month: %d day: %d",vek[0],vek[1],vek[2]));
@@ -417,13 +418,29 @@ 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, like
+ [DD [HH:[MM:[SS]]]].fraction
+ 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)
@@ -432,53 +449,66 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
uint not_zero_date;
const char *pos;
const char *end=str+length;
+ bool found_delimitier= 0;
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(&my_charset_latin1, *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(&my_charset_latin1,*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(&my_charset_latin1,*str) ; i++)
{
uint tmp_value=(uint) (uchar) (*str++ - '0');
- while (str != end && isdigit(str[0]) && field_length--)
+ while (str != end && my_isdigit(&my_charset_latin1,str[0]) &&
+ field_length--)
{
tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
str++;
}
+ if (found_delimitier && (int) field_length < 0)
+ {
+ /* The number can't match any valid date or datetime string */
+ DBUG_RETURN(TIMESTAMP_NONE);
+ }
date[i]=tmp_value;
not_zero_date|= tmp_value;
if (i == 2 && str != end && *str == 'T')
str++; // ISO8601: CCYYMMDDThhmmss
else if ( i != 5 ) // Skip inter-field delimiters
{
- while (str != end && (ispunct(*str) || isspace(*str)))
+ while (str != end &&
+ (my_ispunct(&my_charset_latin1,*str) ||
+ my_isspace(&my_charset_latin1,*str)))
{
// Only allow space between days and hours
- if (isspace(*str) && i != 2)
+ if (my_isspace(&my_charset_latin1,*str) && i != 2)
DBUG_RETURN(TIMESTAMP_NONE);
str++;
+ found_delimitier=1; // Should be a 'normal' 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(&my_charset_latin1,str[1]))
{
str++;
uint tmp_value=(uint) (uchar) (*str - '0');
- field_length=3;
- while (str++ != end && isdigit(str[0]) && field_length--)
+ field_length=5;
+ while (str++ != end && my_isdigit(&my_charset_latin1,str[0]) &&
+ field_length--)
tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
date[6]=tmp_value;
not_zero_date|= tmp_value;
@@ -500,7 +530,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(&my_charset_latin1, *str))
{
not_zero_date= 1; // Give warning
break;
@@ -515,7 +545,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(&my_charset_latin1,*str))
{
current_thd->cuted_fields++;
break;
@@ -561,12 +591,22 @@ longlong str_to_datetime(const char *str,uint length,bool fuzzy_date)
}
-/*****************************************************************************
-** convert a time string to a (ulong) value.
-** Can use all full timestamp formats and
-** [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS, [M]MSS or [S]S
-** There may be an optional [.second_part] after seconds
-*****************************************************************************/
+/*
+ Convert a time string to a TIME struct.
+
+ SYNOPSIS
+ str_to_time()
+ str A string in full TIMESTAMP format or
+ [-] DAYS [H]H:MM:SS, [H]H:MM:SS, [M]M:SS, [H]HMMSS,
+ [M]MSS or [S]S
+ There may be an optional [.second_part] after seconds
+ length Length of str
+ l_time Store result here
+
+ RETURN
+ 0 ok
+ 1 error
+*/
bool str_to_time(const char *str,uint length,TIME *l_time)
{
@@ -576,7 +616,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(&my_charset_latin1,*str) && *str != '-' ; str++)
length--;
if (str != end && *str == '-')
{
@@ -595,25 +636,29 @@ 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(&my_charset_latin1,*str) ; str++)
value=value*10L + (long) (*str - '0');
- if (*str == ' ')
+ /* Move to last space */
+ if (str != end && *str == ' ')
{
- while (++str != end && str[0] == ' ') ;
+ while (++str != end && str[0] == ' ')
+ {}
str--;
}
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(&my_charset_latin1,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(&my_charset_latin1,str[1]))
{
date[0]=0; // Assume we found hours
date[1]=value;
@@ -635,10 +680,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(&my_charset_latin1,*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(&my_charset_latin1,str[1]))
break;
str++; // Skip ':'
}
@@ -658,11 +704,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(&my_charset_latin1,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(&my_charset_latin1,str[0]) &&
+ field_length--)
value=value*10 + (uint) (uchar) (*str - '0');
date[4]=value;
}
@@ -687,7 +735,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
{
do
{
- if (!isspace(*str))
+ if (!my_isspace(&my_charset_latin1,*str))
{
current_thd->cuted_fields++;
break;
@@ -696,3 +744,20 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
}
return 0;
}
+
+
+/*
+ Convert a system time structure to TIME
+*/
+
+void localtime_to_TIME(TIME *to, struct tm *from)
+{
+ to->neg=0;
+ to->second_part=0;
+ to->year= (int) ((from->tm_year+1900) % 10000);
+ to->month= (int) from->tm_mon+1;
+ to->day= (int) from->tm_mday;
+ to->hour= (int) from->tm_hour;
+ to->minute= (int) from->tm_min;
+ to->second= (int) from->tm_sec;
+}
diff --git a/sql/udf_example.cc b/sql/udf_example.cc
index 176ddeb10a3..dfe8177bfce 100644
--- a/sql/udf_example.cc
+++ b/sql/udf_example.cc
@@ -126,6 +126,8 @@ typedef long long longlong;
#include <m_ctype.h>
#include <m_string.h> // To get strmov()
+static pthread_mutex_t LOCK_hostname;
+
#ifdef HAVE_DLOPEN
/* These must be right or mysqld will not find the symbol! */
@@ -282,8 +284,8 @@ char *metaphon(UDF_INIT *initid, UDF_ARGS *args, char *result,
for (n = ntrans + 1, n_end = ntrans + sizeof(ntrans)-2;
word != w_end && n < n_end; word++ )
- if ( isalpha ( *word ))
- *n++ = toupper ( *word );
+ if ( my_isalpha ( my_charset_latin1, *word ))
+ *n++ = my_toupper ( my_charset_latin1, *word );
if ( n == ntrans + 1 ) /* return empty string if 0 bytes */
{
@@ -583,6 +585,8 @@ longlong myfunc_int(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
case REAL_RESULT: // Add numers as longlong
val += (longlong) *((double*) args->args[i]);
break;
+ default:
+ break;
}
}
return val;
@@ -642,8 +646,6 @@ longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
**
****************************************************************************/
-#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
-
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -651,9 +653,11 @@ longlong sequence(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
extern "C" {
my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+void lookup_deinit(UDF_INIT *initid);
char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *length, char *null_value, char *error);
my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
+void reverse_lookup_deinit(UDF_INIT *initid);
char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *length, char *null_value, char *error);
}
@@ -676,9 +680,19 @@ my_bool lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
}
initid->max_length=11;
initid->maybe_null=1;
+#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+ (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
+#endif
return 0;
}
+void lookup_deinit(UDF_INIT *initid)
+{
+#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+ (void) pthread_mutex_destroy(&LOCK_hostname);
+#endif
+}
+
char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *null_value, char *error)
{
@@ -696,13 +710,23 @@ char *lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
length=sizeof(name_buff)-1;
memcpy(name_buff,args->args[0],length);
name_buff[length]=0;
-
+#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
if (!(hostent=gethostbyname_r(name_buff,&tmp_hostent,hostname_buff,
sizeof(hostname_buff), &tmp_errno)))
{
*null_value=1;
return 0;
}
+#else
+ VOID(pthread_mutex_lock(&LOCK_hostname));
+ if (!(hostent= gethostbyname((char*) name_buff)))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_hostname));
+ *null_value= 1;
+ return 0;
+ }
+ VOID(pthread_mutex_unlock(&LOCK_hostname));
+#endif
struct in_addr in;
memcpy_fixed((char*) &in,(char*) *hostent->h_addr_list, sizeof(in.s_addr));
*res_length= (ulong) (strmov(result, inet_ntoa(in)) - result);
@@ -731,9 +755,18 @@ my_bool reverse_lookup_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
}
initid->max_length=32;
initid->maybe_null=1;
+#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+ (void) pthread_mutex_init(&LOCK_hostname,MY_MUTEX_INIT_SLOW);
+#endif
return 0;
}
+void reverse_lookup_deinit(UDF_INIT *initid)
+{
+#if !defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
+ (void) pthread_mutex_destroy(&LOCK_hostname);
+#endif
+}
char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *null_value, char *error)
@@ -776,6 +809,7 @@ char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
return 0;
}
struct hostent *hp;
+#if defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
int tmp_errno;
if (!(hp=gethostbyaddr_r((char*) &taddr,sizeof(taddr), AF_INET,
&tmp_hostent, name_buff,sizeof(name_buff),
@@ -784,10 +818,19 @@ char *reverse_lookup(UDF_INIT *initid, UDF_ARGS *args, char *result,
*null_value=1;
return 0;
}
+#else
+ VOID(pthread_mutex_lock(&LOCK_hostname));
+ if (!(hp= gethostbyaddr((char*) &taddr, sizeof(taddr), AF_INET)))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_hostname));
+ *null_value= 1;
+ return 0;
+ }
+ VOID(pthread_mutex_unlock(&LOCK_hostname));
+#endif
*res_length=(ulong) (strmov(result,hp->h_name) - result);
return result;
}
-#endif // defined(HAVE_GETHOSTBYADDR_R) && defined(HAVE_SOLARIS_STYLE_GETHOST)
/*
** Syntax for the new aggregate commands are:
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 5183f471fa2..fa843fe5d1e 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 17 /* 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");
@@ -453,12 +451,16 @@ static bool pack_fields(File file,List<create_field> &create_fields)
buff[0]= (uchar) field->row;
buff[1]= (uchar) field->col;
buff[2]= (uchar) field->sc_length;
- buff[3]= (uchar) field->length;
+ int2store(buff+3, field->length);
uint recpos=(uint) field->offset+1;
- int2store(buff+4,recpos);
- int2store(buff+6,field->pack_flag);
- int2store(buff+8,field->unireg_check);
- buff[10]= (uchar) field->interval_id;
+ int3store(buff+5,recpos);
+ int2store(buff+8,field->pack_flag);
+ int2store(buff+10,field->unireg_check);
+ buff[12]= (uchar) field->interval_id;
+ buff[13]= (uchar) field->sql_type;
+ buff[14]= (uchar) field->charset->number;
+ int2store(buff+15, 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), &my_charset_bin);
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, 1);
+ (void) field->def->save_in_field(regfield, 1);
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)),system_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)),system_charset_info);
else
regfield->reset();
delete regfield;
diff --git a/sql/unireg.h b/sql/unireg.h
index 7e98d0d3cbe..9430329e67a 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -63,6 +63,15 @@
#define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD)
#define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD)
+
+/* Memory allocated when parsing a statement / saving a statement */
+#define MEM_ROOT_BLOCK_SIZE 8192
+#define MEM_ROOT_PREALLOC 8192
+#define TRANS_MEM_ROOT_BLOCK_SIZE 4096
+#define TRANS_MEM_ROOT_PREALLOC 4096
+
+#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 */
@@ -133,6 +142,8 @@ bfill((A)->null_flags,(A)->null_bytes,255);\
#define BIN_LOG_HEADER_SIZE 4
+#define FLOATING_POINT_BUFFER 331
+
/* Include prototypes for unireg */
#include "mysqld_error.h"