diff options
Diffstat (limited to 'sql')
102 files changed, 4630 insertions, 5265 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index a4858ab2b38..c3b7c77e252 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -46,7 +46,7 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ item_strfunc.h item_timefunc.h item_uniq.h \ item_create.h item_subselect.h item_row.h \ - mysql_priv.h \ + mysql_priv.h item_geofunc.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 \ @@ -55,19 +55,19 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.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 \ + log_event.h sql_repl.h slave.h \ stacktrace.h sql_sort.h sql_cache.h set_var.h \ - spatial.h gstream.h + spatial.h gstream.h client_settings.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ thr_malloc.cc item_create.cc item_subselect.cc \ - item_row.cc \ + item_row.cc item_geofunc.cc \ field.cc key.cc sql_class.cc sql_list.cc \ 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 \ + 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 \ @@ -83,7 +83,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.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 sql_derived.cc \ - mini_client.cc mini_client_errors.c pack.c\ + client.c mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\ gstream.cc spatial.cc sql_help.cc protocol_cursor.cc gen_lex_hash_SOURCES = gen_lex_hash.cc @@ -104,6 +104,8 @@ link_sources: @LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c rm -f pack.c @LN_CP_F@ ../sql-common/pack.c pack.c + rm -f client.c + @LN_CP_F@ ../sql-common/client.c client.c gen_lex_hash.o: gen_lex_hash.cc lex.h $(CXXCOMPILE) -c $(INCLUDES) $< diff --git a/sql/client_settings.h b/sql/client_settings.h new file mode 100644 index 00000000000..bc4cdf2a777 --- /dev/null +++ b/sql/client_settings.h @@ -0,0 +1,33 @@ +/* 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 */ + + +#include <thr_alarm.h> + +extern char *mysql_unix_port; + +#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG \ + | CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION) + + +extern ulong slave_net_timeout; +#define init_sigpipe_variables +#define set_sigpipe(mysql) +#define reset_sigpipe(mysql) + +#ifdef HAVE_SMEM +#undef HAVE_SMEM +#endif diff --git a/sql/convert.cc b/sql/convert.cc deleted file mode 100644 index bfdf49bf42d..00000000000 --- a/sql/convert.cc +++ /dev/null @@ -1,465 +0,0 @@ -/* 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 */ - -#if 0 - -/* -** Convert tables between different character sets -** Some of the tables are hidden behind IFDEF to reduce some space. -** One can enable them by removing the // characters from the next comment -** One must also give a name to each mapping that one wants to use... -*/ - -/* #define DEFINE_ALL_CHARACTER_SETS */ - -#include "mysql_priv.h" - -/**************************************************************************** - Convert tables -****************************************************************************/ - -/* Windows cp1251->koi8 and reverse conversion by Timur I. Bakeyev <translate@bat.ru> */ -/* based on Russian-Apache Team tables by Dmitry M. Klimoff <dmk@kosnet.ru> */ - -static unsigned char cp1251_koi8[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, -144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, -160,161,162,163,164,189,166,167,179,169,180,171,172,173,174,183, -176,177,182,166,173,181,182,183,163,185,164,187,188,189,190,167, -225,226,247,231,228,229,246,250,233,234,235,236,237,238,239,240, -242,243,244,245,230,232,227,254,251,253,255,249,248,252,224,241, -193,194,215,199,196,197,214,218,201,202,203,204,205,206,207,208, -210,211,212,213,198,200,195,222,219,221,223,217,216,220,192,209 -}; - -static unsigned char koi8_cp1251[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, -144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, -160,161,162,184,186,165,179,191,168,169,170,171,172,180,174,175, -176,177,178,168,170,181,178,175,184,185,186,187,188,165,190,191, -254,224,225,246,228,229,244,227,245,232,233,234,235,236,237,238, -239,255,240,241,242,243,230,226,252,251,231,248,253,249,247,250, -222,192,193,214,196,197,212,195,213,200,201,202,203,204,205,206, -207,223,208,209,210,211,198,194,220,219,199,216,221,217,215,218 -}; - - -#ifdef DEFINE_ALL_CHARACTER_SETS - -/* These tables was generated from package 'cstools' (author Jan "Yenya" Kasprzak <kas@muni.cz>) */ - -/* Windows pc1250 to iso 8859-2 */ - -static unsigned char t1250_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129, 0,131, 0, 0, 0, 0,136, 0,169, 0,166,171,174,172, -144, 0, 0, 0, 0, 0, 0, 0,152, 0,185, 0,182,187,190,188, -160,183,162,163,164,161, 0,167,168, 0,170, 0, 0,173, 0,175, -176, 0,178,179,180, 0, 0, 0,184,177,186, 0,165,189,181,191, -192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, -208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, -224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, -240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 -}; - -static unsigned char til2_t1250[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129, 0,131, 0, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0, -144, 0, 0, 0, 0, 0, 0, 0,152, 0, 0, 0, 0, 0, 0, 0, -160,165,162,163,164,188,140,167,168,138,170,141,143,173,142,175, -176,185,178,179,180,190,156,161,184,154,186,157,159,189,158,191, -192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, -208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, -224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, -240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 -}; - -/* Windows pc1252 to iso 8859-2 */ - -static unsigned char t1252_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129, 0, 0, 0, 0, 0, 0,136, 0,169, 0, 0,141,142,143, -144, 0, 0, 0, 0, 0, 0, 0,189, 0,185, 0, 0,157,158, 0, -160, 0, 0, 0,164, 0, 0,167,168, 0, 0, 0, 0,173, 0, 0, -176, 0, 0, 0,180, 0, 0, 0,184, 0, 0, 0, 0, 0, 0, 0, - 0,193,194, 0,196, 0, 0,199, 0,201, 0,203, 0,205,206, 0, -208, 0, 0,211,212, 0,214,215, 0, 0,218, 0,220,221, 0,223, - 0,225,226, 0,228, 0, 0,231, 0,233, 0,235, 0,237,238, 0, -240, 0, 0,243,244, 0,246,247, 0, 0,250, 0,252,253, 0, 0 -}; -static unsigned char til2_t1252[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129, 0, 0, 0, 0, 0, 0,136, 0, 0, 0, 0,141,142,143, -144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,157,158, 0, -160, 0, 0, 0,164, 0, 0,167,168,138, 0, 0, 0,173, 0, 0, -176, 0, 0, 0,180, 0, 0, 0,184,154, 0, 0, 0,152, 0, 0, - 0,193,194, 0,196, 0, 0,199, 0,201, 0,203, 0,205,206, 0, -208, 0, 0,211,212, 0,214,215, 0, 0,218, 0,220,221, 0,223, - 0,225,226, 0,228, 0, 0,231, 0,233, 0,235, 0,237,238, 0, -240, 0, 0,243,244, 0,246,247, 0, 0,250, 0,252,253, 0, 0 -}; - -/* MSDOS Kamenicky encoding (for Czech/Slovak) to iso 8859-2 */ - -static unsigned char tkam_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -200,252,233,239,228,207,171,232,236,204,197,205,181,229,196,193, -201,190,174,244,246,211,249,218,253,214,220,169,165,221,216,187, -225,237,243,250,242,210,217,212,185,248,224,192, 0,167, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,247, 0,176, 0, 0, 0, 0, 0, 0, 0 -}; -static unsigned char til2_tkam[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,156, 0,173, 0,155, 0,134, 0, 0,146, 0, -248, 0, 0, 0, 0,140, 0, 0, 0,168, 0,159, 0, 0,145, 0, -171,143, 0, 0,142,138, 0, 0,128,144, 0, 0,137,139, 0,133, - 0, 0,165,149,167, 0,153, 0,158,166,151, 0,154,157, 0, 0, -170,160, 0, 0,132,141, 0, 0,135,130, 0, 0,136,161, 0,131, - 0, 0,164,162,147, 0,148,246,169,150,163, 0,129,152, 0, 0 -}; - -/* Macintosh Roman encoding to iso 8859-2 */ - -static unsigned char tmac_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -196, 0,199,201, 0,214,220,225, 0,226,228, 0, 0,231,233, 0, - 0,235,237, 0,238, 0, 0,243, 0,244,246, 0,250, 0, 0,252, - 0,176, 0, 0,167, 0, 0,223, 0, 0, 0,180,168, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,160, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,247, 0, 0, 0, 0,164, 0, 0, 0, 0, - 0, 0, 0, 0, 0,194, 0,193,203, 0,205,206, 0, 0,211,212, - 0, 0,218, 0, 0, 0, 0, 0, 0,162,255, 0,184,189,178,183 -}; -static unsigned char til2_tmac[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202, 0,249, 0,219, 0, 0,164,172, 0, 0, 0, 0, 0, 0, 0, -161, 0,254, 0,171, 0, 0,255,252, 0, 0, 0, 0,253, 0, 0, - 0,231,229, 0,128, 0, 0,130, 0,131, 0,232, 0,234,235, 0, - 0, 0, 0,238,239, 0,133, 0, 0, 0,242, 0,134, 0, 0,167, - 0,135,137, 0,138, 0, 0,141, 0,142, 0,145, 0,146,148, 0, - 0, 0, 0,151,153, 0,154,214, 0, 0,156, 0,159, 0, 0,250 -}; - -/* Macintosh Central European encodingto iso 8859-2 */ - -static unsigned char tmacce_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -196, 0, 0,201,161,214,220,225,177,200,228,232,198,230,233,172, -188,207,237,239, 0, 0, 0,243, 0,244,246, 0,250,204,236,252, - 0,176,202, 0,167, 0, 0,223, 0, 0, 0,234,168, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,179, 0, 0,165,181,197,229, 0, - 0,209, 0, 0,241,210, 0, 0, 0, 0,160,242,213, 0,245, 0, - 0, 0, 0, 0, 0, 0,247, 0, 0,192,224,216, 0, 0,248, 0, - 0,169, 0, 0,185,166,182,193,171,187,205,174,190, 0,211,212, - 0,217,218,249,219,251, 0, 0,221,253, 0,175,163,191, 0,183 -}; -static unsigned char til2_tmacce[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -202,132, 0,252, 0,187,229,164,172,225, 0,232,143, 0,235,251, -161,136, 0,184, 0,188,230,255, 0,228, 0,233,144, 0,236,253, -217,231, 0, 0,128,189,140, 0,137,131,162, 0,157,234, 0,145, - 0,193,197,238,239,204,133, 0,219,241,242,244,134,248, 0,167, -218,135, 0, 0,138,190,141, 0,139,142,171, 0,158,146, 0,147, - 0,196,203,151,153,206,154,214,222,243,156,245,159,249, 0, 0 -}; - -/* PC-Latin2 encoding, supported by M$-DOS to iso 8859-2 */ - -static unsigned char tpc2_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -199,252,233,226,228,249,230,231,179,235,213,245,238,172,196,198, -201,197,229,244,246,165,181,166,182,214,220,171,187,163,215,232, -225,237,243,250,161,177,174,190,202,234, 0,188,200,186, 0, 0, - 0, 0, 0, 0, 0,193,194,204,170, 0, 0, 0, 0,175,191, 0, - 0, 0, 0, 0, 0, 0,195,227, 0, 0, 0, 0, 0, 0, 0,164, -240,208,207,203,239,210,205,206,236, 0, 0, 0, 0,222,217, 0, -211,223,212,209,241,242,169,185,192,218,224,219,253,221,254,180, - 0,189,178,183,162,167,247,184, 0,168,255,251,216,248, 0, 0 -}; -static unsigned char til2_tpc2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,164,244,157,207,149,151,245,249,230,184,155,141, 0,166,189, - 0,165,242,136,239,150,152,243,247,231,173,156,171,241,167,190, -232,181,182,198,142,145,143,128,172,144,168,211,183,214,215,210, -209,227,213,224,226,138,153,158,252,222,233,235,154,237,221,225, -234,160,131,199,132,146,134,135,159,130,169,137,216,161,140,212, -208,228,229,162,147,139,148,246,253,133,163,251,129,236,238,250 -}; - -/* Encoding used by standard IBM PC vga cards to iso8859-2 */ -static unsigned char tvga_til2[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -199,252,233,226,228, 0, 0,231, 0,235, 0, 0,238, 0,196, 0, -201, 0, 0,244,246, 0, 0, 0, 0,214,220, 0, 0, 0, 0, 0, -225,237,243,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,247, 0,176, 0, 0, 0, 0, 0, 0, 0 -}; -static unsigned char til2_tvga[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,142, 0, 0,128, 0,144, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,153, 0, 0, 0, 0, 0,154, 0, 0, 0, - 0,160,131, 0,132, 0, 0,135, 0,130, 0,137, 0,161,140, 0, - 0, 0, 0,162,147, 0,148,246, 0, 0,163, 0,129, 0, 0, 0 -}; - -//Ukrainian koi8 and win1251 converting tables by Max Veremayenko -//(verem@tg.kiev.ua - -static unsigned char koi8_ukr_win1251ukr[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, -144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, -160,161,162,184,186,165,179,191,168,169,170,171,172,180,174,175, -176,177,178,168,170,181,178,175,184,185,186,187,188,165,190,191, -254,224,225,246,228,229,244,227,245,232,233,234,235,236,237,238, -239,255,240,241,242,243,230,226,252,251,231,248,253,249,247,250, -222,192,193,214,196,197,212,195,213,200,201,202,203,204,205,206, -207,223,208,209,210,211,198,194,220,219,199,216,221,217,215,218 -}; - -static unsigned char win1251ukr_koi8_ukr[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, -112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, -128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, -144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, -160,161,162,163,164,189,166,167,179,169,180,171,172,173,174,183, -176,177,182,166,173,181,182,183,163,185,164,187,188,189,190,167, -225,226,247,231,228,229,246,250,233,234,235,236,237,238,239,240, -242,243,244,245,230,232,227,254,251,253,255,249,248,252,224,241, -193,194,215,199,196,197,214,218,201,202,203,204,205,206,207,208, -210,211,212,213,198,200,195,222,219,221,223,217,216,220,192,209 -}; - -#endif /* DEFINE_ALL_CHARACTER_SETS */ - -/**************************************************************************** -** Declare mapping variables -****************************************************************************/ - - -CONVERT conv_cp1251_koi8("cp1251_koi8", cp1251_koi8, koi8_cp1251, 1); -#ifdef DEFINE_ALL_CHARACTER_SETS -CONVERT conv_cp1250_latin2("cp1250_latin2", t1250_til2, til2_t1250, 2); -CONVERT conv_kam_latin2("kam_latin2", tkam_til2, til2_tkam, 3); -CONVERT conv_mac_latin2("mac_latin2", tmac_til2, til2_tmac, 4); -CONVERT conv_macce_latin2("macce_latin2", tmacce_til2, til2_tmacce, 5); -CONVERT conv_pc2_latin2("pc2_latin2", tpc2_til2, til2_tpc2, 6); -CONVERT conv_vga_latin2("vga_latin2", tvga_til2, til2_tvga, 7); -CONVERT conv_koi8_cp1251("koi8_cp1251", koi8_cp1251, cp1251_koi8, 8); -CONVERT conv_win1251ukr_koi8_ukr("win1251ukr_koi8_ukr", win1251ukr_koi8_ukr, - koi8_ukr_win1251ukr, 9); -CONVERT conv_koi8_ukr_win1251ukr("koi8_ukr_win1251ukr", koi8_ukr_win1251ukr, - win1251ukr_koi8_ukr, 10); -#endif /* DEFINE_ALL_CHARACTER_SETS */ - -CONVERT *convert_tables[]= { - &conv_cp1251_koi8, -#ifdef DEFINE_ALL_CHARACTER_SETS - &conv_cp1250_latin2, - &conv_kam_latin2, - &conv_mac_latin2, - &conv_macce_latin2, - &conv_pc2_latin2, - &conv_vga_latin2, - &conv_koi8_cp1251, - &conv_win1251ukr_koi8_ukr, - &conv_koi8_ukr_win1251ukr, -#endif /* DEFINE_ALL_CHARACTER_SETS */ - NULL -}; - - -CONVERT *get_convert_set(const char *name) -{ - for (CONVERT **ptr=convert_tables ; *ptr ; ptr++) - { - if (!my_strcasecmp(&my_charset_latin1,(*ptr)->name,name)) - return (*ptr); - } - return 0; -} - - -void CONVERT::convert_array(const uchar *map, uchar * buf, uint len) -{ - for (uchar *end=buf+len ; buf != end ; buf++) - *buf= map[*buf]; -} - - -/* This is identical as net_store_data, but with a conversion */ - -bool CONVERT::store(String *packet,const char *from,uint length) -{ - uint packet_length=packet->length(); - 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, - (ulonglong)length); - packet->length((uint) (store_dest(to, from, length)-packet->ptr())); - return 0; -} - -#endif diff --git a/sql/field.cc b/sql/field.cc index e54986ded22..04859dd22e0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -161,6 +161,14 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) } +static inline uint field_length_without_space(const char *ptr, uint length) +{ + const char *end= ptr+length; + while (end > ptr && end[-1] == ' ') + end--; + return (uint) (end-ptr); +} + /**************************************************************************** ** Functions for the base classes ** This is an unpacked number. @@ -246,26 +254,6 @@ 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; @@ -347,7 +335,7 @@ bool Field::optimize_range(uint idx) void Field_null::sql_type(String &res) const { - res.set_latin1("null", 4); + res.set_ascii("null", 4); } @@ -367,7 +355,7 @@ void Field_decimal::overflow(bool negative) uint len=field_length; char *to=ptr, filler= '9'; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); if (negative) { if (!unsigned_flag) @@ -477,7 +465,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) from++; if (from == end) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); is_cuted_fields_incr=1; } else if (*from == '+' || *from == '-') // Found some sign ? @@ -553,7 +541,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) for (;from != end && my_isspace(&my_charset_bin, *from); from++) ; if (from != end) // If still something left, warn { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); is_cuted_fields_incr=1; } } @@ -731,7 +719,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) if (tmp_char != '0') // Losing a non zero digit ? { if (!is_cuted_fields_incr) - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return 0; } continue; @@ -748,7 +736,7 @@ int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) if (tmp_char != '0') // Losing a non zero digit ? { if (!is_cuted_fields_incr) - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return 0; } continue; @@ -868,7 +856,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)), if (field_length < tmp_length) // Error in data val_ptr->length(0); else - val_ptr->set_latin1((const char*) str, field_length-tmp_length); + val_ptr->set_ascii((const char*) str, field_length-tmp_length); return val_ptr; } @@ -944,7 +932,7 @@ void Field_decimal::sql_type(String &res) const tmp--; if (dec) tmp--; - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "decimal(%d,%d)",tmp,dec)); add_zerofill_and_unsigned(res); } @@ -966,18 +954,18 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp < 0) { tmp=0; /* purecov: inspected */ - current_thd->cuted_fields++; /* purecov: inspected */ + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (tmp > 255) { tmp= 255; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } } @@ -986,18 +974,18 @@ int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp < -128) { tmp= -128; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (tmp >= 128) { tmp= 127; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } } @@ -1015,13 +1003,13 @@ int Field_tiny::store(double nr) if (nr < 0.0) { *ptr=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > 255.0) { *ptr=(char) 255; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1032,13 +1020,13 @@ int Field_tiny::store(double nr) if (nr < -128.0) { *ptr= (char) -128; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > 127.0) { *ptr=127; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1055,13 +1043,13 @@ int Field_tiny::store(longlong nr) if (nr < 0L) { *ptr=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > 255L) { *ptr= (char) 255; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1072,13 +1060,13 @@ int Field_tiny::store(longlong nr) if (nr < -128L) { *ptr= (char) -128; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > 127L) { *ptr=127; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1112,9 +1100,11 @@ String *Field_tiny::val_str(String *val_buffer, char *to=(char*) val_buffer->ptr(); if (unsigned_flag) - length= (uint) cs->long10_to_str(cs,to,mlength, 10,(long) *((uchar*) ptr)); + length= (uint) cs->cset->long10_to_str(cs,to,mlength, 10, + (long) *((uchar*) ptr)); else - length= (uint) cs->long10_to_str(cs,to,mlength,-10,(long) *((signed char*) ptr)); + length= (uint) cs->cset->long10_to_str(cs,to,mlength,-10, + (long) *((signed char*) ptr)); val_buffer->length(length); if (zerofill) @@ -1147,7 +1137,7 @@ void Field_tiny::sort_string(char *to,uint length __attribute__((unused))) void Field_tiny::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "tinyint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -1168,18 +1158,18 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp < 0) { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (tmp > (uint16) ~0) { tmp=(uint16) ~0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } } @@ -1188,18 +1178,18 @@ int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp < INT_MIN16) { tmp= INT_MIN16; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (tmp > INT_MAX16) { tmp=INT_MAX16; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } } @@ -1225,13 +1215,13 @@ int Field_short::store(double nr) if (nr < 0) { res=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (double) (uint16) ~0) { res=(int16) (uint16) ~0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1242,13 +1232,13 @@ int Field_short::store(double nr) if (nr < (double) INT_MIN16) { res=INT_MIN16; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (double) INT_MAX16) { res=INT_MAX16; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1274,13 +1264,13 @@ int Field_short::store(longlong nr) if (nr < 0L) { res=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (longlong) (uint16) ~0) { res=(int16) (uint16) ~0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1291,13 +1281,13 @@ int Field_short::store(longlong nr) if (nr < INT_MIN16) { res=INT_MIN16; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > INT_MAX16) { res=INT_MAX16; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1357,9 +1347,10 @@ String *Field_short::val_str(String *val_buffer, shortget(j,ptr); if (unsigned_flag) - length=(uint) cs->long10_to_str(cs, to, mlength, 10, (long) (uint16) j); + length=(uint) cs->cset->long10_to_str(cs, to, mlength, 10, + (long) (uint16) j); else - length=(uint) cs->long10_to_str(cs, to, mlength,-10, (long) j); + length=(uint) cs->cset->long10_to_str(cs, to, mlength,-10, (long) j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -1420,7 +1411,7 @@ void Field_short::sort_string(char *to,uint length __attribute__((unused))) void Field_short::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "smallint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -1442,18 +1433,18 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp < 0) { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (tmp >= (long) (1L << 24)) { tmp=(long) (1L << 24)-1L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } } @@ -1462,18 +1453,18 @@ int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp < INT_MIN24) { tmp= INT_MIN24; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (tmp > INT_MAX24) { tmp=INT_MAX24; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } } @@ -1492,14 +1483,14 @@ int Field_medium::store(double nr) if (nr < 0) { int3store(ptr,0); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr >= (double) (long) (1L << 24)) { uint32 tmp=(uint32) (1L << 24)-1L; int3store(ptr,tmp); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1511,14 +1502,14 @@ int Field_medium::store(double nr) { long tmp=(long) INT_MIN24; int3store(ptr,tmp); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (double) INT_MAX24) { long tmp=(long) INT_MAX24; int3store(ptr,tmp); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1535,14 +1526,14 @@ int Field_medium::store(longlong nr) if (nr < 0L) { int3store(ptr,0); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr >= (longlong) (long) (1L << 24)) { long tmp=(long) (1L << 24)-1L;; int3store(ptr,tmp); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1554,14 +1545,14 @@ int Field_medium::store(longlong nr) { long tmp=(long) INT_MIN24; int3store(ptr,tmp); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (longlong) INT_MAX24) { long tmp=(long) INT_MAX24; int3store(ptr,tmp); - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1595,7 +1586,7 @@ String *Field_medium::val_str(String *val_buffer, char *to=(char*) val_buffer->ptr(); long j= unsigned_flag ? (long) uint3korr(ptr) : sint3korr(ptr); - length=(uint) cs->long10_to_str(cs,to,mlength,-10,j); + length=(uint) cs->cset->long10_to_str(cs,to,mlength,-10,j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); /* purecov: inspected */ @@ -1639,7 +1630,7 @@ void Field_medium::sort_string(char *to,uint length __attribute__((unused))) void Field_medium::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "mediumint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -1655,7 +1646,7 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) int error= 0; char *end; - tmp= cs->scan(cs, from, from+len, MY_SEQ_SPACES); + tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES); len-= tmp; from+= tmp; my_errno=0; @@ -1676,7 +1667,8 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) (from+len != end && current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); + error= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1700,13 +1692,13 @@ int Field_long::store(double nr) if (nr < 0) { res=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (double) (ulong) ~0L) { res=(int32) (uint32) ~0L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1717,13 +1709,13 @@ int Field_long::store(double nr) if (nr < (double) INT_MIN32) { res=(int32) INT_MIN32; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (double) INT_MAX32) { res=(int32) INT_MAX32; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1750,13 +1742,13 @@ int Field_long::store(longlong nr) if (nr < 0) { res=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr >= (LL(1) << 32)) { res=(int32) (uint32) ~0L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1767,13 +1759,13 @@ int Field_long::store(longlong nr) if (nr < (longlong) INT_MIN32) { res=(int32) INT_MIN32; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > (longlong) INT_MAX32) { res=(int32) INT_MAX32; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1832,9 +1824,9 @@ String *Field_long::val_str(String *val_buffer, longget(j,ptr); if (unsigned_flag) - length=cs->long10_to_str(cs,to,mlength, 10,(long) (uint32)j); + length=cs->cset->long10_to_str(cs,to,mlength, 10,(long) (uint32)j); else - length=cs->long10_to_str(cs,to,mlength,-10,(long) j); + length=cs->cset->long10_to_str(cs,to,mlength,-10,(long) j); val_buffer->length(length); if (zerofill) prepend_zeros(val_buffer); @@ -1897,7 +1889,7 @@ void Field_long::sort_string(char *to,uint length __attribute__((unused))) void Field_long::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "int(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -1912,7 +1904,7 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) int error= 0; char *end; - tmp= cs->scan(cs, from, from+len, MY_SEQ_SPACES); + tmp= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES); len-= (uint)tmp; from+= tmp; my_errno=0; @@ -1932,7 +1924,10 @@ int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) if (error || (from+len != end && current_thd->count_cuted_fields && !test_if_int(from,len,end,cs))) - current_thd->cuted_fields++; + { + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); + error= 1; + } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -1955,13 +1950,13 @@ int Field_longlong::store(double nr) if (nr < 0) { res=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr >= (double) ~ (ulonglong) 0) { res= ~(longlong) 0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -1972,13 +1967,13 @@ int Field_longlong::store(double nr) if (nr <= (double) LONGLONG_MIN) { res=(longlong) LONGLONG_MIN; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr >= (double) LONGLONG_MAX) { res=(longlong) LONGLONG_MAX; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -2053,7 +2048,7 @@ String *Field_longlong::val_str(String *val_buffer, #endif longlongget(j,ptr); - length=(uint) (cs->longlong10_to_str)(cs,to,mlength, + length=(uint) (cs->cset->longlong10_to_str)(cs,to,mlength, unsigned_flag ? 10 : -10, j); val_buffer->length(length); if (zerofill) @@ -2127,7 +2122,7 @@ void Field_longlong::sort_string(char *to,uint length __attribute__((unused))) void Field_longlong::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "bigint(%d)",(int) field_length)); add_zerofill_and_unsigned(res); } @@ -2142,7 +2137,7 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) 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++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return 1; } return (err) ? 1 : 0; @@ -2157,20 +2152,20 @@ int Field_float::store(double nr) nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point if (unsigned_flag && nr < 0) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); nr=0; error= 1; } if (nr < -FLT_MAX) { j= -FLT_MAX; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr > FLT_MAX) { j=FLT_MAX; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -2193,7 +2188,7 @@ int Field_float::store(longlong nr) float j= (float) nr; if (unsigned_flag && j < 0) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); j=0; error= 1; } @@ -2394,12 +2389,12 @@ void Field_float::sql_type(String &res) const { if (dec == NOT_FIXED_DEC) { - res.set_latin1("float", 5); + res.set_ascii("float", 5); } else { CHARSET_INFO *cs= res.charset(); - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "float(%d,%d)",(int) field_length,dec)); } add_zerofill_and_unsigned(res); @@ -2415,11 +2410,12 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) 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++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); + err= 1; } if (unsigned_flag && j < 0) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); j=0; err= 1; } @@ -2442,7 +2438,7 @@ int Field_double::store(double nr) nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point if (unsigned_flag && nr < 0) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); nr=0; error= 1; } @@ -2464,7 +2460,7 @@ int Field_double::store(longlong nr) int error= 0; if (unsigned_flag && j < 0) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; j=0; } @@ -2651,11 +2647,11 @@ void Field_double::sql_type(String &res) const CHARSET_INFO *cs=res.charset(); if (dec == NOT_FIXED_DEC) { - res.set_latin1("double",6); + res.set_ascii("double",6); } else { - res.length(cs->snprintf(cs,(char*) res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*) res.ptr(),res.alloced_length(), "double(%d,%d)",(int) field_length,dec)); } add_zerofill_and_unsigned(res); @@ -2705,7 +2701,7 @@ int Field_timestamp::store(double nr) if (nr < 0 || nr > 99991231235959.0) { nr= 0; // Avoid overflow on buff - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } error|= Field_timestamp::store((longlong) rint(nr)); @@ -2721,6 +2717,7 @@ int Field_timestamp::store(double nr) static longlong fix_datetime(longlong nr) { + current_thd->last_cuted_field= 0; if (nr == LL(0) || nr >= LL(10000101000000)) return nr; // Normal datetime >= Year 1000 if (nr < 101) @@ -2745,7 +2742,7 @@ static longlong fix_datetime(longlong nr) return nr+LL(19000000000000); // YYMMDDHHMMSS, 1970-1999 err: - current_thd->cuted_fields++; + current_thd->last_cuted_field= 1; return LL(0); } @@ -2778,6 +2775,8 @@ int Field_timestamp::store(longlong nr) else #endif longstore(ptr,(uint32) timestamp); + if (current_thd->last_cuted_field) + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return 0; } @@ -2988,7 +2987,7 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - res.set_latin1("timestamp", 9); + res.set_ascii("timestamp", 9); } @@ -3021,6 +3020,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) { tmp=0L; error= 1; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } else { @@ -3030,7 +3030,7 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) if (tmp > 8385959) { tmp=8385959; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } } @@ -3048,13 +3048,13 @@ int Field_time::store(double nr) if (nr > 8385959.0) { tmp=8385959L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr < -8385959.0) { tmp= -8385959L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3065,7 +3065,7 @@ int Field_time::store(double nr) if (tmp % 100 > 59 || tmp/100 % 100 > 59) { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } } @@ -3081,13 +3081,13 @@ int Field_time::store(longlong nr) if (nr > (longlong) 8385959L) { tmp=8385959L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else if (nr < (longlong) -8385959L) { tmp= -8385959L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3096,7 +3096,7 @@ int Field_time::store(longlong nr) if (tmp % 100 > 59 || tmp/100 % 100 > 59) { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } } @@ -3186,7 +3186,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused))) void Field_time::sql_type(String &res) const { - res.set_latin1("time", 4); + res.set_ascii("time", 4); } /**************************************************************************** @@ -3204,11 +3204,11 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { *ptr=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); return 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len,end,cs)) - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); if (nr != 0 || len != 4) { if (nr < YY_PART_YEAR) @@ -3236,7 +3236,7 @@ int Field_year::store(longlong nr) if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { *ptr=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); return 1; } if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000 @@ -3284,7 +3284,7 @@ String *Field_year::val_str(String *val_buffer, void Field_year::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - res.length(cs->snprintf(cs,(char*)res.ptr(),res.alloced_length(), + res.length(cs->cset->snprintf(cs,(char*)res.ptr(),res.alloced_length(), "year(%d)",(int) field_length)); } @@ -3305,6 +3305,7 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) { tmp=0; error= 1; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } else tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day); @@ -3329,7 +3330,7 @@ int Field_date::store(double nr) if (nr < 0.0 || nr > 99991231.0) { tmp=0L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3355,7 +3356,7 @@ int Field_date::store(longlong nr) if (nr < 0 || nr > LL(99991231)) { tmp=0L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3466,7 +3467,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused))) void Field_date::sql_type(String &res) const { - res.set_latin1("date", 4); + res.set_ascii("date", 4); } /**************************************************************************** @@ -3484,6 +3485,7 @@ int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) { tmp=0L; error= 1; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } else tmp= l_time.day + l_time.month*32 + l_time.year*16*32; @@ -3496,6 +3498,7 @@ int Field_newdate::store(double nr) if (nr < 0.0 || nr > 99991231235959.0) { (void) Field_newdate::store((longlong) -1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return 1; } else @@ -3512,7 +3515,7 @@ int Field_newdate::store(longlong nr) if (nr < 0L || nr > 99991231L) { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3530,7 +3533,7 @@ int Field_newdate::store(longlong nr) if (month > 12 || day > 31) { tmp=0L; // Don't allow date to change - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3548,7 +3551,7 @@ void Field_newdate::store_time(TIME *ltime,timestamp_type type) else { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } int3store(ptr,tmp); } @@ -3604,11 +3607,11 @@ bool Field_newdate::get_date(TIME *ltime,bool fuzzydate) if (is_null()) return 1; uint32 tmp=(uint32) uint3korr(ptr); - bzero((char*) ltime,sizeof(*ltime)); ltime->day= tmp & 31; ltime->month= (tmp >> 5) & 15; ltime->year= (tmp >> 9); ltime->time_type=TIMESTAMP_DATE; + ltime->hour= ltime->minute= ltime->second= ltime->second_part= 0; return (!fuzzydate && (!ltime->month || !ltime->day)) ? 1 : 0; } @@ -3634,7 +3637,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) void Field_newdate::sql_type(String &res) const { - res.set_latin1("date", 4); + res.set_ascii("date", 4); } @@ -3666,7 +3669,7 @@ int Field_datetime::store(double nr) if (nr < 0.0 || nr > 99991231235959.0) { nr=0.0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } error |= Field_datetime::store((longlong) rint(nr)); @@ -3680,7 +3683,7 @@ int Field_datetime::store(longlong nr) if (nr < 0 || nr > LL(99991231235959)) { nr=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE); error= 1; } else @@ -3693,6 +3696,8 @@ int Field_datetime::store(longlong nr) else #endif longlongstore(ptr,nr); + if (current_thd->last_cuted_field) + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); return error; } @@ -3705,7 +3710,7 @@ void Field_datetime::store_time(TIME *ltime,timestamp_type type) else { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -3865,7 +3870,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused))) void Field_datetime::sql_type(String &res) const { - res.set_latin1("datetime", 8); + res.set_ascii("datetime", 8); } /**************************************************************************** @@ -3896,7 +3901,7 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { memcpy(ptr,from,length); if (length < field_length) - field_charset->fill(field_charset,ptr+length,field_length-length,' '); + field_charset->cset->fill(field_charset,ptr+length,field_length-length,' '); } else { @@ -3905,10 +3910,10 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { // Check if we loosed some info const char *end=from+length; from+= field_length; - from+= field_charset->scan(field_charset, from, end, MY_SEQ_SPACES); + from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES); if (from != end) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error=1; } } @@ -3932,7 +3937,7 @@ int Field_string::store(longlong nr) char buff[64]; int l; CHARSET_INFO *cs=charset(); - l= (cs->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr); + l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr); return Field_string::store(buff,(uint)l,cs); } @@ -3969,9 +3974,19 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)), int Field_string::cmp(const char *a_ptr, const char *b_ptr) { - return my_strnncoll(field_charset, - (const uchar*)a_ptr,field_length, - (const uchar*)b_ptr,field_length); + if (field_charset->strxfrm_multiply > 1) + { + /* + We have to remove end space to be able to compare multi-byte-characters + like in latin_de 'ae' and 0xe4 + */ + return field_charset->coll->strnncollsp(field_charset, + (const uchar*) a_ptr, field_length, + (const uchar*) b_ptr, field_length); + } + return field_charset->coll->strnncoll(field_charset, + (const uchar*) a_ptr, field_length, + (const uchar*) b_ptr, field_length); } void Field_string::sort_string(char *to,uint length) @@ -3987,7 +4002,7 @@ void Field_string::sort_string(char *to,uint length) void Field_string::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - ulong length= cs->snprintf(cs,(char*) res.ptr(), + ulong length= cs->cset->snprintf(cs,(char*) res.ptr(), res.alloced_length(), "%s(%d)", (field_length > 3 && (table->db_options_in_use & @@ -3995,7 +4010,6 @@ void Field_string::sql_type(String &res) const "varchar" : "char"), (int) field_length); res.length(length); - add_binary_or_charset(res); } @@ -4077,7 +4091,7 @@ int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) if (length > field_length) { length=field_length; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error= 1; } memcpy(ptr+2,from,length); @@ -4101,7 +4115,7 @@ int Field_varstring::store(longlong nr) char buff[64]; int l; CHARSET_INFO *cs=charset(); - l= (cs->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr); + l= (cs->cset->longlong10_to_str)(cs,buff,sizeof(buff),-10,nr); return Field_varstring::store(buff,(uint)l,cs); } @@ -4158,11 +4172,10 @@ void Field_varstring::sort_string(char *to,uint length) void Field_varstring::sql_type(String &res) const { CHARSET_INFO *cs=res.charset(); - ulong length= cs->snprintf(cs,(char*) res.ptr(), + ulong length= cs->cset->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) @@ -4300,7 +4313,7 @@ void Field_blob::store_length(uint32 number) if (number > 255) { number=255; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } ptr[0]= (uchar) number; break; @@ -4308,7 +4321,7 @@ void Field_blob::store_length(uint32 number) if (number > (uint16) ~0) { number= (uint16) ~0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -4323,7 +4336,7 @@ void Field_blob::store_length(uint32 number) if (number > (uint32) (1L << 24)) { number= (uint32) (1L << 24)-1L; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } int3store(ptr,number); break; @@ -4602,17 +4615,12 @@ void Field_blob::sql_type(String &res) const case 3: str="medium"; length= 6; break; case 4: str="long"; length=4; break; } - res.set_latin1(str,length); + res.set_ascii(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); - } } } @@ -4934,11 +4942,11 @@ int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) if (err || end != from+length || tmp > typelib->count) { tmp=0; - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } } else - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); } store_type((ulonglong) tmp); return err; @@ -4956,7 +4964,7 @@ int Field_enum::store(longlong nr) int error= 0; if ((uint) nr > typelib->count || nr == 0) { - current_thd->cuted_fields++; + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); nr=0; error=1; } @@ -5066,7 +5074,6 @@ void Field_enum::sql_type(String &res) const flag=1; } res.append(')'); - add_binary_or_charset(res); } @@ -5084,7 +5091,7 @@ void Field_enum::sql_type(String &res) const */ ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, - uint *err_len) + uint *err_len, bool *set_warning) { const char *end= x + length; *err_pos= 0; // No error yet @@ -5095,8 +5102,7 @@ ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, ulonglong found= 0; if (x != end) { - const char *start= x; - bool error= 0; + const char *start= x; for (;;) { const char *pos= start; @@ -5109,7 +5115,7 @@ ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, { *err_pos= (char*) start; *err_len= var_len; - error= 1; + *set_warning= 1; } else found|= ((longlong) 1 << (find - 1)); @@ -5117,8 +5123,6 @@ ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, break; start= pos + 1; } - if (error) - current_thd->cuted_fields++; } return found; } @@ -5126,6 +5130,7 @@ ulonglong find_set(TYPELIB *lib, const char *x, uint length, char **err_pos, int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { + bool set_warning= 0; int err= 0; char *not_used; uint not_used2; @@ -5138,7 +5143,7 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) from= tmpstr.ptr(); length= tmpstr.length(); } - ulonglong tmp= find_set(typelib, from, length, ¬_used, ¬_used2); + ulonglong tmp= find_set(typelib, from, length, ¬_used, ¬_used2, &set_warning); if (!tmp && length && length < 22) { /* This is for reading numbers with LOAD DATA INFILE */ @@ -5147,10 +5152,12 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) if (err || end != from+length || tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { - tmp=0; + tmp=0; + current_thd->cuted_fields++; + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED), + field_name, 0); } - else - current_thd->cuted_fields--; // Remove warning from find_set } store_type(tmp); return err; @@ -5163,8 +5170,8 @@ int Field_set::store(longlong nr) if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { - nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1); - current_thd->cuted_fields++; + nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1); + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); error=1; } store_type((ulonglong) nr); @@ -5211,7 +5218,6 @@ void Field_set::sql_type(String &res) const flag=1; } res.append(')'); - add_binary_or_charset(res); } /* returns 1 if the fields are equally defined */ @@ -5480,3 +5486,13 @@ create_field::create_field(Field *old_field,Field *orig_field) geom_type= ((Field_geom*)old_field)->geom_type; } } + + +/* Warning handling */ +void Field::set_warning(const uint level, const uint code) +{ + THD *thd= current_thd; + thd->cuted_fields++; + push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level, + code, ER(code), field_name, thd->row_count); +} diff --git a/sql/field.h b/sql/field.h index 088dae49c6f..21f2ab4b6e9 100644 --- a/sql/field.h +++ b/sql/field.h @@ -84,7 +84,8 @@ public: virtual void reset_fields() {} virtual void set_default() { - my_ptrdiff_t offset = table->default_values - table->record[0]; + my_ptrdiff_t offset = (my_ptrdiff_t) (table->default_values - + table->record[0]); memcpy(ptr, ptr + offset, pack_length()); if (null_ptr) *null_ptr= ((*null_ptr & (uchar) ~null_bit) | @@ -135,6 +136,8 @@ public: Field *tmp= (Field*) memdup_root(root,(char*) this,size_of()); if (tmp) { + if (tmp->table->maybe_null) + tmp->flags&= ~NOT_NULL_FLAG; tmp->table= new_table; tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0; tmp->unireg_check=Field::NONE; @@ -210,7 +213,9 @@ public: 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 bool has_charset(void) const { return FALSE; } virtual void set_charset(CHARSET_INFO *charset) { } + void set_warning(const unsigned int level, const unsigned int code); 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); @@ -274,12 +279,10 @@ public: 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; } 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; @@ -786,7 +789,7 @@ public: enum ha_base_keytype key_type() const { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } bool zero_pack() const { return 0; } - void reset(void) { charset()->fill(charset(),ptr,field_length,' '); } + void reset(void) { charset()->cset->fill(charset(),ptr,field_length,' '); } int store(const char *to,uint length,CHARSET_INFO *charset); int store(double nr); int store(longlong nr); @@ -804,6 +807,7 @@ public: uint max_packed_col_length(uint max_length); uint size_of() const { return sizeof(*this); } enum_field_types real_type() const { return FIELD_TYPE_STRING; } + bool has_charset(void) const { return TRUE; } }; @@ -846,6 +850,7 @@ public: uint max_packed_col_length(uint max_length); uint size_of() const { return sizeof(*this); } enum_field_types real_type() const { return FIELD_TYPE_VAR_STRING; } + bool has_charset(void) const { return TRUE; } }; @@ -933,6 +938,8 @@ public: inline void clear_temporary() { bzero((char*) &value,sizeof(value)); } friend void field_conv(Field *to,Field *from); uint size_of() const { return sizeof(*this); } + bool has_charset(void) const + { return charset() == &my_charset_bin ? FALSE : TRUE; } }; @@ -1001,6 +1008,7 @@ public: virtual bool zero_pack() const { return 0; } bool optimize_range(uint idx) { return 0; } bool eq_def(Field *field); + bool has_charset(void) const { return TRUE; } }; @@ -1025,6 +1033,7 @@ public: String *val_str(String*,String *); void sql_type(String &str) const; enum_field_types real_type() const { return FIELD_TYPE_SET; } + bool has_charset(void) const { return TRUE; } }; @@ -1109,7 +1118,7 @@ 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, - char **err_pos, uint *err_len); + char **err_pos, uint *err_len, bool *set_warning); bool test_if_int(const char *str, int length, const char *int_end, CHARSET_INFO *cs); diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 47996606638..ec2488f520a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -121,7 +121,7 @@ set_field_to_null(Field *field) field->reset(); if (current_thd->count_cuted_fields) { - current_thd->cuted_fields++; // Increment error counter + field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_DATA_TRUNCATED); return 0; } if (!current_thd->no_errors) @@ -175,7 +175,7 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) return 0; // field is set in handler.cc if (current_thd->count_cuted_fields) { - current_thd->cuted_fields++; // Increment error counter + field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_NULL_TO_NOTNULL); return 0; } if (!current_thd->no_errors) @@ -225,7 +225,8 @@ static void do_copy_not_null(Copy_field *copy) { if (*copy->from_null_ptr & copy->from_bit) { - current_thd->cuted_fields++; + copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_TRUNCATED); copy->to_field->reset(); } else @@ -324,7 +325,8 @@ static void do_cut_string(Copy_field *copy) { if (!my_isspace(system_charset_info, *ptr)) // QQ: ucs incompatible { - current_thd->cuted_fields++; // Give a warning + copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_TRUNCATED); break; } } @@ -344,7 +346,8 @@ static void do_varstring(Copy_field *copy) { length=copy->to_length-2; if (current_thd->count_cuted_fields) - current_thd->cuted_fields++; // Increment error counter + copy->to_field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_DATA_TRUNCATED); } int2store(copy->to_ptr,length); memcpy(copy->to_ptr+2, copy->from_ptr,length); diff --git a/sql/filesort.cc b/sql/filesort.cc index a3d24cd9242..2130bdaeb93 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -76,7 +76,7 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, ulong memavl, min_sort_memory; uint maxbuffer; BUFFPEK *buffpek; - ha_rows records; + ha_rows records= HA_POS_ERROR; uchar **sort_keys; IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; SORTPARAM param; @@ -494,6 +494,7 @@ static void make_sortkey(register SORTPARAM *param, sort_field != param->end ; sort_field++) { + bool maybe_null=0; if ((field=sort_field->field)) { // Field if (field->maybe_null()) @@ -519,7 +520,7 @@ static void make_sortkey(register SORTPARAM *param, case STRING_RESULT: { CHARSET_INFO *cs=item->charset(); - if (item->maybe_null) + if ((maybe_null=item->maybe_null)) *to++=1; /* All item->str() to use some extra byte for end null.. */ String tmp((char*) to,sort_field->length+4,cs); @@ -567,7 +568,7 @@ static void make_sortkey(register SORTPARAM *param, case INT_RESULT: { longlong value=item->val_int(); - if (item->maybe_null) + if ((maybe_null=item->maybe_null)) *to++=1; /* purecov: inspected */ if (item->null_value) { @@ -601,13 +602,13 @@ static void make_sortkey(register SORTPARAM *param, case REAL_RESULT: { double value=item->val(); - if (item->null_value) + if ((maybe_null=item->null_value)) { bzero((char*) to,sort_field->length+1); to++; break; } - if (item->maybe_null) + if ((maybe_null=item->maybe_null)) *to++=1; change_double_for_sort(value,(byte*) to); break; @@ -621,6 +622,8 @@ static void make_sortkey(register SORTPARAM *param, } if (sort_field->reverse) { /* Revers key */ + if (maybe_null) + to[-1]= ~to[-1]; length=sort_field->length; while (length--) { diff --git a/sql/ha_heap.h b/sql/ha_heap.h index fe874dab3f2..c369c7029b4 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -53,8 +53,9 @@ class ha_heap: public handler uint max_keys() const { return MAX_KEY; } uint max_key_parts() const { return MAX_REF_PARTS; } uint max_key_length() const { return HA_MAX_REC_LENGTH; } - virtual double scan_time() { return (double) (records+deleted) / 20.0+10; } - virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; } + double scan_time() { return (double) (records+deleted) / 20.0+10; } + double read_time(uint index, uint ranges, ha_rows rows) + { return (double) rows / 20.0+1; } virtual bool fast_key_read() { return 1;} int open(const char *name, int mode, uint test_if_locked); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 4f955d8f79e..bf4dc7e5066 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -100,7 +100,7 @@ char* innobase_unix_file_flush_method = NULL; /* Below we have boolean-valued start-up parameters, and their default values */ -uint innobase_flush_log_at_trx_commit = 0; +uint innobase_flush_log_at_trx_commit = 1; my_bool innobase_log_archive = FALSE; my_bool innobase_use_native_aio = FALSE; my_bool innobase_fast_shutdown = TRUE; @@ -242,6 +242,10 @@ convert_error_code_to_mysql( return(HA_ERR_CANNOT_ADD_FOREIGN); + } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) { + + return(HA_WRONG_CREATE_OPTION); + } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) { return(HA_ERR_CRASHED); @@ -556,12 +560,12 @@ innobase_query_caching_of_table_permitted( #endif if (row_search_check_if_query_cache_permitted(trx, norm_name)) { - printf("Query cache for %s permitted\n", norm_name); + /* printf("Query cache for %s permitted\n", norm_name); */ return((my_bool)TRUE); } - printf("Query cache for %s NOT permitted\n", norm_name); + /* printf("Query cache for %s NOT permitted\n", norm_name); */ return((my_bool)FALSE); } @@ -597,7 +601,7 @@ innobase_invalidate_query_cache( Call this when you have opened a new table handle in HANDLER, before you call index_read_idx() etc. Actually, we can let the cursor stay open even over a transaction commit! Then you should call this before every operation, -fecth next etc. This function inits the necessary things even after a +fetch next etc. This function inits the necessary things even after a transaction commit. */ void @@ -644,6 +648,8 @@ ha_innobase::init_table_handle_for_HANDLER(void) we???? */ prebuilt->read_just_key = FALSE; + + prebuilt->used_in_HANDLER = TRUE; } /************************************************************************* @@ -883,7 +889,7 @@ innobase_flush_logs(void) DBUG_ENTER("innobase_flush_logs"); - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); DBUG_RETURN(result); } @@ -932,7 +938,7 @@ Commits a transaction in an InnoDB database. */ int innobase_commit( /*============*/ - /* out: 0 or error number */ + /* out: 0 */ THD* thd, /* in: MySQL thread handle of the user for whom the transaction should be committed */ void* trx_handle)/* in: InnoDB trx handle or @@ -940,7 +946,6 @@ innobase_commit( that the current SQL statement ended, and we should mark the start of a new statement with a savepoint */ { - int error = 0; trx_t* trx; DBUG_ENTER("innobase_commit"); @@ -967,29 +972,27 @@ innobase_commit( innobase_release_stat_resources(trx); trx_mark_sql_stat_end(trx); -#ifndef DBUG_OFF - if (error) { - DBUG_PRINT("error", ("error: %d", error)); - } -#endif /* Tell InnoDB server that there might be work for utility threads: */ srv_active_wake_master_thread(); - DBUG_RETURN(error); + DBUG_RETURN(0); } /********************************************************************* This is called when MySQL writes the binlog entry for the current transaction. Writes to the InnoDB tablespace info which tells where the MySQL binlog entry for the current transaction ended. Also commits the -transaction inside InnoDB. */ +transaction inside InnoDB but does NOT flush InnoDB log files to disk. +To flush you have to call innobase_flush_log_to_disk. We have separated +flushing to eliminate the bottleneck of LOCK_log in log.cc which disabled +InnoDB's group commit capability. */ int innobase_report_binlog_offset_and_commit( /*=====================================*/ - /* out: 0 or error code */ + /* out: 0 */ THD* thd, /* in: user thread */ void* trx_handle, /* in: InnoDB trx handle */ char* log_file_name, /* in: latest binlog file name */ @@ -1005,7 +1008,39 @@ innobase_report_binlog_offset_and_commit( trx->mysql_log_file_name = log_file_name; trx->mysql_log_offset = (ib_longlong)end_offset; - return(innobase_commit(thd, trx_handle)); + trx->flush_log_later = TRUE; + + innobase_commit(thd, trx_handle); + + trx->flush_log_later = FALSE; + + return(0); +} + +/********************************************************************* +This is called after MySQL has written the binlog entry for the current +transaction. Flushes the InnoDB log files to disk if required. */ + +int +innobase_commit_complete( +/*=====================*/ + /* out: 0 */ + void* trx_handle) /* in: InnoDB trx handle */ +{ + trx_t* trx; + + if (srv_flush_log_at_trx_commit == 0) { + + return(0); + } + + trx = (trx_t*)trx_handle; + + ut_a(trx != NULL); + + trx_commit_complete_for_mysql(trx); + + return(0); } /********************************************************************* @@ -1195,6 +1230,9 @@ ha_innobase::open( last_query_id = (ulong)-1; + active_index = 0; + active_index_before_scan = (uint)-1; /* undefined value */ + if (!(share=get_share(name))) DBUG_RETURN(1); @@ -1938,13 +1976,6 @@ ha_innobase::write_row( build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW); } - if (user_thd->lex.sql_command == SQLCOM_INSERT - && user_thd->lex.duplicates == DUP_IGNORE) { - prebuilt->trx->ignore_duplicates_in_insert = TRUE; - } else { - prebuilt->trx->ignore_duplicates_in_insert = FALSE; - } - srv_conc_enter_innodb(prebuilt->trx); error = row_insert_for_mysql((byte*) record, prebuilt); @@ -1985,8 +2016,6 @@ ha_innobase::write_row( } } - prebuilt->trx->ignore_duplicates_in_insert = FALSE; - error = convert_error_code_to_mysql(error, user_thd); /* Tell InnoDB server that there might be work for @@ -2057,7 +2086,8 @@ calc_row_difference( upd_t* uvect, /* in/out: update vector */ mysql_byte* old_row, /* in: old row in MySQL format */ mysql_byte* new_row, /* in: new row in MySQL format */ - struct st_table* table, /* in: table in MySQL data dictionary */ + struct st_table* table, /* in: table in MySQL data + dictionary */ mysql_byte* upd_buff, /* in: buffer to use */ row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */ THD* thd) /* in: user thread */ @@ -2107,8 +2137,10 @@ calc_row_difference( case DATA_VARCHAR: case DATA_BINARY: case DATA_VARMYSQL: - o_ptr = row_mysql_read_var_ref_noninline(&o_len, o_ptr); - n_ptr = row_mysql_read_var_ref_noninline(&n_len, n_ptr); + o_ptr = row_mysql_read_var_ref_noninline(&o_len, + o_ptr); + n_ptr = row_mysql_read_var_ref_noninline(&n_len, + n_ptr); default: ; } @@ -2556,7 +2588,7 @@ ha_innobase::change_active_index( /* 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 + and then calculates the 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. */ @@ -2755,6 +2787,11 @@ ha_innobase::rnd_init( row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; + /* Store the active index value so that we can restore the original + value after a scan */ + + active_index_before_scan = active_index; + if (prebuilt->clust_index_was_generated) { err = change_active_index(MAX_KEY); } else { @@ -2767,13 +2804,25 @@ ha_innobase::rnd_init( } /********************************************************************* -Ends a table scan ???????????????? */ +Ends a table scan. */ int ha_innobase::rnd_end(void) /*======================*/ /* out: 0 or error number */ { + /* Restore the old active_index back; MySQL may assume that a table + scan does not change active_index. We only restore the value if + MySQL has called rnd_init before: sometimes MySQL seems to call + rnd_end WITHOUT calling rnd_init. */ + + if (active_index_before_scan != (uint)-1) { + + change_active_index(active_index_before_scan); + + active_index_before_scan = (uint)-1; + } + return(index_end()); } @@ -3088,6 +3137,9 @@ ha_innobase::create( trx_search_latch_release_if_reserved(parent_trx); trx = trx_allocate_for_mysql(); + + trx->mysql_thd = thd; + trx->mysql_query_str = &((*thd).query); if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -3216,7 +3268,7 @@ ha_innobase::create( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); innobase_table = dict_table_get(norm_name, NULL); @@ -3271,6 +3323,9 @@ ha_innobase::delete_table( trx = trx_allocate_for_mysql(); + trx->mysql_thd = current_thd; + trx->mysql_query_str = &((*current_thd).query); + name_len = strlen(name); assert(name_len < 1000); @@ -3288,7 +3343,7 @@ ha_innobase::delete_table( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3349,6 +3404,8 @@ innobase_drop_database( my_casedn_str(system_charset_info, namebuf); #endif trx = trx_allocate_for_mysql(); + trx->mysql_thd = current_thd; + trx->mysql_query_str = &((*current_thd).query); error = row_drop_database_for_mysql(namebuf, trx); @@ -3356,7 +3413,7 @@ innobase_drop_database( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3408,6 +3465,8 @@ ha_innobase::rename_table( } trx = trx_allocate_for_mysql(); + trx->mysql_thd = current_thd; + trx->mysql_query_str = &((*current_thd).query); name_len1 = strlen(from); name_len2 = strlen(to); @@ -3426,7 +3485,7 @@ ha_innobase::rename_table( the InnoDB data dictionary get out-of-sync if the user runs with innodb_flush_log_at_trx_commit = 0 */ - log_flush_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP); + log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE); /* Tell the InnoDB server that there might be work for utility threads: */ @@ -3541,10 +3600,8 @@ ha_innobase::records_in_range( /************************************************************************* Gives an UPPER BOUND to the number of rows in a table. This is used in -filesort.cc and the upper bound must hold. TODO: Since the number of -rows in a table may change after this function is called, we still may -get a 'Sort aborted' error in filesort.cc of MySQL. The ultimate fix is to -improve the algorithm of filesort.cc. */ +filesort.cc and its better if the upper bound hold. +*/ ha_rows ha_innobase::estimate_number_of_rows(void) @@ -3610,6 +3667,29 @@ ha_innobase::scan_time() return((double) (prebuilt->table->stat_clustered_index_size)); } +/* + Calculate the time it takes to read a set of ranges through and index + This enables us to optimise reads for clustered indexes. +*/ + +double ha_innobase::read_time(uint index, uint ranges, ha_rows rows) +{ + ha_rows total_rows; + double time_for_scan; + if (index != table->primary_key) + return handler::read_time(index, ranges, rows); // Not clustered + if (rows <= 2) + return (double) rows; + /* + Assume that the read is proportional to scan time for all rows + one + seek per range. + */ + time_for_scan= scan_time(); + if ((total_rows= estimate_number_of_rows()) < rows) + return time_for_scan; + return (ranges + (double) rows / (double) total_rows * time_for_scan); +} + /************************************************************************* Returns statistics information of the table to the MySQL interpreter, in various fields of the handle object. */ @@ -3734,6 +3814,23 @@ ha_innobase::info( DBUG_VOID_RETURN; } +/************************************************************************** +Updates index cardinalities of the table, based on 10 random dives into +each index tree. This does NOT calculate exact statistics of the table. */ + +int +ha_innobase::analyze( +/*=================*/ + /* out: returns always 0 (success) */ + THD* thd, /* in: connection thread handle */ + HA_CHECK_OPT* check_opt) /* in: currently ignored */ +{ + /* Simply call ::info() with all the flags */ + info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); + + return(0); +} + /*********************************************************************** Tries to check that an InnoDB table is not corrupted. If corruption is noticed, prints to stderr information about it. In case of corruption @@ -3915,7 +4012,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: prebuilt->read_just_key = 0; - break; + break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; break; @@ -4084,6 +4181,8 @@ ha_innobase::external_lock( trx->mysql_n_tables_locked = 0; + prebuilt->used_in_HANDLER = FALSE; + /* Here we release the search latch and InnoDB thread FIFO ticket if they were reserved. */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index be1174added..9ca8475e75e 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -58,7 +58,15 @@ class ha_innobase: public handler ulong start_of_scan; /* this is set to 1 when we are starting a table scan but have not yet fetched any row, else 0 */ - + uint active_index_before_scan; + /* since a table scan in InnoDB is + always done through an index, a table + scan may change active_index; but + MySQL may assume that active_index + after a table scan is the same as + before; we store the value here so + that we can restore the value after + a scan */ uint last_match_mode;/* match mode of the latest search: ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX, or undefined */ @@ -118,6 +126,7 @@ class ha_innobase: public handler void initialize(void); int close(void); double scan_time(); + double read_time(uint index, uint ranges, ha_rows rows); int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); @@ -143,6 +152,7 @@ class ha_innobase: public handler void position(const byte *record); void info(uint); + int analyze(THD* thd,HA_CHECK_OPT* check_opt); int extra(enum ha_extra_function operation); int reset(void); int external_lock(THD *thd, int lock_type); @@ -189,6 +199,9 @@ extern char *innobase_unix_file_flush_method; /* The following variables have to be my_bool for SHOW VARIABLES to work */ extern my_bool innobase_log_archive, innobase_use_native_aio, innobase_fast_shutdown; +extern "C" { +extern ulong srv_max_buf_pool_modified_pct; +} extern TYPELIB innobase_lock_typelib; @@ -203,6 +216,8 @@ int innobase_report_binlog_offset_and_commit( void* trx_handle, char* log_file_name, my_off_t end_offset); +int innobase_commit_complete( + void* trx_handle); int innobase_rollback(THD *thd, void* trx_handle); int innobase_close_connection(THD *thd); int innobase_drop_database(char *path); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 213f5baf388..a9c3ddaef60 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -499,7 +499,7 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) param.thd = thd; param.op_name = (char*) "repair"; param.testflag = ((check_opt->flags & ~(T_EXTEND)) | - T_SILENT | T_FORCE_CREATE | + T_SILENT | T_FORCE_CREATE | T_CALC_CHECKSUM | (check_opt->flags & T_EXTEND ? T_REP : T_REP_BY_SORT)); param.sort_buffer_length= check_opt->sort_buffer_size; start_records=file->state->records; @@ -592,10 +592,24 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) { local_testflag|= T_STATISTICS; param.testflag|= T_STATISTICS; // We get this for free - thd->proc_info="Repair by sorting"; statistics_done=1; - error = mi_repair_by_sort(¶m, file, fixed_name, - param.testflag & T_QUICK); + if (current_thd->variables.myisam_repair_threads>1) + { + char buf[40]; + /* TODO: respect myisam_repair_threads variable */ + my_snprintf(buf, 40, "Repair with %d threads", my_count_bits(key_map)); + thd->proc_info=buf; + error = mi_repair_parallel(¶m, file, fixed_name, + param.testflag & T_QUICK); + thd->proc_info="Repair done"; // to reset proc_info, as + // it was pointing to local buffer + } + else + { + thd->proc_info="Repair by sorting"; + error = mi_repair_by_sort(¶m, file, fixed_name, + param.testflag & T_QUICK); + } } else { diff --git a/sql/handler.cc b/sql/handler.cc index f2b7dbdf531..db1857e938c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -253,6 +253,9 @@ int ha_autocommit_or_rollback(THD *thd, int error) replication. This function also calls the commit of the table handler, because the order of transactions in the log of the table handler must be the same as in the binlog. + NOTE that to eliminate the bottleneck of the group commit, we do not + flush the handler log files here, but only later in a call of + ha_commit_complete(). arguments: thd: the thread handle of the current connection @@ -279,13 +282,38 @@ int ha_report_binlog_offset_and_commit(THD *thd, my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); error=1; } - trans->innodb_active_trans=0; } #endif return error; } /* + Flushes the handler log files (if my.cnf settings do not free us from it) + after we have called ha_report_binlog_offset_and_commit(). To eliminate + the bottleneck from the group commit, this should be called when + LOCK_log has been released in log.cc. + + arguments: + thd: the thread handle of the current connection + return value: always 0 +*/ + +int ha_commit_complete(THD *thd) +{ +#ifdef HAVE_INNOBASE_DB + THD_TRANS *trans; + trans = &thd->transaction.all; + if (trans->innobase_tid) + { + innobase_commit_complete(trans->innobase_tid); + + trans->innodb_active_trans=0; + } +#endif + return 0; +} + +/* This function should be called when MySQL sends rows of a SELECT result set or the EOF mark to the client. It releases a possible adaptive hash index S-latch held by thd in InnoDB and also releases a possible InnoDB query @@ -812,7 +840,8 @@ void handler::print_error(int error, myf errflag) DBUG_VOID_RETURN; } - /* Return key if error because of duplicated keys */ + +/* Return key if error because of duplicated keys */ uint handler::get_dup_key(int error) { @@ -823,6 +852,7 @@ uint handler::get_dup_key(int error) DBUG_RETURN(table->file->errkey); } + int handler::delete_table(const char *name) { int error=0; @@ -849,9 +879,10 @@ int handler::rename_table(const char * from, const char * to) DBUG_RETURN(0); } -/* Tell the handler to turn on or off logging to the handler's - recovery log +/* + Tell the handler to turn on or off logging to the handler's recovery log */ + int ha_recovery_logging(THD *thd, bool on) { int error=0; @@ -906,7 +937,6 @@ bool handler::caching_allowed(THD* thd, char* table_key, int ha_create_table(const char *name, HA_CREATE_INFO *create_info, bool update_create_info) - { int error; TABLE table; diff --git a/sql/handler.h b/sql/handler.h index 8c23a3625e0..97ce295d520 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -235,7 +235,8 @@ public: void change_table_ptr(TABLE *table_arg) { table=table_arg; } virtual double scan_time() { return ulonglong2double(data_file_length) / IO_SIZE + 1; } - virtual double read_time(ha_rows rows) { return rows2double(rows); } + virtual double read_time(uint index, uint ranges, ha_rows rows) + { return rows2double(ranges+rows); } virtual bool fast_key_read() { return 0;} virtual key_map keys_to_use_for_scanning() { return 0; } virtual bool has_transactions(){ return 0;} @@ -389,6 +390,7 @@ void ha_resize_key_cache(void); int ha_start_stmt(THD *thd); int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name, my_off_t end_offset); +int ha_commit_complete(THD *thd); int ha_release_temporary_latches(THD *thd); int ha_commit_trans(THD *thd, THD_TRANS *trans); int ha_rollback_trans(THD *thd, THD_TRANS *trans); diff --git a/sql/init.cc b/sql/init.cc index 8834fd3a89c..50d504068a0 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -38,13 +38,11 @@ void unireg_init(ulong options) init_my_atof(); /* use our atof */ #endif my_abort_hook=unireg_abort; /* Abort with close of databases */ - f_fyllchar=' '; /* Input fill char */ VOID(strmov(reg_ext,".frm")); for (i=0 ; i < 6 ; i++) // YYMMDDHHMMSS dayord.pos[i]=i; specialflag=SPECIAL_SAME_DB_NAME; - blob_newline='^'; /* Convert newline in blobs to this */ /* Make a tab of powers of 10 */ for (i=0,nr=1.0; i < array_elements(log_10) ; i++) { /* It's used by filesort... */ diff --git a/sql/item.cc b/sql/item.cc index 053a94cb695..42a949287e5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -90,28 +90,32 @@ bool Item::check_cols(uint c) return 0; } -void Item::set_name(const char *str,uint length, CHARSET_INFO *cs) + +void Item::set_name(const char *str, uint length, CHARSET_INFO *cs) { if (!length) - name= (char*) str; // Empty string, used by AS - else { - while (length && !my_isgraph(cs,*str)) - { // Fix problem with yacc - length--; - str++; - } - if (length && !my_charset_same(cs, system_charset_info)) - { - String tmp; - tmp.copy(str, length, cs, system_charset_info); - name=sql_strmake(tmp.ptr(),min(tmp.length(),MAX_FIELD_WIDTH)); - } - else - name=sql_strmake(str,min(length,MAX_FIELD_WIDTH)); + /* Empty string, used by AS or internal function like last_insert_id() */ + name= (char*) str; + return; } + while (length && !my_isgraph(cs,*str)) + { // Fix problem with yacc + length--; + str++; + } + if (!my_charset_same(cs, system_charset_info)) + { + uint32 res_length; + name= sql_strmake_with_convert(str, length, cs, + MAX_ALIAS_NAME, system_charset_info, + &res_length); + } + else + name=sql_strmake(str, min(length,MAX_ALIAS_NAME)); } + /* This function is only called when comparing items in the WHERE clause */ @@ -1048,6 +1052,7 @@ inline uint char_val(char X) X-'a'+10); } + Item_varbinary::Item_varbinary(const char *str, uint str_length) { name=(char*) str-2; // Lex makes this start with 0x @@ -1447,7 +1452,7 @@ bool Item_insert_value::fix_fields(THD *thd, struct st_table_list *table_list, I Field *field=field_arg->field; /* charset doesn't matter here, it's to avoid sigsegv only */ set_field(new Field_null(0,0,Field::NONE,field->field_name,field->table, - default_charset_info)); + &my_charset_bin)); } return 0; } diff --git a/sql/item.h b/sql/item.h index 470937f8ee7..2d285bbe434 100644 --- a/sql/item.h +++ b/sql/item.h @@ -644,6 +644,7 @@ public: #include "item_row.h" #include "item_cmpfunc.h" #include "item_strfunc.h" +#include "item_geofunc.h" #include "item_timefunc.h" #include "item_uniq.h" #include "item_subselect.h" diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index e2885c8764a..299014689f0 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -90,7 +90,7 @@ static bool convert_constant_item(Field *field, Item **item) bool Item_bool_func2::set_cmp_charset(CHARSET_INFO *cs1, enum coercion co1, CHARSET_INFO *cs2, enum coercion co2) { - if((cs1 == &my_charset_bin) || (cs2 == &my_charset_bin)) + if ((cs1 == &my_charset_bin) || (cs2 == &my_charset_bin)) { cmp_charset= &my_charset_bin; return 0; @@ -114,32 +114,104 @@ bool Item_bool_func2::set_cmp_charset(CHARSET_INFO *cs1, enum coercion co1, { if (co1 == COER_COERCIBLE) { - CHARSET_INFO *c= get_charset_by_csname(cs1->csname,MY_CS_PRIMARY,MYF(0)); - if (c) + CHARSET_INFO *c; + if ((c= get_charset_by_csname(cs1->csname, MY_CS_PRIMARY, MYF(0)))) { cmp_charset= c; return 0; } - else - return 1; } - else - return 1; + return 1; + } + } + return 0; +} + + +bool Item_bool_func2::fix_fields(THD *thd, struct st_table_list *tables, + Item ** ref) +{ + if (Item_int_func::fix_fields(thd, tables, ref)) + return 1; + + /* + We allow to convert to Unicode character sets in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + - character set of A is superset for character set of B + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + */ + + if (args[0] && args[1]) + { + uint strong= 0; + uint weak= 0; + + if ((args[0]->coercibility < args[1]->coercibility) && + !my_charset_same(args[0]->charset(), args[1]->charset()) && + (args[0]->charset()->state & MY_CS_UNICODE)) + { + weak= 1; + } + else if ((args[1]->coercibility < args[0]->coercibility) && + !my_charset_same(args[0]->charset(), args[1]->charset()) && + (args[1]->charset()->state & MY_CS_UNICODE)) + { + strong= 1; + } + + if (strong || weak) + { + Item* conv= 0; + if (args[weak]->type() == STRING_ITEM) + { + String tmp, cstr; + String *ostr= args[weak]->val_str(&tmp); + cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(), + args[strong]->charset()); + conv= new Item_string(cstr.ptr(),cstr.length(),cstr.charset(), + args[weak]->coercibility); + ((Item_string*)conv)->str_value.copy(); + } + else + { + conv= new Item_func_conv_charset(args[weak],args[strong]->charset()); + conv->coercibility= args[weak]->coercibility; + } + args[weak]= conv ? conv : args[weak]; + set_cmp_charset(args[0]->charset(), args[0]->coercibility, + args[1]->charset(), args[1]->coercibility); } } + if (!cmp_charset) + { + /* set_cmp_charset() failed */ + my_error(ER_CANT_AGGREGATE_COLLATIONS,MYF(0), + args[0]->charset()->name,coercion_name(args[0]->coercibility), + args[1]->charset()->name,coercion_name(args[1]->coercibility), + func_name()); + return 1; + } return 0; } + void Item_bool_func2::fix_length_and_dec() { max_length= 1; // Function returns 0 or 1 /* As some compare functions are generated after sql_yacc, - we have to check for out of memory conditons here + we have to check for out of memory conditions here */ if (!args[0] || !args[1]) return; + + // Make a special case of compare with fields to get nicer DATE comparisons if (args[0]->type() == FIELD_ITEM) { @@ -149,7 +221,8 @@ void Item_bool_func2::fix_length_and_dec() if (convert_constant_item(field,&args[1])) { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, - INT_RESULT); // Works for all types. + INT_RESULT); // Works for all types. + cmp_charset= &my_charset_bin; // For test in fix_fields return; } } @@ -163,20 +236,19 @@ void Item_bool_func2::fix_length_and_dec() { cmp.set_cmp_func(this, tmp_arg, tmp_arg+1, INT_RESULT); // Works for all types. + cmp_charset= &my_charset_bin; // For test in fix_fields return; } } } - if (set_cmp_charset(args[0]->charset(), args[0]->coercibility, - args[1]->charset(), args[1]->coercibility)) - { - my_error(ER_CANT_AGGREGATE_COLLATIONS,MYF(0), - args[0]->charset()->name,coercion_name(args[0]->coercibility), - args[1]->charset()->name,coercion_name(args[1]->coercibility), - func_name()); - return; - } set_cmp_func(); + /* + We must set cmp_charset here as we may be called from for an automatic + generated item, like in natural join + */ +end: + set_cmp_charset(args[0]->charset(), args[0]->coercibility, + args[1]->charset(), args[1]->coercibility); } @@ -194,22 +266,22 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) comparators= 0; return 1; } - if ((comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) - for (uint i=0; i < n; i++) + if (!(comparators= (Arg_comparator *) sql_alloc(sizeof(Arg_comparator)*n))) + return 1; + for (uint i=0; i < n; i++) + { + if ((*a)->el(i)->cols() != (*b)->el(i)->cols()) { - 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)); + my_error(ER_CARDINALITY_COL, MYF(0), (*a)->el(i)->cols()); + return 1; } - else - return 1; + comparators[i].set_cmp_func(owner, (*a)->addr(i), (*b)->addr(i)); + } } return 0; } + int Arg_comparator::compare_string() { String *res1,*res2; @@ -1419,7 +1491,7 @@ bool Item_func_in::nulls_in_row() static int srtcmp_in(const String *x,const String *y) { CHARSET_INFO *cs= x->charset(); - return cs->strnncollsp(cs, + return cs->coll->strnncollsp(cs, (unsigned char *) x->ptr(),x->length(), (unsigned char *) y->ptr(),y->length()); } @@ -1427,7 +1499,7 @@ static int srtcmp_in(const String *x,const String *y) static int bincmp_in(const String *x,const String *y) { CHARSET_INFO *cs= &my_charset_bin; - return cs->strnncollsp(cs, + return cs->coll->strnncollsp(cs, (unsigned char *) x->ptr(),x->length(), (unsigned char *) y->ptr(),y->length()); } @@ -1884,16 +1956,6 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) if (Item_bool_func2::fix_fields(thd, tlist, ref)) return 1; - if (set_cmp_charset(args[0]->charset(), args[0]->coercibility, - args[1]->charset(), args[1]->coercibility)) - { - my_error(ER_CANT_AGGREGATE_COLLATIONS,MYF(0), - args[0]->charset()->name,coercion_name(args[0]->coercibility), - args[1]->charset()->name,coercion_name(args[1]->coercibility), - func_name()); - return 1; - } - /* 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. @@ -2301,85 +2363,3 @@ 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() + SRID_SIZE, - res1->length() - SRID_SIZE) || - g2.create_from_wkb(res2->ptr() + SRID_SIZE, - res2->length() - SRID_SIZE) || - 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 *swkb= args[0]->val_str(&tmp); - Geometry geom; - int isclosed; - - null_value= (!swkb || - args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !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 5e246e3e285..4438b902011 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -116,7 +116,8 @@ protected: public: Item_bool_func2(Item *a,Item *b): - Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1) {} + Item_int_func(a,b), cmp(tmp_arg, tmp_arg+1), cmp_charset(0) {} + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref); void fix_length_and_dec(); void set_cmp_func() { @@ -849,79 +850,3 @@ inline Item *and_conds(Item *a,Item *b) } 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_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) : - Item_bool_func2(a,b) { spatial_rel = sp_rel; } - longlong val_int(); - 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"; - } - } -}; - - -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 1e547a9c76e..00c98937659 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -321,10 +321,10 @@ Item *create_func_current_user() char buff[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; uint length; - length= (uint) (strxmov(buff, thd->priv_user, "@", thd->host_or_ip, NullS) - + length= (uint) (strxmov(buff, thd->priv_user, "@", thd->priv_host, NullS) - buff); return new Item_string(NullS, thd->memdup(buff, length), length, - default_charset_info); + system_charset_info); } Item *create_func_quarter(Item* a) @@ -437,7 +437,7 @@ Item *create_func_version(void) { return new Item_string(NullS,server_version, (uint) strlen(server_version), - system_charset_info); + system_charset_info, Item::COER_IMPLICIT); } Item *create_func_weekday(Item* a) @@ -457,13 +457,16 @@ Item *create_load_file(Item* a) } -Item *create_func_cast(Item *a, Item_cast cast_type) +Item *create_func_cast(Item *a, Item_cast cast_type, CHARSET_INFO *cs) { Item *res; LINT_INIT(res); switch (cast_type) { case ITEM_CAST_BINARY: res= new Item_func_binary(a); break; - case ITEM_CAST_CHAR: res= new Item_char_typecast(a); break; + case ITEM_CAST_CHAR: + res= (cs == NULL) ? (Item*) new Item_char_typecast(a) : + (Item*) new Item_func_conv_charset(a,cs); + break; case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break; case ITEM_CAST_UNSIGNED_INT: res= new Item_func_unsigned(a); break; case ITEM_CAST_DATE: res= new Item_date_typecast(a); break; diff --git a/sql/item_create.h b/sql/item_create.h index c79fe07b8d4..b679c639244 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -28,7 +28,7 @@ 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_cast(Item *a, Item_cast cast_type, CHARSET_INFO *cs); Item *create_func_connection_id(void); Item *create_func_conv(Item* a, Item *b, Item *c); Item *create_func_cos(Item* a); diff --git a/sql/item_func.cc b/sql/item_func.cc index 6af65ece692..6482d81f484 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -40,8 +40,8 @@ eval_const_cond(COND *cond) } -Item_func::Item_func(List<Item> &list): - allowed_arg_cols(1) +Item_func::Item_func(List<Item> &list) + :allowed_arg_cols(1) { arg_count=list.elements; if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) @@ -109,15 +109,18 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { // Print purify happy for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { + Item *item; + /* We can't yet set item to *arg as fix_fields may change *arg */ if ((*arg)->fix_fields(thd, tables, arg) || (*arg)->check_cols(allowed_arg_cols)) return 1; /* purecov: inspected */ - if ((*arg)->maybe_null) + item= *arg; + if (item->maybe_null) maybe_null=1; - with_sum_func= with_sum_func || (*arg)->with_sum_func; - used_tables_cache|=(*arg)->used_tables(); - const_item_cache&= (*arg)->const_item(); + with_sum_func= with_sum_func || item->with_sum_func; + used_tables_cache|=item->used_tables(); + const_item_cache&= item->const_item(); } } fix_length_and_dec(); @@ -140,14 +143,15 @@ 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++) { - 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) + Item *item=* arg; + if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) + 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(*arg); - ref_pointer_array[el]= *arg; - *arg= new Item_ref(ref_pointer_array + el, 0, (*arg)->name); + fields.push_front(item); + ref_pointer_array[el]= item; + *arg= new Item_ref(ref_pointer_array + el, 0, item->name); } } } @@ -1250,47 +1254,6 @@ longlong Item_func_find_in_set::val_int() return 0; } -static char nbits[256] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, -}; - -uint count_bits(ulonglong v) -{ -#if SIZEOF_LONG_LONG > 4 - /* The following code is a bit faster on 16 bit machines than if we would - only shift v */ - ulong v2=(ulong) (v >> 32); - return (uint) (uchar) (nbits[(uchar) v] + - nbits[(uchar) (v >> 8)] + - nbits[(uchar) (v >> 16)] + - nbits[(uchar) (v >> 24)] + - nbits[(uchar) (v2)] + - nbits[(uchar) (v2 >> 8)] + - nbits[(uchar) (v2 >> 16)] + - nbits[(uchar) (v2 >> 24)]); -#else - return (uint) (uchar) (nbits[(uchar) v] + - nbits[(uchar) (v >> 8)] + - nbits[(uchar) (v >> 16)] + - nbits[(uchar) (v >> 24)]); -#endif -} - longlong Item_func_bit_count::val_int() { ulonglong value= (ulonglong) args[0]->val_int(); @@ -1299,7 +1262,7 @@ longlong Item_func_bit_count::val_int() null_value=1; /* purecov: inspected */ return 0; /* purecov: inspected */ } - return (longlong) count_bits(value); + return (longlong) my_count_bits(value); } @@ -1373,16 +1336,17 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, arg != arg_end ; arg++,i++) { - if ((*arg)->fix_fields(thd, tables, arg) || (*arg)->check_cols(1)) + Item *item= *arg; + if (item->fix_fields(thd, tables, arg) || item->check_cols(1)) return 1; - if ((*arg)->binary()) + if (item->binary()) func->set_charset(&my_charset_bin); - if ((*arg)->maybe_null) + if (item->maybe_null) func->maybe_null=1; - func->with_sum_func= func->with_sum_func || (*arg)->with_sum_func; - used_tables_cache|=(*arg)->used_tables(); - const_item_cache&=(*arg)->const_item(); - f_args.arg_type[i]=(*arg)->result_type(); + func->with_sum_func= func->with_sum_func || item->with_sum_func; + used_tables_cache|=item->used_tables(); + const_item_cache&=item->const_item(); + f_args.arg_type[i]=item->result_type(); } if (!(buffers=new String[arg_count]) || !(f_args.args= (char**) sql_alloc(arg_count * sizeof(char *))) || @@ -2452,7 +2416,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) used_tables_cache|=item->used_tables(); } /* check that all columns come from the same table */ - if (count_bits(used_tables_cache) != 1) + if (my_count_bits(used_tables_cache) != 1) key=NO_SUCH_KEY; const_item_cache=0; table=((Item_field *)fields.head())->field->table; @@ -2626,10 +2590,7 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name) char buff[MAX_SYS_VAR_LENGTH+3+8], *pos; if (!(var= find_sys_var(name.str, name.length))) - { - net_printf(thd, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); return 0; - } if (!(item=var->item(thd, var_type))) return 0; // Impossible thd->lex.uncacheable(); @@ -2719,139 +2680,3 @@ longlong Item_func_is_used_lock::val_int() null_value=0; return ull->thread_id; } - - - -/************************************************************************** - Spatial functions -***************************************************************************/ - -longlong Item_func_dimension::val_int() -{ - uint32 dim; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - geom.dimension(&dim)); - return (longlong) dim; -} - -longlong Item_func_numinteriorring::val_int() -{ - uint32 num; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !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 *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, num_geometries) || - geom.num_geometries(&num)); - return (longlong) num; -} - -longlong Item_func_numpoints::val_int() -{ - uint32 num; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, num_points) || - geom.num_points(&num)); - return (longlong) num; -} - - -double Item_func_x::val() -{ - double res; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, get_x) || - geom.get_x(&res)); - return res; -} - - -double Item_func_y::val() -{ - double res; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, get_y) || - geom.get_y(&res)); - return res; -} - - -double Item_func_area::val() -{ - double res; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, area) || - geom.area(&res)); - return res; -} - - -double Item_func_glength::val() -{ - double res; - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, length) || - geom.length(&res)); - return res; -} - - -longlong Item_func_srid::val_int() -{ - String *swkb= args[0]->val_str(&value); - Geometry geom; - - null_value= (!swkb || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE)); - uint32 res= uint4korr(swkb->ptr()); - return (longlong) res; -} diff --git a/sql/item_func.h b/sql/item_func.h index e1d6156c12c..8ef2b85de52 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1037,101 +1037,6 @@ public: }; -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"; } -}; - - -class Item_func_srid: public Item_int_func -{ - String value; -public: - Item_func_srid(Item *a): Item_int_func(a) {} - longlong val_int(); - const char *func_name() const { return "srid"; } - void fix_length_and_dec() { max_length= 10; } -}; - - class Item_func_match_nl :public Item_func_match { public: diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc new file mode 100644 index 00000000000..fa858922c1b --- /dev/null +++ b/sql/item_geofunc.cc @@ -0,0 +1,653 @@ +/* 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 */ + + +/* This file defines all spatial functions */ + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" +#include "sql_acl.h" +#include <m_ctype.h> + +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()); + uint32 srid; + + if ((arg_count == 2) && !args[1]->null_value) + srid= args[1]->val_int(); + else + srid= 0; + + if (str->reserve(SRID_SIZE, 512)) + return 0; + str->length(0); + str->q_append(srid); + 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_geometry_from_wkb::val_str(String *str) +{ + String arg_val; + String *wkb= args[0]->val_str(&arg_val); + Geometry geom; + uint32 srid; + + if ((arg_count == 2) && !args[1]->null_value) + srid= args[1]->val_int(); + else + srid= 0; + + if (str->reserve(SRID_SIZE, 512)) + return 0; + str->length(0); + str->q_append(srid); + if ((null_value= (args[0]->null_value || + geom.create_from_wkb(wkb->ptr(), wkb->length())))) + return 0; + + str->append(*wkb); + return str; +} + + +void Item_func_geometry_from_wkb::fix_length_and_dec() +{ + max_length=MAX_BLOB_WIDTH; +} + + +String *Item_func_as_text::val_str(String *str) +{ + String arg_val; + String *swkb= args[0]->val_str(&arg_val); + Geometry geom; + + if ((null_value= (args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE)))) + 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_as_wkb::val_str(String *str) +{ + String arg_val; + String *swkb= args[0]->val_str(&arg_val); + Geometry geom; + + if ((null_value= (args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE)))) + return 0; + + str->copy(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE, + &my_charset_bin); + return str; +} + +void Item_func_as_wkb::fix_length_and_dec() +{ + max_length= MAX_BLOB_WIDTH; +} + +String *Item_func_geometry_type::val_str(String *str) +{ + String *swkb= args[0]->val_str(str); + Geometry geom; + + if ((null_value= (args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE)))) + return 0; + str->copy(geom.get_class_info()->m_name, + strlen(geom.get_class_info()->m_name), + default_charset()); + return str; +} + + +String *Item_func_envelope::val_str(String *str) +{ + String arg_val; + String *swkb= args[0]->val_str(&arg_val); + Geometry geom; + + if ((null_value= args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE))) + return 0; + + uint32 srid= uint4korr(swkb->ptr()); + str->length(0); + if (str->reserve(SRID_SIZE, 512)) + return 0; + str->q_append(srid); + return (null_value= geom.envelope(str)) ? 0 : str; +} + + +String *Item_func_centroid::val_str(String *str) +{ + String arg_val; + String *swkb= args[0]->val_str(&arg_val); + Geometry geom; + + if ((null_value= args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, centroid))) + return 0; + + if (str->reserve(SRID_SIZE, 512)) + return 0; + str->length(0); + uint32 srid= uint4korr(swkb->ptr()); + str->q_append(srid); + + return (null_value= geom.centroid(str)) ? 0 : str; +} + + +/* + Spatial decomposition functions +*/ + +String *Item_func_spatial_decomp::val_str(String *str) +{ + String arg_val; + String *swkb= args[0]->val_str(&arg_val); + Geometry geom; + + if ((null_value= (args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE)))) + return 0; + + null_value= 1; + if (str->reserve(SRID_SIZE, 512)) + return 0; + str->length(0); + uint32 srid= uint4korr(swkb->ptr()); + str->q_append(srid); + 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 *swkb= 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(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE)))) + return 0; + + null_value= 1; + if (str->reserve(SRID_SIZE, 512)) + return 0; + str->length(0); + uint32 srid= uint4korr(swkb->ptr()); + str->q_append(srid); + 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(1 + 4 + 4, 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; +} + +/* + 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() + SRID_SIZE, + res1->length() - SRID_SIZE) || + g2.create_from_wkb(res2->ptr() + SRID_SIZE, + res2->length() - SRID_SIZE) || + 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 *swkb= args[0]->val_str(&tmp); + Geometry geom; + int isclosed; + + null_value= (!swkb || + args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom,is_closed) || + geom.is_closed(&isclosed)); + + return (longlong) isclosed; +} + +/* + Numerical functions +*/ + +longlong Item_func_dimension::val_int() +{ + uint32 dim; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + geom.dimension(&dim)); + return (longlong) dim; +} + +longlong Item_func_numinteriorring::val_int() +{ + uint32 num; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !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 *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, num_geometries) || + geom.num_geometries(&num)); + return (longlong) num; +} + +longlong Item_func_numpoints::val_int() +{ + uint32 num; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + args[0]->null_value || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, num_points) || + geom.num_points(&num)); + return (longlong) num; +} + +double Item_func_x::val() +{ + double res; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, get_x) || + geom.get_x(&res)); + return res; +} + +double Item_func_y::val() +{ + double res; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, get_y) || + geom.get_y(&res)); + return res; +} + +double Item_func_area::val() +{ + double res; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, area) || + geom.area(&res)); + return res; +} + +double Item_func_glength::val() +{ + double res; + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, length) || + geom.length(&res)); + return res; +} + +longlong Item_func_srid::val_int() +{ + String *swkb= args[0]->val_str(&value); + Geometry geom; + + null_value= (!swkb || + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE)); + uint32 res= uint4korr(swkb->ptr()); + return (longlong) res; +} diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h new file mode 100644 index 00000000000..21e94735f31 --- /dev/null +++ b/sql/item_geofunc.h @@ -0,0 +1,360 @@ +/* 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 */ + + +/* This file defines all spatial functions */ + +#ifdef __GNUC__ +#pragma interface /* gcc class implementation */ +#endif + +#define SRID_SIZE sizeof(uint32) + +class Item_func_geometry_from_text: public Item_str_func +{ +public: + Item_func_geometry_from_text(Item *a) :Item_str_func(a) {} + Item_func_geometry_from_text(Item *a, Item *srid) :Item_str_func(a, srid) {} + const char *func_name() const { return "geometryfromtext"; } + String *val_str(String *); + void fix_length_and_dec(); +}; + +class Item_func_geometry_from_wkb: public Item_str_func +{ +public: + Item_func_geometry_from_wkb(Item *a): Item_str_func(a) {} + Item_func_geometry_from_wkb(Item *a, Item *srid): Item_str_func(a, srid) {} + const char *func_name() const { return "geometryfromwkb"; } + 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_as_wkb: public Item_str_func +{ +public: + Item_func_as_wkb(Item *a): Item_str_func(a) {} + const char *func_name() const { return "aswkb"; } + 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) {} + Item_func_point(Item *a, Item *b, Item *srid): Item_str_func(a, b, srid) {} + 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"; } +}; + +#ifdef HAVE_COMPRESS + +class Item_func_compress: public Item_str_func +{ + String buffer; +public: + Item_func_compress(Item *a):Item_str_func(a){} + String *val_str(String *); + void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} + const char *func_name() const{return "compress";} +}; + +class Item_func_uncompress: public Item_str_func +{ + String buffer; +public: + Item_func_uncompress(Item *a): Item_str_func(a){} + String *val_str(String *); + void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;} + const char *func_name() const{return "uncompress";} +}; + +#endif + +/* + Spatial relations +*/ + +class Item_func_spatial_rel: public Item_bool_func2 +{ + enum Functype spatial_rel; +public: + Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) : + Item_bool_func2(a,b) { spatial_rel = sp_rel; } + longlong val_int(); + 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"; + } + } +}; + +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"; } +}; + +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"; } +}; + + +class Item_func_srid: public Item_int_func +{ + String value; +public: + Item_func_srid(Item *a): Item_int_func(a) {} + longlong val_int(); + const char *func_name() const { return "srid"; } + void fix_length_and_dec() { max_length= 10; } +}; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 8aaf9f944e8..3c4b5070850 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -27,9 +27,6 @@ #include "mysql_priv.h" #include "sql_acl.h" #include <m_ctype.h> -#ifdef HAVE_CRYPT_H -#include <crypt.h> -#endif #ifdef HAVE_OPENSSL #include <openssl/des.h> #endif /* HAVE_OPENSSL */ @@ -931,7 +928,7 @@ void Item_str_func::left_right_max_length() max_length=args[0]->max_length; if (args[1]->const_item()) { - int length=(int) args[1]->val_int(); + int length=(int) args[1]->val_int()*charset()->mbmaxlen; if (length <= 0) max_length=0; else @@ -942,6 +939,7 @@ void Item_str_func::left_right_max_length() void Item_func_left::fix_length_and_dec() { + set_charset(args[0]->charset(), args[0]->coercibility); left_right_max_length(); } @@ -968,6 +966,7 @@ String *Item_func_right::val_str(String *str) void Item_func_right::fix_length_and_dec() { + set_charset(args[0]->charset(), args[0]->coercibility); left_right_max_length(); } @@ -1012,7 +1011,7 @@ void Item_func_substr::fix_length_and_dec() } if (arg_count == 3 && args[2]->const_item()) { - int32 length= (int32) args[2]->val_int(); + int32 length= (int32) args[2]->val_int() * default_charset_info->mbmaxlen; if (length <= 0) max_length=0; /* purecov: inspected */ else @@ -1462,10 +1461,12 @@ String *Item_func_database::val_str(String *str) { THD *thd= current_thd; if (!thd->db) + { str->length(0); + str->set_charset(system_charset_info); + } else - str->copy((const char*) thd->db,(uint) strlen(thd->db), - system_charset_info, default_charset()); + str->copy((const char*) thd->db,(uint) strlen(thd->db),system_charset_info); return str; } @@ -1474,7 +1475,7 @@ String *Item_func_database::val_str(String *str) String *Item_func_user::val_str(String *str) { THD *thd=current_thd; - CHARSET_INFO *cs= default_charset(); + CHARSET_INFO *cs= system_charset_info; const char *host= thd->host_or_ip; uint res_length; @@ -1488,7 +1489,7 @@ String *Item_func_user::val_str(String *str) null_value=1; return 0; } - res_length=cs->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s", + res_length=cs->cset->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s", thd->user, host); str->length(res_length); str->set_charset(cs); @@ -1591,15 +1592,17 @@ String *Item_func_format::val_str(String *str) str_length=str->length(); if (nr < 0) str_length--; // Don't count sign - length=str->length()+(diff=(str_length- dec-1)/3); - if (diff) + + /* We need this test to handle 'nan' values */ + if (str_length >= dec+4) { char *tmp,*pos; - str=copy_if_not_alloced(&tmp_str,str,length); + length= str->length()+(diff=(str_length- dec-1)/3); + str= copy_if_not_alloced(&tmp_str,str,length); str->length(length); - tmp=(char*) str->ptr()+length - dec-1; - for (pos=(char*) str->ptr()+length ; pos != tmp; pos--) - pos[0]=pos[- (int) diff]; + tmp= (char*) str->ptr()+length - dec-1; + for (pos= (char*) str->ptr()+length ; pos != tmp; pos--) + pos[0]= pos[-(int) diff]; while (diff) { pos[0]=pos[-(int) diff]; pos--; @@ -2130,7 +2133,7 @@ String *Item_func_conv_charset3::val_str(String *str) while (1) { - cnvres=from_charset->mb_wc(from_charset,&wc,s,se); + cnvres=from_charset->cset->mb_wc(from_charset,&wc,s,se); if (cnvres>0) { s+=cnvres; @@ -2144,7 +2147,7 @@ String *Item_func_conv_charset3::val_str(String *str) break; outp: - cnvres=to_charset->wc_mb(to_charset,wc,d,de); + cnvres=to_charset->cset->wc_mb(to_charset,wc,d,de); if (cnvres>0) { d+=cnvres; @@ -2184,7 +2187,7 @@ void Item_func_set_collation::fix_length_and_dec() const char *colname; String tmp, *str= args[1]->val_str(&tmp); colname= str->c_ptr(); - if (!strncmp(colname,"BINARY",6)) + if (colname == binary_keyword) set_collation= get_charset_by_csname(args[0]->charset()->csname, MY_CS_BINSORT,MYF(0)); else @@ -2254,7 +2257,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),default_charset_info)) + if (str->copy(ans,(uint32) (ptr-ans),default_charset())) return &empty_string; // End of memory return str; } @@ -2363,7 +2366,7 @@ String* Item_func_export_set::val_str(String* str) } break; case 3: - sep_buf.set(",", 1, default_charset_info); + sep_buf.set(",", 1, default_charset()); sep = &sep_buf; } null_value=0; @@ -2519,428 +2522,6 @@ null: 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()); - uint32 srid; - - if ((arg_count == 2) && !args[1]->null_value) - srid= args[1]->val_int(); - else - srid= 0; - - if (str->reserve(SRID_SIZE, 512)) - return 0; - str->length(0); - str->q_append(srid); - 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_geometry_from_wkb::val_str(String *str) -{ - String arg_val; - String *wkb= args[0]->val_str(&arg_val); - Geometry geom; - uint32 srid; - - if ((arg_count == 2) && !args[1]->null_value) - srid= args[1]->val_int(); - else - srid= 0; - - if (str->reserve(SRID_SIZE, 512)) - return 0; - str->length(0); - str->q_append(srid); - if ((null_value= (args[0]->null_value || - geom.create_from_wkb(wkb->ptr(), wkb->length())))) - return 0; - - str->append(*wkb); - return str; -} - - -void Item_func_geometry_from_wkb::fix_length_and_dec() -{ - max_length=MAX_BLOB_WIDTH; -} - - -String *Item_func_as_text::val_str(String *str) -{ - String arg_val; - String *swkb= args[0]->val_str(&arg_val); - Geometry geom; - - if ((null_value= (args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE)))) - 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_as_wkb::val_str(String *str) -{ - String arg_val; - String *swkb= args[0]->val_str(&arg_val); - Geometry geom; - - if ((null_value= (args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE)))) - return 0; - - str->copy(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE, - &my_charset_bin); - return str; -} - -void Item_func_as_wkb::fix_length_and_dec() -{ - max_length= MAX_BLOB_WIDTH; -} - -String *Item_func_geometry_type::val_str(String *str) -{ - String *swkb= args[0]->val_str(str); - Geometry geom; - - if ((null_value= (args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE)))) - 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 arg_val; - String *swkb= args[0]->val_str(&arg_val); - Geometry geom; - - if ((null_value= args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE))) - return 0; - - uint32 srid= uint4korr(swkb->ptr()); - str->length(0); - if (str->reserve(SRID_SIZE, 512)) - return 0; - str->q_append(srid); - return (null_value= geom.envelope(str)) ? 0 : str; -} - - -String *Item_func_centroid::val_str(String *str) -{ - String arg_val; - String *swkb= args[0]->val_str(&arg_val); - Geometry geom; - - if ((null_value= args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, centroid))) - return 0; - - if (str->reserve(SRID_SIZE, 512)) - return 0; - str->length(0); - uint32 srid= uint4korr(swkb->ptr()); - str->q_append(srid); - - return (null_value= geom.centroid(str)) ? 0 : str; -} - - -/*********************************************** - Spatial decomposition functions -***********************************************/ - -String *Item_func_spatial_decomp::val_str(String *str) -{ - String arg_val; - String *swkb= args[0]->val_str(&arg_val); - Geometry geom; - - if ((null_value= (args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE)))) - return 0; - - null_value= 1; - if (str->reserve(SRID_SIZE, 512)) - return 0; - str->length(0); - uint32 srid= uint4korr(swkb->ptr()); - str->q_append(srid); - 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 *swkb= 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(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE)))) - return 0; - - null_value= 1; - if (str->reserve(SRID_SIZE, 512)) - return 0; - str->length(0); - uint32 srid= uint4korr(swkb->ptr()); - str->q_append(srid); - 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(1 + 4 + 4, 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; -} - #ifdef HAVE_COMPRESS #include "../zlib/zlib.h" diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index abe2a5355be..65aad3a3fff 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -333,12 +333,12 @@ public: class Item_func_database :public Item_str_func { public: - Item_func_database() {} + Item_func_database() { coercibility= COER_IMPLICIT; } String *val_str(String *); void fix_length_and_dec() { - max_length= MAX_FIELD_NAME * default_charset()->mbmaxlen; - set_charset(default_charset()); + max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen; + set_charset(system_charset_info); } const char *func_name() const { return "database"; } }; @@ -346,12 +346,12 @@ public: class Item_func_user :public Item_str_func { public: - Item_func_user() {} + Item_func_user() { coercibility= COER_IMPLICIT; } String *val_str(String *); void fix_length_and_dec() { - max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*default_charset()->mbmaxlen; - set_charset(default_charset()); + max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen; + set_charset(system_charset_info); } const char *func_name() const { return "user"; } }; @@ -628,242 +628,3 @@ public: set_charset(default_charset()); }; }; - - -/******************************************************* -Spatial functions -********************************************************/ - -#define SRID_SIZE sizeof(uint32) - -class Item_func_geometry_from_text :public Item_str_func -{ -public: - Item_func_geometry_from_text(Item *a) :Item_str_func(a) {} - Item_func_geometry_from_text(Item *a, Item *srid) :Item_str_func(a, srid) {} - const char *func_name() const { return "geometryfromtext"; } - String *val_str(String *); - void fix_length_and_dec(); -}; - -class Item_func_geometry_from_wkb: public Item_str_func -{ -public: - Item_func_geometry_from_wkb(Item *a) :Item_str_func(a) {} - Item_func_geometry_from_wkb(Item *a, Item *srid) :Item_str_func(a, srid) {} - const char *func_name() const { return "geometryfromwkb"; } - 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_as_wkb :public Item_str_func -{ -public: - Item_func_as_wkb(Item *a) :Item_str_func(a) {} - const char *func_name() const { return "aswkb"; } - 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) {} - Item_func_point(Item *a, Item *b, Item *srid) :Item_str_func(a, b, srid) {} - 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"; } -}; - -#ifdef HAVE_COMPRESS - -class Item_func_compress : public Item_str_func -{ - String buffer; -public: - Item_func_compress(Item *a):Item_str_func(a){} - String *val_str(String *); - void fix_length_and_dec(){max_length= (args[0]->max_length*120)/100+12;} - const char *func_name() const{return "compress";} -}; - -class Item_func_uncompress : public Item_str_func -{ - String buffer; -public: - Item_func_uncompress(Item *a):Item_str_func(a){} - String *val_str(String *); - void fix_length_and_dec(){max_length= MAX_BLOB_WIDTH;} - const char *func_name() const{return "uncompress";} -}; - -#endif - -/* -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 index c749fba616f..8c9b3eeebde 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -79,8 +79,10 @@ void Item_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) } -bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) { + thd= thd_param; + if (substitution) { (*ref)= substitution; @@ -115,6 +117,20 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return res; } +bool Item_subselect::exec() +{ + MEM_ROOT *old_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC); + if (&thd->mem_root != old_root) + { + my_pthread_setspecific_ptr(THR_MALLOC, &thd->mem_root); + int res= engine->exec(); + my_pthread_setspecific_ptr(THR_MALLOC, old_root); + return (res); + } + else + return engine->exec(); +} + Item::Type Item_subselect::type() const { return SUBSELECT_ITEM; @@ -253,12 +269,12 @@ bool Item_singlerow_subselect::null_inside() void Item_singlerow_subselect::bring_value() { - engine->exec(); + exec(); } double Item_singlerow_subselect::val () { - if (!engine->exec() && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val(); @@ -272,7 +288,7 @@ double Item_singlerow_subselect::val () longlong Item_singlerow_subselect::val_int () { - if (!engine->exec() && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_int(); @@ -286,7 +302,7 @@ longlong Item_singlerow_subselect::val_int () String *Item_singlerow_subselect::val_str (String *str) { - if (!engine->exec() && !value->null_value) + if (!exec() && !value->null_value) { null_value= 0; return value->val_str(str); @@ -354,7 +370,7 @@ void Item_exists_subselect::fix_length_and_dec() double Item_exists_subselect::val () { - if (engine->exec()) + if (exec()) { reset(); return 0; @@ -364,7 +380,7 @@ double Item_exists_subselect::val () longlong Item_exists_subselect::val_int () { - if (engine->exec()) + if (exec()) { reset(); return 0; @@ -374,7 +390,7 @@ longlong Item_exists_subselect::val_int () String *Item_exists_subselect::val_str(String *str) { - if (engine->exec()) + if (exec()) { reset(); return 0; @@ -385,7 +401,7 @@ String *Item_exists_subselect::val_str(String *str) double Item_in_subselect::val () { - if (engine->exec()) + if (exec()) { reset(); null_value= 1; @@ -398,7 +414,7 @@ double Item_in_subselect::val () longlong Item_in_subselect::val_int () { - if (engine->exec()) + if (exec()) { reset(); null_value= 1; @@ -411,7 +427,7 @@ longlong Item_in_subselect::val_int () String *Item_in_subselect::val_str(String *str) { - if (engine->exec()) + if (exec()) { reset(); null_value= 1; diff --git a/sql/item_subselect.h b/sql/item_subselect.h index fc4dad5a6b3..3ed3f2af0e9 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -36,6 +36,8 @@ 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: + /* thread handler, will be assigned in fix_fields only */ + THD *thd; /* substitution instead of subselect in case of optimization */ Item *substitution; /* engine that perform execution of subselect (single select or union) */ @@ -81,6 +83,7 @@ public: return null_value; } bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 60976ab993a..e5be3809230 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -219,12 +219,14 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) void Item_sum_sum::reset() { - null_value=0; sum=0.0; Item_sum_sum::add(); + null_value=1; sum=0.0; Item_sum_sum::add(); } bool Item_sum_sum::add() { sum+=args[0]->val(); + if (!args[0]->null_value) + null_value= 0; return 0; } @@ -641,8 +643,10 @@ void Item_sum_sum::reset_field() { double nr=args[0]->val(); // Nulls also return 0 float8store(result_field->ptr,nr); - null_value=0; - result_field->set_notnull(); + if (args[0]->null_value) + result_field->set_null(); + else + result_field->set_notnull(); } @@ -698,7 +702,10 @@ void Item_sum_sum::update_field(int offset) float8get(old_nr,res+offset); nr=args[0]->val(); if (!args[0]->null_value) + { old_nr+=nr; + result_field->set_notnull(); + } float8store(res,old_nr); } diff --git a/sql/item_sum.h b/sql/item_sum.h index e306a42c6bc..7deec8de564 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -99,9 +99,6 @@ public: class Item_sum_int :public Item_sum_num { - void fix_length_and_dec() - { decimals=0; max_length=21; maybe_null=null_value=0; } - public: Item_sum_int(Item *item_par) :Item_sum_num(item_par) {} Item_sum_int(List<Item> &list) :Item_sum_num(list) {} @@ -109,6 +106,8 @@ public: double val() { return (double) 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; maybe_null=null_value=0; } }; @@ -127,6 +126,7 @@ class Item_sum_sum :public Item_sum_num double val(); void reset_field(); void update_field(int offset); + void no_rows_in_result() {} const char *func_name() const { return "sum"; } Item *copy_or_same(THD* thd) { return new Item_sum_sum(thd, *this); } }; @@ -449,6 +449,8 @@ class Item_sum_bit :public Item_sum_int void reset(); longlong val_int(); void reset_field(); + void fix_length_and_dec() + { decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; } }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 997247b6141..61c869cddba 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -511,7 +511,7 @@ void Item_func_curtime::fix_length_and_dec() (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec)); - buff_length=cs->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d", + buff_length=cs->cset->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d", (int) start->tm_hour, (int) start->tm_min, (int) start->tm_sec); @@ -543,7 +543,7 @@ void Item_func_now::fix_length_and_dec() (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec))); - buff_length= (uint) cs->snprintf(cs,buff, sizeof(buff), + buff_length= (uint) cs->cset->snprintf(cs,buff, sizeof(buff), "%04d-%02d-%02d %02d:%02d:%02d", ((int) (start->tm_year+1900)) % 10000, (int) start->tm_mon+1, @@ -950,7 +950,7 @@ String *Item_func_from_unixtime::val_str(String *str) l=20*cs->mbmaxlen+32; if (str->alloc(l)) return str; /* purecov: inspected */ - l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", + l=cs->cset->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, @@ -1134,7 +1134,7 @@ String *Item_date_add_interval::val_str(String *str) l=11*cs->mbmaxlen+32; if (str->alloc(l)) goto null_date; - l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d", + l=cs->cset->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d", ltime.year,ltime.month,ltime.day); str->length(l); } @@ -1143,7 +1143,7 @@ String *Item_date_add_interval::val_str(String *str) l=20*cs->mbmaxlen+32; if (str->alloc(l)) goto null_date; - l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", + l=cs->cset->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(l); diff --git a/sql/lex.h b/sql/lex.h index f85431aadf7..e89c9f51520 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -430,6 +430,7 @@ static SYMBOL sql_functions[] = { { "AES_DECRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_decrypt)}, { "AREA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_area)}, { "ASIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_asin)}, + { "ASBINARY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_as_wkb)}, { "ASTEXT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_as_text)}, { "ASWKB", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_as_wkb)}, { "ATAN", SYM(ATAN),0,0}, diff --git a/sql/log.cc b/sql/log.cc index c9e20bc0cc9..c05d52bdc5d 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -317,7 +317,10 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, DBUG_RETURN(0); err: - sql_print_error("Could not use %s for logging (error %d)", log_name, errno); + sql_print_error("Could not use %s for logging (error %d). \ +Turning logging off for the whole duration of the MySQL server process. \ +To turn it on again: fix the cause, \ +shutdown the MySQL server and restart it.", log_name, errno); if (file >= 0) my_close(file,MYF(0)); if (index_file_nr >= 0) @@ -1157,6 +1160,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, bool MYSQL_LOG::write(Log_event* event_info) { + THD *thd=event_info->thd; + bool called_handler_commit=0; bool error=0; bool should_rotate = 0; DBUG_ENTER("MYSQL_LOG::write(event)"); @@ -1171,7 +1176,6 @@ bool MYSQL_LOG::write(Log_event* event_info) /* In most cases this is only called if 'is_open()' is true */ if (is_open()) { - THD *thd=event_info->thd; const char *local_db = event_info->get_db(); #ifdef USING_TRANSACTIONS IO_CACHE *file = ((event_info->get_cache_stmt()) ? @@ -1268,24 +1272,35 @@ bool MYSQL_LOG::write(Log_event* event_info) the table handler commit here, protected by the LOCK_log mutex, because otherwise the transactions may end up in a different order in the table handler log! + + Note that we will NOT call ha_report_binlog_offset_and_commit() if + there are binlog events cached in the transaction cache. That is + because then the log event which we write to the binlog here is + not a transactional event. In versions < 4.0.13 before this fix this + caused an InnoDB transaction to be committed if in the middle there + was a MyISAM event! */ - if (file == &log_file) + if (file == &log_file) // we are writing to the real log (disk) { - /* - LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog - chunks also before it is successfully completed. We only report - the binlog write and do the commit inside the transactional table - handler if the log event type is appropriate. - */ - - if (event_info->get_type_code() == QUERY_EVENT - || event_info->get_type_code() == EXEC_LOAD_EVENT) + if (opt_using_transactions && !my_b_tell(&thd->transaction.trans_log)) { - error = ha_report_binlog_offset_and_commit(thd, log_file_name, - file->pos_in_file); + /* + LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog + chunks also before it is successfully completed. We only report + the binlog write and do the commit inside the transactional table + handler if the log event type is appropriate. + */ + + if (event_info->get_type_code() == QUERY_EVENT + || event_info->get_type_code() == EXEC_LOAD_EVENT) + { + error = ha_report_binlog_offset_and_commit(thd, log_file_name, + file->pos_in_file); + called_handler_commit=1; + } } - + /* we wrote to the real log, check automatic rotation */ should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size); } @@ -1309,6 +1324,16 @@ err: } pthread_mutex_unlock(&LOCK_log); + + /* + Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit + */ + + if (called_handler_commit) + ha_commit_complete(thd); + #ifdef HAVE_REPLICATION if (should_rotate && expire_logs_days) { @@ -1316,7 +1341,6 @@ err: if (purge_time >= 0) error= purge_logs_before_date(purge_time); } - #endif DBUG_RETURN(error); } @@ -1423,6 +1447,13 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache) } VOID(pthread_mutex_unlock(&LOCK_log)); + + /* Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit */ + + ha_commit_complete(thd); + DBUG_RETURN(0); err: diff --git a/sql/log_event.cc b/sql/log_event.cc index 530e878b458..fb690efc364 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -26,11 +26,10 @@ #define log_cs &my_charset_latin1 -/***************************************************************************** - +/* my_b_safe_write() +*/ - ****************************************************************************/ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, int len) { @@ -45,11 +44,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) { @@ -75,11 +74,11 @@ static void pretty_print_str(FILE* file, char* str, int len) } #endif // MYSQL_CLIENT -/***************************************************************************** +/* ignored_error_code() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) inline int ignored_error_code(int err_code) { @@ -87,11 +86,10 @@ inline int ignored_error_code(int err_code) } #endif -/***************************************************************************** - +/* pretty_print_str() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT static char* pretty_print_str(char* packet, char* str, int len) { @@ -117,13 +115,13 @@ static char* pretty_print_str(char* packet, char* str, int len) *pos++= '\''; return pos; } -#endif // !MYSQL_CLIENT +#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) @@ -138,8 +136,7 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, } #endif -/***************************************************************************** - +/* cleanup_load_tmpdir() Delete all temporary files used for SQL_LOAD. @@ -148,8 +145,8 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, - 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() { @@ -170,22 +167,22 @@ static void cleanup_load_tmpdir() } #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) { @@ -198,19 +195,14 @@ static inline int read_str(char * &buf, char *buf_end, char * &str, } -/***************************************************************************** - ***************************************************************************** - - Log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Log_event methods +**************************************************************************/ +/* Log_event::get_type_str() +*/ - ****************************************************************************/ const char* Log_event::get_type_str() { switch(get_type_code()) { @@ -232,11 +224,11 @@ const char* Log_event::get_type_str() } } -/***************************************************************************** +/* 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), @@ -258,13 +250,13 @@ Log_event::Log_event() when= time(NULL); log_pos= 0; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ -/***************************************************************************** +/* Log_event::Log_event() +*/ - ****************************************************************************/ Log_event::Log_event(const char* buf, bool old_format) :temp_buf(0), cached_event_len(0), cache_stmt(0) { @@ -285,15 +277,13 @@ Log_event::Log_event(const char* buf, bool old_format) #endif } - #ifndef MYSQL_CLIENT #ifdef HAVE_REPLICATION -/***************************************************************************** - +/* Log_event::exec_event() +*/ - ****************************************************************************/ int Log_event::exec_event(struct st_relay_log_info* rli) { /* @@ -324,15 +314,15 @@ int Log_event::exec_event(struct st_relay_log_info* rli) - then it will be MyISAM on the slave - but as opt_using_transactions is true, the slave will believe he is transactional with the MyISAM table. And problems will come when one - does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at BEGIN - whereas there has not been any rollback). This is the problem of + does START SLAVE; STOP SLAVE; START SLAVE; (the slave will resume at + BEGIN whereas there has not been any rollback). This is the problem of using opt_using_transactions instead of a finer "does the slave support _the_transactional_handler_used_on_the_master_". More generally, we'll have problems when a query mixes a transactional handler and MyISAM and STOP SLAVE is issued in the middle of the - "transaction". START SLAVE will resume at BEGIN while the MyISAM table has - already been updated. + "transaction". START SLAVE will resume at BEGIN while the MyISAM table + has already been updated. */ if ((thd->options & OPTION_BEGIN) && opt_using_transactions) @@ -346,24 +336,22 @@ int Log_event::exec_event(struct st_relay_log_info* rli) return 0; } -/***************************************************************************** +/* Log_event::pack_info() +*/ - ****************************************************************************/ void Log_event::pack_info(Protocol *protocol) { protocol->store("", &my_charset_bin); } -/***************************************************************************** - +/* Log_event::net_send() Only called by SHOW BINLOG EVENTS - - ****************************************************************************/ +*/ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) { @@ -384,11 +372,11 @@ int Log_event::net_send(Protocol *protocol, const char* log_name, my_off_t pos) } #endif /* HAVE_REPLICATION */ -/***************************************************************************** +/* 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)); @@ -404,21 +392,20 @@ void Log_event::init_show_field_list(List<Item>* field_list) #endif // !MYSQL_CLIENT -/***************************************************************************** - +/* 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]; @@ -439,11 +426,10 @@ int Log_event::write_header(IO_CACHE* file) } -/***************************************************************************** - +/* Log_event::read_log_event() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT int Log_event::read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock) @@ -510,13 +496,13 @@ end: #define LOCK_MUTEX #endif -/***************************************************************************** - +/* Log_event::read_log_event() - Allocates memory--the caller is responsible for clean-up + NOTE: + 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, @@ -588,11 +574,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) { @@ -657,9 +643,18 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, } if (!ev || !ev->is_valid()) { - *error= "Found invalid event in binary log"; delete ev; +#ifdef MYSQL_CLIENT + if (!force_opt) + { + *error= "Found invalid event in binary log"; + return 0; + } + ev= new Unknown_log_event(buf, old_format); +#else + *error= "Found invalid event in binary log"; return 0; +#endif } ev->cached_event_len = event_len; return ev; @@ -667,11 +662,10 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, #ifdef MYSQL_CLIENT -/***************************************************************************** - +/* Log_event::print_header() +*/ - ****************************************************************************/ void Log_event::print_header(FILE* file) { char llbuff[22]; @@ -681,11 +675,10 @@ 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; @@ -709,11 +702,10 @@ void Log_event::print_timestamp(FILE* file, time_t* ts) #endif // MYSQL_CLIENT -/***************************************************************************** - +/* Log_event::set_log_pos() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT void Log_event::set_log_pos(MYSQL_LOG* log) { @@ -723,21 +715,16 @@ void Log_event::set_log_pos(MYSQL_LOG* log) #endif // !MYSQL_CLIENT - -/***************************************************************************** - ***************************************************************************** - - Query_log_event methods - - ***************************************************************************** - ****************************************************************************/ +/************************************************************************** + Query_log_event methods +**************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) -/***************************************************************************** +/* Query_log_event::pack_info() +*/ - ****************************************************************************/ void Query_log_event::pack_info(Protocol *protocol) { char *buf, *pos; @@ -761,21 +748,21 @@ void Query_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Query_log_event::write() +*/ - ****************************************************************************/ int Query_log_event::write(IO_CACHE* file) { return query ? Log_event::write(file) : -1; } -/***************************************************************************** +/* Query_log_event::write_data() +*/ - ****************************************************************************/ int Query_log_event::write_data(IO_CACHE* file) { if (!query) @@ -792,11 +779,11 @@ int Query_log_event::write_data(IO_CACHE* file) 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) @@ -812,13 +799,12 @@ 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 // MYSQL_CLIENT - -/***************************************************************************** +#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) @@ -854,11 +840,11 @@ Query_log_event::Query_log_event(const char* buf, int event_len, *((char*)query+q_len) = 0; } -/***************************************************************************** +/* Query_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Query_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -889,13 +875,13 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fprintf(file, ";\n"); } -#endif // MYSQL_CLIENT +#endif /* MYSQL_CLIENT */ -/***************************************************************************** +/* Query_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Query_log_event::exec_event(struct st_relay_log_info* rli) { @@ -996,19 +982,14 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) #endif -/***************************************************************************** - ***************************************************************************** - - Start_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Start_log_event methods +**************************************************************************/ +/* Start_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Start_log_event::pack_info(Protocol *protocol) { @@ -1021,11 +1002,11 @@ void Start_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Start_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Start_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1035,17 +1016,16 @@ void Start_log_event::print(FILE* file, bool short_form, char* last_db) print_header(file); fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, server_version); - print_timestamp(file, (time_t*)&created); + print_timestamp(file, &created); fputc('\n', file); fflush(file); } -#endif // MYSQL_CLIENT - -/***************************************************************************** +#endif /* MYSQL_CLIENT */ +/* Start_log_event::Start_log_event() +*/ - ****************************************************************************/ Start_log_event::Start_log_event(const char* buf, bool old_format) :Log_event(buf, old_format) @@ -1057,11 +1037,11 @@ Start_log_event::Start_log_event(const char* buf, created = uint4korr(buf+ST_CREATED_OFFSET); } -/***************************************************************************** +/* Start_log_event::write_data() +*/ - ****************************************************************************/ int Start_log_event::write_data(IO_CACHE* file) { char buff[START_HEADER_LEN]; @@ -1071,8 +1051,7 @@ int Start_log_event::write_data(IO_CACHE* file) return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); } -/***************************************************************************** - +/* Start_log_event::exec_event() The master started @@ -1080,6 +1059,10 @@ int Start_log_event::write_data(IO_CACHE* file) IMPLEMENTATION - To handle the case where the master died without a stop event, we clean up all temporary tables + locks that we got. + However, we don't clean temporary tables if the master was 3.23 + (this is because a 3.23 master writes a Start_log_event at every + binlog rotation; if we were not careful we would remove temp tables + on the slave when FLUSH LOGS is issued on the master). TODO - Remove all active user locks @@ -1087,36 +1070,37 @@ int Start_log_event::write_data(IO_CACHE* file) 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) { 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) + { + /* + If 4.0 master, all temporary tables have been deleted on the master; + if 3.23 master, this is far from sure. + */ + close_temporary_tables(thd); + /* + If we have old format, load_tmpdir is cleaned up by the I/O thread + */ cleanup_load_tmpdir(); + } DBUG_RETURN(Log_event::exec_event(rli)); } -#endif - - -/***************************************************************************** - ***************************************************************************** - - Load_log_event methods - - ***************************************************************************** - ****************************************************************************/ +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ -/***************************************************************************** +/************************************************************************** + Load_log_event methods +**************************************************************************/ +/* Load_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Load_log_event::pack_info(Protocol *protocol) { @@ -1224,13 +1208,13 @@ void Load_log_event::pack_info(Protocol *protocol) protocol->store(buf, pos-buf, &my_charset_bin); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); } -#endif +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ -/***************************************************************************** +/* Load_log_event::write_data_header() +*/ - ****************************************************************************/ int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; @@ -1243,11 +1227,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)) @@ -1263,11 +1247,11 @@ 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() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, const char *db_arg, const char *table_name_arg, @@ -1347,16 +1331,16 @@ 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 /* !MYSQL_CLIENT */ +/* Load_log_event::Load_log_event() - The caller must do buf[event_len] = 0 before he starts using the - constructed event. + NOTE + 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, bool old_format) :Log_event(buf, old_format),num_fields(0),fields(0), @@ -1368,11 +1352,11 @@ Load_log_event::Load_log_event(const char *buf, int event_len, 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) { @@ -1417,11 +1401,11 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, return 0; } -/***************************************************************************** +/* Load_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Load_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1510,13 +1494,13 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, ";\n"); } -#endif /* #ifdef MYSQL_CLIENT */ +#endif /* MYSQL_CLIENT */ -/***************************************************************************** +/* Load_log_event::set_fields() +*/ - ****************************************************************************/ #ifndef MYSQL_CLIENT void Load_log_event::set_fields(List<Item> &field_list) { @@ -1653,12 +1637,11 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, close_thread_tables(thd); if (thd->query_error) { - int sql_error = thd->net.last_errno; + int sql_error= thd->net.last_errno; if (!sql_error) - sql_error = ER_UNKNOWN_ERROR; - + sql_error= ER_UNKNOWN_ERROR; slave_print_error(rli,sql_error, - "Slave: Error '%s' running load data infile ", + "Error '%s' running LOAD DATA INFILE", ER_SAFE(sql_error)); free_root(&thd->mem_root,0); return 1; @@ -1667,7 +1650,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, if (thd->is_fatal_error) { - sql_print_error("Slave: Fatal error running LOAD DATA INFILE "); + sql_print_error("Fatal error running LOAD DATA INFILE"); return 1; } @@ -1676,19 +1659,14 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, #endif -/***************************************************************************** - ***************************************************************************** - - Rotate_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Rotate_log_event methods +**************************************************************************/ +/* Rotate_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Rotate_log_event::pack_info(Protocol *protocol) { @@ -1707,11 +1685,11 @@ void Rotate_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Rotate_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -1732,11 +1710,11 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) } #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) @@ -1768,11 +1746,11 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len, alloced = 1; } -/***************************************************************************** +/* Rotate_log_event::write_data() +*/ - ****************************************************************************/ int Rotate_log_event::write_data(IO_CACHE* file) { char buf[ROTATE_HEADER_LEN]; @@ -1781,8 +1759,8 @@ int Rotate_log_event::write_data(IO_CACHE* file) 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 @@ -1796,8 +1774,8 @@ int Rotate_log_event::write_data(IO_CACHE* file) RETURN VALUES 0 ok +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) int Rotate_log_event::exec_event(struct st_relay_log_info* rli) { @@ -1818,19 +1796,14 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli) #endif -/***************************************************************************** - ***************************************************************************** - - Intvar_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Intvar_log_event methods +**************************************************************************/ +/* Intvar_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Intvar_log_event::pack_info(Protocol *protocol) { @@ -1842,11 +1815,11 @@ void Intvar_log_event::pack_info(Protocol *protocol) } #endif -/***************************************************************************** +/* Intvar_log_event::Intvar_log_event() +*/ - ****************************************************************************/ Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) :Log_event(buf, old_format) { @@ -1855,11 +1828,11 @@ Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) val = uint8korr(buf+I_VAL_OFFSET); } -/***************************************************************************** +/* Intvar_log_event::get_var_type_name() +*/ - ****************************************************************************/ const char* Intvar_log_event::get_var_type_name() { switch(type) { @@ -1869,11 +1842,11 @@ const char* Intvar_log_event::get_var_type_name() } } -/***************************************************************************** +/* Intvar_log_event::write_data() +*/ - ****************************************************************************/ int Intvar_log_event::write_data(IO_CACHE* file) { char buf[9]; @@ -1882,11 +1855,11 @@ int Intvar_log_event::write_data(IO_CACHE* file) 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) { @@ -1912,13 +1885,13 @@ void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); fflush(file); } -#endif // MYSQL_CLIENT +#endif -/***************************************************************************** +/* Intvar_log_event::exec_event() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT) int Intvar_log_event::exec_event(struct st_relay_log_info* rli) { @@ -1937,9 +1910,9 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli) #endif -/**************************************************************************** +/************************************************************************** Rand_log_event methods -****************************************************************************/ +**************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Rand_log_event::pack_info(Protocol *protocol) @@ -1999,9 +1972,9 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli) #endif // !MYSQL_CLIENT -/*************************************************************************** +/************************************************************************** User_var_log_event methods -***************************************************************************/ +**************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void User_var_log_event::pack_info(Protocol* protocol) @@ -2129,11 +2102,10 @@ int User_var_log_event::write_data(IO_CACHE* file) } -/***************************************************************************** - +/* User_var_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void User_var_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -2176,11 +2148,11 @@ void User_var_log_event::print(FILE* file, bool short_form, char* last_db) } #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) { @@ -2231,10 +2203,21 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli) #endif // !MYSQL_CLIENT -/**************************************************************************** +/************************************************************************** Slave_log_event methods -****************************************************************************/ +**************************************************************************/ + #ifdef HAVE_REPLICATION +#ifdef MYSQL_CLIENT +void Unknown_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (short_form) + return; + print_header(file); + fputc('\n', file); + fprintf(file, "# %s", "Unknown event\n"); +} +#endif #ifndef MYSQL_CLIENT void Slave_log_event::pack_info(Protocol *protocol) @@ -2367,19 +2350,14 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli) #endif // !MYSQL_CLIENT -/***************************************************************************** - ***************************************************************************** - - Stop_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + Stop_log_event methods +**************************************************************************/ +/* Stop_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Stop_log_event::print(FILE* file, bool short_form, char* last_db) { @@ -2392,8 +2370,8 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) } #endif // MYSQL_CLIENT -/***************************************************************************** +/* Stop_log_event::exec_event() The master stopped. Clean up all temporary tables + locks that the @@ -2401,12 +2379,18 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db) 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 + /* + do not clean up immediately after rotate event; + QQ: this should be a useless test: the only case when it is false is when + shutdown occurred just after FLUSH LOGS. It has nothing to do with Rotate? + By the way, immediately after a Rotate the I/O thread does not write + the Stop to the relay log, so we won't come here in that case. + */ if (rli->group_master_log_pos > BIN_LOG_HEADER_SIZE) { close_temporary_tables(thd); @@ -2423,23 +2407,18 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli) flush_relay_log_info(rli); return 0; } -#endif // !MYSQL_CLIENT +#endif /* !MYSQL_CLIENT */ #endif /* HAVE_REPLICATION */ -/***************************************************************************** - ***************************************************************************** - - Create_file_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + 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, @@ -2455,11 +2434,11 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex, } #endif // !MYSQL_CLIENT -/***************************************************************************** +/* Create_file_log_event::write_data_body() +*/ - ****************************************************************************/ int Create_file_log_event::write_data_body(IO_CACHE* file) { int res; @@ -2469,11 +2448,11 @@ int Create_file_log_event::write_data_body(IO_CACHE* file) my_b_safe_write(file, (byte*) block, block_len)); } -/***************************************************************************** +/* Create_file_log_event::write_data_header() +*/ - ****************************************************************************/ int Create_file_log_event::write_data_header(IO_CACHE* file) { int res; @@ -2484,11 +2463,11 @@ int Create_file_log_event::write_data_header(IO_CACHE* file) return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN); } -/***************************************************************************** +/* Create_file_log_event::write_base() +*/ - ****************************************************************************/ int Create_file_log_event::write_base(IO_CACHE* file) { int res; @@ -2498,11 +2477,11 @@ int Create_file_log_event::write_base(IO_CACHE* file) return res; } -/***************************************************************************** +/* Create_file_log_event ctor +*/ - ****************************************************************************/ Create_file_log_event::Create_file_log_event(const char* buf, int len, bool old_format) :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0) @@ -2529,11 +2508,11 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len, } } -/***************************************************************************** +/* Create_file_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Create_file_log_event::print(FILE* file, bool short_form, char* last_db, bool enable_local) @@ -2563,11 +2542,11 @@ void Create_file_log_event::print(FILE* file, bool short_form, } #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) { @@ -2586,11 +2565,11 @@ void Create_file_log_event::pack_info(Protocol *protocol) } #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) { @@ -2651,19 +2630,14 @@ err: #endif -/***************************************************************************** - ***************************************************************************** - - Append_block_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + 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, @@ -2672,13 +2646,13 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, block_len(block_len_arg), file_id(thd_arg->file_id) { } -#endif // !MYSQL_CLIENT +#endif -/***************************************************************************** +/* Append_block_log_event ctor +*/ - ****************************************************************************/ Append_block_log_event::Append_block_log_event(const char* buf, int len) :Log_event(buf, 0),block(0) { @@ -2689,11 +2663,11 @@ Append_block_log_event::Append_block_log_event(const char* buf, int len) block_len = len - APPEND_BLOCK_EVENT_OVERHEAD; } -/***************************************************************************** +/* Append_block_log_event::write_data() +*/ - ****************************************************************************/ int Append_block_log_event::write_data(IO_CACHE* file) { byte buf[APPEND_BLOCK_HEADER_LEN]; @@ -2702,11 +2676,11 @@ int Append_block_log_event::write_data(IO_CACHE* file) my_b_safe_write(file, (byte*) block, block_len)); } -/***************************************************************************** +/* Append_block_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Append_block_log_event::print(FILE* file, bool short_form, char* last_db) @@ -2720,11 +2694,11 @@ void Append_block_log_event::print(FILE* file, bool short_form, } #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) { @@ -2737,11 +2711,11 @@ void Append_block_log_event::pack_info(Protocol *protocol) } #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) { @@ -2773,31 +2747,25 @@ err: #endif -/***************************************************************************** - ***************************************************************************** - - Delete_file_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + 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 - -/***************************************************************************** +#endif +/* 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) { @@ -2806,11 +2774,11 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, int len) file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); } -/***************************************************************************** +/* Delete_file_log_event::write_data() +*/ - ****************************************************************************/ int Delete_file_log_event::write_data(IO_CACHE* file) { byte buf[DELETE_FILE_HEADER_LEN]; @@ -2818,11 +2786,11 @@ int Delete_file_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN); } -/***************************************************************************** +/* Delete_file_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Delete_file_log_event::print(FILE* file, bool short_form, char* last_db) @@ -2835,11 +2803,10 @@ void Delete_file_log_event::print(FILE* file, bool short_form, } #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) { @@ -2850,11 +2817,10 @@ void Delete_file_log_event::pack_info(Protocol *protocol) } #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) { @@ -2871,31 +2837,26 @@ int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) #endif -/***************************************************************************** - ***************************************************************************** - - Execute_load_log_event methods - - ***************************************************************************** - ****************************************************************************/ - -/***************************************************************************** +/************************************************************************** + 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 +#endif -/***************************************************************************** +/* 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) { @@ -2904,11 +2865,11 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, int len) file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET); } -/***************************************************************************** +/* Execute_load_log_event::write_data() +*/ - ****************************************************************************/ int Execute_load_log_event::write_data(IO_CACHE* file) { byte buf[EXEC_LOAD_HEADER_LEN]; @@ -2916,11 +2877,11 @@ int Execute_load_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN); } -/***************************************************************************** +/* Execute_load_log_event::print() +*/ - ****************************************************************************/ #ifdef MYSQL_CLIENT void Execute_load_log_event::print(FILE* file, bool short_form, char* last_db) @@ -2932,13 +2893,12 @@ void Execute_load_log_event::print(FILE* file, bool short_form, fprintf(file, "#Exec_load: file_id=%d\n", file_id); } -#endif // MYSQL_CLIENT - -/***************************************************************************** +#endif +/* Execute_load_log_event::pack_info() +*/ - ****************************************************************************/ #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) void Execute_load_log_event::pack_info(Protocol *protocol) { @@ -2948,11 +2908,10 @@ void Execute_load_log_event::pack_info(Protocol *protocol) protocol->store(buf, (int32) length, &my_charset_bin); } -/***************************************************************************** +/* Execute_load_log_event::exec_event() - - ****************************************************************************/ +*/ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) { @@ -3017,22 +2976,17 @@ err: return error ? error : Log_event::exec_event(rli); } -#endif - - -/***************************************************************************** - ***************************************************************************** - - sql_ex_info methods +#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ - ***************************************************************************** - ****************************************************************************/ -/***************************************************************************** +/************************************************************************** + sql_ex_info methods +**************************************************************************/ +/* sql_ex_info::write_data() +*/ - ****************************************************************************/ int sql_ex_info::write_data(IO_CACHE* file) { if (new_format()) @@ -3058,11 +3012,11 @@ int sql_ex_info::write_data(IO_CACHE* file) } } -/***************************************************************************** +/* sql_ex_info::init() +*/ - ****************************************************************************/ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) { cached_new_format = use_new_format; diff --git a/sql/log_event.h b/sql/log_event.h index 62b5873fabb..1d2fc741fa8 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -227,10 +227,11 @@ struct sql_ex_info 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, USER_VAR_EVENT=14 + UNKNOWN_EVENT= 0, 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, + USER_VAR_EVENT= 14 }; enum Int_event_type @@ -524,14 +525,14 @@ extern char server_version[SERVER_VERSION_LENGTH]; class Start_log_event: public Log_event { public: - uint32 created; + time_t created; uint16 binlog_version; char server_version[ST_SERVER_VER_LEN]; #ifndef MYSQL_CLIENT Start_log_event() :Log_event(), binlog_version(BINLOG_VERSION) { - created = (uint32) when; + created = (time_t) when; memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); } #ifdef HAVE_REPLICATION @@ -887,4 +888,18 @@ public: int write_data(IO_CACHE* file); }; +#ifdef MYSQL_CLIENT +class Unknown_log_event: public Log_event +{ +public: + Unknown_log_event(const char* buf, bool old_format): + Log_event(buf, old_format) + {} + ~Unknown_log_event() {} + void print(FILE* file, bool short_form= 0, char* last_db= 0); + Log_event_type get_type_code() { return UNKNOWN_EVENT;} + bool is_valid() { return 1; } +}; +#endif + #endif /* _log_event_h */ diff --git a/sql/mini_client.cc b/sql/mini_client.cc deleted file mode 100644 index afcee5fbb02..00000000000 --- a/sql/mini_client.cc +++ /dev/null @@ -1,1422 +0,0 @@ -/* 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 */ - -/* - mini MySQL client to be included into the server to do server to server - commincation by Sasha Pachev - - Note: all file-global symbols must begin with mc_ , even the static ones, just - in case we decide to make them external at some point -*/ - -#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() */ -#endif -#include <thr_alarm.h> -#include <mysql_embed.h> -#include <mysql_com.h> -#include <violite.h> -#include <my_sys.h> -#include <mysys_err.h> -#include <m_string.h> -#include <m_ctype.h> -#include "mysql.h" -#include "mini_client.h" -#include "mysql_version.h" -#include "mysqld_error.h" -#include "errmsg.h" -#include <assert.h> - -#if defined( OS2) && defined(MYSQL_SERVER) -#undef ER -#define ER CER -#endif - -extern "C" { // Because of SCO 3.2V4.2 -#include <sys/stat.h> -#include <signal.h> -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#if !defined(MSDOS) && !defined(__WIN__) -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#ifdef HAVE_SELECT_H -# include <select.h> -#endif -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif -#endif /*!defined(MSDOS) && !defined(__WIN__) */ -#ifdef HAVE_SYS_UN_H -# include <sys/un.h> -#endif -#ifndef INADDR_NONE -#define INADDR_NONE -1 -#endif -} - -static void mc_free_rows(MYSQL_DATA *cur); -void mc_end_server(MYSQL *mysql); -static int mc_sock_connect(File s, const struct sockaddr *name, uint namelen, uint to); -static void mc_free_old_query(MYSQL *mysql); -static int mc_send_file_to_server(MYSQL *mysql, const char *filename); -static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, - ulong *lengths); -static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, - uint fields); - - - -#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | \ - CLIENT_LOCAL_FILES | CLIENT_SECURE_CONNECTION) - - -#if defined(MSDOS) || defined(__WIN__) -#define perror(A) -#else -#include <errno.h> -#define SOCKET_ERROR -1 -#endif - -#ifdef __WIN__ -static my_bool is_NT(void) -{ - char *os=getenv("OS"); - return (os && !strcmp(os, "Windows_NT")) ? 1 : 0; -} -#endif - -extern ulong slave_net_timeout; - -/* -** Create a named pipe connection -*/ - -#ifdef __WIN__ - -HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, - char **arg_unix_socket) -{ - HANDLE hPipe=INVALID_HANDLE_VALUE; - char szPipeName [ 257 ]; - DWORD dwMode; - int i; - my_bool testing_named_pipes=0; - char *host= *arg_host, *unix_socket= *arg_unix_socket; - - if (!host || !strcmp(host,LOCAL_HOST)) - host=LOCAL_HOST_NAMEDPIPE; - - sprintf(szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket); - DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s", - host, unix_socket)); - - for (i=0 ; i < 100 ; i++) /* Don't retry forever */ - { - if ((hPipe = CreateFile(szPipeName, - GENERIC_READ | GENERIC_WRITE, - 0, - NULL, - OPEN_EXISTING, - 0, - NULL )) != INVALID_HANDLE_VALUE) - break; - if (GetLastError() != ERROR_PIPE_BUSY) - { - net->last_errno=CR_NAMEDPIPEOPEN_ERROR; - sprintf(net->last_error,ER(net->last_errno),host, unix_socket, - (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - /* wait for for an other instance */ - if (! WaitNamedPipe(szPipeName, connect_timeout*1000) ) - { - net->last_errno=CR_NAMEDPIPEWAIT_ERROR; - sprintf(net->last_error,ER(net->last_errno),host, unix_socket, - (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - } - if (hPipe == INVALID_HANDLE_VALUE) - { - net->last_errno=CR_NAMEDPIPEOPEN_ERROR; - sprintf(net->last_error,ER(net->last_errno),host, unix_socket, - (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - dwMode = PIPE_READMODE_BYTE | PIPE_WAIT; - if ( !SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL) ) - { - CloseHandle( hPipe ); - net->last_errno=CR_NAMEDPIPESETSTATE_ERROR; - sprintf(net->last_error,ER(net->last_errno),host, unix_socket, - (ulong) GetLastError()); - return INVALID_HANDLE_VALUE; - } - *arg_host=host ; *arg_unix_socket=unix_socket; /* connect arg */ - return (hPipe); -} -#endif - - -/**************************************************************************** -** Init MySQL structure or allocate one -****************************************************************************/ - -MYSQL *mc_mysql_init(MYSQL *mysql) -{ - init_client_errs(); - if (!mysql) - { - if (!(mysql=(MYSQL*) my_malloc(sizeof(*mysql),MYF(MY_WME | MY_ZEROFILL)))) - return 0; - mysql->free_me=1; - mysql->net.vio = 0; - } - else - bzero((char*) (mysql),sizeof(*(mysql))); -#ifdef __WIN__ - mysql->options.connect_timeout=20; -#endif - mysql->net.read_timeout = slave_net_timeout; - return mysql; -} - -/************************************************************************** -** Shut down connection -**************************************************************************/ - -void -mc_end_server(MYSQL *mysql) -{ - DBUG_ENTER("mc_end_server"); - if (mysql->net.vio != 0) - { - DBUG_PRINT("info",("Net: %s", vio_description(mysql->net.vio))); - vio_delete(mysql->net.vio); - mysql->net.vio= 0; /* Marker */ - } - net_end(&mysql->net); - mc_free_old_query(mysql); - DBUG_VOID_RETURN; -} - -static void mc_free_old_query(MYSQL *mysql) -{ - DBUG_ENTER("mc_free_old_query"); - if (mysql->fields) - free_root(&mysql->field_alloc,MYF(0)); - else - init_alloc_root(&mysql->field_alloc,8192,0); /* Assume rowlength < 8192 */ - mysql->fields=0; - mysql->field_count=0; /* For API */ - DBUG_VOID_RETURN; -} - - -/**************************************************************************** -* A modified version of connect(). mc_sock_connect() allows you to specify -* a timeout value, in seconds, that we should wait until we -* derermine we can't connect to a particular host. If timeout is 0, -* mc_sock_connect() will behave exactly like connect(). -* -* Base version coded by Steve Bernacki, Jr. <steve@navinet.net> -*****************************************************************************/ - -static int mc_sock_connect(my_socket s, const struct sockaddr *name, - uint namelen, uint to) -{ -#if defined(__WIN__) || defined(OS2) - return connect(s, (struct sockaddr*) name, namelen); -#else - int flags, res, s_err; - SOCKOPT_OPTLEN_TYPE s_err_size = sizeof(uint); - fd_set sfds; - struct timeval tv; - - /* If they passed us a timeout of zero, we should behave - * exactly like the normal connect() call does. - */ - - if (to == 0) - return connect(s, (struct sockaddr*) name, namelen); - - flags = fcntl(s, F_GETFL, 0); /* Set socket to not block */ -#ifdef O_NONBLOCK - fcntl(s, F_SETFL, flags | O_NONBLOCK); /* and save the flags.. */ -#endif - - res = connect(s, (struct sockaddr*) name, namelen); - s_err = errno; /* Save the error... */ - fcntl(s, F_SETFL, flags); - if ((res != 0) && (s_err != EINPROGRESS)) - { - errno = s_err; /* Restore it */ - return(-1); - } - if (res == 0) /* Connected quickly! */ - return(0); - - /* Otherwise, our connection is "in progress." We can use - * the select() call to wait up to a specified period of time - * for the connection to suceed. If select() returns 0 - * (after waiting howevermany seconds), our socket never became - * writable (host is probably unreachable.) Otherwise, if - * select() returns 1, then one of two conditions exist: - * - * 1. An error occured. We use getsockopt() to check for this. - * 2. The connection was set up sucessfully: getsockopt() will - * return 0 as an error. - * - * Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk> - * who posted this method of timing out a connect() in - * comp.unix.programmer on August 15th, 1997. - */ - - FD_ZERO(&sfds); - FD_SET(s, &sfds); - tv.tv_sec = (long) to; - tv.tv_usec = 0; -#ifdef HPUX10 - res = select(s+1, NULL, (int*) &sfds, NULL, &tv); -#else - res = select(s+1, NULL, &sfds, NULL, &tv); -#endif /* HPUX10 */ - if (res <= 0) /* Never became writable */ - return(-1); - - /* select() returned something more interesting than zero, let's - * see if we have any errors. If the next two statements pass, - * we've got an open socket! - */ - - s_err=0; - if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0) - return(-1); - - if (s_err) - { // getsockopt() could succeed - errno = s_err; - return(-1); // but return an error... - } - return(0); /* It's all good! */ -#endif -} - -/***************************************************************************** -** read a packet from server. Give error message if socket was down -** or packet is an error message -*****************************************************************************/ - -ulong -mc_net_safe_read(MYSQL *mysql) -{ - NET *net= &mysql->net; - ulong len=0; - - if (net->vio != 0) - len=my_net_read(net); - - if (len == packet_error || len == 0) - { - DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", - vio_description(net->vio),len)); - if (socket_errno != SOCKET_EINTR) - { - mc_end_server(mysql); - if (net->last_errno != ER_NET_PACKET_TOO_LARGE) - { - net->last_errno=CR_SERVER_LOST; - strmov(net->last_error,ER(net->last_errno)); - } - else - strmov(net->last_error, "Packet too large - increase \ -max_allowed_packet on this server"); - } - return(packet_error); - } - if (net->read_pos[0] == 255) - { - if (len > 3) - { - char *pos=(char*) net->read_pos+1; - if (mysql->protocol_version > 9) - { /* New client protocol */ - net->last_errno=uint2korr(pos); - pos+=2; - len-=2; - if (!net->last_errno) - net->last_errno = CR_UNKNOWN_ERROR; - } - else - { - net->last_errno=CR_UNKNOWN_ERROR; - len--; - } - (void) strmake(net->last_error,(char*) pos, - min(len,sizeof(net->last_error)-1)); - } - else - { - net->last_errno=CR_UNKNOWN_ERROR; - (void) strmov(net->last_error,ER(net->last_errno)); - } - DBUG_PRINT("error",("Got error: %d (%s)", net->last_errno, - net->last_error)); - return(packet_error); - } - return len; -} - - -char *mc_mysql_error(MYSQL *mysql) -{ - return (mysql)->net.last_error; -} - -int mc_mysql_errno(MYSQL *mysql) -{ - return (mysql)->net.last_errno; -} - - -my_bool mc_mysql_reconnect(MYSQL *mysql) -{ - MYSQL tmp_mysql; - DBUG_ENTER("mc_mysql_reconnect"); - - if (!mysql->reconnect) - { - mysql->net.last_errno=CR_SERVER_GONE_ERROR; - strmov(mysql->net.last_error, ER(mysql->net.last_errno)); - DBUG_RETURN(1); - } - mc_mysql_init(&tmp_mysql); - tmp_mysql.options=mysql->options; - if (!mc_mysql_connect(&tmp_mysql,mysql->host,mysql->user,mysql->passwd, - mysql->db, mysql->port, mysql->unix_socket, - mysql->client_flag, mysql->net.read_timeout)) - { - mysql->net.last_errno= tmp_mysql.net.last_errno; - strmov(mysql->net.last_error, tmp_mysql.net.last_error); - DBUG_RETURN(1); - } - tmp_mysql.free_me=mysql->free_me; - mysql->free_me=0; - bzero((char*) &mysql->options,sizeof(&mysql->options)); - mc_mysql_close(mysql); - *mysql=tmp_mysql; - net_clear(&mysql->net); - mysql->affected_rows= ~(my_ulonglong) 0; - DBUG_RETURN(0); -} - - - -int -mc_simple_command(MYSQL *mysql,enum enum_server_command command, - const char *arg, uint length, my_bool skipp_check) -{ - NET *net= &mysql->net; - int result= -1; - - if (mysql->net.vio == 0) - { /* Do reconnect if possible */ - if (mc_mysql_reconnect(mysql)) - goto end; - } - if (mysql->status != MYSQL_STATUS_READY) - { - strmov(net->last_error,ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); - goto end; - } - - 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, NullS, 0, arg, length)) - { - 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, NullS, 0, arg, length)) - { - net->last_errno=CR_SERVER_GONE_ERROR; - strmov(net->last_error,ER(net->last_errno)); - goto end; - } - } - result=0; - if (!skipp_check) - result= ((mysql->packet_length=mc_net_safe_read(mysql)) == packet_error ? - -1 : 0); - end: - return result; -} - - -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; - ulong pkt_length; - NET *net= &mysql->net; - thr_alarm_t alarmed; - ALARM alarm_buff; - ulong max_allowed_packet; - -#ifdef __WIN__ - HANDLE hPipe=INVALID_HANDLE_VALUE; -#endif -#ifdef HAVE_SYS_UN_H - struct sockaddr_un UNIXaddr; -#endif - DBUG_ENTER("mc_mysql_connect"); - DBUG_PRINT("enter",("host: %s db: %s user: %s connect_time_out: %u read_timeout: %u", - host ? host : "(Null)", - db ? db : "(Null)", - 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) - port = MYSQL_PORT; /* Should always be set by mysqld */ - if (!unix_socket) - unix_socket=MYSQL_UNIX_ADDR; - - mysql->reconnect=1; /* Reconnect as default */ - mysql->server_status=SERVER_STATUS_AUTOCOMMIT; - if (!mysql->options.connect_timeout) - mysql->options.connect_timeout= net_read_timeout; - - /* - ** Grab a socket and connect it to the server - */ - -#if defined(HAVE_SYS_UN_H) - if ((!host || !strcmp(host,LOCAL_HOST)) && unix_socket) - { - host=LOCAL_HOST; - host_info=(char*) ER(CR_LOCALHOST_CONNECTION); - DBUG_PRINT("info",("Using UNIX sock '%s'",unix_socket)); - if ((sock = socket(AF_UNIX,SOCK_STREAM,0)) == SOCKET_ERROR) - { - net->last_errno=CR_SOCKET_CREATE_ERROR; - sprintf(net->last_error,ER(net->last_errno),socket_errno); - goto error; - } - net->vio = vio_new(sock, VIO_TYPE_SOCKET, TRUE); - bzero((char*) &UNIXaddr,sizeof(UNIXaddr)); - UNIXaddr.sun_family = AF_UNIX; - strmov(UNIXaddr.sun_path, unix_socket); - if (mc_sock_connect(sock, - my_reinterpret_cast(struct sockaddr *) (&UNIXaddr), - sizeof(UNIXaddr), - mysql->options.connect_timeout) <0) - { - DBUG_PRINT("error",("Got error %d on connect to local server", - socket_errno)); - net->last_errno=CR_CONNECTION_ERROR; - sprintf(net->last_error,ER(net->last_errno),unix_socket,socket_errno); - goto error; - } - } - else -#elif defined(__WIN__) - { - if ((unix_socket || - !host && is_NT() || - host && !strcmp(host,LOCAL_HOST_NAMEDPIPE) || - mysql->options.named_pipe || !have_tcpip)) - { - sock=0; - if ((hPipe=create_named_pipe(net, mysql->options.connect_timeout, - (char**) &host, (char**) &unix_socket)) == - INVALID_HANDLE_VALUE) - { - DBUG_PRINT("error", - ("host: '%s' socket: '%s' named_pipe: %d have_tcpip: %d", - host ? host : "<null>", - unix_socket ? unix_socket : "<null>", - (int) mysql->options.named_pipe, - (int) have_tcpip)); - if (mysql->options.named_pipe || - (host && !strcmp(host,LOCAL_HOST_NAMEDPIPE)) || - (unix_socket && !strcmp(unix_socket,MYSQL_NAMEDPIPE))) - goto error; /* User only requested named pipes */ - /* Try also with TCP/IP */ - } - else - { - net->vio=vio_new_win32pipe(hPipe); - sprintf(host_info=buff, ER(CR_NAMEDPIPE_CONNECTION), host, - unix_socket); - } - } - } - if (hPipe == INVALID_HANDLE_VALUE) -#endif - { - unix_socket=0; /* This is not used */ - if (!host) - host=LOCAL_HOST; - sprintf(host_info=buff,ER(CR_TCP_CONNECTION),host); - DBUG_PRINT("info",("Server name: '%s'. TCP sock: %d", host,port)); - thr_alarm_init(&alarmed); - thr_alarm(&alarmed, net_read_timeout, &alarm_buff); - sock = (my_socket) socket(AF_INET,SOCK_STREAM,0); - thr_end_alarm(&alarmed); - if (sock == SOCKET_ERROR) - { - net->last_errno=CR_IPSOCK_ERROR; - sprintf(net->last_error,ER(net->last_errno),socket_errno); - goto error; - } - net->vio = vio_new(sock,VIO_TYPE_TCPIP,FALSE); - bzero((char*) &sock_addr,sizeof(sock_addr)); - sock_addr.sin_family = AF_INET; - - /* - ** The server name may be a host name or IP address - */ - - if ((int) (ip_addr = inet_addr(host)) != (int) INADDR_NONE) - { - memcpy_fixed(&sock_addr.sin_addr,&ip_addr,sizeof(ip_addr)); - } - else - { - int tmp_errno; - struct hostent tmp_hostent,*hp; - char buff2[GETHOSTBYNAME_BUFF_SIZE]; - hp = my_gethostbyname_r(host,&tmp_hostent,buff2,sizeof(buff2), - &tmp_errno); - if (!hp) - { - net->last_errno=CR_UNKNOWN_HOST; - sprintf(net->last_error, ER(CR_UNKNOWN_HOST), host, tmp_errno); - my_gethostbyname_r_free(); - goto error; - } - memcpy(&sock_addr.sin_addr,hp->h_addr, (size_t) hp->h_length); - my_gethostbyname_r_free(); - } - sock_addr.sin_port = (ushort) htons((ushort) port); - if (mc_sock_connect(sock, - my_reinterpret_cast(struct sockaddr *) (&sock_addr), - sizeof(sock_addr), - mysql->options.connect_timeout) <0) - { - DBUG_PRINT("error",("Got error %d on connect to '%s'", - socket_errno,host)); - net->last_errno= CR_CONN_HOST_ERROR; - sprintf(net->last_error ,ER(CR_CONN_HOST_ERROR), host, socket_errno); - goto error; - } - } - - if (!net->vio || my_net_init(net, net->vio)) - { - vio_delete(net->vio); - net->vio = 0; - net->last_errno=CR_OUT_OF_MEMORY; - strmov(net->last_error,ER(net->last_errno)); - goto error; - } - vio_keepalive(net->vio,TRUE); - net->read_timeout=slave_net_timeout; - /* Get version info */ - mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */ - if (mysql->options.connect_timeout && - vio_poll_read(net->vio, mysql->options.connect_timeout)) - { - net->last_errno= CR_SERVER_LOST; - strmov(net->last_error,ER(net->last_errno)); - goto error; - } - if ((pkt_length=mc_net_safe_read(mysql)) == packet_error) - goto error; - - /* Check if version of protocol matches current one */ - - mysql->protocol_version= net->read_pos[0]; - DBUG_DUMP("packet",(char*) net->read_pos,10); - DBUG_PRINT("info",("mysql protocol version %d, server=%d", - PROTOCOL_VERSION, mysql->protocol_version)); - if (mysql->protocol_version != PROTOCOL_VERSION && - mysql->protocol_version != PROTOCOL_VERSION-1) - { - net->last_errno= CR_VERSION_ERROR; - sprintf(net->last_error, ER(CR_VERSION_ERROR), mysql->protocol_version, - PROTOCOL_VERSION); - goto error; - } - end=strend((char*) net->read_pos+1); - mysql->thread_id=uint4korr(end+1); - end+=5; - strmake(mysql->scramble_buff,end,8); - end+=9; - if (pkt_length >= (uint) (end+1 - (char*) net->read_pos)) - mysql->server_capabilities=uint2korr(end); - if (pkt_length >= (uint) (end+18 - (char*) net->read_pos)) - { - /* New protocol with 16 bytes to describe server characteristics */ - mysql->server_language=end[2]; - mysql->server_status=uint2korr(end+3); - } - - /* Save connection information */ - if (!user) user=""; - if (!passwd) passwd=""; - if (!my_multi_malloc(MYF(0), - &mysql->host_info, (uint) strlen(host_info)+1, - &mysql->host, (uint) strlen(host)+1, - &mysql->unix_socket, - unix_socket ? (uint) strlen(unix_socket)+1 : (uint) 1, - &mysql->server_version, - (uint) (end - (char*) net->read_pos), - NullS) || - !(mysql->user=my_strdup(user,MYF(0))) || - !(mysql->passwd=my_strdup(passwd,MYF(0)))) - { - strmov(net->last_error, ER(net->last_errno=CR_OUT_OF_MEMORY)); - goto error; - } - strmov(mysql->host_info,host_info); - strmov(mysql->host,host); - if (unix_socket) - strmov(mysql->unix_socket,unix_socket); - else - mysql->unix_socket=0; - strmov(mysql->server_version,(char*) net->read_pos+1); - mysql->port=port; - client_flag|=mysql->options.client_flag; - DBUG_PRINT("info",("Server version = '%s' capabilites: %ld", - mysql->server_version,mysql->server_capabilities)); - - /* Send client information for access check */ - client_flag|=CLIENT_CAPABILITIES; - -#ifdef HAVE_OPENSSL - if (mysql->options.ssl_key || mysql->options.ssl_cert || - mysql->options.ssl_ca || mysql->options.ssl_capath || - mysql->options.ssl_cipher) - mysql->options.use_ssl= 1; - if (mysql->options.use_ssl) - client_flag|=CLIENT_SSL; -#endif /* HAVE_OPENSSL */ - - if (db) - client_flag|=CLIENT_CONNECT_WITH_DB; -#ifdef HAVE_COMPRESS - if ((mysql->server_capabilities & CLIENT_COMPRESS) && - (mysql->options.compress || (client_flag & CLIENT_COMPRESS))) - client_flag|=CLIENT_COMPRESS; /* We will use compression */ - else -#endif - client_flag&= ~CLIENT_COMPRESS; - -#ifdef HAVE_OPENSSL - if ((mysql->server_capabilities & CLIENT_SSL) && - (mysql->options.use_ssl || (client_flag & CLIENT_SSL))) - { - DBUG_PRINT("info", ("Changing IO layer to SSL")); - client_flag |= CLIENT_SSL; - } - else - { - if (client_flag & CLIENT_SSL) - { - DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL")); - } - client_flag &= ~CLIENT_SSL; - } -#endif /* HAVE_OPENSSL */ - - int2store(buff,client_flag); - mysql->client_flag=client_flag; - -#ifdef HAVE_OPENSSL - /* - Oops.. are we careful enough to not send ANY information without - encryption? - */ - if (client_flag & CLIENT_SSL) - { - 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)); - goto error; - } - /* Do the SSL layering. */ - DBUG_PRINT("info", ("IO layer change in progress...")); - DBUG_PRINT("info", ("IO context %p",((struct st_VioSSLConnectorFd*)mysql->connector_fd)->ssl_context_)); - sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),mysql->net.vio, (long)(mysql->options.connect_timeout)); - DBUG_PRINT("info", ("IO layer change done!")); - } -#endif /* HAVE_OPENSSL */ - max_allowed_packet=mysql->net.max_packet_size; - int3store(buff+2,max_allowed_packet); - - - if (user && user[0]) - strmake(buff+5,user,32); - else - { - user = getenv("USER"); - if (!user) user = "mysql"; - strmov((char*) buff+5, user ); - } - - DBUG_PRINT("info",("user: %s",buff+5)); - - /* - 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)); - goto 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)); - DBUG_RETURN(mysql); - -error: - DBUG_PRINT("error",("message: %u (%s)",net->last_errno,net->last_error)); - { - /* Free alloced memory */ - my_bool free_me=mysql->free_me; - mc_end_server(mysql); - mysql->free_me=0; - mc_mysql_close(mysql); - mysql->free_me=free_me; - } - DBUG_RETURN(0); -} - - -#ifdef HAVE_OPENSSL -/* -************************************************************************** -** Free strings in the SSL structure and clear 'use_ssl' flag. -** NB! Errors are not reported until you do mysql_real_connect. -************************************************************************** -*/ -int -mysql_ssl_clear(MYSQL *mysql) -{ - my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR)); - mysql->options.ssl_key = 0; - mysql->options.ssl_cert = 0; - mysql->options.ssl_ca = 0; - mysql->options.ssl_capath = 0; - mysql->options.ssl_cipher= 0; - mysql->options.use_ssl = FALSE; - my_free(mysql->connector_fd,MYF(MY_ALLOW_ZERO_PTR)); - mysql->connector_fd = 0; - return 0; -} -#endif /* HAVE_OPENSSL */ - -/************************************************************************* -** Send a QUIT to the server and close the connection -** If handle is alloced by mysql connect free it. -*************************************************************************/ - -void -mc_mysql_close(MYSQL *mysql) -{ - DBUG_ENTER("mysql_close"); - if (mysql) /* Some simple safety */ - { - if (mysql->net.vio != 0) - { - mc_free_old_query(mysql); - mysql->status=MYSQL_STATUS_READY; /* Force command */ - mysql->reconnect=0; - mc_simple_command(mysql,COM_QUIT,NullS,0,1); - mc_end_server(mysql); - } - my_free((gptr) mysql->host_info,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); - /* Clear pointers for better safety */ - mysql->host_info=mysql->user=mysql->passwd=mysql->db=0; - bzero((char*) &mysql->options,sizeof(mysql->options)); -#ifdef HAVE_OPENSSL - mysql_ssl_clear(mysql); -#endif /* HAVE_OPENSSL */ - if (mysql->free_me) - my_free((gptr) mysql,MYF(0)); - } - DBUG_VOID_RETURN; -} - -void mc_mysql_free_result(MYSQL_RES *result) -{ - DBUG_ENTER("mc_mysql_free_result"); - DBUG_PRINT("enter",("mysql_res: %lx",result)); - if (result) - { - if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT) - { - DBUG_PRINT("warning",("Not all rows in set were read; Ignoring rows")); - for (;;) - { - ulong pkt_len; - if ((pkt_len=mc_net_safe_read(result->handle)) == packet_error) - break; - if (pkt_len == 1 && result->handle->net.read_pos[0] == 254) - break; /* End of data */ - } - result->handle->status=MYSQL_STATUS_READY; - } - mc_free_rows(result->data); - if (result->fields) - free_root(&result->field_alloc,MYF(0)); - if (result->row) - my_free((gptr) result->row,MYF(0)); - my_free((gptr) result,MYF(0)); - } - DBUG_VOID_RETURN; -} - -static void mc_free_rows(MYSQL_DATA *cur) -{ - if (cur) - { - free_root(&cur->alloc,MYF(0)); - my_free((gptr) cur,MYF(0)); - } -} - -static MYSQL_FIELD * -mc_unpack_fields(MYSQL_DATA *data,MEM_ROOT *alloc,uint fields, - my_bool default_value, my_bool long_flag_protocol) -{ - MYSQL_ROWS *row; - MYSQL_FIELD *field,*result; - DBUG_ENTER("unpack_fields"); - - field=result=(MYSQL_FIELD*) alloc_root(alloc,sizeof(MYSQL_FIELD)*fields); - if (!result) - DBUG_RETURN(0); - - for (row=data->data; row ; row = row->next,field++) - { - field->table= strdup_root(alloc,(char*) row->data[0]); - field->name= strdup_root(alloc,(char*) row->data[1]); - field->length= (uint) uint3korr(row->data[2]); - field->type= (enum enum_field_types) (uchar) row->data[3][0]; - if (long_flag_protocol) - { - field->flags= uint2korr(row->data[4]); - field->decimals=(uint) (uchar) row->data[4][2]; - } - else - { - field->flags= (uint) (uchar) row->data[4][0]; - field->decimals=(uint) (uchar) row->data[4][1]; - } - if (INTERNAL_NUM_FIELD(field)) - field->flags|= NUM_FLAG; - if (default_value && row->data[5]) - field->def=strdup_root(alloc,(char*) row->data[5]); - else - field->def=0; - field->max_length= 0; - } - mc_free_rows(data); /* Free old data */ - DBUG_RETURN(result); -} - -int mc_mysql_send_query(MYSQL* mysql, const char* query, uint length) -{ - return mc_simple_command(mysql, COM_QUERY, query, length, 1); -} - - -int mc_mysql_read_query_result(MYSQL *mysql) -{ - uchar *pos; - ulong field_count; - MYSQL_DATA *fields; - ulong length; - DBUG_ENTER("mc_mysql_read_query_result"); - - if ((length = mc_net_safe_read(mysql)) == packet_error) - DBUG_RETURN(-1); - mc_free_old_query(mysql); /* Free old result */ -get_info: - pos=(uchar*) mysql->net.read_pos; - if ((field_count= net_field_length(&pos)) == 0) - { - mysql->affected_rows= net_field_length_ll(&pos); - mysql->insert_id= net_field_length_ll(&pos); - if (mysql->server_capabilities & CLIENT_TRANSACTIONS) - { - mysql->server_status=uint2korr(pos); pos+=2; - } - if (pos < mysql->net.read_pos+length && net_field_length(&pos)) - mysql->info=(char*) pos; - DBUG_RETURN(0); - } - if (field_count == NULL_LENGTH) /* LOAD DATA LOCAL INFILE */ - { - int error=mc_send_file_to_server(mysql,(char*) pos); - if ((length=mc_net_safe_read(mysql)) == packet_error || error) - DBUG_RETURN(-1); - goto get_info; /* Get info packet */ - } - if (!(mysql->server_status & SERVER_STATUS_AUTOCOMMIT)) - mysql->server_status|= SERVER_STATUS_IN_TRANS; - - mysql->extra_info= net_field_length_ll(&pos); /* Maybe number of rec */ - if (!(fields=mc_read_rows(mysql,(MYSQL_FIELD*) 0,5))) - DBUG_RETURN(-1); - if (!(mysql->fields=mc_unpack_fields(fields,&mysql->field_alloc, - (uint) field_count,0, - (my_bool) test(mysql->server_capabilities & - CLIENT_LONG_FLAG)))) - DBUG_RETURN(-1); - mysql->status=MYSQL_STATUS_GET_RESULT; - mysql->field_count=field_count; - DBUG_RETURN(0); -} - - -int mc_mysql_query(MYSQL *mysql, const char *query, uint length) -{ - DBUG_ENTER("mc_mysql_query"); - DBUG_PRINT("enter",("handle: %lx",mysql)); - DBUG_PRINT("query",("Query = \"%s\"",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; - uint packet_length=MY_ALIGN(mysql->net.max_packet-16,IO_SIZE); - char *buf, tmp_name[FN_REFLEN]; - DBUG_ENTER("send_file_to_server"); - - if (!(buf=my_malloc(packet_length,MYF(0)))) - { - strmov(mysql->net.last_error, ER(mysql->net.last_errno=CR_OUT_OF_MEMORY)); - DBUG_RETURN(-1); - } - - fn_format(tmp_name,filename,"","",4); /* Convert to client format */ - if ((fd = my_open(tmp_name,O_RDONLY, MYF(0))) < 0) - { - my_net_write(&mysql->net,"",0); // Server needs one packet - net_flush(&mysql->net); - mysql->net.last_errno=EE_FILENOTFOUND; - my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1, - EE(mysql->net.last_errno),tmp_name, errno); - goto err; - } - - while ((readcount = (int) my_read(fd,(byte*) buf,packet_length,MYF(0))) > 0) - { - if (my_net_write(&mysql->net,buf,readcount)) - { - DBUG_PRINT("error",("Lost connection to MySQL server during LOAD DATA of local file")); - mysql->net.last_errno=CR_SERVER_LOST; - strmov(mysql->net.last_error,ER(mysql->net.last_errno)); - goto err; - } - } - /* Send empty packet to mark end of file */ - if (my_net_write(&mysql->net,"",0) || net_flush(&mysql->net)) - { - mysql->net.last_errno=CR_SERVER_LOST; - sprintf(mysql->net.last_error,ER(mysql->net.last_errno),errno); - goto err; - } - if (readcount < 0) - { - mysql->net.last_errno=EE_READ; /* the errmsg for not entire file read */ - my_snprintf(mysql->net.last_error,sizeof(mysql->net.last_error)-1, - tmp_name,errno); - goto err; - } - result=0; // Ok - -err: - if (fd >= 0) - (void) my_close(fd,MYF(0)); - my_free(buf,MYF(0)); - DBUG_RETURN(result); -} - -/* Read all rows (fields or data) from server */ - -static MYSQL_DATA *mc_read_rows(MYSQL *mysql,MYSQL_FIELD *mysql_fields, - uint fields) -{ - uint field; - ulong pkt_len; - ulong len; - uchar *cp; - char *to; - MYSQL_DATA *result; - MYSQL_ROWS **prev_ptr,*cur; - NET *net = &mysql->net; - DBUG_ENTER("mc_read_rows"); - - if ((pkt_len=mc_net_safe_read(mysql)) == packet_error) - DBUG_RETURN(0); - if (!(result=(MYSQL_DATA*) my_malloc(sizeof(MYSQL_DATA), - MYF(MY_ZEROFILL)))) - { - net->last_errno=CR_OUT_OF_MEMORY; - strmov(net->last_error,ER(net->last_errno)); - DBUG_RETURN(0); - } - init_alloc_root(&result->alloc,8192,0); /* Assume rowlength < 8192 */ - result->alloc.min_malloc=sizeof(MYSQL_ROWS); - prev_ptr= &result->data; - result->rows=0; - result->fields=fields; - - while (*(cp=net->read_pos) != 254 || pkt_len != 1) - { - result->rows++; - if (!(cur= (MYSQL_ROWS*) alloc_root(&result->alloc, - sizeof(MYSQL_ROWS))) || - !(cur->data= ((MYSQL_ROW) - alloc_root(&result->alloc, - (fields+1)*sizeof(char *)+pkt_len)))) - { - mc_free_rows(result); - net->last_errno=CR_OUT_OF_MEMORY; - strmov(net->last_error,ER(net->last_errno)); - DBUG_RETURN(0); - } - *prev_ptr=cur; - prev_ptr= &cur->next; - to= (char*) (cur->data+fields+1); - for (field=0 ; field < fields ; field++) - { - if ((len=(ulong) net_field_length(&cp)) == NULL_LENGTH) - { /* null field */ - cur->data[field] = 0; - } - else - { - cur->data[field] = to; - memcpy(to,(char*) cp,len); to[len]=0; - to+=len+1; - cp+=len; - if (mysql_fields) - { - if (mysql_fields[field].max_length < len) - mysql_fields[field].max_length=len; - } - } - } - cur->data[field]=to; /* End of last field */ - if ((pkt_len=mc_net_safe_read(mysql)) == packet_error) - { - mc_free_rows(result); - DBUG_RETURN(0); - } - } - *prev_ptr=0; /* last pointer is null */ - DBUG_PRINT("exit",("Got %d rows",result->rows)); - DBUG_RETURN(result); -} - - -/* -** Read one row. Uses packet buffer as storage for fields. -** When next packet is read, the previous field values are destroyed -*/ - - -static int mc_read_one_row(MYSQL *mysql,uint fields,MYSQL_ROW row, - ulong *lengths) -{ - uint field; - ulong pkt_len,len; - uchar *pos; - uchar *prev_pos; - - if ((pkt_len=mc_net_safe_read(mysql)) == packet_error) - return -1; - if (pkt_len == 1 && mysql->net.read_pos[0] == 254) - return 1; /* End of data */ - prev_pos= 0; /* allowed to write at packet[-1] */ - pos=mysql->net.read_pos; - for (field=0 ; field < fields ; field++) - { - if ((len=(ulong) net_field_length(&pos)) == NULL_LENGTH) - { /* null field */ - row[field] = 0; - *lengths++=0; - } - else - { - row[field] = (char*) pos; - pos+=len; - *lengths++=len; - } - if (prev_pos) - *prev_pos=0; /* Terminate prev field */ - prev_pos= pos; - } - row[field]=(char*) prev_pos+1; /* End of last field */ - *prev_pos=0; /* Terminate last field */ - return 0; -} - -my_ulonglong mc_mysql_num_rows(MYSQL_RES *res) -{ - return res->row_count; -} - -unsigned int mc_mysql_num_fields(MYSQL_RES *res) -{ - return res->field_count; -} - -void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row) -{ - MYSQL_ROWS *tmp=0; - DBUG_PRINT("info",("mysql_data_seek(%ld)",(long) row)); - if (result->data) - for (tmp=result->data->data; row-- && tmp ; tmp = tmp->next) ; - result->current_row=0; - result->data_cursor = tmp; -} - -MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res) -{ - DBUG_ENTER("mc_mysql_fetch_row"); - if (!res->data) - { /* Unbufferred fetch */ - if (!res->eof) - { - if (!(mc_read_one_row(res->handle,res->field_count,res->row, - res->lengths))) - { - res->row_count++; - DBUG_RETURN(res->current_row=res->row); - } - else - { - DBUG_PRINT("info",("end of data")); - res->eof=1; - res->handle->status=MYSQL_STATUS_READY; - } - } - DBUG_RETURN((MYSQL_ROW) NULL); - } - { - MYSQL_ROW tmp; - if (!res->data_cursor) - { - DBUG_PRINT("info",("end of data")); - DBUG_RETURN(res->current_row=(MYSQL_ROW) NULL); - } - tmp = res->data_cursor->data; - res->data_cursor = res->data_cursor->next; - DBUG_RETURN(res->current_row=tmp); - } -} - -int mc_mysql_select_db(MYSQL *mysql, const char *db) -{ - int error; - DBUG_ENTER("mysql_select_db"); - DBUG_PRINT("enter",("db: '%s'",db)); - - if ((error=mc_simple_command(mysql,COM_INIT_DB,db,(uint) strlen(db),0))) - DBUG_RETURN(error); - my_free(mysql->db,MYF(MY_ALLOW_ZERO_PTR)); - mysql->db=my_strdup(db,MYF(MY_WME)); - DBUG_RETURN(0); -} - - -MYSQL_RES *mc_mysql_store_result(MYSQL *mysql) -{ - MYSQL_RES *result; - DBUG_ENTER("mysql_store_result"); - - if (!mysql->fields) - DBUG_RETURN(0); - if (mysql->status != MYSQL_STATUS_GET_RESULT) - { - strmov(mysql->net.last_error, - ER(mysql->net.last_errno=CR_COMMANDS_OUT_OF_SYNC)); - DBUG_RETURN(0); - } - mysql->status=MYSQL_STATUS_READY; /* server is ready */ - if (!(result=(MYSQL_RES*) my_malloc(sizeof(MYSQL_RES)+ - sizeof(ulong)*mysql->field_count, - MYF(MY_ZEROFILL)))) - { - mysql->net.last_errno=CR_OUT_OF_MEMORY; - strmov(mysql->net.last_error, ER(mysql->net.last_errno)); - DBUG_RETURN(0); - } - result->eof=1; /* Marker for buffered */ - result->lengths=(ulong*) (result+1); - if (!(result->data=mc_read_rows(mysql,mysql->fields,mysql->field_count))) - { - my_free((gptr) result,MYF(0)); - DBUG_RETURN(0); - } - mysql->affected_rows= result->row_count= result->data->rows; - result->data_cursor= result->data->data; - result->fields= mysql->fields; - result->field_alloc= mysql->field_alloc; - result->field_count= mysql->field_count; - result->current_field=0; - result->current_row=0; /* Must do a fetch first */ - mysql->fields=0; /* fields is now in result */ - DBUG_RETURN(result); /* Data fetched */ -} - -#endif /* HAVE_EXTERNAL_CLIENT */ diff --git a/sql/mini_client.h b/sql/mini_client.h deleted file mode 100644 index 24c13646170..00000000000 --- a/sql/mini_client.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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 _MINI_CLIENT_H -#define _MINI_CLIENT_H - - -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); -int mc_simple_command(MYSQL *mysql,enum enum_server_command command, - const char *arg, uint length, my_bool skipp_check); -void mc_mysql_close(MYSQL *mysql); -MYSQL *mc_mysql_init(MYSQL *mysql); -void mc_mysql_debug(const char *debug); -ulong mc_net_safe_read(MYSQL *mysql); -char *mc_mysql_error(MYSQL *mysql); -int mc_mysql_errno(MYSQL *mysql); -my_bool mc_mysql_reconnect(MYSQL* mysql); -int mc_mysql_send_query(MYSQL* mysql, const char* query, uint length); -int mc_mysql_read_query_result(MYSQL *mysql); -int mc_mysql_query(MYSQL *mysql, const char *query, uint length); -MYSQL_RES * mc_mysql_store_result(MYSQL *mysql); -void mc_mysql_free_result(MYSQL_RES *result); -void mc_mysql_data_seek(MYSQL_RES *result, my_ulonglong row); -my_ulonglong mc_mysql_num_rows(MYSQL_RES *res); -unsigned int mc_mysql_num_fields(MYSQL_RES *res); -MYSQL_ROW STDCALL mc_mysql_fetch_row(MYSQL_RES *res); -int mc_mysql_select_db(MYSQL *mysql, const char *db); -void mc_end_server(MYSQL *mysql); - -#endif diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ea6e544a1fd..a59f1d4b81a 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -45,6 +45,10 @@ char *sql_strdup(const char *str); char *sql_strmake(const char *str,uint len); gptr sql_memdup(const void * ptr,unsigned size); void sql_element_free(void *ptr); +char *sql_strmake_with_convert(const char *str, uint32 arg_length, + CHARSET_INFO *from_cs, + uint32 max_res_length, + CHARSET_INFO *to_cs, uint32 *result_length); void kill_one_thread(THD *thd, ulong id); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); @@ -368,14 +372,19 @@ 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); +#ifndef EMBEDDED_LIBRARY bool check_stack_overrun(THD *thd,char *dummy); +#else +#define check_stack_overrun(A, B) 0 +#endif + bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, bool *write_to_binlog); void table_cache_init(void); void table_cache_free(void); uint cached_tables(void); void kill_mysql(void); -void close_connection(NET *net,uint errcode=0,bool lock=1); +void close_connection(THD *thd, uint errcode, bool lock); bool check_access(THD *thd, ulong access, const char *db=0, ulong *save_priv=0, bool no_grant=0, bool no_errors=0); bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables, @@ -624,8 +633,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table, bool return_if_owned_by_thd=0); bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables); void copy_field_from_tmp_record(Field *field,int offset); -int fill_record(List<Item> &fields,List<Item> &values); -int fill_record(Field **field,List<Item> &values); +int fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors); +int fill_record(Field **field,List<Item> &values, bool ignore_errors); OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild); /* sql_calc.cc */ @@ -678,11 +687,11 @@ bool open_log(MYSQL_LOG *log, const char *hostname, extern time_t start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], - mysql_real_data_home[], *charsets_list, *opt_mysql_tmpdir; + mysql_real_data_home[], *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 *first_keyword, *localhost, *delayed_user, *binary_keyword; extern const char **errmesg; /* Error messages */ extern const char *myisam_recover_options_str; extern uchar *days_in_month; @@ -690,7 +699,6 @@ extern char language[LIBLEN],reg_ext[FN_EXTLEN]; extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], time_zone[30], *opt_init_file; extern char log_error_file[FN_REFLEN]; -extern char blob_newline; extern double log_10[32]; extern ulonglong keybuff_size; extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables; @@ -736,11 +744,11 @@ extern uint volatile thread_count, thread_running, global_read_lock; 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_readonly; 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; @@ -869,6 +877,7 @@ 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, Field *field); +bool get_field(MEM_ROOT *mem, Field *field, class String *res); int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr); /* from hostname.cc */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f73bd6721f0..7011f6dcd36 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -46,7 +46,7 @@ #define MAIN_THD #define SIGNAL_THD -#ifdef PURIFY +#ifdef HAVE_purify #define IF_PURIFY(A,B) (A) #else #define IF_PURIFY(A,B) (B) @@ -116,7 +116,7 @@ int deny_severity = LOG_WARNING; #define my_fromhost(A) fromhost() #define my_hosts_access(A) hosts_access() #define my_eval_client(A) eval_client() -#endif +#endif /* __STDC__ */ #endif /* HAVE_LIBWRAP */ #ifdef HAVE_SYS_MMAN_H @@ -128,8 +128,8 @@ int deny_severity = LOG_WARNING; #include <library.h> #include <monitor.h> -event_handle_t eh; -Report_t ref; +static event_handle_t eh; +static Report_t ref; #endif /* __NETWARE__ */ #ifdef _AIX41 @@ -169,6 +169,7 @@ inline void reset_floating_point_exceptions() #else #define THR_KILL_SIGNAL SIGUSR2 // Can't use this with LinuxThreads #endif +#define MYSQL_KILL_SIGNAL SIGTERM #ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R #include <sys/types.h> @@ -183,229 +184,95 @@ inline void reset_floating_point_exceptions() extern "C" int gethostname(char *name, int namelen); #endif -#define MYSQL_KILL_SIGNAL SIGTERM - -#ifndef DBUG_OFF -static const char* default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", - "d:t:i:o,/tmp/mysqld.trace"); -#endif - -#ifdef __NT__ -static char szPipeName [ 257 ]; -static SECURITY_ATTRIBUTES saPipeSecurity; -static SECURITY_DESCRIPTOR sdPipeDescriptor; -static HANDLE hPipe = INVALID_HANDLE_VALUE; -#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; -#endif /* Set prefix for windows binary */ #ifdef __WIN__ #undef MYSQL_SERVER_SUFFIX #ifdef __NT__ -#if defined(HAVE_INNOBASE_DB) || defined(HAVE_BERKELEY_DB) +#if defined(HAVE_BERKELEY_DB) #define MYSQL_SERVER_SUFFIX "-max-nt" #else #define MYSQL_SERVER_SUFFIX "-nt" #endif /* ...DB */ -#elif defined(HAVE_INNOBASE_DB) || defined(HAVE_BERKELEY_DB) +#elif defined(HAVE_BERKELEY_DB) #define MYSQL_SERVER_SUFFIX "-max" #else #define MYSQL_SERVER_SUFFIX "" #endif /* __NT__ */ #endif /* __WIN__ */ -#ifdef HAVE_BERKELEY_DB -SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_berkeley_db=SHOW_OPTION_NO; -#endif -#ifdef HAVE_INNOBASE_DB -SHOW_COMP_OPTION have_innodb=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_innodb=SHOW_OPTION_NO; -#endif -#ifdef HAVE_ISAM -SHOW_COMP_OPTION have_isam=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_isam=SHOW_OPTION_NO; -#endif -#ifdef USE_RAID -SHOW_COMP_OPTION have_raid=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_raid=SHOW_OPTION_NO; -#endif -#ifdef HAVE_OPENSSL -SHOW_COMP_OPTION have_openssl=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_openssl=SHOW_OPTION_NO; -#endif -#ifdef HAVE_BROKEN_REALPATH -SHOW_COMP_OPTION have_symlink=SHOW_OPTION_NO; -#else -SHOW_COMP_OPTION have_symlink=SHOW_OPTION_YES; -#endif -#ifdef HAVE_QUERY_CACHE -SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO; -#endif -#ifdef HAVE_CRYPT -SHOW_COMP_OPTION have_crypt=SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_crypt=SHOW_OPTION_NO; -#endif -#ifdef HAVE_COMPRESS -SHOW_COMP_OPTION have_compress= SHOW_OPTION_YES; -#else -SHOW_COMP_OPTION have_compress= SHOW_OPTION_NO; -#endif -const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; +/* Constants */ -bool opt_large_files= sizeof(my_off_t) > 4; +const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; +const char *sql_mode_names[] = +{ + "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 }; +const char *first_keyword= "first", *binary_keyword= "BINARY"; +const char *localhost= "localhost", *delayed_user= "DELAYED"; #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES) #define GET_HA_ROWS GET_ULL #else #define GET_HA_ROWS GET_ULONG #endif -#ifdef HAVE_LIBWRAP -char *libwrapName= NULL; -#endif +bool opt_large_files= sizeof(my_off_t) > 4; +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}}; -/* - Variables to store startup options -*/ -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; +/* Global variables */ -ulong back_log, connect_timeout, concurrency; -char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30]; -char log_error_file[FN_REFLEN]; bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool server_id_supplied = 0; +bool opt_endinfo,using_udf_functions, locked_in_memory; +bool opt_using_transactions, using_update_log; +bool volatile abort_loop, select_thread_in_use, signal_thread_in_use; +bool volatile ready_to_exit, shutdown_in_progress, grant_option; + +my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted +my_bool opt_reckless_slave = 0; my_bool opt_enable_named_pipe= 0; my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol; -uint delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; - -static bool opt_do_pstack = 0; -static ulong opt_specialflag=SPECIAL_ENGLISH; - -static ulong opt_myisam_block_size; -static my_socket unix_sock= INVALID_SOCKET,ip_sock= INVALID_SOCKET; -static my_string opt_logname=0,opt_update_logname=0, - opt_binlog_index_name = 0,opt_slow_logname=0; - -static char* mysql_home_ptr= mysql_home; -static char* pidfile_name_ptr= pidfile_name; -char* log_error_file_ptr= log_error_file; -static pthread_t select_thread; -static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0; my_bool opt_safe_user_create = 0, opt_no_mix_types = 0; my_bool lower_case_table_names, opt_old_rpl_compat; my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0; my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0; my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam; +my_bool opt_readonly, use_temp_pool, relay_log_purge; +volatile bool mqh_used = 0; -volatile bool mqh_used = 0; -FILE *bootstrap_file=0; - -static bool kill_in_progress=0, segfaulted= 0; -struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() -static int cleanup_done; -static char **defaults_argv; -char glob_hostname[FN_REFLEN]; - -#include "sslopt-vars.h" -#ifdef HAVE_OPENSSL -char *des_key_file = 0; -struct st_VioSSLAcceptorFd *ssl_acceptor_fd= 0; -#endif /* HAVE_OPENSSL */ - -I_List <i_string_pair> replicate_rewrite_db; -I_List<i_string> replicate_do_db, replicate_ignore_db; -// allow the user to tell us which db to replicate and which to ignore -I_List<i_string> binlog_do_db, binlog_ignore_db; - -/* if we guessed server_id , we need to know about it */ -ulong server_id= 0; // Must be long becasue of set_var.cc -bool server_id_supplied = 0; +uint mysql_port, test_flags, select_errors, dropping_tables, ha_open_options; +uint delay_key_write_options, protocol_version; +uint volatile thread_count, thread_running, kill_cached_threads, wake_thread; -uint mysql_port; -uint test_flags = 0, select_errors=0, dropping_tables=0,ha_open_options=0; -uint volatile thread_count=0, thread_running=0, kill_cached_threads=0, - wake_thread=0; -ulong thd_startup_options=(OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | - OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE ); -uint protocol_version=PROTOCOL_VERSION; -struct system_variables global_system_variables; -struct system_variables max_system_variables; -ulonglong keybuff_size; -ulong table_cache_size, - thread_stack, - thread_stack_min,what_to_log= ~ (1L << (uint) COM_TIME), - query_buff_size, - slow_launch_time = 2L, - slave_open_temp_tables=0, - open_files_limit=0, max_binlog_size; -ulong com_stat[(uint) SQLCOM_END], com_other; +ulong back_log, connect_timeout, concurrency; +ulong server_id, thd_startup_options; +ulong table_cache_size, thread_stack, thread_stack_min, what_to_log; +ulong query_buff_size, slow_launch_time, slave_open_temp_tables; +ulong open_files_limit, max_binlog_size; ulong slave_net_timeout; ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0; ulong query_cache_size=0; -#ifdef HAVE_QUERY_CACHE -ulong query_cache_limit= 0; -ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE; -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; -my_bool opt_enable_shared_memory = 0; -#endif - -volatile ulong cached_thread_count=0; - -// replication parameters, if master_host is not NULL, we are a slave -my_string master_user = (char*) "test", master_password = 0, master_host=0, - master_info_file = (char*) "master.info", - relay_log_info_file = (char*) "relay-log.info", - master_ssl_key=0, master_ssl_cert=0, master_ssl_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; -uint report_port = MYSQL_PORT; -bool master_ssl = 0; - -ulong master_retry_count=0; -ulong bytes_sent = 0L, bytes_received = 0L; - -bool opt_endinfo,using_udf_functions, locked_in_memory; -bool opt_using_transactions, using_update_log; -bool volatile abort_loop, select_thread_in_use, signal_thread_in_use; -bool volatile ready_to_exit, shutdown_in_progress, grant_option; +ulong com_stat[(uint) SQLCOM_END], com_other; +ulong bytes_sent, bytes_received; ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */ -ulong query_id=1L,long_query_count,aborted_threads, - aborted_connects,delayed_insert_timeout,delayed_insert_limit, - delayed_queue_size,delayed_insert_threads,delayed_insert_writes, - delayed_rows_in_use,delayed_insert_errors,flush_time, thread_created; +ulong query_id, long_query_count, aborted_threads, aborted_connects; +ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; +ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; +ulong delayed_insert_errors,flush_time, thread_created; ulong filesort_rows, filesort_range_count, filesort_scan_count; ulong filesort_merge_passes; ulong select_range_check_count, select_range_count, select_scan_count; @@ -417,52 +284,51 @@ ulong max_connections,max_insert_delayed_threads,max_used_connections, ulong thread_id=1L,current_pid; ulong slow_launch_threads = 0; ulong expire_logs_days = 0; +ulong rpl_recovery_rank=0; +ulong my_bind_addr; /* the address we bind to */ +volatile ulong cached_thread_count= 0; +ulonglong keybuff_size; + +double log_10[32]; /* 10 potences */ + +time_t start_time; + +char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], time_zone[30]; +char log_error_file[FN_REFLEN], glob_hostname[FN_REFLEN]; +char* log_error_file_ptr= log_error_file; char mysql_real_data_home[FN_REFLEN], - language[LIBLEN],reg_ext[FN_EXTLEN], - mysql_charsets_dir[FN_REFLEN], *charsets_list, - blob_newline,f_fyllchar,max_sort_char,*mysqld_user,*mysqld_chroot, - *opt_init_file; -char *language_ptr= language; + language[LIBLEN],reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], + max_sort_char,*mysqld_user,*mysqld_chroot, *opt_init_file; +char *language_ptr, *default_collation_name, *default_character_set_name; char mysql_data_home_buff[2], *mysql_data_home=mysql_real_data_home; -#ifndef EMBEDDED_LIBRARY -bool mysql_embedded=0; -#else -bool mysql_embedded=1; -#endif - -static char *opt_bin_logname = 0; -char *opt_relay_logname = 0, *opt_relaylog_index_name=0; char server_version[SERVER_VERSION_LENGTH]=MYSQL_SERVER_VERSION; -const char *first_keyword="first"; +char *mysql_unix_port, *opt_mysql_tmpdir; +char *my_bind_addr_str; const char **errmesg; /* Error messages */ const char *myisam_recover_options_str="OFF"; const char *sql_mode_str="OFF"; -ulong rpl_recovery_rank=0; -my_bool relay_log_purge=1; -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; -double log_10[32]; /* 10 potences */ +FILE *bootstrap_file; + +I_List <i_string_pair> replicate_rewrite_db; +I_List<i_string> replicate_do_db, replicate_ignore_db; +// allow the user to tell us which db to replicate and which to ignore +I_List<i_string> binlog_do_db, binlog_ignore_db; I_List<THD> threads,thread_cache; -time_t start_time; -const char *sql_mode_names[] = -{ - "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}; +struct system_variables global_system_variables; +struct system_variables max_system_variables; +MY_TMPDIR mysql_tmpdir_list; +DATE_FORMAT dayord; MY_BITMAP temp_pool; -my_bool use_temp_pool=0; + +SHOW_COMP_OPTION have_berkeley_db, have_innodb, have_isam; +SHOW_COMP_OPTION have_raid, have_openssl, have_symlink, have_query_cache; +SHOW_COMP_OPTION have_crypt, have_compress; + +/* Thread specific variables */ pthread_key(MEM_ROOT*,THR_MALLOC); pthread_key(THD*, THR_THD); @@ -480,24 +346,98 @@ pthread_cond_t COND_thread_cache,COND_flush_thread_cache; pthread_t signal_thread; pthread_attr_t connection_attrib; +/* replication parameters, if master_host is not NULL, we are a slave */ +my_bool master_ssl; +uint master_port= MYSQL_PORT, master_connect_retry = 60; +uint report_port= MYSQL_PORT; +ulong master_retry_count=0; +char *master_user, *master_password, *master_host, *master_info_file; +char *relay_log_info_file, *master_ssl_key, *master_ssl_cert; +char *master_ssl_capath, *master_ssl_cipher, *report_user; +char *report_password, *report_host; +char *opt_relay_logname = 0, *opt_relaylog_index_name=0; + +/* Static variables */ + +static bool kill_in_progress, segfaulted; +static my_bool opt_do_pstack, opt_noacl, opt_bootstrap, opt_myisam_log; +static int cleanup_done; +static ulong opt_specialflag, opt_myisam_block_size; +static char *opt_logname, *opt_update_logname, *opt_binlog_index_name; +static char *opt_slow_logname; +static char *mysql_home_ptr, *pidfile_name_ptr; +static char **defaults_argv; +static char *opt_bin_logname; + +static my_socket unix_sock,ip_sock; +static pthread_t select_thread; +struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() + +/* OS specific variables */ + #ifdef __WIN__ #undef getpid #include <process.h> + +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; + #if !defined(EMBEDDED_LIBRARY) -HANDLE hEventShutdown; +static HANDLE hEventShutdown; static char shutdown_event_name[40]; #include "nt_servc.h" static NTService Service; // Service object for WinNT -#endif +#endif /* EMBEDDED_LIBRARY */ +#endif /* __WIN__ */ + +#ifdef __NT__ +static char szPipeName [ 257 ]; +static SECURITY_ATTRIBUTES saPipeSecurity; +static SECURITY_DESCRIPTOR sdPipeDescriptor; +static HANDLE hPipe = INVALID_HANDLE_VALUE; #endif #ifdef OS2 pthread_cond_t eventShutdown; #endif +#ifndef EMBEDDED_LIBRARY +bool mysql_embedded=0; +#else +bool mysql_embedded=1; +#endif + +#ifndef DBUG_OFF +static const char* default_dbug_option; +#endif +#ifdef HAVE_LIBWRAP +char *libwrapName= NULL; +#endif +#ifdef HAVE_QUERY_CACHE +ulong query_cache_limit= 0; +ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE; +Query_cache query_cache; +#endif +#ifdef HAVE_SMEM +char *shared_memory_base_name= default_shared_memory_base_name; +my_bool opt_enable_shared_memory; +#endif + +#include "sslopt-vars.h" +#ifdef HAVE_OPENSSL +char *des_key_file; +struct st_VioSSLAcceptorFd *ssl_acceptor_fd; +#endif /* HAVE_OPENSSL */ + + +/* Function declarations */ + static void start_signal_handler(void); extern "C" pthread_handler_decl(signal_hand, arg); -static void set_options(void); +static void mysql_init_variables(void); static void get_options(int argc,char **argv); static int init_thread_environment(); static char *get_relative_path(const char *path); @@ -657,7 +597,6 @@ static void close_connections(void) /* Force remaining threads to die by closing the connection to the client */ - (void) my_net_init(&net, (st_vio*) 0); for (;;) { DBUG_PRINT("quit",("Locking LOCK_thread_count")); @@ -669,17 +608,16 @@ static void close_connections(void) break; } #ifndef __bsdi__ // Bug in BSDI kernel - if ((net.vio=tmp->net.vio) != 0) + if (tmp->net.vio) { sql_print_error(ER(ER_FORCING_CLOSE),my_progname, tmp->thread_id,tmp->user ? tmp->user : ""); - close_connection(&net,0,0); + close_connection(tmp,0,0); } #endif DBUG_PRINT("quit",("Unlocking LOCK_thread_count")); (void) pthread_mutex_unlock(&LOCK_thread_count); } - net_end(&net); /* All threads has now been aborted */ DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count)); (void) pthread_mutex_lock(&LOCK_thread_count); @@ -823,9 +761,9 @@ static void __cdecl kill_server(int sig_ptr) unireg_end(); #ifdef __NETWARE__ pthread_join(select_thread, NULL); // wait for main thread -#else - pthread_exit(0); /* purecov: deadcode */ #endif /* __NETWARE__ */ + + pthread_exit(0); /* purecov: deadcode */ #endif /* EMBEDDED_LIBRARY */ RETURN_FROM_KILL_SERVER; @@ -883,13 +821,11 @@ void unireg_end(void) { clean_up(1); my_thread_end(); -#ifndef __NETWARE__ -#ifdef SIGNALS_DONT_BREAK_READ +#if defined(SIGNALS_DONT_BREAK_READ) && !defined(__NETWARE__) exit(0); #else pthread_exit(0); // Exit is in main thread #endif -#endif /* __NETWARE__ */ } @@ -941,7 +877,6 @@ void clean_up(bool print_message) #endif if (defaults_argv) free_defaults(defaults_argv); - my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR)); free_tmpdir(&mysql_tmpdir_list); #ifdef HAVE_REPLICATION my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); @@ -954,6 +889,8 @@ void clean_up(bool print_message) end_slave_list(); #endif #ifdef HAVE_OPENSSL + if (ssl_acceptor_fd) + my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR)); free_des_key_file(); #endif /* HAVE_OPENSSL */ #ifdef USE_REGEX @@ -1276,19 +1213,20 @@ void yyerror(const char *s) #ifndef EMBEDDED_LIBRARY -void close_connection(NET *net,uint errcode,bool lock) +void close_connection(THD *thd, uint errcode, bool lock) { - st_vio* vio; + st_vio *vio; DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("fd: %s error: '%s'", - net->vio? vio_description(net->vio):"(not connected)", - errcode ? ER(errcode) : "")); + thd->net.vio ? vio_description(thd->net.vio) : + "(not connected)", + errcode ? ER(errcode) : "")); if (lock) (void) pthread_mutex_lock(&LOCK_thread_count); - if ((vio=net->vio) != 0) + if ((vio=thd->net.vio) != 0) { if (errcode) - net_send_error(net,errcode,ER(errcode)); /* purecov: inspected */ + send_error(thd, errcode, ER(errcode)); /* purecov: inspected */ vio_close(vio); /* vio is freed in delete thd */ } if (lock) @@ -1647,6 +1585,7 @@ static void init_signals(void) sa.sa_handler=handle_segfault; #endif sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGABRT, &sa, NULL); #ifdef SIGBUS sigaction(SIGBUS, &sa, NULL); #endif @@ -1732,9 +1671,10 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) /* Setup alarm handler - The two extra handlers are for slave threads + This should actually be '+ max_number_of_slaves' instead of +10, + but the +10 should be quite safe. */ - init_thr_alarm(max_connections+max_insert_delayed_threads+2); + init_thr_alarm(max_connections+max_insert_delayed_threads+10); #if SIGINT != THR_KILL_SIGNAL (void) sigemptyset(&set); // Setup up SIGINT for debug (void) sigaddset(&set,SIGINT); // For debugging @@ -1997,6 +1937,7 @@ static int init_common_variables(const char *conf_file_name, int argc, max_system_variables.pseudo_thread_id= (ulong)~0; start_time=time((time_t*) 0); + mysql_init_variables(); #ifdef OS2 { @@ -2035,7 +1976,6 @@ static int init_common_variables(const char *conf_file_name, int argc, load_defaults(conf_file_name, groups, &argc, &argv); defaults_argv=argv; - set_options(); get_options(argc,argv); if (init_thread_environment()) return 1; @@ -2088,14 +2028,30 @@ static int init_common_variables(const char *conf_file_name, int argc, #ifdef USE_REGEX regex_init(&my_charset_latin1); #endif - if (!(default_charset_info= get_charset_by_name(sys_charset.value, MYF(MY_WME)))) + if (!(default_charset_info= get_charset_by_csname(default_character_set_name, + MY_CS_PRIMARY, + MYF(MY_WME)))) return 1; - global_system_variables.collation_results= default_charset_info; - global_system_variables.collation_client= default_charset_info; + if (default_collation_name) + { + CHARSET_INFO *default_collation; + default_collation= get_charset_by_name(default_collation_name, MYF(0)); + if (!default_collation || !my_charset_same(default_charset_info, + default_collation)) + { + sql_print_error(ER(ER_COLLATION_CHARSET_MISMATCH), + default_collation_name, + default_charset_info->csname); + return 1; + } + default_charset_info= default_collation; + } + global_system_variables.character_set_server= default_charset_info; + global_system_variables.character_set_database= default_charset_info; + global_system_variables.character_set_results= default_charset_info; + global_system_variables.character_set_client= default_charset_info; global_system_variables.collation_connection= default_charset_info; - charsets_list= list_charsets(MYF(MY_CS_COMPILED | MY_CS_CONFIG)); - if (use_temp_pool && bitmap_init(&temp_pool,1024,1)) return 1; return 0; @@ -2327,7 +2283,9 @@ static void handle_connections_methods() #endif /* __NT__ */ if (have_tcpip && !opt_disable_networking) { +#ifdef __NT__ handler_count++; +#endif if (pthread_create(&hThread,&connection_attrib, handle_connections_sockets, 0)) { @@ -2338,7 +2296,9 @@ static void handle_connections_methods() #ifdef HAVE_SMEM if (opt_enable_shared_memory) { +#ifdef __NT__ handler_count++; +#endif if (pthread_create(&hThread,&connection_attrib, handle_connections_shared_memory, 0)) { @@ -2762,7 +2722,7 @@ static void create_new_thread(THD *thd) if (thread_count - delayed_insert_threads >= max_connections+1 || abort_loop) { DBUG_PRINT("error",("Too many connections")); - close_connection(net,ER_CON_COUNT_ERROR); + close_connection(thd, ER_CON_COUNT_ERROR, 1); delete thd; DBUG_VOID_RETURN; } @@ -2817,7 +2777,7 @@ static void create_new_thread(THD *thd) (void) pthread_mutex_unlock(&LOCK_thread_count); net_printf(thd,ER_CANT_CREATE_THREAD,error); (void) pthread_mutex_lock(&LOCK_thread_count); - close_connection(net,0,0); + close_connection(thd,0,0); delete thd; (void) pthread_mutex_unlock(&LOCK_thread_count); DBUG_VOID_RETURN; @@ -3138,7 +3098,7 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) || my_net_init(&thd->net, thd->net.vio)) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); delete thd; continue; } @@ -3339,7 +3299,7 @@ Send number of connection to client 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); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); delete thd; error_allow = TRUE; } @@ -3364,10 +3324,12 @@ error: 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); +#ifdef __NT__ pthread_mutex_lock(&LOCK_thread_count); handler_count--; pthread_mutex_unlock(&LOCK_thread_count); pthread_cond_signal(&COND_handler_count); +#endif DBUG_RETURN(0); } #endif /* HAVE_SMEM */ @@ -3468,10 +3430,11 @@ enum options OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER, OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE, OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME, + OPT_READONLY, OPT_SORT_BUFFER, OPT_TABLE_CACHE, OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE, OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK, - OPT_WAIT_TIMEOUT, + OPT_WAIT_TIMEOUT, OPT_MYISAM_REPAIR_THREADS, OPT_INNODB_MIRRORED_LOG_GROUPS, OPT_INNODB_LOG_FILES_IN_GROUP, OPT_INNODB_LOG_FILE_SIZE, @@ -3483,6 +3446,7 @@ enum options OPT_INNODB_LOCK_WAIT_TIMEOUT, OPT_INNODB_THREAD_CONCURRENCY, OPT_INNODB_FORCE_RECOVERY, + OPT_INNODB_MAX_DIRTY_PAGES_PCT, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, OPT_BDB_MAX_LOCK, @@ -3492,7 +3456,8 @@ enum options OPT_OLD_PASSWORDS, OPT_EXPIRE_LOGS_DAYS, OPT_DEFAULT_WEEK_FORMAT, - OPT_GROUP_CONCAT_MAX_LEN + OPT_GROUP_CONCAT_MAX_LEN, + OPT_DEFAULT_COLLATION }; @@ -3579,8 +3544,11 @@ Disable with --skip-bdb (will save memory)", 0, 0, 0, 0, 0, 0}, #endif /* HAVE_OPENSSL */ {"default-character-set", 'C', "Set the default character set", - (gptr*) &sys_charset.value, (gptr*) &sys_charset.value, 0, GET_STR, - REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + (gptr*) &default_character_set_name, (gptr*) &default_character_set_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, + {"default-collation", OPT_DEFAULT_COLLATION, "Set the default collation", + (gptr*) &default_collation_name, (gptr*) &default_collation_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, {"default-table-type", OPT_TABLE_TYPE, "Set the default table type for tables", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -3649,6 +3617,10 @@ Disable with --skip-bdb (will save memory)", {"innodb_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN, "Speeds up server shutdown process", (gptr*) &innobase_fast_shutdown, (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT, + "Percentage of dirty pages allowed in bufferpool", (gptr*) &srv_max_buf_pool_modified_pct, + (gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0}, + #endif /* End HAVE_INNOBASE_DB */ {"help", '?', "Display this help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -3667,7 +3639,7 @@ Disable with --skip-bdb (will save memory)", (gptr*) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0}, {"log-bin", OPT_BIN_LOG, - "Log queries in new binary format (for replication)", + "Log update queries in binary format", (gptr*) &opt_bin_logname, (gptr*) &opt_bin_logname, 0, GET_STR_ALLOC, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"log-bin-index", OPT_BIN_LOG_INDEX, @@ -3721,27 +3693,32 @@ Disable with --skip-bdb (will save memory)", (gptr*) &master_retry_count, (gptr*) &master_retry_count, 0, GET_ULONG, REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0}, {"master-info-file", OPT_MASTER_INFO_FILE, - "The location of the file that remembers where we left off on the master during the replication process. The default is `master.info' in the data directory. You should not need to change this.", + "The location and name of the file that remembers the master and where the I/O replication \ +thread is in the master's binlogs.", (gptr*) &master_info_file, (gptr*) &master_info_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl", OPT_MASTER_SSL, - "Turn SSL on for replication. Be warned that is this is a relatively new feature.", + "Planned to enable the slave to connect to the master using SSL. Does nothing yet.", (gptr*) &master_ssl, (gptr*) &master_ssl, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-key", OPT_MASTER_SSL_KEY, - "Master SSL keyfile name. Only applies if you have enabled master-ssl.", + "Master SSL keyfile name. Only applies if you have enabled master-ssl. Does \ +nothing yet.", (gptr*) &master_ssl_key, (gptr*) &master_ssl_key, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cert", OPT_MASTER_SSL_CERT, - "Master SSL certificate file name. Only applies if you have enabled master-ssl.", + "Master SSL certificate file name. Only applies if you have enabled \ +master-ssl. Does nothing yet.", (gptr*) &master_ssl_cert, (gptr*) &master_ssl_cert, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-capath", OPT_MASTER_SSL_CAPATH, - "Master SSL CA path. Only applies if you have enabled master-ssl.", + "Master SSL CA path. Only applies if you have enabled master-ssl. \ +Does nothing yet.", (gptr*) &master_ssl_capath, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"master-ssl-cipher", OPT_MASTER_SSL_CIPHER, - "Master SSL cipher. Only applies if you have enabled master-ssl.", + "Master SSL cipher. Only applies if you have enabled master-ssl. \ +Does nothing yet.", (gptr*) &master_ssl_cipher, (gptr*) &master_ssl_capath, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"myisam-recover", OPT_MYISAM_RECOVER, @@ -3842,10 +3819,13 @@ Disable with --skip-bdb (will save memory)", {"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented", (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"relay-log", OPT_RELAY_LOG, "Undocumented", + {"relay-log", OPT_RELAY_LOG, + "The location and name to use for relay logs", (gptr*) &opt_relay_logname, (gptr*) &opt_relay_logname, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"relay-log-index", OPT_RELAY_LOG_INDEX, "Undocumented", + {"relay-log-index", OPT_RELAY_LOG_INDEX, + "The location and name to use for the file that keeps a list of the last \ +relay logs", (gptr*) &opt_relaylog_index_name, (gptr*) &opt_relaylog_index_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", @@ -3915,16 +3895,20 @@ Disable with --skip-isam", {"skip-stack-trace", OPT_SKIP_STACK_TRACE, "Don't print a stack trace on failure", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables", + {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Depricated option. Use --skip-symbolic-links instead", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-thread-priority", OPT_SKIP_PRIOR, "Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE, "Undocumented", + {"relay-log-info-file", OPT_RELAY_LOG_INFO_FILE, + "The location and name of the file that remembers where the SQL replication \ +thread is in the relay logs", (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", + {"slave-load-tmpdir", OPT_SLAVE_LOAD_TMPDIR, + "The location where the slave should put its temporary files when \ +replicating a LOAD DATA INFILE command", (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, @@ -3965,11 +3949,12 @@ Disable with --skip-isam", {"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running", (gptr*) &opt_external_locking, (gptr*) &opt_external_locking, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, -#ifdef USE_SYMDIR - {"use-symbolic-links", 's', "Enable symbolic link support", + {"use-symbolic-links", 's', "Enable symbolic link support. Depricated option; Use --symbolic-links instead", + (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, + IF_PURIFY(0,1), 0, 0, 0, 0, 0}, + {"--symbolic-links", 's', "Enable symbolic link support", (gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG, IF_PURIFY(0,1), 0, 0, 0, 0, 0}, -#endif {"user", 'u', "Run mysqld daemon as user", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit", 0, 0, 0, GET_NO_ARG, @@ -4147,7 +4132,7 @@ Disable with --skip-isam", (gptr*) &max_connect_errors, (gptr*) &max_connect_errors, 0, GET_ULONG, REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0}, {"max_delayed_threads", OPT_MAX_DELAYED_THREADS, - "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.", + "Don't start more than this number of threads to handle INSERT DELAYED statements. If 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, @@ -4209,12 +4194,18 @@ Disable with --skip-isam", (gptr*) &global_system_variables.myisam_max_extra_sort_file_size, (gptr*) &max_system_variables.myisam_max_extra_sort_file_size, 0, GET_ULL, REQUIRED_ARG, (ulonglong) MI_MAX_TEMP_LENGTH, - 0, ~0L, 0, 1, 0}, + 0, (ulonglong) MAX_FILE_SIZE, 0, 1, 0}, {"myisam_max_sort_file_size", OPT_MYISAM_MAX_SORT_FILE_SIZE, "Don't use the fast sort index method to created index if the temporary file would get bigger than this!", (gptr*) &global_system_variables.myisam_max_sort_file_size, (gptr*) &max_system_variables.myisam_max_sort_file_size, 0, - GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, ~0L, 0, 1024*1024, 0}, + GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE, + 0, 1024*1024, 0}, + {"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS, + "Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.", + (gptr*) &global_system_variables.myisam_repair_threads, + (gptr*) &max_system_variables.myisam_repair_threads, 0, + GET_ULONG, REQUIRED_ARG, 1, 1, ~0L, 0, 1, 0}, {"myisam_sort_buffer_size", OPT_MYISAM_SORT_BUFFER_SIZE, "The buffer that is allocated when sorting the index when doing a REPAIR or when creating indexes with CREATE INDEX or ALTER TABLE.", (gptr*) &global_system_variables.myisam_sort_buff_size, @@ -4289,7 +4280,7 @@ Disable with --skip-isam", (gptr*) &relay_log_purge, 0, GET_BOOL, NO_ARG, 1, 0, 1, 0, 1, 0}, {"relay_log_space_limit", OPT_RELAY_LOG_SPACE_LIMIT, - "Max space to use for all relay logs", + "Maximum space to use for all relay logs", (gptr*) &relay_log_space_limit, (gptr*) &relay_log_space_limit, 0, GET_ULL, REQUIRED_ARG, 0L, 0L, (longlong) ULONG_MAX, 0, 1, 0}, @@ -4303,6 +4294,11 @@ Disable with --skip-isam", (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 */ + {"read-only", OPT_READONLY, + "Make all tables readonly, with the expections for replications (slave) threads and users with the SUPER privilege", + (gptr*) &opt_readonly, + (gptr*) &opt_readonly, + 0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 1, 0}, {"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, @@ -4544,6 +4540,12 @@ static void use_help(void) static void usage(void) { + if (!(default_charset_info= get_charset_by_csname(default_character_set_name, + MY_CS_PRIMARY, + MYF(MY_WME)))) + exit(1); + if (!default_collation_name) + default_collation_name= (char*) default_charset_info->name; print_version(); puts("\ Copyright (C) 2000 MySQL AB, by Monty and others\n\ @@ -4579,20 +4581,116 @@ To see what values a running MySQL server is using, type\n\ } -static void set_options(void) -{ -#if !defined( my_pthread_setprio ) && !defined( HAVE_PTHREAD_SETSCHEDPARAM ) - opt_specialflag |= SPECIAL_NO_PRIOR; -#endif +/* + Initialize all MySQL global variables to default values + + SYNOPSIS + mysql_init_variables() + + NOTES + The reason to set a lot of global variables to zero is to allow one to + restart the embedded server with a clean environment + It's also needed on some exotic platforms where global variables are + not set to 0 when a program starts. - sys_charset.value= (char*) MYSQL_CHARSET; - (void) strmake(language, LANGUAGE, sizeof(language)-1); - (void) strmake(mysql_real_data_home, get_relative_path(DATADIR), - sizeof(mysql_real_data_home)-1); + We don't need to set numeric variables refered to in my_long_options + as these are initialized by my_getopt. +*/ - /* Set default values for some variables */ - global_system_variables.collation_results= default_charset_info; - global_system_variables.collation_client= default_charset_info; +static void mysql_init_variables(void) +{ + /* Things reset to zero */ + opt_skip_slave_start= opt_reckless_slave = 0; + mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; + opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0; + opt_disable_networking= opt_skip_show_db=0; + opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0; + opt_bootstrap= opt_myisam_log= use_old_passwords= 0; + mqh_used= 0; + segfaulted= kill_in_progress= 0; + cleanup_done= 0; + defaults_argv= 0; + server_id_supplied= 0; + test_flags= select_errors= dropping_tables= ha_open_options=0; + thread_count= thread_running= kill_cached_threads= wake_thread=0; + slave_open_temp_tables= 0; + com_other= 0; + cached_thread_count= 0; + bytes_sent= bytes_received= 0; + opt_endinfo= using_udf_functions= 0; + opt_using_transactions= using_update_log= 0; + abort_loop= select_thread_in_use= signal_thread_in_use= 0; + ready_to_exit= shutdown_in_progress= grant_option= 0; + long_query_count= aborted_threads= aborted_connects= 0; + delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0; + delayed_insert_errors= thread_created= 0; + filesort_rows= filesort_range_count= filesort_scan_count= 0; + filesort_merge_passes= select_range_check_count= select_range_count= 0; + select_scan_count= select_full_range_join_count= select_full_join_count= 0; + specialflag= opened_tables= created_tmp_tables= created_tmp_disk_tables= 0; + max_used_connections= slow_launch_threads = 0; + max_sort_char= 0; + mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0; + errmesg= 0; + mysql_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS; + bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); + bzero((gptr) &com_stat, sizeof(com_stat)); + + /* Things with default values that are not zero */ + delay_key_write_options= (uint) DELAY_KEY_WRITE_ON; + opt_specialflag= SPECIAL_ENGLISH; + unix_sock= ip_sock= INVALID_SOCKET; + mysql_home_ptr= mysql_home; + pidfile_name_ptr= pidfile_name; + log_error_file_ptr= log_error_file; + language_ptr= language; + mysql_data_home= mysql_real_data_home; + thd_startup_options= (OPTION_UPDATE_LOG | OPTION_AUTO_IS_NULL | + OPTION_BIN_LOG | OPTION_QUOTE_SHOW_CREATE); + protocol_version= PROTOCOL_VERSION; + what_to_log= ~ (1L << (uint) COM_TIME); + refresh_version= flush_version= 1L; /* Increments on each reload */ + thread_id= 1L; + strmov(server_version, MYSQL_SERVER_VERSION); + myisam_recover_options_str= sql_mode_str= "OFF"; + my_bind_addr = htonl(INADDR_ANY); + threads.empty(); + thread_cache.empty(); + + /* Initialize structures that is used when processing options */ + replicate_rewrite_db.empty(); + replicate_do_db.empty(); + replicate_ignore_db.empty(); + binlog_do_db.empty(); + binlog_ignore_db.empty(); + + /* Set directory paths */ + strmake(language, LANGUAGE, sizeof(language)-1); + strmake(mysql_real_data_home, get_relative_path(DATADIR), + sizeof(mysql_real_data_home)-1); + mysql_data_home_buff[0]=FN_CURLIB; // all paths are relative from here + mysql_data_home_buff[1]=0; + + /* Replication parameters */ + master_user= (char*) "test"; + master_password= master_host= 0; + master_info_file= (char*) "master.info", + relay_log_info_file= (char*) "relay-log.info", + master_ssl_key= master_ssl_cert= master_ssl_capath= master_ssl_cipher= 0; + report_user= report_password = report_host= 0; /* TO BE DELETED */ + opt_relay_logname= opt_relaylog_index_name= 0; + + /* Variables in libraries */ + charsets_dir= 0; + default_character_set_name= (char*) MYSQL_DEFAULT_CHARSET_NAME; + default_collation_name= (char*) MYSQL_DEFAULT_COLLATION_NAME; + sys_charset_system.value= (char*) system_charset_info->csname; + + /* Set default values for some option variables */ + global_system_variables.character_set_server= default_charset_info; + global_system_variables.character_set_database= default_charset_info; + global_system_variables.character_set_results= default_charset_info; + global_system_variables.character_set_client= default_charset_info; global_system_variables.collation_connection= default_charset_info; global_system_variables.table_type= DB_TYPE_MYISAM; global_system_variables.tx_isolation= ISO_REPEATABLE_READ; @@ -4601,6 +4699,71 @@ static void set_options(void) global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; + /* Variables that depends on compile options */ +#ifndef DBUG_OFF + default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace", + "d:t:i:o,/tmp/mysqld.trace"); +#endif + opt_error_log= IF_WIN(1,0); +#ifdef HAVE_BERKELEY_DB + have_berkeley_db= SHOW_OPTION_YES; +#else + have_berkeley_db= SHOW_OPTION_NO; +#endif +#ifdef HAVE_INNOBASE_DB + have_innodb=SHOW_OPTION_YES; +#else + have_innodb=SHOW_OPTION_NO; +#endif +#ifdef HAVE_ISAM + have_isam=SHOW_OPTION_YES; +#else + have_isam=SHOW_OPTION_NO; +#endif +#ifdef USE_RAID + have_raid=SHOW_OPTION_YES; +#else + have_raid=SHOW_OPTION_NO; +#endif +#ifdef HAVE_OPENSSL + have_openssl=SHOW_OPTION_YES; +#else + have_openssl=SHOW_OPTION_NO; +#endif +#ifdef HAVE_BROKEN_REALPATH + have_symlink=SHOW_OPTION_NO; +#else + have_symlink=SHOW_OPTION_YES; +#endif +#ifdef HAVE_QUERY_CACHE + have_query_cache=SHOW_OPTION_YES; +#else + have_query_cache=SHOW_OPTION_NO; +#endif +#ifdef HAVE_CRYPT + have_crypt=SHOW_OPTION_YES; +#else + have_crypt=SHOW_OPTION_NO; +#endif +#ifdef HAVE_COMPRESS + SHOW_COMP_OPTION have_compress= SHOW_OPTION_YES; +#else + SHOW_COMP_OPTION have_compress= SHOW_OPTION_NO; +#endif +#ifdef HAVE_LIBWRAP + libwrapName= NullS; +#endif +#ifdef HAVE_OPENSSL + des_key_file = 0; + ssl_acceptor_fd= 0; +#endif +#ifdef HAVE_SMEM + shared_memory_base_name= default_shared_memory_base_name; +#endif +#if !defined(my_pthread_setprio) && !defined(HAVE_PTHREAD_SETSCHEDPARAM) + opt_specialflag |= SPECIAL_NO_PRIOR; +#endif + #if defined(__WIN__) || defined(__NETWARE__) /* Allow Win32 and NetWare users to move MySQL anywhere */ { @@ -4615,10 +4778,6 @@ static void set_options(void) tmpenv = DEFAULT_MYSQL_HOME; (void) strmake(mysql_home, tmpenv, sizeof(mysql_home)-1); #endif - - my_disable_locking=myisam_single_user= 1; - opt_external_locking=0; - my_bind_addr = htonl( INADDR_ANY ); } @@ -4643,6 +4802,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'b': strmake(mysql_home,argument,sizeof(mysql_home)-1); break; + case 'C': + default_collation_name= 0; + break; case 'l': opt_log=1; break; @@ -4844,9 +5006,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE; myisam_concurrent_insert=0; myisam_recover_options= HA_RECOVER_NONE; - my_disable_symlinks=1; my_use_symdir=0; - have_symlink=SHOW_OPTION_DISABLED; ha_open_options&= ~(HA_OPEN_ABORT_IF_CRASHED | HA_OPEN_DELAY_KEY_WRITE); #ifdef HAVE_QUERY_CACHE query_cache_size=0; @@ -4893,9 +5053,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), test_flags|=TEST_NO_STACKTRACE; break; case (int) OPT_SKIP_SYMLINKS: - my_disable_symlinks=1; my_use_symdir=0; - have_symlink=SHOW_OPTION_DISABLED; break; case (int) OPT_BIND_ADDRESS: if (argument && my_isdigit(mysqld_charset, argument[0])) @@ -5141,6 +5299,11 @@ static void get_options(int argc,char **argv) if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) exit(ho_error); + if (argc > 0) + { + fprintf(stderr, "%s: Too many arguments.\nUse --help to get a list of available options\n", my_progname); + exit(ho_error); + } #if defined(HAVE_BROKEN_REALPATH) my_use_symdir=0; @@ -5167,11 +5330,9 @@ static void get_options(int argc,char **argv) my_disable_locking= myisam_single_user= test(opt_external_locking == 0); my_default_record_cache_size=global_system_variables.read_buff_size; myisam_max_temp_length= - (my_off_t) min(global_system_variables.myisam_max_sort_file_size, - (ulonglong) MAX_FILE_SIZE); + (my_off_t) global_system_variables.myisam_max_sort_file_size; myisam_max_extra_temp_length= - (my_off_t) min(global_system_variables.myisam_max_extra_sort_file_size, - (ulonglong) MAX_FILE_SIZE); + (my_off_t) global_system_variables.myisam_max_extra_sort_file_size; /* Set global variables based on startup options */ myisam_block_size=(uint) 1 << my_bit_log2(opt_myisam_block_size); diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 550fb772fce..8271d971782 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -48,13 +48,6 @@ can't normally do this the client should have a bigger max_allowed_packet. */ -#ifdef MYSQL_SERVER -#define USE_QUERY_CACHE -extern uint test_flags; -extern void query_cache_insert(NET *net, const char *packet, ulong length); -#else -#endif - #if defined(__WIN__) || !defined(MYSQL_SERVER) /* The following is because alarms doesn't work on windows. */ #define NO_ALARM @@ -63,16 +56,23 @@ extern void query_cache_insert(NET *net, const char *packet, ulong length); #ifndef NO_ALARM #include "my_pthread.h" void sql_print_error(const char *format,...); -extern ulong bytes_sent, bytes_received; -extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #else -#undef statistic_add -#define statistic_add(A,B,C) #define DONT_USE_THR_ALARM #endif /* NO_ALARM */ #include "thr_alarm.h" +#ifdef MYSQL_SERVER +#define USE_QUERY_CACHE +extern uint test_flags; +extern void query_cache_insert(NET *net, const char *packet, ulong length); +extern ulong bytes_sent, bytes_received; +extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; +#else +#undef statistic_add +#define statistic_add(A,B,C) +#endif + #define TEST_BLOCKING 8 #define MAX_PACKET_LENGTH (256L*256L*256L-1) diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7526772cd09..6c1c49e23fc 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -283,7 +283,7 @@ typedef struct st_qsel_param { KEY_PART *key_parts,*key_parts_end,*key[MAX_KEY]; MEM_ROOT *mem_root; table_map prev_tables,read_tables,current_table; - uint baseflag,keys,max_key_part; + uint baseflag, keys, max_key_part, range_count; uint real_keynr[MAX_KEY]; char min_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH], max_key[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; @@ -379,8 +379,8 @@ SQL_SELECT::~SQL_SELECT() #undef index // Fix for Unixware 7 QUICK_SELECT::QUICK_SELECT(TABLE *table,uint key_nr,bool no_alloc) - :dont_free(0),error(0),index(key_nr),max_used_key_length(0),head(table), - it(ranges),range(0) + :dont_free(0),error(0),index(key_nr),max_used_key_length(0), + used_key_parts(0), head(table), it(ranges),range(0) { if (!no_alloc) { @@ -709,8 +709,10 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, (double) keys_per_block); } else - found_read_time= head->file->read_time(found_records)+ - (double) found_records / TIME_FOR_COMPARE; + found_read_time= (head->file->read_time(keynr, + param.range_count, + found_records)+ + (double) found_records / TIME_FOR_COMPARE); if (read_time > found_read_time) { read_time=found_read_time; @@ -2074,11 +2076,12 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree) if (!tree) DBUG_RETURN(HA_POS_ERROR); // Can't use it + param->max_key_part=0; + param->range_count=0; if (tree->type == SEL_ARG::IMPOSSIBLE) DBUG_RETURN(0L); // Impossible select. return if (tree->type != SEL_ARG::KEY_RANGE || tree->part != 0) DBUG_RETURN(HA_POS_ERROR); // Don't use tree - param->max_key_part=0; records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0); if (records != HA_POS_ERROR) { @@ -2146,6 +2149,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree, } keynr=param->real_keynr[idx]; + param->range_count++; if (!tmp_min_flag && ! tmp_max_flag && (uint) key_tree->part+1 == param->table->key_info[keynr].key_parts && (param->table->key_info[keynr].flags & HA_NOSAME) && @@ -2322,6 +2326,7 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key, flag); set_if_bigger(quick->max_used_key_length,range->min_length); set_if_bigger(quick->max_used_key_length,range->max_length); + set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1); if (!range) // Not enough memory return 1; quick->ranges.push_back(range); diff --git a/sql/opt_range.h b/sql/opt_range.h index bc56fb99b4b..00736bfc22f 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -70,7 +70,7 @@ class QUICK_SELECT { public: bool next,dont_free; int error; - uint index,max_used_key_length; + uint index, max_used_key_length, used_key_parts; TABLE *head; handler *file; byte *record; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 1e116518da0..34cce98d087 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -69,8 +69,10 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond); RETURN VALUES 0 No errors - 1 if all items was resolved - -1 on impossible conditions + 1 if all items were resolved + -1 on impossible conditions + OR an error number from my_base.h HA_ERR_... if a deadlock or a lock + wait timeout happens, for example */ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) @@ -82,6 +84,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) table_map where_tables= 0; Item *item; COND *org_conds= conds; + int error; if (conds) where_tables= conds->used_tables(); @@ -131,7 +134,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (outer_tables || (table->table->file->table_flags() & HA_NOT_EXACT_COUNT)) { - const_result= 0; // Can't optimize left join + const_result= 0; // Can't optimize left join break; } tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -164,6 +167,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) Item_field *item_field= ((Item_field*) expr); TABLE *table= item_field->field->table; + if ((table->file->table_flags() & HA_NOT_READ_AFTER_KEY)) + { + const_result=0; + break; + } /* Look for a partial key that can be used for optimization. If we succeed, ref.key_length will contain the length of @@ -179,18 +187,21 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) const_result= 0; break; } - bool error= table->file->index_init((uint) ref.key); + error= table->file->index_init((uint) ref.key); if (!ref.key_length) - error= table->file->index_first(table->record[0]) != 0; + error= table->file->index_first(table->record[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); + { + 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); + if (!error && reckey_in_range(0, &ref, item_field->field, + conds, range_fl, prefix_len)) + error= HA_ERR_KEY_NOT_FOUND; + } if (table->key_read) { table->key_read= 0; @@ -198,10 +209,16 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } table->file->index_end(); if (error) - return -1; // No rows matching where + { + if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) + return -1; // No rows matching WHERE + /* HA_ERR_LOCK_DEADLOCK or some other error */ + table->file->print_error(error, MYF(0)); + return(error); + } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item()) // This is VERY seldom false { const_result= 0; break; @@ -249,18 +266,21 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) const_result= 0; break; } - bool error= table->file->index_init((uint) ref.key); + error= table->file->index_init((uint) ref.key); if (!ref.key_length) - error=table->file->index_last(table->record[0]) != 0; + error= table->file->index_last(table->record[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); + { + 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); + if (!error && reckey_in_range(1, &ref, item_field->field, + conds, range_fl, prefix_len)) + error= HA_ERR_KEY_NOT_FOUND; + } if (table->key_read) { table->key_read=0; @@ -268,10 +288,16 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } table->file->index_end(); if (error) - return -1; // Impossible query + { + if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE) + return -1; // No rows matching WHERE + /* HA_ERR_LOCK_DEADLOCK or some other error */ + table->file->print_error(error, MYF(0)); + return(error); + } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item()) // This is VERY seldom false { const_result= 0; break; @@ -597,6 +623,10 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo, (if we have a condition field = const, prefix_len contains the length of the whole search key) + NOTE + This function may set table->key_read to 1, which must be reset after + index is used! (This can only happen when function returns 1) + RETURN 0 Index can not be used to optimize MIN(field)/MAX(field) 1 Can use key to optimize MIN()/MAX() diff --git a/sql/protocol.cc b/sql/protocol.cc index d00ecb5dbc4..7abbf3ce85b 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -52,7 +52,7 @@ void send_error(THD *thd, uint sql_errno, const char *err) { #ifndef EMBEDDED_LIBRARY uint length; - char buff[MYSQL_ERRMSG_SIZE+2]; + char buff[MYSQL_ERRMSG_SIZE+2], *pos; #endif NET *net= &thd->net; DBUG_ENTER("send_error"); @@ -98,7 +98,14 @@ void send_error(THD *thd, uint sql_errno, const char *err) 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); + pos= buff+2; + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + /* The first # is to make the protocol backward compatible */ + strmov(buff+2, "#000000"); + pos= buff + 2 + SQLSTATE_LENGTH +1; + } + length= (uint) (strmake(pos, err, MYSQL_ERRMSG_SIZE-1) - buff); err=buff; } else @@ -113,26 +120,6 @@ void send_error(THD *thd, uint sql_errno, const char *err) 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 @@ -173,7 +160,7 @@ net_printf(THD *thd, uint errcode, ...) #ifndef EMBEDDED_LIBRARY const char *text_pos; #else - char text_pos[500]; + char text_pos[1024]; #endif int head_length= NET_HEADER_SIZE; NET *net= &thd->net; @@ -199,9 +186,11 @@ net_printf(THD *thd, uint errcode, ...) format=va_arg(args,char*); errcode= ER_UNKNOWN_ERROR; } - offset= net->return_errno ? 2 : 0; + offset= (net->return_errno ? + ((thd->client_capabilities & CLIENT_PROTOCOL_41) ? + 2+SQLSTATE_LENGTH+1 : 2) : 0); #ifndef EMBEDDED_LIBRARY - text_pos=(char*) net->buff+head_length+offset+1; + 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); @@ -228,7 +217,15 @@ net_printf(THD *thd, uint errcode, ...) 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); + { + uchar *pos= net->buff+head_length+1; + int2store(pos, errcode); + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + /* The first # is to make the protocol backward compatible */ + memcpy(pos+2, "#000000", SQLSTATE_LENGTH +1); + } + } VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); #else net->last_errno= errcode; @@ -502,6 +499,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) String tmp((char*) buff,sizeof(buff),&my_charset_bin); Protocol_simple prot(thd); String *packet= prot.storage_packet(); + CHARSET_INFO *thd_charset= thd->variables.character_set_results; DBUG_ENTER("send_fields"); if (flag & 1) @@ -526,36 +524,37 @@ bool Protocol::send_fields(List<Item> *list, uint flag) if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (prot.store(field.db_name, (uint) strlen(field.db_name), - cs, thd->charset()) || + if (prot.store("std", 3, cs, thd_charset) || + prot.store(field.db_name, (uint) strlen(field.db_name), + cs, thd_charset) || prot.store(field.table_name, (uint) strlen(field.table_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.org_table_name, (uint) strlen(field.org_table_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.col_name, (uint) strlen(field.col_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.org_col_name, (uint) strlen(field.org_col_name), - cs, thd->charset()) || + cs, thd_charset) || packet->realloc(packet->length()+12)) goto err; /* Store fixed length fields */ pos= (char*) packet->ptr()+packet->length(); - *pos++= 11; // Length of packed fields + *pos++= 12; // 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 + int4store(pos+2, field.length); + pos[6]= field.type; + int2store(pos+7,field.flags); + pos[9]= (char) field.decimals; pos[10]= 0; // For the future - pos+= 11; + pos[11]= 0; // For the future + pos+= 12; } else { if (prot.store(field.table_name, (uint) strlen(field.table_name), - cs, thd->charset()) || + cs, thd_charset) || prot.store(field.col_name, (uint) strlen(field.col_name), - cs, thd->charset()) || + cs, thd_charset) || packet->realloc(packet->length()+10)) goto err; pos= (char*) packet->ptr()+packet->length(); @@ -709,7 +708,7 @@ bool Protocol_simple::store(const char *from, uint length, field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; #endif - if (!my_charset_same(fromcs, tocs) && + if (tocs && !my_charset_same(fromcs, tocs) && (fromcs != &my_charset_bin) && (tocs != &my_charset_bin)) { @@ -724,7 +723,7 @@ bool Protocol_simple::store(const char *from, uint length, bool Protocol_simple::store(const char *from, uint length, CHARSET_INFO *fromcs) { - CHARSET_INFO *tocs= this->thd->variables.collation_results; + CHARSET_INFO *tocs= this->thd->variables.character_set_results; #ifndef DEBUG_OFF DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_DECIMAL || @@ -732,7 +731,7 @@ bool Protocol_simple::store(const char *from, uint length, field_types[field_pos] <= MYSQL_TYPE_GEOMETRY)); field_pos++; #endif - if (!my_charset_same(fromcs, tocs) && + if (tocs && !my_charset_same(fromcs, tocs) && (fromcs != &my_charset_bin) && (tocs != &my_charset_bin)) { @@ -831,12 +830,14 @@ bool Protocol_simple::store(Field *field) #endif char buff[MAX_FIELD_WIDTH]; String str(buff,sizeof(buff), &my_charset_bin); + CHARSET_INFO *tocs= this->thd->variables.character_set_results; + field->val_str(&str,&str); - if (!my_charset_same(field->charset(), this->thd->charset()) && + if (tocs && !my_charset_same(field->charset(), tocs) && (field->charset() != &my_charset_bin) && - (this->thd->charset() != &my_charset_bin)) + (tocs != &my_charset_bin)) { - convert.copy(str.ptr(), str.length(), str.charset(), this->thd->charset()); + convert.copy(str.ptr(), str.length(), str.charset(), tocs); return net_store_data(convert.ptr(), convert.length()); } else @@ -891,9 +892,10 @@ bool Protocol_simple::store_time(TIME *tm) #endif char buff[40]; uint length; + uint day= (tm->year || tm->month) ? 0 : tm->day; length= my_sprintf(buff,(buff, "%s%02ld:%02d:%02d", tm->neg ? "-" : "", - (long) tm->day*3600L+(long) tm->hour, + (long) day*24L+(long) tm->hour, (int) tm->minute, (int) tm->second)); return net_store_data((char*) buff, length); diff --git a/sql/protocol.h b/sql/protocol.h index dd644afd335..ffd61b3e848 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -60,6 +60,8 @@ public: { return store_longlong((longlong) from, 0); } inline bool store(ulonglong from) { return store_longlong((longlong) from, 1); } + inline bool store(String *str) + { return store(str->c_ptr(),str->length(),str->charset()); } virtual bool prepare_for_send(List<Item> *item_list) { @@ -162,7 +164,6 @@ 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); diff --git a/sql/records.cc b/sql/records.cc index 9d8627bc1fc..783ca663dfe 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -16,7 +16,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Functions to read, write and lock records */ +/* Functions for easy reading of records, possible through a cache */ #include "mysql_priv.h" diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 58769827bed..bbfd7866aa2 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -23,7 +23,6 @@ #include "sql_repl.h" #include "slave.h" #include "sql_acl.h" -#include "mini_client.h" #include "log_event.h" #include <mysql.h> @@ -72,7 +71,7 @@ static int init_failsafe_rpl_thread(THD* thd) if (init_thr_lock() || thd->store_globals()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); // is this needed? + close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed? end_thread(thd,0); DBUG_RETURN(-1); } @@ -484,14 +483,15 @@ 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",16) || - !(res = mc_mysql_store_result(mysql))) + + if (mysql_real_query(mysql,"SHOW SLAVE HOSTS",16) || + !(res = mysql_store_result(mysql))) { - error= mc_mysql_error(mysql); + error= mysql_error(mysql); goto err; } - switch (mc_mysql_num_fields(res)) { + switch (mysql_num_fields(res)) { case 5: have_auth_info = 0; port_ind=2; @@ -508,7 +508,7 @@ HOSTS"; pthread_mutex_lock(&LOCK_slave_list); - while ((row= mc_mysql_fetch_row(res))) + while ((row= mysql_fetch_row(res))) { uint32 server_id; SLAVE_INFO* si, *old_si; @@ -541,7 +541,7 @@ HOSTS"; err: if (res) - mc_mysql_free_result(res); + mysql_free_result(res); if (error) { sql_print_error("While trying to obtain the list of slaves from the master \ @@ -566,7 +566,7 @@ pthread_handler_decl(handle_failsafe_rpl,arg) thd->thread_stack = (char*)&thd; MYSQL* recovery_captain = 0; pthread_detach_this_thread(); - if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mc_mysql_init(0))) + if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mysql_init(0))) { sql_print_error("Could not initialize failsafe replication thread"); goto err; @@ -599,7 +599,7 @@ pthread_handler_decl(handle_failsafe_rpl,arg) pthread_mutex_unlock(&LOCK_rpl_status); err: if (recovery_captain) - mc_mysql_close(recovery_captain); + mysql_close(recovery_captain); delete thd; my_thread_end(); pthread_exit(0); @@ -668,9 +668,10 @@ int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi) strmov(mysql->net.last_error, "Master is not configured"); DBUG_RETURN(1); } - if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, - mi->port, 0, 0, - slave_net_timeout)) + mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *)&slave_net_timeout); + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, (char *)default_charset_info); + if (!mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, + mi->port, 0, 0)) DBUG_RETURN(1); DBUG_RETURN(0); } @@ -682,9 +683,9 @@ static inline void cleanup_mysql_results(MYSQL_RES* db_res, for (; cur >= start; --cur) { if (*cur) - mc_mysql_free_result(*cur); + mysql_free_result(*cur); } - mc_mysql_free_result(db_res); + mysql_free_result(db_res); } @@ -692,8 +693,8 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db, MYSQL_RES *table_res, MASTER_INFO *mi) { MYSQL_ROW row; - for (row = mc_mysql_fetch_row(table_res); row; - row = mc_mysql_fetch_row(table_res)) + for (row = mysql_fetch_row(table_res); row; + row = mysql_fetch_row(table_res)) { TABLE_LIST table; const char* table_name= row[0]; @@ -727,7 +728,7 @@ int load_master_data(THD* thd) int error = 0; const char* errmsg=0; int restart_thread_mask; - mc_mysql_init(&mysql); + mysql_init(&mysql); /* We do not want anyone messing with the slave at all for the entire @@ -749,7 +750,7 @@ int load_master_data(THD* thd) if (connect_to_master(thd, &mysql, active_mi)) { net_printf(thd, error= ER_CONNECT_TO_MASTER, - mc_mysql_error(&mysql)); + mysql_error(&mysql)); goto err; } @@ -758,15 +759,15 @@ 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", 14) || - !(db_res = mc_mysql_store_result(&mysql))) + if (mysql_real_query(&mysql, "SHOW DATABASES", 14) || + !(db_res = mysql_store_result(&mysql))) { net_printf(thd, error = ER_QUERY_ON_MASTER, - mc_mysql_error(&mysql)); + mysql_error(&mysql)); goto err; } - if (!(num_dbs = (uint) mc_mysql_num_rows(db_res))) + if (!(num_dbs = (uint) mysql_num_rows(db_res))) goto err; /* In theory, the master could have no databases at all @@ -785,12 +786,12 @@ 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", 27) || - mc_mysql_query(&mysql, "SHOW MASTER STATUS",18) || - !(master_status_res = mc_mysql_store_result(&mysql))) + if (mysql_real_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) || + mysql_real_query(&mysql, "SHOW MASTER STATUS",18) || + !(master_status_res = mysql_store_result(&mysql))) { net_printf(thd, error = ER_QUERY_ON_MASTER, - mc_mysql_error(&mysql)); + mysql_error(&mysql)); goto err; } @@ -805,7 +806,7 @@ int load_master_data(THD* thd) cur_table_res++) { // since we know how many rows we have, this can never be NULL - MYSQL_ROW row = mc_mysql_fetch_row(db_res); + MYSQL_ROW row = mysql_fetch_row(db_res); char* db = row[0]; /* @@ -834,12 +835,12 @@ int load_master_data(THD* thd) goto err; } - if (mc_mysql_select_db(&mysql, db) || - mc_mysql_query(&mysql, "SHOW TABLES", 11) || - !(*cur_table_res = mc_mysql_store_result(&mysql))) + if (mysql_select_db(&mysql, db) || + mysql_real_query(&mysql, "SHOW TABLES", 11) || + !(*cur_table_res = mysql_store_result(&mysql))) { net_printf(thd, error = ER_QUERY_ON_MASTER, - mc_mysql_error(&mysql)); + mysql_error(&mysql)); cleanup_mysql_results(db_res, cur_table_res - 1, table_res); goto err; } @@ -857,7 +858,7 @@ int load_master_data(THD* thd) // adjust position in the master if (master_status_res) { - MYSQL_ROW row = mc_mysql_fetch_row(master_status_res); + MYSQL_ROW row = mysql_fetch_row(master_status_res); /* We need this check because the master may not be running with @@ -875,13 +876,13 @@ int load_master_data(THD* thd) active_mi->master_log_pos = BIN_LOG_HEADER_SIZE; flush_master_info(active_mi); } - mc_mysql_free_result(master_status_res); + mysql_free_result(master_status_res); } - if (mc_mysql_query(&mysql, "UNLOCK TABLES", 13)) + if (mysql_real_query(&mysql, "UNLOCK TABLES", 13)) { net_printf(thd, error = ER_QUERY_ON_MASTER, - mc_mysql_error(&mysql)); + mysql_error(&mysql)); goto err; } } @@ -920,7 +921,7 @@ err: UNLOCK_ACTIVE_MI; thd->proc_info = 0; - mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init() + mysql_close(&mysql); // safe to call since we always do mysql_init() if (!error) send_ok(thd); diff --git a/sql/set_var.cc b/sql/set_var.cc index e4adbb0a318..60b0d24430d 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -87,6 +87,8 @@ 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_query_cache_min_res_unit(THD *thd, enum_var_type type); static void fix_key_buffer_size(THD *thd, enum_var_type type); +static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type); +static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); @@ -101,13 +103,16 @@ sys_var_long_ptr sys_binlog_cache_size("binlog_cache_size", &binlog_cache_size); sys_var_thd_ulong sys_bulk_insert_buff_size("bulk_insert_buffer_size", &SV::bulk_insert_buff_size); -sys_var_str sys_charset("character_set", +sys_var_character_set_server sys_character_set_server("character_set_server"); +sys_var_str sys_charset_system("character_set_system", sys_check_charset, sys_update_charset, sys_set_default_charset); -sys_var_collation_client sys_collation_client("collation_client"); +sys_var_character_set_database sys_character_set_database("character_set_database"); +sys_var_character_set_client sys_character_set_client("character_set_client"); +sys_var_character_set_connection sys_character_set_connection("character_set_connection"); +sys_var_character_set_results sys_character_set_results("character_set_results"); sys_var_collation_connection sys_collation_connection("collation_connection"); -sys_var_collation_results sys_collation_results("collation_results"); sys_var_bool_ptr sys_concurrent_insert("concurrent_insert", &myisam_concurrent_insert); sys_var_long_ptr sys_connect_timeout("connect_timeout", @@ -184,8 +189,9 @@ sys_var_thd_ulong sys_max_tmp_tables("max_tmp_tables", &SV::max_tmp_tables); sys_var_long_ptr sys_max_write_lock_count("max_write_lock_count", &max_write_lock_count); -sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size); -sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size); +sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort_file_size", &SV::myisam_max_extra_sort_file_size, fix_myisam_max_extra_sort_file_size, 1); +sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1); +sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads); sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size); sys_var_thd_ulong sys_net_buffer_length("net_buffer_length", &SV::net_buffer_length); @@ -229,6 +235,7 @@ sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol", sys_var_long_ptr sys_slave_net_timeout("slave_net_timeout", &slave_net_timeout); #endif +sys_var_bool_ptr sys_readonly("read_only", &opt_readonly); sys_var_long_ptr sys_slow_launch_time("slow_launch_time", &slow_launch_time); sys_var_thd_ulong sys_sort_buffer("sort_buffer_size", @@ -249,6 +256,11 @@ 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); + +#ifdef HAVE_INNOBASE_DB +sys_var_long_ptr sys_innodb_max_dirty_pages_pct("innodb_max_dirty_pages_pct", + &srv_max_buf_pool_modified_pct); +#endif /* Variables that are bits in THD */ @@ -267,7 +279,7 @@ static sys_var_thd_bit sys_sql_big_tables("sql_big_tables", #endif static sys_var_thd_bit sys_big_selects("sql_big_selects", set_option_bit, - OPTION_BIG_TABLES); + OPTION_BIG_SELECTS); static sys_var_thd_bit sys_log_off("sql_log_off", set_option_bit, OPTION_LOG_OFF); @@ -349,9 +361,12 @@ sys_var *sys_variables[]= &sys_binlog_cache_size, &sys_buffer_results, &sys_bulk_insert_buff_size, - &sys_collation_client, + &sys_character_set_server, + &sys_character_set_database, + &sys_character_set_client, + &sys_character_set_connection, + &sys_character_set_results, &sys_collation_connection, - &sys_collation_results, &sys_concurrent_insert, &sys_connect_timeout, &sys_default_week_format, @@ -395,6 +410,7 @@ sys_var *sys_variables[]= &sys_max_write_lock_count, &sys_myisam_max_extra_sort_file_size, &sys_myisam_max_sort_file_size, + &sys_myisam_repair_threads, &sys_myisam_sort_buffer_size, &sys_net_buffer_length, &sys_net_read_timeout, @@ -426,6 +442,7 @@ sys_var *sys_variables[]= &sys_slave_net_timeout, &sys_slave_skip_counter, #endif + &sys_readonly, &sys_slow_launch_time, &sys_sort_buffer, &sys_sql_big_tables, @@ -439,6 +456,9 @@ sys_var *sys_variables[]= &sys_timestamp, &sys_tmp_table_size, &sys_tx_isolation, +#ifdef HAVE_INNOBASE_DB + &sys_innodb_max_dirty_pages_pct, +#endif &sys_unique_checks, &sys_warning_count }; @@ -463,11 +483,13 @@ struct show_var_st init_vars[]= { #endif {sys_binlog_cache_size.name,(char*) &sys_binlog_cache_size, SHOW_SYS}, {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_collation_client.name, (char*) &sys_collation_client, SHOW_SYS}, + {sys_character_set_server.name, (char*) &sys_character_set_server,SHOW_SYS}, + {sys_charset_system.name, (char*) &sys_charset_system, SHOW_SYS}, + {sys_character_set_database.name, (char*) &sys_character_set_database,SHOW_SYS}, + {sys_character_set_client.name,(char*) &sys_character_set_client,SHOW_SYS}, + {sys_character_set_connection.name,(char*) &sys_character_set_connection,SHOW_SYS}, + {sys_character_set_results.name,(char*) &sys_character_set_results, SHOW_SYS}, {sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS}, - {sys_collation_results.name, (char*) &sys_collation_results, SHOW_SYS}, {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS}, {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {"datadir", mysql_real_data_home, SHOW_CHAR}, @@ -514,6 +536,7 @@ struct show_var_st init_vars[]= { {"innodb_log_files_in_group", (char*) &innobase_log_files_in_group, SHOW_LONG}, {"innodb_log_group_home_dir", (char*) &innobase_log_group_home_dir, SHOW_CHAR_PTR}, {"innodb_mirrored_log_groups", (char*) &innobase_mirrored_log_groups, SHOW_LONG}, + {sys_innodb_max_dirty_pages_pct.name, (char*) &sys_innodb_max_dirty_pages_pct, SHOW_SYS}, #endif {sys_interactive_timeout.name,(char*) &sys_interactive_timeout, SHOW_SYS}, {sys_join_buffer_size.name, (char*) &sys_join_buffer_size, SHOW_SYS}, @@ -550,13 +573,14 @@ struct show_var_st init_vars[]= { {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}, + {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, {sys_max_write_lock_count.name, (char*) &sys_max_write_lock_count,SHOW_SYS}, {sys_myisam_max_extra_sort_file_size.name, (char*) &sys_myisam_max_extra_sort_file_size, SHOW_SYS}, - {sys_myisam_max_sort_file_size.name, - (char*) &sys_myisam_max_sort_file_size, + {sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size, + SHOW_SYS}, + {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, {"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, @@ -595,6 +619,7 @@ struct show_var_st init_vars[]= { #ifdef HAVE_REPLICATION {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, #endif + {sys_readonly.name, (char*) &sys_readonly, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, {"skip_networking", (char*) &opt_disable_networking, SHOW_BOOL}, {"skip_show_database", (char*) &opt_skip_show_db, SHOW_BOOL}, @@ -661,6 +686,21 @@ static void fix_low_priority_updates(THD *thd, enum_var_type type) } +static void +fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type) +{ + myisam_max_extra_temp_length= + (my_off_t) global_system_variables.myisam_max_extra_sort_file_size; +} + + +static void +fix_myisam_max_sort_file_size(THD *thd, enum_var_type type) +{ + myisam_max_temp_length= + (my_off_t) global_system_variables.myisam_max_sort_file_size; +} + /* Set the OPTION_BIG_SELECTS flag if max_join_size == HA_POS_ERROR */ @@ -911,15 +951,22 @@ byte *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type) bool sys_var_thd_ulonglong::update(THD *thd, set_var *var) { + ulonglong tmp= var->value->val_int(); + + if ((ulonglong) tmp > max_system_variables.*offset) + tmp= max_system_variables.*offset; + + if (option_limits) + tmp= (ulong) getopt_ull_limit_value(tmp, option_limits); if (var->type == OPT_GLOBAL) { /* Lock is needed to make things safe on 32 bit systems */ pthread_mutex_lock(&LOCK_global_system_variables); - global_system_variables.*offset= var->value->val_int(); + global_system_variables.*offset= (ulonglong) tmp; pthread_mutex_unlock(&LOCK_global_system_variables); } else - thd->variables.*offset= var->value->val_int(); + thd->variables.*offset= (ulonglong) tmp; return 0; } @@ -1010,6 +1057,7 @@ err: bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) { + bool not_used; char buff[80], *error= 0; uint error_len= 0; String str(buff, sizeof(buff), system_charset_info), *res; @@ -1019,7 +1067,7 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names) 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); + find_set(enum_names, res->c_ptr(), res->length(), &error, &error_len, ¬_used); if (error_len) { strmake(buff, error, min(sizeof(buff), error_len)); @@ -1202,7 +1250,7 @@ CHARSET_INFO *get_old_charset_by_name(const char *name) for (c= old_conv; c->old_name; c++) { if (!my_strcasecmp(&my_charset_latin1,name,c->old_name)) - return get_charset_by_name(c->new_name,MYF(0)); + return get_charset_by_csname(c->new_name,MY_CS_PRIMARY,MYF(0)); } return NULL; } @@ -1216,7 +1264,31 @@ bool sys_var_collation::check(THD *thd, set_var *var) if (!(res=var->value->val_str(&str))) res= &empty_string; - if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))) && + 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_character_set::check(THD *thd, set_var *var) +{ + CHARSET_INFO *tmp; + char buff[80]; + String str(buff,sizeof(buff), system_charset_info), *res; + + if (!(res=var->value->val_str(&str))) + { + if (!nullable) + { + my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), "NULL"); + return 1; + } + tmp= NULL; + } + else if (!(tmp=get_charset_by_csname(res->c_ptr(),MY_CS_PRIMARY,MYF(0))) && !(tmp=get_old_charset_by_name(res->c_ptr()))) { my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr()); @@ -1226,83 +1298,127 @@ bool sys_var_collation::check(THD *thd, set_var *var) return 0; } -bool sys_var_collation_client::update(THD *thd, set_var *var) +bool sys_var_character_set::update(THD *thd, set_var *var) { - if (var->type == OPT_GLOBAL) - global_system_variables.collation_client= var->save_result.charset; - else - thd->variables.collation_client= var->save_result.charset; + ci_ptr(thd,var->type)[0]= var->save_result.charset; return 0; } -byte *sys_var_collation_client::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_character_set::value_ptr(THD *thd, enum_var_type type) { - CHARSET_INFO *cs= ((type == OPT_GLOBAL) ? - global_system_variables.collation_client : - thd->variables.collation_client); - return cs ? (byte*) cs->name : (byte*) ""; + CHARSET_INFO *cs= ci_ptr(thd,type)[0]; + return cs ? (byte*) cs->csname : (byte*) "NULL"; } -void sys_var_collation_client::set_default(THD *thd, enum_var_type type) + +CHARSET_INFO ** sys_var_character_set_connection::ci_ptr(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + return &global_system_variables.collation_connection; + else + return &thd->variables.collation_connection; +} + +void sys_var_character_set_connection::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) - global_system_variables.collation_client= default_charset_info; + global_system_variables.collation_connection= default_charset_info; else - thd->variables.collation_client= global_system_variables.collation_client; + thd->variables.collation_connection= global_system_variables.collation_connection; } -bool sys_var_collation_connection::update(THD *thd, set_var *var) +CHARSET_INFO ** sys_var_character_set_client::ci_ptr(THD *thd, enum_var_type type) { - if (var->type == OPT_GLOBAL) - global_system_variables.collation_connection= var->save_result.charset; + if (type == OPT_GLOBAL) + return &global_system_variables.character_set_client; else - thd->variables.collation_connection= var->save_result.charset; - return 0; + return &thd->variables.character_set_client; } -byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type) +void sys_var_character_set_client::set_default(THD *thd, enum_var_type type) { - CHARSET_INFO *cs= ((type == OPT_GLOBAL) ? - global_system_variables.collation_connection : - thd->variables.collation_connection); - return cs ? (byte*) cs->name : (byte*) ""; + if (type == OPT_GLOBAL) + global_system_variables.character_set_client= default_charset_info; + else + thd->variables.character_set_client= global_system_variables.character_set_client; } -void sys_var_collation_connection::set_default(THD *thd, enum_var_type type) +CHARSET_INFO ** sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + return &global_system_variables.character_set_results; + else + return &thd->variables.character_set_results; +} + +void sys_var_character_set_results::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) - global_system_variables.collation_connection= default_charset_info; + global_system_variables.character_set_results= default_charset_info; else - thd->variables.collation_connection= global_system_variables.collation_connection; + thd->variables.character_set_results= global_system_variables.character_set_results; +} + +CHARSET_INFO ** sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + return &global_system_variables.character_set_server; + else + return &thd->variables.character_set_server; } -bool sys_var_collation_results::update(THD *thd, set_var *var) +void sys_var_character_set_server::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.character_set_server= default_charset_info; + else + thd->variables.character_set_server= global_system_variables.character_set_server; +} + +CHARSET_INFO ** sys_var_character_set_database::ci_ptr(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + return &global_system_variables.character_set_database; + else + return &thd->variables.character_set_database; +} + +void sys_var_character_set_database::set_default(THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.character_set_database= default_charset_info; + else + thd->variables.character_set_database= thd->db_charset; +} + +bool sys_var_collation_connection::update(THD *thd, set_var *var) { if (var->type == OPT_GLOBAL) - global_system_variables.collation_results= var->save_result.charset; + global_system_variables.collation_connection= var->save_result.charset; else - thd->variables.collation_results= var->save_result.charset; + thd->variables.collation_connection= var->save_result.charset; return 0; } -byte *sys_var_collation_results::value_ptr(THD *thd, enum_var_type type) +byte *sys_var_collation_connection::value_ptr(THD *thd, enum_var_type type) { CHARSET_INFO *cs= ((type == OPT_GLOBAL) ? - global_system_variables.collation_results : - thd->variables.collation_results); - return cs ? (byte*) cs->name : (byte*) ""; + global_system_variables.collation_connection : + thd->variables.collation_connection); + return cs ? (byte*) cs->name : (byte*) "NULL"; } -void sys_var_collation_results::set_default(THD *thd, enum_var_type type) +void sys_var_collation_connection::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) - global_system_variables.collation_results= default_charset_info; + global_system_variables.collation_connection= default_charset_info; else - thd->variables.collation_results= global_system_variables.collation_results; + thd->variables.collation_connection= global_system_variables.collation_connection; } + /***************************************************************************** Functions to handle SET NAMES and SET CHARACTER SET *****************************************************************************/ @@ -1314,9 +1430,9 @@ int set_var_collation_client::check(THD *thd) int set_var_collation_client::update(THD *thd) { - thd->variables.collation_client= collation_client; + thd->variables.character_set_client= character_set_client; + thd->variables.character_set_results= character_set_results; thd->variables.collation_connection= collation_connection; - thd->variables.collation_results= collation_results; thd->protocol_simple.init(thd); thd->protocol_prep.init(thd); return 0; @@ -1635,7 +1751,7 @@ sys_var *find_sys_var(const char *str, uint length) int sql_set_variables(THD *thd, List<set_var_base> *var_list) { int error= 0; - List_iterator<set_var_base> it(*var_list); + List_iterator_fast<set_var_base> it(*var_list); set_var_base *var; while ((var=it++)) @@ -1751,5 +1867,5 @@ int set_var_password::update(THD *thd) #ifdef __GNUC__ template class List<set_var_base>; -template class List_iterator<set_var_base>; +template class List_iterator_fast<set_var_base>; #endif diff --git a/sql/set_var.h b/sql/set_var.h index fbd20228d24..d016c3a7085 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -235,17 +235,27 @@ class sys_var_thd_ulonglong :public sys_var_thd { public: ulonglong SV::*offset; + bool only_global; 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) + sys_after_update_func func, bool only_global_arg) + :sys_var_thd(name_arg, func), offset(offset_arg), + only_global(only_global_arg) {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONGLONG; } byte *value_ptr(THD *thd, enum_var_type type); + bool check_default(enum_var_type type) + { + return type == OPT_GLOBAL && !option_limits; + } + bool check_type(enum_var_type type) + { + return (only_global && type != OPT_GLOBAL); + } }; @@ -420,34 +430,80 @@ SHOW_TYPE type() { return SHOW_CHAR; } virtual void set_default(THD *thd, enum_var_type type)= 0; }; -class sys_var_collation_client :public sys_var_collation +class sys_var_character_set :public sys_var_thd { public: - sys_var_collation_client(const char *name_arg) :sys_var_collation(name_arg) {} + bool nullable; + sys_var_character_set(const char *name_arg) :sys_var_thd(name_arg) + { nullable= 0; } + bool check(THD *thd, set_var *var); +SHOW_TYPE type() { return SHOW_CHAR; } + bool check_update_type(Item_result type) + { + return type != STRING_RESULT; /* Only accept strings */ + } + bool check_default(enum_var_type type) { return 0; } bool update(THD *thd, set_var *var); - void set_default(THD *thd, enum_var_type type); byte *value_ptr(THD *thd, enum_var_type type); + virtual void set_default(THD *thd, enum_var_type type)= 0; + virtual CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type)= 0; }; -class sys_var_collation_connection :public sys_var_collation +class sys_var_character_set_client :public sys_var_character_set { public: - sys_var_collation_connection(const char *name_arg) :sys_var_collation(name_arg) {} - bool update(THD *thd, set_var *var); + sys_var_character_set_client(const char *name_arg) : + sys_var_character_set(name_arg) {} void set_default(THD *thd, enum_var_type type); - byte *value_ptr(THD *thd, enum_var_type type); + CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); }; -class sys_var_collation_results :public sys_var_collation +class sys_var_character_set_results :public sys_var_character_set { public: - sys_var_collation_results(const char *name_arg) :sys_var_collation(name_arg) {} + sys_var_character_set_results(const char *name_arg) : + sys_var_character_set(name_arg) + { nullable= 1; } + void set_default(THD *thd, enum_var_type type); + CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); +}; + +class sys_var_character_set_server :public sys_var_character_set +{ +public: + sys_var_character_set_server(const char *name_arg) : + sys_var_character_set(name_arg) {} + void set_default(THD *thd, enum_var_type type); + CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); +}; + +class sys_var_character_set_database :public sys_var_character_set +{ +public: + sys_var_character_set_database(const char *name_arg) : + sys_var_character_set(name_arg) {} + void set_default(THD *thd, enum_var_type type); + CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); +}; + +class sys_var_character_set_connection :public sys_var_character_set +{ +public: + sys_var_character_set_connection(const char *name_arg) : + sys_var_character_set(name_arg) {} + void set_default(THD *thd, enum_var_type type); + CHARSET_INFO **ci_ptr(THD *thd, enum_var_type type); +}; + +class sys_var_collation_connection :public sys_var_collation +{ +public: + sys_var_collation_connection(const char *name_arg) :sys_var_collation(name_arg) {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); byte *value_ptr(THD *thd, enum_var_type type); }; - /* Variable that you can only read from */ class sys_var_readonly: public sys_var @@ -555,16 +611,16 @@ public: class set_var_collation_client: public set_var_base { - CHARSET_INFO *collation_client; + CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_results; CHARSET_INFO *collation_connection; - CHARSET_INFO *collation_results; public: set_var_collation_client(CHARSET_INFO *client_coll_arg, CHARSET_INFO *connection_coll_arg, CHARSET_INFO *result_coll_arg) - :collation_client(client_coll_arg), - collation_connection(connection_coll_arg), - collation_results(result_coll_arg) + :character_set_client(client_coll_arg), + character_set_results(result_coll_arg), + collation_connection(connection_coll_arg) {} int check(THD *thd); int update(THD *thd); @@ -581,5 +637,5 @@ sys_var *find_sys_var(const char *str, uint length=0); int sql_set_variables(THD *thd, List<set_var_base> *var_list); void fix_delay_key_write(THD *thd, enum_var_type type); -extern sys_var_str sys_charset; +extern sys_var_str sys_charset_system; CHARSET_INFO *get_old_charset_by_name(const char *old_name); diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml index 9b95326fe9e..6e091066654 100644 --- a/sql/share/charsets/Index.xml +++ b/sql/share/charsets/Index.xml @@ -1,6 +1,6 @@ <?xml version='1.0' encoding="utf-8"?> -<charsets max-id="83"> +<charsets max-id="91"> <description> This file lists all of the available character sets. @@ -19,7 +19,11 @@ To make maintaining easier please: <alias>csbig5</alias> <collation name="big5_chinese_ci" id="1" order="Chinese"> <flag>primary</flag> - <flag>compiled"</flag> + <flag>compiled</flag> + </collation> + <collation name="big5_bin" id="84" order="Binary"> + <flag>binary</flag> + <flag>compiled</flag> </collation> </charset> @@ -96,7 +100,10 @@ To make maintaining easier please: <collation name="latin1_swedish_ci" id="8" order="Finnish, Swedish" flag="primary"/> <collation name="latin1_danish_ci" id="15" order="Danish"/> <collation name="latin1_german2_ci" id="31" order="German Phonebook" flag="compiled"/> - <collation name="latin1_bin" id="47" order="Binary" flag="binary"/> + <collation name="latin1_bin" id="47" order="Binary"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> <collation name="latin1_general_ci" id="48"> <order>Dutch</order> <order>English</order> @@ -169,7 +176,14 @@ To make maintaining easier please: <family>Japanese</family> <description>EUC-JP Japanese</description> <alias>euc-jp</alias> - <collation name="ujis_japanese_ci" id="12" order="Japanese" flag="primary"/> + <collation name="ujis_japanese_ci" id="12" order="Japanese"> + <flag>primary</flag> + <flag>compiled</flag> + </collation> + <collation name="ujis_bin" id="91" order="Japanese"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> </charset> <charset name="sjis"> @@ -178,7 +192,14 @@ To make maintaining easier please: <alias>s-jis</alias> <alias>shift-jis</alias> <alias>x-sjis</alias> - <collation name="sjis_japanese_ci" id="13" order="Japanese" flag="primary"/> + <collation name="sjis_japanese_ci" id="13" order="Japanese"> + <flag>primary</flag> + <flag>compiled</flag> + </collation> + <collation name="sjis_bin" id="88" order="Binary"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> </charset> <charset name="cp1251"> @@ -236,6 +257,10 @@ To make maintaining easier please: <flag>primary</flag> <flag>compiled</flag> </collation> + <collation name="tis620_bin" id="89" order="Binary"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> </charset> <charset name="euckr"> @@ -245,7 +270,11 @@ To make maintaining easier please: <alias>euc-kr</alias> <collation name="euckr_korean_ci" id="19" order="Korean"> <flag>primary</flag> - <flag>compiled"</flag> + <flag>compiled</flag> + </collation> + <collation name="euckr_bin" id="85"> + <flag>binary</flag> + <flag>compiled</flag> </collation> </charset> @@ -255,7 +284,7 @@ To make maintaining easier please: <alias>BalticRim</alias> <alias>iso-8859-13</alias> <alias>l7</alias> - <collation name="latin7_estonian_ci" id="20"> + <collation name="latin7_estonian_cs" id="20"> <order>Estonian</order> </collation> <collation name="latin7_general_ci" id="41"> @@ -285,7 +314,11 @@ To make maintaining easier please: <alias>iso-ir-58</alias> <collation name="gb2312_chinese_ci" id="24" order="Chinese"> <flag>primary</flag> - <flag>compiled"</flag> + <flag>compiled</flag> + </collation> + <collation name="gb2312_bin" id="86"> + <flag>binary</flag> + <flag>compiled</flag> </collation> </charset> @@ -315,7 +348,9 @@ To make maintaining easier please: <order>Slovenian</order> <order>Sorbian</order> </collation> - <collation name="cp1250_czech_ci" id="34" order="Czech"/> + <collation name="cp1250_czech_ci" id="34" order="Czech"> + <flag>compiled</flag> + </collation> <collation name="cp1250_bin" id="66" order="Binary" flag="binary"/> </charset> @@ -327,6 +362,10 @@ To make maintaining easier please: <flag>primary</flag> <flag>compiled</flag> </collation> + <collation name="gbk_bin" id="87" order="Binary"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> </charset> <charset name="cp1257"> @@ -369,14 +408,27 @@ To make maintaining easier please: <family>Unicode</family> <description>UTF-8 Unicode</description> <alias>utf-8</alias> - <collation name="utf8_general_ci" id="33" flag="primary"/> - <collation name="utf8_bin" id="83" flag="binary"/> + <collation name="utf8_general_ci" id="33"> + <flag>primary</flag> + <flag>compiled</flag> + </collation> + <collation name="utf8_bin" id="83"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> </charset> <charset name="ucs2"> <family>Unicode</family> <description>UCS-2 Unicode</description> - <collation name="ucs2_general_ci" id="35" flag="primary"/> + <collation name="ucs2_general_ci" id="35"> + <flag>primary</flag> + <flag>compiled</flag> + </collation> + <collation name="ucs2_bin" id="90"> + <flag>binary</flag> + <flag>compiled</flag> + </collation> </charset> <charset name="cp866"> diff --git a/sql/share/charsets/latin7.xml b/sql/share/charsets/latin7.xml index d50601b5a90..1c25f5894b6 100644 --- a/sql/share/charsets/latin7.xml +++ b/sql/share/charsets/latin7.xml @@ -93,7 +93,7 @@ </unicode> -<collation name="latin7_estonian_ci"> +<collation name="latin7_estonian_cs"> <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 @@ -115,7 +115,7 @@ </collation> -<collation name="latin7_general_ci"> +<collation name="latin7_general_cs"> <!-- Created for case-sensitive record search --> <!-- by Andis Grasis & Rihards Grasis e-mail:andis@cata.lv --> <map> @@ -139,7 +139,7 @@ </collation> -<collation name="latin7_general_cs"> +<collation name="latin7_general_ci"> <!-- Created for case-insensitive record search --> <!-- Created by Andis & Rihards --> <map> diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index e04d4494a93..e277c19e26f 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -114,7 +114,7 @@ v/* "Blob polo-B¾ka '%-.64s' nemù¾e mít defaultní hodnotu", "Nep-Bøípustné jméno databáze '%-.64s'", "Nep-Bøípustné jméno tabulky '%-.64s'", -"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET OPTION SQL_BIG_SELECTS=1", +"Zadan-Bý SELECT by procházel pøíli¹ mnoho záznamù a trval velmi dlouho. Zkontrolujte tvar WHERE a je-li SELECT v poøádku, pou¾ijte SET SQL_BIG_SELECTS=1", "Nezn-Bámá chyba", "Nezn-Bámá procedura %s", "Chybn-Bý poèet parametrù procedury %s", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ff89dbb6bcf..01856ffed01 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -108,7 +108,7 @@ "BLOB feltet '%-.64s' kan ikke have en standard værdi", "Ugyldigt database navn '%-.64s'", "Ugyldigt tabel navn '%-.64s'", -"SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET OPTION SQL_BIG_SELECTS=1 hvis udtrykket er korrekt", +"SELECT ville undersøge for mange poster og ville sandsynligvis tage meget lang tid. Undersøg WHERE delen og brug SET SQL_BIG_SELECTS=1 hvis udtrykket er korrekt", "Ukendt fejl", "Ukendt procedure %s", "Forkert antal parametre til proceduren %s", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 98ca6a834e4..4b9b0b9f710 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -116,7 +116,7 @@ "Blob veld '%-.64s' can geen standaardwaarde bevatten", "Databasenaam '%-.64s' is niet getoegestaan", "Niet toegestane tabelnaam '%-.64s'", -"Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET OPTION SQL_BIG_SELECTS=1 als het stament in orde is.", +"Het SELECT-statement zou te veel records analyseren en dus veel tijd in beslagnemen. Kijk het WHERE-gedeelte van de query na en kies SET SQL_BIG_SELECTS=1 als het stament in orde is.", "Onbekende Fout", "Onbekende procedure %s", "Foutief aantal parameters doorgegeven aan procedure %s", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index cb709c45326..89045b13985 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -105,7 +105,7 @@ "BLOB column '%-.64s' can't have a default value", "Incorrect database name '%-.100s'", "Incorrect table name '%-.100s'", -"The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok", +"The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok", "Unknown error", "Unknown procedure '%-.64s'", "Incorrect parameter count to procedure '%-.64s'", @@ -249,16 +249,21 @@ "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", -"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", -"Z_DATA_ERROR: Input data was corrupted for zlib", -"%d line(s) was(were) cut by group_concat()", +"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" +"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)" +"Z_BUF_ERROR: Not enough memory available for zlib" +"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)" +"Z_DATA_ERROR: Input data was corrupted for zlib" +"%d line(s) was(were) cut by group_concat()" +"Record count is fewer than the column count at row %ld"; +"Record count is more than the column count at row %ld"; +"Data truncated, NULL supplied to NOT NULL column '%s' at row %ld"; +"Data truncated, out of range for column '%s' at row %ld"; +"Data truncated for column '%s' at row %ld" "Using storage engine %s for table '%s'", "Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index f9d5a2b6324..d5064b53790 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -110,7 +110,7 @@ "BLOB-tüüpi tulp '%-.64s' ei saa omada vaikeväärtust", "Vigane andmebaasi nimi '%-.100s'", "Vigane tabeli nimi '%-.100s'", -"SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET OPTION SQL_BIG_SELECTS=1", +"SELECT lause peab läbi vaatama suure hulga kirjeid ja võtaks tõenäoliselt liiga kaua aega. Tasub kontrollida WHERE klauslit ja vajadusel kasutada käsku SET SQL_BIG_SELECTS=1", "Tundmatu viga", "Tundmatu protseduur '%-.64s'", "Vale parameetrite hulk protseduurile '%-.64s'", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index 1c4efab7e53..eb936243332 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -105,7 +105,7 @@ "BLOB '%-.64s' ne peut avoir de valeur par défaut", "Nom de base de donnée illégal: '%-.64s'", "Nom de table illégal: '%-.64s'", -"SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET OPTION SQL_BIG_SELECTS=1 si SELECT se passe bien", +"SELECT va devoir examiner beaucoup d'enregistrements ce qui va prendre du temps. Vérifiez la clause WHERE et utilisez SET SQL_BIG_SELECTS=1 si SELECT se passe bien", "Erreur inconnue", "Procédure %s inconnue", "Mauvais nombre de paramètres pour la procedure %s", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 00d6e784dcb..2ac25216b8e 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -114,7 +114,7 @@ "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 oder gegebenenfalls SET OPTION SQL_BIG_SELECTS=1 verwenden.", +"Die Ausführung des SELECT würde zu viele Datensätze untersuchen und wahrscheinlich sehr lange daueren. Bitte WHERE überprüfen oder gegebenenfalls SET SQL_BIG_SELECTS=1 verwenden.", "Unbekannter Fehler.", "Unbekannte Procedure %-.64s.", "Falsche Parameterzahl für Procedure %-.64s.", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index fdeb787859c..8e82559db5c 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -105,7 +105,7 @@ "Ôá Blob ðåäßá '%-.64s' äåí ìðïñïýí íá Ý÷ïõí ðñïêáèïñéóìÝíåò ôéìÝò (default value)", "ËÜèïò üíïìá âÜóçò äåäïìÝíùí '%-.100s'", "ËÜèïò üíïìá ðßíáêá '%-.100s'", -"Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET OPTION SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü", +"Ôï SELECT èá åîåôÜóåé ìåãÜëï áñéèìü åããñáöþí êáé ðéèáíþò èá êáèõóôåñÞóåé. Ðáñáêáëþ åîåôÜóôå ôéò ðáñáìÝôñïõò ôïõ WHERE êáé ÷ñçóéìïðïéåßóôå SET SQL_BIG_SELECTS=1 áí ôï SELECT åßíáé óùóôü", "ÐñïÝêõøå Üãíùóôï ëÜèïò", "Áãíùóôç äéáäéêáóßá '%-.64s'", "ËÜèïò áñéèìüò ðáñáìÝôñùí óôç äéáäéêáóßá '%-.64s'", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 708bad26391..de0e7da614e 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -107,7 +107,7 @@ "A(z) '%-.64s' blob objektumnak nem lehet alapertelmezett erteke", "Hibas adatbazisnev: '%-.100s'", "Hibas tablanev: '%-.100s'", -"A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET OPTION SQL_BIG_SELECTS=1 beallitast, ha a SELECT ok", +"A SELECT tul sok rekordot fog megvizsgalni es nagyon sokaig fog tartani. Ellenorizze a WHERE-t es hasznalja a SET SQL_BIG_SELECTS=1 beallitast, ha a SELECT ok", "Ismeretlen hiba", "Ismeretlen eljaras: '%-.64s'", "Rossz parameter a(z) '%-.64s'eljaras szamitasanal", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 23d157ce628..d9308faf8a6 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -105,7 +105,7 @@ "Il campo BLOB '%-.64s' non puo` avere un valore di default", "Nome database errato '%-.100s'", "Nome tabella errato '%-.100s'", -"La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET OPTION SQL_BIG_SELECTS=1 se e` tutto a posto.", +"La SELECT dovrebbe esaminare troppi record e usare troppo tempo. Controllare la WHERE e usa SET SQL_BIG_SELECTS=1 se e` tutto a posto.", "Errore sconosciuto", "Procedura '%-.64s' sconosciuta", "Numero di parametri errato per la procedura '%-.64s'", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 82a8c23ab67..45e78941906 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -107,7 +107,7 @@ "BLOB column '%-.64s' can't have a default value", "»ØÄꤷ¤¿ database ̾ '%-.100s' ¤¬´Ö°ã¤Ã¤Æ¤¤¤Þ¤¹", "»ØÄꤷ¤¿ table ̾ '%-.100s' ¤Ï¤Þ¤Á¤¬¤Ã¤Æ¤¤¤Þ¤¹", -"The SELECT would examine too many records and probably take a very long time. Check your WHERE and use SET OPTION SQL_BIG_SELECTS=1 if the SELECT is ok", +"The SELECT would examine more rows than MAX_JOIN_SIZE. Check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is ok", "Unknown error", "Unknown procedure '%-.64s'", "Incorrect parameter count to procedure '%-.64s'", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index a96805c1dc5..43d291ae3a5 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -105,7 +105,7 @@ "BLOB Ä®·³ '%-.64s' ´Â µðÆúÆ® °ªÀ» °¡Áú ¼ö ¾ø½À´Ï´Ù.", "'%-.100s' µ¥ÀÌŸº£À̽ºÀÇ À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.", "'%-.100s' Å×À̺í À̸§ÀÌ ºÎÁ¤È®ÇÕ´Ï´Ù.", -"SELECT ¸í·É¿¡¼ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET OPTION SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä.", +"SELECT ¸í·É¿¡¼ ³Ê¹« ¸¹Àº ·¹Äڵ带 ã±â ¶§¹®¿¡ ¸¹Àº ½Ã°£ÀÌ ¼Ò¿äµË´Ï´Ù. µû¶ó¼ WHERE ¹®À» Á¡°ËÇϰųª, ¸¸¾à SELECT°¡ okµÇ¸é SET SQL_BIG_SELECTS=1 ¿É¼ÇÀ» »ç¿ëÇϼ¼¿ä.", "¾Ë¼ö ¾ø´Â ¿¡·¯ÀÔ´Ï´Ù.", "¾Ë¼ö ¾ø´Â ¼öÇ๮ : '%-.64s'", "'%-.64s' ¼öÇ๮¿¡ ´ëÇÑ ºÎÁ¤È®ÇÑ ÆĶó¸ÞÅÍ", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 31e2afa0cc9..c0c045438ec 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -107,7 +107,7 @@ "Blob feltet '%-.64s' kan ikkje ha ein standard verdi", "Ugyldig database namn '%-.64s'", "Ugyldig tabell namn '%-.64s'", -"SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET OPTION SQL_BIG_SELECTS=1 om SELECTen er korrekt", +"SELECT ville undersøkje for mange postar og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt", "Ukjend feil", "Ukjend prosedyre %s", "Feil parameter tal til prosedyra %s", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 2e1468bc815..03430ae546b 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -107,7 +107,7 @@ "Blob feltet '%-.64s' kan ikke ha en standard verdi", "Ugyldig database navn '%-.64s'", "Ugyldig tabell navn '%-.64s'", -"SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET OPTION SQL_BIG_SELECTS=1 om SELECTen er korrekt", +"SELECT ville undersøke for mange poster og ville sannsynligvis ta veldig lang tid. Undersøk WHERE klausulen og bruk SET SQL_BIG_SELECTS=1 om SELECTen er korrekt", "Ukjent feil", "Ukjent prosedyre %s", "Feil parameter antall til prosedyren %s", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 284334cbfbd..ef051d957cb 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -105,7 +105,7 @@ "Coluna BLOB '%-.64s' não pode ter um valor padrão (default)", "Nome de banco de dados '%-.100s' incorreto", "Nome de tabela '%-.100s' incorreto", -"O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET OPTION SQL_BIG_SELECTS=1, se o SELECT estiver correto", +"O SELECT examinaria registros demais e provavelmente levaria muito tempo. Cheque sua cláusula WHERE e use SET SQL_BIG_SELECTS=1, se o SELECT estiver correto", "Erro desconhecido", "'Procedure' '%-.64s' desconhecida", "Número de parâmetros incorreto para a 'procedure' '%-.64s'", @@ -219,46 +219,46 @@ "Não pode acrescentar uma restrição de chave estrangeira", "Não pode acrescentar uma linha filha: uma restrição de chave estrangeira falhou", "Não pode apagar uma linha pai: uma restrição de chave estrangeira falhou", -"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", -"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", -"Too big size of uncompressed data. The maximum size is %d. (probably, length of uncompressed data was corrupted)", -"Z_BUF_ERROR: Not enough memory available for zlib", -"Z_MEM_ERROR: Not enough room in the output buffer for zlib (probably, length of uncompressed data was corrupted)", -"Z_DATA_ERROR: Input data was corrupted for zlib", -"%d line(s) was(were) cut by group_concat()", -"Using storage engine %s for table '%s'", -"Illegal mix of collations (%s,%s) and (%s,%s) for operation '%s'", +"Erro connectando para o master: %-.128s", +"Erro rodando consulta no master: %-.128s", +"Erro quando executando comando %s: %-.128s", +"Uso errado de %s e %s", +"Os comandos SELECT usados têm diferentes números de colunas", +"Não pode executar a consulta porque você tem um conflitante travamento de leitura", +"Combinação de tabelas transacionais e não transacionais está desativada", +"Opção '%s' usada duas vezes no comando", +"Usuário '%-.64s' há excedido o '%s' de recursos (atual valor: %ld)", +"Acesso negado. Você necessita o privilégio %-.128s para essa operação", +"Variável '%-.64s' é uma LOCAL variável e não pode ser usada com SET GLOBAL", +"Variável '%-.64s' é uma GLOBAL variável e deve ser configurada com SET GLOBAL", +"Variável '%-.64s' não tem um valor default (padrão)", +"Variável '%-.64s' não pode ser configurada para o valor de '%-.64s'", +"Tipo de argumento errado para a variável '%-.64s'", +"Variável '%-.64s' somente pode ser configurada, não lida", +"Uso/localização errada de '%s'", +"Esta versão de MySQL não suporta ainda '%s'", +"Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log", +"Definição errada da chave estrangeira para '%-.64s': %s", +"Referência da chave e referência da tabela não coincidem", +"Error de cardinalidade (mais/menos que %d colunas)", +"Subconsulta retorna mais que 1 registro", +"Desconhecido manipulador de declaração preparado (%ld) determinado para %s", +"Banco de dado de ajuda corrupto ou não existente", +"Referência cíclica em subconsultas", +"Convertendo coluna '%s' de %s para %s", +"Referência '%-.64s' não suportada (%s)", +"Cada tabela derivada deve ter seu próprio alias", +"Select %u foi reduzido durante otimização", +"Tabela '%-.64s' de um dos SELECT's não pode ser usada em %-.32s", +"Cliente não suporta o protocolo de autenticação exigido pelo servidor. Considere a atualização deo cliente MySQL", +"Todas as partes de uma SPATIAL KEY devem ser NOT NULL", +"COLLATION '%s' não é válida para CHARACTER SET '%s'", +"O slave já está rodando", +"O slave já está parado", +"Tamanho muito grande dos dados des comprimidos. O máximo tamanho é %d. (provavelmente, o comprimento dos dados descomprimidos está corrupto)", +"Z_BUF_ERROR: Não suficiente memória disponível para zlib", +"Z_MEM_ERROR: Não suficiente espaço no buffer emissor para zlib (provavelmente, o comprimento dos dados descomprimidos está corrupto)", +"Z_DATA_ERROR: Dados de entrada está corrupto para zlib", +"%d linha(s) foi(foram) cortada(s) por group_concat()", +"Usando engine de armazenamento %s para tabela '%s'", +"Combinação ilegal de collations (%s,%s) e (%s,%s) para operação '%s'", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 1966b37bc72..89c00b4bf15 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -109,7 +109,7 @@ "Coloana BLOB '%-.64s' nu poate avea o valoare default", "Numele bazei de date este incorect '%-.100s'", "Numele tabelei este incorect '%-.100s'", -"SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp. Verifica clauza WHERE si foloseste SET OPTION SQL_BIG_SELECTS=1 daca SELECT-ul e ok", +"SELECT-ul ar examina prea multe cimpuri si probabil ar lua prea mult timp. Verifica clauza WHERE si foloseste SET SQL_BIG_SELECTS=1 daca SELECT-ul e ok", "Eroare unknown", "Procedura unknown '%-.64s'", "Procedura '%-.64s' are un numar incorect de parametri", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 3935aef82e3..fac4dedb3ee 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -107,7 +107,7 @@ "îÅ×ÏÚÍÏÖÎÏ ÕËÁÚÙ×ÁÔØ ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ ÓÔÏÌÂÃÁ BLOB '%-.64s'", "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÂÁÚÙ ÄÁÎÎÙÈ '%-.100s'", "îÅËÏÒÒÅËÔÎÏÅ ÉÍÑ ÔÁÂÌÉÃÙ '%-.100s'", -"äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET OPTION SQL_BIG_SELECTS=1", +"äÌÑ ÔÁËÏÊ ×ÙÂÏÒËÉ SELECT ÄÏÌÖÅÎ ÂÕÄÅÔ ÐÒÏÓÍÏÔÒÅÔØ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÚÁÐÉÓÅÊ É, ×ÉÄÉÍÏ, ÜÔÏ ÚÁÊÍÅÔ ÏÞÅÎØ ÍÎÏÇÏ ×ÒÅÍÅÎÉ. ðÒÏ×ÅÒØÔÅ ×ÁÛÅ ÕËÁÚÁÎÉÅ WHERE, É, ÅÓÌÉ × ÎÅÍ ×ÓÅ × ÐÏÒÑÄËÅ, ÕËÁÖÉÔÅ SET SQL_BIG_SELECTS=1", "îÅÉÚ×ÅÓÔÎÁÑ ÏÛÉÂËÁ", "îÅÉÚ×ÅÓÔÎÁÑ ÐÒÏÃÅÄÕÒÁ '%-.64s'", "îÅËÏÒÒÅËÔÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÐÁÒÁÍÅÔÒÏ× ÄÌÑ ÐÒÏÃÅÄÕÒÙ '%-.64s'", diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index db25f12ed13..8f7747c6bf6 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -113,7 +113,7 @@ "Pole BLOB '%-.64s' nemô¾e ma» implicitnú hodnotu", "Neprípustné meno databázy '%-.100s'", "Neprípustné meno tabuµky '%-.100s'", -"Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET OPTION SQL_BIG_SELECTS=1", +"Zadaná po¾iadavka SELECT by prechádzala príli¹ mnoho záznamov a trvala by príli¹ dlho. Skontrolujte tvar WHERE a ak je v poriadku, pou¾ite SET SQL_BIG_SELECTS=1", "Neznámá chyba", "Neznámá procedúra '%-.64s'", "Chybný poèet parametrov procedúry '%-.64s'", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 44fb0a19640..4a7989ce7be 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -106,7 +106,7 @@ "Campo Blob '%-.64s' no puede tener valores patron", "Nombre de base de datos ilegal '%-.64s'", "Nombre de tabla ilegal '%-.64s'", -"El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET OPTION SQL_BIG_SELECTS=1 si el SELECT esta correcto", +"El SELECT puede examinar muchos registros y probablemente con mucho tiempo. Verifique tu WHERE y usa SET SQL_BIG_SELECTS=1 si el SELECT esta correcto", "Error desconocido", "Procedimiento desconocido %s", "Equivocado parametro count para procedimiento %s", diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index e40a44957f1..6734369d3ac 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -105,7 +105,7 @@ "BLOB fält '%-.64s' kan inte ha ett DEFAULT-värde", "Felaktigt databasnamn '%-.64s'", "Felaktigt tabellnamn '%-.64s'", -"Den angivna frågan skulle troligen ta mycket lång tid! Kontrollera din WHERE och använd SET OPTION SQL_BIG_SELECTS=1 ifall du vill hantera stora joins", +"Den angivna frågan skulle läsa mer än MAX_JOIN_SIZE rader. Kontrollera din WHERE och använd SET SQL_BIG_SELECTS=1 eller SET MAX_JOIN_SIZE=# ifall du vill hantera stora joins", "Oidentifierat fel", "Okänd procedur: %s", "Felaktigt antal parametrar till procedur %s", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 968327a1024..67c52dc8fee 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -110,7 +110,7 @@ "óÔÏ×ÂÅÃØ BLOB '%-.64s' ÎÅ ÍÏÖÅ ÍÁÔÉ ÚÎÁÞÅÎÎÑ ÐÏ ÚÁÍÏ×ÞÕ×ÁÎÎÀ", "îÅצÒÎÅ ¦Í'Ñ ÂÁÚÉ ÄÁÎÎÉÈ '%-.100s'", "îÅצÒÎÅ ¦Í'Ñ ÔÁÂÌÉæ '%-.100s'", -"úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET OPTION SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ", +"úÁÐÉÔÕ SELECT ÐÏÔÒ¦ÂÎÏ ÏÂÒÏÂÉÔÉ ÂÁÇÁÔÏ ÚÁÐÉÓ¦×, ÝÏ, ÐÅ×ÎÅ, ÚÁÊÍÅ ÄÕÖÅ ÂÁÇÁÔÏ ÞÁÓÕ. ðÅÒÅצÒÔÅ ×ÁÛÅ WHERE ÔÁ ×ÉËÏÒÉÓÔÏ×ÕÊÔÅ SET SQL_BIG_SELECTS=1, ÑËÝÏ ÃÅÊ ÚÁÐÉÔ SELECT ¤ צÒÎÉÍ", "îÅצÄÏÍÁ ÐÏÍÉÌËÁ", "îÅצÄÏÍÁ ÐÒÏÃÅÄÕÒÁ '%-.64s'", "èÉÂÎÁ ˦ÌØ˦ÓÔØ ÐÁÒÁÍÅÔÒ¦× ÐÒÏÃÅÄÕÒÉ '%-.64s'", diff --git a/sql/slave.cc b/sql/slave.cc index eae795ae760..22c47bbdd05 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -20,12 +20,12 @@ #include <mysql.h> #include <myisam.h> -#include "mini_client.h" #include "slave.h" #include "sql_repl.h" #include "repl_failsafe.h" #include <thr_alarm.h> #include <my_dir.h> +#include <sql_common.h> bool use_slave_mask = 0; MY_BITMAP slave_error_mask; @@ -1164,15 +1164,15 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, if (!called_connected) { - if (!(mysql = mc_mysql_init(NULL))) + if (!(mysql = mysql_init(NULL))) { send_error(thd); // EOM DBUG_RETURN(1); } if (connect_to_master(thd, mysql, mi)) { - net_printf(thd, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql)); - mc_mysql_close(mysql); + net_printf(thd, ER_CONNECT_TO_MASTER, mysql_error(mysql)); + mysql_close(mysql); DBUG_RETURN(1); } if (thd->killed) @@ -1193,7 +1193,7 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, err: thd->net.no_send_ok = 0; // Clear up garbage after create_table_from_dump if (!called_connected) - mc_mysql_close(mysql); + mysql_close(mysql); if (errmsg && thd->net.vio) send_error(thd, error, errmsg); DBUG_RETURN(test(error)); // Return 1 on error @@ -1560,12 +1560,12 @@ int register_slave_on_master(MYSQL* mysql) /* The master will fill in master_id */ int4store(pos, 0); pos+= 4; - if (mc_simple_command(mysql, COM_REGISTER_SLAVE, (char*) buf, + if (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)); + mysql_errno(mysql), + mysql_error(mysql)); return 1; } return 0; @@ -1959,18 +1959,18 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi, int4store(buf + 6, server_id); len = (uint) strlen(logname); memcpy(buf + 10, logname,len); - if (mc_simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1)) + if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1)) { /* Something went wrong, so we will just reconnect and retry later in the future, we should do a better error analysis, but for now we just fill up the error log :-) */ - if (mc_mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) + if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) *suppress_warnings= 1; // Suppress reconnect warning else sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs", - mc_mysql_errno(mysql), mc_mysql_error(mysql), + mysql_errno(mysql), mysql_error(mysql), master_connect_retry); DBUG_RETURN(1); } @@ -1997,7 +1997,7 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table) *p++ = table_len; memcpy(p, table, table_len); - if (mc_simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1)) + if (simple_command(mysql, COM_TABLE_DUMP, buf, p - buf + table_len, 1)) { sql_print_error("request_table_dump: Error sending the table dump \ command"); @@ -2041,10 +2041,10 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) return packet_error; #endif - len = mc_net_safe_read(mysql); + len = net_safe_read(mysql); if (len == packet_error || (long) len < 1) { - if (mc_mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) + if (mysql_errno(mysql) == ER_NET_READ_INTERRUPTED) { /* We are trying a normal reconnect after a read timeout; @@ -2056,7 +2056,7 @@ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) else sql_print_error("Error reading packet from server: %s (\ server_errno=%d)", - mc_mysql_error(mysql), mc_mysql_errno(mysql)); + mysql_error(mysql), mysql_errno(mysql)); return packet_error; } @@ -2064,7 +2064,7 @@ server_errno=%d)", { sql_print_error("Slave: received 0 length packet from server, apparent\ master shutdown: %s", - mc_mysql_error(mysql)); + mysql_error(mysql)); return packet_error; } @@ -2214,7 +2214,7 @@ slave_begin: mi->master_log_name, llstr(mi->master_log_pos,llbuff))); - if (!(mi->mysql = mysql = mc_mysql_init(NULL))) + if (!(mi->mysql = mysql = mysql_init(NULL))) { sql_print_error("Slave I/O thread: error in mc_mysql_init()"); goto err; @@ -2269,7 +2269,7 @@ dump"); } thd->proc_info = "Waiiting to reconnect after a failed dump request"; - mc_end_server(mysql); + end_server(mysql); /* First time retry immediately, assuming that we can recover right away - if first time fails, sleep between re-tries @@ -2319,7 +2319,7 @@ after reconnect"); if (event_len == packet_error) { - uint mysql_error_number= mc_mysql_errno(mysql); + uint mysql_error_number= mysql_errno(mysql); if (mysql_error_number == ER_NET_PACKET_TOO_LARGE) { sql_print_error("\ @@ -2332,11 +2332,11 @@ max_allowed_packet", if (mysql_error_number == ER_MASTER_FATAL_ERROR_READING_BINLOG) { sql_print_error(ER(mysql_error_number), mysql_error_number, - mc_mysql_error(mysql)); + mysql_error(mysql)); goto err; } thd->proc_info = "Waiting to reconnect after a failed read"; - mc_end_server(mysql); + end_server(mysql); if (retry_count++) { if (retry_count > master_retry_count) @@ -2406,7 +2406,7 @@ err: VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (mysql) { - mc_mysql_close(mysql); + mysql_close(mysql); mi->mysql=0; } thd->proc_info = "Waiting for slave mutex on exit"; @@ -2429,9 +2429,7 @@ err: goto slave_begin; #endif my_thread_end(); -#ifndef __NETWARE__ pthread_exit(0); -#endif /* __NETWARE__ */ DBUG_RETURN(0); // Can't return anything here } @@ -2573,9 +2571,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ goto slave_begin; #endif my_thread_end(); -#ifndef __NETWARE__ pthread_exit(0); -#endif /* __NETWARE__ */ DBUG_RETURN(0); // Can't return anything here } @@ -2951,22 +2947,24 @@ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, client_flag=CLIENT_COMPRESS; /* We will use compression */ while (!(slave_was_killed = io_slave_killed(thd,mi)) && - (reconnect ? mc_mysql_reconnect(mysql) != 0: - !mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0, - mi->port, 0, client_flag, - thd->variables.net_read_timeout))) + (reconnect ? mysql_reconnect(mysql) != 0: + !(mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, + (char *)&thd->variables.net_read_timeout), + mysql_options(mysql, MYSQL_SET_CHARSET_NAME, (char *)default_charset_info), + mysql_real_connect(mysql, mi->host, mi->user, mi->password, 0, + mi->port, 0, client_flag)))) { /* Don't repeat last error */ - if (mc_mysql_errno(mysql) != last_errno) + if ((int)mysql_errno(mysql) != last_errno) { - last_errno=mc_mysql_errno(mysql); + last_errno=mysql_errno(mysql); suppress_warnings= 0; sql_print_error("Slave I/O thread: error %s to master \ '%s@%s:%d': \ Error: '%s' errno: %d retry-time: %d retries: %d", (reconnect ? "reconnecting" : "connecting"), mi->user,mi->host,mi->port, - mc_mysql_error(mysql), last_errno, + mysql_error(mysql), last_errno, mi->connect_retry, master_retry_count); } diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index b6191b2061e..ec6db64ea73 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -70,7 +70,7 @@ static ACL_USER *find_acl_user(const char *host, const char *user); static bool update_user_table(THD *thd, const char *host, const char *user, const char *new_password); static void update_hostname(acl_host_and_ip *host, const char *hostname); -static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, +static bool compare_hostname(const acl_host_and_ip *host,const char *hostname, const char *ip); /* @@ -496,8 +496,9 @@ void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble) 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, char *prepared_scramble, - uint *cur_priv_version, ACL_USER **cached_user) + char *priv_host, 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; @@ -593,7 +594,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, { Vio *vio=thd->net.vio; /* - In this point we know that user is allowed to connect + At 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 @@ -611,8 +612,11 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, /* Connections with non-valid certificates are dropped already in sslaccept() anyway, so we do not check validity here. + + We need to check for absence of SSL because without SSL + we should reject connection. */ - if (SSL_get_peer_certificate(vio->ssl_)) + if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_)) user_access=acl_user->access; break; case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */ @@ -622,6 +626,8 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, If cipher name is specified, we compare it to actual cipher in use. */ + if (vio_type(vio) != VIO_TYPE_SSL) + break; if (acl_user->ssl_cipher) { DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'", @@ -630,6 +636,10 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, user_access=acl_user->access; else { + if (global_system_variables.log_warnings) + sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'", + acl_user->ssl_cipher, + SSL_get_cipher(vio->ssl_)); user_access=NO_ACCESS; break; } @@ -647,6 +657,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, acl_user->x509_issuer, ptr)); if (strcmp(acl_user->x509_issuer, ptr)) { + if (global_system_variables.log_warnings) + sql_print_error("X509 issuer mismatch: should be '%s' but is '%s'", + acl_user->x509_issuer, ptr); user_access=NO_ACCESS; free(ptr); break; @@ -662,7 +675,12 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, DBUG_PRINT("info",("comparing subjects: '%s' and '%s'", acl_user->x509_subject, ptr)); if (strcmp(acl_user->x509_subject,ptr)) + { + if (global_system_variables.log_warnings) + sql_print_error("X509 subject mismatch: '%s' vs '%s'", + acl_user->x509_subject, ptr); user_access=NO_ACCESS; + } else user_access=acl_user->access; free(ptr); @@ -677,6 +695,11 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, if (!acl_user->user) *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */ + if (acl_user->host.hostname) + strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME); + else + *priv_host= 0; + unlock_and_exit: VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(user_access); @@ -780,7 +803,7 @@ static void acl_insert_user(const char *user, const char *host, VOID(push_dynamic(&acl_users,(gptr) &acl_user)); if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]) - allow_all_hosts=1; // Anyone can connect /* purecov: tested */ + allow_all_hosts=1; // Anyone can connect /* purecov: tested */ qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements, sizeof(ACL_USER),(qsort_cmp) acl_compare); @@ -1126,8 +1149,7 @@ bool change_password(THD *thd, const char *host, const char *user, Simple hack to avoid cracking */ length=(uint) strlen(new_password); - - if (length!=45) + if (length != 45) new_password[length & 16]=0; VOID(pthread_mutex_lock(&acl_cache->lock)); @@ -2060,10 +2082,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } -int mysql_table_grant (THD *thd, TABLE_LIST *table_list, - List <LEX_USER> &user_list, - List <LEX_COLUMN> &columns, ulong rights, - bool revoke_grant) +int mysql_table_grant(THD *thd, TABLE_LIST *table_list, + List <LEX_USER> &user_list, + List <LEX_COLUMN> &columns, ulong rights, + bool revoke_grant) { ulong column_priv = 0; List_iterator <LEX_USER> str_list (user_list); @@ -2437,7 +2459,7 @@ my_bool grant_init(THD *org_thd) 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 */ + grant_option= FALSE; /* purecov: deadcode */ goto end_unlock; } } @@ -2477,16 +2499,16 @@ void grant_reload(THD *thd) rw_wrlock(&LOCK_grant); grant_version++; old_column_priv_hash= column_priv_hash; - old_grant_option = grant_option; - old_mem = memex; + 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 */ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ - grant_option = old_grant_option; /* purecov: deadcode */ - memex = old_mem; /* purecov: deadcode */ + grant_option= old_grant_option; /* purecov: deadcode */ + memex= old_mem; /* purecov: deadcode */ } else { @@ -2583,8 +2605,8 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, } -bool check_grant_column (THD *thd,TABLE *table, const char *name, - uint length, uint show_tables) +bool check_grant_column(THD *thd,TABLE *table, const char *name, + uint length, uint show_tables) { GRANT_TABLE *grant_table; GRANT_COLUMN *grant_column; @@ -2650,7 +2672,12 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) want_access &= ~table->grant.privilege; if (!want_access) - return 0; // Already checked + return 0; // Already checked + if (!grant_option) + { + field= table->field[0]; // To give a meaningful error message + goto err2; + } rw_rdlock(&LOCK_grant); @@ -2679,9 +2706,9 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) return 0; /* We must use my_printf_error() here! */ - err: +err: rw_unlock(&LOCK_grant); - +err2: const char *command=""; if (want_access & SELECT_ACL) command ="select"; @@ -3108,11 +3135,11 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) } } } - global.append(" ON ",4); + global.append(" ON `",5); global.append(grant_table->db); - global.append(".",1); + global.append("`.`",3); global.append(grant_table->tname); - global.append(" TO '",5); + global.append("` TO '",6); global.append(lex_user->user.str,lex_user->user.length); global.append("'@'",3); global.append(lex_user->host.str,lex_user->host.length); diff --git a/sql/sql_acl.h b/sql/sql_acl.h index ceb866d809f..d85a281cbb5 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -136,7 +136,8 @@ void acl_free(bool end=0); ulong acl_get(const char *host, const char *ip, const char *bin_ip, const char *user, const char *db); ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, - const char *password,const char *scramble,char **priv_user, + const char *password,const char *scramble, + char **priv_user, char *priv_host, bool old_ver, USER_RESOURCES *max,char* prepared_scramble, uint *cur_priv_version, ACL_USER **cached_user); bool acl_check_host(const char *host, const char *ip); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fc95f5deb40..81c620fdaf4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -423,8 +423,9 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) { DBUG_ENTER("close_thread_table"); - bool found_old_table=0; - TABLE *table=*table_ptr; + bool found_old_table= 0; + TABLE *table= *table_ptr; + DBUG_ASSERT(table->key_read == 0); *table_ptr=table->next; if (table->version != refresh_version || @@ -1693,7 +1694,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, else thd->dupp_field=field; } - if (check_grants && check_grant_column(thd,table,name,length)) + if (check_grants && check_grant_column(thd,table,name,length)) return WRONG_GRANT; return field; } @@ -1743,8 +1744,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, { found_table=1; Field *find=find_field_in_table(thd,tables->table,name,length, - grant_option && - tables->table->grant.want_privilege, + test(tables->table->grant. + want_privilege), 1); if (find) { @@ -1801,8 +1802,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, } Field *field=find_field_in_table(thd,tables->table,name,length, - grant_option && - tables->table->grant.want_privilege, + test(tables->table->grant.want_privilege), allow_rowid); if (field) { @@ -2098,9 +2098,10 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, (!db_name || !strcmp(tables->db,db_name)))) { /* Ensure that we have access right to all columns */ - if (grant_option && !thd->master_access && - check_grant_all_columns(thd,SELECT_ACL,table) ) + if (!(table->grant.privilege & SELECT_ACL) && + check_grant_all_columns(thd,SELECT_ACL,table)) DBUG_RETURN(-1); + Field **ptr=table->field,*field; thd->used_tables|=table->map; while ((field = *ptr++)) @@ -2227,7 +2228,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ******************************************************************************/ int -fill_record(List<Item> &fields,List<Item> &values) +fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors) { List_iterator_fast<Item> f(fields),v(values); Item *value; @@ -2237,7 +2238,7 @@ fill_record(List<Item> &fields,List<Item> &values) while ((field=(Item_field*) f++)) { value=v++; - if (value->save_in_field(field->field, 0) > 0) + if (value->save_in_field(field->field, 0) > 0 && !ignore_errors) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2245,7 +2246,7 @@ fill_record(List<Item> &fields,List<Item> &values) int -fill_record(Field **ptr,List<Item> &values) +fill_record(Field **ptr,List<Item> &values, bool ignore_errors) { List_iterator_fast<Item> v(values); Item *value; @@ -2255,7 +2256,7 @@ fill_record(Field **ptr,List<Item> &values) while ((field = *ptr++)) { value=v++; - if (value->save_in_field(field, 0) == 1) + if (value->save_in_field(field, 0) == 1 && !ignore_errors) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2310,7 +2311,7 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) DBUG_ENTER("mysql_create_index"); bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; - create_info.table_charset= thd->db_charset; + create_info.table_charset= thd->variables.character_set_database; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, fields, keys, drop, alter, 0, (ORDER*)0, FALSE, @@ -2327,7 +2328,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop) DBUG_ENTER("mysql_drop_index"); bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; - create_info.table_charset= thd->db_charset; + create_info.table_charset= thd->variables.character_set_database; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, fields, keys, drop, alter, 0, (ORDER*)0, FALSE, diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index d8265a1b359..adc3d177fdf 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -761,11 +761,11 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) uint8 tables_type= 0; if ((local_tables = is_cacheable(thd, thd->query_length, - thd->query, &thd->lex, tables_used, - &tables_type))) + thd->query, &thd->lex, tables_used, + &tables_type))) { NET *net= &thd->net; - byte flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); + byte flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); STRUCT_LOCK(&structure_guard_mutex); if (query_cache_size == 0) @@ -790,8 +790,10 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) */ flags|= (byte) thd->charset()->number; DBUG_ASSERT(thd->charset()->number < 128); - tot_length=thd->query_length+thd->db_length+2; - thd->query[tot_length-1] = (char) flags; + tot_length= thd->query_length+thd->db_length+2+sizeof(ha_rows); + thd->query[tot_length-1]= (char) flags; + memcpy((void *)(thd->query + (tot_length-sizeof(ha_rows)-1)), + (const void *)&thd->variables.select_limit, sizeof(ha_rows)); /* Check if another thread is processing the same query? */ Query_cache_block *competitor = (Query_cache_block *) @@ -921,7 +923,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) } Query_cache_block *query_block; - tot_length=query_length+thd->db_length+2; + tot_length= query_length+thd->db_length+2+sizeof(ha_rows); if (thd->db_length) { memcpy(sql+query_length+1, thd->db, thd->db_length); @@ -937,10 +939,12 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Most significant bit - CLIENT_LONG_FLAG, Other - charset number (0 no charset convertion) */ - flags = (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); - flags |= (byte) thd->charset()->number; + flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0); + flags|= (byte) thd->charset()->number; DBUG_ASSERT(thd->charset()->number < 128); - sql[tot_length-1] = (char) flags; + sql[tot_length-1]= (char) flags; + memcpy((void *)(sql + (tot_length-sizeof(ha_rows)-1)), + (const void *)&thd->variables.select_limit, sizeof(ha_rows)); query_block = (Query_cache_block *) hash_search(&queries, (byte*) sql, tot_length); /* Quick abort on unlocked data */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f579b02ee50..fb088b602b1 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -109,7 +109,7 @@ THD::THD():user_time(0), is_fatal_error(0), file_id = 0; cond_count=0; warn_id= 0; - db_charset=default_charset_info; + db_charset= global_system_variables.character_set_database; mysys_var=0; #ifndef DBUG_OFF dbug_sentry=THD_SENTRY_MAGIC; @@ -120,6 +120,7 @@ THD::THD():user_time(0), is_fatal_error(0), net.last_error[0]=0; // If error on boot ull=0; system_thread=cleanup_done=0; + peer_port= 0; // For SHOW PROCESSLIST transaction.changed_tables = 0; #ifdef __WIN__ real_id = 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index 925afde2202..157a58cb8fa 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -358,6 +358,7 @@ struct system_variables ulong max_prep_stmt_count; ulong max_sort_length; ulong max_tmp_tables; + ulong myisam_repair_threads; ulong myisam_sort_buff_size; ulong net_buffer_length; ulong net_interactive_timeout; @@ -385,9 +386,11 @@ struct system_variables my_bool low_priority_updates; my_bool new_mode; - CHARSET_INFO *collation_client; + CHARSET_INFO *character_set_server; + CHARSET_INFO *character_set_database; + CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_results; CHARSET_INFO *collation_connection; - CHARSET_INFO *collation_results; }; void free_tmp_table(THD *thd, TABLE *entry); @@ -434,13 +437,14 @@ public: ip - client IP */ char *host,*user,*priv_user,*db,*ip; + char priv_host[MAX_HOSTNAME]; /* remote (peer) port */ uint16 peer_port; /* Points to info-string that will show in SHOW PROCESSLIST */ const char *proc_info; /* points to host if host is available, otherwise points to ip */ const char *host_or_ip; - + ulong client_capabilities; /* What the client supports */ /* Determines if which non-standard SQL behaviour should be enabled */ ulong max_client_packet_length; @@ -512,6 +516,7 @@ public: ulong query_id, warn_id, version, options, thread_id, col_access; ulong current_stmt_id; ulong rand_saved_seed1, rand_saved_seed2; + ulong row_count; // Row counter, mainly for errors and warnings long dbug_thread_id; pthread_t real_id; uint current_tablenr,tmp_table,cond_count; @@ -530,6 +535,7 @@ public: uint8 query_cache_type; // type of query cache processing bool slave_thread; bool set_query_id,locked,count_cuted_fields,some_tables_deleted; + bool last_cuted_field; 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; @@ -668,7 +674,7 @@ public: net.report_error= 1; DBUG_PRINT("error",("Fatal error set")); } - inline CHARSET_INFO *charset() { return variables.collation_client; } + inline CHARSET_INFO *charset() { return variables.character_set_client; } }; /* diff --git a/sql/sql_db.cc b/sql/sql_db.cc index fe8a945bff8..f8cf1eee0c5 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -51,7 +51,7 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, 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) +static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) { register File file; char buf[256]; // Should be enough for one option @@ -61,8 +61,9 @@ static bool write_db_opt(const char *path, HA_CREATE_INFO *create) { 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)); + create->table_charset : + thd->variables.character_set_database; + length= my_sprintf(buf,(buf, "default-character-set=%s\ndefault-collation=%s\n", cs->csname,cs->name)); /* Error is written by my_write */ if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME))) @@ -89,7 +90,7 @@ static bool write_db_opt(const char *path, HA_CREATE_INFO *create) */ -static bool load_db_opt(const char *path, HA_CREATE_INFO *create) +static bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create) { File file; char buf[256]; @@ -98,7 +99,7 @@ static bool load_db_opt(const char *path, HA_CREATE_INFO *create) uint nbytes; bzero((char*) create,sizeof(*create)); - create->table_charset= default_charset_info; + create->table_charset= global_system_variables.character_set_database; if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0) { IO_CACHE cache; @@ -115,12 +116,18 @@ static bool load_db_opt(const char *path, HA_CREATE_INFO *create) { if (!strncmp(buf,"default-character-set", (pos-buf))) { - if (strcmp(pos+1,"DEFAULT")) + if (!(create->table_charset=get_charset_by_csname(pos+1, + MY_CS_PRIMARY, + MYF(0)))) { - if (!(create->table_charset=get_charset_by_name(pos+1, MYF(0)))) - { - sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); - } + sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); + } + } + else if (!strncmp(buf,"default-collation", (pos-buf))) + { + if (!(create->table_charset=get_charset_by_name(pos+1, MYF(0)))) + { + sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1); } } } @@ -197,7 +204,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, unpack_dirname(path, path); strcat(path,MY_DB_OPT_FILE); - if (write_db_opt(path, create_info)) + if (write_db_opt(thd, path, create_info)) { /* Could not create options file. @@ -270,7 +277,7 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) /* 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))) + if ((error=write_db_opt(thd, path, create_info))) goto exit; /* @@ -280,7 +287,9 @@ int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) if (thd->db && !strcmp(thd->db,db)) { thd->db_charset= (create_info && create_info->table_charset) ? - create_info->table_charset : default_charset_info; + create_info->table_charset : + global_system_variables.character_set_database; + thd->variables.character_set_database= thd->db_charset; } mysql_update_log.write(thd,thd->query, thd->query_length); @@ -401,6 +410,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, ulong found_other_files=0; char filePath[FN_REFLEN]; TABLE_LIST *tot_list=0, **tot_list_next; + List<String> raid_dirs; + DBUG_ENTER("mysql_rm_known_files"); DBUG_PRINT("enter",("path: %s", org_path)); @@ -420,6 +431,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, { char newpath[FN_REFLEN]; MY_DIR *new_dirp; + String *dir; + strxmov(newpath,org_path,"/",file->name,NullS); unpack_filename(newpath,newpath); if ((new_dirp = my_dir(newpath,MYF(MY_DONT_SORT)))) @@ -430,7 +443,11 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, my_dirend(dirp); DBUG_RETURN(-1); } + raid_dirs.push_back(dir=new String(newpath, &my_charset_latin1)); + dir->copy(); + continue; } + found_other_files++; continue; } if (find_type(fn_ext(file->name),&deletable_extentions,1+2) <= 0) @@ -440,7 +457,7 @@ 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(&my_charset_latin1, + if (db && !my_strcasecmp(&my_charset_latin1, fn_ext(file->name), reg_ext)) { /* Drop the table nicely */ @@ -470,12 +487,19 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, deleted++; } } - my_dirend(dirp); - if (thd->killed || (tot_list && mysql_rm_table_part2_with_lock(thd, tot_list, 1, 0, 1))) + { + my_dirend(dirp); DBUG_RETURN(-1); - + } + List_iterator<String> it(raid_dirs); + String *dir; + while ((dir= it++)) + if (rmdir(dir->c_ptr()) < 0) + found_other_files++; + my_dirend(dirp); + /* If the directory is a symbolic link, remove the link first, then remove the directory the symbolic link pointed at @@ -573,11 +597,11 @@ bool mysql_change_db(THD *thd, const char *name) { net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, - thd->host_or_ip, + thd->priv_host, dbname); mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), thd->priv_user, - thd->host_or_ip, + thd->priv_host, dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); @@ -600,8 +624,11 @@ bool mysql_change_db(THD *thd, const char *name) 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; + load_db_opt(thd, path, &create); + thd->db_charset= create.table_charset ? + create.table_charset : + global_system_variables.character_set_database; + thd->variables.character_set_database= thd->db_charset; DBUG_RETURN(0); } @@ -659,7 +686,7 @@ int mysqld_show_create_db(THD *thd, char *dbname, if (found_libchar) path[length-1]= FN_LIBCHAR; strmov(path+length, MY_DB_OPT_FILE); - load_db_opt(path, &create); + load_db_opt(thd, path, &create); List<Item> field_list; field_list.push_back(new Item_empty_string("Database",NAME_LEN)); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 6bb336a87a6..ebb09b99df7 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -67,7 +67,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, } /* Test if the user wants to delete all rows */ - if (!using_limit && const_cond && + if (!using_limit && const_cond && (!conds || conds->val_int()) && !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE))) { deleted= table->file->records; @@ -178,6 +178,15 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, (void) table->file->extra(HA_EXTRA_NORMAL); cleanup: + /* + Invalidate the table in the query cache if something changed. This must + be before binlog writing and ha_autocommit_... + */ + if (deleted) + { + query_cache_invalidate3(thd, table_list, 1); + } + transactional_table= table->file->has_transactions(); log_delayed= (transactional_table || table->tmp_table); if (deleted && (error <= 0 || !transactional_table)) @@ -199,14 +208,6 @@ cleanup: error=1; } - /* - Store table for future invalidation or invalidate it in - the query cache if something changed - */ - if (deleted) - { - query_cache_invalidate3(thd, table_list, 1); - } if (thd->lock) { mysql_unlock_tables(thd, thd->lock); @@ -480,6 +481,12 @@ bool multi_delete::send_eof() /* reset used flags */ thd->proc_info="end"; + /* + We must invalidate the query cache before binlog writing and + ha_autocommit_... + */ + if (deleted) + query_cache_invalidate3(thd, delete_tables, 1); /* Write the SQL statement to the binlog if we deleted @@ -504,9 +511,6 @@ bool multi_delete::send_eof() if (transactional_tables) if (ha_autocommit_or_rollback(thd,local_error > 0)) local_error=1; - - if (deleted) - query_cache_invalidate3(thd, delete_tables, 1); if (local_error) ::send_error(thd); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 7f555f37d40..2bf1a68e504 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -116,7 +116,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, 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)) + setup_wild(thd, first_table, select_cursor->item_list, 0, + select_cursor->with_wild)) { res= -1; goto exit; @@ -128,16 +129,18 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, (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)) + 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 */ + /* + 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, @@ -190,6 +193,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, org_table_list->table=table; table->derived_select_number= select_cursor->select_number; table->tmp_table= TMP_TABLE; + org_table_list->grant.privilege= SELECT_ACL; if (lex->describe) { // to fix a problem in EXPLAIN @@ -206,7 +210,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, /* 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 + // Force read of table stats in the optimizer table->file->info(HA_STATUS_VARIABLE); } } diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 3b9c329d5e5..db0dbe0dedc 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -79,6 +79,7 @@ void mysql_reset_errors(THD *thd) free_root(&thd->warn_root,MYF(0)); bzero((char*) thd->warn_count, sizeof(thd->warn_count)); thd->warn_list.empty(); + thd->row_count= 1; // by default point to row 1 } DBUG_VOID_RETURN; } diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 36c7ef87b17..2925141d331 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -26,74 +26,155 @@ struct st_find_field 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} + { "help_topic", "help_topic_id", 0}, + { "help_topic", "name", 0}, + { "help_topic", "help_category_id", 0}, + { "help_topic", "description", 0}, + { "help_topic", "example", 0}, + + { "help_category", "help_category_id", 0}, + { "help_category", "parent_category_id", 0}, + { "help_category", "name", 0}, + + { "help_keyword", "help_keyword_id", 0}, + { "help_keyword", "name", 0}, + + { "help_relation", "help_topic_id", 0}, + { "help_relation", "help_keyword_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 + help_topic_help_topic_id= 0, + help_topic_name, + help_topic_help_category_id, + help_topic_description, + help_topic_example, + + help_category_help_category_id, + help_category_parent_category_id, + help_category_name, + + help_keyword_help_keyword_id, + help_keyword_name, + + help_relation_help_topic_id, + help_relation_help_keyword_id }; /* - Fill local used field structure with pointer to fields */ + Fill st_find_field structure with pointers to fields + + SYNOPSIS + init_fields() + thd Thread handler + tables list of all tables for fields + find_fields array of structures + count size of previous array + + RETURN VALUES + 0 all ok + 1 one of the fileds didn't finded +*/ static bool init_fields(THD *thd, TABLE_LIST *tables, - struct st_find_field *find_field, - uint count) + struct st_find_field *find_fields, uint count) { - for (; count-- ; find_field++) + DBUG_ENTER("init_fields"); + for (; count-- ; find_fields++) { 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, - ¬_used, - TRUE))) - return 1; + Item_field *field= new Item_field("mysql", find_fields->table_name, + find_fields->field_name); + if (!(find_fields->field= find_field_in_tables(thd, field, tables, + ¬_used, TRUE))) + DBUG_RETURN(1); } - return 0; + DBUG_RETURN(0); } +/* + + Returns variants of found topic for help (if it is just single topic, + returns description and example, or else returns only names..) + + SYNOPSIS + memorize_variant_topic() + + thd Thread handler + topics Table of topics + count number of alredy found topics + find_fields Filled array of information for work with fields + + RETURN VALUES + names array of names of found topics (out) -#define help_charset &my_charset_latin1 + name name of found topic (out) + description description of found topic (out) + example example for found topic (out) + + NOTE + Field 'names' is set only if more than one topic is found. + Fields 'name', 'description', 'example' are set only if + found exactly one topic. +*/ + +void memorize_variant_topic(THD *thd, TABLE *topics, int count, + struct st_find_field *find_fields, + List<String> *names, + String *name, String *description, String *example) +{ + DBUG_ENTER("memorize_variant_topic"); + MEM_ROOT *mem_root= &thd->mem_root; + if (count==0) + { + get_field(mem_root,find_fields[help_topic_name].field, name); + get_field(mem_root,find_fields[help_topic_description].field, description); + get_field(mem_root,find_fields[help_topic_example].field, example); + } + else + { + if (count==1) + names->push_back(name); + String *new_name= new String; + get_field(mem_root,find_fields[help_topic_name].field,new_name); + names->push_back(new_name); + } + DBUG_VOID_RETURN; +} /* 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. + thd Thread handler + topics Table of topics + find_fields Filled array of info for fields + select Function to test for matching help topic. + Normally 'help_topic.name like 'bit%' + RETURN VALUES - # number of topics founded + # number of topics found + + names array of names of found topics (out) + name name of found topic (out) + description description of found topic (out) + example example for found topic (out) + + NOTE + Field 'names' is set only if more than one topic was found. + Fields 'name', 'description', 'example' are set only if + exactly one topic was found. + */ -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) +int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_fields, + SQL_SELECT *select, List<String> *names, + String *name, String *description, String *example) { - DBUG_ENTER("search_functions"); + DBUG_ENTER("search_topics"); int count= 0; READ_RECORD read_record_info; @@ -102,139 +183,93 @@ int search_topics(THD *thd, TABLE *topics, struct st_find_field *find_field, { if (!select->cond->val_int()) // Dosn't match like continue; - - char *lname= get_field(&thd->mem_root, find_field[help_topic_name].field); + memorize_variant_topic(thd,topics,count,find_fields, + names,name,description,example); 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 + Look for keyword 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) + search_keyword() + thd Thread handler + keywords Table of keywords + find_fields Filled array of info for fields + select Function to test for matching keyword. + Normally 'help_keyword.name like 'bit%' + + key_id help_keyword_if of found topics (out) RETURN VALUES - # Number of categories founded + 0 didn't find any topics matching the mask + 1 found exactly one topic matching the mask + 2 found more then one topic matching the mask */ -int search_categories(THD *thd, TABLE *categories, - struct st_find_field *find_fields, - SQL_SELECT *select, List<char> *names, int16 *res_id) +int search_keyword(THD *thd, TABLE *keywords, struct st_find_field *find_fields, + SQL_SELECT *select, int *key_id) { - Field *pfname= find_fields[help_category_name].field; - DBUG_ENTER("search_categories"); + DBUG_ENTER("search_keyword"); 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)) + READ_RECORD read_record_info; + init_read_record(&read_record_info, thd, keywords, select,1,0); + while (!read_record_info.read_record(&read_record_info) && count<2) { - if (select && !select->cond->val_int()) + if (!select->cond->val_int()) // Dosn't match like 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); + + *key_id= find_fields[help_keyword_help_keyword_id].field->val_int(); + + count++; } end_read_record(&read_record_info); - + DBUG_RETURN(count); } - /* - Send to client rows in format: - column1 : <name> - column2 : <is_it_category> + Look for all topics with keyword SYNOPSIS - send_variant_2_list() - protocol Protocol for sending - names List of names - cat Value of the column <is_it_category> + get_topics_for_keyword() + thd Thread handler + topics Table of topics + relations Table of m:m relation "topic/keyword" + find_fields Filled array of info for fields + key_id Primary index to use to find for keyword 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); -} + # number of topics found + names array of name of found topics (out) -/* - Look for all topics of category + name name of found topic (out) + description description of found topic (out) + example example for found topic (out) - 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 + NOTE + Field 'names' is set only if more than one topic was found. + Fields 'name', 'description', 'example' are set only if + exactly one topic was found. */ -int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations, - struct st_find_field *find_fields, - int16 cat_id, List<char> *res) +int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations, + struct st_find_field *find_fields, int16 key_id, + List<String> *names, + String *name, String *description, String *example) { - char buff[8]; // Max int length - DBUG_ENTER("get_all_topics_for_category"); - + char buff[8]; // Max int length + int count= 0; int iindex_topic, iindex_relations; - Field *rtopic_id, *rcat_id; + Field *rtopic_id, *rkey_id; + + DBUG_ENTER("get_topics_for_keyword"); if ((iindex_topic= find_type((char*) "PRIMARY", &topics->keynames, 1+2)-1)<0 || @@ -245,37 +280,156 @@ int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations, DBUG_RETURN(-1); } rtopic_id= find_fields[help_relation_help_topic_id].field; - rcat_id= find_fields[help_relation_help_category_id].field; + rkey_id= find_fields[help_relation_help_keyword_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, + rkey_id->store((longlong) key_id); + rkey_id->get_key_image(buff, rkey_id->pack_length(), rkey_id->charset(), Field::itRAW); int key_res= relations->file->index_read(relations->record[0], - (byte *)buff, rcat_id->pack_length(), + (byte *)buff, rkey_id->pack_length(), HA_READ_KEY_EXACT); - for ( ; !key_res && cat_id == (int16) rcat_id->val_int() ; + for ( ; + !key_res && key_id == (int16) rkey_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->get_key_image(topic_id_buff, field->pack_length(), field->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)); + field->pack_length(), HA_READ_KEY_EXACT)) + { + memorize_variant_topic(thd,topics,count,find_fields, + names,name,description,example); + count++; + } } - DBUG_RETURN(0); + DBUG_RETURN(count); +} + +/* + Look for topics with keyword by mask + + SYNOPSIS + search_topics_by_keyword() + thd Thread handler + keywords Table of keywords + topics Table of topics + relations Table of m:m relation "topic/keyword" + find_fields Filled array of info for fields + select Function to test for if matching help keyword. + Normally 'help_keyword.name like 'bit%' + + RETURN VALUES + # number of topics found + + names array of name of found topics (out) + + name name of found topic (out) + description description of found topic (out) + example example for found topic (out) + + NOTE + Field 'names' is set only if more than one topic was found. + Fields 'name', 'description', 'example' are set only if + exactly one topic was found. +*/ + +int search_topics_by_keyword(THD *thd, + TABLE *keywords, TABLE *topics, TABLE *relations, + struct st_find_field *find_fields, + SQL_SELECT *select, List<String> *names, + String *name, String *description, String *example) +{ + int key_id; + return search_keyword(thd,keywords,find_fields,select,&key_id)!=1 + ? 0 : get_topics_for_keyword(thd,topics,relations,find_fields,key_id, + names,name,description,example); +} + +/* + Look for categories by mask + + SYNOPSIS + search_categories() + thd THD for init_read_record + categories Table of categories + find_fields Filled array of info for fields + select Function to test for if matching help topic. + Normally 'help_vategory.name like 'bit%' + names List of found categories names (out) + res_id Primary index of found category (only if + found exactly one category) + + RETURN VALUES + # Number of categories found +*/ + +int search_categories(THD *thd, TABLE *categories, + struct st_find_field *find_fields, + SQL_SELECT *select, List<String> *names, int16 *res_id) +{ + Field *pfname= find_fields[help_category_name].field; + Field *pcat_id= find_fields[help_category_help_category_id].field; + int count= 0; + READ_RECORD read_record_info; + + DBUG_ENTER("search_categories"); + + 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; + String *lname= new String; + get_field(&thd->mem_root,pfname,lname); + if (++count == 1 && res_id) + *res_id= (int16) pcat_id->val_int(); + names->push_back(lname); + } + end_read_record(&read_record_info); + + DBUG_RETURN(count); } +/* + Look for all topics or subcategories of category + + SYNOPSIS + get_all_items_for_category() + thd Thread handler + items Table of items + pfname Field "name" in items + select "where" part of query.. + res list of finded names +*/ + +void get_all_items_for_category(THD *thd, TABLE *items, Field *pfname, + SQL_SELECT *select, List<String> *res) +{ + DBUG_ENTER("get_all_items_for_category"); + + READ_RECORD read_record_info; + init_read_record(&read_record_info, thd, items, select,1,0); + while (!read_record_info.read_record(&read_record_info)) + { + if (!select->cond->val_int()) + continue; + String *name= new String(); + get_field(&thd->mem_root,pfname,name); + res->push_back(name); + } + end_read_record(&read_record_info); + + DBUG_VOID_RETURN; +} /* Send to client answer for help request @@ -284,17 +438,16 @@ int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations, 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" + s2 - value of column "Description" + s3 - value of column "Example" IMPLEMENTATION Format used: - +----------+---------+------------+------------+ - |Name: |Category |Description |Example | - +----------+---------+------------+------------+ - |String(64)|String(1)|String(1000)|String(1000)| - +----------+---------+------------+------------+ + +----------+------------+------------+ + |name |description |example | + +----------+------------+------------+ + |String(64)|String(1000)|String(1000)| + +----------+------------+------------+ with exactly one row! RETURN VALUES @@ -303,24 +456,21 @@ int get_all_topics_for_category(THD *thd, TABLE *topics, TABLE *relations, 0 Successeful send */ -int send_answer_1(Protocol *protocol, const char *s1, const char *s2, - const char *s3, const char *s4) +int send_answer_1(Protocol *protocol, String *s1, String *s2, String *s3) { 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)); + field_list.push_back(new Item_empty_string("name",64)); + 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); + protocol->store(s1); + protocol->store(s2); + protocol->store(s3); if (protocol->write()) DBUG_RETURN(-1); DBUG_RETURN(0); @@ -332,28 +482,151 @@ int send_answer_1(Protocol *protocol, const char *s1, const char *s2, SYNOPSIS send_header_2() - protocol - protocol for sending + protocol - protocol for sending + is_it_category - need column 'source_category_name' IMPLEMENTATION - +----------+---------+ - |Name: |Category | - +----------+---------+ - |String(64)|String(1)| - +----------+---------+ + +- -+ + |+-------------------- | +----------+--------------+ + ||source_category_name | |name |is_it_category| + |+-------------------- | +----------+--------------+ + ||String(64) | |String(64)|String(1) | + |+-------------------- | +----------+--------------+ + +- -+ RETURN VALUES result of protocol->send_fields */ -int send_header_2(Protocol *protocol) +int send_header_2(Protocol *protocol, bool for_category) { - DBUG_ENTER("send_header2"); + DBUG_ENTER("send_header_2"); List<Item> field_list; - field_list.push_back(new Item_empty_string("Name",64)); - field_list.push_back(new Item_empty_string("Category",1)); + if (for_category) + field_list.push_back(new Item_empty_string("source_category_name",64)); + field_list.push_back(new Item_empty_string("name",64)); + field_list.push_back(new Item_empty_string("is_it_category",1)); DBUG_RETURN(protocol->send_fields(&field_list,1)); } +/* + strcmp for using in qsort + + SYNOPSIS + strptrcmp() + ptr1 (const void*)&str1 + ptr2 (const void*)&str2 + + RETURN VALUES + same as strcmp +*/ + +int string_ptr_cmp(const void* ptr1, const void* ptr2) +{ + String *str1= *(String**)ptr1; + String *str2= *(String**)ptr2; + return strcmp(str1->c_ptr(),str2->c_ptr()); +} + +/* + 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> + source_name name of category for all items.. + + RETURN VALUES + -1 Writing fail + 0 Data was successefully send +*/ + +int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol, + List<String> *names, + const char *cat, String *source_name) +{ + DBUG_ENTER("send_variant_2_list"); + + String **pointers= (String**)alloc_root(mem_root, + sizeof(String*)*names->elements); + String **pos= pointers; + + List_iterator<String> it(*names); + String *cur_name; + while ((*pos++= it++)); + + qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp); + + String **end= pointers + names->elements; + for (String **pos= pointers; pos!=end; pos++) + { + protocol->prepare_for_resend(); + if (source_name) + protocol->store(source_name); + protocol->store(*pos); + protocol->store(cat,1,&my_charset_latin1); + if (protocol->write()) + DBUG_RETURN(-1); + } + + DBUG_RETURN(0); +} + +/* + Prepare simple SQL_SELECT table.* WHERE <Item> + + SYNOPSIS + prepare_simple_select() + thd Thread handler + cond WHERE part of select + tables list of tables, used in WHERE + table goal table + + error code of error (out) + + RETURN VALUES + # created SQL_SELECT +*/ + +SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables, + TABLE *table, int *error) +{ + cond->fix_fields(thd, tables, &cond); // can never fail + SQL_SELECT *res= make_select(table,0,0,cond,error); + return (*error || (res && res->check_quick(0, HA_POS_ERROR))) ? 0 : res; +} + +/* + Prepare simple SQL_SELECT table.* WHERE table.name LIKE mask + + SYNOPSIS + prepare_select_for_name() + thd Thread handler + mask mask for compare with name + mlen length of mask + tables list of tables, used in WHERE + table goal table + pfname field "name" in table + + error code of error (out) + + RETURN VALUES + # created SQL_SELECT +*/ + +SQL_SELECT *prepare_select_for_name(THD *thd, const char *mask, uint mlen, + TABLE_LIST *tables, TABLE *table, + Field *pfname, int *error) +{ + Item *cond= new Item_func_like(new Item_field(pfname), + new Item_string(mask,mlen,pfname->charset()), + (char*) "\\"); + return prepare_simple_select(thd,cond,tables,table,error); +} /* Server-side function 'help' @@ -371,12 +644,13 @@ int send_header_2(Protocol *protocol) int mysqld_help(THD *thd, const char *mask) { Protocol *protocol= thd->protocol; - SQL_SELECT *select= 0, *select_cat= 0; - Item *cond_topic, *cond_cat; + SQL_SELECT *select_topics_by_name= 0, *select_keyword_by_name= 0, + *select_cat_by_name= 0, *select_topics_by_cat= 0, *select_cat_by_cat= 0, + *select_root_cats= 0; st_find_field used_fields[array_elements(init_used_fields)]; DBUG_ENTER("mysqld_help"); - TABLE_LIST tables[3]; + TABLE_LIST tables[4]; bzero((gptr)tables,sizeof(tables)); tables[0].alias= tables[0].real_name= (char*) "help_topic"; tables[0].lock_type= TL_READ; @@ -389,11 +663,17 @@ int mysqld_help(THD *thd, const char *mask) 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; + tables[2].next= &tables[3]; + tables[3].alias= tables[3].real_name= (char*) "help_keyword"; + tables[3].lock_type= TL_READ; + tables[3].db= (char*) "mysql"; + tables[3].next= 0; - List<char> function_list, categories_list; - char *name, *description, *example; + List<String> topics_list, categories_list, subcategories_list; + String name, description, example; int res, count_topics, count_categories, error; + uint mlen= strlen(mask); + MEM_ROOT *mem_root= &thd->mem_root; if (open_and_lock_tables(thd, tables)) { @@ -409,111 +689,101 @@ int mysqld_help(THD *thd, const char *mask) 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(); + for (size_t i=0; i<sizeof(tables)/sizeof(TABLE_LIST); i++) + tables[i].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))) + if (!(select_topics_by_name= + prepare_select_for_name(thd,mask,mlen,tables,tables[0].table, + used_fields[help_topic_name].field,&error)) || + !(select_cat_by_name= + prepare_select_for_name(thd,mask,mlen,tables,tables[1].table, + used_fields[help_category_name].field,&error))|| + !(select_keyword_by_name= + prepare_select_for_name(thd,mask,mlen,tables,tables[3].table, + used_fields[help_keyword_name].field,&error))) { res= -1; goto end; } res= 1; - count_topics= search_topics(thd,tables[0].table, used_fields, select, - &function_list, &name, &description, &example); + count_topics= search_topics(thd,tables[0].table,used_fields, + select_topics_by_name,&topics_list, + &name, &description, &example); + + if (count_topics == 0) + count_topics= search_topics_by_keyword(thd,tables[3].table,tables[0].table, + tables[2].table,used_fields, + select_keyword_by_name,&topics_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 - + Field *cat_cat_id= used_fields[help_category_parent_category_id].field; count_categories= search_categories(thd, tables[1].table, used_fields, - select_cat, &categories_list, - &category_id); - if (count_categories == 1) + select_cat_by_name, + &categories_list,&category_id); + if (!count_categories) { - if (get_all_topics_for_category(thd,tables[0].table, - tables[2].table, used_fields, - category_id, &function_list)) - { - res= -1; + if (send_header_2(protocol,false)) 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()))) + } + else if (count_categories > 1) + { + if (send_header_2(protocol,false) || + send_variant_2_list(mem_root,protocol,&categories_list,"Y",0)) goto end; } - else + else { - if (send_header_2(protocol)) + Field *topic_cat_id= used_fields[help_topic_help_category_id].field; + Item *cond_topic_by_cat= new Item_func_equal(new Item_field(topic_cat_id), + new Item_int(category_id)); + Item *cond_cat_by_cat= new Item_func_equal(new Item_field(cat_cat_id), + new Item_int(category_id)); + if (!(select_topics_by_cat= prepare_simple_select(thd,cond_topic_by_cat, + tables,tables[0].table, + &error)) || + !(select_cat_by_cat= prepare_simple_select(thd,cond_cat_by_cat,tables, + tables[1].table,&error))) + { + res= -1; 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")) + } + get_all_items_for_category(thd,tables[0].table, + used_fields[help_topic_name].field, + select_topics_by_cat,&topics_list); + get_all_items_for_category(thd,tables[1].table, + used_fields[help_category_name].field, + select_cat_by_cat,&subcategories_list); + String *cat= categories_list.head(); + if (send_header_2(protocol, true) || + send_variant_2_list(mem_root,protocol,&topics_list, "N",cat) || + send_variant_2_list(mem_root,protocol,&subcategories_list,"Y",cat)) goto end; } } else if (count_topics == 1) { - if (send_answer_1(protocol,name,"N",description, example)) + if (send_answer_1(protocol,&name,&description,&example)) goto end; } else { /* First send header and functions */ - if (send_header_2(protocol) || - send_variant_2_list(protocol, &function_list, "N")) + if (send_header_2(protocol, false) || + send_variant_2_list(mem_root,protocol, &topics_list, "N", 0)) goto end; - search_categories(thd, tables[1].table, used_fields, select_cat, - &categories_list, 0); + search_categories(thd, tables[1].table, used_fields, + select_cat_by_name,&categories_list, 0); /* Then send categories */ - if (send_variant_2_list(protocol, &categories_list, "Y")) + if (send_variant_2_list(mem_root,protocol, &categories_list, "Y", 0)) 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 7418140517c..1908f898a27 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -258,7 +258,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, if (fields.elements || !value_count) { restore_record(table,default_values); // Get empty record - if (fill_record(fields,*values)|| thd->net.report_error || + if (fill_record(fields, *values, 0)|| thd->net.report_error || check_null_fields(thd,table)) { if (values_list.elements != 1 && !thd->net.report_error) @@ -276,7 +276,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, restore_record(table,default_values); // Get empty record else table->record[0][0]=table->default_values[0]; // Fix delete marker - if (fill_record(table->field,*values) || thd->net.report_error) + if (fill_record(table->field,*values, 0) || thd->net.report_error) { if (values_list.elements != 1 && ! thd->net.report_error) { @@ -306,6 +306,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, { // Get auto increment value id= thd->last_insert_id; } + thd->row_count++; } if (lock_type == TL_WRITE_DELAYED) { @@ -343,7 +344,16 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, else if (table->next_number_field) id=table->next_number_field->val_int(); // Return auto_increment value + /* + Invalidate the table in the query cache if something changed. + For the transactional algorithm to work the invalidation must be + before binlog writing and ha_autocommit_... + */ + if (info.copied || info.deleted) + query_cache_invalidate3(thd, table_list, 1); + transactional_table= table->file->has_transactions(); + log_delayed= (transactional_table || table->tmp_table); if ((info.copied || info.deleted) && (error <= 0 || !transactional_table)) { @@ -361,14 +371,6 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, if (transactional_table) error=ha_autocommit_or_rollback(thd,error); - /* - Store table for future invalidation or invalidate it in - the query cache if something changed - */ - if (info.copied || info.deleted) - { - query_cache_invalidate3(thd, table_list, 1); - } if (thd->lock) { mysql_unlock_tables(thd, thd->lock); @@ -483,7 +485,8 @@ int write_record(TABLE *table,COPY_INFO *info) key_copy((byte*) key,table,key_nr,0); if ((error=(table->file->index_read_idx(table->record[1],key_nr, (byte*) key, - table->key_info[key_nr].key_length, + table->key_info[key_nr]. + key_length, HA_READ_KEY_EXACT)))) goto err; } @@ -495,7 +498,7 @@ int write_record(TABLE *table,COPY_INFO *info) */ store_record(table,insert_values); restore_record(table,record[1]); - if (fill_record(*info->update_fields,*info->update_values)) + if (fill_record(*info->update_fields, *info->update_values, 0)) goto err; if ((error=table->file->update_row(table->record[1],table->record[0]))) goto err; @@ -506,10 +509,11 @@ int write_record(TABLE *table,COPY_INFO *info) { if (last_uniq_key(table,key_nr)) { - if ((error=table->file->update_row(table->record[1],table->record[0]))) + if ((error=table->file->update_row(table->record[1], + table->record[0]))) goto err; info->deleted++; - break; /* Update logfile and count */ + break; /* Update logfile and count */ } else if ((error=table->file->delete_row(table->record[1]))) goto err; @@ -708,6 +712,9 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) /* no match; create a new thread to handle the table */ if (!(tmp=find_handler(thd,table_list))) { + /* Don't create more than max_insert_delayed_threads */ + if (delayed_insert_threads >= max_insert_delayed_threads) + DBUG_RETURN(0); thd->proc_info="Creating delayed handler"; pthread_mutex_lock(&LOCK_delayed_create); if (!(tmp=find_handler(thd,table_list))) // Was just created @@ -1086,12 +1093,12 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) while (!thd->killed) { int error; -#if (defined(HAVE_BROKEN_COND_TIMEDWAIT) || defined(HAVE_LINUXTHREADS)) +#if defined(HAVE_BROKEN_COND_TIMEDWAIT) error=pthread_cond_wait(&di->cond,&di->mutex); #else error=pthread_cond_timedwait(&di->cond,&di->mutex,&abstime); #ifdef EXTRA_DEBUG - if (error && error != EINTR) + if (error && error != EINTR && error != ETIMEDOUT) { fprintf(stderr, "Got error %d from pthread_cond_timedwait\n",error); DBUG_PRINT("error",("Got error %d from pthread_cond_timedwait", @@ -1393,9 +1400,9 @@ bool select_insert::send_data(List<Item> &values) return 0; } if (fields->elements) - fill_record(*fields,values); + fill_record(*fields, values, 1); else - fill_record(table->field,values); + fill_record(table->field, values, 1); if (thd->net.report_error || write_record(table,&info)) return 1; if (table->next_number_field) // Clear for next record @@ -1414,11 +1421,9 @@ void select_insert::send_error(uint errcode,const char *err) ::send_error(thd,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); - ha_rollback_stmt(thd); if (info.copied || info.deleted) - { query_cache_invalidate3(thd, table, 1); - } + ha_rollback_stmt(thd); } @@ -1429,6 +1434,14 @@ bool select_insert::send_eof() error=table->file->activate_all_index(thd); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); + /* + We must invalidate the table in the query cache before binlog writing + and ha_autocommit_... + */ + + if (info.copied || info.deleted) + query_cache_invalidate3(thd, table, 1); + /* Write to binlog before commiting transaction */ if (mysql_bin_log.is_open()) { @@ -1438,10 +1451,6 @@ bool select_insert::send_eof() } if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error) error=error2; - if (info.copied || info.deleted) - { - query_cache_invalidate3(thd, table, 1); - } if (error) { table->file->print_error(error,MYF(0)); @@ -1460,7 +1469,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,info.copied,last_insert_id,buff); + ::send_ok(thd,info.copied+info.deleted,last_insert_id,buff); mysql_update_log.write(thd,thd->query,thd->query_length); return 0; } @@ -1510,7 +1519,7 @@ bool select_create::send_data(List<Item> &values) unit->offset_limit_cnt--; return 0; } - fill_record(field,values); + fill_record(field, values, 1); 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_list.h b/sql/sql_list.h index f4cca627515..ff21663576a 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.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 @@ -368,6 +368,7 @@ template <class T> class I_List :private base_ilist { public: I_List() :base_ilist() {} + inline void empty() { base_ilist::empty(); } inline bool is_empty() { return base_ilist::is_empty(); } inline void append(T* a) { base_ilist::append(a); } inline void push_back(T* a) { base_ilist::push_back(a); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index a68eada0025..12acfb9b5df 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -185,7 +185,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { unpack_filename(name,ex->file_name); -#if !defined(__WIN__) && !defined(OS2) +#if !defined(__WIN__) && !defined(OS2) && ! defined(__NETWARE__) MY_STAT stat_info; if (!my_stat(name,&stat_info,MYF(MY_WME))) DBUG_RETURN(-1); @@ -215,7 +215,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, info.handle_duplicates=handle_duplicates; info.escape_char=escaped->length() ? (*escaped)[0] : INT_MAX; - READ_INFO read_info(file,tot_length,thd->db_charset, + READ_INFO read_info(file,tot_length,thd->variables.character_set_database, *field_term,*ex->line_start, *ex->line_term, *enclosed, info.escape_char, read_file_from_client, is_fifo); if (read_info.error) @@ -283,6 +283,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table->copy_blobs=0; thd->count_cuted_fields=0; /* Don`t calc cuted fields */ + /* + We must invalidate the table in query cache before binlog writing and + ha_autocommit_... + */ + query_cache_invalidate3(thd, table_list, 0); + if (error) { if (transactional_table) @@ -344,8 +350,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } if (transactional_table) error=ha_autocommit_or_rollback(thd,error); - query_cache_invalidate3(thd, table_list, 0); - err: if (thd->lock) { @@ -370,7 +374,8 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, ulonglong id; DBUG_ENTER("read_fixed_length"); - id=0; + id= 0; + /* No fields can be null in this format. mark all fields as not null */ while ((sql_field= (Item_field*) it++)) sql_field->field->set_notnull(); @@ -389,11 +394,14 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, #endif while ((sql_field= (Item_field*) it++)) { - Field *field=sql_field->field; + Field *field= sql_field->field; if (pos == read_info.row_end) { - thd->cuted_fields++; /* Not enough fields */ - field->reset(); + thd->cuted_fields++; /* Not enough fields */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_FEW_RECORDS, + ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); + field->reset(); } else { @@ -403,14 +411,19 @@ 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,read_info.read_charset); + 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 */ } } if (pos != read_info.row_end) + { thd->cuted_fields++; /* To long row */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_MANY_RECORDS, + ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); + } if (write_record(table,&info)) DBUG_RETURN(1); /* @@ -426,7 +439,13 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, if (read_info.next_line()) // Skip to next line break; if (read_info.line_cuted) + { thd->cuted_fields++; /* To long row */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_MANY_RECORDS, + ER(ER_WARN_TOO_MANY_RECORDS), thd->row_count); + } + thd->row_count++; } if (id && !read_info.error) thd->insert_id(id); // For binary/update log @@ -447,8 +466,8 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, DBUG_ENTER("read_sep_field"); enclosed_length=enclosed.length(); - id=0; - + id= 0; + for (;;it.rewind()) { if (thd->killed) @@ -477,8 +496,9 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, { if (field->type() == FIELD_TYPE_TIMESTAMP) ((Field_timestamp*) field)->set_time(); - else if (field != table->next_number_field) - thd->cuted_fields++; + else if (field != table->next_number_field) + field->set_warning((uint)MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_NULL_TO_NOTNULL); } continue; } @@ -497,6 +517,9 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, sql_field->field->set_null(); sql_field->field->reset(); thd->cuted_fields++; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_FEW_RECORDS, + ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); } } if (write_record(table,&info)) @@ -514,7 +537,13 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, if (read_info.next_line()) // Skip to next line break; if (read_info.line_cuted) + { thd->cuted_fields++; /* To long row */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_WARN_TOO_MANY_RECORDS, ER(ER_WARN_TOO_MANY_RECORDS), + thd->row_count); + } + thd->row_count++; } if (id && !read_info.error) thd->insert_id(id); // For binary/update log diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 1d2449839d8..f098ce0d0b6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -59,6 +59,9 @@ static void refresh_status(void); static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name); +static bool single_table_command_access(THD *thd, ulong privilege, + TABLE_LIST *tables, int *res); + const char *any_db="*any*"; // Special symbol for check_access const char *command_name[]={ @@ -213,7 +216,15 @@ static int check_user(THD *thd,enum_server_command command, const char *user, thd->db=0; thd->db_length=0; USER_RESOURCES ur; + char tmp_passwd[SCRAMBLE41_LENGTH]; DBUG_ENTER("check_user"); + + /* + Move password to temporary buffer as it may be stored in communication + buffer + */ + strmake(tmp_passwd, passwd, sizeof(tmp_passwd)); + passwd= tmp_passwd; // Use local copy /* We shall avoid dupplicate user allocations here */ if (!thd->user && !(thd->user = my_strdup(user, MYF(0)))) @@ -222,7 +233,8 @@ static int check_user(THD *thd,enum_server_command command, const char *user, DBUG_RETURN(1); } thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, - passwd, thd->scramble, &thd->priv_user, + passwd, thd->scramble, + &thd->priv_user, thd->priv_host, (protocol_version == 9 || !(thd->client_capabilities & CLIENT_LONG_PASSWORD)), @@ -230,9 +242,9 @@ static int check_user(THD *thd,enum_server_command command, const char *user, cur_priv_version,hint_user); DBUG_PRINT("info", - ("Capabilities: %d packet_length: %ld Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", + ("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'", thd->client_capabilities, thd->max_client_packet_length, - thd->host_or_ip, thd->priv_user, + thd->host_or_ip, thd->user, thd->priv_user, had_password ? "yes": "no", thd->master_access, thd->db ? thd->db : "*none*")); @@ -307,6 +319,7 @@ static int check_user(THD *thd,enum_server_command command, const char *user, DBUG_RETURN(error); } send_ok(thd); // Ready to handle questions + thd->password= test(passwd[0]); // Remember for error messages DBUG_RETURN(0); // ok } @@ -582,7 +595,6 @@ check_connections(THD *thd) DBUG_PRINT("info",("Host: %s",thd->host)); thd->host_or_ip= thd->host; thd->ip= 0; - thd->peer_port= 0; bzero((char*) &thd->remote,sizeof(struct sockaddr)); } /* Ensure that wrong hostnames doesn't cause buffer overflows */ @@ -592,8 +604,8 @@ check_connections(THD *thd) { /* buff[] needs to big enough to hold the server_version variable */ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64]; - int client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | - CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); + ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | + CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION); if (opt_using_transactions) client_flags|=CLIENT_TRANSACTIONS; @@ -611,7 +623,7 @@ check_connections(THD *thd) memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1); end+=SCRAMBLE_LENGTH +1; int2store(end,client_flags); - end[2]=(char) MY_CHARSET_CURRENT; + end[2]=(char) default_charset_info->number; int2store(end+3,thd->server_status); bzero(end+5,13); end+=18; @@ -635,11 +647,38 @@ check_connections(THD *thd) return(ER_OUT_OF_RESOURCES); thd->client_capabilities=uint2korr(net->read_pos); +#ifdef TO_BE_REMOVED_IN_4_1_RELEASE + /* + This is just a safety check against any client that would use the old + CLIENT_CHANGE_USER flag + */ + if ((thd->client_capabilities & CLIENT_PROTOCOL_41) && + !(thd->client_capabilities & (CLIENT_RESERVED | + CLIENT_SECURE_CONNECTION | + CLIENT_MULTI_RESULTS))) + thd->client_capabilities&= ~CLIENT_PROTOCOL_41; +#endif 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; + if (!(thd->variables.character_set_client= + get_charset((uint) net->read_pos[8], MYF(0)))) + { + thd->variables.character_set_client= + global_system_variables.character_set_client; + thd->variables.collation_connection= + global_system_variables.collation_connection; + thd->variables.character_set_results= + global_system_variables.character_set_results; + } + else + { + thd->variables.character_set_results= + thd->variables.collation_connection= + thd->variables.character_set_client; + } + end= (char*) net->read_pos+32; } else { @@ -751,7 +790,6 @@ check_connections(THD *thd) } else if (res) return -1; // Error sent from check_user() - thd->password=using_password; return 0; } @@ -770,7 +808,7 @@ pthread_handler_decl(handle_one_connection,arg) // The following calls needs to be done before we call DBUG_ macros if (!(test_flags & TEST_NO_THREADS) & my_thread_init()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); statistic_increment(aborted_connects,&LOCK_status); end_thread(thd,0); return 0; @@ -797,7 +835,7 @@ pthread_handler_decl(handle_one_connection,arg) #endif if (thd->store_globals()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); statistic_increment(aborted_connects,&LOCK_status); end_thread(thd,0); return 0; @@ -855,7 +893,7 @@ pthread_handler_decl(handle_one_connection,arg) } end_thread: - close_connection(net); + close_connection(thd, 0, 1); end_thread(thd,1); /* If end_thread returns, we are either running with --one-thread @@ -881,7 +919,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) /* The following must be called before DBUG_ENTER */ if (my_thread_init() || thd->store_globals()) { - close_connection(&thd->net,ER_OUT_OF_RESOURCES); + close_connection(thd, ER_OUT_OF_RESOURCES, 1); thd->fatal_error(); goto end; } @@ -1284,7 +1322,8 @@ restore_user: break; #else { - char *fields; + char *fields, *pend; + String convname; TABLE_LIST table_list; statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status); bzero((char*) &table_list,sizeof(table_list)); @@ -1294,8 +1333,11 @@ restore_user: break; } thd->free_list=0; - table_list.alias= table_list.real_name= thd->strdup(packet); - packet=strend(packet)+1; + pend= strend(packet); + convname.copy(packet, pend-packet, + thd->variables.character_set_client, system_charset_info); + table_list.alias= table_list.real_name= convname.c_ptr(); + packet= pend+1; // command not cachable => no gap for data base name if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1))) break; @@ -1411,7 +1453,7 @@ restore_user: #ifndef OS2 send_eof(thd); // This is for 'quit request' #endif - close_connection(net); + close_connection(thd, 0, 1); close_thread_tables(thd); // Free before kill free_root(&thd->mem_root,MYF(0)); free_root(&thd->transaction.mem_root,MYF(0)); @@ -1551,7 +1593,8 @@ bool alloc_query(THD *thd, char *packet, ulong packet_length) /* We must allocate some extra memory for query cache */ if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), packet_length, - thd->db_length+2))) + thd->db_length+2+ + sizeof(ha_rows)))) return 1; thd->query[packet_length]=0; thd->query_length= packet_length; @@ -1648,6 +1691,18 @@ mysql_execute_command(THD *thd) #endif ) DBUG_VOID_RETURN; + + /* + When option readonly is set deny operations which change tables. + Except for the replication thread and the 'super' users. + */ + if (opt_readonly && + !(thd->slave_thread || (thd->master_access & SUPER_ACL)) && + (uc_update_queries[lex->sql_command] > 0)) + { + send_error(thd, ER_CANT_UPDATE_WITH_READLOCK); + DBUG_VOID_RETURN; + } statistic_increment(com_stat[lex->sql_command],&LOCK_status); switch (lex->sql_command) { @@ -1832,7 +1887,8 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_SLAVE_STAT: { - if (check_global_access(thd, SUPER_ACL)) + /* Accept one of two privileges */ + if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; LOCK_ACTIVE_MI; res = show_master_info(thd,active_mi); @@ -1841,7 +1897,8 @@ mysql_execute_command(THD *thd) } case SQLCOM_SHOW_MASTER_STAT: { - if (check_global_access(thd, SUPER_ACL)) + /* Accept one of two privileges */ + if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error; res = show_binlog_info(thd); break; @@ -2247,15 +2304,10 @@ mysql_execute_command(THD *thd) TABLE_LIST *table; if (check_db_used(thd,tables)) goto error; - for (table=tables ; table ; table=table->next) - { - if (table->derived) - table->grant.privilege= SELECT_ACL; - else if (check_access(thd,UPDATE_ACL,table->db,&table->grant.privilege)) + + if (single_table_command_access(thd, UPDATE_ACL, tables, &res)) goto error; - } - if (grant_option && check_grant(thd,UPDATE_ACL,tables)) - goto error; + if (select_lex->item_list.elements != lex->value_list.elements) { send_error(thd,ER_WRONG_VALUE_COUNT); @@ -2309,10 +2361,10 @@ mysql_execute_command(THD *thd) 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,privilege,tables)) - goto error; + + if (single_table_command_access(thd, privilege, tables, &res)) + goto error; + if (select_lex->item_list.elements != lex->value_list.elements) { send_error(thd,ER_WRONG_VALUE_COUNT); @@ -2394,10 +2446,9 @@ mysql_execute_command(THD *thd) break; case SQLCOM_DELETE: { - if (check_access(thd,DELETE_ACL,tables->db,&tables->grant.privilege)) - goto error; /* purecov: inspected */ - if (grant_option && check_grant(thd,DELETE_ACL,tables)) + if (single_table_command_access(thd, DELETE_ACL, tables, &res)) goto error; + // Set privilege for the WHERE clause tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); res = mysql_delete(thd,tables, select_lex->where, @@ -3056,14 +3107,63 @@ error: } +/* + Check grants for commands which work only with one table and all other + tables belong to subselects. + + SYNOPSYS + single_table_command_access() + thd - Thread handler + privilege - asked privelage + tables - table list of command + res - pointer on result code variable + + RETURN + 0 - OK + 1 - access denied +*/ + +static bool single_table_command_access(THD *thd, ulong privilege, + TABLE_LIST *tables, int *res) + +{ + if (check_access(thd, privilege, tables->db, &tables->grant.privilege)) + return 1; + + // Show only 1 table for check_grant + TABLE_LIST *subselects_tables= tables->next; + tables->next= 0; + if (grant_option && check_grant(thd, privilege, tables)) + return 1; + + // check rights on tables of subselect (if exists) + if (subselects_tables) + { + tables->next= subselects_tables; + if ((*res= check_table_access(thd, SELECT_ACL, subselects_tables))) + return 1; + } + return 0; +} + + /**************************************************************************** Get the user (global) and database privileges for all used tables - Returns true (error) if we can't get the privileges and we don't use - table/column grants. - The idea of EXTRA_ACL is that one will be granted access to the table if - one has the asked privilege on any column combination of the table; For - example to be able to check a table one needs to have SELECT privilege on - any column of the table. + + NOTES + The idea of EXTRA_ACL is that one will be granted access to the table if + one has the asked privilege on any column combination of the table; For + example to be able to check a table one needs to have SELECT privilege on + any column of the table. + + RETURN + 0 ok + 1 If we can't get the privileges and we don't use table/column grants. + + save_priv In this we store global and db level grants for the table + Note that we don't store db level grants if the global grants + is enough to satisfy the request and the global grants contains + a SELECT grant. ****************************************************************************/ bool @@ -3088,7 +3188,17 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((thd->master_access & want_access) == want_access) { - *save_priv=thd->master_access; + /* + If we don't have a global SELECT privilege, we have to get the database + specific access rights to be able to handle queries of type + UPDATE t1 SET a=1 WHERE b > 0 + */ + db_access= thd->db_access; + if (!(thd->master_access & SELECT_ACL) && + (db && (!thd->db || strcmp(db,thd->db)))) + db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr, + thd->priv_user, db); /* purecov: inspected */ + *save_priv=thd->master_access | db_access; DBUG_RETURN(FALSE); } if (((want_access & ~thd->master_access) & ~(DB_ACLS | EXTRA_ACL)) || @@ -3097,7 +3207,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if (!no_errors) net_printf(thd,ER_ACCESS_DENIED_ERROR, thd->priv_user, - thd->host_or_ip, + thd->priv_host, thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } @@ -3122,18 +3232,35 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if (!no_errors) net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, - thd->host_or_ip, + thd->priv_host, db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } -/* check for global access and give descriptive error message if it fails */ +/* + check for global access and give descriptive error message if it fails + + SYNOPSIS + check_global_access() + thd Thread handler + want_access Use should have any of these global rights + + WARNING + One gets access rigth if one has ANY of the rights in want_access + This is useful as one in most cases only need one global right, + but in some case we want to check if the user has SUPER or + REPL_CLIENT_ACL rights. + + RETURN + 0 ok + 1 Access denied. In this case an error is sent to the client +*/ bool check_global_access(THD *thd, ulong want_access) { char command[128]; - if ((thd->master_access & want_access) == want_access) + if ((thd->master_access & want_access)) return 0; get_privilege_desc(command, sizeof(command), want_access); net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR, @@ -3237,6 +3364,7 @@ static bool check_merge_table_access(THD *thd, char *db, #define used_stack(A,B) (long) (B - A) #endif +#ifndef EMBEDDED_LIBRARY bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) { long stack_used; @@ -3250,6 +3378,7 @@ bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) } return 0; } +#endif /* EMBEDDED_LIBRARY */ #define MY_YACC_INIT 1000 // Start with big alloc #define MY_YACC_MAX 32000 // Because of 'short' @@ -3548,9 +3677,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, 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 */ + if (length && !(new_field->length= (uint) atoi(length))) + length=0; /* purecov: inspected */ uint sign_len=type_modifier & UNSIGNED_FLAG ? 0 : 1; if (new_field->length && new_field->decimals && @@ -3583,10 +3711,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, break; case FIELD_TYPE_DECIMAL: if (!length) - new_field->length = 10; // Default length for DECIMAL - new_field->length+=sign_len; - if (new_field->decimals) - new_field->length++; + new_field->length= 10; // Default length for DECIMAL + if (new_field->length < MAX_FIELD_WIDTH) // Skip wrong argument + { + new_field->length+=sign_len; + if (new_field->decimals) + new_field->length++; + } break; case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: @@ -3716,12 +3847,13 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type, { char *not_used; uint not_used2; + bool not_used3; thd->cuted_fields=0; String str,*res; res=default_value->val_str(&str); (void) find_set(interval, res->ptr(), res->length(), ¬_used, - ¬_used2); + ¬_used2, ¬_used3); if (thd->cuted_fields) { net_printf(thd,ER_INVALID_DEFAULT,field_name); @@ -4011,6 +4143,24 @@ void add_join_on(TABLE_LIST *b,Item *expr) } +/* + Mark that we have a NATURAL JOIN between two tables + + SYNOPSIS + add_join_natural() + a Table to do normal join with + b Do normal join with this table + + IMPLEMENTATION + This function just marks that table b should be joined with a. + The function setup_cond() will create in b->on_expr a list + of equal condition between all fields of the same name. + + SELECT * FROM t1 NATURAL LEFT JOIN t2 + <=> + SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... ) +*/ + void add_join_natural(TABLE_LIST *a,TABLE_LIST *b) { b->natural_join=a; diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index a39541b0fc5..fe47e553cf3 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -22,7 +22,6 @@ #include "sql_repl.h" #include "sql_acl.h" #include "log_event.h" -#include "mini_client.h" #include <my_dir.h> extern const char* any_db; @@ -1079,6 +1078,9 @@ err: } send_eof(thd); + pthread_mutex_lock(&LOCK_thread_count); + thd->current_linfo = 0; + pthread_mutex_unlock(&LOCK_thread_count); DBUG_RETURN(0); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 85ebb9f207f..4167da5802a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -466,8 +466,17 @@ JOIN::optimize() if (tables_list && tmp_table_param.sum_func_count && ! group_list) { int res; + /* + opt_sum_query() returns -1 if no rows match to the WHERE conditions, + or 1 if all items were resolved, or 0, or an error number HA_ERR_... + */ if ((res=opt_sum_query(tables_list, all_fields, conds))) { + if (res > 1) + { + delete procedure; + DBUG_RETURN(-1); + } if (res < 0) { zero_result_cause= "No matching min/max row"; @@ -610,7 +619,17 @@ JOIN::optimize() select_distinct= 0; no_order= !order; if (all_order_fields_used) + { + if (order && skip_sort_order) + { + /* + Force MySQL to read the table in sorted order to get result in + ORDER BY order. + */ + tmp_table_param.quick_group=0; + } order=0; + } group=1; // For end_write_group } else @@ -2379,7 +2398,10 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, if (table->quick_keys & ((key_map) 1 << key)) records= (double) table->quick_rows[key]; else - records= (double) s->records/rec; // quick_range couldn't use key! + { + /* quick_range couldn't use key! */ + records= (double) s->records/rec; + } } else { @@ -3037,6 +3059,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) join->unit->select_limit_cnt)) < 0) DBUG_RETURN(1); // Impossible range sel->cond=orig_cond; + /* Fix for EXPLAIN */ + if (sel->quick) + join->best_positions[i].records_read= sel->quick->records; } else { @@ -4239,7 +4264,6 @@ 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; @@ -5027,6 +5051,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) ha_rows found_records=join->found_records; READ_RECORD *info= &join_tab->read_record; + join->thd->row_count= 0; do { if (join->thd->killed) // Aborted by user @@ -5035,6 +5060,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return -2; /* purecov: inspected */ } join->examined_rows++; + join->thd->row_count++; if (!on_expr || on_expr->val_int()) { found=1; @@ -6249,14 +6275,14 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part, */ static uint -test_if_subkey(ORDER *order, TABLE *table, uint ref, key_map usable_keys) +test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, + 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++) @@ -6291,10 +6317,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, bool no_changes) { int ref_key; + uint ref_key_parts; TABLE *table=tab->table; SQL_SELECT *select=tab->select; key_map usable_keys; DBUG_ENTER("test_if_skip_sort_order"); + LINT_INIT(ref_key_parts); /* Check which keys can be used to resolve ORDER BY */ usable_keys= ~(key_map) 0; @@ -6310,9 +6338,15 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, ref_key= -1; if (tab->ref.key >= 0) // Constant range in WHERE - ref_key=tab->ref.key; + { + ref_key= tab->ref.key; + ref_key_parts= tab->ref.key_parts; + } else if (select && select->quick) // Range found by opt_range - ref_key=select->quick->index; + { + ref_key= select->quick->index; + ref_key_parts= select->quick->used_key_parts; + } if (ref_key >= 0) { @@ -6326,20 +6360,28 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, /* 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) + uint new_ref_key; + /* + If using index only read, only consider other possible index only + keys + */ + if (table->used_keys & (((key_map) 1 << ref_key))) + usable_keys|= table->used_keys; + if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts, + usable_keys)) < MAX_KEY) { + /* Found key that can be used to retrieve data in sorted order */ if (tab->ref.key >= 0) { - tab->ref.key= a; - table->file->index_init(a); + tab->ref.key= new_ref_key; + table->file->index_init(new_ref_key); } else { - select->quick->index= a; + select->quick->index= new_ref_key; select->quick->init(); } - ref_key= a; + ref_key= new_ref_key; } } /* Check if we get the rows in requested sorted order by using the key */ @@ -7249,7 +7291,8 @@ setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, while ((item=li++)) { - if (item->type() != Item::SUM_FUNC_ITEM && !item->marker) + if (item->type() != Item::SUM_FUNC_ITEM && !item->marker && + !item->const_item()) { my_printf_error(ER_WRONG_FIELD_WITH_GROUP, ER(ER_WRONG_FIELD_WITH_GROUP), @@ -7957,6 +8000,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, TABLE *table=tab->table; char buff[512],*buff_ptr=buff; char buff1[512], buff2[512]; + char derived_name[64]; String tmp1(buff1,sizeof(buff1),cs); String tmp2(buff2,sizeof(buff2),cs); tmp1.length(0); @@ -7970,13 +8014,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, cs)); if (tab->type == JT_ALL && tab->select && tab->select->quick) tab->type= JT_RANGE; - if (table->tmp_table == TMP_TABLE && table->derived_select_number != 0) + if (table->derived_select_number) { - // Derived table name generation - char buff[512]; - int len= my_snprintf(buff, 512, "<derived%u>", + /* Derived table name generation */ + int len= my_snprintf(derived_name, sizeof(derived_name)-1, + "<derived%u>", table->derived_select_number); - item_list.push_back(new Item_string(buff, len, cs)); + item_list.push_back(new Item_string(derived_name, len, cs)); } else item_list.push_back(new Item_string(table->table_name, @@ -8170,5 +8214,3 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) unit= unit->next_unit()) unit->cleanup(); } - - diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 2b8982f2484..803280c56c6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -679,7 +679,8 @@ 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)); + if (verbose) + 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)); @@ -719,8 +720,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, protocol->store(field->field_name, system_charset_info); field->sql_type(type); protocol->store(type.ptr(), type.length(), system_charset_info); - protocol->store(field->charset()->name, system_charset_info); - + if (verbose) + protocol->store(field->has_charset() ? field->charset()->name : "NULL", + system_charset_info); pos=(byte*) ((flags & NOT_NULL_FLAG) && field->type() != FIELD_TYPE_TIMESTAMP ? "" : "YES"); @@ -923,7 +925,10 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) protocol->store((const char*) pos, system_charset_info); protocol->store(table->file->index_type(i), system_charset_info); /* Comment */ - protocol->store("", system_charset_info); + if (!(table->keys_in_use & ((key_map) 1 << i))) + protocol->store("disabled",8, system_charset_info); + else + protocol->store("", 0, system_charset_info); if (protocol->write()) DBUG_RETURN(1); /* purecov: inspected */ } @@ -1070,23 +1075,36 @@ store_create_info(THD *thd, TABLE *table, String *packet) field->sql_type(type); packet->append(type.ptr(),type.length()); - 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) + if (field->has_charset()) { - packet->append(" collate ", 9); - packet->append(field->charset()->name); + if (field->charset() == &my_charset_bin) + packet->append(" binary"); + else if (!limited_mysql_mode && !foreign_db_mode) + { + if (field->charset() != table->table_charset) + { + packet->append(" character set "); + packet->append(field->charset()->csname); + } + /* + For string types dump collation name only if + collation is not primary for the given charset + */ + if (!(field->charset()->state & MY_CS_PRIMARY)) + { + packet->append(" collate ", 9); + packet->append(field->charset()->name); + } + } } + if (flags & NOT_NULL_FLAG) packet->append(" NOT NULL", 9); + bool has_default = (field->type() != FIELD_TYPE_BLOB && + field->type() != FIELD_TYPE_TIMESTAMP && + field->unireg_check != Field::NEXT_NUMBER); + if (has_default) { packet->append(" default ", 9); @@ -1417,11 +1435,11 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) static bool write_collation(Protocol *protocol, CHARSET_INFO *cs) { protocol->prepare_for_resend(); - protocol->store(cs->csname, system_charset_info); protocol->store(cs->name, system_charset_info); + protocol->store(cs->csname, system_charset_info); protocol->store_short((longlong) cs->number); - protocol->store((cs->state & MY_CS_PRIMARY) ? "Y" : "",system_charset_info); - protocol->store((cs->state & MY_CS_COMPILED)? "Y" : "",system_charset_info); + protocol->store((cs->state & MY_CS_PRIMARY) ? "Yes" : "",system_charset_info); + protocol->store((cs->state & MY_CS_COMPILED)? "Yes" : "",system_charset_info); protocol->store_short((longlong) cs->strxfrm_multiply); return protocol->write(); } @@ -1437,11 +1455,11 @@ int mysqld_show_collations(THD *thd, const char *wild) DBUG_ENTER("mysqld_show_charsets"); - field_list.push_back(new Item_empty_string("Charset",30)); field_list.push_back(new Item_empty_string("Collation",30)); + field_list.push_back(new Item_empty_string("Charset",30)); field_list.push_back(new Item_return_int("Id",11, FIELD_TYPE_SHORT)); - field_list.push_back(new Item_empty_string("D",30)); - field_list.push_back(new Item_empty_string("C",30)); + field_list.push_back(new Item_empty_string("Default",30)); + field_list.push_back(new Item_empty_string("Compiled",30)); field_list.push_back(new Item_return_int("Sortlen",3, FIELD_TYPE_SHORT)); if (protocol->send_fields(&field_list, 1)) @@ -1587,7 +1605,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_QUESTION: end= int10_to_str((long) thd->query_id, buff, 10); break; -#ifndef EMBEDDED_LIBRARY +#ifdef HAVE_REPLICATION case SHOW_RPL_STATUS: end= strmov(buff, rpl_status_type[(int)rpl_status]); break; @@ -1599,7 +1617,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, UNLOCK_ACTIVE_MI; break; } -#endif /* EMBEDDED_LIBRARY */ +#endif /* HAVE_REPLICATION */ case SHOW_OPENTABLES: end= int10_to_str((long) cached_tables(), buff, 10); break; diff --git a/sql/sql_string.cc b/sql/sql_string.cc index ca38651b3b6..cf6645fa23e 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -28,15 +28,12 @@ #include <floatingpoint.h> #endif -CHARSET_INFO *system_charset_info= &my_charset_utf8; -CHARSET_INFO *files_charset_info= &my_charset_utf8; -CHARSET_INFO *national_charset_info= &my_charset_utf8; +CHARSET_INFO *system_charset_info= &my_charset_utf8_general_ci; +CHARSET_INFO *files_charset_info= &my_charset_utf8_general_ci; +CHARSET_INFO *national_charset_info= &my_charset_utf8_general_ci; 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" @@ -104,7 +101,7 @@ bool String::set(longlong num, CHARSET_INFO *cs) if (alloc(l)) return TRUE; - str_length=(uint32) (cs->longlong10_to_str)(cs,Ptr,l,-10,num); + str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,-10,num); str_charset=cs; return FALSE; } @@ -115,7 +112,7 @@ bool String::set(ulonglong num, CHARSET_INFO *cs) if (alloc(l)) return TRUE; - str_length=(uint32) (cs->longlong10_to_str)(cs,Ptr,l,10,num); + str_length=(uint32) (cs->cset->longlong10_to_str)(cs,Ptr,l,10,num); str_charset=cs; return FALSE; } @@ -268,9 +265,9 @@ bool String::copy(const char *str, uint32 arg_length, */ -bool String::set_latin1(const char *str, uint32 arg_length) +bool String::set_ascii(const char *str, uint32 arg_length) { - if (str_charset->mbmaxlen == 1) + if (!(str_charset->state & MY_CS_NONTEXT)) { set(str, arg_length, str_charset); return 0; @@ -399,13 +396,13 @@ bool String::append(IO_CACHE* file, uint32 arg_length) uint32 String::numchars() { - return str_charset->numchars(str_charset, Ptr, Ptr+str_length); + return str_charset->cset->numchars(str_charset, Ptr, Ptr+str_length); } int String::charpos(int i,uint32 offset) { if (i<0) return i; - return str_charset->charpos(str_charset,Ptr+offset,Ptr+str_length,i); + return str_charset->cset->charpos(str_charset,Ptr+offset,Ptr+str_length,i); } int String::strstr(const String &s,uint32 offset) @@ -583,7 +580,7 @@ void String::qs_append(const char &c) int sortcmp(const String *x,const String *y, CHARSET_INFO *cs) { - return cs->strnncollsp(cs, + return cs->coll->strnncollsp(cs, (unsigned char *) x->ptr(),x->length(), (unsigned char *) y->ptr(),y->length()); } @@ -630,7 +627,7 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) */ -static uint32 +uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, const char *from, uint32 from_length, CHARSET_INFO *from_cs) { @@ -642,7 +639,7 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, while (1) { - if ((cnvres=from_cs->mb_wc(from_cs, &wc, (uchar*) from, from_end)) > 0) + if ((cnvres=from_cs->cset->mb_wc(from_cs, &wc, (uchar*) from, from_end)) > 0) from+= cnvres; else if (cnvres == MY_CS_ILSEQ) { @@ -653,7 +650,7 @@ copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, break; // Impossible char. outp: - if ((cnvres= to_cs->wc_mb(to_cs, wc, (uchar*) to, to_end)) > 0) + if ((cnvres= to_cs->cset->wc_mb(to_cs, wc, (uchar*) to, to_end)) > 0) to+= cnvres; else if (cnvres == MY_CS_ILUNI && wc != '?') { diff --git a/sql/sql_string.h b/sql/sql_string.h index 9c494600058..ee38853a2d3 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -27,6 +27,9 @@ class String; int sortcmp(const String *a,const String *b, CHARSET_INFO *cs); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); +uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs, + const char *from, uint32 from_length, + CHARSET_INFO *from_cs); class String { @@ -114,7 +117,7 @@ public: Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0; str_charset=cs; } - bool set_latin1(const char *str, uint32 arg_length); + bool set_ascii(const char *str, uint32 arg_length); inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs) { if (!alloced) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3cac88d05b2..c53ca0b68a8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -23,6 +23,7 @@ #endif #include <hash.h> #include <myisam.h> +#include <my_dir.h> #ifdef __WIN__ #include <io.h> @@ -480,7 +481,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { if (!sql_field->charset) sql_field->charset = create_info->table_charset ? - create_info->table_charset : thd->db_charset; + create_info->table_charset : + thd->variables.character_set_database; switch (sql_field->sql_type) { case FIELD_TYPE_BLOB: @@ -716,6 +718,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, column->field_name); DBUG_RETURN(-1); } + /* for fulltext keys keyseg length is 1 for blobs (it's ignored in + ft code anyway, and 0 (set to column width later) for char's. + it has to be correct col width for char's, as char data are not + prefixed with length (unlike blobs, where ft code takes data length + from a data prefix, ignoring column->length). + */ + if (key->type == Key::FULLTEXT) + column->length=test(f_is_blob(sql_field->pack_flag)); if (f_is_blob(sql_field->pack_flag)) { if (!(file->table_flags() & HA_BLOB_KEY)) @@ -726,15 +736,10 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (!column->length) { - if (key->type == Key::FULLTEXT) - column->length=1; /* ft-code ignores it anyway :-) */ - else - { - my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, - ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0), - column->field_name); - DBUG_RETURN(-1); - } + my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, + ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0), + column->field_name); + DBUG_RETURN(-1); } } if (key->type == Key::SPATIAL) @@ -752,8 +757,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, { if (key->type == Key::PRIMARY) { - my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0)); - DBUG_RETURN(-1); + /* Implicitly set primary key fields to NOT NULL for ISO conf. */ + sql_field->flags|= NOT_NULL_FLAG; + sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; } if (!(file->table_flags() & HA_NULL_KEY)) { @@ -1081,12 +1087,9 @@ mysql_rename_table(enum db_type base, Win32 clients must also have a WRITE LOCK on the table ! */ -bool close_cached_table(THD *thd,TABLE *table) +static void safe_remove_from_cache(THD *thd,TABLE *table) { - bool result=0; - DBUG_ENTER("close_cached_table"); - safe_mutex_assert_owner(&LOCK_open); - + DBUG_ENTER("safe_remove_from_cache"); if (table) { DBUG_PRINT("enter",("table: %s", table->real_name)); @@ -1109,16 +1112,29 @@ bool close_cached_table(THD *thd,TABLE *table) #endif /* When lock on LOCK_open is freed other threads can continue */ pthread_cond_broadcast(&COND_refresh); + } + DBUG_VOID_RETURN; +} + +bool close_cached_table(THD *thd,TABLE *table) +{ + DBUG_ENTER("close_cached_table"); + safe_mutex_assert_owner(&LOCK_open); + + if (table) + { + safe_remove_from_cache(thd,table); /* Close lock if this is not got with LOCK TABLES */ if (thd->lock) { - mysql_unlock_tables(thd, thd->lock); thd->lock=0; // Start locked threads + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; // Start locked threads } /* Close all copies of 'table'. This also frees all LOCK TABLES lock */ thd->open_tables=unlink_open_table(thd,thd->open_tables,table); } - DBUG_RETURN(result); + DBUG_RETURN(0); } static int send_check_errmsg(THD *thd, TABLE_LIST* table, @@ -1199,69 +1215,105 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, } -static int prepare_for_repair(THD* thd, TABLE_LIST* table, +static int prepare_for_repair(THD* thd, TABLE_LIST *table_list, HA_CHECK_OPT *check_opt) { + int error= 0; + TABLE tmp_table, *table; DBUG_ENTER("prepare_for_repair"); if (!(check_opt->sql_flags & TT_USEFRM)) - { DBUG_RETURN(0); - } - else + + if (!(table= table_list->table)) /* if open_ltable failed */ { + char name[FN_REFLEN]; + strxmov(name, mysql_data_home, "/", table_list->db, "/", + table_list->real_name, NullS); + if (openfrm(name, "", 0, 0, 0, &tmp_table)) + DBUG_RETURN(0); // Can't open frm file + table= &tmp_table; + } - char from[FN_REFLEN],tmp[FN_REFLEN]; - char* db = thd->db ? thd->db : table->db; + /* + User gave us USE_FRM which means that the header in the index file is + trashed. + In this case we will try to fix the table the following way: + - Rename the data file to a temporary name + - Truncate the table + - Replace the new data file with the old one + - Run a normal repair using the new index file and the old data file + */ - sprintf(from, "%s/%s/%s", mysql_real_data_home, db, table->real_name); - fn_format(from, from, "", MI_NAME_DEXT, 4); - sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); + char from[FN_REFLEN],tmp[FN_REFLEN+32]; + const char **ext= table->file->bas_ext(); + MY_STAT stat_info; - pthread_mutex_lock(&LOCK_open); - close_cached_table(thd,table->table); - pthread_mutex_unlock(&LOCK_open); + /* + Check if this is a table type that stores index and data separately, + like ISAM or MyISAM + */ + if (!ext[0] || !ext[1]) + goto end; // No data file - if (lock_and_wait_for_table_name(thd,table)) - DBUG_RETURN(-1); + strxmov(from, table->path, ext[1], NullS); // Name of data file + if (!my_stat(from, &stat_info, MYF(0))) + goto end; // Can't use USE_FRM flag - if (my_rename(from, tmp, MYF(MY_WME))) - { - pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(send_check_errmsg(thd, table, "repair", - "Failed renaming .MYD file")); - } - if (mysql_truncate(thd, table, 1)) - { - pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(send_check_errmsg(thd, table, "repair", - "Failed generating table from .frm file")); - } - if (my_rename(tmp, from, MYF(MY_WME))) - { - pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); - pthread_mutex_unlock(&LOCK_open); - DBUG_RETURN(send_check_errmsg(thd, table, "repair", - "Failed restoring .MYD file")); - } + sprintf(tmp,"%s-%lx_%lx", from, current_pid, thd->thread_id); + + pthread_mutex_lock(&LOCK_open); + close_cached_table(thd,table_list->table); + pthread_mutex_unlock(&LOCK_open); + + if (lock_and_wait_for_table_name(thd,table_list)) + { + error= -1; + goto end; + } + if (my_rename(from, tmp, MYF(MY_WME))) + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table_list); + pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed renaming data file"); + goto end; + } + if (mysql_truncate(thd, table_list, 1)) + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table_list); + pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed generating table from .frm file"); + goto end; + } + if (my_rename(tmp, from, MYF(MY_WME))) + { + pthread_mutex_lock(&LOCK_open); + unlock_table_name(thd, table_list); + pthread_mutex_unlock(&LOCK_open); + error= send_check_errmsg(thd, table_list, "repair", + "Failed restoring .MYD file"); + goto end; } /* Now we should be able to open the partially repaired table to finish the repair in the handler later on. */ - if (!(table->table = reopen_name_locked_table(thd, table))) + if (!(table_list->table = reopen_name_locked_table(thd, table_list))) { pthread_mutex_lock(&LOCK_open); - unlock_table_name(thd, table); + unlock_table_name(thd, table_list); pthread_mutex_unlock(&LOCK_open); } - DBUG_RETURN(0); + +end: + if (table == &tmp_table) + closefrm(table); // Free allocated memory + DBUG_RETURN(error); } @@ -1759,9 +1811,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, case LEAVE_AS_IS: break; case ENABLE: - error=table->file->activate_all_index(thd); + safe_remove_from_cache(thd,table); + error= table->file->activate_all_index(thd); break; case DISABLE: + safe_remove_from_cache(thd,table); table->file->deactivate_non_unique_index(HA_POS_ERROR); break; } @@ -2403,6 +2457,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, handle_duplicates == DUP_REPLACE) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); next_field=to->next_number_field; + thd->row_count= 0; while (!(error=info.read_record(&info))) { if (thd->killed) @@ -2411,6 +2466,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, error= 1; break; } + thd->row_count++; if (next_field) next_field->reset(); for (Copy_field *copy_ptr=copy ; copy_ptr != copy_end ; copy_ptr++) @@ -2428,7 +2484,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, delete_count++; } else - found_count++; + found_count++; } end_read_record(&info); free_io_cache(from); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index fe4ca49da14..1d0f37f0042 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -76,7 +76,7 @@ bool select_union::send_data(List<Item> &values) unit->offset_limit_cnt--; return 0; } - fill_record(table->field,values); + fill_record(table->field, values, 1); if (thd->net.report_error || write_record(table,&info)) { if (thd->net.last_errno == ER_RECORD_FILE_FULL) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7c5983a0362..1f6364ec427 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -62,33 +62,46 @@ int mysql_update(THD *thd, int error=0; uint used_index, want_privilege; ulong query_id=thd->query_id, timestamp_query_id; + ha_rows updated, found; key_map old_used_keys; TABLE *table; SQL_SELECT *select; READ_RECORD info; - TABLE_LIST *update_table_list= (TABLE_LIST*) - thd->lex.select_lex.table_list.first; + TABLE_LIST *update_table_list= ((TABLE_LIST*) + thd->lex.select_lex.table_list.first); + TABLE_LIST tables; + List<Item> all_fields; DBUG_ENTER("mysql_update"); + LINT_INIT(used_index); LINT_INIT(timestamp_query_id); if ((open_and_lock_tables(thd, table_list))) DBUG_RETURN(-1); + thd->proc_info="init"; 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"; /* Calculate "table->used_keys" based on the WHERE */ table->used_keys=table->keys_in_use; table->quick_keys=0; want_privilege=table->grant.want_privilege; table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); - if (setup_tables(update_table_list) || - setup_conds(thd,update_table_list,&conds) - || setup_ftfuncs(&thd->lex.select_lex)) + + bzero((char*) &tables,sizeof(tables)); // For ORDER BY + tables.table= table; + + if (setup_tables(update_table_list) || + setup_conds(thd,update_table_list,&conds) || + setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array, + order_num) || + setup_order(thd, thd->lex.select_lex.ref_pointer_array, + &tables, all_fields, all_fields, order) || + setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(-1); /* purecov: inspected */ + + /* Check that we are not using table that we are updating in a sub select */ if (find_real_table_in_list(table_list->next, table_list->db, table_list->real_name)) { @@ -96,8 +109,7 @@ int mysql_update(THD *thd, DBUG_RETURN(-1); } - old_used_keys=table->used_keys; // Keys used in WHERE - + old_used_keys= table->used_keys; // Keys used in WHERE /* Change the query_id for the timestamp column so that we can check if this is modified directly @@ -151,10 +163,9 @@ int mysql_update(THD *thd, thd->lex.select_lex.options|=QUERY_NO_INDEX_USED; if (safe_update && !using_limit) { - delete select; - free_underlaid_joins(thd, &thd->lex.select_lex); - send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); - DBUG_RETURN(1); + my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, + ER(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); + goto err; } } init_ftfuncs(thd, &thd->lex.select_lex, 1); @@ -175,14 +186,6 @@ int mysql_update(THD *thd, matching rows before updating the table! */ table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); - IO_CACHE tempfile; - if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX, - 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)) { table->key_read=1; @@ -191,94 +194,102 @@ int mysql_update(THD *thd, if (order) { + /* + Doing an ORDER BY; Let filesort find and sort the rows we are going + to update + */ uint length; SORT_FIELD *sortorder; - TABLE_LIST tables; List<Item> fields; - List<Item> all_fields; ha_rows examined_rows; - bzero((char*) &tables,sizeof(tables)); - tables.table = table; - table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE), - MYF(MY_FAE | MY_ZEROFILL)); - 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)) || + MYF(MY_FAE | MY_ZEROFILL)); + if (!(sortorder=make_unireg_sortorder(order, &length)) || (table->sort.found_records = filesort(thd, table, sortorder, length, - (SQL_SELECT *) 0, - HA_POS_ERROR, &examined_rows)) + select, limit, + &examined_rows)) == HA_POS_ERROR) { - delete select; - free_underlaid_joins(thd, &thd->lex.select_lex); - DBUG_RETURN(-1); + free_io_cache(table); + goto err; } + /* + Filesort has already found and selected the rows we want to update, + so we don't need the where clause + */ + delete select; + select= 0; } + else + { + /* + We are doing a search on a key that is updated. In this case + we go trough the matching rows, save a pointer to them and + update these in a separate loop based on the pointer. + */ + + IO_CACHE tempfile; + if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX, + DISK_BUFFER_SIZE, MYF(MY_WME))) + goto err; - init_read_record(&info,thd,table,select,0,1); - thd->proc_info="Searching rows for update"; + init_read_record(&info,thd,table,select,0,1); + thd->proc_info="Searching rows for update"; + uint tmp_limit= limit; - while (!(error=info.read_record(&info)) && !thd->killed) - { - if (!(select && select->skipp_record())) + while (!(error=info.read_record(&info)) && !thd->killed) { - table->file->position(table->record[0]); - if (my_b_write(&tempfile,table->file->ref, - table->file->ref_length)) + if (!(select && select->skipp_record())) { - error=1; /* purecov: inspected */ - break; /* purecov: inspected */ + table->file->position(table->record[0]); + if (my_b_write(&tempfile,table->file->ref, + table->file->ref_length)) + { + error=1; /* purecov: inspected */ + break; /* purecov: inspected */ + } + if (!--limit && using_limit) + { + error= -1; + break; + } } } + limit= tmp_limit; + end_read_record(&info); + /* Change select to use tempfile */ + if (select) + { + delete select->quick; + if (select->free_cond) + delete select->cond; + select->quick=0; + select->cond=0; + } else { - if (!(test_flags & 512)) /* For debugging */ - { - DBUG_DUMP("record",(char*) table->record[0],table->reclength); - } + select= new SQL_SELECT; + select->head=table; } + if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) + error=1; /* purecov: inspected */ + select->file=tempfile; // Read row ptrs from this file + if (error >= 0) + goto err; } - end_read_record(&info); - if (table->key_read) { table->key_read=0; table->file->extra(HA_EXTRA_NO_KEYREAD); } - /* Change select to use tempfile */ - if (select) - { - delete select->quick; - if (select->free_cond) - delete select->cond; - select->quick=0; - select->cond=0; - } - else - { - select= new SQL_SELECT; - select->head=table; - } - if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0)) - error=1; /* purecov: inspected */ - select->file=tempfile; // Read row ptrs from this file - if (error >= 0) - { - delete select; - free_underlaid_joins(thd, &thd->lex.select_lex); - DBUG_RETURN(-1); - } } if (handle_duplicates == DUP_IGNORE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); init_read_record(&info,thd,table,select,0,1); - ha_rows updated=0L,found=0L; + updated= found= 0; thd->count_cuted_fields=1; /* calc cuted fields */ thd->cuted_fields=0L; thd->proc_info="Updating"; @@ -289,7 +300,7 @@ int mysql_update(THD *thd, if (!(select && select->skipp_record())) { store_record(table,record[1]); - if (fill_record(fields,values) || thd->net.report_error) + if (fill_record(fields,values, 0) || thd->net.report_error) break; /* purecov: inspected */ found++; if (compare_record(table, query_id)) @@ -298,11 +309,6 @@ int mysql_update(THD *thd, (byte*) table->record[0]))) { updated++; - if (!--limit && using_limit) - { - error= -1; - break; - } } else if (handle_duplicates != DUP_IGNORE || error != HA_ERR_FOUND_DUPP_KEY) @@ -312,13 +318,28 @@ int mysql_update(THD *thd, break; } } + if (!--limit && using_limit) + { + error= -1; // Simulate end of file + break; + } } else table->file->unlock_row(); + thd->row_count++; } end_read_record(&info); + free_io_cache(table); // If ORDER BY thd->proc_info="end"; VOID(table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY)); + + /* + Invalidate the table in the query cache if something changed. + This must be before binlog writing and ha_autocommit_... + */ + if (updated) + query_cache_invalidate3(thd, table_list, 1); + transactional_table= table->file->has_transactions(); log_delayed= (transactional_table || table->tmp_table); if (updated && (error <= 0 || !transactional_table)) @@ -340,14 +361,6 @@ int mysql_update(THD *thd, error=1; } - /* - Store table for future invalidation or invalidate it in - the query cache if something changed - */ - if (updated) - { - query_cache_invalidate3(thd, table_list, 1); - } if (thd->lock) { mysql_unlock_tables(thd, thd->lock); @@ -370,8 +383,17 @@ int mysql_update(THD *thd, } thd->count_cuted_fields=0; /* calc cuted fields */ free_io_cache(table); - DBUG_RETURN(0); + +err: + delete select; + free_underlaid_joins(thd, &thd->lex.select_lex); + if (table->key_read) + { + table->key_read=0; + table->file->extra(HA_EXTRA_NO_KEYREAD); + } + DBUG_RETURN(-1); } @@ -508,6 +530,8 @@ int multi_update::prepare(List<Item> ¬_used_values, SELECT_LEX_UNIT *unit) table->pos_in_table_list= tl; } } + + table_count= update.elements; update_tables= (TABLE_LIST*) update.first; @@ -732,7 +756,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) { table->status|= STATUS_UPDATED; store_record(table,record[1]); - if (fill_record(*fields_for_table[offset], *values_for_table[offset])) + if (fill_record(*fields_for_table[offset], *values_for_table[offset], 0)) DBUG_RETURN(1); found++; if (compare_record(table, thd->query_id)) @@ -760,7 +784,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) { int error; TABLE *tmp_table= tmp_tables[offset]; - fill_record(tmp_table->field+1, *values_for_table[offset]); + fill_record(tmp_table->field+1, *values_for_table[offset], 1); found++; /* Store pointer to row */ memcpy((char*) tmp_table->field[0]->ptr, @@ -770,7 +794,7 @@ bool multi_update::send_data(List<Item> ¬_used_values) (error != HA_ERR_FOUND_DUPP_KEY && error != HA_ERR_FOUND_DUPP_UNIQUE)) { - if (create_myisam_from_heap(thd, table, tmp_table_param + offset, + if (create_myisam_from_heap(thd, tmp_table, tmp_table_param + offset, error, 1)) { do_update=0; @@ -926,6 +950,14 @@ bool multi_update::send_eof() int local_error = (table_count) ? do_updates(0) : 0; thd->proc_info= "end"; + /* We must invalidate the query cache before binlog writing and + ha_autocommit_... */ + + if (updated) + { + query_cache_invalidate3(thd, update_tables, 1); + } + /* Write the SQL statement to the binlog if we updated rows and we succeeded or if we updated some non @@ -964,10 +996,6 @@ bool multi_update::send_eof() sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, (long) thd->cuted_fields); - if (updated) - { - query_cache_invalidate3(thd, update_tables, 1); - } ::send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e3b2c738949..66a29a8cbd5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -555,11 +555,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %left '^' %right NOT %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 ',' -%left STRAIGHT_JOIN JOIN_SYM -%nonassoc CROSS INNER_SYM NATURAL LEFT RIGHT %type <lex_str> IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME @@ -853,7 +848,7 @@ create: bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.options=$2 | $4; lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type; - lex->create_info.table_charset= thd->db_charset; + lex->create_info.table_charset= thd->variables.character_set_database; lex->name=0; } create2 @@ -1411,7 +1406,7 @@ opt_binary: | BINARY { Lex->charset=&my_charset_bin; } | UNICODE_SYM { - if (!(Lex->charset=get_charset_by_name("ucs2",MYF(0)))) + if (!(Lex->charset=get_charset_by_csname("ucs2",MY_CS_PRIMARY,MYF(0)))) { net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,"ucs2"); YYABORT; @@ -1541,7 +1536,7 @@ alter: lex->select_lex.db=lex->name=0; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.db_type= DB_TYPE_DEFAULT; - lex->create_info.table_charset= thd->db_charset; + lex->create_info.table_charset= thd->variables.character_set_database; lex->create_info.row_type= ROW_TYPE_NOT_USED; lex->alter_keys_onoff=LEAVE_AS_IS; lex->simple_alter=1; @@ -1933,7 +1928,10 @@ select_option: Select->options|= OPTION_FOUND_ROWS; } | SQL_NO_CACHE_SYM { Lex->uncacheable(); } - | SQL_CACHE_SYM { Select->options|= OPTION_TO_QUERY_CACHE; } + | SQL_CACHE_SYM + { + Lex->select_lex.options|= OPTION_TO_QUERY_CACHE; + } | ALL {} ; @@ -2182,8 +2180,10 @@ simple_expr: simple_ident | simple_expr COLLATE_SYM ident_or_text %prec NEG { - $$= new Item_func_set_collation($1,new Item_string($3.str,$3.length, - YYTHD->charset())); + $$= new Item_func_set_collation($1, + new Item_string($3.str, + $3.length, + YYTHD->charset())); } | literal | param_marker @@ -2230,13 +2230,15 @@ simple_expr: | 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)); + $$= new Item_func_set_collation($2,new Item_string(binary_keyword, + 6, &my_charset_latin1)); } - | CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); } + | CAST_SYM '(' expr AS cast_type ')' + { $$= create_func_cast($3, $5, Lex->charset); } | 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 ',' cast_type ')' + { $$= create_func_cast($3, $5, Lex->charset); } | CONVERT_SYM '(' expr USING charset_name ')' { $$= new Item_func_conv_charset($3,$5); } | CONVERT_SYM '(' expr ',' expr ',' expr ')' @@ -2581,8 +2583,12 @@ sum_expr: { $$=new Item_sum_count(new Item_int((int32) 0L,1)); } | COUNT_SYM '(' in_sum_expr ')' { $$=new Item_sum_count($3); } - | COUNT_SYM '(' DISTINCT expr_list ')' - { $$=new Item_sum_count_distinct(* $4); } + | COUNT_SYM '(' DISTINCT + { Select->select_lex()->in_sum_expr++; } + expr_list + { Select->select_lex()->in_sum_expr--; } + ')' + { $$=new Item_sum_count_distinct(* $5); } | GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')' { $$= new Item_sum_unique_users($3,atoi($5.str),atoi($7.str),$9); } | MIN_SYM '(' in_sum_expr ')' @@ -2641,15 +2647,15 @@ in_sum_expr: }; cast_type: - BINARY { $$=ITEM_CAST_BINARY; } - | CHAR_SYM { $$=ITEM_CAST_CHAR; } - | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; } - | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; } - | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; } - | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; } - | DATE_SYM { $$=ITEM_CAST_DATE; } - | TIME_SYM { $$=ITEM_CAST_TIME; } - | DATETIME { $$=ITEM_CAST_DATETIME; } + BINARY { $$=ITEM_CAST_BINARY; Lex->charset= NULL; } + | CHAR_SYM opt_binary { $$=ITEM_CAST_CHAR; } + | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; } + | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; } + | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; } + | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; } + | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; } + | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; } + | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; } ; expr_list: @@ -2711,7 +2717,7 @@ join_table_list: | join_table_list ',' join_table_list { $$=$3; } | join_table_list normal_join join_table_list { $$=$3; } | join_table_list STRAIGHT_JOIN join_table_list - { $$=$3 ; $$->straight=1; } + { $$=$3 ; $1->next->straight=1; } | join_table_list normal_join join_table_list ON expr { add_join_on($3,$5); $$=$3; } | join_table_list normal_join join_table_list @@ -2735,9 +2741,13 @@ join_table_list: USING '(' using_list ')' { add_join_on($5,$9); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | join_table_list NATURAL LEFT opt_outer JOIN_SYM join_table_list - { add_join_natural($1,$6); $6->outer_join|=JOIN_TYPE_LEFT; $$=$6; } + { + add_join_natural($1,$1->next); + $1->next->outer_join|=JOIN_TYPE_LEFT; + $$=$6; + } | join_table_list RIGHT opt_outer JOIN_SYM join_table_list ON expr - { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } + { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; } | join_table_list RIGHT opt_outer JOIN_SYM join_table_list { SELECT_LEX *sel= Select->select_lex(); @@ -2745,11 +2755,15 @@ join_table_list: sel->db2=$5->db; sel->table2=$5->alias; } USING '(' using_list ')' - { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } + { add_join_on($1,$9); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; } | join_table_list NATURAL RIGHT opt_outer JOIN_SYM join_table_list - { add_join_natural($6,$1); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } + { + add_join_natural($1->next,$1); + $1->outer_join|=JOIN_TYPE_RIGHT; + $$=$6; + } | join_table_list NATURAL JOIN_SYM join_table_list - { add_join_natural($1,$4); $$=$4; }; + { add_join_natural($1,$1->next); $$=$4; }; normal_join: JOIN_SYM {} @@ -2849,15 +2863,15 @@ key_usage_list2: key_usage_list2 ',' ident { Select->select_lex()-> interval_list.push_back(new String((const char*) $3.str, $3.length, - default_charset_info)); } + system_charset_info)); } | ident { Select->select_lex()-> interval_list.push_back(new String((const char*) $1.str, $1.length, - default_charset_info)); } + system_charset_info)); } | PRIMARY_SYM { Select->select_lex()-> interval_list.push_back(new String("PRIMARY", 7, - default_charset_info)); }; + system_charset_info)); }; using_list: ident @@ -3076,7 +3090,7 @@ delete_limit_clause: ULONG_NUM: NUM { $$= strtoul($1.str,NULL,10); } - | LONG_NUM { $$= (ulonglong) strtoll($1.str,NULL,10); } + | LONG_NUM { $$= (ulong) strtoll($1.str,NULL,10); } | ULONGLONG_NUM { $$= (ulong) strtoull($1.str,NULL,10); } | REAL_NUM { $$= strtoul($1.str,NULL,10); } | FLOAT_NUM { $$= strtoul($1.str,NULL,10); }; @@ -3742,7 +3756,7 @@ opt_describe_column: /* empty */ {} | text_string { Lex->wild= $1; } | ident - { Lex->wild= new String((const char*) $1.str,$1.length,default_charset_info); }; + { Lex->wild= new String((const char*) $1.str,$1.length,system_charset_info); }; /* flush things */ @@ -4420,24 +4434,18 @@ option_value: find_sys_var("tx_isolation"), new Item_int((int32) $4))); } - | charset old_or_new_charset_name_or_default opt_collate + | charset old_or_new_charset_name_or_default { THD *thd= YYTHD; LEX *lex= Lex; - $2= $2 ? $2: global_system_variables.collation_client; - $3= $3 ? $3 : $2; - if (!my_charset_same($2,$3)) - { - net_printf(thd,ER_COLLATION_CHARSET_MISMATCH,$3->name,$2->csname); - YYABORT; - } - lex->var_list.push_back(new set_var_collation_client($3,thd->db_charset,$3)); + $2= $2 ? $2: global_system_variables.character_set_client; + lex->var_list.push_back(new set_var_collation_client($2,thd->variables.character_set_database,$2)); } | NAMES_SYM charset_name_or_default opt_collate { THD *thd= YYTHD; LEX *lex= Lex; - $2= $2 ? $2 : global_system_variables.collation_client; + $2= $2 ? $2 : global_system_variables.character_set_client; $3= $3 ? $3 : $2; if (!my_charset_same($2,$3)) { @@ -4821,7 +4829,7 @@ column_list: column_list_id: ident { - String *new_str = new String((const char*) $1.str,$1.length,default_charset_info); + String *new_str = new String((const char*) $1.str,$1.length,system_charset_info); List_iterator <LEX_COLUMN> iter(Lex->columns); class LEX_COLUMN *point; LEX *lex=Lex; diff --git a/sql/table.cc b/sql/table.cc index 3aed75c7ac6..908d6807450 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1161,6 +1161,33 @@ rename_file_ext(const char * from,const char * to,const char * ext) /* + Allocate string field in MEM_ROOT and return it as String + + SYNOPSIS + get_field() + mem MEM_ROOT for allocating + field Field for retrieving of string + res result String + + RETURN VALUES + true string is empty + false all ok +*/ + +bool get_field(MEM_ROOT *mem, Field *field, String *res) +{ + char buff[MAX_FIELD_WIDTH]; + String str(buff,sizeof(buff),&my_charset_bin); + field->val_str(&str,&str); + uint length=str.length(); + if (!length) + return true; + char *to= strmake_root(mem, str.ptr(), length); + res->set(to,length,((Field_str*)field)->charset()); + return false; +} + +/* Allocate string field in MEM_ROOT and return it as NULL-terminated string SYNOPSIS diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index 57560715fbe..fa678ec7de2 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -85,3 +85,33 @@ gptr sql_memdup(const void *ptr,uint len) void sql_element_free(void *ptr __attribute__((unused))) {} /* purecov: deadcode */ + + + +char *sql_strmake_with_convert(const char *str, uint32 arg_length, + CHARSET_INFO *from_cs, + uint32 max_res_length, + CHARSET_INFO *to_cs, uint32 *result_length) +{ + char *pos; + uint32 new_length= to_cs->mbmaxlen*arg_length; + max_res_length--; // Reserve place for end null + + set_if_smaller(new_length, max_res_length); + if (!(pos= sql_alloc(new_length+1))) + return pos; // Error + + if ((from_cs == &my_charset_bin) || (to_cs == &my_charset_bin)) + { + // Safety if to_cs->mbmaxlen > 0 + new_length= min(arg_length, max_res_length); + memcpy(pos, str, new_length); + } + else + new_length= copy_and_convert((char*) pos, new_length, to_cs, str, + arg_length, from_cs); + pos[new_length]= 0; + *result_length= new_length; + return pos; +} + diff --git a/sql/time.cc b/sql/time.cc index 94f9cb2e5e8..eba664a690d 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -251,145 +251,6 @@ void get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, DBUG_VOID_RETURN; } -/* find date from string and put it in vektor - Input: pos = "YYMMDD" OR "YYYYMMDD" in any order or - "xxxxx YYxxxMMxxxDD xxxx" where xxx is anything exept - a number. Month or day mustn't exeed 2 digits, year may be 4 digits. -*/ - - -#ifdef NOT_NEEDED - -void find_date(string pos,uint *vek,uint flag) -{ - uint length,value; - string start; - DBUG_ENTER("find_date"); - DBUG_PRINT("enter",("pos: '%s' flag: %d",pos,flag)); - - bzero((char*) vek,sizeof(int)*4); - 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 (my_isdigit(my_charset_latin1,pos[0]) && - ((pos-start) < 2 || ((pos-start) < 4 && length >= 8 && - !(flag & 3)))) - { - value=value*10 + (uint) (uchar) (*pos - '0'); - pos++; - } - vek[flag & 3]=value; flag>>=2; - 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])); - DBUG_VOID_RETURN; -} /* find_date */ - - - /* Outputs YYMMDD if input year < 100 or YYYYMMDD else */ - -static long calc_daynr_from_week(uint year,uint week,uint day) -{ - long daynr; - int weekday; - - daynr=calc_daynr(year,1,1); - if ((weekday= calc_weekday(daynr,0)) >= 3) - daynr+= (7-weekday); - else - daynr-=weekday; - - return (daynr+week*7+day-8); -} - -void convert_week_to_date(string date,uint flag,uint *res_length) -{ - string format; - uint year,vek[4]; - - find_date(date,vek,(uint) (1*4+2*16)); /* YY-WW-DD */ - year=vek[0]; - - get_date_from_daynr(calc_daynr_from_week(vek[0],vek[1],vek[2]), - &vek[0],&vek[1],&vek[2]); - *res_length=8; - format="%04d%02d%02d"; - if (year < 100) - { - vek[0]= vek[0]%100; - *res_length=6; - format="%02d%02d%02d"; - } - sprintf(date,format,vek[flag & 3],vek[(flag >> 2) & 3], - vek[(flag >> 4) & 3]); - return; -} - - /* returns YYWWDD or YYYYWWDD according to input year */ - /* flag only reflects format of input date */ - -void convert_date_to_week(string date,uint flag,uint *res_length) -{ - uint vek[4],weekday,days,year,week,day; - long daynr,first_daynr; - char buff[256],*format; - - if (! date[0]) - { - get_date(buff,0,0L); /* Use current date */ - find_date(buff+2,vek,(uint) (1*4+2*16)); /* YY-MM-DD */ - } - else - find_date(date,vek,flag); - - year= vek[0]; - daynr= calc_daynr(year,vek[1],vek[2]); - first_daynr=calc_daynr(year,1,1); - - /* Caculate year and first daynr of year */ - if (vek[1] == 1 && (weekday=calc_weekday(first_daynr,0)) >= 3 && - vek[2] <= 7-weekday) - { - if (!year--) - year=99; - first_daynr=first_daynr-calc_days_in_year(year); - } - else if (vek[1] == 12 && - (weekday=calc_weekday(first_daynr+calc_days_in_year(year)),0) < 3 && - vek[2] > 31-weekday) - { - first_daynr=first_daynr+calc_days_in_year(year); - if (year++ == 99) - year=0; - } - - /* Calulate daynr of first day of week 1 */ - if ((weekday= calc_weekday(first_daynr,0)) >= 3) - first_daynr+= (7-weekday); - else - first_daynr-=weekday; - - days=(int) (daynr-first_daynr); - week=days/7+1 ; day=calc_weekday(daynr,0)+1; - - *res_length=8; - format="%04d%02d%02d"; - if (year < 100) - { - *res_length=6; - format="%02d%02d%02d"; - } - sprintf(date,format,year,week,day); - return; -} - -#endif - /* Functions to handle periods */ ulong convert_period_to_month(ulong period) @@ -516,14 +377,14 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) else date[6]=0; - if (year_length == 2) + if (year_length == 2 && i >=2 && (date[1] || date[2])) date[0]+= (date[0] < YY_PART_YEAR ? 2000 : 1900); number_of_fields=i; while (i < 6) date[i++]=0; if (number_of_fields < 3 || date[1] > 12 || date[2] > 31 || date[3] > 23 || date[4] > 59 || date[5] > 59 || - !fuzzy_date && (date[1] == 0 || date[2] == 0)) + (!fuzzy_date && (date[1] == 0 || date[2] == 0))) { /* Only give warning for a zero date if there is some garbage after */ if (!not_zero_date) // If zero date diff --git a/sql/udf_example.cc b/sql/udf_example.cc index dfe8177bfce..7f4417bf8fe 100644 --- a/sql/udf_example.cc +++ b/sql/udf_example.cc @@ -284,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 ( my_isalpha ( my_charset_latin1, *word )) - *n++ = my_toupper ( my_charset_latin1, *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 */ { diff --git a/sql/unireg.h b/sql/unireg.h index ff942f6748a..6ddd9856724 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -45,6 +45,7 @@ #define LIBLEN FN_REFLEN-FN_LEN /* Max l{ngd p} dev */ #define MAX_DBKEY_LENGTH (FN_LEN*2+6) /* extra 4 bytes for slave tmp * tables */ +#define MAX_ALIAS_NAME 256 #define MAX_FIELD_NAME 34 /* Max colum name length +2 */ #define MAX_SYS_VAR_LENGTH 32 #define MAX_KEY 32 /* Max used keys */ @@ -55,6 +56,7 @@ #else #define MAX_REFLENGTH 4 /* Max length for record ref */ #endif +#define MAX_HOSTNAME 61 /* len+1 in mysql.user */ #define MAX_FIELD_WIDTH 256 /* Max column width +1 */ #define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */ |